packwerk 1.0.0 → 1.0.1

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: cdc39eaf91ef0f8f247cc31b54a3bb1680fcc0ddee4e9552f60a8c9bbdcf3410
4
- data.tar.gz: d449d1c6484b490d79a6dd3d98b0cdc84bf2ffdae1aa0564544ee3aa1e592f12
3
+ metadata.gz: 6adf93154744a85f6f49a1b830710dee4f4c7b8e05373de50aef86926167f23e
4
+ data.tar.gz: cfea93c802c34114e63966717e7a643cf1de94f3061b13ed434b04dd12469bed
5
5
  SHA512:
6
- metadata.gz: c1f2d61a18cb126e85e824e0bc6d2a5854e2dd7114717165fb71ae9a5765f719464c7b66177078c01a5601aca9e8500112f68d695594a650f03da62a0d3054a2
7
- data.tar.gz: a674e776393ab5cc078ab21c9faefa554d54a85010bde8c40e47cb5bf6eed1b3e8e523cecce8f8673a0dfb606f455aac1ae3bb71b12acd7c5dfccffa2b645eda
6
+ metadata.gz: 00dfee149ce8b43ce862a0df57eda5af2583fd4066cd1596ffaae2a1a5f562150e8caf84d29f062e11a039bf08bea3eb360e9a2817b14c2d9229ce77a89dc2e4
7
+ data.tar.gz: f74cecc91b2fce594df2c1dae811d469a1f8e490daefbd396ed2fb87cb6438e7286de98f63c425d196af2b7ce4ed6f8ef6e0cfb9ddf8b47d17e38bbccda2a0db
@@ -1,6 +1,6 @@
1
1
  name: CI
2
2
 
3
- on: [push]
3
+ on: [push, pull_request]
4
4
 
5
5
  jobs:
6
6
  build:
data/.gitignore CHANGED
@@ -9,4 +9,5 @@
9
9
  /.bundle/
10
10
  /tmp/
11
11
  .rubocop-*
12
+ .byebug_history
12
13
  sorbet/rbi/hidden-definitions/errors.txt
@@ -85,7 +85,7 @@ GIT
85
85
  PATH
86
86
  remote: .
87
87
  specs:
88
- packwerk (1.0.0)
88
+ packwerk (1.0.1)
89
89
  activesupport (>= 5.2)
90
90
  ast
91
91
  better_html
data/README.md CHANGED
@@ -16,9 +16,9 @@ Packwerk supports MRI versions 2.6 and above.
16
16
 
17
17
  ## Demo
18
18
 
19
- Watch a [1-minute video demo](https://drive.google.com/file/d/1D-t1nYduwgpHAP4DHY-EwVwVNFHlwRWj/view?usp=sharing) on how Packwerk works.
19
+ Watch a [1-minute video demo](https://www.youtube.com/watch?v=NwqlyBAxVpQ&feature=youtu.be) on how Packwerk works.
20
20
 
21
- [![](./static/packwerk-check-demo.png)](https://drive.google.com/file/d/1D-t1nYduwgpHAP4DHY-EwVwVNFHlwRWj/view?usp=sharing)
21
+ [![](./static/packwerk-check-demo.png)](https://www.youtube.com/watch?v=NwqlyBAxVpQ&feature=youtu.be)
22
22
 
23
23
  ## Installation
24
24
 
@@ -28,6 +28,8 @@ Watch a [1-minute video demo](https://drive.google.com/file/d/1D-t1nYduwgpHAP4DH
28
28
  gem 'packwerk'
29
29
  ```
30
30
 
31
+ _Note: Packwerk has to be grouped in production environment within the Gemfile if your Rails app has custom inflections._
32
+
31
33
  2. Install the gem
32
34
 
33
35
  Execute:
@@ -16,7 +16,7 @@ You can specify folders or packages in Packwerk commands for a shorter run time:
16
16
 
17
17
  bundle exec packwerk check components/your_package
18
18
 
19
- bundle exec packwerk update components/your_package
19
+ bundle exec packwerk update-deprecations components/your_package
20
20
 
21
21
  _Note: You cannot specify folders or packages for `packwerk validate` because the command runs for the entire application._
22
22
 
data/USAGE.md CHANGED
@@ -47,11 +47,11 @@ Here is a list of files generated:
47
47
 
48
48
  | File | Location | Description |
49
49
  |-----------------------------|--------------|------------|
50
- | Packwerk configuration | packwerk.yml | See [Setting up configuration file](#Setting-up-configuration-file) |
50
+ | Packwerk configuration | packwerk.yml | See [Setting up the configuration file](#Setting-up-the-configuration-file) |
51
51
  | Root package | package.yml | A package for the root folder |
52
52
  | Bin script | bin/packwerk | For Rails applications to run Packwerk validation on CI, see [Validating the package system](#Validating-the-package-system) |
53
53
  | Validation test | test/packwerk_validator_test.rb | For Ruby projects to run Packwerk validation using tests, see [Validating the package system](#Validating-the-package-system) |
54
- | Custom inflections | configs/inflections.yml | A custom inflections file is only required if you have custom inflections in `inflections.rb`, see [Inflections](#Inflections) |
54
+ | Custom inflections | config/inflections.yml | A custom inflections file is only required if you have custom inflections in `inflections.rb`, see [Inflections](#Inflections) |
55
55
 
56
56
  After that, you may begin creating packages for your application. See [Defining packages](#Defining-packages)
57
57
 
@@ -59,33 +59,37 @@ After that, you may begin creating packages for your application. See [Defining
59
59
 
60
60
  Packwerk reads from the `packwerk.yml` configuration file in the root directory. Packwerk will run with the default configuration if any of these settings are not specified.
61
61
 
62
- | Key | Default value | Description |
63
- |----------------------|------------------------------------|--------------|
64
- | include | **/*.{rb,rake,erb} | list of patterns for folder paths to include |
65
- | exclude | {bin,node_modules,script,tmp}/**/* | list of patterns for folder paths to exclude |
66
- | package_paths | **/ | patterns to find package configuration files, see: Defining packages |
67
- | load_paths | All application autoload paths | list of load paths |
68
- | custom_associations | N/A | list of custom associations, if any |
62
+ | Key | Default value | Description |
63
+ |----------------------|-------------------------------------------|--------------|
64
+ | include | **/*.{rb,rake,erb} | list of patterns for folder paths to include |
65
+ | exclude | {bin,node_modules,script,tmp,vendor}/**/* | list of patterns for folder paths to exclude |
66
+ | package_paths | **/ | patterns to find package configuration files, see: Defining packages |
67
+ | load_paths | All application autoload paths | list of load paths |
68
+ | custom_associations | N/A | list of custom associations, if any |
69
69
 
70
70
 
71
71
  ### Inflections
72
72
 
73
73
  Packwerk requires custom inflections to be defined in `inflections.yml` instead of the traditional `inflections.rb`. This is because Packwerk accounts for custom inflections, such as acronyms, when resolving constants. Additionally, Packwerk interprets Active Record associations as references to constants. For example, `has_many :birds` is reference to the `Birds` constant.
74
74
 
75
- In order to make your custom inflections compatible with Active Support and Packwerk, you must create an `inflections.yml` file and point `ActiveSupport::Inflector` to that file.
75
+ In order to make your custom inflections compatible with Active Support and Packwerk, you must create a `config/inflections.yml` file and point `ActiveSupport::Inflector` to that file.
76
76
 
77
77
  In `inflections.rb`, add:
78
78
 
79
79
  ```rb
80
+ require "packwerk/inflections/custom"
81
+
80
82
  ActiveSupport::Inflector.inflections do |inflect|
81
83
  # please add all custom inflections in the file below.
82
84
  Packwerk::Inflections::Custom.new(
83
- Rails.root.join("inflections.yml")
85
+ Rails.root.join("config", "inflections.yml")
84
86
  ).apply_to(inflect)
85
87
  end
86
88
  ```
87
89
 
88
- Next, move your existing custom inflections into `inflections.yml`:
90
+ _Note: Packwerk has to be grouped in production environment within the Gemfile if you have custom inflections._
91
+
92
+ Next, move your existing custom inflections into `config/inflections.yml`:
89
93
 
90
94
  ```yaml
91
95
  acronym:
@@ -97,9 +101,11 @@ irregular:
97
101
  - ['reserve', 'reserves']
98
102
  uncountable:
99
103
  - 'payment_details'
104
+ singular:
105
+ - [!ruby/regexp /status$/, 'status']
100
106
  ```
101
107
 
102
- Any new inflectors should be added to `inflections.yml`.
108
+ Any new inflectors should be added to `config/inflections.yml`.
103
109
 
104
110
  ## Validating the package system
105
111
 
@@ -168,7 +174,17 @@ enforce_privacy:
168
174
  It will be a privacy violation when a file outside of the `components/merchandising` package tries to reference `Merchandising::Product`.
169
175
 
170
176
  ##### Using public folders
171
- You may enforce privacy either way mentioned above and still expose a public API for your package by placing constants in the `app/public` folder. The constants in the public folder will be made available for use by the rest of the application.
177
+ You may enforce privacy either way mentioned above and still expose a public API for your package by placing constants in the public folder, which by default is `app/public`. The constants in the public folder will be made available for use by the rest of the application.
178
+
179
+ ##### Defining your own public folder
180
+
181
+ You may prefer to override the default public folder, you can do so on a per-package basis by defining a `public_path`.
182
+
183
+ Example:
184
+
185
+ ```yaml
186
+ public_path: my/custom/path/
187
+ ```
172
188
 
173
189
  #### Enforcing dependency boundary
174
190
  A package's dependency boundary is violated whenever it references a constant in some package that has not been declared as a dependency.
@@ -210,17 +226,17 @@ For existing codebases, packages are likely to have existing boundary violations
210
226
 
211
227
  If so, you will want to stop the bleeding and prevent more violations from occuring. The existing violations in the codebase can be recorded in a [deprecated references list](#Understanding_the_list_of_deprecated_references) by executing:
212
228
 
213
- bundle exec packwerk update
229
+ bundle exec packwerk update-deprecations
214
230
 
215
- Similar to `packwerk check`, you may also run `packwerk update` on folders or packages:
231
+ Similar to `packwerk check`, you may also run `packwerk update-deprecations` on folders or packages:
216
232
 
217
- bundle exec packwerk update components/your_package
233
+ bundle exec packwerk update-deprecations components/your_package
218
234
 
219
235
  ![](static/packwerk_update.gif)
220
236
 
221
237
  _Note: Changing dependencies or enabling dependencies will not require a full update of the codebase, only the package that changed. On the other hand, changing or enabling privacy will require a full update of the codebase._
222
238
 
223
- `packwerk update` should only be run to record existing violations and to remove deprecated references that have been worked off. Running `packwerk update` to resolve a violation should be the very last resort.
239
+ `packwerk update-deprecations` should only be run to record existing violations and to remove deprecated references that have been worked off. Running `packwerk update-deprecations` to resolve a violation should be the very last resort.
224
240
 
225
241
  See: [TROUBLESHOOT.md - Troubleshooting violations](TROUBLESHOOT.md#Troubleshooting_violations)
226
242
 
@@ -34,7 +34,6 @@ require "packwerk/package_set"
34
34
  require "packwerk/parsers"
35
35
  require "packwerk/privacy_checker"
36
36
  require "packwerk/reference_extractor"
37
- require "packwerk/reference_lister"
38
37
  require "packwerk/run_context"
39
38
  require "packwerk/updating_deprecated_references"
40
39
  require "packwerk/version"
@@ -113,7 +113,7 @@ module Packwerk
113
113
  hash = YAML.load_file(f)
114
114
  next unless hash
115
115
 
116
- known_keys = %w(enforce_privacy enforce_dependencies dependencies metadata)
116
+ known_keys = %w(enforce_privacy enforce_dependencies public_path dependencies metadata)
117
117
  unknown_keys = hash.keys - known_keys
118
118
 
119
119
  unless unknown_keys.empty?
@@ -134,6 +134,12 @@ module Packwerk
134
134
  end
135
135
  end
136
136
 
137
+ if hash.key?("public_path")
138
+ unless hash["public_path"].is_a?(String)
139
+ errors << "'public_path' option must be a string in #{f.inspect}: #{hash['public_path'].inspect}"
140
+ end
141
+ end
142
+
137
143
  next unless hash.key?("dependencies")
138
144
  next if hash["dependencies"].is_a?(Array)
139
145
 
@@ -170,8 +176,8 @@ module Packwerk
170
176
  Packwerk::Inflections::Custom.new(inflections_file).apply_to(test_inflections)
171
177
 
172
178
  results = %i(plurals singulars uncountables humans acronyms).map do |type|
173
- expected = ActiveSupport::Inflector.inflections.public_send(type).to_a
174
- actual = test_inflections.public_send(type).to_a
179
+ expected = ActiveSupport::Inflector.inflections.public_send(type).to_set
180
+ actual = test_inflections.public_send(type).to_set
175
181
 
176
182
  if expected == actual
177
183
  Result.new(true)
@@ -325,7 +331,7 @@ module Packwerk
325
331
  end
326
332
 
327
333
  def package_manifests(glob_pattern)
328
- Dir.glob(File.join(glob_pattern, Packwerk::PackageSet::PACKAGE_CONFIG_FILENAME)).map { |f| File.realpath(f) }
334
+ PackageSet.package_paths(@configuration.root_path, glob_pattern).map(&:to_s)
329
335
  end
330
336
 
331
337
  def relative_paths(paths)
@@ -22,23 +22,38 @@ module Packwerk
22
22
  end
23
23
 
24
24
  def constant_name_from_node(node, ancestors:)
25
- return unless Node.type(node) == Node::METHOD_CALL
26
-
27
- method_name = Node.method_name(node)
28
- return nil unless @associations.include?(method_name)
25
+ return unless Node.method_call?(node)
26
+ return unless association?(node)
29
27
 
30
28
  arguments = Node.method_arguments(node)
31
- association_name = Node.literal_value(arguments[0]) if Node.type(arguments[0]) == Node::SYMBOL
32
- return nil unless association_name
29
+ return unless (association_name = association_name(arguments))
33
30
 
34
- association_options = arguments.detect { |n| Node.type(n) == Node::HASH }
35
- class_name_node = Node.value_from_hash(association_options, :class_name) if association_options
36
-
37
- if class_name_node
38
- Node.literal_value(class_name_node) if Node.type(class_name_node) == Node::STRING
31
+ if (class_name_node = custom_class_name(arguments))
32
+ return unless Node.string?(class_name_node)
33
+ Node.literal_value(class_name_node)
39
34
  else
40
35
  @inflector.classify(association_name.to_s)
41
36
  end
42
37
  end
38
+
39
+ private
40
+
41
+ def association?(node)
42
+ method_name = Node.method_name(node)
43
+ @associations.include?(method_name)
44
+ end
45
+
46
+ def custom_class_name(arguments)
47
+ association_options = arguments.detect { |n| Node.hash?(n) }
48
+ return unless association_options
49
+
50
+ Node.value_from_hash(association_options, :class_name)
51
+ end
52
+
53
+ def association_name(arguments)
54
+ return unless Node.symbol?(arguments[0])
55
+
56
+ Node.literal_value(arguments[0])
57
+ end
43
58
  end
44
59
  end
@@ -0,0 +1,20 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+ require "packwerk/reference_lister"
6
+
7
+ module Packwerk
8
+ module Checker
9
+ extend T::Sig
10
+ extend T::Helpers
11
+
12
+ interface!
13
+
14
+ sig { params(reference: Reference, reference_lister: ReferenceLister).returns(T::Boolean).abstract }
15
+ def invalid_reference?(reference, reference_lister); end
16
+
17
+ sig { params(reference: Reference).returns(String).abstract }
18
+ def message_for(reference); end
19
+ end
20
+ end
@@ -43,6 +43,8 @@ module Packwerk
43
43
  check(args)
44
44
  when "update"
45
45
  update(args)
46
+ when "update-deprecations"
47
+ update_deprecations(args)
46
48
  when "validate"
47
49
  validate(args)
48
50
  when nil, "help"
@@ -52,7 +54,8 @@ module Packwerk
52
54
  Subcommands:
53
55
  init - set up packwerk
54
56
  check - run all checks
55
- update - update deprecated references
57
+ update - update deprecated references (deprecated, use update-deprecations instead)
58
+ update-deprecations - update deprecated references
56
59
  validate - verify integrity of packwerk and package configuration
57
60
  help - display help information about packwerk
58
61
  USAGE
@@ -117,6 +120,11 @@ module Packwerk
117
120
  end
118
121
 
119
122
  def update(paths)
123
+ warn("`packwerk update` is deprecated in favor of `packwerk update-deprecations`.")
124
+ update_deprecations(paths)
125
+ end
126
+
127
+ def update_deprecations(paths)
120
128
  updating_deprecated_references = ::Packwerk::UpdatingDeprecatedReferences.new(@configuration.root_path)
121
129
  @run_context = Packwerk::RunContext.from_configuration(
122
130
  @configuration,
@@ -28,7 +28,7 @@ module Packwerk
28
28
 
29
29
  DEFAULT_CONFIG_PATH = "packwerk.yml"
30
30
  DEFAULT_INCLUDE_GLOBS = ["**/*.{rb,rake,erb}"]
31
- DEFAULT_EXCLUDE_GLOBS = ["{bin,node_modules,script,tmp}/**/*"]
31
+ DEFAULT_EXCLUDE_GLOBS = ["{bin,node_modules,script,tmp,vendor}/**/*"]
32
32
 
33
33
  attr_reader(
34
34
  :include, :exclude, :root_path, :package_paths, :custom_associations, :load_paths, :inflections_file,
@@ -58,15 +58,19 @@ module Packwerk
58
58
  (engine.config.autoload_paths + engine.config.eager_load_paths + engine.config.autoload_once_paths).uniq
59
59
  end
60
60
 
61
- all_paths = all_paths.map do |path_string|
62
- # ignore paths outside of the Rails root
61
+ bundle_path_match = Bundler.bundle_path.join("**").to_s
62
+
63
+ all_paths = all_paths.each_with_object([]) do |path_string, paths|
64
+ # ignore paths inside gems
63
65
  path = Pathname.new(path_string)
64
- if path.exist? && path.realpath.fnmatch(Rails.root.join("**").to_s)
65
- path.relative_path_from(Rails.root).to_s
66
- end
66
+
67
+ next unless path.exist?
68
+ next if path.realpath.fnmatch(bundle_path_match)
69
+
70
+ paths << path.relative_path_from(Rails.root).to_s
67
71
  end
68
72
 
69
- all_paths.compact.tap do |paths|
73
+ all_paths.tap do |paths|
70
74
  if paths.empty?
71
75
  raise <<~EOS
72
76
  No autoload paths have been set up in your Rails app. This is likely a bug, and
@@ -2,9 +2,12 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "packwerk/violation_type"
5
+ require "packwerk/checker"
5
6
 
6
7
  module Packwerk
7
8
  class DependencyChecker
9
+ include Checker
10
+
8
11
  def violation_type
9
12
  ViolationType::Dependency
10
13
  end
@@ -58,7 +58,7 @@ module Packwerk
58
58
  #
59
59
  # You can regenerate this file using the following command:
60
60
  #
61
- # bundle exec packwerk update #{@package.name}
61
+ # bundle exec packwerk update-deprecations #{@package.name}
62
62
  MESSAGE
63
63
  File.open(@filepath, "w") do |f|
64
64
  f.write(message)
@@ -35,7 +35,7 @@ module Packwerk
35
35
  return true
36
36
  end
37
37
 
38
- source_file_path = File.expand_path("../templates/packwerk", __FILE__)
38
+ source_file_path = File.expand_path("templates/packwerk", __dir__)
39
39
  FileUtils.cp(source_file_path, destination_file_path)
40
40
 
41
41
  @out.puts("✅ Packwerk application validation bin script generated in #{destination_file_path}")
@@ -51,7 +51,7 @@ module Packwerk
51
51
  return true
52
52
  end
53
53
 
54
- source_file_path = File.expand_path("../templates/packwerk_validator_test.rb", __FILE__)
54
+ source_file_path = File.expand_path("templates/packwerk_validator_test.rb", __dir__)
55
55
  FileUtils.cp(source_file_path, destination_file_path)
56
56
 
57
57
  @out.puts("✅ Packwerk application validation test generated in #{destination_file_path}")
@@ -11,6 +11,10 @@ enforce_dependencies: true
11
11
  # We recommend enabling this for any new packages you create to aid with encapsulation.
12
12
  enforce_privacy: false
13
13
 
14
+ # By default the public path will be app/public/, however this may not suit all applications' architecture so
15
+ # this allows you to modify what your package's public path is.
16
+ # public_path: app/public/
17
+
14
18
  # A list of this package's dependencies
15
19
  # Note that packages in this list require their own `package.yml` file
16
20
  # dependencies:
@@ -10,12 +10,12 @@ ENV["RAILS_ENV"] = "test"
10
10
  packwerk_argv = ARGV.dup
11
11
 
12
12
  begin
13
- load(File.expand_path("../spring", __FILE__))
13
+ load(File.expand_path("spring", __dir__))
14
14
  rescue LoadError => e
15
15
  raise unless e.message.include?("spring")
16
16
  end
17
17
 
18
- require File.expand_path("../../config/environment", __FILE__)
18
+ require File.expand_path("../config/environment", __dir__)
19
19
 
20
20
  require "packwerk"
21
21
 
@@ -7,7 +7,7 @@
7
7
 
8
8
  # List of patterns for folder paths to exclude
9
9
  # exclude:
10
- # - "{bin,node_modules,script,tmp}/**/*"
10
+ # - "{bin,node_modules,script,tmp,vendor}/**/*"
11
11
 
12
12
  # Patterns to find package configuration files
13
13
  # package_paths: "**/"
@@ -103,8 +103,24 @@ module Packwerk
103
103
  Location.new(location.line, location.column)
104
104
  end
105
105
 
106
+ def method_call?(node)
107
+ type(node) == METHOD_CALL
108
+ end
109
+
110
+ def hash?(node)
111
+ type(node) == HASH
112
+ end
113
+
114
+ def string?(node)
115
+ type(node) == STRING
116
+ end
117
+
118
+ def symbol?(node)
119
+ type(node) == SYMBOL
120
+ end
121
+
106
122
  def method_arguments(method_call_node)
107
- raise TypeError unless type(method_call_node) == METHOD_CALL
123
+ raise TypeError unless method_call?(method_call_node)
108
124
 
109
125
  # (send (lvar :foo) :bar (int 1))
110
126
  # "foo.bar(1)"
@@ -112,7 +128,7 @@ module Packwerk
112
128
  end
113
129
 
114
130
  def method_name(method_call_node)
115
- raise TypeError unless type(method_call_node) == METHOD_CALL
131
+ raise TypeError unless method_call?(method_call_node)
116
132
 
117
133
  # (send (lvar :foo) :bar (int 1))
118
134
  # "foo.bar(1)"
@@ -176,7 +192,7 @@ module Packwerk
176
192
  end
177
193
 
178
194
  def value_from_hash(hash_node, key)
179
- raise TypeError unless type(hash_node) == HASH
195
+ raise TypeError unless hash?(hash_node)
180
196
  pair = hash_pairs(hash_node).detect { |pair_node| literal_value(hash_pair_key(pair_node)) == key }
181
197
  hash_pair_value(pair) if pair
182
198
  end
@@ -204,7 +220,7 @@ module Packwerk
204
220
  end
205
221
 
206
222
  def hash_pairs(hash_node)
207
- raise TypeError unless type(hash_node) == HASH
223
+ raise TypeError unless hash?(hash_node)
208
224
 
209
225
  # (hash (pair (int 1) (int 2)) (pair (int 3) (int 4)))
210
226
  # "{1 => 2, 3 => 4}"
@@ -222,7 +238,7 @@ module Packwerk
222
238
  def module_creation?(node)
223
239
  # "Class.new"
224
240
  # "Module.new"
225
- type(node) == METHOD_CALL &&
241
+ method_call?(node) &&
226
242
  type(receiver(node)) == CONSTANT &&
227
243
  ["Class", "Module"].include?(constant_name(receiver(node))) &&
228
244
  method_name(node) == :new
@@ -3,9 +3,21 @@
3
3
 
4
4
  require "packwerk/node"
5
5
  require "packwerk/offense"
6
+ require "packwerk/checker"
7
+ require "packwerk/reference_lister"
6
8
 
7
9
  module Packwerk
8
10
  class NodeProcessor
11
+ extend T::Sig
12
+
13
+ sig do
14
+ params(
15
+ reference_extractor: ReferenceExtractor,
16
+ reference_lister: ReferenceLister,
17
+ filename: String,
18
+ checkers: T::Array[Checker]
19
+ ).void
20
+ end
9
21
  def initialize(reference_extractor:, reference_lister:, filename:, checkers:)
10
22
  @reference_extractor = reference_extractor
11
23
  @reference_lister = reference_lister
@@ -33,13 +33,20 @@ module Packwerk
33
33
  end
34
34
 
35
35
  def public_path
36
- @public_path ||= File.join(@name, "app/public/")
36
+ @public_path ||= File.join(@name, user_defined_public_path || "app/public/")
37
37
  end
38
38
 
39
39
  def public_path?(path)
40
40
  path.start_with?(public_path)
41
41
  end
42
42
 
43
+ def user_defined_public_path
44
+ return unless @config["public_path"]
45
+ return @config["public_path"] if @config["public_path"].end_with?("/")
46
+
47
+ @config["public_path"] + "/"
48
+ end
49
+
43
50
  def <=>(other)
44
51
  return nil unless other.is_a?(self.class)
45
52
  name <=> other.name
@@ -25,13 +25,15 @@ module Packwerk
25
25
  new(packages)
26
26
  end
27
27
 
28
- private
29
-
30
28
  def package_paths(root_path, package_pathspec)
29
+ bundle_path_match = Bundler.bundle_path.join("**").to_s
30
+
31
31
  Dir.glob(File.join(root_path, package_pathspec, PACKAGE_CONFIG_FILENAME))
32
- .map! { |path| Pathname.new(path) }
32
+ .map { |path| Pathname.new(path) }.reject { |path| path.realpath.fnmatch(bundle_path_match) }
33
33
  end
34
34
 
35
+ private
36
+
35
37
  def create_root_package_if_none_in(packages)
36
38
  return if packages.any?(&:root?)
37
39
  packages << Package.new(name: Package::ROOT_PACKAGE_NAME, config: nil)
@@ -2,9 +2,12 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "packwerk/violation_type"
5
+ require "packwerk/checker"
5
6
 
6
7
  module Packwerk
7
8
  class PrivacyChecker
9
+ include Checker
10
+
8
11
  def violation_type
9
12
  ViolationType::Privacy
10
13
  end
@@ -39,6 +39,7 @@ module Packwerk
39
39
  new(
40
40
  root_path: configuration.root_path,
41
41
  load_paths: configuration.load_paths,
42
+ package_paths: configuration.package_paths,
42
43
  inflector: ActiveSupport::Inflector,
43
44
  custom_associations: configuration.custom_associations,
44
45
  reference_lister: default_reference_lister,
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Packwerk
5
- VERSION = "1.0.0"
5
+ VERSION = "1.0.1"
6
6
  end
@@ -33,7 +33,7 @@ Gem::Specification.new do |spec|
33
33
  spec.bindir = "exe"
34
34
  spec.executables << "packwerk"
35
35
 
36
- spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
36
+ spec.files = Dir.chdir(__dir__) do
37
37
  %x(git ls-files -z).split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
38
38
  end
39
39
  spec.require_paths = %w(lib)
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: 1.0.0
4
+ version: 1.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: 2020-09-23 00:00:00.000000000 Z
11
+ date: 2020-10-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -185,6 +185,7 @@ files:
185
185
  - lib/packwerk.rb
186
186
  - lib/packwerk/application_validator.rb
187
187
  - lib/packwerk/association_inspector.rb
188
+ - lib/packwerk/checker.rb
188
189
  - lib/packwerk/checking_deprecated_references.rb
189
190
  - lib/packwerk/cli.rb
190
191
  - lib/packwerk/configuration.rb