packwerk 1.3.1 → 2.1.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 +12 -9
- data/README.md +9 -3
- data/TROUBLESHOOT.md +3 -3
- data/UPGRADING.md +54 -0
- data/USAGE.md +32 -51
- data/exe/packwerk +7 -1
- data/lib/packwerk/application_load_paths.rb +1 -0
- data/lib/packwerk/application_validator.rb +17 -59
- data/lib/packwerk/association_inspector.rb +1 -1
- data/lib/packwerk/cache.rb +168 -0
- data/lib/packwerk/cli.rb +37 -20
- data/lib/packwerk/configuration.rb +40 -5
- data/lib/packwerk/const_node_inspector.rb +3 -2
- data/lib/packwerk/constant_discovery.rb +4 -4
- data/lib/packwerk/constant_name_inspector.rb +1 -1
- data/lib/packwerk/deprecated_references.rb +18 -6
- data/lib/packwerk/file_processor.rb +53 -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 +5 -5
- data/lib/packwerk/graph.rb +2 -0
- data/lib/packwerk/node.rb +2 -0
- data/lib/packwerk/node_processor.rb +10 -22
- data/lib/packwerk/node_processor_factory.rb +0 -3
- data/lib/packwerk/node_visitor.rb +7 -2
- data/lib/packwerk/package.rb +25 -4
- data/lib/packwerk/package_set.rb +44 -8
- data/lib/packwerk/parsed_constant_definitions.rb +5 -4
- 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 +66 -19
- data/lib/packwerk/reference_offense.rb +1 -0
- data/lib/packwerk/run_context.rb +32 -11
- data/lib/packwerk/sanity_checker.rb +1 -1
- data/lib/packwerk/spring_command.rb +28 -0
- data/lib/packwerk/unresolved_reference.rb +10 -0
- data/lib/packwerk/version.rb +1 -1
- data/lib/packwerk/violation_type.rb +1 -1
- data/lib/packwerk.rb +19 -12
- data/packwerk.gemspec +4 -1
- data/service.yml +0 -2
- data/sorbet/rbi/gems/psych@3.3.2.rbi +24 -0
- metadata +41 -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: 66332315c1155336fbe79f8aeb6e44a0893d4100a1d4b6b5f08c81574c940fe0
|
4
|
+
data.tar.gz: 88da350ce07daaf7556d23edbc318a19ca33b74af71ee624d547a8a8598bc16b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b54eeeac5e68285e03c32916d72f2afdc291d9d6d4993de0d2875d7dbb4a9cdf8cde7ca2677107f35288a20a20c1f8fc2f9ddcc330c9a7fe0dfaf8e245c07b3c
|
7
|
+
data.tar.gz: d8597878958e00a069cb5e51c609e04da9526b3c1933c4824399e4bad1173d718703c88ec582411a9c73fb5c88899707b04ebdb7b296a22b70e25598e11b57d6
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
See https://github.com/Shopify/packwerk/releases.
|
data/Gemfile.lock
CHANGED
@@ -87,11 +87,13 @@ GIT
|
|
87
87
|
PATH
|
88
88
|
remote: .
|
89
89
|
specs:
|
90
|
-
packwerk (1.
|
90
|
+
packwerk (2.1.0)
|
91
91
|
activesupport (>= 5.2)
|
92
92
|
ast
|
93
93
|
better_html
|
94
|
+
bundler
|
94
95
|
constant_resolver
|
96
|
+
digest
|
95
97
|
parallel
|
96
98
|
parser
|
97
99
|
sorbet-runtime
|
@@ -117,6 +119,7 @@ GEM
|
|
117
119
|
concurrent-ruby (1.1.8)
|
118
120
|
constant_resolver (0.1.5)
|
119
121
|
crass (1.0.6)
|
122
|
+
digest (3.1.0)
|
120
123
|
erubi (1.10.0)
|
121
124
|
globalid (0.4.2)
|
122
125
|
activesupport (>= 4.2.0)
|
@@ -135,16 +138,14 @@ GEM
|
|
135
138
|
marcel (1.0.0)
|
136
139
|
method_source (1.0.0)
|
137
140
|
mini_mime (1.0.3)
|
138
|
-
mini_portile2 (2.
|
141
|
+
mini_portile2 (2.6.1)
|
139
142
|
minitest (5.14.4)
|
140
143
|
minitest-focus (1.2.1)
|
141
144
|
minitest (>= 4, < 6)
|
142
145
|
mocha (1.12.0)
|
143
146
|
nio4r (2.5.7)
|
144
|
-
nokogiri (1.
|
145
|
-
mini_portile2 (~> 2.
|
146
|
-
racc (~> 1.4)
|
147
|
-
nokogiri (1.11.5-x86_64-darwin)
|
147
|
+
nokogiri (1.12.5)
|
148
|
+
mini_portile2 (~> 2.6.1)
|
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.
|
260
|
+
2.3.4
|
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
|
|
@@ -57,6 +56,13 @@ Read [USAGE.md](USAGE.md) for usage once Packwerk is installed on your project.
|
|
57
56
|
|
58
57
|
"Packwerk" is pronounced [[ˈpakvɛʁk]](https://cdn.shopify.com/s/files/1/0258/7469/files/packwerk.mp3).
|
59
58
|
|
59
|
+
## Ecosystem
|
60
|
+
|
61
|
+
You can use these third party tools to enhance your packwerk experience:
|
62
|
+
|
63
|
+
- https://github.com/bellroy/graphwerk draws a graph of your package dependencies
|
64
|
+
- https://github.com/Gusto/packwerk-vscode integrates packwerk into Visual Studio Code so you can see violations right in your editor
|
65
|
+
|
60
66
|
## Development
|
61
67
|
|
62
68
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
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,9 +75,10 @@ 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 |
|
80
|
+
| cache | false | when true, caches the results of parsing files |
|
81
|
+
| cache_directory | tmp/cache/packwerk | the directory that will hold the packwerk cache |
|
71
82
|
|
72
83
|
### Using a custom ERB parser
|
73
84
|
|
@@ -91,50 +102,16 @@ end
|
|
91
102
|
Packwerk::Parsers::Factory.instance.erb_parser_class = CustomParser
|
92
103
|
```
|
93
104
|
|
94
|
-
|
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._
|
105
|
+
## Using the cache
|
106
|
+
Packwerk ships with an cache to help speed up file parsing. You can turn this on by setting `cache: true` in `packwerk.yml`.
|
114
107
|
|
115
|
-
|
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`.
|
108
|
+
This will write to `tmp/cache/packwerk`.
|
132
109
|
|
133
110
|
## Validating the package system
|
134
111
|
|
135
112
|
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
113
|
|
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`.
|
114
|
+
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
115
|
|
139
116
|
Use the following command to validate the application:
|
140
117
|
|
@@ -231,13 +208,17 @@ After enforcing the boundary checks for a package, you may execute:
|
|
231
208
|
|
232
209
|
Packwerk will check the entire codebase for any new or stale violations.
|
233
210
|
|
234
|
-
You can also specify folders
|
211
|
+
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
212
|
|
236
213
|
packwerk check components/your_package
|
237
214
|
|
215
|
+
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.
|
216
|
+
|
217
|
+
packwerk check --packages=components/your_package,components/your_other_package
|
218
|
+
|
238
219
|
![](static/packwerk_check.gif)
|
239
220
|
|
240
|
-
In order to keep the package system valid at each version of the application, we recommend running `packwerk check` in your CI pipeline.
|
221
|
+
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
222
|
|
242
223
|
See: [TROUBLESHOOT.md - Sample violations](TROUBLESHOOT.md#Sample-violations)
|
243
224
|
|
@@ -247,17 +228,17 @@ For existing codebases, packages are likely to have existing boundary violations
|
|
247
228
|
|
248
229
|
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
230
|
|
250
|
-
packwerk update-deprecations
|
231
|
+
bin/packwerk update-deprecations
|
251
232
|
|
252
|
-
Similar to `packwerk check`, you may also run `packwerk update-deprecations` on folders or packages:
|
233
|
+
Similar to `bin/packwerk check`, you may also run `bin/packwerk update-deprecations` on folders or packages:
|
253
234
|
|
254
|
-
packwerk update-deprecations components/your_package
|
235
|
+
bin/packwerk update-deprecations components/your_package
|
255
236
|
|
256
237
|
![](static/packwerk_update.gif)
|
257
238
|
|
258
239
|
_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
240
|
|
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.
|
241
|
+
`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
242
|
|
262
243
|
See: [TROUBLESHOOT.md - Troubleshooting violations](TROUBLESHOOT.md#Troubleshooting_violations)
|
263
244
|
|
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
|
|
@@ -57,13 +39,13 @@ module Packwerk
|
|
57
39
|
load_paths: @configuration.load_paths
|
58
40
|
)
|
59
41
|
|
60
|
-
results = []
|
42
|
+
results = T.let([], T::Array[Packwerk::Result])
|
61
43
|
|
62
44
|
privacy_settings.each do |config_file_path, setting|
|
63
45
|
next unless setting.is_a?(Array)
|
64
46
|
constants = setting
|
65
47
|
|
66
|
-
assert_constants_can_be_loaded(constants)
|
48
|
+
results += assert_constants_can_be_loaded(constants, config_file_path)
|
67
49
|
|
68
50
|
constant_locations = constants.map { |c| [c, resolver.resolve(c)&.location] }
|
69
51
|
|
@@ -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
|
|
@@ -316,9 +265,18 @@ module Packwerk
|
|
316
265
|
!File.file?(package_path)
|
317
266
|
end
|
318
267
|
|
319
|
-
def assert_constants_can_be_loaded(constants)
|
320
|
-
constants.
|
321
|
-
|
268
|
+
def assert_constants_can_be_loaded(constants, config_file_path)
|
269
|
+
constants.map do |constant|
|
270
|
+
if !constant.start_with?("::")
|
271
|
+
Result.new(
|
272
|
+
false,
|
273
|
+
"'#{constant}', listed in the 'enforce_privacy' option in #{config_file_path}, is invalid.\n"\
|
274
|
+
"Private constants need to be prefixed with the top-level namespace operator `::`."
|
275
|
+
)
|
276
|
+
else
|
277
|
+
constant.try(&:constantize) && Result.new(true)
|
278
|
+
end
|
279
|
+
end
|
322
280
|
end
|
323
281
|
|
324
282
|
def private_constant_unresolvable(name, config_file_path)
|
@@ -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)
|