monoz 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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.