cobra_commander 0.12.0 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +6 -11
  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 -4
  7. data/cobra_commander.gemspec +13 -12
  8. data/{CHANGELOG.md → docs/CHANGELOG.md} +19 -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 -11
  13. data/lib/cobra_commander/change.rb +22 -31
  14. data/lib/cobra_commander/cli/filters.rb +36 -6
  15. data/lib/cobra_commander/cli.rb +12 -11
  16. data/lib/cobra_commander/component.rb +8 -6
  17. data/lib/cobra_commander/dependencies/bundler/package.rb +17 -0
  18. data/lib/cobra_commander/dependencies/bundler.rb +7 -5
  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/context.rb +2 -0
  23. data/lib/cobra_commander/git_changed.rb +41 -0
  24. data/lib/cobra_commander/output/ascii_tree.rb +6 -6
  25. data/lib/cobra_commander/output/graph_viz.rb +1 -1
  26. data/lib/cobra_commander/output/interactive_printer.rb +35 -14
  27. data/lib/cobra_commander/output/markdown_printer.rb +3 -3
  28. data/lib/cobra_commander/umbrella.rb +4 -14
  29. data/lib/cobra_commander/version.rb +1 -1
  30. data/lib/cobra_commander.rb +2 -2
  31. data/mkdocs.yml +8 -0
  32. data/portal.yml +12 -0
  33. metadata +35 -17
  34. data/lib/cobra_commander/dependencies/yarn/package_repo.rb +0 -32
  35. 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: 8461ea231fa9be478360d33fbadfb8983512172687831ac7c17ac1f927614200
4
- data.tar.gz: 0b36b28eadecb6e0bc6e7ee8c3e6db951f7dc7d74be67c91b97659dc7bd52c5e
3
+ metadata.gz: 4fe38b5cf9d55a71b6a24111018d90cbd624c4d6bd3a95a7313f9c7afbeb6e92
4
+ data.tar.gz: 4fe0c927cbc3b985c0153849ff48889511dd726e35ddf534dd723cf9c8d18501
5
5
  SHA512:
6
- metadata.gz: 39a0956db1750d63553d87e4d13ad75246f4f4633b3d6a42de621c45f11a515506ab5f0d7f14343d61f183d03df7e8218dee8f93a439da023e442d70c7f3b681
7
- data.tar.gz: 227acbdb961e2903cdaacd44ed4bdd7b07a48e7298737bbe5b6228bd28df8aa6c7aea6a6949de2a3eea999287b633e9bfcd32b7b9e108e3f7f4fcaa7385e2806
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,14 +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
- - uses: reviewdog/action-rubocop@v1
44
- with:
45
- rubocop_version: 0.88.0
46
- filter_mode: nofilter
47
- fail_on_error: true
48
- rubocop_extensions: ""
49
- github_token: ${{ secrets.github_token }}
41
+ - name: Bundle
42
+ run: bundle
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@v1
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,11 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "bundler/gem_tasks"
4
-
4
+ require "rubocop/rake_task"
5
5
  require "rspec/core/rake_task"
6
- RSpec::Core::RakeTask.new(:spec)
7
6
 
8
- require "rubocop/rake_task"
9
- RuboCop::RakeTask.new
7
+ RSpec::Core::RakeTask.new(:spec)
8
+ RuboCop::RakeTask.new(:rubocop)
10
9
 
11
10
  task default: %i[spec rubocop]
@@ -5,9 +5,9 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
  require "cobra_commander/version"
6
6
 
7
7
  Gem::Specification.new do |spec|
8
- spec.name = "cobra_commander"
9
- spec.version = CobraCommander::VERSION
10
- spec.authors = [
8
+ spec.name = "cobra_commander"
9
+ spec.version = CobraCommander::VERSION
10
+ spec.authors = [
11
11
  "Ben Langfeld",
12
12
  "Garett Arrowood",
13
13
  "Carlos Palhares",
@@ -17,20 +17,20 @@ Gem::Specification.new do |spec|
17
17
  "garett.arrowood@powerhrg.com",
18
18
  "carlos.palhares@powerhrg.com",
19
19
  ]
20
- spec.summary = "Tools for working with Component Based Rails Apps"
21
- spec.description = <<~DESCRIPTION
22
- Tools for working with Component Based Rails Apps (see http://shageman.github.io/cbra.info/).
20
+ spec.summary = "Tools for working with Component Based Rails Apps"
21
+ spec.description = <<~DESCRIPTION
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
26
- spec.homepage = "http://tech.powerhrg.com/cobra_commander/"
27
- spec.license = "MIT"
26
+ spec.homepage = "http://tech.powerhrg.com/cobra_commander/"
27
+ spec.license = "MIT"
28
28
 
29
- spec.files = `git ls-files -z`.split("\x0").reject do |f|
29
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
30
30
  f.match(%r{^(test|spec|features)/})
31
31
  end
32
- spec.bindir = "exe"
33
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
32
+ spec.bindir = "exe"
33
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
34
34
  spec.require_paths = ["lib"]
35
35
 
36
36
  spec.add_dependency "bundler"
@@ -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 "rubocop", "0.88.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,25 @@
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
+
13
+ ## Version 0.14.0 - 2021-11-24
14
+
15
+ * Retain selection on Interactive Printer [#69](https://github.com/powerhome/cobra_commander/pull/69)
16
+ * Sorts the interactive UI alphabetically with failures first [#68](https://github.com/powerhome/cobra_commander/pull/68)
17
+ * Switch from Rubocop to Standardrb [#67](https://github.com/powerhome/cobra_commander/pull/67)
18
+
19
+ ## Version 0.13.0 - 2021-10-21
20
+
21
+ * Sorts the interactive UI alphabetically with failures first [#66](https://github.com/powerhome/cobra_commander/pull/66)
22
+ * Switch linter to standardrb [#67](https://github.com/powerhome/cobra_commander/pull/67)
23
+
5
24
  ## Version 0.12.0 - 2021-09-21
6
25
 
7
26
  * Add interactive UI and Markdown output to `cobra exec` [#63](https://github.com/powerhome/cobra_commander/pull/63)
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"
@@ -25,17 +25,14 @@ module CobraCommander
25
25
  @transitively.map(&method(:affected_component))
26
26
  end
27
27
 
28
- def json_representation # rubocop:disable Metrics/MethodLength
28
+ def json_representation
29
29
  {
30
30
  changed_files: @changes,
31
31
  directly_affected_components: directly,
32
32
  transitively_affected_components: transitively,
33
33
  test_scripts: scripts,
34
34
  component_names: names,
35
- languages: {
36
- ruby: contains_ruby?,
37
- javascript: contains_js?,
38
- },
35
+ languages: { ruby: contains_ruby?, javascript: contains_js? },
39
36
  }.to_json
40
37
  end
41
38
 
@@ -68,7 +65,7 @@ module CobraCommander
68
65
  {
69
66
  name: component.name,
70
67
  path: component.root_paths,
71
- type: component.sources.keys.map(&:to_s).map(&:capitalize).join(" & "),
68
+ type: component.packages.keys.map(&:to_s).map(&:capitalize).join(" & "),
72
69
  }
73
70
  end
74
71
 
@@ -77,23 +74,23 @@ module CobraCommander
77
74
  end
78
75
 
79
76
  def paths
80
- @paths ||= all_affected.map(&:root_paths).flatten.uniq
77
+ @paths ||= all_affected.map(&:root_paths).flatten
81
78
  end
82
79
 
83
- def all_affected_sources
80
+ def all_affected_packages
84
81
  all_affected
85
- .map(&:sources)
82
+ .map(&:packages)
86
83
  .map(&:keys)
87
84
  .flatten
88
85
  .uniq
89
86
  end
90
87
 
91
88
  def contains_ruby?
92
- all_affected_sources.include?(:bundler)
89
+ all_affected_packages.include?(:bundler)
93
90
  end
94
91
 
95
92
  def contains_js?
96
- all_affected_sources.include?(:yarn)
93
+ all_affected_packages.include?(:yarn)
97
94
  end
98
95
  end
99
96
  end
@@ -1,87 +1,78 @@
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
30
  private
32
31
 
32
+ def affected
33
+ @affected ||= Affected.new(@umbrella, @changes)
34
+ end
35
+
33
36
  def show_full
34
37
  changes_since_last_commit
35
38
  directly_affected_components
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,6 +4,7 @@ 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"
@@ -14,16 +15,45 @@ module CobraCommander
14
15
  def find_component(name)
15
16
  return umbrella.root unless name
16
17
 
17
- umbrella.find(name) || error("Component #{name} not found, try one of `cobra ls`") || exit(1)
18
+ umbrella.find(name) || error("Component #{name} not found, maybe #{suggestion(name)}") || exit(1)
18
19
  end
19
20
 
20
- def components_filtered(component_name)
21
- return umbrella.components unless component_name
21
+ def suggestion(name)
22
+ [*suggestions(name), 'one of "cobra ls"'].join(", ")
23
+ end
24
+
25
+ def suggestions(name)
26
+ spell_checker = DidYouMean::SpellChecker.new(dictionary: umbrella.components.map(&:name))
27
+ spell_checker.correct(name)
28
+ rescue NameError
29
+ []
30
+ end
22
31
 
32
+ def affected_by_changes(origin_branch)
33
+ changes = GitChanged.new(umbrella.path, origin_branch)
34
+ Affected.new(umbrella, changes).all_affected
35
+ end
36
+
37
+ def filter_component(component_name)
23
38
  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
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
27
57
  components
28
58
  end
29
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,29 +27,29 @@ 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
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
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
- desc: "Runs in interactive mode to allow the user to inspect the output of each component"
46
- def exec(command_or_component, command = nil)
46
+ desc: "Runs in interactive mode to allow the user to inspect the output of each " \
47
+ "component"
48
+ def exec(command_or_components, command = nil)
47
49
  results = CobraCommander::Executor.exec(
48
- components: components_filtered(command && command_or_component),
49
- command: command || command_or_component,
50
- concurrency: options.concurrency,
51
- status_output: $stderr
50
+ components: components_filtered(command && command_or_components),
51
+ command: command || command_or_components,
52
+ concurrency: options.concurrency, status_output: $stderr
52
53
  )
53
54
  if options.interactive && results.size > 1
54
55
  CobraCommander::Output::InteractivePrinter.run(results, $stdout)
@@ -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
@@ -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,13 +17,13 @@ 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
 
@@ -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"
@@ -4,6 +4,8 @@ require "tty-command"
4
4
 
5
5
  module CobraCommander
6
6
  module Executor
7
+ # Represents a component context to execute a command
8
+ # @private
7
9
  class Context
8
10
  attr_reader :component, :command
9
11
 
@@ -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
@@ -6,9 +6,9 @@ module CobraCommander
6
6
  module Output
7
7
  # Prints the tree in a nice tree form
8
8
  class AsciiTree
9
- SPACE = " "
10
- BAR = "│   "
11
- TEE = "├── "
9
+ SPACE = " "
10
+ BAR = "│   "
11
+ TEE = "├── "
12
12
  CORNER = "└── "
13
13
 
14
14
  def initialize(component)
@@ -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]
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'"
@@ -6,26 +6,47 @@ require "tty-prompt"
6
6
  module CobraCommander
7
7
  module Output
8
8
  # Runs an interactive output printer
9
- module InteractivePrinter
9
+ class InteractivePrinter
10
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
11
+ SUCCESS = "#{pastel.green('')} %s"
12
+ ERROR = "#{pastel.red('')} %s"
13
+ BYE = pastel.decorate("\n\n👋 Bye!", :white, :on_black, :bold).freeze
14
14
 
15
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
16
+ new(contexts).run(output)
17
+ end
18
+
19
+ def initialize(contexts)
20
+ @prompt = TTY::Prompt.new
21
+ @options = map_options(contexts)
22
+ end
23
+
24
+ def run(output)
25
+ selected_context = nil
23
26
  loop do
24
- context = prompt.select("Print output?", context_options)
25
- output.puts context.output
27
+ selected_context = @prompt.select("Print output?", @options, default: @options.key(selected_context))
28
+ output.puts selected_context.output
26
29
  end
27
30
  rescue TTY::Reader::InputInterrupt
28
- output.puts "\n\n", BYE
31
+ output.puts BYE
32
+ end
33
+
34
+ private
35
+
36
+ def map_options(contexts)
37
+ contexts.sort(&method(:sort_contexts))
38
+ .reduce({}) do |options, context|
39
+ template = context.success? ? SUCCESS : ERROR
40
+ options.merge format(template, context.component_name) => context
41
+ end
42
+ end
43
+
44
+ def sort_contexts(context_a, context_b)
45
+ if context_a.success? == context_b.success?
46
+ context_a.component_name <=> context_b.component_name
47
+ else
48
+ context_a.success? ? 1 : -1
49
+ end
29
50
  end
30
51
  end
31
52
  end
@@ -7,9 +7,9 @@ module CobraCommander
7
7
  module Output
8
8
  # Prints the given CobraCommander::Executor::Context to [output] collection in markdown
9
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
10
+ SUCCESS = "\n## ✔ %s\n"
11
+ ERROR = "\n## ✖ %s\n"
12
+ OUTPUT = "\n```\n$ %s\n\n%s\n```\n"
13
13
 
14
14
  def self.run(contexts, output)
15
15
  contexts.each do |context|
@@ -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.12.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.12.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-09-21 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
@@ -206,16 +206,30 @@ dependencies:
206
206
  requirements:
207
207
  - - '='
208
208
  - !ruby/object:Gem::Version
209
- version: 0.88.0
209
+ version: 1.30.1
210
210
  type: :development
211
211
  prerelease: false
212
212
  version_requirements: !ruby/object:Gem::Requirement
213
213
  requirements:
214
214
  - - '='
215
215
  - !ruby/object:Gem::Version
216
- version: 0.88.0
216
+ version: 1.30.1
217
+ - !ruby/object:Gem::Dependency
218
+ name: rubocop-powerhome
219
+ requirement: !ruby/object:Gem::Requirement
220
+ requirements:
221
+ - - ">="
222
+ - !ruby/object:Gem::Version
223
+ version: 0.5.0
224
+ type: :development
225
+ prerelease: false
226
+ version_requirements: !ruby/object:Gem::Requirement
227
+ requirements:
228
+ - - ">="
229
+ - !ruby/object:Gem::Version
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