packwerk 1.3.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1 -0
- data/Gemfile.lock +11 -8
- data/README.md +2 -3
- data/TROUBLESHOOT.md +3 -3
- data/UPGRADING.md +54 -0
- data/USAGE.md +27 -53
- data/exe/packwerk +7 -1
- data/lib/packwerk/application_load_paths.rb +1 -0
- data/lib/packwerk/application_validator.rb +3 -54
- data/lib/packwerk/association_inspector.rb +1 -1
- data/lib/packwerk/cli.rb +37 -20
- data/lib/packwerk/configuration.rb +34 -4
- data/lib/packwerk/const_node_inspector.rb +3 -2
- data/lib/packwerk/constant_discovery.rb +1 -1
- data/lib/packwerk/constant_name_inspector.rb +1 -1
- data/lib/packwerk/deprecated_references.rb +19 -7
- data/lib/packwerk/file_processor.rb +39 -14
- data/lib/packwerk/files_for_processing.rb +15 -4
- data/lib/packwerk/formatters/offenses_formatter.rb +1 -1
- data/lib/packwerk/formatters/progress_formatter.rb +1 -1
- data/lib/packwerk/generators/configuration_file.rb +4 -19
- data/lib/packwerk/generators/templates/package.yml +1 -1
- data/lib/packwerk/generators/templates/packwerk.yml.erb +0 -6
- data/lib/packwerk/graph.rb +2 -0
- data/lib/packwerk/node.rb +1 -0
- data/lib/packwerk/node_processor.rb +10 -22
- data/lib/packwerk/node_processor_factory.rb +0 -2
- data/lib/packwerk/node_visitor.rb +4 -2
- data/lib/packwerk/package.rb +25 -4
- data/lib/packwerk/package_set.rb +43 -8
- data/lib/packwerk/parsed_constant_definitions.rb +1 -0
- data/lib/packwerk/reference.rb +2 -1
- data/lib/packwerk/reference_checking/checkers/checker.rb +21 -0
- data/lib/packwerk/reference_checking/checkers/dependency_checker.rb +31 -0
- data/lib/packwerk/reference_checking/checkers/privacy_checker.rb +58 -0
- data/lib/packwerk/reference_checking/reference_checker.rb +33 -0
- data/lib/packwerk/reference_extractor.rb +2 -2
- data/lib/packwerk/reference_offense.rb +1 -0
- data/lib/packwerk/run_context.rb +10 -7
- data/lib/packwerk/sanity_checker.rb +1 -1
- data/lib/packwerk/spring_command.rb +28 -0
- data/lib/packwerk/version.rb +1 -1
- data/lib/packwerk/violation_type.rb +1 -1
- data/lib/packwerk.rb +17 -12
- data/packwerk.gemspec +3 -1
- data/service.yml +0 -2
- data/sorbet/rbi/gems/psych@3.3.2.rbi +24 -0
- metadata +25 -11
- data/lib/packwerk/checker.rb +0 -17
- data/lib/packwerk/dependency_checker.rb +0 -26
- data/lib/packwerk/generators/inflections_file.rb +0 -43
- data/lib/packwerk/generators/templates/inflections.yml +0 -6
- data/lib/packwerk/inflections/custom.rb +0 -33
- data/lib/packwerk/inflections/default.rb +0 -73
- data/lib/packwerk/inflector.rb +0 -48
- data/lib/packwerk/privacy_checker.rb +0 -53
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a473db2c54adea132ca7e61a51072b570d7e37b7d63c021259eef3cc7625177b
|
4
|
+
data.tar.gz: 1b8486e61969621fac562d2fb6ebe47dcf6f71fcd13f6d18524337a3ed831ac2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8c05f0ce6e8b398a87e98453c721d00707628918ce8455600c1cb00fb2cb9c68efc6bea373323e889d36fc3658ff45db3508b0e6386b876da58ca50cdb53ab9f
|
7
|
+
data.tar.gz: 51586b68f489ff1f32df06338d05a64cab753da56c11575b3c5c8fa55019e9a8527e0a20c54c8695e1432307227d26c10f01b0d6c610e41c55d84296be000bd8
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
See https://github.com/Shopify/packwerk/releases.
|
data/Gemfile.lock
CHANGED
@@ -87,10 +87,11 @@ GIT
|
|
87
87
|
PATH
|
88
88
|
remote: .
|
89
89
|
specs:
|
90
|
-
packwerk (
|
90
|
+
packwerk (2.0.0)
|
91
91
|
activesupport (>= 5.2)
|
92
92
|
ast
|
93
93
|
better_html
|
94
|
+
bundler
|
94
95
|
constant_resolver
|
95
96
|
parallel
|
96
97
|
parser
|
@@ -135,16 +136,16 @@ GEM
|
|
135
136
|
marcel (1.0.0)
|
136
137
|
method_source (1.0.0)
|
137
138
|
mini_mime (1.0.3)
|
138
|
-
mini_portile2 (2.
|
139
|
+
mini_portile2 (2.6.1)
|
139
140
|
minitest (5.14.4)
|
140
141
|
minitest-focus (1.2.1)
|
141
142
|
minitest (>= 4, < 6)
|
142
143
|
mocha (1.12.0)
|
143
144
|
nio4r (2.5.7)
|
144
|
-
nokogiri (1.
|
145
|
-
mini_portile2 (~> 2.
|
145
|
+
nokogiri (1.12.5)
|
146
|
+
mini_portile2 (~> 2.6.1)
|
146
147
|
racc (~> 1.4)
|
147
|
-
nokogiri (1.
|
148
|
+
nokogiri (1.12.5-x86_64-darwin)
|
148
149
|
racc (~> 1.4)
|
149
150
|
parallel (1.20.1)
|
150
151
|
parlour (6.0.0)
|
@@ -157,6 +158,7 @@ GEM
|
|
157
158
|
pry (0.14.0)
|
158
159
|
coderay (~> 1.1)
|
159
160
|
method_source (~> 1.0)
|
161
|
+
psych (3.3.2)
|
160
162
|
racc (1.5.2)
|
161
163
|
rack (2.2.3)
|
162
164
|
rack-test (1.1.0)
|
@@ -189,7 +191,7 @@ GEM
|
|
189
191
|
rubocop-sorbet (0.6.1)
|
190
192
|
rubocop
|
191
193
|
ruby-progressbar (1.11.0)
|
192
|
-
smart_properties (1.
|
194
|
+
smart_properties (1.16.3)
|
193
195
|
sorbet (0.5.6360)
|
194
196
|
sorbet-static (= 0.5.6360)
|
195
197
|
sorbet-runtime (0.5.6360)
|
@@ -233,16 +235,17 @@ GEM
|
|
233
235
|
|
234
236
|
PLATFORMS
|
235
237
|
ruby
|
238
|
+
x86_64-darwin
|
236
239
|
x86_64-darwin-20
|
237
240
|
|
238
241
|
DEPENDENCIES
|
239
|
-
bundler
|
240
242
|
byebug
|
241
243
|
constant_resolver
|
242
244
|
m
|
243
245
|
minitest-focus
|
244
246
|
mocha
|
245
247
|
packwerk!
|
248
|
+
psych (~> 3)
|
246
249
|
rails!
|
247
250
|
rake
|
248
251
|
rubocop-performance
|
@@ -254,4 +257,4 @@ DEPENDENCIES
|
|
254
257
|
tapioca
|
255
258
|
|
256
259
|
BUNDLED WITH
|
257
|
-
2.2.
|
260
|
+
2.2.22
|
data/README.md
CHANGED
@@ -35,8 +35,6 @@ Watch a [1-minute video demo](https://www.youtube.com/watch?v=NwqlyBAxVpQ&featur
|
|
35
35
|
gem 'packwerk'
|
36
36
|
```
|
37
37
|
|
38
|
-
_Note: Packwerk has to be grouped in production environment within the Gemfile if your Rails app has custom inflections._
|
39
|
-
|
40
38
|
2. Install the gem
|
41
39
|
|
42
40
|
Execute:
|
@@ -47,7 +45,8 @@ Or install it yourself as:
|
|
47
45
|
|
48
46
|
$ gem install packwerk
|
49
47
|
|
50
|
-
|
48
|
+
2. Run `bundle binstub packwerk` to generate the binstub
|
49
|
+
3. Run `bin/packwerk init` to generate the configuration files
|
51
50
|
|
52
51
|
## Usage
|
53
52
|
|
data/TROUBLESHOOT.md
CHANGED
@@ -14,11 +14,11 @@ Packwerk can give feedback via continuous integration (CI) if you have it set up
|
|
14
14
|
|
15
15
|
You can specify folders or packages in Packwerk commands for a shorter run time:
|
16
16
|
|
17
|
-
packwerk check components/your_package
|
17
|
+
bin/packwerk check components/your_package
|
18
18
|
|
19
|
-
packwerk update-deprecations components/your_package
|
19
|
+
bin/packwerk update-deprecations components/your_package
|
20
20
|
|
21
|
-
_Note: You cannot specify folders or packages for `packwerk validate` because the command runs for the entire application._
|
21
|
+
_Note: You cannot specify folders or packages for `bin/packwerk validate` because the command runs for the entire application._
|
22
22
|
|
23
23
|
![](static/packwerk_check_violation.gif)
|
24
24
|
|
data/UPGRADING.md
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
# Upgrading from 1.x to 2.0
|
2
|
+
|
3
|
+
With Packwerk 2.0, we made a few changes to simplify the setup. Updating will require removing some previously necessary files and configuration.
|
4
|
+
|
5
|
+
## Gem group
|
6
|
+
|
7
|
+
Because packwerk is no longer involved in specifying the application's inflections, it doesn't have to live in the `production` group in your `Gemfile` anymore. We recommend moving it to the `development` group.
|
8
|
+
|
9
|
+
## Removing application config caches
|
10
|
+
|
11
|
+
### Load paths
|
12
|
+
We no longer require the `load_paths` key in `packwerk.yml`. You can simply delete the load_paths key as it will not be read anymore. Instead, Packwerk will ask Rails for load paths. If you're using spring, make sure to properly set up spring (see [USAGE.md](USAGE.md#setting-up-spring)) to keep packwerk fast.
|
13
|
+
|
14
|
+
### Inflections
|
15
|
+
We no longer require a custom `inflections.yml` file. Instead, you'll want to revert BACK to using the `inflections.rb` initializer as you would have done prior to adopting packwerk. To do this, you'll want to convert back to using the plain [ActiveSupport Inflections API](https://api.rubyonrails.org/classes/ActiveSupport/Inflector/Inflections.html).
|
16
|
+
|
17
|
+
|
18
|
+
Given the following example `inflections.yml`, here is an example `inflections.rb` that would follow. Tip: if you're using git, you can run `git log config/inflections.yml`, find the first commit that introduced `inflections.yml`, find the COMMIT_SHA, and then run `git show COMMIT_SHA` to see what your inflections file looked like before (note that you may have changed `inflections.yml` since then, though).
|
19
|
+
|
20
|
+
`config/inflections.yml`
|
21
|
+
```yml
|
22
|
+
# List your inflections in this file instead of `inflections.rb`
|
23
|
+
# See steps to set up custom inflections:
|
24
|
+
# https://github.com/Shopify/packwerk/blob/main/USAGE.md#Inflections
|
25
|
+
|
26
|
+
acronym:
|
27
|
+
- 'HTML'
|
28
|
+
- 'API'
|
29
|
+
|
30
|
+
singular:
|
31
|
+
- ['oxen', 'oxen']
|
32
|
+
|
33
|
+
irregular:
|
34
|
+
- ['person', 'people']
|
35
|
+
|
36
|
+
uncountable:
|
37
|
+
- 'fish'
|
38
|
+
- 'sheep'
|
39
|
+
```
|
40
|
+
|
41
|
+
`config/initializers/inflections.rb`
|
42
|
+
```ruby
|
43
|
+
ActiveSupport::Inflector.inflections(:en) do |inflect|
|
44
|
+
inflect.acronym('HTML')
|
45
|
+
inflect.acronym('API')
|
46
|
+
|
47
|
+
inflect.singular('oxen', 'oxen')
|
48
|
+
|
49
|
+
inflect.irregular('person', 'people')
|
50
|
+
|
51
|
+
inflect.uncountable('fish')
|
52
|
+
inflect.uncountable('sheep')
|
53
|
+
end
|
54
|
+
```
|
data/USAGE.md
CHANGED
@@ -6,8 +6,9 @@
|
|
6
6
|
* [What is a package?](#what-is-a-package)
|
7
7
|
* [Package principles](#package-principles)
|
8
8
|
* [Getting started](#getting-started)
|
9
|
-
* [Setting up
|
10
|
-
|
9
|
+
* [Setting up Spring](#setting-up-spring)
|
10
|
+
* [Configuring Packwerk](#configuring-packwerk)
|
11
|
+
* [Using a custom ERB parser](#using-a-custom-erb-parser)
|
11
12
|
* [Validating the package system](#validating-the-package-system)
|
12
13
|
* [Defining packages](#defining-packages)
|
13
14
|
* [Package metadata](#package-metadata)
|
@@ -42,9 +43,12 @@ The [package principles](https://en.wikipedia.org/wiki/Package_principles) page
|
|
42
43
|
|
43
44
|
## Getting started
|
44
45
|
|
45
|
-
After including Packwerk in the Gemfile, you
|
46
|
+
After including Packwerk in the Gemfile, you will first want to generate a binstub:
|
47
|
+
You can do this by running `bundle binstub packwerk`, which will generate a [binstub](https://bundler.io/man/bundle-binstubs.1.html#DESCRIPTION) at `bin/packwerk`.
|
46
48
|
|
47
|
-
|
49
|
+
Then, you can generate the necessary files to get Packwerk running by executing:
|
50
|
+
|
51
|
+
bin/packwerk init
|
48
52
|
|
49
53
|
Here is a list of files generated:
|
50
54
|
|
@@ -52,11 +56,17 @@ Here is a list of files generated:
|
|
52
56
|
|-----------------------------|--------------|------------|
|
53
57
|
| Packwerk configuration | packwerk.yml | See [Setting up the configuration file](#Setting-up-the-configuration-file) |
|
54
58
|
| Root package | package.yml | A package for the root folder |
|
55
|
-
| Custom inflections | config/inflections.yml | A custom inflections file is only required if you have custom inflections in `inflections.rb`, see [Inflections](#Inflections) |
|
56
59
|
|
57
60
|
After that, you may begin creating packages for your application. See [Defining packages](#Defining-packages)
|
58
61
|
|
59
|
-
|
62
|
+
### Setting up Spring
|
63
|
+
|
64
|
+
[Spring](https://github.com/rails/spring) is a preloader for Rails. Because `packwerk` loads `Rails`, it can be sped up dramatically by enabling spring. Packwerk supports the usage of Spring.
|
65
|
+
Firstly, spring needs to know about the packwerk spring command when spring is loading. To do that, add `require 'packwerk/spring_command'` to `config/spring.rb` in your application.
|
66
|
+
Secondly, to enable Spring, first run `bin/spring binstub packwerk` which will "springify" the generated binstub.
|
67
|
+
|
68
|
+
|
69
|
+
## Configuring Packwerk
|
60
70
|
|
61
71
|
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.
|
62
72
|
|
@@ -65,7 +75,6 @@ Packwerk reads from the `packwerk.yml` configuration file in the root directory.
|
|
65
75
|
| include | **/*.{rb,rake,erb} | list of patterns for folder paths to include |
|
66
76
|
| exclude | {bin,node_modules,script,tmp,vendor}/**/* | list of patterns for folder paths to exclude |
|
67
77
|
| package_paths | **/ | a single pattern or a list of patterns to find package configuration files, see: [Defining packages](#Defining-packages) |
|
68
|
-
| load_paths | All application autoload paths | list of load paths |
|
69
78
|
| custom_associations | N/A | list of custom associations, if any |
|
70
79
|
| parallel | true | when true, fork code parsing out to subprocesses |
|
71
80
|
|
@@ -91,50 +100,11 @@ end
|
|
91
100
|
Packwerk::Parsers::Factory.instance.erb_parser_class = CustomParser
|
92
101
|
```
|
93
102
|
|
94
|
-
### Inflections
|
95
|
-
|
96
|
-
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 a reference to the `Bird` constant.
|
97
|
-
|
98
|
-
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.
|
99
|
-
|
100
|
-
In `inflections.rb`, add:
|
101
|
-
|
102
|
-
```rb
|
103
|
-
require "packwerk/inflections/custom"
|
104
|
-
|
105
|
-
ActiveSupport::Inflector.inflections do |inflect|
|
106
|
-
# please add all custom inflections in the file below.
|
107
|
-
Packwerk::Inflections::Custom.new(
|
108
|
-
Rails.root.join("config", "inflections.yml")
|
109
|
-
).apply_to(inflect)
|
110
|
-
end
|
111
|
-
```
|
112
|
-
|
113
|
-
_Note: Packwerk has to be grouped in production environment within the Gemfile if you have custom inflections._
|
114
|
-
|
115
|
-
Next, move your existing custom inflections into `config/inflections.yml`:
|
116
|
-
|
117
|
-
```yaml
|
118
|
-
acronym:
|
119
|
-
- 'GraphQL'
|
120
|
-
- 'MRuby'
|
121
|
-
- 'TOS'
|
122
|
-
irregular:
|
123
|
-
- ['analysis', 'analyses']
|
124
|
-
- ['reserve', 'reserves']
|
125
|
-
uncountable:
|
126
|
-
- 'payment_details'
|
127
|
-
singular:
|
128
|
-
- [!ruby/regexp /status$/, 'status']
|
129
|
-
```
|
130
|
-
|
131
|
-
Any new inflectors should be added to `config/inflections.yml`.
|
132
|
-
|
133
103
|
## Validating the package system
|
134
104
|
|
135
105
|
There are some criteria that an application must meet in order to have a valid package system. These criteria include having a valid autoload path cache, package definition files, and application folder structure. The dependency graph within the package system also has to be acyclic.
|
136
106
|
|
137
|
-
We recommend setting up the package system validation for your Rails application in a CI step (or through a test suite for Ruby projects) separate from `packwerk check`.
|
107
|
+
We recommend setting up the package system validation for your Rails application in a CI step (or through a test suite for Ruby projects) separate from `bin/packwerk check`.
|
138
108
|
|
139
109
|
Use the following command to validate the application:
|
140
110
|
|
@@ -231,13 +201,17 @@ After enforcing the boundary checks for a package, you may execute:
|
|
231
201
|
|
232
202
|
Packwerk will check the entire codebase for any new or stale violations.
|
233
203
|
|
234
|
-
You can also specify folders
|
204
|
+
You can also specify folders for a shorter run time. When checking against folders all subfolders will be analyzed, irrespective of nested package boundaries.
|
235
205
|
|
236
206
|
packwerk check components/your_package
|
237
207
|
|
208
|
+
You can also specify packages for a shorter run time. When checking against packages any packages nested underneath the specified packages will not be checked. This can be helpful to test packages like the root package, which can have many nested packages.
|
209
|
+
|
210
|
+
packwerk check --packages=components/your_package,components/your_other_package
|
211
|
+
|
238
212
|
![](static/packwerk_check.gif)
|
239
213
|
|
240
|
-
In order to keep the package system valid at each version of the application, we recommend running `packwerk check` in your CI pipeline.
|
214
|
+
In order to keep the package system valid at each version of the application, we recommend running `bin/packwerk check` in your CI pipeline.
|
241
215
|
|
242
216
|
See: [TROUBLESHOOT.md - Sample violations](TROUBLESHOOT.md#Sample-violations)
|
243
217
|
|
@@ -247,17 +221,17 @@ For existing codebases, packages are likely to have existing boundary violations
|
|
247
221
|
|
248
222
|
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:
|
249
223
|
|
250
|
-
packwerk update-deprecations
|
224
|
+
bin/packwerk update-deprecations
|
251
225
|
|
252
|
-
Similar to `packwerk check`, you may also run `packwerk update-deprecations` on folders or packages:
|
226
|
+
Similar to `bin/packwerk check`, you may also run `bin/packwerk update-deprecations` on folders or packages:
|
253
227
|
|
254
|
-
packwerk update-deprecations components/your_package
|
228
|
+
bin/packwerk update-deprecations components/your_package
|
255
229
|
|
256
230
|
![](static/packwerk_update.gif)
|
257
231
|
|
258
232
|
_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._
|
259
233
|
|
260
|
-
`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.
|
234
|
+
`bin/packwerk update-deprecations` should only be run to record existing violations and to remove deprecated references that have been worked off. Running `bin/packwerk update-deprecations` to resolve a violation should be the very last resort.
|
261
235
|
|
262
236
|
See: [TROUBLESHOOT.md - Troubleshooting violations](TROUBLESHOOT.md#Troubleshooting_violations)
|
263
237
|
|
data/exe/packwerk
CHANGED
@@ -3,4 +3,10 @@
|
|
3
3
|
|
4
4
|
require "packwerk"
|
5
5
|
|
6
|
-
|
6
|
+
# Needs to be run in test environment in order to have test helper paths available in the autoload paths
|
7
|
+
ENV["RAILS_ENV"] = "test"
|
8
|
+
|
9
|
+
# Command line arguments needs to be duplicated because spring modifies it
|
10
|
+
packwerk_argv = ARGV.dup
|
11
|
+
cli = Packwerk::Cli.new(style: Packwerk::OutputStyles::Coloured.new)
|
12
|
+
cli.run(packwerk_argv)
|
@@ -1,30 +1,27 @@
|
|
1
1
|
# typed: true
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require "active_support/inflector/inflections"
|
5
4
|
require "constant_resolver"
|
6
5
|
require "pathname"
|
7
6
|
require "yaml"
|
8
7
|
|
9
8
|
module Packwerk
|
9
|
+
# Checks the structure of the application and its packwerk configuration to make sure we can run a check and deliver
|
10
|
+
# correct results.
|
10
11
|
class ApplicationValidator
|
11
12
|
def initialize(config_file_path:, configuration:, environment:)
|
12
13
|
@config_file_path = config_file_path
|
13
14
|
@configuration = configuration
|
14
15
|
@environment = environment
|
15
|
-
|
16
|
-
@application_load_paths = ApplicationLoadPaths.extract_relevant_paths(configuration.root_path, environment)
|
17
16
|
end
|
18
17
|
|
19
18
|
Result = Struct.new(:ok?, :error_value)
|
20
19
|
|
21
20
|
def check_all
|
22
21
|
results = [
|
23
|
-
check_autoload_path_cache,
|
24
22
|
check_package_manifests_for_privacy,
|
25
23
|
check_package_manifest_syntax,
|
26
24
|
check_application_structure,
|
27
|
-
check_inflection_file,
|
28
25
|
check_acyclic_graph,
|
29
26
|
check_package_manifest_paths,
|
30
27
|
check_valid_package_dependencies,
|
@@ -34,21 +31,6 @@ module Packwerk
|
|
34
31
|
merge_results(results)
|
35
32
|
end
|
36
33
|
|
37
|
-
def check_autoload_path_cache
|
38
|
-
expected = @application_load_paths
|
39
|
-
actual = @configuration.load_paths
|
40
|
-
if expected.sort == actual.sort
|
41
|
-
Result.new(true)
|
42
|
-
else
|
43
|
-
Result.new(
|
44
|
-
false,
|
45
|
-
"Load path cache in #{@config_file_path} incorrect!\n"\
|
46
|
-
"Paths missing from file:\n#{format_yaml_strings(expected - actual)}\n"\
|
47
|
-
"Extraneous load paths in file:\n#{format_yaml_strings(actual - expected)}"
|
48
|
-
)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
34
|
def check_package_manifests_for_privacy
|
53
35
|
privacy_settings = package_manifests_settings_for("enforce_privacy")
|
54
36
|
|
@@ -140,39 +122,6 @@ module Packwerk
|
|
140
122
|
end
|
141
123
|
end
|
142
124
|
|
143
|
-
def check_inflection_file
|
144
|
-
inflections_file = @configuration.inflections_file
|
145
|
-
|
146
|
-
application_inflections = ActiveSupport::Inflector.inflections
|
147
|
-
packwerk_inflections = Packwerk::Inflector.from_file(inflections_file).inflections
|
148
|
-
|
149
|
-
results = %i(plurals singulars uncountables humans acronyms).map do |type|
|
150
|
-
expected = application_inflections.public_send(type).to_set
|
151
|
-
actual = packwerk_inflections.public_send(type).to_set
|
152
|
-
|
153
|
-
if expected == actual
|
154
|
-
Result.new(true)
|
155
|
-
else
|
156
|
-
missing_msg = unless (expected - actual).empty?
|
157
|
-
"Expected #{type} to be specified in file: #{expected - actual}"
|
158
|
-
end
|
159
|
-
extraneous_msg = unless (actual - expected).empty?
|
160
|
-
"Extraneous #{type} was specified in file: #{actual - expected}"
|
161
|
-
end
|
162
|
-
Result.new(
|
163
|
-
false,
|
164
|
-
[missing_msg, extraneous_msg].join("\n")
|
165
|
-
)
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
merge_results(
|
170
|
-
results,
|
171
|
-
separator: "\n",
|
172
|
-
errors_headline: "Inflections specified in #{inflections_file} don't line up with application!\n"
|
173
|
-
)
|
174
|
-
end
|
175
|
-
|
176
125
|
def check_acyclic_graph
|
177
126
|
edges = package_set.flat_map do |package|
|
178
127
|
package.dependencies.map { |dependency| [package, package_set.fetch(dependency)] }
|
@@ -296,7 +245,7 @@ module Packwerk
|
|
296
245
|
end
|
297
246
|
|
298
247
|
def package_manifests(glob_pattern = package_glob)
|
299
|
-
PackageSet.package_paths(@configuration.root_path, glob_pattern)
|
248
|
+
PackageSet.package_paths(@configuration.root_path, glob_pattern, @configuration.exclude)
|
300
249
|
.map { |f| File.realpath(f) }
|
301
250
|
end
|
302
251
|
|
@@ -19,7 +19,7 @@ module Packwerk
|
|
19
19
|
CustomAssociations
|
20
20
|
)
|
21
21
|
|
22
|
-
sig { params(inflector: Inflector, custom_associations: CustomAssociations).void }
|
22
|
+
sig { params(inflector: T.class_of(ActiveSupport::Inflector), custom_associations: CustomAssociations).void }
|
23
23
|
def initialize(inflector:, custom_associations: Set.new)
|
24
24
|
@inflector = inflector
|
25
25
|
@associations = T.let(RAILS_ASSOCIATIONS + custom_associations, CustomAssociations)
|
data/lib/packwerk/cli.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
# typed: true
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require "optparse"
|
5
|
+
|
4
6
|
module Packwerk
|
7
|
+
# A command-line interface to Packwerk.
|
5
8
|
class Cli
|
6
9
|
extend T::Sig
|
7
10
|
|
@@ -50,8 +53,6 @@ module Packwerk
|
|
50
53
|
output_result(parse_run(args).check)
|
51
54
|
when "detect-stale-violations"
|
52
55
|
output_result(parse_run(args).detect_stale_violations)
|
53
|
-
when "update"
|
54
|
-
update(args)
|
55
56
|
when "update-deprecations"
|
56
57
|
output_result(parse_run(args).update_deprecations)
|
57
58
|
when "validate"
|
@@ -85,19 +86,18 @@ module Packwerk
|
|
85
86
|
|
86
87
|
def generate_configs
|
87
88
|
configuration_file = Packwerk::Generators::ConfigurationFile.generate(
|
88
|
-
load_paths: Packwerk::ApplicationLoadPaths.extract_relevant_paths(@configuration.root_path, @environment),
|
89
89
|
root: @configuration.root_path,
|
90
90
|
out: @out
|
91
91
|
)
|
92
|
-
|
92
|
+
|
93
93
|
root_package = Packwerk::Generators::RootPackage.generate(root: @configuration.root_path, out: @out)
|
94
94
|
|
95
|
-
success = configuration_file &&
|
95
|
+
success = configuration_file && root_package
|
96
96
|
|
97
97
|
result = if success
|
98
98
|
<<~EOS
|
99
99
|
|
100
|
-
🎉 Packwerk is ready to be used. You can start defining packages and run `packwerk check`.
|
100
|
+
🎉 Packwerk is ready to be used. You can start defining packages and run `bin/packwerk check`.
|
101
101
|
For more information on how to use Packwerk, see: https://github.com/Shopify/packwerk/blob/main/USAGE.md
|
102
102
|
EOS
|
103
103
|
else
|
@@ -112,19 +112,18 @@ module Packwerk
|
|
112
112
|
success
|
113
113
|
end
|
114
114
|
|
115
|
-
def update(paths)
|
116
|
-
warn("`packwerk update` is deprecated in favor of `packwerk update-deprecations`.")
|
117
|
-
output_result(parse_run(paths).update_deprecations)
|
118
|
-
end
|
119
|
-
|
120
115
|
def output_result(result)
|
121
116
|
@out.puts
|
122
117
|
@out.puts(result.message)
|
123
118
|
result.status
|
124
119
|
end
|
125
120
|
|
126
|
-
def fetch_files_to_process(paths)
|
127
|
-
files = FilesForProcessing.fetch(
|
121
|
+
def fetch_files_to_process(paths, ignore_nested_packages)
|
122
|
+
files = FilesForProcessing.fetch(
|
123
|
+
paths: paths,
|
124
|
+
ignore_nested_packages: ignore_nested_packages,
|
125
|
+
configuration: @configuration
|
126
|
+
)
|
128
127
|
abort("No files found or given. "\
|
129
128
|
"Specify files or check the include and exclude glob in the config file.") if files.empty?
|
130
129
|
files
|
@@ -132,11 +131,6 @@ module Packwerk
|
|
132
131
|
|
133
132
|
def validate(_paths)
|
134
133
|
@progress_formatter.started_validation do
|
135
|
-
checker = Packwerk::ApplicationValidator.new(
|
136
|
-
config_file_path: @configuration.config_path,
|
137
|
-
configuration: @configuration,
|
138
|
-
environment: @environment,
|
139
|
-
)
|
140
134
|
result = checker.check_all
|
141
135
|
|
142
136
|
list_validation_errors(result)
|
@@ -145,6 +139,14 @@ module Packwerk
|
|
145
139
|
end
|
146
140
|
end
|
147
141
|
|
142
|
+
def checker
|
143
|
+
Packwerk::ApplicationValidator.new(
|
144
|
+
config_file_path: @configuration.config_path,
|
145
|
+
configuration: @configuration,
|
146
|
+
environment: @environment,
|
147
|
+
)
|
148
|
+
end
|
149
|
+
|
148
150
|
def list_validation_errors(result)
|
149
151
|
@out.puts
|
150
152
|
if result.ok?
|
@@ -155,9 +157,24 @@ module Packwerk
|
|
155
157
|
end
|
156
158
|
end
|
157
159
|
|
158
|
-
def parse_run(
|
160
|
+
def parse_run(params)
|
161
|
+
paths = T.let([], T::Array[String])
|
162
|
+
ignore_nested_packages = nil
|
163
|
+
|
164
|
+
if params.any? { |p| p.include?("--packages") }
|
165
|
+
OptionParser.new do |parser|
|
166
|
+
parser.on("--packages=PACKAGESLIST", Array, "package names, comma separated") do |p|
|
167
|
+
paths = p
|
168
|
+
end
|
169
|
+
end.parse!(params)
|
170
|
+
ignore_nested_packages = true
|
171
|
+
else
|
172
|
+
paths = params
|
173
|
+
ignore_nested_packages = false
|
174
|
+
end
|
175
|
+
|
159
176
|
ParseRun.new(
|
160
|
-
files: fetch_files_to_process(paths),
|
177
|
+
files: fetch_files_to_process(paths, ignore_nested_packages),
|
161
178
|
configuration: @configuration,
|
162
179
|
progress_formatter: @progress_formatter,
|
163
180
|
offenses_formatter: @offenses_formatter
|
@@ -34,24 +34,54 @@ module Packwerk
|
|
34
34
|
DEFAULT_EXCLUDE_GLOBS = ["{bin,node_modules,script,tmp,vendor}/**/*"]
|
35
35
|
|
36
36
|
attr_reader(
|
37
|
-
:include, :exclude, :root_path, :package_paths, :custom_associations, :
|
38
|
-
:config_path,
|
37
|
+
:include, :exclude, :root_path, :package_paths, :custom_associations, :config_path
|
39
38
|
)
|
40
39
|
|
41
40
|
def initialize(configs = {}, config_path: nil)
|
41
|
+
if configs["load_paths"]
|
42
|
+
warning = <<~WARNING
|
43
|
+
DEPRECATION WARNING: The 'load_paths' key in `packwerk.yml` is deprecated.
|
44
|
+
This value is no longer cached, and you can remove the key from `packwerk.yml`.
|
45
|
+
WARNING
|
46
|
+
|
47
|
+
warn(warning)
|
48
|
+
end
|
49
|
+
|
50
|
+
inflection_file = File.expand_path(configs["inflections_file"] || "config/inflections.yml", @root_path)
|
51
|
+
if configs["inflections_file"]
|
52
|
+
warning = <<~WARNING
|
53
|
+
DEPRECATION WARNING: The 'inflections_file' key in `packwerk.yml` is deprecated.
|
54
|
+
This value is no longer cached, and you can remove the key from `packwerk.yml`.
|
55
|
+
You can also delete #{configs["inflections_file"]}.
|
56
|
+
WARNING
|
57
|
+
|
58
|
+
warn(warning)
|
59
|
+
end
|
60
|
+
|
61
|
+
if Pathname.new(inflection_file).exist?
|
62
|
+
warning = <<~WARNING
|
63
|
+
DEPRECATION WARNING: Inflections YMLs in packwerk are now deprecated.
|
64
|
+
This value is no longer cached, and you can now delete #{inflection_file}
|
65
|
+
WARNING
|
66
|
+
|
67
|
+
warn(warning)
|
68
|
+
end
|
69
|
+
|
42
70
|
@include = configs["include"] || DEFAULT_INCLUDE_GLOBS
|
43
71
|
@exclude = configs["exclude"] || DEFAULT_EXCLUDE_GLOBS
|
44
72
|
root = config_path ? File.dirname(config_path) : "."
|
45
73
|
@root_path = File.expand_path(root)
|
46
74
|
@package_paths = configs["package_paths"] || "**/"
|
47
75
|
@custom_associations = configs["custom_associations"] || []
|
48
|
-
@load_paths = configs["load_paths"] || []
|
49
|
-
@inflections_file = File.expand_path(configs["inflections_file"] || "config/inflections.yml", @root_path)
|
50
76
|
@parallel = configs.key?("parallel") ? configs["parallel"] : true
|
51
77
|
|
52
78
|
@config_path = config_path
|
53
79
|
end
|
54
80
|
|
81
|
+
def load_paths
|
82
|
+
@load_paths ||= ApplicationLoadPaths.extract_relevant_paths(@root_path, "test")
|
83
|
+
end
|
84
|
+
|
55
85
|
def parallel?
|
56
86
|
@parallel
|
57
87
|
end
|
@@ -15,6 +15,9 @@ module Packwerk
|
|
15
15
|
def constant_name_from_node(node, ancestors:)
|
16
16
|
return nil unless Node.constant?(node)
|
17
17
|
parent = ancestors.first
|
18
|
+
|
19
|
+
# Only process the root `const` node for namespaced constant references. For example, in the
|
20
|
+
# reference `Spam::Eggs::Thing`, we only process the const node associated with `Spam`.
|
18
21
|
return nil unless root_constant?(parent)
|
19
22
|
|
20
23
|
if parent && constant_in_module_or_class_definition?(node, parent: parent)
|
@@ -30,8 +33,6 @@ module Packwerk
|
|
30
33
|
|
31
34
|
private
|
32
35
|
|
33
|
-
# Only process the root `const` node for namespaced constant references. For example, in the
|
34
|
-
# reference `Spam::Eggs::Thing`, we only process the const node associated with `Spam`.
|
35
36
|
sig { params(parent: T.nilable(AST::Node)).returns(T::Boolean) }
|
36
37
|
def root_constant?(parent)
|
37
38
|
!(parent && Node.constant?(parent))
|
@@ -45,7 +45,7 @@ module Packwerk
|
|
45
45
|
begin
|
46
46
|
constant = @resolver.resolve(const_name, current_namespace_path: current_namespace_path)
|
47
47
|
rescue ConstantResolver::Error => e
|
48
|
-
raise(ConstantResolver::Error, e.message
|
48
|
+
raise(ConstantResolver::Error, e.message)
|
49
49
|
end
|
50
50
|
|
51
51
|
return unless constant
|