cobra_commander 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +1 -4
- data/.github/workflows/release.yml +1 -1
- data/CHANGELOG.md +5 -0
- data/cobra_commander.gemspec +1 -0
- data/lib/cobra_commander/cli/filters.rb +30 -0
- data/lib/cobra_commander/cli.rb +16 -25
- data/lib/cobra_commander/executor/{multi_exec.rb → concurrent.rb} +12 -21
- data/lib/cobra_commander/executor/context.rb +47 -0
- data/lib/cobra_commander/executor.rb +6 -11
- data/lib/cobra_commander/output/ascii_tree.rb +2 -0
- data/lib/cobra_commander/output/interactive_printer.rb +32 -0
- data/lib/cobra_commander/output/markdown_printer.rb +24 -0
- data/lib/cobra_commander/output.rb +2 -0
- data/lib/cobra_commander/version.rb +1 -1
- metadata +21 -4
- data/lib/cobra_commander/executor/component_exec.rb +0 -33
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8461ea231fa9be478360d33fbadfb8983512172687831ac7c17ac1f927614200
|
4
|
+
data.tar.gz: 0b36b28eadecb6e0bc6e7ee8c3e6db951f7dc7d74be67c91b97659dc7bd52c5e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 39a0956db1750d63553d87e4d13ad75246f4f4633b3d6a42de621c45f11a515506ab5f0d7f14343d61f183d03df7e8218dee8f93a439da023e442d70c7f3b681
|
7
|
+
data.tar.gz: 227acbdb961e2903cdaacd44ed4bdd7b07a48e7298737bbe5b6228bd28df8aa6c7aea6a6949de2a3eea999287b633e9bfcd32b7b9e108e3f7f4fcaa7385e2806
|
data/.github/workflows/ci.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,11 @@
|
|
2
2
|
|
3
3
|
## Unreleased
|
4
4
|
|
5
|
+
## Version 0.12.0 - 2021-09-21
|
6
|
+
|
7
|
+
* Add interactive UI and Markdown output to `cobra exec` [#63](https://github.com/powerhome/cobra_commander/pull/63)
|
8
|
+
* Add `--self` and `--no-self` filters to `cobra exec` and `cobra ls`, defaults to `--self` [#61](https://github.com/powerhome/cobra_commander/pull/61)
|
9
|
+
|
5
10
|
## Version 0.11.0 - 2021-04-23
|
6
11
|
|
7
12
|
* Add concurrency limit to multi exec [#57](https://github.com/powerhome/cobra_commander/pull/57)
|
data/cobra_commander.gemspec
CHANGED
@@ -38,6 +38,7 @@ Gem::Specification.new do |spec|
|
|
38
38
|
spec.add_dependency "ruby-graphviz", "~> 1.2.3"
|
39
39
|
spec.add_dependency "thor", ["< 2.0", ">= 0.18.1"]
|
40
40
|
spec.add_dependency "tty-command", "~> 0.10.0"
|
41
|
+
spec.add_dependency "tty-prompt", "~> 0.23.1"
|
41
42
|
spec.add_dependency "tty-spinner", "~> 0.9.3"
|
42
43
|
|
43
44
|
spec.add_development_dependency "aruba", "~> 0.14.2"
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CobraCommander
|
4
|
+
# @private
|
5
|
+
class CLI
|
6
|
+
private_class_method def self.filter_options(dependents:, dependencies:)
|
7
|
+
method_option :dependencies, type: :boolean, aliases: "-d", desc: dependencies
|
8
|
+
method_option :dependents, type: :boolean, aliases: "-D", desc: dependents
|
9
|
+
method_option :self, type: :boolean, default: true, desc: "Include the own component"
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def find_component(name)
|
15
|
+
return umbrella.root unless name
|
16
|
+
|
17
|
+
umbrella.find(name) || error("Component #{name} not found, try one of `cobra ls`") || exit(1)
|
18
|
+
end
|
19
|
+
|
20
|
+
def components_filtered(component_name)
|
21
|
+
return umbrella.components unless component_name
|
22
|
+
|
23
|
+
component = find_component(component_name)
|
24
|
+
components = options.self ? [component] : []
|
25
|
+
components.concat component.deep_dependencies if options.dependencies
|
26
|
+
components.concat component.deep_dependents if options.dependents
|
27
|
+
components
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/cobra_commander/cli.rb
CHANGED
@@ -13,6 +13,8 @@ require "cobra_commander/output"
|
|
13
13
|
module CobraCommander
|
14
14
|
# Implements the tool's CLI
|
15
15
|
class CLI < Thor
|
16
|
+
require "cobra_commander/cli/filters"
|
17
|
+
|
16
18
|
DEFAULT_CONCURRENCY = (Concurrent.processor_count / 2.0).ceil
|
17
19
|
|
18
20
|
class_option :app, default: Dir.pwd, aliases: "-a", type: :string
|
@@ -25,10 +27,8 @@ module CobraCommander
|
|
25
27
|
end
|
26
28
|
|
27
29
|
desc "ls [component]", "Lists the components in the context of a given component or umbrella"
|
28
|
-
|
29
|
-
|
30
|
-
method_option :dependents, type: :boolean, aliases: "-D",
|
31
|
-
desc: "Run the command on each dependency of a given component"
|
30
|
+
filter_options dependents: "Lists all dependents of a given component",
|
31
|
+
dependencies: "Lists all dependencies of a given component"
|
32
32
|
method_option :total, type: :boolean, aliases: "-t", desc: "Prints the total count of components"
|
33
33
|
def ls(component = nil)
|
34
34
|
components = components_filtered(component)
|
@@ -37,16 +37,24 @@ module CobraCommander
|
|
37
37
|
|
38
38
|
desc "exec [component] <command>", "Executes the command in the context of a given component or set thereof. " \
|
39
39
|
"Defaults to all components."
|
40
|
-
|
41
|
-
|
40
|
+
filter_options dependents: "Run the command on each dependent of a given component",
|
41
|
+
dependencies: "Run the command on each dependency of a given component"
|
42
42
|
method_option :concurrency, type: :numeric, default: DEFAULT_CONCURRENCY, aliases: "-c",
|
43
43
|
desc: "Max number of jobs to run concurrently"
|
44
|
+
method_option :interactive, type: :boolean, default: true, aliases: "-i",
|
45
|
+
desc: "Runs in interactive mode to allow the user to inspect the output of each component"
|
44
46
|
def exec(command_or_component, command = nil)
|
45
|
-
CobraCommander::Executor.exec(
|
47
|
+
results = CobraCommander::Executor.exec(
|
46
48
|
components: components_filtered(command && command_or_component),
|
47
49
|
command: command || command_or_component,
|
48
|
-
concurrency: options.concurrency
|
50
|
+
concurrency: options.concurrency,
|
51
|
+
status_output: $stderr
|
49
52
|
)
|
53
|
+
if options.interactive && results.size > 1
|
54
|
+
CobraCommander::Output::InteractivePrinter.run(results, $stdout)
|
55
|
+
else
|
56
|
+
CobraCommander::Output::MarkdownPrinter.run(results, $stdout)
|
57
|
+
end
|
50
58
|
end
|
51
59
|
|
52
60
|
desc "tree [component]", "Prints the dependency tree of a given component or umbrella"
|
@@ -80,22 +88,5 @@ module CobraCommander
|
|
80
88
|
def umbrella
|
81
89
|
@umbrella ||= CobraCommander.umbrella(options.app, yarn: options.js, bundler: options.ruby)
|
82
90
|
end
|
83
|
-
|
84
|
-
def find_component(name)
|
85
|
-
return umbrella.root unless name
|
86
|
-
|
87
|
-
umbrella.find(name) || error("Component #{name} not found, try one of `cobra ls`") || exit(1)
|
88
|
-
end
|
89
|
-
|
90
|
-
def components_filtered(component_name)
|
91
|
-
return umbrella.components unless component_name
|
92
|
-
|
93
|
-
component = find_component(component_name)
|
94
|
-
|
95
|
-
return component.deep_dependencies if options.dependencies
|
96
|
-
return component.deep_dependents if options.dependents
|
97
|
-
|
98
|
-
[component]
|
99
|
-
end
|
100
91
|
end
|
101
92
|
end
|
@@ -1,32 +1,26 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "tty-spinner"
|
4
|
-
require "stringio"
|
5
4
|
require "concurrent-ruby"
|
6
5
|
|
7
|
-
require_relative "component_exec"
|
8
|
-
|
9
6
|
module CobraCommander
|
10
7
|
module Executor
|
11
|
-
# Execute a command on multiple components
|
12
|
-
class
|
13
|
-
def initialize(components, concurrency:, spin_output:
|
8
|
+
# Execute a command on multiple components concurrently
|
9
|
+
class Concurrent
|
10
|
+
def initialize(components, concurrency:, spin_output:)
|
14
11
|
@components = components
|
15
12
|
@multi = TTY::Spinner::Multi.new(":spinner :task", output: spin_output)
|
16
|
-
@semaphore = Concurrent::Semaphore.new(concurrency)
|
13
|
+
@semaphore = ::Concurrent::Semaphore.new(concurrency)
|
17
14
|
end
|
18
15
|
|
19
|
-
def
|
20
|
-
buffer = StringIO.new
|
16
|
+
def exec(command)
|
21
17
|
@multi.top_spinner.update(task: "Running #{command}")
|
18
|
+
@results = []
|
22
19
|
@components.each do |component|
|
23
|
-
register_job(
|
24
|
-
output: buffer, stderr: :stdout,
|
25
|
-
only_output_on_error: true, **kwargs)
|
20
|
+
register_job(component, command)
|
26
21
|
end
|
27
22
|
@multi.auto_spin
|
28
|
-
|
29
|
-
@multi.success?
|
23
|
+
@results
|
30
24
|
end
|
31
25
|
|
32
26
|
private
|
@@ -43,15 +37,12 @@ module CobraCommander
|
|
43
37
|
}
|
44
38
|
end
|
45
39
|
|
46
|
-
def register_job(component
|
40
|
+
def register_job(component, command)
|
47
41
|
@multi.register(":spinner #{component.name}", **spinner_options) do |spinner|
|
48
42
|
@semaphore.acquire
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
else
|
53
|
-
spinner.error
|
54
|
-
end
|
43
|
+
context = Context.new(component, command)
|
44
|
+
context.success? ? spinner.success : spinner.error
|
45
|
+
@results << context
|
55
46
|
@semaphore.release
|
56
47
|
end
|
57
48
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "tty-command"
|
4
|
+
|
5
|
+
module CobraCommander
|
6
|
+
module Executor
|
7
|
+
class Context
|
8
|
+
attr_reader :component, :command
|
9
|
+
|
10
|
+
def initialize(component, command)
|
11
|
+
@component = component
|
12
|
+
@command = command
|
13
|
+
@tty = TTY::Command.new(pty: true, printer: :null, stderr: :stdout)
|
14
|
+
end
|
15
|
+
|
16
|
+
def results
|
17
|
+
@results ||= @component.root_paths.map do |path|
|
18
|
+
isolate_bundle do
|
19
|
+
@tty.run!(command, chdir: path)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def component_name
|
25
|
+
component.name
|
26
|
+
end
|
27
|
+
|
28
|
+
def success?
|
29
|
+
results.all?(&:success?)
|
30
|
+
end
|
31
|
+
|
32
|
+
def output
|
33
|
+
results.join("\n")
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def isolate_bundle(&block)
|
39
|
+
if Bundler.respond_to?(:with_unbundled_env)
|
40
|
+
Bundler.with_unbundled_env(&block)
|
41
|
+
else
|
42
|
+
Bundler.with_clean_env(&block)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -1,19 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "executor/
|
4
|
-
require_relative "executor/
|
3
|
+
require_relative "executor/context"
|
4
|
+
require_relative "executor/concurrent"
|
5
5
|
|
6
6
|
module CobraCommander
|
7
|
-
# Execute
|
7
|
+
# Execute a command on all given components
|
8
8
|
module Executor
|
9
|
-
def self.exec(components:, command:, concurrency:,
|
10
|
-
components
|
11
|
-
|
12
|
-
ComponentExec.new(components.first)
|
13
|
-
else
|
14
|
-
MultiExec.new(components, concurrency: concurrency, spin_output: status_output)
|
15
|
-
end
|
16
|
-
exec.run(command, output: output)
|
9
|
+
def self.exec(components:, command:, concurrency:, status_output:)
|
10
|
+
Concurrent.new(components, concurrency: concurrency, spin_output: status_output)
|
11
|
+
.exec(command)
|
17
12
|
end
|
18
13
|
end
|
19
14
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pastel"
|
4
|
+
require "tty-prompt"
|
5
|
+
|
6
|
+
module CobraCommander
|
7
|
+
module Output
|
8
|
+
# Runs an interactive output printer
|
9
|
+
module InteractivePrinter
|
10
|
+
pastel = Pastel.new
|
11
|
+
SUCCESS = "#{pastel.green("✔")} %s".freeze
|
12
|
+
ERROR = "#{pastel.red("✖")} %s".freeze
|
13
|
+
BYE = pastel.decorate("👋 Bye!", :white, :on_black, :bold).freeze
|
14
|
+
|
15
|
+
def self.run(contexts, output)
|
16
|
+
prompt = TTY::Prompt.new
|
17
|
+
context_options = contexts.reduce({}) do |options, context|
|
18
|
+
template = context.success? ? SUCCESS : ERROR
|
19
|
+
options.merge(
|
20
|
+
format(template, context.component_name) => context
|
21
|
+
)
|
22
|
+
end
|
23
|
+
loop do
|
24
|
+
context = prompt.select("Print output?", context_options)
|
25
|
+
output.puts context.output
|
26
|
+
end
|
27
|
+
rescue TTY::Reader::InputInterrupt
|
28
|
+
output.puts "\n\n", BYE
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pastel"
|
4
|
+
require "tty-prompt"
|
5
|
+
|
6
|
+
module CobraCommander
|
7
|
+
module Output
|
8
|
+
# Prints the given CobraCommander::Executor::Context to [output] collection in markdown
|
9
|
+
module MarkdownPrinter
|
10
|
+
SUCCESS = "\n## ✔ %s\n".freeze
|
11
|
+
ERROR = "\n## ✖ %s\n".freeze
|
12
|
+
OUTPUT = "\n```\n$ %s\n\n%s\n```\n".freeze
|
13
|
+
|
14
|
+
def self.run(contexts, output)
|
15
|
+
contexts.each do |context|
|
16
|
+
template = context.success? ? SUCCESS : ERROR
|
17
|
+
|
18
|
+
output.print format(template, context.component_name)
|
19
|
+
output.print format(OUTPUT, context.command, context.output)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cobra_commander
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.12.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Langfeld
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: exe
|
12
12
|
cert_chain: []
|
13
|
-
date: 2021-
|
13
|
+
date: 2021-09-21 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: bundler
|
@@ -88,6 +88,20 @@ dependencies:
|
|
88
88
|
- - "~>"
|
89
89
|
- !ruby/object:Gem::Version
|
90
90
|
version: 0.10.0
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: tty-prompt
|
93
|
+
requirement: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - "~>"
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: 0.23.1
|
98
|
+
type: :runtime
|
99
|
+
prerelease: false
|
100
|
+
version_requirements: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - "~>"
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: 0.23.1
|
91
105
|
- !ruby/object:Gem::Dependency
|
92
106
|
name: tty-spinner
|
93
107
|
requirement: !ruby/object:Gem::Requirement
|
@@ -237,6 +251,7 @@ files:
|
|
237
251
|
- lib/cobra_commander/affected.rb
|
238
252
|
- lib/cobra_commander/change.rb
|
239
253
|
- lib/cobra_commander/cli.rb
|
254
|
+
- lib/cobra_commander/cli/filters.rb
|
240
255
|
- lib/cobra_commander/component.rb
|
241
256
|
- lib/cobra_commander/dependencies.rb
|
242
257
|
- lib/cobra_commander/dependencies/bundler.rb
|
@@ -244,12 +259,14 @@ files:
|
|
244
259
|
- lib/cobra_commander/dependencies/yarn/package_repo.rb
|
245
260
|
- lib/cobra_commander/dependencies/yarn_workspace.rb
|
246
261
|
- lib/cobra_commander/executor.rb
|
247
|
-
- lib/cobra_commander/executor/
|
248
|
-
- lib/cobra_commander/executor/
|
262
|
+
- lib/cobra_commander/executor/concurrent.rb
|
263
|
+
- lib/cobra_commander/executor/context.rb
|
249
264
|
- lib/cobra_commander/output.rb
|
250
265
|
- lib/cobra_commander/output/ascii_tree.rb
|
251
266
|
- lib/cobra_commander/output/flat_list.rb
|
252
267
|
- lib/cobra_commander/output/graph_viz.rb
|
268
|
+
- lib/cobra_commander/output/interactive_printer.rb
|
269
|
+
- lib/cobra_commander/output/markdown_printer.rb
|
253
270
|
- lib/cobra_commander/umbrella.rb
|
254
271
|
- lib/cobra_commander/version.rb
|
255
272
|
- renovate.json
|
@@ -1,33 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "tty-command"
|
4
|
-
|
5
|
-
module CobraCommander
|
6
|
-
module Executor
|
7
|
-
# Execute a command on a single component
|
8
|
-
class ComponentExec
|
9
|
-
def initialize(component)
|
10
|
-
@component = component
|
11
|
-
end
|
12
|
-
|
13
|
-
def run(command, output: $stdout, **cmd_options)
|
14
|
-
tty = TTY::Command.new(pty: true, printer: :quiet, output: output)
|
15
|
-
isolate_bundle do
|
16
|
-
@component.root_paths.all? do |path|
|
17
|
-
tty.run!(command, chdir: path, **cmd_options).success?
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
def isolate_bundle(&block)
|
25
|
-
if Bundler.respond_to?(:with_unbundled_env)
|
26
|
-
Bundler.with_unbundled_env(&block)
|
27
|
-
else
|
28
|
-
Bundler.with_clean_env(&block)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|