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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cf88be500ee51ad9217ce6729399a3dd45ea69bc91f8d0a2f9ffc97521f802a3
4
- data.tar.gz: 13c889293a2173dc698257d1e614a2072b705faca25c3a59d8066e5d09326974
3
+ metadata.gz: 8461ea231fa9be478360d33fbadfb8983512172687831ac7c17ac1f927614200
4
+ data.tar.gz: 0b36b28eadecb6e0bc6e7ee8c3e6db951f7dc7d74be67c91b97659dc7bd52c5e
5
5
  SHA512:
6
- metadata.gz: 2300c5d0b41084a2d6403444c8548710e57a6645e770ee0d1befa029bfa947e738fe0909d33c522a1543b24892580e0acd7dd2504baae7100ed05af5e32e4a45
7
- data.tar.gz: 64e6ff60e979d5ffe2c0c7cceed3cd23733694cc479ad96f484b4af1b6ed421a2aa65ec2e4450699363b3006274784daed0737e27b4b4f4c904123764b1c11ed
6
+ metadata.gz: 39a0956db1750d63553d87e4d13ad75246f4f4633b3d6a42de621c45f11a515506ab5f0d7f14343d61f183d03df7e8218dee8f93a439da023e442d70c7f3b681
7
+ data.tar.gz: 227acbdb961e2903cdaacd44ed4bdd7b07a48e7298737bbe5b6228bd28df8aa6c7aea6a6949de2a3eea999287b633e9bfcd32b7b9e108e3f7f4fcaa7385e2806
@@ -1,9 +1,6 @@
1
1
  name: CI
2
2
 
3
- on:
4
- push:
5
- pull_request:
6
- types: [opened, reopened]
3
+ on: push
7
4
 
8
5
  jobs:
9
6
  test:
@@ -3,7 +3,7 @@ name: Publish Gem
3
3
  on:
4
4
  push:
5
5
  branches:
6
- - master
6
+ - main
7
7
  tags:
8
8
  - v*
9
9
  jobs:
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)
@@ -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
@@ -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
- method_option :dependencies, type: :boolean, aliases: "-d",
29
- desc: "Run the command on each dependency of a given component"
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
- method_option :dependencies, type: :boolean, desc: "Run the command on each dependency of a given component"
41
- method_option :dependents, type: :boolean, desc: "Run the command on each dependency of a given component"
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 MultiExec
13
- def initialize(components, concurrency:, spin_output: $stderr)
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 run(command, output: $stdout, **kwargs)
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(command: command, component: component,
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
- output << buffer.string
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:, command:, **kwargs)
40
+ def register_job(component, command)
47
41
  @multi.register(":spinner #{component.name}", **spinner_options) do |spinner|
48
42
  @semaphore.acquire
49
- exec = ComponentExec.new(component)
50
- if exec.run(command, **kwargs)
51
- spinner.success
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/component_exec"
4
- require_relative "executor/multi_exec"
3
+ require_relative "executor/context"
4
+ require_relative "executor/concurrent"
5
5
 
6
6
  module CobraCommander
7
- # Execute commands on all components of a ComponentTree
7
+ # Execute a command on all given components
8
8
  module Executor
9
- def self.exec(components:, command:, concurrency:, output: $stdout, status_output: $stderr)
10
- components = Array(components)
11
- exec = if components.size == 1
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
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "stringio"
4
+
3
5
  module CobraCommander
4
6
  module Output
5
7
  # Prints the tree in a nice tree form
@@ -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
@@ -3,3 +3,5 @@
3
3
  require_relative "output/flat_list"
4
4
  require_relative "output/ascii_tree"
5
5
  require_relative "output/graph_viz"
6
+ require_relative "output/interactive_printer"
7
+ require_relative "output/markdown_printer"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CobraCommander
4
- VERSION = "0.11.0"
4
+ VERSION = "0.12.0"
5
5
  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.11.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-04-23 00:00:00.000000000 Z
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/component_exec.rb
248
- - lib/cobra_commander/executor/multi_exec.rb
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