monoz 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3809e6abcde49688db77aeb2c395d7293a68528ac2a3a3fab51a753de5040048
4
+ data.tar.gz: 138e119bf0ba056dd1f1ca54061b1d24e5c507a25e42a035a8639d2d548900e2
5
+ SHA512:
6
+ metadata.gz: 5b52995d260a8ef32d5ee8341624f80e96ab5836b35995033ecbb2cc54987757102d0e4b8b4e9cebe1bf28190ce5895d8d5f6896700ec17e1d43bfccd3c28ff3
7
+ data.tar.gz: fb384e4182854c0ab3633869e62283306af0a24f3bb030e99bc43514f1bf68f5107651b344480f4b22838890963d9233b50a3d7e31a83c55ef53fbeaf1ae2895
data/README.md ADDED
@@ -0,0 +1,98 @@
1
+ # Monoz
2
+
3
+ Monoz is a command-line tool that helps you manage your **ruby** monorepo. It provides an easy way to manage multiple related **ruby** projects and their dependencies in a single repository. Monoz helps you keep track of your projects and their interdependencies, making it easier to maintain and scale your codebase.
4
+
5
+ ## Installation
6
+
7
+ You can install Monoz by running the following command:
8
+
9
+ ```console
10
+ $ gem install monoz
11
+ ```
12
+
13
+ ## Getting started
14
+
15
+ To initialize a Monoz repository in the current directory, simply run:
16
+
17
+ ```console
18
+ $ monoz init
19
+ ```
20
+ *For a specific directory, provide the path as an argument.*
21
+
22
+
23
+ This will create a new Monoz repo with the following structure:
24
+
25
+ ```
26
+ ├── .git
27
+ ├── apps
28
+ ├── gems
29
+ └── monoz.yml
30
+ ```
31
+
32
+ ### Adding projects
33
+
34
+ Once you've initialized your Monoz repository, you can start adding projects to it.
35
+
36
+ To add a new project, simply create a new directory in either the `apps/` or `gems/` directory, depending on whether it's an application or a library.
37
+
38
+ For example, a Monoz repository with both a frontend and a backend application that shares the same libraries could look like this:
39
+
40
+ ```
41
+ ├── .git
42
+ ├── apps
43
+ │ ├── example-com
44
+ │ └── example-com-admin
45
+ ├── gems
46
+ │ ├── myengine
47
+ │ ├── sharedmodels
48
+ │ └── privatelibrary
49
+ └── monoz.yml
50
+ ```
51
+
52
+ ### Bundle projects
53
+
54
+ To manage the dependencies of your projects, you can use the monoz bundle command. This command will create a new Gemfile.lock file in each project directory based on the dependencies specified in their respective Gemfiles.
55
+
56
+ To bundle all the projects in the Monoz repository, simply run:
57
+
58
+ ```console
59
+ $ monoz bundle
60
+ ```
61
+
62
+ This will create a `Gemfile.lock` file for each project in the repository.
63
+
64
+ If you want to update the dependencies of your projects, you can use the `monoz bundle update` command. This command will update the `Gemfile.lock` file of each project based on the latest available versions of their dependencies.
65
+
66
+ To update the dependencies of all projects in the Monoz repository, simply run:
67
+
68
+ ```console
69
+ $ monoz bundle update
70
+ ```
71
+
72
+ Note that when you add a new dependency to a project, you'll need to run `monoz bundle` to update its `Gemfile.lock` file before you can use the new dependency. Similarly, if you update the dependencies of a project's `Gemfile`, you'll need to run `monoz bundle` to update its `Gemfile.lock` file with the new versions.
73
+
74
+ ### Inspect projects
75
+
76
+ You can inspect the projects in your Monoz repository using the monoz inspect command. This command will display a table that shows the projects in the repository, their type (app or gem), the gem name (if it's a gem), the test framework(s) used, and the projects that depend on them.
77
+
78
+ Here's an example output of the monoz inspect command:
79
+
80
+ ```console
81
+ $ monoz inspect
82
+
83
+ o---------------o--------o-------------o---------------------o-------------------------------------o
84
+ | Project | Type | Gem Name | Test Framework(s) | Dependants |
85
+ o---------------o--------o-------------o---------------------o-------------------------------------o
86
+ | content_api | app | | rspec | |
87
+ | core_api | app | | rspec | |
88
+ | kiqr_cloud | app | | rspec | |
89
+ | kiqr_core | gem | kiqr_core | rspec | content_api, core_api, kiqr_cloud |
90
+ o---------------o--------o-------------o---------------------o-------------------------------------o
91
+ ```
92
+
93
+ ## Contributing
94
+ We welcome contributions from everyone! If you're interested in contributing to Monoz, please check out our contributing guidelines for more information.
95
+
96
+ ## License
97
+
98
+ Monoz is released under the MIT License.
data/bin/monoz ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "monoz"
5
+
6
+ begin
7
+ Monoz::Cli::Main.start(ARGV)
8
+ rescue Monoz::Errors::ConfigurationNotFound
9
+ puts "This is not a valid Monoz directory."
10
+ puts "Run monoz init to initialize Monoz in the current directory."
11
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thor"
4
+ require "yaml"
5
+
6
+ module Monoz
7
+ module Cli
8
+ class Bundle < Thor
9
+ default_task :install
10
+
11
+ desc "install", "Install dependencies in all projects"
12
+ def install
13
+ Monoz.projects.order(:dependants).each do |project|
14
+ say "#{project.type} ", project.text_color, false
15
+ say "[#{project.name}] ", [:blue, :bold], false
16
+ say "bundle install", :green
17
+ project.run "bundle", "install"
18
+ end
19
+ end
20
+
21
+ desc "update", "Update dependencies in all projects"
22
+ def update
23
+ Monoz.projects.order(:dependants).each do |project|
24
+ say "#{project.type} ", project.text_color, false
25
+ say "[#{project.name}] ", [:blue, :bold], false
26
+ say "bundle update", :green
27
+ project.run "bundle", "update"
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thor"
4
+ require "yaml"
5
+
6
+ module Monoz
7
+ module Cli
8
+ class Inspect < Thor
9
+ default_task :all
10
+
11
+ desc "all", "Returns a list of all projects in this monozrepo"
12
+ def all
13
+ Monoz.projects.order(:name).to_table
14
+ end
15
+
16
+ desc "apps", "Returns a list of apps in this monozrepo"
17
+ def apps
18
+ Monoz.projects.order(:name).filter(:apps).to_table
19
+ end
20
+
21
+ desc "gems", "Returns a list of gems in this monozrepo"
22
+ def gems
23
+ Monoz.projects.filter(:gems).order(:name).to_table
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thor"
4
+ require "yaml"
5
+ require "fileutils"
6
+
7
+ module Monoz
8
+ module Cli
9
+ class Main < Thor
10
+ desc "init [PATH]", "Initialize a monozrepo at the specified PATH"
11
+ def init(path = ".")
12
+ Monoz::Services::InitService.new(self).call(path)
13
+ end
14
+
15
+ desc "bundle", "Run bundle commands in all projects"
16
+ subcommand "bundle", Monoz::Cli::Bundle
17
+
18
+ desc "inspect", "Inspect this monozrepo"
19
+ subcommand "inspect", Monoz::Cli::Inspect
20
+
21
+ map "run" => "run_action"
22
+ desc "run [action]", "Run commands in all projects"
23
+ def run_action(keys = nil)
24
+ return help("run") if keys.nil? || keys == "help"
25
+
26
+ Monoz::Services::RunActionService.new(self).call(keys)
27
+ end
28
+
29
+ desc "version", "Get the current version of Monoz"
30
+ def version
31
+ say "Monoz version: #{Monoz::VERSION}"
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,43 @@
1
+ require "yaml"
2
+ require "active_support/core_ext/module/delegation"
3
+
4
+ module Monoz
5
+ class Configuration
6
+ attr_reader :config_file_path
7
+ delegate_missing_to :@contents
8
+
9
+ def initialize(project_path)
10
+ @config_file_path = find_config_file(project_path)
11
+ raise Monoz::Errors::ConfigurationNotFound.new("Configuration not found at: #{project_path}") unless @config_file_path
12
+ @contents = load_config(@config_file_path) || {}
13
+ end
14
+
15
+ def contents
16
+ @contents ||= load_config(@config_file_path) if @config_file_path
17
+ end
18
+
19
+ def root_path
20
+ File.dirname @config_file_path
21
+ end
22
+
23
+ class << self
24
+ def default_config
25
+ { "folders" => ["apps", "gems"] }
26
+ end
27
+ end
28
+
29
+ private
30
+ def find_config_file(dir_path)
31
+ while dir_path != "/"
32
+ config_file_path = File.join(dir_path, "monoz.yml")
33
+ return config_file_path if File.exist?(config_file_path)
34
+
35
+ dir_path = File.dirname(dir_path)
36
+ end
37
+ end
38
+
39
+ def load_config(config_file_path)
40
+ YAML.load_file(config_file_path)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,123 @@
1
+ module Monoz
2
+ class Project
3
+ attr_reader :name, :root_path, :gemspec, :type, :dependencies, :gem_name, :dependants
4
+
5
+ def initialize(root_path)
6
+ @root_path = root_path
7
+
8
+ parse_project_files
9
+ parse_dependencies
10
+
11
+ setup_instance_variables
12
+ end
13
+
14
+ def is_gem?
15
+ !gemspec_path.nil?
16
+ end
17
+
18
+ def valid?
19
+ @root_path != nil && gemfile_path != nil
20
+ end
21
+
22
+ def run(*command)
23
+ FileUtils.chdir(root_path) do
24
+ system(*command)
25
+ end
26
+ end
27
+
28
+ def text_color
29
+ is_gem? ? :green : :blue
30
+ end
31
+
32
+ def test_frameworks
33
+ frameworks = []
34
+
35
+ rspec_files = Dir.glob(File.join(@root_path, "**/*_spec.rb"))
36
+ if !rspec_files.empty?
37
+ frameworks << "rspec"
38
+ end
39
+
40
+ minitest_files = Dir.glob(File.join(@root_path, "test/**/*_test.rb"))
41
+ if !minitest_files.empty?
42
+ frameworks << "minitest"
43
+ end
44
+
45
+ frameworks
46
+ end
47
+
48
+ private
49
+ def parse_project_files
50
+ @gemspec = parse_gemspec
51
+ end
52
+
53
+ def parse_dependencies
54
+ @dependencies = gem_dependencies
55
+ end
56
+
57
+ def parse_gemspec
58
+ return nil unless (gemspec_file = gemspec_path) && File.exist?(gemspec_file)
59
+
60
+ spec = Gem::Specification.load(gemspec_file)
61
+ {
62
+ name: spec.name,
63
+ version: spec.version.to_s
64
+ }
65
+ end
66
+
67
+ def setup_instance_variables
68
+ @name = File.basename(root_path)
69
+ @gem_name = @gemspec.dig(:name) if is_gem?
70
+ @type = is_gem? ? "gem" : "app"
71
+ @test_frameworks =
72
+ @dependants = []
73
+ end
74
+
75
+ def gemspec_path
76
+ Dir.glob(File.join(@root_path, "*.gemspec")).first
77
+ end
78
+
79
+ def gemfile_path
80
+ Dir.glob(File.join(@root_path, "Gemfile")).first
81
+ end
82
+
83
+ def gem_dependencies
84
+ dependencies = {}
85
+
86
+ # Check if a Gemfile exists
87
+ if (gemfile = gemfile_path) && File.exist?(gemfile)
88
+ gemfile_content = File.read(gemfile)
89
+
90
+ # Use regex to find all gem entries
91
+ gem_entries = gemfile_content.scan(/gem\s+['"]([^'"]+)['"](?:,\s*['"]([^'"]+)['"])?(?:,\s*['"]([^'"]+)['"])?/)
92
+
93
+ # Add each gem and its version to the hash
94
+ gem_entries.each do |gem_entry|
95
+ gem_name = gem_entry[0]
96
+ version_spec = gem_entry[1] || ""
97
+ dependencies[gem_name] = version_spec
98
+ end
99
+ end
100
+
101
+ # Check if a gemspec exists
102
+ if (gemspec_file = gemspec_path) && File.exist?(gemspec_file)
103
+ spec = Gem::Specification.load(gemspec_file)
104
+ spec.dependencies.each do |dep|
105
+ dependencies[dep.name] = dep.requirement.to_s
106
+ end
107
+ end
108
+
109
+ dependencies
110
+ end
111
+
112
+ public
113
+
114
+ # Update dependants of this project based on other projects in the collection
115
+ def update_dependants(collection)
116
+ collection.each do |project|
117
+ if project.dependencies.key?(name)
118
+ project.dependants << self
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,121 @@
1
+ require "pathname"
2
+ require "active_support/core_ext/module/delegation"
3
+ require "terminal-table"
4
+
5
+ module Monoz
6
+ class ProjectCollection
7
+ include Enumerable
8
+ delegate_missing_to :@items
9
+
10
+ def initialize(file_path)
11
+ @items = []
12
+ project_folders = Monoz.config.dig("folders") || ["apps", "gems"]
13
+
14
+ search_paths = project_folders.map { |folder| File.join(file_path, folder) }
15
+
16
+ search_paths.each do |search_path|
17
+ Dir.glob(File.join(search_path, "*/Gemfile")).each do |gemfile_path|
18
+ project_path = File.dirname(gemfile_path)
19
+ project = Project.new(project_path)
20
+ if project.valid?
21
+ @items << project
22
+ refresh_dependants(project)
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ def exist?(name)
29
+ !!find(name)
30
+ end
31
+
32
+ def find(name)
33
+ @items.select { |i| i.name == name }&.first
34
+ end
35
+
36
+ def all
37
+ @items
38
+ end
39
+
40
+ def order(key)
41
+ if key.to_sym == :name
42
+ @items = order_by_name
43
+ self
44
+ elsif key.to_sym == :dependants
45
+ @items = order_by_dependants
46
+ self
47
+ else
48
+ raise "Invalid order key: #{key}"
49
+ end
50
+ end
51
+
52
+ def filter(key)
53
+ if key.to_sym == :apps
54
+ @items = @items.select { |i| i.type == "app" }
55
+ self
56
+ elsif key.to_sym == :gems
57
+ @items = @items.select { |i| i.type == "gem" }
58
+ self
59
+ else
60
+ raise "Invalid filter key: #{key}"
61
+ end
62
+ end
63
+
64
+ def to_table
65
+ rows = []
66
+ @items.each do |project|
67
+ rows << [project.name, project.type, project.gem_name, project.test_frameworks.join(", "), project.dependants.join(", ")]
68
+ end
69
+ table = Terminal::Table.new(
70
+ headings: ["Project", "Type", "Gem Name", "Test Framework(s)", "Dependants"],
71
+ rows: rows,
72
+ style: { padding_left: 2, padding_right: 2, border_i: "o" },
73
+ )
74
+ puts table
75
+ end
76
+
77
+ private
78
+ def refresh_dependants(project)
79
+ @items.each do |other_project|
80
+ next if other_project == project
81
+ other_project.dependencies.each do |dep_name, _|
82
+ if dep_name == project.gem_name
83
+ project.dependants << other_project.name
84
+ break
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ def order_by_name
91
+ @items.sort_by(&:name)
92
+ end
93
+
94
+ def order_by_dependants
95
+ sorted_items = []
96
+ items = @items.dup # make a copy of items to avoid modifying @items
97
+ dependants = Hash.new { |h, k| h[k] = [] }
98
+
99
+ # build a hash of dependants for each project
100
+ items.each do |project|
101
+ project.dependants.each do |dependant|
102
+ dependants[dependant] << project.name
103
+ end
104
+ end
105
+
106
+ # perform a topological sort
107
+ until items.empty?
108
+ no_dependencies = items.select { |project| dependants[project.name].empty? }
109
+ raise "Circular dependency detected" if no_dependencies.empty?
110
+ sorted_items.concat(no_dependencies)
111
+ no_dependencies.each do |project|
112
+ items.delete(project)
113
+ dependants.each { |_, v| v.delete(project.name) }
114
+ end
115
+ end
116
+
117
+ sorted_items
118
+ end
119
+
120
+ end
121
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+ require "fileutils"
5
+
6
+ module Monoz
7
+ module Services
8
+ class BaseService
9
+ include Thor::Shell
10
+
11
+ def initialize(thor_instance)
12
+ @thor = thor_instance
13
+ end
14
+
15
+ class << self
16
+ def call(path)
17
+ new(path).call
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+ require "fileutils"
5
+
6
+ module Monoz
7
+ module Services
8
+ class InitService < Monoz::Services::BaseService
9
+ def call(path)
10
+ config_file_path = File.join(File.expand_path(path), "monoz.yml")
11
+ project_dir = File.dirname(config_file_path)
12
+
13
+ if File.exist?(config_file_path)
14
+ @thor.say "Error: monoz.yaml already exists in #{config_file_path}", :red
15
+ return
16
+ end
17
+
18
+ FileUtils.mkdir_p(project_dir)
19
+ FileUtils.mkdir_p(File.join(project_dir, "apps"))
20
+ FileUtils.mkdir_p(File.join(project_dir, "gems"))
21
+ FileUtils.touch(File.join(project_dir, "apps/.keep"))
22
+ FileUtils.touch(File.join(project_dir, "gems/.keep"))
23
+ File.write(config_file_path, Monoz::Configuration.default_config.to_yaml)
24
+
25
+ FileUtils.chdir(project_dir) do
26
+ system "git", "init"
27
+ end
28
+
29
+ @thor.say "Successfully initialized Monoz in #{project_dir}", :green
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+ require "fileutils"
5
+
6
+ module Monoz
7
+ module Services
8
+ class RunActionService < Monoz::Services::BaseService
9
+ def call(keys = nil)
10
+ action = Monoz.config.dig("actions", *keys)
11
+
12
+ if action.nil?
13
+ say "Invalid action: ", :red, false
14
+ say keys, [:red, :bold]
15
+ exit 0
16
+ end
17
+
18
+ pp action
19
+ # Monoz.projects.order(:dependants).each do |project|
20
+ # project.run "ls"
21
+ # end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,3 @@
1
+ module Monoz
2
+ VERSION = "0.1.0"
3
+ end
data/lib/monoz.rb ADDED
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "monoz/version"
4
+
5
+ require "pathname"
6
+
7
+ module Monoz
8
+ module Errors
9
+ class ConfigurationNotFound < StandardError; end
10
+ end
11
+
12
+ module Cli
13
+ autoload "Bundle", "monoz/cli/bundle"
14
+ autoload "Inspect", "monoz/cli/inspect"
15
+ autoload "Main", "monoz/cli/main"
16
+ autoload "Run", "monoz/cli/run"
17
+ end
18
+
19
+ module Services
20
+ autoload "BaseService", "monoz/services/base_service"
21
+ autoload "InitService", "monoz/services/init_service"
22
+ autoload "RunActionService", "monoz/services/run_action_service"
23
+ end
24
+
25
+ autoload "Configuration", "monoz/configuration"
26
+ autoload "Project", "monoz/project"
27
+ autoload "ProjectCollection", "monoz/project_collection"
28
+
29
+ class << self
30
+ def config
31
+ @config ||= Monoz::Configuration.new(pwd)
32
+ end
33
+
34
+ def projects
35
+ Monoz::ProjectCollection.new(config.root_path)
36
+ end
37
+
38
+ def pwd
39
+ @pwd ||= Pathname.new(Dir.pwd)
40
+ end
41
+
42
+ def pwd=(value)
43
+ @pwd = value
44
+ end
45
+ end
46
+ end
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: monoz
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - kjellberg
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-04-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '7'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '7'
41
+ - !ruby/object:Gem::Dependency
42
+ name: terminal-table
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 3.0.1
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 3.0.1
55
+ description: Command line tool for managing ruby monorepos.
56
+ email:
57
+ - 2277443+kjellberg@users.noreply.github.com
58
+ executables:
59
+ - monoz
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - README.md
64
+ - bin/monoz
65
+ - lib/monoz.rb
66
+ - lib/monoz/cli/bundle.rb
67
+ - lib/monoz/cli/inspect.rb
68
+ - lib/monoz/cli/main.rb
69
+ - lib/monoz/configuration.rb
70
+ - lib/monoz/project.rb
71
+ - lib/monoz/project_collection.rb
72
+ - lib/monoz/services/base_service.rb
73
+ - lib/monoz/services/init_service.rb
74
+ - lib/monoz/services/run_action_service.rb
75
+ - lib/monoz/version.rb
76
+ homepage: https://github.com/kjellberg/monoz
77
+ licenses:
78
+ - MIT
79
+ metadata:
80
+ homepage_uri: https://github.com/kjellberg/monoz
81
+ source_code_uri: https://github.com/kjellberg/monoz
82
+ changelog_uri: https://github.com/kjellberg/monoz
83
+ post_install_message:
84
+ rdoc_options: []
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: 2.6.0
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ requirements: []
98
+ rubygems_version: 3.4.5
99
+ signing_key:
100
+ specification_version: 4
101
+ summary: Command line tool for managing ruby monorepos.
102
+ test_files: []