packwerk 2.3.0 → 3.0.1

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.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +2 -5
  3. data/.ruby-version +1 -1
  4. data/Gemfile +0 -1
  5. data/Gemfile.lock +5 -95
  6. data/README.md +2 -7
  7. data/RESOLVING_VIOLATIONS.md +3 -8
  8. data/TROUBLESHOOT.md +2 -25
  9. data/UPGRADING.md +12 -0
  10. data/USAGE.md +136 -54
  11. data/dev.yml +1 -1
  12. data/exe/packwerk +4 -0
  13. data/gemfiles/Gemfile-rails-6-1 +1 -1
  14. data/lib/packwerk/application_validator.rb +54 -285
  15. data/lib/packwerk/association_inspector.rb +2 -0
  16. data/lib/packwerk/cache.rb +6 -5
  17. data/lib/packwerk/checker.rb +54 -0
  18. data/lib/packwerk/cli/result.rb +11 -0
  19. data/lib/packwerk/cli.rb +55 -40
  20. data/lib/packwerk/configuration.rb +61 -40
  21. data/lib/packwerk/const_node_inspector.rb +2 -0
  22. data/lib/packwerk/constant_context.rb +8 -0
  23. data/lib/packwerk/constant_discovery.rb +5 -6
  24. data/lib/packwerk/constant_name_inspector.rb +2 -0
  25. data/lib/packwerk/disable_sorbet.rb +41 -0
  26. data/lib/packwerk/extension_loader.rb +24 -0
  27. data/lib/packwerk/file_processor.rb +3 -1
  28. data/lib/packwerk/files_for_processing.rb +25 -12
  29. data/lib/packwerk/formatters/default_offenses_formatter.rb +77 -0
  30. data/lib/packwerk/formatters/progress_formatter.rb +31 -12
  31. data/lib/packwerk/generators/configuration_file.rb +7 -2
  32. data/lib/packwerk/generators/root_package.rb +5 -1
  33. data/lib/packwerk/generators/templates/package.yml +0 -10
  34. data/lib/packwerk/graph.rb +10 -2
  35. data/lib/packwerk/node.rb +1 -1
  36. data/lib/packwerk/node_helpers.rb +14 -7
  37. data/lib/packwerk/node_processor.rb +2 -0
  38. data/lib/packwerk/node_processor_factory.rb +6 -4
  39. data/lib/packwerk/node_visitor.rb +10 -1
  40. data/lib/packwerk/offense_collection.rb +26 -18
  41. data/lib/packwerk/offenses_formatter.rb +59 -2
  42. data/lib/packwerk/package.rb +7 -35
  43. data/lib/packwerk/package_set.rb +1 -1
  44. data/lib/packwerk/package_todo.rb +19 -20
  45. data/lib/packwerk/parse_run.rb +27 -34
  46. data/lib/packwerk/parsed_constant_definitions.rb +28 -5
  47. data/lib/packwerk/parsers/erb.rb +23 -4
  48. data/lib/packwerk/parsers/factory.rb +11 -2
  49. data/lib/packwerk/parsers/parser_interface.rb +1 -1
  50. data/lib/packwerk/parsers/ruby.rb +13 -3
  51. data/lib/packwerk/parsers.rb +6 -2
  52. data/lib/packwerk/{application_load_paths.rb → rails_load_paths.rb} +6 -4
  53. data/lib/packwerk/reference.rb +7 -1
  54. data/lib/packwerk/reference_checking/checkers/dependency_checker.rb +29 -6
  55. data/lib/packwerk/reference_checking/reference_checker.rb +1 -1
  56. data/lib/packwerk/reference_extractor.rb +24 -12
  57. data/lib/packwerk/reference_offense.rb +2 -2
  58. data/lib/packwerk/run_context.rb +7 -10
  59. data/lib/packwerk/spring_command.rb +9 -2
  60. data/lib/packwerk/unresolved_reference.rb +9 -1
  61. data/lib/packwerk/validator/result.rb +18 -0
  62. data/lib/packwerk/validator.rb +90 -0
  63. data/lib/packwerk/validators/dependency_validator.rb +154 -0
  64. data/lib/packwerk/version.rb +1 -1
  65. data/lib/packwerk.rb +64 -26
  66. data/packwerk.gemspec +4 -2
  67. data/sorbet/rbi/gems/{zeitwerk@2.6.0.rbi → zeitwerk@2.6.4.rbi} +291 -228
  68. data/sorbet/rbi/shims/minitest/test.rb +8 -0
  69. data/sorbet/rbi/shims/packwerk/reference.rbi +33 -0
  70. data/sorbet/rbi/shims/packwerk/unresolved_reference.rbi +33 -0
  71. data/sorbet/rbi/shims/parser.rbi +13 -0
  72. metadata +34 -15
  73. data/lib/packwerk/formatters/offenses_formatter.rb +0 -52
  74. data/lib/packwerk/reference_checking/checkers/checker.rb +0 -34
  75. data/lib/packwerk/reference_checking/checkers/privacy_checker.rb +0 -76
  76. data/lib/packwerk/result.rb +0 -9
  77. data/lib/packwerk/sanity_checker.rb +0 -8
  78. data/lib/packwerk/violation_type.rb +0 -11
  79. data/sorbet/rbi/gems/html_tokenizer@0.0.7.rbi +0 -46
  80. data/sorbet/rbi/gems/mini_portile2@2.8.0.rbi +0 -8
@@ -0,0 +1,8 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Minitest
5
+ class Test
6
+ include StubConst
7
+ end
8
+ end
@@ -0,0 +1,33 @@
1
+ # typed: true
2
+
3
+ module Packwerk
4
+ class Reference
5
+ sig do
6
+ params(
7
+ package: Package,
8
+ relative_path: String,
9
+ constant: ConstantContext,
10
+ source_location: T.nilable(Node::Location),
11
+ ).void
12
+ end
13
+ def initialize(
14
+ package:,
15
+ relative_path:,
16
+ constant:,
17
+ source_location:
18
+ )
19
+ end
20
+
21
+ sig { returns(Package) }
22
+ attr_reader(:package)
23
+
24
+ sig { returns(T.nilable(String)) }
25
+ attr_reader(:relative_path)
26
+
27
+ sig { returns(ConstantContext) }
28
+ attr_reader(:constant)
29
+
30
+ sig { returns(T.nilable(Node::Location)) }
31
+ attr_reader(:source_location)
32
+ end
33
+ end
@@ -0,0 +1,33 @@
1
+ # typed: true
2
+
3
+ module Packwerk
4
+ class UnresolvedReference
5
+ sig do
6
+ params(
7
+ constant_name: String,
8
+ namespace_path: T.nilable(T::Array[String]),
9
+ relative_path: String,
10
+ source_location: T.nilable(Node::Location),
11
+ ).void
12
+ end
13
+ def initialize(
14
+ constant_name:,
15
+ namespace_path:,
16
+ relative_path:,
17
+ source_location:
18
+ )
19
+ end
20
+
21
+ sig { returns(String) }
22
+ attr_reader(:constant_name)
23
+
24
+ sig { returns(T.nilable(T::Array[String])) }
25
+ attr_reader(:namespace_path)
26
+
27
+ sig { returns(String) }
28
+ attr_reader(:relative_path)
29
+
30
+ sig { returns(T.nilable(Node::Location)) }
31
+ attr_reader(:source_location)
32
+ end
33
+ end
@@ -0,0 +1,13 @@
1
+ # typed: strict
2
+
3
+ class Parser::Base < ::Racc::Parser
4
+ # Parses a source buffer and returns the AST, or `nil` in case of a non fatal error.
5
+ #
6
+ # @api public
7
+ # @param source_buffer [Parser::Source::Buffer] The source buffer to parse.
8
+ # @return [Parser::AST::Node, nil]
9
+ #
10
+ # source://parser-3.1.2.1/lib/parser/base.rb:186
11
+ sig { params(source_buffer: Parser::Source::Buffer).returns(T.nilable(Parser::AST::Node)) }
12
+ def parse(source_buffer); end
13
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: packwerk
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
4
+ version: 3.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-02-21 00:00:00.000000000 Z
11
+ date: 2023-03-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '5.2'
19
+ version: '6.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '5.2'
26
+ version: '6.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -136,6 +136,20 @@ dependencies:
136
136
  - - ">="
137
137
  - !ruby/object:Gem::Version
138
138
  version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: railties
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
139
153
  description: |
140
154
  Sets package level boundaries between a specified set of ruby
141
155
  constants to minimize cross-boundary referencing and dependency.
@@ -179,18 +193,22 @@ files:
179
193
  - gemfiles/Gemfile-rails-6-0
180
194
  - gemfiles/Gemfile-rails-6-1
181
195
  - lib/packwerk.rb
182
- - lib/packwerk/application_load_paths.rb
183
196
  - lib/packwerk/application_validator.rb
184
197
  - lib/packwerk/association_inspector.rb
185
198
  - lib/packwerk/cache.rb
199
+ - lib/packwerk/checker.rb
186
200
  - lib/packwerk/cli.rb
201
+ - lib/packwerk/cli/result.rb
187
202
  - lib/packwerk/configuration.rb
188
203
  - lib/packwerk/const_node_inspector.rb
204
+ - lib/packwerk/constant_context.rb
189
205
  - lib/packwerk/constant_discovery.rb
190
206
  - lib/packwerk/constant_name_inspector.rb
207
+ - lib/packwerk/disable_sorbet.rb
208
+ - lib/packwerk/extension_loader.rb
191
209
  - lib/packwerk/file_processor.rb
192
210
  - lib/packwerk/files_for_processing.rb
193
- - lib/packwerk/formatters/offenses_formatter.rb
211
+ - lib/packwerk/formatters/default_offenses_formatter.rb
194
212
  - lib/packwerk/formatters/progress_formatter.rb
195
213
  - lib/packwerk/generators/configuration_file.rb
196
214
  - lib/packwerk/generators/root_package.rb
@@ -218,20 +236,19 @@ files:
218
236
  - lib/packwerk/parsers/factory.rb
219
237
  - lib/packwerk/parsers/parser_interface.rb
220
238
  - lib/packwerk/parsers/ruby.rb
239
+ - lib/packwerk/rails_load_paths.rb
221
240
  - lib/packwerk/reference.rb
222
- - lib/packwerk/reference_checking/checkers/checker.rb
223
241
  - lib/packwerk/reference_checking/checkers/dependency_checker.rb
224
- - lib/packwerk/reference_checking/checkers/privacy_checker.rb
225
242
  - lib/packwerk/reference_checking/reference_checker.rb
226
243
  - lib/packwerk/reference_extractor.rb
227
244
  - lib/packwerk/reference_offense.rb
228
- - lib/packwerk/result.rb
229
245
  - lib/packwerk/run_context.rb
230
- - lib/packwerk/sanity_checker.rb
231
246
  - lib/packwerk/spring_command.rb
232
247
  - lib/packwerk/unresolved_reference.rb
248
+ - lib/packwerk/validator.rb
249
+ - lib/packwerk/validator/result.rb
250
+ - lib/packwerk/validators/dependency_validator.rb
233
251
  - lib/packwerk/version.rb
234
- - lib/packwerk/violation_type.rb
235
252
  - packwerk.gemspec
236
253
  - shipit.rubygems.yml
237
254
  - sorbet/config
@@ -258,7 +275,6 @@ files:
258
275
  - sorbet/rbi/gems/digest@3.1.0.rbi
259
276
  - sorbet/rbi/gems/erubi@1.11.0.rbi
260
277
  - sorbet/rbi/gems/globalid@1.0.0.rbi
261
- - sorbet/rbi/gems/html_tokenizer@0.0.7.rbi
262
278
  - sorbet/rbi/gems/i18n@1.12.0.rbi
263
279
  - sorbet/rbi/gems/json@2.6.2.rbi
264
280
  - sorbet/rbi/gems/language_server-protocol@3.16.0.3.rbi
@@ -268,7 +284,6 @@ files:
268
284
  - sorbet/rbi/gems/marcel@1.0.2.rbi
269
285
  - sorbet/rbi/gems/method_source@1.0.0.rbi
270
286
  - sorbet/rbi/gems/mini_mime@1.1.2.rbi
271
- - sorbet/rbi/gems/mini_portile2@2.8.0.rbi
272
287
  - sorbet/rbi/gems/minitest-focus@1.3.1.rbi
273
288
  - sorbet/rbi/gems/minitest@5.16.2.rbi
274
289
  - sorbet/rbi/gems/mocha@1.14.0.rbi
@@ -318,7 +333,11 @@ files:
318
333
  - sorbet/rbi/gems/websocket-extensions@0.1.5.rbi
319
334
  - sorbet/rbi/gems/yard-sorbet@0.6.1.rbi
320
335
  - sorbet/rbi/gems/yard@0.9.28.rbi
321
- - sorbet/rbi/gems/zeitwerk@2.6.0.rbi
336
+ - sorbet/rbi/gems/zeitwerk@2.6.4.rbi
337
+ - sorbet/rbi/shims/minitest/test.rb
338
+ - sorbet/rbi/shims/packwerk/reference.rbi
339
+ - sorbet/rbi/shims/packwerk/unresolved_reference.rbi
340
+ - sorbet/rbi/shims/parser.rbi
322
341
  - sorbet/rbi/shims/psych.rbi
323
342
  - sorbet/tapioca/require.rb
324
343
  homepage: https://github.com/Shopify/packwerk
@@ -337,7 +356,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
337
356
  requirements:
338
357
  - - ">="
339
358
  - !ruby/object:Gem::Version
340
- version: '2.6'
359
+ version: '2.7'
341
360
  required_rubygems_version: !ruby/object:Gem::Requirement
342
361
  requirements:
343
362
  - - ">="
@@ -1,52 +0,0 @@
1
- # typed: strict
2
- # frozen_string_literal: true
3
-
4
- module Packwerk
5
- module Formatters
6
- class OffensesFormatter
7
- include Packwerk::OffensesFormatter
8
-
9
- extend T::Sig
10
-
11
- sig { params(style: OutputStyle).void }
12
- def initialize(style: OutputStyles::Plain.new)
13
- @style = style
14
- end
15
-
16
- sig { override.params(offenses: T::Array[T.nilable(Offense)]).returns(String) }
17
- def show_offenses(offenses)
18
- return "No offenses detected" if offenses.empty?
19
-
20
- <<~EOS
21
- #{offenses_list(offenses)}
22
- #{offenses_summary(offenses)}
23
- EOS
24
- end
25
-
26
- sig { override.params(offense_collection: Packwerk::OffenseCollection, fileset: T::Set[String]).returns(String) }
27
- def show_stale_violations(offense_collection, fileset)
28
- if offense_collection.stale_violations?(fileset)
29
- "There were stale violations found, please run `packwerk update-todo`"
30
- else
31
- "No stale violations detected"
32
- end
33
- end
34
-
35
- private
36
-
37
- sig { params(offenses: T::Array[T.nilable(Offense)]).returns(String) }
38
- def offenses_list(offenses)
39
- offenses
40
- .compact
41
- .map { |offense| offense.to_s(@style) }
42
- .join("\n")
43
- end
44
-
45
- sig { params(offenses: T::Array[T.nilable(Offense)]).returns(String) }
46
- def offenses_summary(offenses)
47
- offenses_string = "offense".pluralize(offenses.length)
48
- "#{offenses.length} #{offenses_string} detected"
49
- end
50
- end
51
- end
52
- end
@@ -1,34 +0,0 @@
1
- # typed: strict
2
- # frozen_string_literal: true
3
-
4
- module Packwerk
5
- module ReferenceChecking
6
- module Checkers
7
- module Checker
8
- extend T::Sig
9
- extend T::Helpers
10
-
11
- abstract!
12
-
13
- sig { abstract.returns(ViolationType) }
14
- def violation_type; end
15
-
16
- sig { abstract.params(reference: Reference).returns(T::Boolean) }
17
- def invalid_reference?(reference); end
18
-
19
- sig { abstract.params(reference: Reference).returns(String) }
20
- def message(reference); end
21
-
22
- sig { params(reference: Reference).returns(String) }
23
- def standard_help_message(reference)
24
- standard_message = <<~EOS
25
- Inference details: this is a reference to #{reference.constant.name} which seems to be defined in #{reference.constant.location}.
26
- To receive help interpreting or resolving this error message, see: https://github.com/Shopify/packwerk/blob/main/TROUBLESHOOT.md#Troubleshooting-violations
27
- EOS
28
-
29
- standard_message.chomp
30
- end
31
- end
32
- end
33
- end
34
- end
@@ -1,76 +0,0 @@
1
- # typed: strict
2
- # frozen_string_literal: true
3
-
4
- module Packwerk
5
- module ReferenceChecking
6
- module Checkers
7
- # Checks whether a given reference references a private constant of another package.
8
- class PrivacyChecker
9
- extend T::Sig
10
- include Checker
11
-
12
- sig { override.returns(Packwerk::ViolationType) }
13
- def violation_type
14
- ViolationType::Privacy
15
- end
16
-
17
- sig do
18
- override
19
- .params(reference: Packwerk::Reference)
20
- .returns(T::Boolean)
21
- end
22
- def invalid_reference?(reference)
23
- return false if reference.constant.public?
24
-
25
- privacy_option = reference.constant.package.enforce_privacy
26
- return false if enforcement_disabled?(privacy_option)
27
-
28
- return false unless privacy_option == true ||
29
- explicitly_private_constant?(reference.constant, explicitly_private_constants: privacy_option)
30
-
31
- true
32
- end
33
-
34
- sig do
35
- override
36
- .params(reference: Packwerk::Reference)
37
- .returns(String)
38
- end
39
- def message(reference)
40
- source_desc = "'#{reference.source_package}'"
41
-
42
- message = <<~EOS
43
- Privacy violation: '#{reference.constant.name}' is private to '#{reference.constant.package}' but referenced from #{source_desc}.
44
- Is there a public entrypoint in '#{reference.constant.package.public_path}' that you can use instead?
45
-
46
- #{standard_help_message(reference)}
47
- EOS
48
-
49
- message.chomp
50
- end
51
-
52
- private
53
-
54
- sig do
55
- params(
56
- constant: ConstantDiscovery::ConstantContext,
57
- explicitly_private_constants: T::Array[String]
58
- ).returns(T::Boolean)
59
- end
60
- def explicitly_private_constant?(constant, explicitly_private_constants:)
61
- explicitly_private_constants.include?(constant.name) ||
62
- # nested constants
63
- explicitly_private_constants.any? { |epc| constant.name.start_with?(epc + "::") }
64
- end
65
-
66
- sig do
67
- params(privacy_option: T.nilable(T.any(T::Boolean, T::Array[String])))
68
- .returns(T::Boolean)
69
- end
70
- def enforcement_disabled?(privacy_option)
71
- [false, nil].include?(privacy_option)
72
- end
73
- end
74
- end
75
- end
76
- end
@@ -1,9 +0,0 @@
1
- # typed: strict
2
- # frozen_string_literal: true
3
-
4
- module Packwerk
5
- class Result < T::Struct
6
- const :message, String
7
- const :status, T::Boolean
8
- end
9
- end
@@ -1,8 +0,0 @@
1
- # typed: strict
2
- # frozen_string_literal: true
3
-
4
- module Packwerk
5
- # To do: This alias and file should be removed as it is deprecated
6
- warn("DEPRECATION WARNING: Packwerk::SanityChecker is deprecated, use Packwerk::ApplicationValidator instead.")
7
- SanityChecker = ApplicationValidator
8
- end
@@ -1,11 +0,0 @@
1
- # typed: strict
2
- # frozen_string_literal: true
3
-
4
- module Packwerk
5
- class ViolationType < T::Enum
6
- enums do
7
- Privacy = new
8
- Dependency = new
9
- end
10
- end
11
- end
@@ -1,46 +0,0 @@
1
- # DO NOT EDIT MANUALLY
2
- # This is an autogenerated file for types exported from the `html_tokenizer` gem.
3
- # Please instead update this file by running `dev typecheck update`.
4
-
5
- # typed: true
6
-
7
- module HtmlTokenizer
8
- end
9
-
10
- class HtmlTokenizer::Parser
11
- def initialize; end
12
-
13
- def append_placeholder(_); end
14
- def attribute_name; end
15
- def attribute_quoted?; end
16
- def attribute_value; end
17
- def cdata_text; end
18
- def closing_tag?; end
19
- def column_number; end
20
- def comment_text; end
21
- def context; end
22
- def document; end
23
- def document_length; end
24
- def errors; end
25
- def errors_count; end
26
- def line_number; end
27
- def parse(_); end
28
- def quote_character; end
29
- def rawtext_text; end
30
- def self_closing_tag?; end
31
- def tag_name; end
32
- end
33
-
34
- class HtmlTokenizer::ParserError < ::RuntimeError
35
- def initialize(message, position, line, column); end
36
-
37
- def column; end
38
- def line; end
39
- def position; end
40
- end
41
-
42
- class HtmlTokenizer::Tokenizer
43
- def initialize; end
44
-
45
- def tokenize(_); end
46
- end
@@ -1,8 +0,0 @@
1
- # typed: true
2
-
3
- # DO NOT EDIT MANUALLY
4
- # This is an autogenerated file for types exported from the `mini_portile2` gem.
5
- # Please instead update this file by running `bin/tapioca gem mini_portile2`.
6
-
7
- # THIS IS AN EMPTY RBI FILE.
8
- # see https://github.com/Shopify/tapioca/wiki/Manual-Gem-Requires