monoz 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e73d1688f568042f98029b57b070f6541c3a19ba0ae206c7f89a3ecb60dda061
4
- data.tar.gz: 3f9a57bfc7abacf3bf67783e713d3e92bcc6bea586c0c8c53b1b298c3ecfc990
3
+ metadata.gz: a4b5b401a4bf7239ed13540d493ca21b270307357e9e0c6aa4eaadacb7b0a887
4
+ data.tar.gz: 0537ac18ffe150db50875fb8c1dd7537019792d50616cef4693f4fbf9192913d
5
5
  SHA512:
6
- metadata.gz: 4d5a0d391b17475e9a5d0a05a1bacf8815d5f8d23ed79608dabd1fd31c4df491dad9fa0f33c9ae058e69ffaaa1138a4c0def0cb4e5e1a752ff13281822191fd0
7
- data.tar.gz: ae0449a70ae6c4b0a8474fd4d80fc8d39e26c4316b2a6191eccf16e3a6dc55bbc310902db0a0fae04423d35ca3421b8f016e3594dcb8a72df07b585c03483d26
6
+ metadata.gz: d2c82d448831e9cfec6901a3dcc09b9b2531a63621849a2def1c4b50aa2f150547148ef01a454eb7f57012922da93560fd3884f497ba79a9965f227be4e78abe
7
+ data.tar.gz: a569b1c68211574c5e03beeb87a6d95b9cc7047d41c692c095f0e63168e5aec03fcc6bb3fe1f01c7ce0d6d980393148b7da327f9926df6e35655a32b73f18e59
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
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
4
 
5
- ## Installation
5
+ ## Getting started
6
6
 
7
7
  You can install Monoz by running the following command:
8
8
 
@@ -10,8 +10,6 @@ You can install Monoz by running the following command:
10
10
  $ gem install monoz
11
11
  ```
12
12
 
13
- ## Getting started
14
-
15
13
  To initialize a Monoz repository in the current directory, simply run:
16
14
 
17
15
  ```console
@@ -29,7 +27,9 @@ This will create a new Monoz repo with the following structure:
29
27
  └── monoz.yml
30
28
  ```
31
29
 
32
- ### Adding projects
30
+ ## Projects
31
+
32
+ ### Add a project
33
33
 
34
34
  Once you've initialized your Monoz repository, you can start adding projects to it.
35
35
 
@@ -72,6 +72,13 @@ To update the dependencies of all projects in the Monoz repository, simply run:
72
72
 
73
73
  ```console
74
74
  $ monoz bundle update
75
+
76
+ kiqr_core: bundle update ✓
77
+ content_api: bundle update ✓
78
+ core_api: bundle update ✓
79
+ kiqr_cloud: bundle update ✓
80
+
81
+ The command ran successfully in all projects without any errors.
75
82
  ```
76
83
 
77
84
  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.
@@ -95,6 +102,27 @@ Error: The command bundle exec rubocop failed to run in one or more project dire
95
102
 
96
103
  This will execute the `bundle exec rubocop` command in each project directory, ensuring that all the necessary dependencies are installed and loaded for each project. Similarly, you can run other bundler commands such as `bundle install`, `bundle update`, and so on, by appending the desired arguments to the `monoz bundle` command.
97
104
 
105
+ ### List projects
106
+
107
+ You can inspect the projects in your Monoz repository using the `monoz projects` 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.
108
+
109
+ Here's an example output of the `monoz projects` command:
110
+
111
+ ```console
112
+ $ monoz projects
113
+
114
+ o---------------o--------o-------------o---------------------o-------------------------------------o
115
+ | Project | Type | Gem Name | Test Framework(s) | Dependants |
116
+ o---------------o--------o-------------o---------------------o-------------------------------------o
117
+ | content_api | app | | rspec | |
118
+ | core_api | app | | rspec | |
119
+ | kiqr_cloud | app | | rspec | |
120
+ | kiqr_core | gem | kiqr_core | rspec | content_api, core_api, kiqr_cloud |
121
+ o---------------o--------o-------------o---------------------o-------------------------------------o
122
+ ```
123
+
124
+ ## Runing commands
125
+
98
126
  ### Running commands in projects
99
127
 
100
128
  You can run any command in all projects of your Monoz repository using the `monoz run` command. Simply provide the command you want to run as an argument, and Monoz will execute it in each project directory.
@@ -144,20 +172,32 @@ example_com: bin/dev
144
172
  23:41:06 css.1 | Done in 354ms.
145
173
  ```
146
174
 
147
- ### Filter projects
175
+ ### Filtering projects
148
176
 
149
177
  The `--filter` option in Monoz allows you to select certain projects based on specific criteria. This is useful if you only want to run a command on a specific subset of projects, rather than all of them. To use the `--filter` option, you simply specify a filter expression after the option. The filter expression is a comma-separated list of keywords that match the project names or tags in your Monoz configuration.
150
178
 
151
- For example, suppose you have a Monoz configuration with several projects, some of which are tagged as **apps** and some of which are tagged as **gems**. You can use the "--filter" option to select only the **apps** projects by running the following command:
179
+ For example, suppose you have a Monoz configuration with several projects, some of which are tagged as **apps** and some of which are tagged as **gems**. You can use the `--filter` option to select only the **apps** projects by running the following command:
152
180
 
153
181
  ```console
154
182
  $ monoz bundle --filter=apps
183
+
184
+ content_api: bundle ✓
185
+ core_api: bundle ✓
186
+ kiqr_cloud: bundle ✓
187
+
188
+ The command ran successfully in all project directories without any errors.
155
189
  ```
156
190
 
157
191
  Similarly, if you only want to list only gem projects, you can use the following command:
158
192
 
159
193
  ```console
160
194
  $ monoz projects --filter=gems
195
+
196
+ o-------------o--------o-------------o----------------------o-------------------------------------o
197
+ | Project | Type | Gem name | Found Framework(s) | Dependants |
198
+ o-------------o--------o-------------o----------------------o-------------------------------------o
199
+ | kiqr_core | gem | kiqr_core | rspec | content_api, core_api, kiqr_cloud |
200
+ o-------------o--------o-------------o----------------------o-------------------------------------o
161
201
  ```
162
202
 
163
203
  You can also use multiple keywords in the filter expression to select projects that match any of the keywords. For example, to run the `mrsk deploy` command on all **apps** and **apis** projects, you can use the following command:
@@ -172,25 +212,6 @@ Finally, you can also specify individual project names in the filter expression.
172
212
  $ monoz run rubocop --filter="gem1,gem2"
173
213
  ```
174
214
 
175
- ### List projects
176
-
177
- You can inspect the projects in your Monoz repository using the `monoz projects` 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.
178
-
179
- Here's an example output of the `monoz projects` command:
180
-
181
- ```console
182
- $ monoz projects
183
-
184
- o---------------o--------o-------------o---------------------o-------------------------------------o
185
- | Project | Type | Gem Name | Test Framework(s) | Dependants |
186
- o---------------o--------o-------------o---------------------o-------------------------------------o
187
- | content_api | app | | rspec | |
188
- | core_api | app | | rspec | |
189
- | kiqr_cloud | app | | rspec | |
190
- | kiqr_core | gem | kiqr_core | rspec | content_api, core_api, kiqr_cloud |
191
- o---------------o--------o-------------o---------------------o-------------------------------------o
192
- ```
193
-
194
215
  ## Contributing
195
216
  We welcome contributions from everyone! If you're interested in contributing to Monoz, please check out our contributing guidelines for more information.
196
217
 
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Monoz
4
+ class ActionCommand
5
+ attr_reader :filter, :command
6
+ def initialize(filter, command)
7
+ @filter = filter
8
+ @command = command
9
+ end
10
+ end
11
+
12
+ class Action
13
+ attr_reader :name, :commands
14
+
15
+ def initialize(name, raw_commands)
16
+ @name = name
17
+ @commands = []
18
+ parse_commands(raw_commands)
19
+ end
20
+
21
+ private
22
+ def parse_commands(raw_commands)
23
+ raw_commands.each do |command|
24
+ @commands << Monoz::ActionCommand.new(command.dig("in"), command.dig("run"))
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/module/delegation"
4
+
5
+ module Monoz
6
+ class ActionCollection
7
+ include Enumerable
8
+ delegate_missing_to :@items
9
+
10
+ def initialize
11
+ @items = []
12
+ populate_items
13
+ end
14
+
15
+ def exist?(name)
16
+ !!find(name)
17
+ end
18
+
19
+ def find(name)
20
+ @items.select { |i| i.name == name.to_s }&.first
21
+ end
22
+
23
+ def all
24
+ @items
25
+ end
26
+
27
+ private
28
+ def populate_items
29
+ actions = Monoz.config.dig("actions")
30
+ return if actions.empty?
31
+
32
+ raise "Invalid format, actions must be a hash." unless actions.is_a?(Hash)
33
+
34
+ actions.each do |action_name, config_raw_data|
35
+ @items << Monoz::Action.new(action_name, config_raw_data)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -6,7 +6,7 @@ require "fileutils"
6
6
 
7
7
  module Monoz
8
8
  class Application < Thor
9
- class_option :tty, type: :boolean, aliases: ["--verbose", "-t"], default: false
9
+ class_option :verbose, type: :boolean, aliases: ["--tty", "-t"], default: false
10
10
  class_option :filter
11
11
 
12
12
  def initialize(*args)
@@ -49,5 +49,11 @@ module Monoz
49
49
  def version
50
50
  say "Monoz version: #{Monoz::VERSION}"
51
51
  end
52
+
53
+ # This method will be called when a command is not found
54
+ desc "[ACTION]", "Custom action"
55
+ def method_missing(action_name, *args)
56
+ Monoz::Services::ActionService.new(self).call(action_name)
57
+ end
52
58
  end
53
59
  end
@@ -11,7 +11,7 @@ module Monoz
11
11
 
12
12
  def initialize(file_path)
13
13
  @items = []
14
- project_folders = Monoz.config.dig("folders") || ["apps", "gems"]
14
+ project_folders = Monoz.folders
15
15
 
16
16
  search_paths = project_folders.map { |folder| File.join(file_path, folder) }
17
17
 
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+ require "fileutils"
5
+
6
+ module Monoz
7
+ module Services
8
+ class ActionService < Monoz::Services::BaseService
9
+ def call(action)
10
+ @action = Monoz.actions.find(action)
11
+ say_invalid_action(action) if @action.nil?
12
+ Monoz.verbose = true
13
+ run_action
14
+ end
15
+
16
+ private
17
+ def run_action
18
+ say "Running Monoz action: "
19
+ say @action.name, [:bold, :blue]
20
+
21
+ @action.commands.each do |action_command|
22
+ projects = Monoz.projects.filter(action_command.filter).order(:dependants)
23
+ command = action_command.command.split(" ")
24
+ Monoz::Services::RunService.new(self).call(projects, *command)
25
+ end
26
+ end
27
+
28
+ def say_invalid_action(cmd_or_action)
29
+ say "Error: The command or action ", :red
30
+ say "#{cmd_or_action} ", [:red, :bold]
31
+ say "does not exist.", [:red]
32
+ exit(1)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -2,35 +2,44 @@
2
2
 
3
3
  require "yaml"
4
4
  require "fileutils"
5
- require "open3"
5
+ require "pty"
6
6
 
7
7
  module Monoz
8
- module Services
9
- class RunService < Monoz::Services::BaseService
10
- attr_reader :errors, :warnings
8
+ module Responses
9
+ class RunServiceResponse
10
+ attr_reader :output, :exit_code
11
11
 
12
- def initialize(thor_instance)
13
- @projects = nil
14
- @errors = []
15
- @warnings = []
16
- super(thor_instance)
12
+ def initialize(output, exit_code)
13
+ @output = output
14
+ @exit_code = exit_code
17
15
  end
18
16
 
19
17
  def success?
20
- !errors? && !warnings?
18
+ exit_code == 0
21
19
  end
22
20
 
23
- def errors?
24
- @errors.any?
21
+ def failed?
22
+ !!success?
25
23
  end
24
+ end
25
+ end
26
26
 
27
- def warnings?
28
- @warnings.any?
27
+ module Services
28
+ class RunService < Monoz::Services::BaseService
29
+ attr_reader :errors, :warnings
30
+
31
+ def initialize(thor_instance)
32
+ super(thor_instance)
33
+ @projects = nil
34
+ @errors = []
35
+ @warnings = []
36
+ @command = []
29
37
  end
30
38
 
31
39
  def call(projects, *command)
32
- raise ArgumentError.new("Missing command") if command.empty?
40
+ raise ArgumentError, "Missing command" if command.empty?
33
41
 
42
+ @command = command
34
43
  if projects.is_a?(Monoz::ProjectCollection)
35
44
  @projects = projects.all
36
45
  elsif projects.is_a?(Monoz::Project)
@@ -39,30 +48,16 @@ module Monoz
39
48
  raise "Invalid projects"
40
49
  end
41
50
 
42
- @projects.each do |project|
43
- say "#{project.name}: ", [:bold, :blue]
44
- Monoz.tty? ? say(command.join(" ")) : say("#{command.join(" ")} ")
45
-
46
- response = run_commands_in_project(project, *command)
47
-
48
- if response.success?
49
- say "\u2713", [:green, :bold] unless Monoz.tty? # Checkmark symbol in green and bold
50
- else
51
- say "\u2717", [:red, :bold] unless Monoz.tty? # Cross symbol in red
52
- say response.output
53
- say ""
54
- @errors << {
55
- project: project.name,
56
- command: command.join(" "),
57
- exit_code: response.exit_code,
58
- output: response.output
59
- }
60
- end
61
- end
51
+ say "Running ", nil, false
52
+ say command.join(" "), [:bold], false
53
+ say " in #{@projects.map { |p| p.name }.join(", ")}:"
62
54
 
55
+ say ""
56
+ run_commands
63
57
  say ""
64
58
 
65
59
  if errors?
60
+ say ""
66
61
  say "Error: The command ", :red
67
62
  say "#{command.join(" ")} ", [:red, :bold]
68
63
  say "failed to run in one or more project directories", [:red]
@@ -70,32 +65,74 @@ module Monoz
70
65
  end
71
66
  end
72
67
 
68
+ def success?
69
+ !errors? && !warnings?
70
+ end
71
+
72
+ def errors?
73
+ @errors.any?
74
+ end
75
+
76
+ def warnings?
77
+ @warnings.any?
78
+ end
79
+
73
80
  private
74
- def run_commands_in_project(project, *command)
75
- raise ArgumentError.new("Invalid command") if command.empty?
81
+ def run_commands
82
+ @projects.each do |project|
83
+ if spinner?
84
+ spinner = Monoz::Spinner.new(@command.join(" "), prefix: project.name).start
85
+ else
86
+ say "[#{project.name}] ", [:blue, :bold], nil
87
+ say @command.join(" ")
88
+ end
89
+
90
+ response = run_in_project(project, *@command)
91
+
92
+ if response.success?
93
+ spinner&.success! if spinner?
94
+ else
95
+ spinner&.error! if spinner?
96
+ say response.output
97
+ say "" # line break
98
+ @errors << {
99
+ project: project.name,
100
+ command: @command.join(" "),
101
+ exit_code: response.exit_code,
102
+ output: response.output
103
+ }
104
+ end
105
+ end
106
+ end
107
+
108
+ def spinner?
109
+ !Monoz.verbose?
110
+ end
111
+
112
+ def run_in_project(project, *command)
113
+ raise ArgumentError, "Invalid command" if command.empty?
76
114
 
77
115
  output = ""
78
116
  exit_status = nil
79
117
 
80
118
  FileUtils.chdir(project.root_path) do
81
- if Monoz.tty?
82
- Open3.popen2e(*command.map { |arg| Shellwords.escape(arg) }) do |stdin, stdout_err, wait_thr|
83
- while line = stdout_err.gets
119
+ PTY.spawn(*command.map { |arg| Shellwords.escape(arg) }) do |stdout, stdin, pid|
120
+ begin
121
+ stdout.each do |line|
84
122
  output += line
85
- print line
123
+ print line if Monoz.verbose?
86
124
  end
87
-
88
- exit_status = wait_thr.value.exitstatus
125
+ rescue Errno::EIO
89
126
  end
90
127
 
91
- say ""
92
- else
93
- output, status = Open3.capture2e(*command.map { |arg| Shellwords.escape(arg) })
94
- exit_status = status.exitstatus
128
+ Process.wait(pid)
129
+ exit_status = $?.exitstatus
95
130
  end
96
131
  end
97
132
 
98
- return Monoz::Responses::CaptureRunResponse.new(output, exit_status)
133
+ Monoz::Responses::RunServiceResponse.new(output, exit_status)
134
+ rescue Errno::ENOENT => e
135
+ Monoz::Responses::RunServiceResponse.new(e.message, 1)
99
136
  end
100
137
  end
101
138
  end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Monoz
4
+ class Spinner
5
+ include Thor::Shell
6
+
7
+ def initialize(message, prefix: nil)
8
+ @spinner = nil
9
+ @message = message
10
+ @prefix = prefix
11
+ end
12
+
13
+ def start
14
+ @spinner = main
15
+ self
16
+ end
17
+
18
+ def success!
19
+ @spinner.kill
20
+ say_formatted(" \u2713 ", [:bold, :green])
21
+ say() # line break
22
+ end
23
+
24
+ def error!
25
+ @spinner.kill
26
+ say_formatted(" \u2717 ", [:bold, :red])
27
+ say() # line break
28
+ end
29
+
30
+ private
31
+ def reset
32
+ say("\r", nil, false)
33
+ end
34
+
35
+ def say_formatted(suffix, suffix_formatting = nil)
36
+ if @prefix != nil
37
+ say "\r[#{@prefix}] ", [:blue, :bold], nil
38
+ say @message, nil, false
39
+ say suffix, suffix_formatting, false
40
+ else
41
+ say "\r#{@message}", nil, false
42
+ say suffix, suffix_formatting, false
43
+ end
44
+ end
45
+
46
+ def main
47
+ spinner_count = 0
48
+
49
+ Thread.new do
50
+ loop do
51
+ dots = case spinner_count % 3
52
+ when 0 then "."
53
+ when 1 then ".."
54
+ when 2 then "..."
55
+ end
56
+
57
+ say_formatted(dots)
58
+ spinner_count += 1
59
+ sleep(0.5)
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
data/lib/monoz/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Monoz
2
- VERSION = "0.4.0"
2
+ VERSION = "0.5.0"
3
3
  end
data/lib/monoz.rb CHANGED
@@ -11,35 +11,20 @@ module Monoz
11
11
  class ConfigurationNotFound < StandardError; end
12
12
  end
13
13
 
14
- module Responses
15
- class CaptureRunResponse
16
- attr_reader :output, :exit_code
17
-
18
- def initialize(output, exit_code)
19
- @output = output
20
- @exit_code = exit_code
21
- end
22
-
23
- def success?
24
- exit_code == 0
25
- end
26
-
27
- def error?
28
- exit_code == 1
29
- end
30
- end
31
- end
32
-
33
14
  module Services
15
+ autoload "ActionService", "monoz/services/action_service"
34
16
  autoload "BaseService", "monoz/services/base_service"
35
17
  autoload "InitService", "monoz/services/init_service"
36
18
  autoload "RunService", "monoz/services/run_service"
37
19
  end
38
20
 
21
+ autoload "Action", "monoz/action"
22
+ autoload "ActionCollection", "monoz/action_collection"
39
23
  autoload "Application", "monoz/application"
40
24
  autoload "Configuration", "monoz/configuration"
41
25
  autoload "Project", "monoz/project"
42
26
  autoload "ProjectCollection", "monoz/project_collection"
27
+ autoload "Spinner", "monoz/spinner"
43
28
 
44
29
  class << self
45
30
  def app
@@ -54,12 +39,24 @@ module Monoz
54
39
  @config ||= Monoz::Configuration.new(pwd)
55
40
  end
56
41
 
42
+ def actions
43
+ @actions ||= Monoz::ActionCollection.new
44
+ end
45
+
57
46
  def options
58
47
  @app&.options
59
48
  end
60
49
 
61
- def tty?
62
- Monoz.options.dig("tty") == true
50
+ def folders
51
+ config.dig("folders") || ["apps", "gems"]
52
+ end
53
+
54
+ def verbose?
55
+ @verbose ||= Monoz.options.dig("verbose") == true
56
+ end
57
+
58
+ def verbose=(value)
59
+ @verbose = value
63
60
  end
64
61
 
65
62
  def projects
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: monoz
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - kjellberg
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-04-04 00:00:00.000000000 Z
11
+ date: 2023-04-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -64,13 +64,17 @@ files:
64
64
  - README.md
65
65
  - bin/monoz
66
66
  - lib/monoz.rb
67
+ - lib/monoz/action.rb
68
+ - lib/monoz/action_collection.rb
67
69
  - lib/monoz/application.rb
68
70
  - lib/monoz/configuration.rb
69
71
  - lib/monoz/project.rb
70
72
  - lib/monoz/project_collection.rb
73
+ - lib/monoz/services/action_service.rb
71
74
  - lib/monoz/services/base_service.rb
72
75
  - lib/monoz/services/init_service.rb
73
76
  - lib/monoz/services/run_service.rb
77
+ - lib/monoz/spinner.rb
74
78
  - lib/monoz/version.rb
75
79
  homepage: https://github.com/kjellberg/monoz
76
80
  licenses:
@@ -94,7 +98,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
94
98
  - !ruby/object:Gem::Version
95
99
  version: '0'
96
100
  requirements: []
97
- rubygems_version: 3.4.5
101
+ rubygems_version: 3.4.10
98
102
  signing_key:
99
103
  specification_version: 4
100
104
  summary: Command line tool for managing ruby monorepos.