packs 0.0.22 → 0.0.24

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: bfd963aed9035b204092449d956a985ebdd62eec89bd32d522b2a8ca7a82ad74
4
- data.tar.gz: 7a4e8471530a3847b42f9b1bd3f8523fa920e3b2e3f6c83036279d25ff9173b2
3
+ metadata.gz: e9fe9bf45b169182149107b9617affd7f2b678c23568d040f16a4bcb6dfd1b1f
4
+ data.tar.gz: ade3de604d5b0a7fb3b25770eb08dce6a953028f32c66008882b80c16e4a9006
5
5
  SHA512:
6
- metadata.gz: 23442ca91f171f85f9b2d523cc91bd34ace4186dbbb8b6f92f57ca896c473c3bcc0556c27a2e869d55285ff8c40e72df4a019af678c2f60a674af6230dae5d1a
7
- data.tar.gz: 8754d2368251ab1ec8073191e38791dffd6c79f07c6a8eaaa49cd69d6dae0b99def340fde2c050140fdce8017612d2266d22b13b81ddafa8cbe6f67192cbeb7a
6
+ metadata.gz: 30171b07e4b4ad796dfdd0cd1ca4425bae6f974e75cf7a70e3f2c46ad296117d5002a29303830f033913d34be90e894d5dc21230cf5cec3a64c9bc8d7af5a370
7
+ data.tar.gz: 3ea267d582ea488d4f425321f2e111c0b9adeca1b092649ccb82f88314fe8572b7a4f922936822dc84a9ad8c3c39adbe57c7a60b6dd0b7bdbe76502da7a8b795
data/README.md CHANGED
@@ -1,9 +1,36 @@
1
- # Packs
1
+ # packs
2
2
 
3
- Packs is a gem that helps in creating and maintaining packs. It exists to help perform some basic operations needed for pack setup and configuration. It provides a basic ruby file packager utility for [`packwerk`](https://github.com/Shopify/packwerk/). It assumes you are using [`packs-rails`](https://github.com/rubyatscale/packs-rails) to organize your packages.
3
+ `packs` are a specification for an extensible packaging system to help modularize Ruby applications.
4
+
5
+ A `pack` (short for `package`) is a folder of Ruby code with a `package.yml` at the root that is intended to represent a well-modularized domain.
6
+
7
+ This gem provides a development CLI, `bin/packs`, to make using `packs` easier.
8
+
9
+ # Configuration
10
+ By default, this library will look for `packs` in the folder `packs/*/package.yml` (as well as nested packs at `packs/*/*/package.yml`). To change where `packs` are located, create a `packs.yml` file:
11
+ ```yml
12
+ pack_paths:
13
+ - "{packs,utilities,deprecated}/*" # packs with multiple roots!
14
+ - "{packs,utilities,deprecated}/*/*" # nested packs!
15
+ - gems/* # gems can be packs too!
16
+ ```
17
+
18
+ # Ecosystem
19
+ The rest of the [rubyatscale](https://github.com/rubyatscale) ecosystem is intended to help make using packs and improving the boundaries between them more clear.
20
+
21
+ Here are some example integrations with `packs`:
22
+ - [`packs-specification`](https://github.com/rubyatscale/packs-specification) is a low-dependency gem that allows your production environment to query simple information about packs
23
+ - [`packs-rails`](https://github.com/rubyatscale/packs-rails) can be used to integrate `packs` into your `rails` application
24
+ - [`rubocop-packs`](https://github.com/rubyatscale/rubocop-packs) contains cops to improve boundaries around `packs`
25
+ - [`packwerk`](https://github.com/Shopify/packwerk) and [`packwerk-extensions`](https://github.com/rubyatscale/packwerk-extensions) help you describe and constrain your package graph in terms of dependencies between packs and pack public API
26
+ - [`code_ownership`](https://github.com/rubyatscale/code_ownership) gives your application the capability to determine the owner of a pack
27
+ - [`pack_stats`](https://github.com/rubyatscale/pack_stats) makes it easy to send metrics about pack adoption and modularization to your favorite metrics provider, such as DataDog (which has built-in support).
28
+
29
+ # How is a pack different from a gem?
30
+ A ruby [`gem`](https://guides.rubygems.org/what-is-a-gem/) is the Ruby community solution for packaging and distributing Ruby code. A gem is a great place to start new projects, and a great end state for code that's been extracted from an existing codebase. `packs` are intended to help gradually modularize an application that has some conceptual boundaries, but is not yet ready to be factored into gems.
4
31
 
5
32
  ## Usage
6
- Make sure to run `bundle binstub use_packs` to generate `bin/packs` within your application.
33
+ Make sure to run `bundle binstub packs` to generate `bin/packs` within your application.
7
34
 
8
35
  ## CLI Documentation
9
36
  ## Describe available commands or one specific command
@@ -90,16 +117,16 @@ Releases happen automatically through github actions once a version update is co
90
117
  To keep things organized, here are some recommended homes:
91
118
 
92
119
  ### Issues:
93
- https://github.com/rubyatscale/use_packs/issues
120
+ https://github.com/rubyatscale/packs/issues
94
121
 
95
122
  ### Questions:
96
- https://github.com/rubyatscale/use_packs/discussions/categories/q-a
123
+ https://github.com/rubyatscale/packs/discussions/categories/q-a
97
124
 
98
125
  ### General discussions:
99
- https://github.com/rubyatscale/use_packs/discussions/categories/general
126
+ https://github.com/rubyatscale/packs/discussions/categories/general
100
127
 
101
128
  ### Ideas, new features, requests for change:
102
- https://github.com/rubyatscale/use_packs/discussions/categories/ideas
129
+ https://github.com/rubyatscale/packs/discussions/categories/ideas
103
130
 
104
131
  ### Showcasing your work:
105
- https://github.com/rubyatscale/use_packs/discussions/categories/show-and-tell
132
+ https://github.com/rubyatscale/packs/discussions/categories/show-and-tell
data/lib/packs/cli.rb CHANGED
@@ -10,6 +10,7 @@ module Packs
10
10
  sig { params(pack_name: String).void }
11
11
  def create(pack_name)
12
12
  Packs.create_pack!(pack_name: pack_name)
13
+ exit_successfully
13
14
  end
14
15
 
15
16
  desc 'add_dependency packs/from_pack packs/to_pack', 'Add packs/to_pack to packs/from_pack/package.yml list of dependencies'
@@ -27,6 +28,7 @@ module Packs
27
28
  pack_name: from_pack,
28
29
  dependency_name: to_pack
29
30
  )
31
+ exit_successfully
30
32
  end
31
33
 
32
34
  desc 'list_top_dependency_violations packs/your_pack', 'List the top dependency violations of packs/your_pack'
@@ -44,6 +46,7 @@ module Packs
44
46
  pack_name: pack_name,
45
47
  limit: options[:limit]
46
48
  )
49
+ exit_successfully
47
50
  end
48
51
 
49
52
  desc 'list_top_privacy_violations packs/your_pack', 'List the top privacy violations of packs/your_pack'
@@ -61,6 +64,7 @@ module Packs
61
64
  pack_name: pack_name,
62
65
  limit: options[:limit]
63
66
  )
67
+ exit_successfully
64
68
  end
65
69
 
66
70
  desc 'make_public path/to/file.rb path/to/directory', 'Make files or directories public API'
@@ -75,6 +79,7 @@ module Packs
75
79
  paths_relative_to_root: paths,
76
80
  per_file_processors: [Packs::RubocopPostProcessor.new, Packs::CodeOwnershipPostProcessor.new]
77
81
  )
82
+ exit_successfully
78
83
  end
79
84
 
80
85
  desc 'move packs/destination_pack path/to/file.rb path/to/directory', 'Move files or directories from one pack to another'
@@ -91,6 +96,7 @@ module Packs
91
96
  paths_relative_to_root: paths,
92
97
  per_file_processors: [Packs::RubocopPostProcessor.new, Packs::CodeOwnershipPostProcessor.new]
93
98
  )
99
+ exit_successfully
94
100
  end
95
101
 
96
102
  desc 'lint_package_todo_yml_files', 'Lint `package_todo.yml` files to check for formatting issues'
@@ -108,37 +114,40 @@ module Packs
108
114
  desc 'validate', 'Run bin/packwerk validate (detects cycles)'
109
115
  sig { void }
110
116
  def validate
111
- system('bin/packwerk validate')
117
+ Private.exit_with(Packs.validate)
112
118
  end
113
119
 
114
120
  desc 'check [ packs/my_pack ]', 'Run bin/packwerk check'
115
121
  sig { params(paths: String).void }
116
122
  def check(*paths)
117
- Packs.execute(['check', *paths])
123
+ Private.exit_with(Packs.check(paths))
118
124
  end
119
125
 
120
126
  desc 'update', 'Run bin/packwerk update-todo'
121
127
  sig { void }
122
128
  def update
123
- system('bin/packwerk update-todo')
129
+ Private.exit_with(Packs.update)
124
130
  end
125
131
 
126
132
  desc 'get_info [ packs/my_pack packs/my_other_pack ]', 'Get info about size and violations for packs'
127
133
  sig { params(pack_names: String).void }
128
134
  def get_info(*pack_names)
129
135
  Private.get_info(packs: parse_pack_names(pack_names))
136
+ exit_successfully
130
137
  end
131
138
 
132
139
  desc 'visualize [ packs/my_pack packs/my_other_pack ]', 'Visualize packs'
133
140
  sig { params(pack_names: String).void }
134
141
  def visualize(*pack_names)
135
142
  Private.visualize(packs: parse_pack_names(pack_names))
143
+ exit_successfully
136
144
  end
137
145
 
138
146
  desc 'rename', 'Rename a pack'
139
147
  sig { void }
140
148
  def rename
141
149
  puts Private.rename_pack
150
+ exit_successfully
142
151
  end
143
152
 
144
153
  desc 'move_to_parent packs/child_pack packs/parent_pack ', 'Set packs/child_pack as a child of packs/parent_pack'
@@ -149,6 +158,7 @@ module Packs
149
158
  pack_name: child_pack_name,
150
159
  per_file_processors: [Packs::RubocopPostProcessor.new, Packs::CodeOwnershipPostProcessor.new]
151
160
  )
161
+ exit_successfully
152
162
  end
153
163
 
154
164
  private
@@ -159,6 +169,11 @@ module Packs
159
169
  def parse_pack_names(pack_names)
160
170
  pack_names.empty? ? Packs.all : pack_names.map { |p| Packs.find(p.gsub(%r{/$}, '')) }.compact
161
171
  end
172
+
173
+ sig { void }
174
+ def exit_successfully
175
+ Private.exit_with(true)
176
+ end
162
177
  end
163
178
  end
164
179
  end
@@ -16,7 +16,7 @@ module Packs
16
16
 
17
17
  sig { override.params(prompt: TTY::Prompt).void }
18
18
  def perform!(prompt)
19
- system('bin/packwerk check')
19
+ Private.exit_with(Packs.check([]))
20
20
  end
21
21
  end
22
22
  end
@@ -10,9 +10,9 @@ module Packs
10
10
 
11
11
  interface!
12
12
 
13
- sig { params(base: Class).void }
13
+ sig { params(base: T::Class[T.anything]).void }
14
14
  def self.included(base)
15
- @use_cases ||= T.let(@use_cases, T.nilable(T::Array[Class]))
15
+ @use_cases ||= T.let(@use_cases, T.nilable(T::Array[T::Class[T.anything]]))
16
16
  @use_cases ||= []
17
17
  @use_cases << base
18
18
  end
@@ -16,7 +16,7 @@ module Packs
16
16
 
17
17
  sig { override.params(prompt: TTY::Prompt).void }
18
18
  def perform!(prompt)
19
- system('bin/packwerk update')
19
+ Private.exit_with(Packs.update)
20
20
  end
21
21
  end
22
22
  end
@@ -16,7 +16,7 @@ module Packs
16
16
 
17
17
  sig { override.params(prompt: TTY::Prompt).void }
18
18
  def perform!(prompt)
19
- system('bin/packwerk validate')
19
+ Private.exit_with(Packs.validate)
20
20
  end
21
21
  end
22
22
  end
data/lib/packs/private.rb CHANGED
@@ -8,7 +8,6 @@ require 'sorbet-runtime'
8
8
  require 'packs/private/file_move_operation'
9
9
  require 'packs/private/pack_relationship_analyzer'
10
10
  require 'packs/private/interactive_cli'
11
- require 'packs/private/packwerk_wrapper'
12
11
 
13
12
  module Packs
14
13
  module Private
@@ -295,7 +294,7 @@ module Packs
295
294
  config: package.config
296
295
  )
297
296
  ParsePackwerk.write_package_yml!(new_package)
298
- PackwerkWrapper.validate!
297
+ Packs.validate
299
298
  end
300
299
 
301
300
  sig { params(file_move_operation: FileMoveOperation, per_file_processors: T::Array[Packs::PerFileProcessorInterface]).void }
@@ -404,7 +403,7 @@ module Packs
404
403
  return if @loaded_client_configuration
405
404
 
406
405
  @loaded_client_configuration = true
407
- client_configuration = Pathname.pwd.join('config/use_packs.rb')
406
+ client_configuration = Pathname.pwd.join('config/packs.rb')
408
407
  require client_configuration.to_s if client_configuration.exist?
409
408
  end
410
409
 
@@ -523,13 +522,13 @@ module Packs
523
522
  sig { void }
524
523
  def self.lint_package_todo_yml_files!
525
524
  contents_before = Private.get_package_todo_contents
526
- Packs.execute(['update-todo'])
525
+ Packs.update
527
526
  contents_after = Private.get_package_todo_contents
528
527
  diff = Private.diff_package_todo_yml(contents_before, contents_after)
529
528
 
530
529
  if diff == ''
531
530
  # No diff generated by `update-todo`
532
- safe_exit 0
531
+ exit_with true
533
532
  else
534
533
  output = <<~OUTPUT
535
534
  All `package_todo.yml` files must be up-to-date and that no diff is generated when running `bin/packwerk update-todo`.
@@ -551,7 +550,7 @@ module Packs
551
550
 
552
551
  puts output
553
552
  Packs.config.on_package_todo_lint_failure.call(output)
554
- safe_exit 1
553
+ exit_with false
555
554
  end
556
555
  end
557
556
 
@@ -608,10 +607,16 @@ module Packs
608
607
  end
609
608
 
610
609
  # This function exists to give us something to stub in test
611
- sig { params(code: Integer).void }
612
- def self.safe_exit(code)
610
+ sig { params(code: T::Boolean).void }
611
+ def self.exit_with(code)
613
612
  exit code
614
613
  end
614
+
615
+ # This function exists to give us something to stub in test
616
+ sig { params(command: String).returns(T::Boolean) }
617
+ def self.system_with(command)
618
+ T.cast(system(command), T::Boolean)
619
+ end
615
620
  end
616
621
 
617
622
  private_constant :Private
@@ -193,7 +193,7 @@ module Packs
193
193
 
194
194
  sig { returns(String) }
195
195
  def documentation_link
196
- 'https://github.com/rubyatscale/use_packs#readme'
196
+ 'https://github.com/rubyatscale/packs#readme'
197
197
  end
198
198
  end
199
199
  end
data/lib/packs.rb CHANGED
@@ -36,6 +36,21 @@ module Packs
36
36
  Private::InteractiveCli.start!
37
37
  end
38
38
 
39
+ sig { returns(T::Boolean) }
40
+ def self.update
41
+ Private.system_with('bin/packwerk update-todo')
42
+ end
43
+
44
+ sig { returns(T::Boolean) }
45
+ def self.validate
46
+ Private.system_with('bin/packwerk validate')
47
+ end
48
+
49
+ sig { params(files: T::Array[String]).returns(T::Boolean) }
50
+ def self.check(files)
51
+ Private.system_with("bin/packwerk check #{files.join(' ')}")
52
+ end
53
+
39
54
  sig do
40
55
  params(
41
56
  pack_name: String,
@@ -222,32 +237,6 @@ module Packs
222
237
  Specification.bust_cache!
223
238
  end
224
239
 
225
- #
226
- # execute_command is like `run` except it does not `exit`
227
- #
228
- sig { params(argv: T.untyped, formatter: T.nilable(Packwerk::OffensesFormatter)).void }
229
- def self.execute(argv, formatter = nil)
230
- Private::PackwerkWrapper.with_safe_exit_if_no_files_found do
231
- Private::PackwerkWrapper.packwerk_cli(formatter).execute_command(argv)
232
- end
233
- end
234
-
235
- sig { params(files: T::Array[String]).returns(T::Array[Packwerk::ReferenceOffense]) }
236
- def self.get_offenses_for_files(files)
237
- formatter = Private::PackwerkWrapper::OffensesAggregatorFormatter.new
238
- Private::PackwerkWrapper.packwerk_cli_execute_safely(['check', *files], formatter)
239
- formatter.aggregated_offenses.compact
240
- end
241
-
242
- sig { params(files: T::Array[String]).returns(T::Array[Packwerk::ReferenceOffense]) }
243
- def self.get_offenses_for_files_by_package(files)
244
- packages = Private::PackwerkWrapper.package_names_for_files(files)
245
- argv = ['check', '--packages', packages.join(',')]
246
- formatter = Private::PackwerkWrapper::OffensesAggregatorFormatter.new
247
- Private::PackwerkWrapper.packwerk_cli_execute_safely(argv, formatter)
248
- formatter.aggregated_offenses.compact
249
- end
250
-
251
240
  sig { void }
252
241
  def self.lint_package_todo_yml_files!
253
242
  Private.lint_package_todo_yml_files!
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: packs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.22
4
+ version: 0.0.24
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gusto Engineers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-10 00:00:00.000000000 Z
11
+ date: 2023-08-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: code_ownership
@@ -276,6 +276,20 @@ dependencies:
276
276
  - - ">="
277
277
  - !ruby/object:Gem::Version
278
278
  version: '0'
279
+ - !ruby/object:Gem::Dependency
280
+ name: spoom
281
+ requirement: !ruby/object:Gem::Requirement
282
+ requirements:
283
+ - - '='
284
+ - !ruby/object:Gem::Version
285
+ version: 1.2.1
286
+ type: :development
287
+ prerelease: false
288
+ version_requirements: !ruby/object:Gem::Requirement
289
+ requirements:
290
+ - - '='
291
+ - !ruby/object:Gem::Version
292
+ version: 1.2.1
279
293
  - !ruby/object:Gem::Dependency
280
294
  name: tapioca
281
295
  requirement: !ruby/object:Gem::Requirement
@@ -331,7 +345,6 @@ files:
331
345
  - lib/packs/private/interactive_cli/use_cases/validate.rb
332
346
  - lib/packs/private/interactive_cli/use_cases/visualize.rb
333
347
  - lib/packs/private/pack_relationship_analyzer.rb
334
- - lib/packs/private/packwerk_wrapper.rb
335
348
  - lib/packs/private/packwerk_wrapper/offenses_aggregator_formatter.rb
336
349
  - lib/packs/rubocop_post_processor.rb
337
350
  - lib/packs/user_event_logger.rb
@@ -1,70 +0,0 @@
1
- # typed: strict
2
-
3
- require 'packwerk'
4
- require 'packs/private/packwerk_wrapper/offenses_aggregator_formatter'
5
-
6
- module Packs
7
- module Private
8
- module PackwerkWrapper
9
- extend T::Sig
10
-
11
- #
12
- # execute_command is like `run` except it does not `exit`
13
- #
14
- sig { params(argv: T.untyped, formatter: T.nilable(Packwerk::OffensesFormatter)).void }
15
- def self.packwerk_cli_execute_safely(argv, formatter = nil)
16
- with_safe_exit_if_no_files_found do
17
- packwerk_cli(formatter).execute_command(argv)
18
- end
19
- end
20
-
21
- sig { params(block: T.proc.returns(T.untyped)).void }
22
- def self.with_safe_exit_if_no_files_found(&block)
23
- block.call
24
- rescue SystemExit => e
25
- # Packwerk should probably exit positively here rather than raising an error -- there should be no
26
- # errors if the user has excluded all files being checked.
27
- unless e.message == 'No files found or given. Specify files or check the include and exclude glob in the config file.'
28
- raise
29
- end
30
- end
31
-
32
- sig { params(formatter: T.nilable(Packwerk::OffensesFormatter)).returns(Packwerk::Cli) }
33
- def self.packwerk_cli(formatter)
34
- # This is mostly copied from exe/packwerk within the packwerk gem, but we use our own formatters
35
- # Note that packwerk does not allow you to pass in your own progress formatter currently
36
- ENV['RAILS_ENV'] = 'test'
37
-
38
- style = Packwerk::OutputStyles::Coloured.new
39
- Packwerk::Cli.new(style: style, offenses_formatter: formatter)
40
- end
41
-
42
- sig { params(files: T::Array[String]).returns(T::Array[Packwerk::ReferenceOffense]) }
43
- def self.get_offenses_for_files(files)
44
- formatter = OffensesAggregatorFormatter.new
45
- packwerk_cli_execute_safely(['check', *files], formatter)
46
- formatter.aggregated_offenses.compact
47
- end
48
-
49
- sig { void }
50
- def self.validate!
51
- formatter = OffensesAggregatorFormatter.new
52
- packwerk_cli_execute_safely(['validate'], formatter)
53
- end
54
-
55
- sig { params(files: T::Array[String]).returns(T::Array[Packwerk::ReferenceOffense]) }
56
- def self.get_offenses_for_files_by_package(files)
57
- packages = package_names_for_files(files)
58
- argv = ['check', '--packages', packages.join(',')]
59
- formatter = OffensesAggregatorFormatter.new
60
- packwerk_cli_execute_safely(argv, formatter)
61
- formatter.aggregated_offenses.compact
62
- end
63
-
64
- sig { params(files: T::Array[String]).returns(T::Array[String]) }
65
- def self.package_names_for_files(files)
66
- files.map { |f| ParsePackwerk.package_from_path(f).name }.compact.uniq
67
- end
68
- end
69
- end
70
- end