cobra_commander 1.1.0 → 1.2.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: 3e4912ef5e1373f254652d50f2c88bd5d6fc2785675f2d53bdf3572ffcbfafaf
4
- data.tar.gz: 5c0bdd82e4ea3fcffeb1f8d7a44aece59ca929d40171f3c22b6a3c95d951b942
3
+ metadata.gz: da1b8808311f316b8e200895575b653357a88b92f8a1d05d833ab8f0bd55b0d5
4
+ data.tar.gz: 442d8ae693c4bac9f3d888a33fc4b5e1d1a5904c681dba43144284651b42abfd
5
5
  SHA512:
6
- metadata.gz: 3d8882fe6141cc4ddc6c7ec92616aceb7010c3d889b8c6b7f2d039d589fcd1c9bed43d8dcac946f239057f27eb2ab51c5cd65a181a838401cff2e38f6edb1e8d
7
- data.tar.gz: ceda5086044a31eae40445597289fae8c23aef320160b07b8d9a1b3fc33ea9318eb2815e97781af5a70f4295842bc59e07e9cc562473fa92933c837db47a9f36
6
+ metadata.gz: '07940522fad6ad8f3220e25f654a19a34a8b61497b0f68c33c368db9926fd8f32446e4423112f91630511c447469866398b152736db79fc726e27dd96809d0c4'
7
+ data.tar.gz: a1e5b9db402504b0114c7cad3a65a4ba22bce8ba003269abb03a824128df5d586c1c39fde4d9132da97d71143b2b3d65bb6966dba464a8068e5193fb159aa373
@@ -23,6 +23,7 @@ Gem::Specification.new do |spec|
23
23
  DESCRIPTION
24
24
  spec.homepage = "http://tech.powerhrg.com/cobra_commander/"
25
25
  spec.license = "MIT"
26
+ spec.required_ruby_version = ">= 3.2.0"
26
27
 
27
28
  spec.metadata["rubygems_mfa_required"] = "true"
28
29
  spec.metadata["homepage_uri"] = spec.homepage
@@ -34,18 +35,18 @@ Gem::Specification.new do |spec|
34
35
  spec.executables = %w[cobra]
35
36
  spec.require_paths = %w[lib]
36
37
 
37
- spec.add_dependency "bundler"
38
+ spec.add_dependency "bundler", ">= 2.4.17"
38
39
  spec.add_dependency "thor", ["< 2.0", ">= 0.18.1"]
39
40
  spec.add_dependency "tty-command", "~> 0.10.0"
40
41
  spec.add_dependency "tty-prompt", "~> 0.23.1"
41
42
 
42
- spec.add_development_dependency "aruba", "~> 0.14.2"
43
- spec.add_development_dependency "bundler"
44
- spec.add_development_dependency "guard-rspec"
45
- spec.add_development_dependency "license_finder", ">= 7.0"
46
- spec.add_development_dependency "pry"
47
- spec.add_development_dependency "rake", ">= 12.3.3"
48
- spec.add_development_dependency "rspec", "~> 3.5"
49
- spec.add_development_dependency "rubocop", "1.30.1"
50
- spec.add_development_dependency "rubocop-powerhome", ">= 0.5.0"
43
+ spec.add_development_dependency "aruba", "0.14.14"
44
+ spec.add_development_dependency "guard-rspec", "4.7.3"
45
+ spec.add_development_dependency "license_finder", "7.1"
46
+ spec.add_development_dependency "ostruct", "0.6.3"
47
+ spec.add_development_dependency "pry", "0.14.2"
48
+ spec.add_development_dependency "rake", "13.0.6"
49
+ spec.add_development_dependency "rspec", "3.13.0"
50
+ spec.add_development_dependency "rubocop", "1.82.1"
51
+ spec.add_development_dependency "rubocop-powerhome", "0.6.1"
51
52
  end
data/docs/CHANGELOG.md CHANGED
@@ -1,6 +1,9 @@
1
1
  # Change Log
2
2
 
3
- ## Unreleased
3
+ ## Version 1.2.0 - 2026-06-09
4
+
5
+ * Add an `around_command` extension point so plugins can enhance the shell used to run `cmd`/`exec`. `Source#around_command` wraps execution (e.g. Bundler isolation) and yields a hash of environment variables for the command (base yields `{}`, scoped per-execution via TTY). Packages delegate to their source; `Component#around_command` nests each distinct source's wrapper and yields their merged env. `exec` applies it once per component (all packages contribute, later sources win); `cmd` applies each package's own. `IsolatedPTY` is now a plain PTY command — isolation comes from the sources.
6
+ * Raise the minimum supported Ruby version to 3.2 and expand CI to cover Ruby 4.0.
4
7
 
5
8
  ## Version 1.1.0 - 2023-03-09
6
9
 
@@ -12,8 +12,8 @@ module CobraCommander
12
12
  @changes = changes
13
13
  end
14
14
 
15
- def each(&block)
16
- (directly | transitively).sort_by(&:name).each(&block)
15
+ def each(&)
16
+ (directly | transitively).sort_by(&:name).each(&)
17
17
  end
18
18
 
19
19
  def directly
@@ -43,12 +43,12 @@ module CobraCommander
43
43
 
44
44
  def add_tee(io, outdents, dep)
45
45
  io.puts line(outdents, TEE, dep.name)
46
- list_dependencies(io, dep, (outdents + [BAR]))
46
+ list_dependencies(io, dep, outdents + [BAR])
47
47
  end
48
48
 
49
49
  def add_corner(io, outdents, dep)
50
50
  io.puts line(outdents, CORNER, dep.name)
51
- list_dependencies(io, dep, (outdents + [SPACE]))
51
+ list_dependencies(io, dep, outdents + [SPACE])
52
52
  end
53
53
 
54
54
  def line(outdents, sym, name)
@@ -73,7 +73,7 @@ module CobraCommander
73
73
  desc "tree [component]", "Prints the dependency tree of a given component or umbrella"
74
74
  def tree(component = nil)
75
75
  components = component ? [find_component(component)] : umbrella.components
76
- puts Output::AsciiTree.new(components).to_s
76
+ puts Output::AsciiTree.new(components)
77
77
  end
78
78
 
79
79
  desc "graph [component]", "Outputs a graph of a given component or umbrella"
@@ -25,6 +25,18 @@ module CobraCommander
25
25
  @packages.map(&:path).uniq
26
26
  end
27
27
 
28
+ # Wraps the execution of a command on this component by nesting the
29
+ # around_command of each distinct source backing its packages, so every
30
+ # package gets a chance to enhance the surrounding process. The env vars
31
+ # each source yields are merged (later sources win) and the merged hash is
32
+ # yielded to the block.
33
+ #
34
+ # @yieldparam env [Hash{String => String}] merged env vars for the command
35
+ # @return the value returned by the block
36
+ def around_command(&)
37
+ nest_sources(@packages.map(&:source).uniq, {}, &)
38
+ end
39
+
28
40
  def inspect
29
41
  "#<CobraCommander::Component:#{object_id} #{name} dependencies=#{dependencies.map(&:name)} packages=#{packages}>"
30
42
  end
@@ -50,5 +62,18 @@ module CobraCommander
50
62
  def dependencies
51
63
  @dependencies ||= @dependency_names.sort.filter_map { |name| @umbrella.find(name) }
52
64
  end
65
+
66
+ private
67
+
68
+ # Nests each source's #around_command, accumulating the env each yields,
69
+ # and finally yields the merged env to the block.
70
+ def nest_sources(sources, env, &block)
71
+ return yield(env) if sources.empty?
72
+
73
+ head, *rest = sources
74
+ head.around_command do |source_env|
75
+ nest_sources(rest, env.merge(source_env), &block)
76
+ end
77
+ end
53
78
  end
54
79
  end
@@ -21,29 +21,31 @@ module CobraCommander
21
21
  # @param package [CobraComander::Package] target package to execute the named command
22
22
  # @return [Array<Symbol, String>]
23
23
  def call(tty, package)
24
- run_command tty, package, @command_name
24
+ package.around_command do |env|
25
+ run_command tty, package, @command_name, env
26
+ end
25
27
  end
26
28
 
27
29
  private
28
30
 
29
- def run_command(tty, package, command_name)
31
+ def run_command(tty, package, command_name, env)
30
32
  definition = package.source.config&.dig("commands", command_name)
31
33
  case definition
32
- when Array then run_multiple(tty, package, definition)
33
- when Hash then run_with_criteria(tty, package, definition)
34
+ when Array then run_multiple(tty, package, definition, env)
35
+ when Hash then run_with_criteria(tty, package, definition, env)
34
36
  when nil then [:skip, format(SKIP_UNEXISTING, command_name, package.key)]
35
- else run_script(tty, definition, package.path)
37
+ else run_script(tty, definition, package.path, env: env)
36
38
  end
37
39
  end
38
40
 
39
- def run_with_criteria(tty, package, command)
41
+ def run_with_criteria(tty, package, command, env)
40
42
  return [:skip, format(SKIP_CRITERIA, package.name)] unless match_criteria?(package, command.fetch("if", {}))
41
43
 
42
- run_script(tty, command["run"], package.path)
44
+ run_script(tty, command["run"], package.path, env: env)
43
45
  end
44
46
 
45
- def run_multiple(tty, package, commands)
46
- run_many(commands) { run_command(tty, package, _1) }
47
+ def run_multiple(tty, package, commands, env)
48
+ run_many(commands) { run_command(tty, package, _1, env) }
47
49
  end
48
50
  end
49
51
  end
@@ -3,26 +3,17 @@
3
3
  module CobraCommander
4
4
  module Executor
5
5
  #
6
- # Executes commands in a clean environment, without the influence
7
- # of the current Bundler env vars.
6
+ # A PTY-enabled TTY::Command used to execute component scripts.
7
+ #
8
+ # Per-execution environment variables are supplied to TTY::Command#run!
9
+ # (so they are scoped to each subprocess and never mutate the parent
10
+ # ENV), while environment isolation/enhancement such as Bundler's
11
+ # `with_unbundled_env` is contributed by the package sources through
12
+ # their #around_command (see CobraCommander::Ruby::Bundle).
8
13
  #
9
14
  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
15
+ def initialize(**)
16
+ super(pty: true, **)
26
17
  end
27
18
  end
28
19
  end
@@ -3,8 +3,8 @@
3
3
  module CobraCommander
4
4
  module Executor
5
5
  module RunScript
6
- def run_script(tty, script, path)
7
- result = tty.run!(script, chdir: path, err: :out)
6
+ def run_script(tty, script, path, env: {})
7
+ result = tty.run!(env, script, chdir: path, err: :out)
8
8
 
9
9
  return [:error, result.out] if result.failed?
10
10
 
@@ -14,10 +14,10 @@ module CobraCommander
14
14
  def run_many(collection, &block)
15
15
  collection.lazy.map(&block)
16
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
17
+ new_output = [prev_output&.strip, output&.strip].join("\n")
18
+ return [:error, new_output] if result == :error
19
19
 
20
- [:success, new_output]
20
+ [:success, new_output]
21
21
  end
22
22
  end
23
23
  end
@@ -22,7 +22,9 @@ module CobraCommander
22
22
  # @param component [CobraComander::Component] target component
23
23
  # @return [Array<Symbol, String>]
24
24
  def call(tty, component)
25
- run_many(component.root_paths) { run_script(tty, @script, _1) }
25
+ component.around_command do |env|
26
+ run_many(component.root_paths) { run_script(tty, @script, _1, env: env) }
27
+ end
26
28
  end
27
29
  end
28
30
  end
@@ -62,7 +62,7 @@ module CobraCommander
62
62
  @jobs = []
63
63
  @queue = Queue.new
64
64
 
65
- push_all(jobs, &(name_f || :describe))
65
+ push_all(jobs, &name_f || :describe)
66
66
  end
67
67
 
68
68
  def error?
@@ -70,7 +70,7 @@ module CobraCommander
70
70
  end
71
71
 
72
72
  def push_all(jobs, &name_f)
73
- jobs.each { push(name_f&.(_1), *Array(_1)) }
73
+ jobs.each { push(name_f&.call(_1), *Array(_1)) }
74
74
  end
75
75
 
76
76
  def push(name, *args)
@@ -32,13 +32,13 @@ module CobraCommander
32
32
  # @param jobs [Enumerable<CobraCommander::Executor::Job>] the jobs to run
33
33
  # @param interactive [Boolean] prefer interactive output
34
34
  # @see CobraCommander::Executor::WorkerPool for more options
35
- def execute_and_handle_exit(jobs:, interactive: false, **kwargs, &name_f)
35
+ def execute_and_handle_exit(jobs:, interactive: false, **, &name_f)
36
36
  printer = if jobs.size == 1 then :quiet
37
37
  elsif interactive then :progress
38
38
  else
39
39
  ::CobraCommander::Executor::BufferedPrinter
40
40
  end
41
- pool = WorkerPool.new(jobs: jobs, printer: printer, **kwargs, &name_f).tap(&:start)
41
+ pool = WorkerPool.new(jobs: jobs, printer: printer, **, &name_f).tap(&:start)
42
42
  return CobraCommander::Executor::OutputPrompt.run(pool) if interactive && jobs.size > 1
43
43
 
44
44
  exit(1) if pool.error?
@@ -19,8 +19,8 @@ module CobraCommander
19
19
  @base_branch = base_branch
20
20
  end
21
21
 
22
- def each(&block)
23
- changes.each(&block)
22
+ def each(&)
23
+ changes.each(&)
24
24
  end
25
25
 
26
26
  private
@@ -9,7 +9,7 @@ module CobraCommander
9
9
 
10
10
  attr_reader :source, :path, :name, :dependencies
11
11
 
12
- def_delegators :source, :key
12
+ def_delegators :source, :key, :around_command
13
13
 
14
14
  def initialize(source, path:, dependencies:, name:)
15
15
  @source = source
@@ -22,8 +22,19 @@ module CobraCommander
22
22
  to_a
23
23
  end
24
24
 
25
- def each(&block)
26
- packages.each(&block)
25
+ # Wraps the execution of commands on this source's packages, letting the
26
+ # source enhance the surrounding process (e.g. Bundler isolation) and
27
+ # contribute environment variables to the command. The base implementation
28
+ # yields an empty env; plugins override it (see CobraCommander::Ruby::Bundle).
29
+ #
30
+ # @yieldparam env [Hash{String => String}] env vars to pass to the command
31
+ # @return the value returned by the block
32
+ def around_command
33
+ yield({})
34
+ end
35
+
36
+ def each(&)
37
+ packages.each(&)
27
38
  rescue Errno::ENOENT => e
28
39
  raise Error, e.message
29
40
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CobraCommander
4
- VERSION = "1.1.0"
4
+ VERSION = "1.2.0"
5
5
  end
metadata CHANGED
@@ -1,16 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cobra_commander
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Langfeld
8
8
  - Garett Arrowood
9
9
  - Carlos Palhares
10
- autorequire:
11
10
  bindir: exe
12
11
  cert_chain: []
13
- date: 2023-03-09 00:00:00.000000000 Z
12
+ date: 1980-01-02 00:00:00.000000000 Z
14
13
  dependencies:
15
14
  - !ruby/object:Gem::Dependency
16
15
  name: bundler
@@ -18,14 +17,14 @@ dependencies:
18
17
  requirements:
19
18
  - - ">="
20
19
  - !ruby/object:Gem::Version
21
- version: '0'
20
+ version: 2.4.17
22
21
  type: :runtime
23
22
  prerelease: false
24
23
  version_requirements: !ruby/object:Gem::Requirement
25
24
  requirements:
26
25
  - - ">="
27
26
  - !ruby/object:Gem::Version
28
- version: '0'
27
+ version: 2.4.17
29
28
  - !ruby/object:Gem::Dependency
30
29
  name: thor
31
30
  requirement: !ruby/object:Gem::Requirement
@@ -78,128 +77,128 @@ dependencies:
78
77
  name: aruba
79
78
  requirement: !ruby/object:Gem::Requirement
80
79
  requirements:
81
- - - "~>"
80
+ - - '='
82
81
  - !ruby/object:Gem::Version
83
- version: 0.14.2
82
+ version: 0.14.14
84
83
  type: :development
85
84
  prerelease: false
86
85
  version_requirements: !ruby/object:Gem::Requirement
87
86
  requirements:
88
- - - "~>"
87
+ - - '='
89
88
  - !ruby/object:Gem::Version
90
- version: 0.14.2
89
+ version: 0.14.14
91
90
  - !ruby/object:Gem::Dependency
92
- name: bundler
91
+ name: guard-rspec
93
92
  requirement: !ruby/object:Gem::Requirement
94
93
  requirements:
95
- - - ">="
94
+ - - '='
96
95
  - !ruby/object:Gem::Version
97
- version: '0'
96
+ version: 4.7.3
98
97
  type: :development
99
98
  prerelease: false
100
99
  version_requirements: !ruby/object:Gem::Requirement
101
100
  requirements:
102
- - - ">="
101
+ - - '='
103
102
  - !ruby/object:Gem::Version
104
- version: '0'
103
+ version: 4.7.3
105
104
  - !ruby/object:Gem::Dependency
106
- name: guard-rspec
105
+ name: license_finder
107
106
  requirement: !ruby/object:Gem::Requirement
108
107
  requirements:
109
- - - ">="
108
+ - - '='
110
109
  - !ruby/object:Gem::Version
111
- version: '0'
110
+ version: '7.1'
112
111
  type: :development
113
112
  prerelease: false
114
113
  version_requirements: !ruby/object:Gem::Requirement
115
114
  requirements:
116
- - - ">="
115
+ - - '='
117
116
  - !ruby/object:Gem::Version
118
- version: '0'
117
+ version: '7.1'
119
118
  - !ruby/object:Gem::Dependency
120
- name: license_finder
119
+ name: ostruct
121
120
  requirement: !ruby/object:Gem::Requirement
122
121
  requirements:
123
- - - ">="
122
+ - - '='
124
123
  - !ruby/object:Gem::Version
125
- version: '7.0'
124
+ version: 0.6.3
126
125
  type: :development
127
126
  prerelease: false
128
127
  version_requirements: !ruby/object:Gem::Requirement
129
128
  requirements:
130
- - - ">="
129
+ - - '='
131
130
  - !ruby/object:Gem::Version
132
- version: '7.0'
131
+ version: 0.6.3
133
132
  - !ruby/object:Gem::Dependency
134
133
  name: pry
135
134
  requirement: !ruby/object:Gem::Requirement
136
135
  requirements:
137
- - - ">="
136
+ - - '='
138
137
  - !ruby/object:Gem::Version
139
- version: '0'
138
+ version: 0.14.2
140
139
  type: :development
141
140
  prerelease: false
142
141
  version_requirements: !ruby/object:Gem::Requirement
143
142
  requirements:
144
- - - ">="
143
+ - - '='
145
144
  - !ruby/object:Gem::Version
146
- version: '0'
145
+ version: 0.14.2
147
146
  - !ruby/object:Gem::Dependency
148
147
  name: rake
149
148
  requirement: !ruby/object:Gem::Requirement
150
149
  requirements:
151
- - - ">="
150
+ - - '='
152
151
  - !ruby/object:Gem::Version
153
- version: 12.3.3
152
+ version: 13.0.6
154
153
  type: :development
155
154
  prerelease: false
156
155
  version_requirements: !ruby/object:Gem::Requirement
157
156
  requirements:
158
- - - ">="
157
+ - - '='
159
158
  - !ruby/object:Gem::Version
160
- version: 12.3.3
159
+ version: 13.0.6
161
160
  - !ruby/object:Gem::Dependency
162
161
  name: rspec
163
162
  requirement: !ruby/object:Gem::Requirement
164
163
  requirements:
165
- - - "~>"
164
+ - - '='
166
165
  - !ruby/object:Gem::Version
167
- version: '3.5'
166
+ version: 3.13.0
168
167
  type: :development
169
168
  prerelease: false
170
169
  version_requirements: !ruby/object:Gem::Requirement
171
170
  requirements:
172
- - - "~>"
171
+ - - '='
173
172
  - !ruby/object:Gem::Version
174
- version: '3.5'
173
+ version: 3.13.0
175
174
  - !ruby/object:Gem::Dependency
176
175
  name: rubocop
177
176
  requirement: !ruby/object:Gem::Requirement
178
177
  requirements:
179
178
  - - '='
180
179
  - !ruby/object:Gem::Version
181
- version: 1.30.1
180
+ version: 1.82.1
182
181
  type: :development
183
182
  prerelease: false
184
183
  version_requirements: !ruby/object:Gem::Requirement
185
184
  requirements:
186
185
  - - '='
187
186
  - !ruby/object:Gem::Version
188
- version: 1.30.1
187
+ version: 1.82.1
189
188
  - !ruby/object:Gem::Dependency
190
189
  name: rubocop-powerhome
191
190
  requirement: !ruby/object:Gem::Requirement
192
191
  requirements:
193
- - - ">="
192
+ - - '='
194
193
  - !ruby/object:Gem::Version
195
- version: 0.5.0
194
+ version: 0.6.1
196
195
  type: :development
197
196
  prerelease: false
198
197
  version_requirements: !ruby/object:Gem::Requirement
199
198
  requirements:
200
- - - ">="
199
+ - - '='
201
200
  - !ruby/object:Gem::Version
202
- version: 0.5.0
201
+ version: 0.6.1
203
202
  description: |
204
203
  Tools for working with Component Based Rails Apps (see https://cbra.info).
205
204
  Includes tools for graphing the components of an app and their relationships, as well as selectively
@@ -248,7 +247,6 @@ metadata:
248
247
  homepage_uri: http://tech.powerhrg.com/cobra_commander/
249
248
  source_code_uri: https://github.com/powerhome/cobra_commander
250
249
  changelog_uri: https://github.com/powerhome/cobra_commander/blob/main/cobra_commander/docs/CHANGELOG.md
251
- post_install_message:
252
250
  rdoc_options: []
253
251
  require_paths:
254
252
  - lib
@@ -256,15 +254,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
256
254
  requirements:
257
255
  - - ">="
258
256
  - !ruby/object:Gem::Version
259
- version: '0'
257
+ version: 3.2.0
260
258
  required_rubygems_version: !ruby/object:Gem::Requirement
261
259
  requirements:
262
260
  - - ">="
263
261
  - !ruby/object:Gem::Version
264
262
  version: '0'
265
263
  requirements: []
266
- rubygems_version: 3.4.6
267
- signing_key:
264
+ rubygems_version: 3.6.9
268
265
  specification_version: 4
269
266
  summary: Tools for working with Component Based Rails Apps
270
267
  test_files: []