cobra_commander 0.14.0 → 0.15.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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +4 -6
  3. data/.github/workflows/release.yml +1 -1
  4. data/.rubocop.yml +9 -16
  5. data/.rubocop_todo.yml +15 -0
  6. data/Rakefile +3 -2
  7. data/cobra_commander.gemspec +5 -4
  8. data/{CHANGELOG.md → docs/CHANGELOG.md} +8 -0
  9. data/{CODE_OF_CONDUCT.md → docs/CODE_OF_CONDUCT.md} +0 -0
  10. data/{README.md → docs/README.md} +31 -18
  11. data/gemfiles/bundler2.gemfile +1 -1
  12. data/lib/cobra_commander/affected.rb +8 -8
  13. data/lib/cobra_commander/change.rb +23 -32
  14. data/lib/cobra_commander/cli/filters.rb +25 -6
  15. data/lib/cobra_commander/cli.rb +12 -11
  16. data/lib/cobra_commander/component.rb +10 -8
  17. data/lib/cobra_commander/dependencies/bundler/package.rb +17 -0
  18. data/lib/cobra_commander/dependencies/bundler.rb +8 -6
  19. data/lib/cobra_commander/dependencies/yarn/package.rb +10 -27
  20. data/lib/cobra_commander/dependencies/yarn.rb +40 -0
  21. data/lib/cobra_commander/dependencies.rb +1 -1
  22. data/lib/cobra_commander/executor/concurrent.rb +2 -2
  23. data/lib/cobra_commander/executor/context.rb +1 -1
  24. data/lib/cobra_commander/executor.rb +1 -1
  25. data/lib/cobra_commander/git_changed.rb +41 -0
  26. data/lib/cobra_commander/output/ascii_tree.rb +4 -4
  27. data/lib/cobra_commander/output/graph_viz.rb +1 -1
  28. data/lib/cobra_commander/output/interactive_printer.rb +4 -4
  29. data/lib/cobra_commander/umbrella.rb +4 -14
  30. data/lib/cobra_commander/version.rb +1 -1
  31. data/lib/cobra_commander.rb +2 -2
  32. data/mkdocs.yml +8 -0
  33. data/portal.yml +12 -0
  34. metadata +36 -18
  35. data/lib/cobra_commander/dependencies/yarn/package_repo.rb +0 -32
  36. data/lib/cobra_commander/dependencies/yarn_workspace.rb +0 -55
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d3e2348a3ed7ceecd361b13fe0632bb5daa54a59652d4dd9eac5646c2ccc5878
4
- data.tar.gz: 49dc4f2937e87a8146c685d82d7d45fea82dd16e3e0b880ef9944c8ac0710b0c
3
+ metadata.gz: 4fe38b5cf9d55a71b6a24111018d90cbd624c4d6bd3a95a7313f9c7afbeb6e92
4
+ data.tar.gz: 4fe0c927cbc3b985c0153849ff48889511dd726e35ddf534dd723cf9c8d18501
5
5
  SHA512:
6
- metadata.gz: 2ca9041bfb43cbec99252e00f52e117d8e2f09778afc686f1b204c4ff2e5733841f10b727adc3e3c9f28b121d61dff6ef4c79745a9e7574eb9bc36c3dd6ee5a9
7
- data.tar.gz: befffb97f5743fce5066db00f5c434053bdebc275c12b74d95c3d33a375b8c9e6bf5e10fa186188a163f1f9c8fd91f01055d56c8880ee40815915878077aebc9
6
+ metadata.gz: e1d80dac7d927f2f6cf754d09f6aa731f95ac7279f49784f3c4d03f1d4373d17cd44edc67c30218af28cdf3957c3042ed683cbd899903fe4cdd568c4b061c116
7
+ data.tar.gz: f87bf50a8747adfc75617b3c55dabd11d1148bfe90587ed07c362d4fe0cfe9d30299889aab1b5fda6b3af4a8993cc26ce0381816d8585bc368fdf4876dee6013
@@ -10,8 +10,6 @@ jobs:
10
10
  fail-fast: false
11
11
  matrix:
12
12
  ruby:
13
- - "2.5"
14
- - "2.6"
15
13
  - "2.7"
16
14
  - "3.0"
17
15
  bundler:
@@ -20,7 +18,7 @@ jobs:
20
18
  env:
21
19
  BUNDLE_GEMFILE: gemfiles/bundler${{ matrix.bundler }}.gemfile
22
20
  steps:
23
- - uses: actions/checkout@v2
21
+ - uses: actions/checkout@v3
24
22
  - uses: ruby/setup-ruby@v1
25
23
  with:
26
24
  ruby-version: ${{ matrix.ruby }}
@@ -36,11 +34,11 @@ jobs:
36
34
  name: Lint Ruby
37
35
  runs-on: ubuntu-latest
38
36
  steps:
39
- - uses: actions/checkout@v2
37
+ - uses: actions/checkout@v3
40
38
  - uses: ruby/setup-ruby@v1
41
39
  with:
42
40
  ruby-version: 3.0
43
41
  - name: Bundle
44
42
  run: bundle
45
- - name: Run standard
46
- run: bundle exec rake standard
43
+ - name: Run Rubocop
44
+ run: bundle exec rubocop
@@ -10,7 +10,7 @@ jobs:
10
10
  build:
11
11
  runs-on: ubuntu-latest
12
12
  steps:
13
- - uses: actions/checkout@v2
13
+ - uses: actions/checkout@v3
14
14
  - name: Release Gem
15
15
  uses: cadwallion/publish-rubygems-action@master
16
16
  if: contains(github.ref, 'refs/tags/v')
data/.rubocop.yml CHANGED
@@ -1,20 +1,13 @@
1
- AllCops:
2
- TargetRubyVersion: 2.5
3
- NewCops: enable
1
+ inherit_from: .rubocop_todo.yml
4
2
 
5
- Metrics/BlockLength:
6
- Exclude:
7
- - spec/**/*.rb
8
- - cobra_commander.gemspec
3
+ require:
4
+ - rubocop-powerhome
9
5
 
10
- Layout/AccessModifierIndentation:
11
- EnforcedStyle: outdent
6
+ Rails:
7
+ Enabled: false
12
8
 
13
- Style/StringLiterals:
14
- EnforcedStyle: double_quotes
9
+ Gemspec/RequireMFA:
10
+ Enabled: false
15
11
 
16
- Style/TrailingCommaInArrayLiteral:
17
- EnforcedStyleForMultiline: consistent_comma
18
-
19
- Style/TrailingCommaInHashLiteral:
20
- EnforcedStyleForMultiline: consistent_comma
12
+ Style/ClassAndModuleChildren:
13
+ Enabled: false
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,15 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2022-08-09 19:10:45 UTC using RuboCop version 1.30.1.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 8
10
+ Performance/MethodObjectAsBlock:
11
+ Exclude:
12
+ - 'lib/cobra_commander/affected.rb'
13
+ - 'lib/cobra_commander/component.rb'
14
+ - 'lib/cobra_commander/dependencies/yarn_workspace.rb'
15
+ - 'lib/cobra_commander/output/interactive_printer.rb'
data/Rakefile CHANGED
@@ -1,9 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "bundler/gem_tasks"
4
- require "standard/rake"
4
+ require "rubocop/rake_task"
5
5
  require "rspec/core/rake_task"
6
6
 
7
7
  RSpec::Core::RakeTask.new(:spec)
8
+ RuboCop::RakeTask.new(:rubocop)
8
9
 
9
- task default: %i[spec standard]
10
+ task default: %i[spec rubocop]
@@ -10,16 +10,16 @@ Gem::Specification.new do |spec|
10
10
  spec.authors = [
11
11
  "Ben Langfeld",
12
12
  "Garett Arrowood",
13
- "Carlos Palhares"
13
+ "Carlos Palhares",
14
14
  ]
15
15
  spec.email = [
16
16
  "blangfeld@powerhrg.com",
17
17
  "garett.arrowood@powerhrg.com",
18
- "carlos.palhares@powerhrg.com"
18
+ "carlos.palhares@powerhrg.com",
19
19
  ]
20
20
  spec.summary = "Tools for working with Component Based Rails Apps"
21
21
  spec.description = <<~DESCRIPTION
22
- Tools for working with Component Based Rails Apps (see http://shageman.github.io/cbra.info/).
22
+ Tools for working with Component Based Rails Apps (see https://cbra.info).
23
23
  Includes tools for graphing the components of an app and their relationships, as well as selectively
24
24
  testing components based on changes made.
25
25
  DESCRIPTION
@@ -47,5 +47,6 @@ Gem::Specification.new do |spec|
47
47
  spec.add_development_dependency "pry"
48
48
  spec.add_development_dependency "rake", ">= 12.3.3"
49
49
  spec.add_development_dependency "rspec", "~> 3.5"
50
- spec.add_development_dependency "standard", ">= 1.3.0"
50
+ spec.add_development_dependency "rubocop", "1.30.1"
51
+ spec.add_development_dependency "rubocop-powerhome", ">= 0.5.0"
51
52
  end
@@ -2,6 +2,14 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## Version 0.15.0 - 2022-08-16
6
+
7
+ * Add `--affected` filter to `cobra ls` and `cobra exec`, to target all components affected by changes since given branch [#80](https://github.com/powerhome/cobra_commander/pull/80)
8
+ * Allows a comma separated list of components on `cobra ls` and `cobra exec` instead of a single component [#79](https://github.com/powerhome/cobra_commander/pull/79)
9
+ * Resolve YARN dependencies based on yarn workspaces info workspaceDependencies [#81](https://github.com/powerhome/cobra_commander/pull/81)
10
+ * Fix cbra.info links [#70](https://github.com/powerhome/cobra_commander/pull/70)
11
+ * Replace standardrb by rubocop-powerhome [#78](https://github.com/powerhome/cobra_commander/pull/78)
12
+
5
13
  ## Version 0.14.0 - 2021-11-24
6
14
 
7
15
  * Retain selection on Interactive Printer [#69](https://github.com/powerhome/cobra_commander/pull/69)
File without changes
@@ -5,7 +5,7 @@
5
5
  [![CI](https://github.com/powerhome/cobra_commander/actions/workflows/ci.yml/badge.svg)](https://github.com/powerhome/cobra_commander/actions/workflows/ci.yml)
6
6
  [![Maintainability](https://api.codeclimate.com/v1/badges/7fe0781c18f6923ab753/maintainability)](https://codeclimate.com/github/powerhome/cobra_commander/maintainability)
7
7
 
8
- Tools for working with Component Based Rails Apps (see https://cbra.info/). Includes tools for graphing both Ruby and Javascript components in an application and their relationships, as well as selectively testing components based on changes made.
8
+ Tools for working with Component Based Rails Apps (see https://cbra.info). Includes tools for graphing both Ruby and Javascript components in an application and their relationships, as well as selectively testing components based on changes made.
9
9
 
10
10
  ## Installation
11
11
 
@@ -28,16 +28,16 @@ Or install it yourself as:
28
28
  ```bash
29
29
  Commands:
30
30
  cobra changes [--results=RESULTS] [--branch=BRANCH] # Prints list of changed files
31
- cobra exec [component] <command> # Executes the command in the context of a given component or set of components. If no component is given executes the command in all components.
31
+ cobra exec [components] <command> # Executes the command in the context of a given component or set thereof. Defaults to all components.
32
32
  cobra graph [component] # Outputs a graph of a given component or umbrella
33
33
  cobra help [COMMAND] # Describe available commands or one specific command
34
- cobra ls [component] # Lists the components in the context of a given component or umbrella
34
+ cobra ls [components] # Lists the components in the context of a given component or umbrella
35
35
  cobra tree [component] # Prints the dependency tree of a given component or umbrella
36
36
  cobra version # Prints version
37
37
 
38
38
  Options:
39
39
  -a, [--app=APP]
40
- # Default: /Users/chjunior/workspace/power/cobra_commander
40
+ # Default: /Users/me/myapp
41
41
  [--js], [--no-js] # Consider only the JS dependency graph
42
42
  [--ruby], [--no-ruby] # Consider only the Ruby dependency graph
43
43
  ```
@@ -45,7 +45,6 @@ Options:
45
45
  ### cobra changes
46
46
 
47
47
  ```sh
48
- ➜ nitro git:(nova/remove-cobra-commander) be cobra help changes
49
48
  Usage:
50
49
  cobra changes [--results=RESULTS] [--branch=BRANCH]
51
50
 
@@ -55,7 +54,7 @@ Options:
55
54
  -b, [--branch=BRANCH] # Specified target to calculate against
56
55
  # Default: master
57
56
  -a, [--app=APP]
58
- # Default: /Users/chjunior/workspace/power/nitro
57
+ # Default: /Users/me/myapp
59
58
  [--js], [--no-js] # Consider only the JS dependency graph
60
59
  [--ruby], [--no-ruby] # Consider only the Ruby dependency graph
61
60
 
@@ -66,17 +65,26 @@ Prints list of changed files
66
65
 
67
66
  ```sh
68
67
  Usage:
69
- cobra exec [component] <command>
68
+ cobra exec [components] <command>
69
+
70
+ [components] is all components by default, or a comma separated list of component names (no spaces between)
70
71
 
71
72
  Options:
72
- [--dependencies], [--no-dependencies] # Run the command on each dependency of a given component
73
- [--dependents], [--no-dependents] # Run the command on each dependency of a given component
73
+ [--affected=AFFECTED] # Components affected since given branch [default: main]
74
+ -d, [--dependencies], [--no-dependencies] # Run the command on each dependency of a given component
75
+ -D, [--dependents], [--no-dependents] # Run the command on each dependent of a given component
76
+ [--self], [--no-self] # Include the own component
77
+ # Default: true
78
+ -c, [--concurrency=N] # Max number of jobs to run concurrently
79
+ # Default: 5
80
+ -i, [--interactive], [--no-interactive] # Runs in interactive mode to allow the user to inspect the output of each component
81
+ # Default: true
74
82
  -a, [--app=APP]
75
- # Default: /Users/chjunior/workspace/power/cobra_commander
83
+ # Default: /Users/me/myapp
76
84
  [--js], [--no-js] # Consider only the JS dependency graph
77
85
  [--ruby], [--no-ruby] # Consider only the Ruby dependency graph
78
86
 
79
- Executes the command in the context of a given component or set of components. If no component is given executes the command in all components.
87
+ Executes the command in the context of a given component or set thereof. Defaults to all components.
80
88
  ```
81
89
 
82
90
  ### cobra graph
@@ -87,9 +95,9 @@ Usage:
87
95
 
88
96
  Options:
89
97
  -o, [--output=OUTPUT] # Output file, accepts .png or .dot
90
- # Default: /Users/chjunior/workspace/power/cobra_commander/output.png
98
+ # Default: /Users/me/myapp/output.png
91
99
  -a, [--app=APP]
92
- # Default: /Users/chjunior/workspace/power/cobra_commander
100
+ # Default: /Users/me/myapp
93
101
  [--js], [--no-js] # Consider only the JS dependency graph
94
102
  [--ruby], [--no-ruby] # Consider only the Ruby dependency graph
95
103
 
@@ -100,14 +108,19 @@ Outputs a graph of a given component or umbrella
100
108
 
101
109
  ```sh
102
110
  Usage:
103
- cobra ls [component]
111
+ cobra ls [components]
112
+
113
+ [components] is all components by default, or a comma separated list of component names (no spaces between)
104
114
 
105
115
  Options:
106
- -d, [--dependencies], [--no-dependencies] # Run the command on each dependency of a given component
107
- -D, [--dependents], [--no-dependents] # Run the command on each dependency of a given component
116
+ [--affected=AFFECTED] # Components affected since given branch [default: main]
117
+ -d, [--dependencies], [--no-dependencies] # Lists all dependencies of a given component
118
+ -D, [--dependents], [--no-dependents] # Lists all dependents of a given component
119
+ [--self], [--no-self] # Include the own component
120
+ # Default: true
108
121
  -t, [--total], [--no-total] # Prints the total count of components
109
122
  -a, [--app=APP]
110
- # Default: /Users/chjunior/workspace/power/cobra_commander
123
+ # Default: /Users/me/myapp
111
124
  [--js], [--no-js] # Consider only the JS dependency graph
112
125
  [--ruby], [--no-ruby] # Consider only the Ruby dependency graph
113
126
 
@@ -122,7 +135,7 @@ Usage:
122
135
 
123
136
  Options:
124
137
  -a, [--app=APP]
125
- # Default: /Users/chjunior/workspace/power/cobra_commander
138
+ # Default: /Users/me/myapp
126
139
  [--js], [--no-js] # Consider only the JS dependency graph
127
140
  [--ruby], [--no-ruby] # Consider only the Ruby dependency graph
128
141
 
@@ -4,4 +4,4 @@ source "https://rubygems.org"
4
4
 
5
5
  gemspec path: "../"
6
6
 
7
- gem "bundler", "~> 2.2.11"
7
+ gem "bundler", "~> 2.3.5"
@@ -32,11 +32,11 @@ module CobraCommander
32
32
  transitively_affected_components: transitively,
33
33
  test_scripts: scripts,
34
34
  component_names: names,
35
- languages: {ruby: contains_ruby?, javascript: contains_js?}
35
+ languages: { ruby: contains_ruby?, javascript: contains_js? },
36
36
  }.to_json
37
37
  end
38
38
 
39
- private
39
+ private
40
40
 
41
41
  def run!
42
42
  @transitively = Set.new
@@ -65,7 +65,7 @@ module CobraCommander
65
65
  {
66
66
  name: component.name,
67
67
  path: component.root_paths,
68
- type: component.sources.keys.map(&:to_s).map(&:capitalize).join(" & ")
68
+ type: component.packages.keys.map(&:to_s).map(&:capitalize).join(" & "),
69
69
  }
70
70
  end
71
71
 
@@ -74,23 +74,23 @@ module CobraCommander
74
74
  end
75
75
 
76
76
  def paths
77
- @paths ||= all_affected.map(&:root_paths).flatten.uniq
77
+ @paths ||= all_affected.map(&:root_paths).flatten
78
78
  end
79
79
 
80
- def all_affected_sources
80
+ def all_affected_packages
81
81
  all_affected
82
- .map(&:sources)
82
+ .map(&:packages)
83
83
  .map(&:keys)
84
84
  .flatten
85
85
  .uniq
86
86
  end
87
87
 
88
88
  def contains_ruby?
89
- all_affected_sources.include?(:bundler)
89
+ all_affected_packages.include?(:bundler)
90
90
  end
91
91
 
92
92
  def contains_js?
93
- all_affected_sources.include?(:yarn)
93
+ all_affected_packages.include?(:yarn)
94
94
  end
95
95
  end
96
96
  end
@@ -1,34 +1,37 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "cobra_commander/git_changed"
3
4
  require "cobra_commander/affected"
4
- require "open3"
5
5
 
6
6
  module CobraCommander
7
7
  # Calculates and prints affected components & files
8
8
  class Change
9
9
  InvalidSelectionError = Class.new(StandardError)
10
10
 
11
- def initialize(umbrella, results, branch)
12
- @root_dir = Dir.chdir(umbrella.path) { `git rev-parse --show-toplevel`.chomp }
13
- @results = results
11
+ def initialize(umbrella, oformat, branch, changes: nil)
12
+ @format = oformat
14
13
  @branch = branch
15
14
  @umbrella = umbrella
16
- @affected = Affected.new(@umbrella, changes)
15
+ @changes = changes || GitChanged.new(umbrella.path, branch)
17
16
  end
18
17
 
19
18
  def run!
20
19
  assert_valid_result_choice
21
- if selected_result?("json")
22
- puts @affected.json_representation
20
+ if selected_format?("json")
21
+ puts affected.json_representation
23
22
  else
24
- show_full if selected_result?("full")
23
+ show_full if selected_format?("full")
25
24
  tests_to_run
26
25
  end
27
- rescue InvalidSelectionError => e
26
+ rescue GitChanged::InvalidSelectionError => e
28
27
  puts e.message
29
28
  end
30
29
 
31
- private
30
+ private
31
+
32
+ def affected
33
+ @affected ||= Affected.new(@umbrella, @changes)
34
+ end
32
35
 
33
36
  def show_full
34
37
  changes_since_last_commit
@@ -36,52 +39,40 @@ module CobraCommander
36
39
  transitively_affected_components
37
40
  end
38
41
 
39
- def changes
40
- @changes ||= begin
41
- diff, _, result = Dir.chdir(@root_dir) do
42
- Open3.capture3("git", "diff", "--name-only", @branch)
43
- end
44
-
45
- raise InvalidSelectionError, "Specified --branch could not be found" if result.exitstatus == 128
46
-
47
- diff.split("\n").map { |f| File.join(@root_dir, f) }
48
- end
49
- end
50
-
51
42
  def assert_valid_result_choice
52
- return if %w[test full name json].include?(@results)
43
+ return if %w[test full name json].include?(@format)
53
44
 
54
45
  raise InvalidSelectionError, "--results must be 'test', 'full', 'name' or 'json'"
55
46
  end
56
47
 
57
- def selected_result?(result)
58
- @results == result
48
+ def selected_format?(result)
49
+ @format == result
59
50
  end
60
51
 
61
52
  def changes_since_last_commit
62
53
  puts "<<< Changes since last commit on #{@branch} >>>"
63
- changes.each { |path| puts path }
54
+ puts(*@changes) if @changes.any?
64
55
  puts blank_line
65
56
  end
66
57
 
67
58
  def directly_affected_components
68
59
  puts "<<< Directly affected components >>>"
69
- @affected.directly.each { |component| puts display(**component) }
60
+ affected.directly.each { |component| puts display(**component) }
70
61
  puts blank_line
71
62
  end
72
63
 
73
64
  def transitively_affected_components
74
65
  puts "<<< Transitively affected components >>>"
75
- @affected.transitively.each { |component| puts display(**component) }
66
+ affected.transitively.each { |component| puts display(**component) }
76
67
  puts blank_line
77
68
  end
78
69
 
79
70
  def tests_to_run
80
- puts "<<< Test scripts to run >>>" if selected_result?("full")
81
- if selected_result?("name")
82
- @affected.names.each { |component_name| puts component_name }
71
+ puts "<<< Test scripts to run >>>" if selected_format?("full")
72
+ if selected_format?("name")
73
+ affected.names.each { |component_name| puts component_name }
83
74
  else
84
- @affected.scripts.each { |component_script| puts component_script }
75
+ affected.scripts.each { |component_script| puts component_script }
85
76
  end
86
77
  end
87
78
 
@@ -4,12 +4,13 @@ module CobraCommander
4
4
  # @private
5
5
  class CLI
6
6
  private_class_method def self.filter_options(dependents:, dependencies:)
7
+ method_option :affected, type: :string, desc: "Components affected since given branch [default: main]"
7
8
  method_option :dependencies, type: :boolean, aliases: "-d", desc: dependencies
8
9
  method_option :dependents, type: :boolean, aliases: "-D", desc: dependents
9
10
  method_option :self, type: :boolean, default: true, desc: "Include the own component"
10
11
  end
11
12
 
12
- private
13
+ private
13
14
 
14
15
  def find_component(name)
15
16
  return umbrella.root unless name
@@ -28,13 +29,31 @@ module CobraCommander
28
29
  []
29
30
  end
30
31
 
31
- def components_filtered(component_name)
32
- return umbrella.components unless component_name
32
+ def affected_by_changes(origin_branch)
33
+ changes = GitChanged.new(umbrella.path, origin_branch)
34
+ Affected.new(umbrella, changes).all_affected
35
+ end
33
36
 
37
+ def filter_component(component_name)
34
38
  component = find_component(component_name)
35
- components = options.self ? [component] : []
36
- components.concat component.deep_dependencies if options.dependencies
37
- components.concat component.deep_dependents if options.dependents
39
+ components = []
40
+ components << component if options.self
41
+ components += component.deep_dependencies if options.dependencies
42
+ components += component.deep_dependents if options.dependents
43
+ components
44
+ end
45
+
46
+ def filter_components(component_names)
47
+ component_names.reduce(Set.new) do |set, name|
48
+ set | filter_component(name)
49
+ end
50
+ end
51
+
52
+ protected
53
+
54
+ def components_filtered(names)
55
+ components = names ? filter_components(names.split(",")) : umbrella.components
56
+ components &= affected_by_changes(options.affected) if options.affected
38
57
  components
39
58
  end
40
59
  end
@@ -7,6 +7,7 @@ require "concurrent-ruby"
7
7
  require "cobra_commander"
8
8
  require "cobra_commander/affected"
9
9
  require "cobra_commander/change"
10
+ require "cobra_commander/git_changed"
10
11
  require "cobra_commander/executor"
11
12
  require "cobra_commander/output"
12
13
 
@@ -26,28 +27,28 @@ module CobraCommander
26
27
  puts CobraCommander::VERSION
27
28
  end
28
29
 
29
- desc "ls [component]", "Lists the components in the context of a given component or umbrella"
30
+ desc "ls [components]", "Lists the components in the context of a given component or umbrella"
30
31
  filter_options dependents: "Lists all dependents of a given component",
31
- dependencies: "Lists all dependencies of a given component"
32
+ dependencies: "Lists all dependencies of a given component"
32
33
  method_option :total, type: :boolean, aliases: "-t", desc: "Prints the total count of components"
33
- def ls(component = nil)
34
- components = components_filtered(component)
34
+ def ls(components = nil)
35
+ components = components_filtered(components)
35
36
  puts options.total ? components.size : CobraCommander::Output::FlatList.new(components).to_s
36
37
  end
37
38
 
38
- desc "exec [component] <command>", "Executes the command in the context of a given component or set thereof. " \
39
- "Defaults to all components."
39
+ desc "exec [components] <command>", "Executes the command in the context of a given component or set thereof. " \
40
+ "Defaults to all components."
40
41
  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
+ dependencies: "Run the command on each dependency of a given component"
42
43
  method_option :concurrency, type: :numeric, default: DEFAULT_CONCURRENCY, aliases: "-c",
43
44
  desc: "Max number of jobs to run concurrently"
44
45
  method_option :interactive, type: :boolean, default: true, aliases: "-i",
45
46
  desc: "Runs in interactive mode to allow the user to inspect the output of each " \
46
47
  "component"
47
- def exec(command_or_component, command = nil)
48
+ def exec(command_or_components, command = nil)
48
49
  results = CobraCommander::Executor.exec(
49
- components: components_filtered(command && command_or_component),
50
- command: command || command_or_component,
50
+ components: components_filtered(command && command_or_components),
51
+ command: command || command_or_components,
51
52
  concurrency: options.concurrency, status_output: $stderr
52
53
  )
53
54
  if options.interactive && results.size > 1
@@ -83,7 +84,7 @@ module CobraCommander
83
84
  Change.new(umbrella, options.results, options.branch).run!
84
85
  end
85
86
 
86
- private
87
+ private
87
88
 
88
89
  def umbrella
89
90
  @umbrella ||= CobraCommander.umbrella(options.app, yarn: options.js, bundler: options.ruby)
@@ -3,22 +3,24 @@
3
3
  module CobraCommander
4
4
  # Represents a component withing an Umbrella
5
5
  class Component
6
- attr_reader :name, :sources
6
+ attr_reader :name, :packages
7
7
 
8
8
  def initialize(umbrella, name)
9
9
  @umbrella = umbrella
10
10
  @name = name
11
11
  @dependency_names = []
12
- @sources = {}
12
+ @packages = {}
13
13
  end
14
14
 
15
- def add_source(key, path, dependency_names)
16
- @sources[key] = path
17
- @dependency_names |= dependency_names
15
+ def add_package(key, package)
16
+ @packages[key] = package
17
+ @dependency_names |= package.dependencies
18
18
  end
19
19
 
20
20
  def root_paths
21
- @sources.values.map(&File.method(:dirname)).uniq
21
+ @packages.values.map do |package|
22
+ File.dirname(package.path)
23
+ end.uniq
22
24
  end
23
25
 
24
26
  def inspect
@@ -45,8 +47,8 @@ module CobraCommander
45
47
 
46
48
  def dependencies
47
49
  @dependencies ||= @dependency_names.sort
48
- .map(&@umbrella.method(:find))
49
- .compact
50
+ .map(&@umbrella.method(:find))
51
+ .compact
50
52
  end
51
53
  end
52
54
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CobraCommander
4
+ module Dependencies
5
+ # Calculates ruby bundler dependencies
6
+ class Bundler::Package
7
+ attr_reader :path, :name, :dependencies
8
+
9
+ def initialize(spec = nil, path: spec&.loaded_from, name: spec&.name, dependencies: spec&.dependencies)
10
+ @spec = spec
11
+ @path = path
12
+ @name = name
13
+ @dependencies = dependencies&.map(&:name)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -8,6 +8,8 @@ module CobraCommander
8
8
  module Dependencies
9
9
  # Calculates ruby bundler dependencies
10
10
  class Bundler
11
+ autoload :Package, "cobra_commander/dependencies/bundler/package"
12
+
11
13
  attr_reader :path
12
14
 
13
15
  def initialize(root)
@@ -15,17 +17,17 @@ module CobraCommander
15
17
  @path = @root.join("Gemfile.lock").realpath
16
18
  end
17
19
 
18
- def dependencies
19
- lockfile.dependencies.values.map(&:name)
20
+ def root
21
+ Package.new(path: path, dependencies: lockfile.dependencies.values)
20
22
  end
21
23
 
22
- def components
23
- components_source.specs.map do |spec|
24
- {path: spec.loaded_from, name: spec.name, dependencies: spec.dependencies.map(&:name)}
24
+ def packages
25
+ @packages ||= components_source.specs.map do |spec|
26
+ Package.new(spec)
25
27
  end
26
28
  end
27
29
 
28
- private
30
+ private
29
31
 
30
32
  def lockfile
31
33
  @lockfile ||= ::Bundler::LockfileParser.new(::Bundler.read_file(path))
@@ -1,37 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "json"
4
- require "pathname"
5
-
6
3
  module CobraCommander
7
4
  module Dependencies
8
- module Yarn
9
- # Represents an Yarn package.json file
10
- class Package
11
- attr_reader :path
12
-
13
- def initialize(path)
14
- @path = ::Pathname.new(File.join(path, "package.json")).realpath
15
- end
16
-
17
- def project_tag
18
- name.match(%r{^@[\w-]+/}).to_s
19
- end
5
+ class Yarn::Package
6
+ attr_reader :path, :name, :dependencies
20
7
 
21
- def name
22
- json["name"]
23
- end
24
-
25
- def dependencies
26
- json.fetch("dependencies", {})
27
- .merge(json.fetch("devDependencies", {}))
28
- end
8
+ def initialize(path:, dependencies:, name: nil)
9
+ @path = path
10
+ @name = untag(name)
11
+ @dependencies = dependencies.map { |dep| untag(dep) }
12
+ end
29
13
 
30
- private
14
+ private
31
15
 
32
- def json
33
- @json ||= JSON.parse(File.read(@path))
34
- end
16
+ def untag(name)
17
+ name&.gsub(%r{^@[\w-]+/}, "")
35
18
  end
36
19
  end
37
20
  end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "open3"
5
+ require "pathname"
6
+
7
+ module CobraCommander
8
+ module Dependencies
9
+ # Yarn workspace components source for an umbrella
10
+ class Yarn
11
+ PACKAGE_FILE = "package.json"
12
+
13
+ autoload :Package, "cobra_commander/dependencies/yarn/package"
14
+
15
+ def initialize(root_path)
16
+ @root_path = Pathname.new(root_path)
17
+ end
18
+
19
+ def root
20
+ @root ||= Package.new(
21
+ path: @root_path.join(PACKAGE_FILE).realpath,
22
+ dependencies: packages.map(&:name)
23
+ )
24
+ end
25
+
26
+ def packages
27
+ @packages ||= begin
28
+ output, = Open3.capture2("yarn workspaces --json info", chdir: @root_path.to_s)
29
+ JSON.parse(JSON.parse(output)["data"]).map do |name, spec|
30
+ Package.new(
31
+ path: @root_path.join(spec["location"], PACKAGE_FILE).realpath,
32
+ dependencies: spec["workspaceDependencies"],
33
+ name: name
34
+ )
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "dependencies/yarn_workspace"
3
+ require_relative "dependencies/yarn"
4
4
  require_relative "dependencies/bundler"
@@ -23,7 +23,7 @@ module CobraCommander
23
23
  @results
24
24
  end
25
25
 
26
- private
26
+ private
27
27
 
28
28
  def pastel
29
29
  @pastel ||= Pastel.new
@@ -33,7 +33,7 @@ module CobraCommander
33
33
  @spinner_options ||= {
34
34
  format: :bouncing,
35
35
  success_mark: pastel.green("[DONE]"),
36
- error_mark: pastel.red("[ERROR]")
36
+ error_mark: pastel.red("[ERROR]"),
37
37
  }
38
38
  end
39
39
 
@@ -35,7 +35,7 @@ module CobraCommander
35
35
  results.join("\n")
36
36
  end
37
37
 
38
- private
38
+ private
39
39
 
40
40
  def isolate_bundle(&block)
41
41
  if Bundler.respond_to?(:with_unbundled_env)
@@ -8,7 +8,7 @@ module CobraCommander
8
8
  module Executor
9
9
  def self.exec(components:, command:, concurrency:, status_output:)
10
10
  Concurrent.new(components, concurrency: concurrency, spin_output: status_output)
11
- .exec(command)
11
+ .exec(command)
12
12
  end
13
13
  end
14
14
  end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "open3"
4
+
5
+ module CobraCommander
6
+ # List of files changed in a git repository in the current branch in relation
7
+ # to the give base branch
8
+ #
9
+ # @private
10
+ #
11
+ class GitChanged
12
+ include Enumerable
13
+
14
+ InvalidSelectionError = Class.new(StandardError)
15
+
16
+ def initialize(repo_root, base_branch)
17
+ @repo_root = repo_root
18
+ @base_branch = base_branch
19
+ end
20
+
21
+ def each(&block)
22
+ changes.each(&block)
23
+ end
24
+
25
+ private
26
+
27
+ def changes
28
+ @changes ||= begin
29
+ diff, _, result = Dir.chdir(@repo_root) do
30
+ Open3.capture3("git", "diff", "--name-only", @base_branch)
31
+ end
32
+
33
+ raise InvalidSelectionError, "Specified branch #{@base_branch} could not be found" if result.exitstatus == 128
34
+
35
+ diff.split("\n").map do |f|
36
+ File.join(@repo_root, f)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -22,7 +22,7 @@ module CobraCommander
22
22
  end.string
23
23
  end
24
24
 
25
- private
25
+ private
26
26
 
27
27
  def list_dependencies(io, component, outdents = [])
28
28
  component.dependencies.each do |dep|
@@ -32,10 +32,10 @@ module CobraCommander
32
32
  end
33
33
 
34
34
  def decide_on_line(io, parent, dep, outdents)
35
- if parent.dependencies.last != dep
36
- add_tee(io, outdents, dep)
37
- else
35
+ if parent.dependencies.last == dep
38
36
  add_corner(io, outdents, dep)
37
+ else
38
+ add_tee(io, outdents, dep)
39
39
  end
40
40
  end
41
41
 
@@ -17,7 +17,7 @@ module CobraCommander
17
17
  end
18
18
 
19
19
  private_class_method def self.extract_format(output)
20
- format = output[-3..-1] # standard:disable Style/SlicingWithRange
20
+ format = output[-3..]
21
21
  return format if %w[png dot].include?(format)
22
22
 
23
23
  raise ArgumentError, "output format must be 'png' or 'dot'"
@@ -8,8 +8,8 @@ module CobraCommander
8
8
  # Runs an interactive output printer
9
9
  class InteractivePrinter
10
10
  pastel = Pastel.new
11
- SUCCESS = "#{pastel.green("")} %s"
12
- ERROR = "#{pastel.red("")} %s"
11
+ SUCCESS = "#{pastel.green('')} %s"
12
+ ERROR = "#{pastel.red('')} %s"
13
13
  BYE = pastel.decorate("\n\n👋 Bye!", :white, :on_black, :bold).freeze
14
14
 
15
15
  def self.run(contexts, output)
@@ -31,11 +31,11 @@ module CobraCommander
31
31
  output.puts BYE
32
32
  end
33
33
 
34
- private
34
+ private
35
35
 
36
36
  def map_options(contexts)
37
37
  contexts.sort(&method(:sort_contexts))
38
- .reduce({}) do |options, context|
38
+ .reduce({}) do |options, context|
39
39
  template = context.success? ? SUCCESS : ERROR
40
40
  options.merge format(template, context.component_name) => context
41
41
  end
@@ -28,25 +28,15 @@ module CobraCommander
28
28
  end
29
29
 
30
30
  def add_source(key, source)
31
- @root_component.add_source key, source.path, source.dependencies
32
- source.components.each do |component|
33
- @components[component[:name]] ||= Component.new(self, component[:name])
34
- @components[component[:name]].add_source key, component[:path], component[:dependencies]
31
+ @root_component.add_package key, source.root
32
+ source.packages.each do |packages|
33
+ @components[packages.name] ||= Component.new(self, packages.name)
34
+ @components[packages.name].add_package key, packages
35
35
  end
36
36
  end
37
37
 
38
38
  def components
39
39
  @components.values
40
40
  end
41
-
42
- def dependents_of(component)
43
- find(component)&.deep_dependents
44
- &.sort_by(&:name)
45
- end
46
-
47
- def dependencies_of(name)
48
- find(name)&.deep_dependencies
49
- &.sort_by(&:name)
50
- end
51
41
  end
52
42
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CobraCommander
4
- VERSION = "0.14.0"
4
+ VERSION = "0.15.0"
5
5
  end
@@ -5,7 +5,7 @@ require "cobra_commander/component"
5
5
  require "cobra_commander/umbrella"
6
6
  require "cobra_commander/version"
7
7
 
8
- # Tools for working with Component Based Rails Apps (see http://shageman.github.io/cbra.info/).
8
+ # Tools for working with Component Based Rails Apps (see https://cbra.info).
9
9
  # Includes tools for graphing the components of an app and their relationships, as well as selectively
10
10
  # testing components based on changes made.
11
11
  module CobraCommander
@@ -13,7 +13,7 @@ module CobraCommander
13
13
 
14
14
  def self.umbrella(root_path, yarn: false, bundler: false, name: UMBRELLA_APP_NAME)
15
15
  umbrella = Umbrella.new(name, root_path)
16
- umbrella.add_source(:yarn, Dependencies::YarnWorkspace.new(root_path)) unless bundler
16
+ umbrella.add_source(:yarn, Dependencies::Yarn.new(root_path)) unless bundler
17
17
  umbrella.add_source(:bundler, Dependencies::Bundler.new(root_path)) unless yarn
18
18
  umbrella
19
19
  end
data/mkdocs.yml ADDED
@@ -0,0 +1,8 @@
1
+ site_name: Cobra Commander
2
+ site_description: Cobra Commander Documentation
3
+ nav:
4
+ - "Home": "README.md"
5
+ - "Changelog": "CHANGELOG.md"
6
+ - "Code of Conduct": "CODE_OF_CONDUCT.md"
7
+ plugins:
8
+ - techdocs-core
data/portal.yml ADDED
@@ -0,0 +1,12 @@
1
+ apiVersion: backstage.io/v1alpha1
2
+ kind: Component
3
+ metadata:
4
+ name: cobra-commander
5
+ title: Cobra Commander
6
+ description: Tools for working with Component Based Rails Apps
7
+ annotations:
8
+ backstage.io/techdocs-ref: dir:.
9
+ spec:
10
+ type: library
11
+ owner: heroes-for-hire
12
+ lifecycle: production
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.14.0
4
+ version: 0.15.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-11-24 00:00:00.000000000 Z
13
+ date: 2022-08-17 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: bundler
@@ -58,22 +58,22 @@ dependencies:
58
58
  name: thor
59
59
  requirement: !ruby/object:Gem::Requirement
60
60
  requirements:
61
- - - ">="
62
- - !ruby/object:Gem::Version
63
- version: 0.18.1
64
61
  - - "<"
65
62
  - !ruby/object:Gem::Version
66
63
  version: '2.0'
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: 0.18.1
67
67
  type: :runtime
68
68
  prerelease: false
69
69
  version_requirements: !ruby/object:Gem::Requirement
70
70
  requirements:
71
- - - ">="
72
- - !ruby/object:Gem::Version
73
- version: 0.18.1
74
71
  - - "<"
75
72
  - !ruby/object:Gem::Version
76
73
  version: '2.0'
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: 0.18.1
77
77
  - !ruby/object:Gem::Dependency
78
78
  name: tty-command
79
79
  requirement: !ruby/object:Gem::Requirement
@@ -201,21 +201,35 @@ dependencies:
201
201
  - !ruby/object:Gem::Version
202
202
  version: '3.5'
203
203
  - !ruby/object:Gem::Dependency
204
- name: standard
204
+ name: rubocop
205
+ requirement: !ruby/object:Gem::Requirement
206
+ requirements:
207
+ - - '='
208
+ - !ruby/object:Gem::Version
209
+ version: 1.30.1
210
+ type: :development
211
+ prerelease: false
212
+ version_requirements: !ruby/object:Gem::Requirement
213
+ requirements:
214
+ - - '='
215
+ - !ruby/object:Gem::Version
216
+ version: 1.30.1
217
+ - !ruby/object:Gem::Dependency
218
+ name: rubocop-powerhome
205
219
  requirement: !ruby/object:Gem::Requirement
206
220
  requirements:
207
221
  - - ">="
208
222
  - !ruby/object:Gem::Version
209
- version: 1.3.0
223
+ version: 0.5.0
210
224
  type: :development
211
225
  prerelease: false
212
226
  version_requirements: !ruby/object:Gem::Requirement
213
227
  requirements:
214
228
  - - ">="
215
229
  - !ruby/object:Gem::Version
216
- version: 1.3.0
230
+ version: 0.5.0
217
231
  description: |
218
- Tools for working with Component Based Rails Apps (see http://shageman.github.io/cbra.info/).
232
+ Tools for working with Component Based Rails Apps (see https://cbra.info).
219
233
  Includes tools for graphing the components of an app and their relationships, as well as selectively
220
234
  testing components based on changes made.
221
235
  email:
@@ -233,17 +247,18 @@ files:
233
247
  - ".gitignore"
234
248
  - ".rspec"
235
249
  - ".rubocop.yml"
236
- - CHANGELOG.md
237
- - CODE_OF_CONDUCT.md
250
+ - ".rubocop_todo.yml"
238
251
  - Gemfile
239
252
  - Guardfile
240
253
  - LICENSE.txt
241
- - README.md
242
254
  - Rakefile
243
255
  - _config.yml
244
256
  - bin/console
245
257
  - bin/setup
246
258
  - cobra_commander.gemspec
259
+ - docs/CHANGELOG.md
260
+ - docs/CODE_OF_CONDUCT.md
261
+ - docs/README.md
247
262
  - exe/cobra
248
263
  - gemfiles/bundler1.gemfile
249
264
  - gemfiles/bundler2.gemfile
@@ -255,12 +270,13 @@ files:
255
270
  - lib/cobra_commander/component.rb
256
271
  - lib/cobra_commander/dependencies.rb
257
272
  - lib/cobra_commander/dependencies/bundler.rb
273
+ - lib/cobra_commander/dependencies/bundler/package.rb
274
+ - lib/cobra_commander/dependencies/yarn.rb
258
275
  - lib/cobra_commander/dependencies/yarn/package.rb
259
- - lib/cobra_commander/dependencies/yarn/package_repo.rb
260
- - lib/cobra_commander/dependencies/yarn_workspace.rb
261
276
  - lib/cobra_commander/executor.rb
262
277
  - lib/cobra_commander/executor/concurrent.rb
263
278
  - lib/cobra_commander/executor/context.rb
279
+ - lib/cobra_commander/git_changed.rb
264
280
  - lib/cobra_commander/output.rb
265
281
  - lib/cobra_commander/output/ascii_tree.rb
266
282
  - lib/cobra_commander/output/flat_list.rb
@@ -269,6 +285,8 @@ files:
269
285
  - lib/cobra_commander/output/markdown_printer.rb
270
286
  - lib/cobra_commander/umbrella.rb
271
287
  - lib/cobra_commander/version.rb
288
+ - mkdocs.yml
289
+ - portal.yml
272
290
  - renovate.json
273
291
  homepage: http://tech.powerhrg.com/cobra_commander/
274
292
  licenses:
@@ -289,7 +307,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
289
307
  - !ruby/object:Gem::Version
290
308
  version: '0'
291
309
  requirements: []
292
- rubygems_version: 3.0.3
310
+ rubygems_version: 3.3.7
293
311
  signing_key:
294
312
  specification_version: 4
295
313
  summary: Tools for working with Component Based Rails Apps
@@ -1,32 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module CobraCommander
4
- module Dependencies
5
- module Yarn
6
- # Yarn package repository to load and cache package.json files
7
- class PackageRepo
8
- def initialize
9
- @specs = {}
10
- end
11
-
12
- def specs
13
- @specs.values
14
- end
15
-
16
- def load_linked_specs(package)
17
- package.dependencies.each_value do |spec|
18
- next unless spec =~ /link:(.+)/
19
-
20
- load_spec(File.join(package.path, "..", Regexp.last_match(1)))
21
- end
22
- end
23
-
24
- def load_spec(path)
25
- @specs[path] ||= Package.new(path).tap do |package|
26
- load_linked_specs(package)
27
- end
28
- end
29
- end
30
- end
31
- end
32
- end
@@ -1,55 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "open3"
4
-
5
- require_relative "yarn/package"
6
- require_relative "yarn/package_repo"
7
-
8
- module CobraCommander
9
- module Dependencies
10
- # Yarn workspace components source for an umbrella
11
- class YarnWorkspace
12
- attr_reader :packages
13
-
14
- def initialize(root_path)
15
- @repo = Yarn::PackageRepo.new
16
- @root_package = Yarn::Package.new(root_path)
17
- @repo.load_linked_specs(@root_package)
18
- load_workspace_packages
19
- end
20
-
21
- def path
22
- @root_package.path
23
- end
24
-
25
- def dependencies
26
- (workspace_spec.keys | @root_package.dependencies.keys).map(&method(:untag))
27
- end
28
-
29
- def components
30
- @repo.specs.map do |spec|
31
- {path: spec.path, name: untag(spec.name), dependencies: spec.dependencies.keys.map(&method(:untag))}
32
- end
33
- end
34
-
35
- private
36
-
37
- def load_workspace_packages
38
- workspace_spec.map do |_name, spec|
39
- @repo.load_spec File.expand_path(File.join(@root_package.path, "..", spec["location"]))
40
- end
41
- end
42
-
43
- def workspace_spec
44
- @workspace_spec ||= begin
45
- output, = Open3.capture2("yarn workspaces --json info", chdir: File.dirname(@root_package.path))
46
- JSON.parse(JSON.parse(output)["data"])
47
- end
48
- end
49
-
50
- def untag(name)
51
- name.gsub(@root_package.project_tag, "")
52
- end
53
- end
54
- end
55
- end