cobra_commander 0.6.1 → 0.7.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 +4 -4
- data/.editorconfig +11 -0
- data/.travis.yml +2 -3
- data/CHANGELOG.md +5 -0
- data/cobra_commander.gemspec +3 -1
- data/lib/cobra_commander.rb +11 -0
- data/lib/cobra_commander/affected.rb +37 -30
- data/lib/cobra_commander/calculated_component_tree.rb +2 -2
- data/lib/cobra_commander/change.rb +6 -6
- data/lib/cobra_commander/cli.rb +17 -34
- data/lib/cobra_commander/component.rb +52 -0
- data/lib/cobra_commander/dependencies.rb +4 -0
- data/lib/cobra_commander/dependencies/bundler.rb +38 -0
- data/lib/cobra_commander/dependencies/yarn/package.rb +37 -0
- data/lib/cobra_commander/dependencies/yarn/package_repo.rb +31 -0
- data/lib/cobra_commander/dependencies/yarn_workspace.rb +55 -0
- data/lib/cobra_commander/executor.rb +8 -18
- data/lib/cobra_commander/graph.rb +6 -14
- data/lib/cobra_commander/output.rb +10 -10
- data/lib/cobra_commander/umbrella.rb +51 -0
- data/lib/cobra_commander/version.rb +1 -1
- data/renovate.json +8 -0
- metadata +23 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7155830962a165a9d34da676e053580b6a375543c0823cf89ce72db41b8fdc7e
|
4
|
+
data.tar.gz: db6fd674597394e4c5ee1f8e42b42d9e24305de678a9043f17ed026238f6edcc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ee123f0d3b655a028e76e991fd3c7c0d411f9ece583965f9f4547a6356cce527049b41e90d665b18c433d5c8a293e43726c9a5b3fa822fb0a433d08b23df8f6e
|
7
|
+
data.tar.gz: 3f9514a4c74710643361ac3d3950e3f3d3b72e864b44c6f5addfc35997ae99a779bf07d5382cb38fa424a9d859de741d7836cd93e57624e55d044d8c0a0cfc0a
|
data/.editorconfig
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# EditorConfig is awesome: https://EditorConfig.org
|
2
|
+
# top-most EditorConfig file
|
3
|
+
root = true
|
4
|
+
|
5
|
+
# Unix-style newlines with a newline ending every file
|
6
|
+
[*]
|
7
|
+
end_of_line = lf
|
8
|
+
insert_final_newline = true
|
9
|
+
trim_trailing_whitespace = true
|
10
|
+
indent_style = space
|
11
|
+
indent_size = 2
|
data/.travis.yml
CHANGED
@@ -4,10 +4,9 @@ before_install:
|
|
4
4
|
- "find /home/travis/.rvm/rubies -wholename '*default/bundler-*.gemspec' -delete"
|
5
5
|
- gem install bundler:"$BUNDLER_VERSION"
|
6
6
|
- sudo apt-get -qq install graphviz
|
7
|
-
- curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.13.0
|
7
|
+
- curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.13.0
|
8
8
|
- export PATH="$HOME/.yarn/bin:$PATH"
|
9
9
|
rvm:
|
10
10
|
- 2.5.1
|
11
11
|
env:
|
12
|
-
- BUNDLER_VERSION=1.
|
13
|
-
- BUNDLER_VERSION=1.16.3
|
12
|
+
- BUNDLER_VERSION=1.17.3
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,11 @@
|
|
2
2
|
|
3
3
|
## Unreleased
|
4
4
|
|
5
|
+
## Version 0.7 - 2020-07-08
|
6
|
+
|
7
|
+
* Introduces CobraCommander::Umbrella with optimizations for dependency resolution
|
8
|
+
* Deprecates cobra cache and cache usages
|
9
|
+
|
5
10
|
## Version 0.6.1 - 2019-07-05
|
6
11
|
|
7
12
|
* Better supports yarn workspaces globbing by delegating to yarn to calculate the list of components rather than re-implementing in Ruby. PR [#34](https://github.com/powerhome/cobra_commander/pull/34)
|
data/cobra_commander.gemspec
CHANGED
@@ -11,10 +11,12 @@ Gem::Specification.new do |spec|
|
|
11
11
|
spec.authors = [
|
12
12
|
"Ben Langfeld",
|
13
13
|
"Garett Arrowood",
|
14
|
+
"Carlos Palhares",
|
14
15
|
]
|
15
16
|
spec.email = [
|
16
17
|
"blangfeld@powerhrg.com",
|
17
18
|
"garett.arrowood@powerhrg.com",
|
19
|
+
"carlos.palhares@powerhrg.com",
|
18
20
|
]
|
19
21
|
spec.summary = "Tools for working with Component Based Rails Apps"
|
20
22
|
spec.description = <<~DESCRIPTION
|
@@ -35,7 +37,7 @@ DESCRIPTION
|
|
35
37
|
spec.add_dependency "thor", ["< 2.0", ">= 0.18.1"]
|
36
38
|
spec.add_dependency "ruby-graphviz", "~> 1.2.3"
|
37
39
|
|
38
|
-
spec.add_development_dependency "bundler", "~> 1.
|
40
|
+
spec.add_development_dependency "bundler", "~> 1.17"
|
39
41
|
spec.add_development_dependency "rake", "~> 10.0"
|
40
42
|
spec.add_development_dependency "rspec", "~> 3.5"
|
41
43
|
spec.add_development_dependency "guard-rspec"
|
data/lib/cobra_commander.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "cobra_commander/dependencies"
|
4
|
+
require "cobra_commander/component"
|
5
|
+
require "cobra_commander/umbrella"
|
6
|
+
|
3
7
|
require "cobra_commander/cli"
|
4
8
|
require "cobra_commander/cached_component_tree"
|
5
9
|
require "cobra_commander/calculated_component_tree"
|
@@ -16,6 +20,13 @@ require "cobra_commander/executor"
|
|
16
20
|
module CobraCommander
|
17
21
|
UMBRELLA_APP_NAME = "App"
|
18
22
|
|
23
|
+
def self.umbrella(root_path, yarn: false, bundler: false, name: UMBRELLA_APP_NAME)
|
24
|
+
umbrella = Umbrella.new(name, root_path)
|
25
|
+
umbrella.add_source(:yarn, Dependencies::YarnWorkspace.new(root_path)) unless bundler
|
26
|
+
umbrella.add_source(:bundler, Dependencies::Bundler.new(root_path)) unless yarn
|
27
|
+
umbrella
|
28
|
+
end
|
29
|
+
|
19
30
|
def self.umbrella_tree(path)
|
20
31
|
CalculatedComponentTree.new(UMBRELLA_APP_NAME, path)
|
21
32
|
end
|
@@ -3,28 +3,33 @@
|
|
3
3
|
module CobraCommander
|
4
4
|
# Calculates directly & transitively affected components
|
5
5
|
class Affected
|
6
|
-
|
7
|
-
|
8
|
-
def initialize(tree, changes, path)
|
9
|
-
@tree = tree
|
6
|
+
def initialize(umbrella, changes)
|
7
|
+
@umbrella = umbrella
|
10
8
|
@changes = changes
|
11
|
-
@path = path
|
12
9
|
run!
|
13
10
|
end
|
14
11
|
|
15
12
|
def names
|
16
|
-
@names ||=
|
13
|
+
@names ||= all_affected.map(&:name)
|
17
14
|
end
|
18
15
|
|
19
16
|
def scripts
|
20
17
|
@scripts ||= paths.map { |path| File.join(path, "test.sh") }
|
21
18
|
end
|
22
19
|
|
20
|
+
def directly
|
21
|
+
@directly.map(&method(:affected_component))
|
22
|
+
end
|
23
|
+
|
24
|
+
def transitively
|
25
|
+
@transitively.map(&method(:affected_component))
|
26
|
+
end
|
27
|
+
|
23
28
|
def json_representation # rubocop:disable Metrics/MethodLength
|
24
29
|
{
|
25
30
|
changed_files: @changes,
|
26
|
-
directly_affected_components:
|
27
|
-
transitively_affected_components:
|
31
|
+
directly_affected_components: directly,
|
32
|
+
transitively_affected_components: transitively,
|
28
33
|
test_scripts: scripts,
|
29
34
|
component_names: names,
|
30
35
|
languages: {
|
@@ -39,46 +44,48 @@ module CobraCommander
|
|
39
44
|
def run!
|
40
45
|
@transitively = Set.new
|
41
46
|
@directly = Set.new
|
42
|
-
|
43
|
-
@transitively.
|
44
|
-
@
|
45
|
-
@directly = @directly.to_a.sort_by { |h| h[:name] }
|
47
|
+
@umbrella.components.each(&method(:add_if_changed))
|
48
|
+
@transitively = @transitively.sort_by(&:name)
|
49
|
+
@directly = @directly.sort_by(&:name)
|
46
50
|
end
|
47
51
|
|
48
|
-
def
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
52
|
+
def add_if_changed(component)
|
53
|
+
return if component.root_paths.uniq.none? { |path| @changes.any?(Regexp.new(path)) }
|
54
|
+
|
55
|
+
@directly << component
|
56
|
+
@transitively.merge(component.deep_dependents)
|
53
57
|
end
|
54
58
|
|
55
|
-
def
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
end
|
59
|
+
def affected_component(component)
|
60
|
+
{
|
61
|
+
name: component.name,
|
62
|
+
path: component.root_paths,
|
63
|
+
type: component.sources.keys.map(&:to_s).map(&:capitalize).join(" & "),
|
64
|
+
}
|
62
65
|
end
|
63
66
|
|
64
67
|
def all_affected
|
65
|
-
@all_affected ||= (@directly
|
68
|
+
@all_affected ||= (@directly | @transitively).sort_by(&:name)
|
66
69
|
end
|
67
70
|
|
68
71
|
def paths
|
69
|
-
@paths ||= all_affected.map
|
72
|
+
@paths ||= all_affected.map(&:root_paths).flatten.uniq
|
70
73
|
end
|
71
74
|
|
72
|
-
def
|
73
|
-
|
75
|
+
def all_affected_sources
|
76
|
+
all_affected
|
77
|
+
.map(&:sources)
|
78
|
+
.map(&:keys)
|
79
|
+
.flatten
|
80
|
+
.uniq
|
74
81
|
end
|
75
82
|
|
76
83
|
def contains_ruby?
|
77
|
-
|
84
|
+
all_affected_sources.include?(:bundler)
|
78
85
|
end
|
79
86
|
|
80
87
|
def contains_js?
|
81
|
-
|
88
|
+
all_affected_sources.include?(:yarn)
|
82
89
|
end
|
83
90
|
end
|
84
91
|
end
|
@@ -132,8 +132,8 @@ module CobraCommander
|
|
132
132
|
|
133
133
|
def yarn_workspaces
|
134
134
|
@yarn_workspaces ||= begin
|
135
|
-
output, = Open3.capture2("yarn workspaces info
|
136
|
-
JSON.parse(output)
|
135
|
+
output, = Open3.capture2("yarn --json workspaces info", chdir: @root_path)
|
136
|
+
JSON.parse(JSON.parse(output)["data"])
|
137
137
|
end
|
138
138
|
end
|
139
139
|
end
|
@@ -8,12 +8,12 @@ module CobraCommander
|
|
8
8
|
class Change
|
9
9
|
InvalidSelectionError = Class.new(StandardError)
|
10
10
|
|
11
|
-
def initialize(
|
12
|
-
@root_dir = Dir.chdir(
|
11
|
+
def initialize(umbrella, results, branch)
|
12
|
+
@root_dir = Dir.chdir(umbrella.path) { `git rev-parse --show-toplevel`.chomp }
|
13
13
|
@results = results
|
14
14
|
@branch = branch
|
15
|
-
@
|
16
|
-
@affected = Affected.new(@
|
15
|
+
@umbrella = umbrella
|
16
|
+
@affected = Affected.new(@umbrella, changes)
|
17
17
|
end
|
18
18
|
|
19
19
|
def run!
|
@@ -85,8 +85,8 @@ module CobraCommander
|
|
85
85
|
end
|
86
86
|
end
|
87
87
|
|
88
|
-
def display(
|
89
|
-
"#{
|
88
|
+
def display(name:, type:, **)
|
89
|
+
"#{name} - #{type}"
|
90
90
|
end
|
91
91
|
|
92
92
|
def blank_line
|
data/lib/cobra_commander/cli.rb
CHANGED
@@ -6,17 +6,16 @@ require "fileutils"
|
|
6
6
|
module CobraCommander
|
7
7
|
# Implements the tool's CLI
|
8
8
|
class CLI < Thor
|
9
|
-
CACHE_DESCRIPTION = "Path to a cache file to use (default: nil). If specified, this file will
|
10
|
-
"the component tree for the app to speed up subsequent invocations. Must be rotated any time
|
11
|
-
"dependency structure changes."
|
9
|
+
CACHE_DESCRIPTION = "[DEPRECATED] Path to a cache file to use (default: nil). If specified, this file will " \
|
10
|
+
"be used to store the component tree for the app to speed up subsequent invocations. Must be rotated any time " \
|
11
|
+
"the component dependency structure changes."
|
12
12
|
COMMON_OPTIONS = "[--app=pwd] [--format=FORMAT] [--cache=nil]"
|
13
13
|
|
14
14
|
desc "do [command] [--app=pwd] [--cache=nil]", "Executes the command in the context of each component in [app]"
|
15
15
|
method_option :app, default: Dir.pwd, aliases: "-a", desc: "App path (default: CWD)"
|
16
16
|
method_option :cache, default: nil, aliases: "-c", desc: CACHE_DESCRIPTION
|
17
17
|
def do(command)
|
18
|
-
|
19
|
-
executor = Executor.new(tree)
|
18
|
+
executor = Executor.new(umbrella(options.app).components)
|
20
19
|
executor.exec(command)
|
21
20
|
end
|
22
21
|
|
@@ -24,10 +23,9 @@ module CobraCommander
|
|
24
23
|
method_option :app, default: Dir.pwd, aliases: "-a", desc: "App path (default: CWD)"
|
25
24
|
method_option :format, default: "tree", aliases: "-f", desc: "Format (list or tree, default: list)"
|
26
25
|
method_option :cache, default: nil, aliases: "-c", desc: CACHE_DESCRIPTION
|
27
|
-
def ls(app_path =
|
28
|
-
tree = maybe_cached_tree(app_path || options.app, options.cache)
|
26
|
+
def ls(app_path = Dir.pwd)
|
29
27
|
Output.print(
|
30
|
-
|
28
|
+
umbrella(app_path).root,
|
31
29
|
options.format
|
32
30
|
)
|
33
31
|
end
|
@@ -37,8 +35,8 @@ module CobraCommander
|
|
37
35
|
method_option :format, default: "count", aliases: "-f", desc: "count or list"
|
38
36
|
method_option :cache, default: nil, aliases: "-c", desc: CACHE_DESCRIPTION
|
39
37
|
def dependents_of(component)
|
40
|
-
|
41
|
-
|
38
|
+
dependents = umbrella(options.app).dependents_of(component)
|
39
|
+
return unless dependents
|
42
40
|
puts "list" == options.format ? dependents.map(&:name) : dependents.size
|
43
41
|
end
|
44
42
|
|
@@ -47,9 +45,8 @@ module CobraCommander
|
|
47
45
|
method_option :format, default: "list", aliases: "-f", desc: "Format (list or tree, default: list)"
|
48
46
|
method_option :cache, default: nil, aliases: "-c", desc: CACHE_DESCRIPTION
|
49
47
|
def dependencies_of(component)
|
50
|
-
tree = maybe_cached_tree(options.app, options.cache)
|
51
48
|
Output.print(
|
52
|
-
|
49
|
+
umbrella(options.app).find(component),
|
53
50
|
options.format
|
54
51
|
)
|
55
52
|
end
|
@@ -59,12 +56,11 @@ module CobraCommander
|
|
59
56
|
puts CobraCommander::VERSION
|
60
57
|
end
|
61
58
|
|
62
|
-
desc "graph APP_PATH [--format=FORMAT] [--cache=nil]", "Outputs graph"
|
59
|
+
desc "graph APP_PATH [--format=FORMAT] [--cache=nil] [--component]", "Outputs graph"
|
63
60
|
method_option :format, default: "png", aliases: "-f", desc: "Accepts png or dot"
|
64
61
|
method_option :cache, default: nil, aliases: "-c", desc: CACHE_DESCRIPTION
|
65
62
|
def graph(app_path)
|
66
|
-
|
67
|
-
Graph.new(tree, options.format).generate!
|
63
|
+
Graph.new(umbrella(app_path).root, options.format).generate!
|
68
64
|
end
|
69
65
|
|
70
66
|
desc "changes APP_PATH [--results=RESULTS] [--branch=BRANCH] [--cache=nil]", "Prints list of changed files"
|
@@ -72,34 +68,21 @@ module CobraCommander
|
|
72
68
|
method_option :branch, default: "master", aliases: "-b", desc: "Specified target to calculate against"
|
73
69
|
method_option :cache, default: nil, aliases: "-c", desc: CACHE_DESCRIPTION
|
74
70
|
def changes(app_path)
|
75
|
-
|
76
|
-
Change.new(tree, options.results, options.branch).run!
|
71
|
+
Change.new(umbrella(app_path), options.results, options.branch).run!
|
77
72
|
end
|
78
73
|
|
79
|
-
desc "cache APP_PATH CACHE_PATH", "Caches a representation of the component structure of the app"
|
74
|
+
desc "cache APP_PATH CACHE_PATH", "[DEPRECATED] Caches a representation of the component structure of the app"
|
80
75
|
def cache(app_path, cache_path)
|
81
76
|
tree = CobraCommander.umbrella_tree(app_path)
|
82
|
-
|
77
|
+
FileUtils.mkdir_p(File.dirname(cache_path))
|
78
|
+
File.write(cache_path, tree.to_json)
|
83
79
|
puts "Created cache of component tree at #{cache_path}"
|
84
80
|
end
|
85
81
|
|
86
82
|
private
|
87
83
|
|
88
|
-
def
|
89
|
-
|
90
|
-
|
91
|
-
if File.exist?(cache_path)
|
92
|
-
CobraCommander.tree_from_cache(cache_path)
|
93
|
-
else
|
94
|
-
tree = CobraCommander.umbrella_tree(app_path)
|
95
|
-
write_tree_cache(tree, cache_path)
|
96
|
-
tree
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
def write_tree_cache(tree, cache_path)
|
101
|
-
FileUtils.mkdir_p(File.dirname(cache_path))
|
102
|
-
File.write(cache_path, tree.to_json)
|
84
|
+
def umbrella(path)
|
85
|
+
CobraCommander.umbrella(path)
|
103
86
|
end
|
104
87
|
end
|
105
88
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CobraCommander
|
4
|
+
# Represents a component withing an Umbrella
|
5
|
+
class Component
|
6
|
+
attr_reader :name, :dependencies, :sources
|
7
|
+
|
8
|
+
def initialize(umbrella, name)
|
9
|
+
@umbrella = umbrella
|
10
|
+
@name = name
|
11
|
+
@dependency_names = []
|
12
|
+
@sources = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_source(key, path, dependency_names)
|
16
|
+
@sources[key] = path
|
17
|
+
@dependency_names |= dependency_names
|
18
|
+
end
|
19
|
+
|
20
|
+
def root_paths
|
21
|
+
@sources.values.map(&File.method(:dirname)).uniq
|
22
|
+
end
|
23
|
+
|
24
|
+
def inspect
|
25
|
+
"#<CobraCommander::Component:#{object_id} #{name} dependencies=#{dependencies.map(&:name)} packages=#{sources}>"
|
26
|
+
end
|
27
|
+
|
28
|
+
def deep_dependents
|
29
|
+
@deep_dependents ||= @umbrella.components.find_all do |dep|
|
30
|
+
dep.deep_dependencies.include?(self)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def deep_dependencies
|
35
|
+
@deep_dependencies ||= dependencies.reduce(dependencies) do |deps, dep|
|
36
|
+
deps | dep.deep_dependencies
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def dependents
|
41
|
+
@dependents ||= @umbrella.components.find_all do |dep|
|
42
|
+
dep.dependencies.include?(self)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def dependencies
|
47
|
+
@dependencies ||= @dependency_names.sort
|
48
|
+
.map(&@umbrella.method(:find))
|
49
|
+
.compact
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CobraCommander
|
4
|
+
module Dependencies
|
5
|
+
# Calculates ruby bundler dependencies
|
6
|
+
class Bundler
|
7
|
+
def initialize(root)
|
8
|
+
@definition = ::Bundler::Definition.build(
|
9
|
+
Pathname.new(File.join(root, "Gemfile")).realpath,
|
10
|
+
Pathname.new(File.join(root, "Gemfile.lock")).realpath,
|
11
|
+
false
|
12
|
+
)
|
13
|
+
end
|
14
|
+
|
15
|
+
def path
|
16
|
+
@definition.lockfile
|
17
|
+
end
|
18
|
+
|
19
|
+
def dependencies
|
20
|
+
@definition.dependencies.map(&:name)
|
21
|
+
end
|
22
|
+
|
23
|
+
def components
|
24
|
+
components_source.specs.map do |spec|
|
25
|
+
{ path: spec.loaded_from, name: spec.name, dependencies: spec.dependencies.map(&:name) }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def components_source
|
32
|
+
@components_source ||= @definition.send(:sources).path_sources.find do |source|
|
33
|
+
source.path.to_s.eql?("components")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
|
5
|
+
module CobraCommander
|
6
|
+
module Dependencies
|
7
|
+
module Yarn
|
8
|
+
# Represents an Yarn package.json file
|
9
|
+
class Package
|
10
|
+
attr_reader :path
|
11
|
+
|
12
|
+
def initialize(path)
|
13
|
+
@path = Pathname.new(File.join(path, "package.json")).realpath
|
14
|
+
end
|
15
|
+
|
16
|
+
def project_tag
|
17
|
+
name.match(%r{^@[\w-]+\/}).to_s
|
18
|
+
end
|
19
|
+
|
20
|
+
def name
|
21
|
+
json["name"]
|
22
|
+
end
|
23
|
+
|
24
|
+
def dependencies
|
25
|
+
json.fetch("dependencies", {})
|
26
|
+
.merge(json.fetch("devDependencies", {}))
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def json
|
32
|
+
@json ||= JSON.parse(File.read(@path))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,31 @@
|
|
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.values.each do |spec|
|
18
|
+
next unless spec =~ /link:(.+)/
|
19
|
+
load_spec(File.join(package.path, "..", Regexp.last_match(1)))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def load_spec(path)
|
24
|
+
@specs[path] ||= Package.new(path).tap do |package|
|
25
|
+
load_linked_specs(package)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,55 @@
|
|
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
|
@@ -3,28 +3,18 @@
|
|
3
3
|
module CobraCommander
|
4
4
|
# Execute commands on all components of a ComponentTree
|
5
5
|
class Executor
|
6
|
-
def initialize(
|
7
|
-
@
|
6
|
+
def initialize(components)
|
7
|
+
@components = components
|
8
8
|
end
|
9
9
|
|
10
10
|
def exec(command, printer = $stdout)
|
11
|
-
@
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
@components.each do |component|
|
12
|
+
component.root_paths.each do |path|
|
13
|
+
printer.puts "===> #{component.name} (#{path})"
|
14
|
+
output, = Open3.capture2e(command, chdir: path, unsetenv_others: true)
|
15
|
+
printer.puts output
|
16
|
+
end
|
15
17
|
end
|
16
18
|
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def run_in_component(component, command)
|
21
|
-
Dir.chdir(component.path) do
|
22
|
-
Open3.capture2e(env_vars(component), command)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def env_vars(component)
|
27
|
-
{ "CURRENT_COMPONENT" => component.name, "CURRENT_COMPONENT_PATH" => component.path }
|
28
|
-
end
|
29
19
|
end
|
30
20
|
end
|
@@ -5,31 +5,23 @@ require "graphviz"
|
|
5
5
|
module CobraCommander
|
6
6
|
# Generates graphs of components
|
7
7
|
class Graph
|
8
|
-
def initialize(
|
8
|
+
def initialize(node, format)
|
9
9
|
@format = format
|
10
|
-
@
|
10
|
+
@node = node
|
11
11
|
end
|
12
12
|
|
13
13
|
def generate!
|
14
14
|
return unless valid_format?
|
15
15
|
|
16
16
|
g = GraphViz.new(:G, type: :digraph, concentrate: true)
|
17
|
+
([@node] + @node.deep_dependencies).each do |component|
|
18
|
+
g.add_nodes component.name
|
19
|
+
g.add_edges component.name, component.dependencies.map(&:name)
|
20
|
+
end
|
17
21
|
|
18
|
-
app_node = g.add_nodes(@tree[:name])
|
19
|
-
map_nodes(g, app_node, @tree)
|
20
22
|
output(g)
|
21
23
|
end
|
22
24
|
|
23
|
-
private
|
24
|
-
|
25
|
-
def map_nodes(g, parent_node, tree)
|
26
|
-
tree[:dependencies].each do |dep|
|
27
|
-
node = g.find_node(dep[:name]) || g.add_nodes(dep[:name])
|
28
|
-
g.add_edges(parent_node, node)
|
29
|
-
map_nodes(g, node, dep)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
25
|
def output(g)
|
34
26
|
graph = "graph.#{@format}"
|
35
27
|
g.output(@format => graph)
|
@@ -3,8 +3,8 @@
|
|
3
3
|
module CobraCommander
|
4
4
|
# Module for pretty printing dependency trees
|
5
5
|
module Output
|
6
|
-
def self.print(
|
7
|
-
output = format == "list" ? Output::FlatList.new(
|
6
|
+
def self.print(node, format)
|
7
|
+
output = format == "list" ? Output::FlatList.new(node) : Output::Tree.new(node)
|
8
8
|
puts output.to_s
|
9
9
|
end
|
10
10
|
|
@@ -15,7 +15,7 @@ module CobraCommander
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def to_s
|
18
|
-
@tree.
|
18
|
+
@tree.deep_dependencies.map(&:name).sort
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
@@ -28,22 +28,22 @@ module CobraCommander
|
|
28
28
|
TEE = "├── "
|
29
29
|
CORNER = "└── "
|
30
30
|
|
31
|
-
def initialize(
|
32
|
-
@
|
31
|
+
def initialize(node)
|
32
|
+
@node = node
|
33
33
|
end
|
34
34
|
|
35
35
|
def to_s
|
36
36
|
StringIO.new.tap do |io|
|
37
|
-
io.puts @
|
38
|
-
list_dependencies(io, @
|
37
|
+
io.puts @node.name
|
38
|
+
list_dependencies(io, @node)
|
39
39
|
end.string
|
40
40
|
end
|
41
41
|
|
42
42
|
private
|
43
43
|
|
44
|
-
def list_dependencies(io,
|
45
|
-
|
46
|
-
decide_on_line(io,
|
44
|
+
def list_dependencies(io, node, outdents = [])
|
45
|
+
node.dependencies.each do |dep|
|
46
|
+
decide_on_line(io, node, dep, outdents)
|
47
47
|
end
|
48
48
|
nil
|
49
49
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CobraCommander
|
4
|
+
# An umbrella application
|
5
|
+
class Umbrella
|
6
|
+
attr_reader :name, :path
|
7
|
+
|
8
|
+
def initialize(name, path)
|
9
|
+
@root_component = Component.new(self, name)
|
10
|
+
@path = path
|
11
|
+
@components = {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def find(name)
|
15
|
+
@components[name]
|
16
|
+
end
|
17
|
+
|
18
|
+
def root
|
19
|
+
@root_component
|
20
|
+
end
|
21
|
+
|
22
|
+
def resolve(component_root_path)
|
23
|
+
return root if root.root_paths.include?(component_root_path)
|
24
|
+
components.find do |component|
|
25
|
+
component.root_paths.include?(component_root_path)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def add_source(key, source)
|
30
|
+
@root_component.add_source key, source.path, source.dependencies
|
31
|
+
source.components.each do |path:, name:, dependencies:|
|
32
|
+
@components[name] ||= Component.new(self, name)
|
33
|
+
@components[name].add_source key, path, dependencies
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def components
|
38
|
+
@components.values
|
39
|
+
end
|
40
|
+
|
41
|
+
def dependents_of(component)
|
42
|
+
find(component)&.deep_dependents
|
43
|
+
&.sort_by(&:name)
|
44
|
+
end
|
45
|
+
|
46
|
+
def dependencies_of(name)
|
47
|
+
find(name)&.deep_dependencies
|
48
|
+
&.sort_by(&:name)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/renovate.json
ADDED
metadata
CHANGED
@@ -1,36 +1,37 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cobra_commander
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Langfeld
|
8
8
|
- Garett Arrowood
|
9
|
+
- Carlos Palhares
|
9
10
|
autorequire:
|
10
11
|
bindir: exe
|
11
12
|
cert_chain: []
|
12
|
-
date:
|
13
|
+
date: 2020-07-08 00:00:00.000000000 Z
|
13
14
|
dependencies:
|
14
15
|
- !ruby/object:Gem::Dependency
|
15
16
|
name: thor
|
16
17
|
requirement: !ruby/object:Gem::Requirement
|
17
18
|
requirements:
|
18
|
-
- - ">="
|
19
|
-
- !ruby/object:Gem::Version
|
20
|
-
version: 0.18.1
|
21
19
|
- - "<"
|
22
20
|
- !ruby/object:Gem::Version
|
23
21
|
version: '2.0'
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 0.18.1
|
24
25
|
type: :runtime
|
25
26
|
prerelease: false
|
26
27
|
version_requirements: !ruby/object:Gem::Requirement
|
27
28
|
requirements:
|
28
|
-
- - ">="
|
29
|
-
- !ruby/object:Gem::Version
|
30
|
-
version: 0.18.1
|
31
29
|
- - "<"
|
32
30
|
- !ruby/object:Gem::Version
|
33
31
|
version: '2.0'
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 0.18.1
|
34
35
|
- !ruby/object:Gem::Dependency
|
35
36
|
name: ruby-graphviz
|
36
37
|
requirement: !ruby/object:Gem::Requirement
|
@@ -51,14 +52,14 @@ dependencies:
|
|
51
52
|
requirements:
|
52
53
|
- - "~>"
|
53
54
|
- !ruby/object:Gem::Version
|
54
|
-
version: '1.
|
55
|
+
version: '1.17'
|
55
56
|
type: :development
|
56
57
|
prerelease: false
|
57
58
|
version_requirements: !ruby/object:Gem::Requirement
|
58
59
|
requirements:
|
59
60
|
- - "~>"
|
60
61
|
- !ruby/object:Gem::Version
|
61
|
-
version: '1.
|
62
|
+
version: '1.17'
|
62
63
|
- !ruby/object:Gem::Dependency
|
63
64
|
name: rake
|
64
65
|
requirement: !ruby/object:Gem::Requirement
|
@@ -150,11 +151,13 @@ description: |
|
|
150
151
|
email:
|
151
152
|
- blangfeld@powerhrg.com
|
152
153
|
- garett.arrowood@powerhrg.com
|
154
|
+
- carlos.palhares@powerhrg.com
|
153
155
|
executables:
|
154
156
|
- cobra
|
155
157
|
extensions: []
|
156
158
|
extra_rdoc_files: []
|
157
159
|
files:
|
160
|
+
- ".editorconfig"
|
158
161
|
- ".gitignore"
|
159
162
|
- ".rspec"
|
160
163
|
- ".rubocop.yml"
|
@@ -177,11 +180,19 @@ files:
|
|
177
180
|
- lib/cobra_commander/calculated_component_tree.rb
|
178
181
|
- lib/cobra_commander/change.rb
|
179
182
|
- lib/cobra_commander/cli.rb
|
183
|
+
- lib/cobra_commander/component.rb
|
180
184
|
- lib/cobra_commander/component_tree.rb
|
185
|
+
- lib/cobra_commander/dependencies.rb
|
186
|
+
- lib/cobra_commander/dependencies/bundler.rb
|
187
|
+
- lib/cobra_commander/dependencies/yarn/package.rb
|
188
|
+
- lib/cobra_commander/dependencies/yarn/package_repo.rb
|
189
|
+
- lib/cobra_commander/dependencies/yarn_workspace.rb
|
181
190
|
- lib/cobra_commander/executor.rb
|
182
191
|
- lib/cobra_commander/graph.rb
|
183
192
|
- lib/cobra_commander/output.rb
|
193
|
+
- lib/cobra_commander/umbrella.rb
|
184
194
|
- lib/cobra_commander/version.rb
|
195
|
+
- renovate.json
|
185
196
|
homepage: http://tech.powerhrg.com/cobra_commander/
|
186
197
|
licenses:
|
187
198
|
- MIT
|
@@ -201,7 +212,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
201
212
|
- !ruby/object:Gem::Version
|
202
213
|
version: '0'
|
203
214
|
requirements: []
|
204
|
-
|
215
|
+
rubyforge_project:
|
216
|
+
rubygems_version: 2.7.3
|
205
217
|
signing_key:
|
206
218
|
specification_version: 4
|
207
219
|
summary: Tools for working with Component Based Rails Apps
|