cobra_commander 1.0.1 → 1.1.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: c5f6e4d7e8d890c46aed5efff6219f669e79f64325f6f73c899cf6a0c5959088
4
- data.tar.gz: 3fe47e6df4f555345c640051ff6aebf25dea8a5907507e6be4ebcc18876897c1
3
+ metadata.gz: 3e4912ef5e1373f254652d50f2c88bd5d6fc2785675f2d53bdf3572ffcbfafaf
4
+ data.tar.gz: 5c0bdd82e4ea3fcffeb1f8d7a44aece59ca929d40171f3c22b6a3c95d951b942
5
5
  SHA512:
6
- metadata.gz: 0add3576fb98e23aa8332939c2c19d7b4dd04cb82ab3d7cebb12191687fbe72e43efad27ddfa24c80d4393d63898f8f01915af1aa6a74a2331c00c1f57dc99a6
7
- data.tar.gz: '03942e8553ee6163ad3703ce4be836ec2d538ea908cbd32d7fcd274a01b316a37f77407e32758c8d57043ec3e5a0b30007b7398e1c1a0d21018e245d8c2c09d6'
6
+ metadata.gz: 3d8882fe6141cc4ddc6c7ec92616aceb7010c3d889b8c6b7f2d039d589fcd1c9bed43d8dcac946f239057f27eb2ab51c5cd65a181a838401cff2e38f6edb1e8d
7
+ data.tar.gz: ceda5086044a31eae40445597289fae8c23aef320160b07b8d9a1b3fc33ea9318eb2815e97781af5a70f4295842bc59e07e9cc562473fa92933c837db47a9f36
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- lib = File.expand_path("lib", __dir__)
4
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
- require "cobra_commander/version"
3
+ require_relative "lib/cobra_commander/version"
6
4
 
7
5
  Gem::Specification.new do |spec|
8
6
  spec.name = "cobra_commander"
@@ -31,19 +29,15 @@ Gem::Specification.new do |spec|
31
29
  spec.metadata["source_code_uri"] = "https://github.com/powerhome/cobra_commander"
32
30
  spec.metadata["changelog_uri"] = "https://github.com/powerhome/cobra_commander/blob/main/cobra_commander/docs/CHANGELOG.md"
33
31
 
34
- spec.files = `git ls-files -z`.split("\x0").reject do |f|
35
- f.match(%r{^(test|spec|features)/})
36
- end
32
+ spec.files = Dir["{docs,exe,lib}/**/*"] + ["cobra_commander.gemspec"]
37
33
  spec.bindir = "exe"
38
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
39
- spec.require_paths = ["lib"]
34
+ spec.executables = %w[cobra]
35
+ spec.require_paths = %w[lib]
40
36
 
41
37
  spec.add_dependency "bundler"
42
- spec.add_dependency "concurrent-ruby", "~> 1.1"
43
38
  spec.add_dependency "thor", ["< 2.0", ">= 0.18.1"]
44
39
  spec.add_dependency "tty-command", "~> 0.10.0"
45
40
  spec.add_dependency "tty-prompt", "~> 0.23.1"
46
- spec.add_dependency "tty-spinner", "~> 0.9.3"
47
41
 
48
42
  spec.add_development_dependency "aruba", "~> 0.14.2"
49
43
  spec.add_development_dependency "bundler"
data/docs/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Change Log
2
2
 
3
+ ## Unreleased
4
+
5
+ ## Version 1.1.0 - 2023-03-09
6
+
7
+ * New Executor by @xjunior in [#104](https://github.com/powerhome/cobra_commander/pull/104)
8
+ * Cleanup cobra changes by @xjunior in [#105](https://github.com/powerhome/cobra_commander/pull/105)
9
+
3
10
  ## Version 1.0.1 - 2023-01-05
4
11
 
5
12
  * Fix Umbrella#resolve unable to resolve a path relative to the project @xjunior [#103](https://github.com/powerhome/cobra_commander/pull/103)
@@ -1,25 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "json"
4
-
5
3
  module CobraCommander
6
4
  # Calculates directly & transitively affected components
5
+ # Takes a list of changes, and resolves all components affected
6
+ #
7
7
  class Affected
8
+ include Enumerable
9
+
8
10
  def initialize(umbrella, changes)
9
11
  @umbrella = umbrella
10
12
  @changes = changes
11
13
  end
12
14
 
13
- def names
14
- @names ||= all.map(&:name)
15
- end
16
-
17
- def all
18
- @all ||= (directly | transitively).sort_by(&:name)
19
- end
20
-
21
- def scripts
22
- @scripts ||= paths.map { |path| path.join("test.sh") }
15
+ def each(&block)
16
+ (directly | transitively).sort_by(&:name).each(&block)
23
17
  end
24
18
 
25
19
  def directly
@@ -31,34 +25,5 @@ module CobraCommander
31
25
  @transitively ||= directly.flat_map(&:deep_dependents)
32
26
  .uniq.sort_by(&:name)
33
27
  end
34
-
35
- def to_json(*_args)
36
- {
37
- changed_files: @changes,
38
- directly_affected_components: directly.map { |c| affected_component(c) },
39
- transitively_affected_components: transitively.map { |c| affected_component(c) },
40
- test_scripts: scripts,
41
- component_names: names,
42
- languages: all_affected_packages,
43
- }.to_json
44
- end
45
-
46
- private
47
-
48
- def affected_component(component)
49
- {
50
- name: component.name,
51
- path: component.root_paths.map(&:to_s),
52
- type: component.packages.map(&:key).map(&:to_s),
53
- }
54
- end
55
-
56
- def paths
57
- @paths ||= all.map(&:root_paths).flatten
58
- end
59
-
60
- def all_affected_packages
61
- all.flat_map(&:packages).map(&:key).uniq
62
- end
63
28
  end
64
29
  end
@@ -29,7 +29,7 @@ module CobraCommander
29
29
 
30
30
  def affected_by_changes(origin_branch)
31
31
  changes = GitChanged.new(umbrella.path, origin_branch)
32
- Affected.new(umbrella, changes).all
32
+ Affected.new(umbrella, changes).to_a
33
33
  end
34
34
 
35
35
  def filter_component(component_name)
@@ -6,27 +6,19 @@ require "cobra_commander/affected"
6
6
  module CobraCommander
7
7
  class CLI
8
8
  module Output
9
- # Calculates and prints affected components & files
10
9
  class Change
11
- InvalidSelectionError = Class.new(StandardError)
12
-
13
- def initialize(umbrella, oformat, branch, changes: nil)
14
- @format = oformat
10
+ def initialize(umbrella, branch, changes: nil)
15
11
  @branch = branch
16
12
  @umbrella = umbrella
17
13
  @changes = changes || GitChanged.new(umbrella.path, branch)
18
14
  end
19
15
 
20
16
  def run!
21
- assert_valid_result_choice
22
- if selected_format?("json")
23
- puts affected.to_json
24
- else
25
- show_full if selected_format?("full")
26
- tests_to_run
27
- end
28
- rescue GitChanged::InvalidSelectionError => e
29
- puts e.message
17
+ print_changes_since_last_commit
18
+ puts
19
+ print_directly_affected_components
20
+ puts
21
+ print_transitively_affected_components
30
22
  end
31
23
 
32
24
  private
@@ -35,55 +27,23 @@ module CobraCommander
35
27
  @affected ||= Affected.new(@umbrella, @changes)
36
28
  end
37
29
 
38
- def show_full
39
- changes_since_last_commit
40
- directly_affected_components
41
- transitively_affected_components
42
- end
43
-
44
- def assert_valid_result_choice
45
- return if %w[test full name json].include?(@format)
46
-
47
- raise InvalidSelectionError, "--results must be 'test', 'full', 'name' or 'json'"
48
- end
49
-
50
- def selected_format?(result)
51
- @format == result
52
- end
53
-
54
- def changes_since_last_commit
30
+ def print_changes_since_last_commit
55
31
  puts "<<< Changes since last commit on #{@branch} >>>"
56
32
  puts(*@changes) if @changes.any?
57
- puts blank_line
58
33
  end
59
34
 
60
- def directly_affected_components
35
+ def print_directly_affected_components
61
36
  puts "<<< Directly affected components >>>"
62
- affected.directly.each { |component| puts display(component) }
63
- puts blank_line
37
+ affected.directly.each { |component| display(component) }
64
38
  end
65
39
 
66
- def transitively_affected_components
40
+ def print_transitively_affected_components
67
41
  puts "<<< Transitively affected components >>>"
68
- affected.transitively.each { |component| puts display(component) }
69
- puts blank_line
70
- end
71
-
72
- def tests_to_run
73
- puts "<<< Test scripts to run >>>" if selected_format?("full")
74
- if selected_format?("name")
75
- affected.names.each { |component_name| puts component_name }
76
- else
77
- affected.scripts.each { |component_script| puts component_script }
78
- end
42
+ affected.transitively.each { |component| display(component) }
79
43
  end
80
44
 
81
45
  def display(component)
82
- "#{component.name} - #{component.packages.map(&:key).map(&:to_s).map(&:capitalize).join(' & ')}"
83
- end
84
-
85
- def blank_line
86
- ""
46
+ puts "#{component.name} - #{component.packages.map(&:key).map(&:to_s).map(&:capitalize).join(' & ')}"
87
47
  end
88
48
  end
89
49
  end
@@ -1,21 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "etc"
3
4
  require "thor"
4
5
  require "fileutils"
5
- require "concurrent-ruby"
6
-
7
6
  require "cobra_commander"
8
7
 
9
8
  module CobraCommander
10
9
  # Implements the tool's CLI
11
10
  class CLI < Thor
11
+ DEFAULT_CONCURRENCY = (Etc.nprocessors / 2.0).ceil
12
+
12
13
  require_relative "cli/filters"
13
14
  require_relative "cli/output/ascii_tree"
14
15
  require_relative "cli/output/change"
15
16
  require_relative "cli/output/dot_graph"
16
17
 
17
- DEFAULT_CONCURRENCY = (Concurrent.processor_count / 2.0).ceil
18
-
19
18
  class_option :app, default: Dir.pwd, aliases: "-a", type: :string
20
19
  Source.all.keys.each do |key|
21
20
  class_option key, default: false, type: :boolean, desc: "Consider only the #{key} dependency graph"
@@ -39,40 +38,36 @@ module CobraCommander
39
38
  "Defaults to all components."
40
39
  filter_options dependents: "Run the script on each dependent of a given component",
41
40
  dependencies: "Run the script on each dependency of a given component"
42
- method_option :concurrency, type: :numeric, default: DEFAULT_CONCURRENCY, aliases: "-c",
43
- desc: "Max number of jobs to run concurrently"
41
+ method_option :concurrency, type: :numeric, aliases: "-c", desc: "Max number of jobs to run concurrently",
42
+ default: DEFAULT_CONCURRENCY
44
43
  method_option :interactive, type: :boolean, default: true, aliases: "-i",
45
44
  desc: "Runs in interactive mode to allow the user to inspect the output of each " \
46
45
  "component"
47
46
  def exec(script_or_components, script = nil)
48
- jobs = CobraCommander::Executor::Script.for(
49
- components_filtered(script && script_or_components),
50
- script || script_or_components
47
+ CobraCommander::Executor.execute_and_handle_exit(
48
+ runner: ::CobraCommander::Executor::Script.new(script || script_or_components),
49
+ workers: options.concurrency,
50
+ interactive: options.interactive,
51
+ jobs: components_filtered(script && script_or_components)
51
52
  )
52
- output_mode = options.interactive && jobs.count > 1 ? :interactive : :markdown
53
- execution = CobraCommander::Executor.execute(jobs: jobs, workers: options.concurrency,
54
- output_mode: output_mode, output: $stdout, status_output: $stderr)
55
- exit 1 unless execution.success?
56
53
  end
57
54
 
58
55
  desc "cmd [components] <command>", "Executes the command in the context of a given component or set thereof. " \
59
56
  "Defaults to all components."
60
57
  filter_options dependents: "Run the command on each dependent of a given component",
61
58
  dependencies: "Run the command on each dependency of a given component"
62
- method_option :concurrency, type: :numeric, default: DEFAULT_CONCURRENCY, aliases: "-c",
63
- desc: "Max number of jobs to run concurrently"
59
+ method_option :concurrency, type: :numeric, aliases: "-c", desc: "Max number of jobs to run concurrently",
60
+ default: DEFAULT_CONCURRENCY
64
61
  method_option :interactive, type: :boolean, default: true, aliases: "-i",
65
62
  desc: "Runs in interactive mode to allow the user to inspect the output of each " \
66
63
  "component"
67
64
  def cmd(command_or_components, command = nil)
68
- jobs = CobraCommander::Executor::Command.for(
69
- components_filtered(command && command_or_components),
70
- command || command_or_components
65
+ CobraCommander::Executor.execute_and_handle_exit(
66
+ runner: ::CobraCommander::Executor::Command.new(command || command_or_components),
67
+ workers: options.concurrency,
68
+ interactive: options.interactive,
69
+ jobs: components_filtered(command && command_or_components).flat_map(&:packages)
71
70
  )
72
- output_mode = options.interactive && jobs.count > 1 ? :interactive : :markdown
73
- execution = CobraCommander::Executor.execute(jobs: jobs, workers: options.concurrency,
74
- output_mode: output_mode, output: $stdout, status_output: $stderr)
75
- exit 1 unless execution.success?
76
71
  end
77
72
 
78
73
  desc "tree [component]", "Prints the dependency tree of a given component or umbrella"
@@ -97,22 +92,18 @@ module CobraCommander
97
92
  end
98
93
 
99
94
  desc "changes [--results=RESULTS] [--branch=BRANCH]", "Prints list of changed files"
100
- method_option :results, default: "test", aliases: "-r", desc: "Accepts test, full, name or json"
101
95
  method_option :branch, default: "master", aliases: "-b", desc: "Specified target to calculate against"
102
96
  def changes
103
- Output::Change.new(umbrella, options.results, options.branch).run!
97
+ Output::Change.new(umbrella, options.branch).run!
104
98
  end
105
99
 
106
100
  private
107
101
 
108
102
  def umbrella
109
- selector = Source.all.keys.reduce({}) do |sel, key|
103
+ selector = CobraCommander::Source.all.keys.reduce({}) do |sel, key|
110
104
  sel.merge(key => options.public_send(key))
111
105
  end
112
- @umbrella ||= CobraCommander::Umbrella.new(
113
- options.app,
114
- **selector
115
- )
106
+ @umbrella ||= CobraCommander::Umbrella.new(options.app, **selector)
116
107
  rescue ::CobraCommander::Source::Error => e
117
108
  error(e.message)
118
109
  exit(1)
@@ -12,6 +12,10 @@ module CobraCommander
12
12
  @packages = []
13
13
  end
14
14
 
15
+ def describe
16
+ "#{name} (#{packages.map(&:key).join(', ')})"
17
+ end
18
+
15
19
  def add_package(package)
16
20
  @packages << package
17
21
  @dependency_names |= package.dependencies
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CobraCommander
4
+ module Executor
5
+ class BufferedPrinter < TTY::Command::Printers::Null
6
+ TIME_FORMAT = "Finished in %5.3fs"
7
+
8
+ def initialize(*)
9
+ super
10
+
11
+ @buffers = Hash.new { |h, k| h[k] = StringIO.new }
12
+ end
13
+
14
+ def write(cmd, message)
15
+ @buffers[cmd.uuid].write message
16
+ end
17
+
18
+ def print_command_out_data(cmd, *args)
19
+ write(cmd, args.join)
20
+ end
21
+
22
+ def print_command_err_data(cmd, *args)
23
+ write(cmd, args.join)
24
+ end
25
+
26
+ def print_command_start(cmd, *args)
27
+ message = "Running #{decorate(cmd.to_command, :yellow, :bold)} #{args.join(' ')}"
28
+ write(cmd, message)
29
+ end
30
+
31
+ def print_command_exit(cmd, status, runtime, *)
32
+ message = TIME_FORMAT % runtime
33
+ message << " with exit status #{status}" if status
34
+
35
+ output.puts @buffers.delete(cmd.uuid).string
36
+ output.puts decorate(message, status == 0 ? :green : :red)
37
+ output.puts
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,74 +1,49 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "./job"
4
- require_relative "./package_criteria"
5
-
6
3
  module CobraCommander
7
4
  module Executor
8
5
  class Command
9
- include ::CobraCommander::Executor::Job
10
6
  include ::CobraCommander::Executor::PackageCriteria
7
+ include ::CobraCommander::Executor::RunScript
11
8
 
12
9
  SKIP_UNEXISTING = "Command %s does not exist. Check your cobra.yml for existing commands in %s."
13
10
  SKIP_CRITERIA = "Package %s does not match criteria."
14
11
 
15
- # Builds the given commands in all packages of all components.
16
- #
17
- # @param components [Enumerable<CobraCommander::Component>] the target components
18
- # @param command [String] shell script to run from the directories of the component's packages
19
- # @return [Array<CobraCommander::Executor::Command>]
20
- def self.for(components, command)
21
- components.flat_map(&:packages).map do |package|
22
- new(package, command)
23
- end
12
+ def initialize(command_name)
13
+ @command_name = command_name
24
14
  end
25
15
 
26
16
  # Calls the commands sequentially, stopping ony if an :error happens.
27
17
  #
28
18
  # If one of the commands skips, the result will be :success.
29
19
  #
30
- # @param commands [Enumerable<CobraCommander::Component>] the target components
31
- # @return [Array<CobraCommander::Executor::Command>]
32
- # @see CobraCommander::Executor::Job
33
- def self.join(commands)
34
- commands.lazy.map(&:call).reduce do |(_, prev_output), (result, output)|
35
- new_output = [prev_output&.strip, output&.strip].join("\n")
36
- return [:error, new_output] if result == :error
37
-
38
- [:success, new_output]
39
- end
20
+ # @param tty [CobraComander::Executor::IsolatedPTY] tty to execute shell scripts
21
+ # @param package [CobraComander::Package] target package to execute the named command
22
+ # @return [Array<Symbol, String>]
23
+ def call(tty, package)
24
+ run_command tty, package, @command_name
40
25
  end
41
26
 
42
- def initialize(package, command)
43
- @package = package
44
- @command = command
45
- end
46
-
47
- def to_s
48
- "#{@package.name} (#{@package.key})"
49
- end
27
+ private
50
28
 
51
- # @see CobraCommander::Executor::Job
52
- def call
53
- command = @package.source.config&.dig("commands", @command)
54
- case command
55
- when Array then run_multiple(@package, command)
56
- when Hash then run_with_criteria(command)
57
- when nil then skip(format(SKIP_UNEXISTING, @command, @package.key))
58
- else run_script(command, @package.path)
29
+ def run_command(tty, package, command_name)
30
+ definition = package.source.config&.dig("commands", command_name)
31
+ case definition
32
+ when Array then run_multiple(tty, package, definition)
33
+ when Hash then run_with_criteria(tty, package, definition)
34
+ when nil then [:skip, format(SKIP_UNEXISTING, command_name, package.key)]
35
+ else run_script(tty, definition, package.path)
59
36
  end
60
37
  end
61
38
 
62
- private
63
-
64
- def run_with_criteria(command)
65
- return skip(format(SKIP_CRITERIA, @package.name)) unless match_criteria?(@package, command.fetch("if", {}))
39
+ def run_with_criteria(tty, package, command)
40
+ return [:skip, format(SKIP_CRITERIA, package.name)] unless match_criteria?(package, command.fetch("if", {}))
66
41
 
67
- run_script(command["run"], @package.path)
42
+ run_script(tty, command["run"], package.path)
68
43
  end
69
44
 
70
- def run_multiple(package, commands)
71
- Command.join(commands.map { |command| Command.new(package, command) })
45
+ def run_multiple(tty, package, commands)
46
+ run_many(commands) { run_command(tty, package, _1) }
72
47
  end
73
48
  end
74
49
  end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CobraCommander
4
+ module Executor
5
+ #
6
+ # Executes commands in a clean environment, without the influence
7
+ # of the current Bundler env vars.
8
+ #
9
+ class IsolatedPTY < ::TTY::Command
10
+ def initialize(**kwargs)
11
+ super(pty: true, **kwargs)
12
+ end
13
+
14
+ def run!(...)
15
+ isolate_bundle do
16
+ super(...)
17
+ end
18
+ end
19
+
20
+ def isolate_bundle(&block)
21
+ if Bundler.respond_to?(:with_unbundled_env)
22
+ Bundler.with_unbundled_env(&block)
23
+ else
24
+ Bundler.with_clean_env(&block)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CobraCommander
4
+ module Executor
5
+ # Runs an interactive output printer
6
+ class OutputPrompt
7
+ def self.run(pool, output = $stdout)
8
+ new(pool.jobs).run(output)
9
+ end
10
+
11
+ pastel = Pastel.new
12
+ ICONS = {
13
+ nil => pastel.dim("⦻"),
14
+ success: pastel.green("✔"),
15
+ skip: pastel.yellow("↷"),
16
+ error: pastel.red("✖"),
17
+ }.freeze
18
+ CANCELLED = pastel.dim("(cancelled)")
19
+ BYE = pastel.bold("\n\n👋 Bye!")
20
+
21
+ def initialize(jobs)
22
+ @jobs = jobs
23
+ @prompt = TTY::Prompt.new(symbols: { cross: " " })
24
+ end
25
+
26
+ def options
27
+ @options ||= @jobs.map do |job|
28
+ {
29
+ name: format_name(job),
30
+ value: job,
31
+ disabled: !job.resolved? && CANCELLED,
32
+ }
33
+ end
34
+ end
35
+
36
+ def run(output)
37
+ return unless @jobs.any?(&:resolved?)
38
+
39
+ selected = nil
40
+ output.puts
41
+ loop do
42
+ selected = @prompt.select("Print output?", options, default: format_name(selected))
43
+ output.puts nil, selected.output, nil
44
+ rescue TTY::Reader::InputInterrupt
45
+ output.puts BYE
46
+ break
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def format_name(job)
53
+ return unless job
54
+
55
+ "#{ICONS[job.status]} #{job.name}"
56
+ end
57
+ end
58
+ end
59
+ end
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "./job"
4
- require_relative "./package_criteria"
5
-
6
3
  module CobraCommander
7
4
  module Executor
8
5
  module PackageCriteria
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CobraCommander
4
+ module Executor
5
+ module RunScript
6
+ def run_script(tty, script, path)
7
+ result = tty.run!(script, chdir: path, err: :out)
8
+
9
+ return [:error, result.out] if result.failed?
10
+
11
+ [:success, result.out]
12
+ end
13
+
14
+ def run_many(collection, &block)
15
+ collection.lazy.map(&block)
16
+ .reduce do |(_, prev_output), (result, output)|
17
+ new_output = [prev_output&.strip, output&.strip].join("\n")
18
+ return [:error, new_output] if result == :error
19
+
20
+ [:success, new_output]
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -1,44 +1,28 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "./job"
4
-
5
3
  module CobraCommander
6
4
  module Executor
7
- # This is a script job. It can tarket any CobraCommander::Package.
5
+ # This is a script job. It can target any CobraCommander::Component.
8
6
  #
9
- # If you want to target a Component, you can use Script.for to target
10
- # individual paths for each given component.
7
+ # Script runs the given script once for each Component#root_paths
11
8
  #
12
- # @see Script.for
13
9
  class Script
14
- include ::CobraCommander::Executor::Job
15
-
16
- # Returns a set of scripts to be executed on the given commends.
17
- #
18
- # If a component has two packages in the same path, only one script for that component will be
19
- # returned.
20
- #
21
- # @param components [Enumerable<CobraCommander::Component>] the target components
22
- # @param script [String] shell script to run from the directories of the component's packages
23
- # @return [Array<CobraCommander::Executor::Script>]
24
- def self.for(components, script)
25
- components.flat_map(&:packages).uniq(&:path).map do |package|
26
- new(package, script)
27
- end
28
- end
10
+ include ::CobraCommander::Executor::RunScript
29
11
 
30
- def initialize(package, script)
31
- @package = package
12
+ def initialize(script)
32
13
  @script = script
33
14
  end
34
15
 
35
- def to_s
36
- @package.name
37
- end
38
-
39
- # @see CobraCommander::Executor::Job
40
- def call
41
- run_script @script, @package.path
16
+ # Runs the script in the given component
17
+ #
18
+ # It runs the script once for each Component#root_paths. If a component has two packages in the
19
+ # same path, it will run the script only once.
20
+ #
21
+ # @param tty [CobraComander::Executor::IsolatedPTY] tty to execute shell scripts
22
+ # @param component [CobraComander::Component] target component
23
+ # @return [Array<Symbol, String>]
24
+ def call(tty, component)
25
+ run_many(component.root_paths) { run_script(tty, @script, _1) }
42
26
  end
43
27
  end
44
28
  end