packwerk 3.0.0 → 3.1.0
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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +36 -8
- data/.ruby-version +1 -1
- data/Gemfile.lock +12 -7
- data/README.md +4 -2
- data/RESOLVING_VIOLATIONS.md +3 -8
- data/Rakefile +10 -1
- data/TROUBLESHOOT.md +2 -3
- data/UPGRADING.md +12 -0
- data/USAGE.md +11 -13
- data/dev.yml +1 -1
- data/exe/packwerk +4 -1
- data/lib/packwerk/application_validator.rb +3 -0
- data/lib/packwerk/checker.rb +13 -4
- data/lib/packwerk/cli.rb +14 -177
- data/lib/packwerk/commands/base_command.rb +69 -0
- data/lib/packwerk/commands/check_command.rb +60 -0
- data/lib/packwerk/commands/help_command.rb +33 -0
- data/lib/packwerk/commands/init_command.rb +42 -0
- data/lib/packwerk/commands/lazy_loaded_entry.rb +37 -0
- data/lib/packwerk/commands/update_todo_command.rb +60 -0
- data/lib/packwerk/commands/uses_parse_run.rb +92 -0
- data/lib/packwerk/commands/validate_command.rb +46 -0
- data/lib/packwerk/commands/version_command.rb +18 -0
- data/lib/packwerk/commands.rb +54 -0
- data/lib/packwerk/configuration.rb +4 -1
- data/lib/packwerk/file_processor.rb +12 -1
- data/lib/packwerk/formatters/default_offenses_formatter.rb +3 -3
- data/lib/packwerk/formatters/progress_formatter.rb +11 -0
- data/lib/packwerk/generators/templates/packwerk.yml.erb +1 -1
- data/lib/packwerk/offense_collection.rb +32 -12
- data/lib/packwerk/offenses_formatter.rb +13 -4
- data/lib/packwerk/package_todo.rb +89 -69
- data/lib/packwerk/parse_run.rb +42 -82
- data/lib/packwerk/spring_command.rb +0 -2
- data/lib/packwerk/validator.rb +18 -4
- data/lib/packwerk/version.rb +1 -1
- data/lib/packwerk.rb +4 -28
- data/sorbet/rbi/gems/parser@3.2.2.0.rbi +7250 -0
- metadata +14 -5
- data/lib/packwerk/cli/result.rb +0 -11
- data/sorbet/rbi/gems/parser@3.1.2.1.rbi +0 -9029
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d72fbde4259baa5a5e7f8bc2ca4406d9bc6a835051efafefc23ef6ef3ae13f32
|
|
4
|
+
data.tar.gz: 65bff304e2be348e16800b0d4f65ab33a1b5fb84ab15ba495e03904d099be4a0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e25488e4af51932d503d4120e458fe92bc4ae2945ca8009219e01f4f2e7756e0430a0d9a6176f01d864d55644f262a06fb88494234b43aae43ba254437d7fb49
|
|
7
|
+
data.tar.gz: 2c821f3e11a16c52d84f7f4e68f01e788e95d5723fd77305f69e15aba07f5f1f81ea43e9c60b6c00ca4503df036eb2b3ea0e0ae1378f0c584d7252614064f9d9
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
name: CI
|
|
2
2
|
|
|
3
|
-
on:
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
- '*-stable'
|
|
8
|
+
pull_request:
|
|
4
9
|
|
|
5
10
|
jobs:
|
|
6
11
|
tests:
|
|
@@ -12,10 +17,10 @@ jobs:
|
|
|
12
17
|
- gemfiles/Gemfile-rails-6-0
|
|
13
18
|
- gemfiles/Gemfile-rails-6-1
|
|
14
19
|
ruby:
|
|
15
|
-
- 2.7
|
|
16
|
-
- 3.0
|
|
17
|
-
- 3.1
|
|
18
|
-
- 3.2
|
|
20
|
+
- "2.7"
|
|
21
|
+
- "3.0"
|
|
22
|
+
- "3.1"
|
|
23
|
+
- "3.2"
|
|
19
24
|
env:
|
|
20
25
|
BUNDLE_GEMFILE: ${{ matrix.gemfile }}
|
|
21
26
|
name: "Tests: Ruby ${{ matrix.ruby }} ${{ matrix.gemfile }}"
|
|
@@ -27,7 +32,30 @@ jobs:
|
|
|
27
32
|
ruby-version: ${{ matrix.ruby }}
|
|
28
33
|
bundler-cache: true
|
|
29
34
|
- name: Run tests
|
|
30
|
-
run: bin/rake
|
|
35
|
+
run: bin/rake test
|
|
36
|
+
loading-tests:
|
|
37
|
+
runs-on: ubuntu-latest
|
|
38
|
+
strategy:
|
|
39
|
+
matrix:
|
|
40
|
+
gemfile:
|
|
41
|
+
- Gemfile
|
|
42
|
+
ruby:
|
|
43
|
+
- "2.7"
|
|
44
|
+
- "3.0"
|
|
45
|
+
- "3.1"
|
|
46
|
+
- "3.2"
|
|
47
|
+
env:
|
|
48
|
+
BUNDLE_GEMFILE: ${{ matrix.gemfile }}
|
|
49
|
+
name: "Loading Tests: Ruby ${{ matrix.ruby }} ${{ matrix.gemfile }}"
|
|
50
|
+
steps:
|
|
51
|
+
- uses: actions/checkout@v2
|
|
52
|
+
- name: Set up Ruby ${{ matrix.ruby }}
|
|
53
|
+
uses: ruby/setup-ruby@v1
|
|
54
|
+
with:
|
|
55
|
+
ruby-version: ${{ matrix.ruby }}
|
|
56
|
+
bundler-cache: true
|
|
57
|
+
- name: Run tests
|
|
58
|
+
run: bin/rake test:loading
|
|
31
59
|
lint:
|
|
32
60
|
runs-on: ubuntu-latest
|
|
33
61
|
name: Lint
|
|
@@ -36,7 +64,7 @@ jobs:
|
|
|
36
64
|
- name: Set up Ruby
|
|
37
65
|
uses: ruby/setup-ruby@v1
|
|
38
66
|
with:
|
|
39
|
-
ruby-version: 3.1
|
|
67
|
+
ruby-version: "3.1"
|
|
40
68
|
bundler-cache: true
|
|
41
69
|
- name: Run style checks
|
|
42
70
|
run: bin/rubocop
|
|
@@ -48,7 +76,7 @@ jobs:
|
|
|
48
76
|
- name: Set up Ruby
|
|
49
77
|
uses: ruby/setup-ruby@v1
|
|
50
78
|
with:
|
|
51
|
-
ruby-version: 3.1
|
|
79
|
+
ruby-version: "3.1"
|
|
52
80
|
# bundler-cache: true
|
|
53
81
|
- name: Run static type checks
|
|
54
82
|
run: |
|
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.2.
|
|
1
|
+
3.2.2
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
packwerk (3.
|
|
4
|
+
packwerk (3.1.0)
|
|
5
5
|
activesupport (>= 6.0)
|
|
6
6
|
ast
|
|
7
7
|
better_html
|
|
@@ -60,23 +60,27 @@ GEM
|
|
|
60
60
|
method_source (>= 0.6.7)
|
|
61
61
|
rake (>= 0.9.2.2)
|
|
62
62
|
method_source (1.0.0)
|
|
63
|
-
mini_portile2 (2.8.
|
|
63
|
+
mini_portile2 (2.8.4)
|
|
64
64
|
minitest (5.16.2)
|
|
65
65
|
minitest-focus (1.3.1)
|
|
66
66
|
minitest (>= 4, < 6)
|
|
67
67
|
mocha (1.14.0)
|
|
68
68
|
netrc (0.11.0)
|
|
69
|
-
nokogiri (1.
|
|
70
|
-
mini_portile2 (~> 2.8.
|
|
69
|
+
nokogiri (1.15.3)
|
|
70
|
+
mini_portile2 (~> 2.8.2)
|
|
71
|
+
racc (~> 1.4)
|
|
72
|
+
nokogiri (1.15.3-x86_64-darwin)
|
|
73
|
+
racc (~> 1.4)
|
|
74
|
+
nokogiri (1.15.3-x86_64-linux)
|
|
71
75
|
racc (~> 1.4)
|
|
72
76
|
parallel (1.22.1)
|
|
73
|
-
parser (3.
|
|
77
|
+
parser (3.2.2.0)
|
|
74
78
|
ast (~> 2.4.1)
|
|
75
79
|
prettier_print (0.1.0)
|
|
76
80
|
pry (0.14.1)
|
|
77
81
|
coderay (~> 1.1)
|
|
78
82
|
method_source (~> 1.0)
|
|
79
|
-
racc (1.
|
|
83
|
+
racc (1.7.1)
|
|
80
84
|
rack (2.2.4)
|
|
81
85
|
rack-test (2.0.2)
|
|
82
86
|
rack (>= 1.3)
|
|
@@ -178,6 +182,7 @@ PLATFORMS
|
|
|
178
182
|
ruby
|
|
179
183
|
x86_64-darwin
|
|
180
184
|
x86_64-darwin-20
|
|
185
|
+
x86_64-linux
|
|
181
186
|
|
|
182
187
|
DEPENDENCIES
|
|
183
188
|
byebug
|
|
@@ -198,4 +203,4 @@ DEPENDENCIES
|
|
|
198
203
|
zeitwerk
|
|
199
204
|
|
|
200
205
|
BUNDLED WITH
|
|
201
|
-
2.4.
|
|
206
|
+
2.4.8
|
data/README.md
CHANGED
|
@@ -58,10 +58,12 @@ Read [USAGE.md](USAGE.md) for usage once Packwerk is installed on your project.
|
|
|
58
58
|
Various third parties have built tooling on top of packwerk. Here's a selection of some that might prove useful:
|
|
59
59
|
|
|
60
60
|
- https://github.com/bellroy/graphwerk draws a graph of your package dependencies
|
|
61
|
-
- https://github.com/
|
|
62
|
-
- https://github.com/
|
|
61
|
+
- https://github.com/rubyatscale/packwerk-vscode integrates packwerk into Visual Studio Code so you can see violations right in your editor
|
|
62
|
+
- https://github.com/vinted/packwerk-intellij integrates packwerk into RubyMine so you can see violations right in your editor
|
|
63
|
+
- https://github.com/rubyatscale/packs-rails sets up Rails autoloading, as well as `rspec` and `FactoryBot` integration, for packages arranged in a flat list. packs-rails is quite convenient, but for autoloading we recommend to use `Rails::Engine`s instead.
|
|
63
64
|
- https://github.com/rubyatscale/danger-packwerk integrates packwerk with [danger.systems](https://danger.systems) to provide packwerk feedback as Github inline PR comments
|
|
64
65
|
- https://github.com/rubyatscale/packwerk-extensions contains extensions for packwerk, including a checker for packwerk that allows you to enforce public API boundaries. This was originally extracted from `packwerk` itself.
|
|
66
|
+
- https://github.com/alexevanczuk/packs is a Rust implementation of packwerk that has experimental support for non-Rails, non-Zeitwerk applications.
|
|
65
67
|
|
|
66
68
|
## Development
|
|
67
69
|
|
data/RESOLVING_VIOLATIONS.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Violations can be [recorded as a deprecation](#recording-violations) or (better!) [eliminated](#eliminating-violations).
|
|
4
4
|
|
|
5
5
|
## Recording Violations
|
|
6
|
-
💡 New
|
|
6
|
+
💡 New dependency violations are never hard-blocked. There are many very valid reasons to run `bin/packwerk update-todo`, adding new violations to `package_todo.yml` files. Even if you feel your reason might not be "valid," if your judgement says adding the violation and shipping your change will produce positive impact, trust your gut.
|
|
7
7
|
|
|
8
8
|
### Emergency Fixes
|
|
9
9
|
❔ Is it a revert or is there a lot of urgency because you are fixing a production bug impacting customers?
|
|
@@ -31,7 +31,7 @@ Violations can be [recorded as a deprecation](#recording-violations) or (better!
|
|
|
31
31
|
➡️ Stay strong. Eliminate the violation. It is important to build a sustainable business that optimizes for the long-term. Look for advocates such as from mentors or within your team who can help you justify improving system design.
|
|
32
32
|
|
|
33
33
|
## Eliminating Violations
|
|
34
|
-
💡 Dependency
|
|
34
|
+
💡 Dependency violations are Packwerk's signal that what we've stated about the desired system design (what
|
|
35
35
|
packages exist and what lives in them, the dependencies in a package.yml, and the public interface in the package's public folder) doesn't match the reality of our system.
|
|
36
36
|
If what we've stated about our system design doesn't feel right, then the violations won't make sense either! Make sure to think through system design before addressing a violation.
|
|
37
37
|
|
|
@@ -40,12 +40,7 @@ If what we've stated about our system design doesn't feel right, then the violat
|
|
|
40
40
|
|
|
41
41
|
If not, find a better place for it to live.
|
|
42
42
|
|
|
43
|
-
Otherwise, follow the guide for eliminating [
|
|
44
|
-
|
|
45
|
-
### Privacy Violations
|
|
46
|
-
💡 Packwerk thinks something is a privacy violation if you're referencing a constant, class, or module defined in the private implementation (i.e. not the public folder) of another package. We care about these because we want to make sure we only use parts of a package that have been exposed as public API.
|
|
47
|
-
|
|
48
|
-
An explicit and implementation-hiding public API is a cornerstone of well-modularized code.
|
|
43
|
+
Otherwise, follow the guide for eliminating [Dependency Violations](#dependency-violations).
|
|
49
44
|
|
|
50
45
|
#### Use Existing Public Interface
|
|
51
46
|
❔ Does the package you're using expose public API in its public folder that supports your use case?
|
data/Rakefile
CHANGED
|
@@ -6,7 +6,16 @@ require "rake/testtask"
|
|
|
6
6
|
Rake::TestTask.new(:test) do |t|
|
|
7
7
|
t.libs << "test"
|
|
8
8
|
t.libs << "lib"
|
|
9
|
-
t.test_files = FileList["test/**/*_test.rb"]
|
|
9
|
+
t.test_files = FileList["test/**/*_test.rb"].reject do |file|
|
|
10
|
+
file.include?("test/loading/")
|
|
11
|
+
end
|
|
12
|
+
t.warning = false
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
Rake::TestTask.new("test:loading") do |t|
|
|
16
|
+
t.libs << "test"
|
|
17
|
+
t.libs << "lib"
|
|
18
|
+
t.test_files = FileList["test/loading/**/*_test.rb"]
|
|
10
19
|
t.warning = false
|
|
11
20
|
end
|
|
12
21
|
|
data/TROUBLESHOOT.md
CHANGED
|
@@ -14,9 +14,8 @@ You can specify folders or packages in Packwerk commands for a shorter run time:
|
|
|
14
14
|
|
|
15
15
|
bin/packwerk check components/your_package
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
_Note: You cannot specify folders or packages for `bin/packwerk validate` because the command runs for the entire application._
|
|
17
|
+
_Note: You cannot specify folders or packages for `bin/packwerk validate` and `bin/packwerk update-todo` because the
|
|
18
|
+
command runs for the entire application._
|
|
20
19
|
|
|
21
20
|

|
|
22
21
|
|
data/UPGRADING.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
# Upgrading from 2.x to 3.0
|
|
2
|
+
|
|
3
|
+
In Packwerk 3.0, we've made two notable changes:
|
|
4
|
+
|
|
5
|
+
## Renaming deprecated_references to package_todo
|
|
6
|
+
|
|
7
|
+
The `update-deprecations` subcommand has been renamed to `update-todo`. Old `deprecated_references.yml` files will be automatically deleted and replaced with `package_todo.yml` files when you run `update-todo`. This behaviour has been in Packwerk [since 2.3.0](https://github.com/Shopify/packwerk/releases/tag/v2.3.0), and automatic deletion will be removed in the next release.
|
|
8
|
+
|
|
9
|
+
### Removal of privacy checking
|
|
10
|
+
|
|
11
|
+
Privacy checking via `enforce_privacy` has been removed. Developers are encouraged to focus on leveraging Packwerk for dependency checking. For those who still need privacy checks, please use [Gusto's extension gem](https://github.com/rubyatscale/packwerk-extensions).
|
|
12
|
+
|
|
1
13
|
# Upgrading from 1.x to 2.0
|
|
2
14
|
|
|
3
15
|
With Packwerk 2.0, we made a few changes to simplify the setup. Updating will require removing some previously necessary files and configuration.
|
data/USAGE.md
CHANGED
|
@@ -144,7 +144,7 @@ Example:
|
|
|
144
144
|
|
|
145
145
|
## Types of boundary checks
|
|
146
146
|
|
|
147
|
-
Packwerk ships with dependency boundary checking only.
|
|
147
|
+
Packwerk ships with dependency boundary checking only. Other checking support may be added by extension gems.
|
|
148
148
|
|
|
149
149
|
#### Enforcing dependency boundary
|
|
150
150
|
|
|
@@ -172,6 +172,8 @@ Then, when you run `bin/packwerk check`, new violations will cause the following
|
|
|
172
172
|
packs/referencing_package cannot have dependency violations on packs/defining_package because strict mode is enabled for dependency violations in packs/referencing_package/package.yml
|
|
173
173
|
```
|
|
174
174
|
|
|
175
|
+
Once the `strict` mode is enabled on a package, running `bin/packwerk update-todo` will not add new violations in the package_todo.yml file and the command will return an error.
|
|
176
|
+
|
|
175
177
|
## Checking for violations
|
|
176
178
|
|
|
177
179
|
After enforcing the boundary checks for a package, you may execute:
|
|
@@ -188,6 +190,10 @@ You can also specify packages for a shorter run time. When checking against pack
|
|
|
188
190
|
|
|
189
191
|
bin/packwerk check --packages=components/your_package,components/your_other_package
|
|
190
192
|
|
|
193
|
+
Using the following command line option you can also enable or disable parallel processing. It is enabled by default.
|
|
194
|
+
|
|
195
|
+
bin/packwerk check --[no-]parallel
|
|
196
|
+
|
|
191
197
|

|
|
192
198
|
|
|
193
199
|
In order to keep the package system valid at each version of the application, we recommend running `bin/packwerk check` in your CI pipeline.
|
|
@@ -198,7 +204,7 @@ See: [TROUBLESHOOT.md - Sample violations](TROUBLESHOOT.md#Sample-violations)
|
|
|
198
204
|
|
|
199
205
|
### Understanding how to respond to new violations
|
|
200
206
|
|
|
201
|
-
When you have a new dependency
|
|
207
|
+
When you have a new dependency violation, what do you do?
|
|
202
208
|
|
|
203
209
|
See: [RESOLVING_VIOLATIONS.md](RESOLVING_VIOLATIONS.md)
|
|
204
210
|
|
|
@@ -235,10 +241,10 @@ Above is an example of a constant violation entry in `package_todo.yml`.
|
|
|
235
241
|
|
|
236
242
|
* `components/merchant` - package where the constant violation is found
|
|
237
243
|
* `::Checkouts::Core::CheckoutId` - violated constant in question
|
|
238
|
-
* `dependency` - type of violation,
|
|
244
|
+
* `dependency` - type of violation, typically dependency
|
|
239
245
|
* `components/merchant/app/public/merchant/generate_order.rb` - path to the file containing the violated constant
|
|
240
246
|
|
|
241
|
-
Violations exist within the package that makes a violating reference.
|
|
247
|
+
Violations exist within the package that makes a violating reference.
|
|
242
248
|
|
|
243
249
|
# Loading Extensions
|
|
244
250
|
|
|
@@ -284,7 +290,7 @@ bin/packwerk check --offenses-formatter=my_offenses_formatter
|
|
|
284
290
|
|
|
285
291
|
### Custom Checkers
|
|
286
292
|
|
|
287
|
-
Packwerk ships with a way to analyze dependencies and also supports custom checkers
|
|
293
|
+
Packwerk ships with a way to analyze dependencies and also supports custom checkers from extension gems.
|
|
288
294
|
|
|
289
295
|
Custom checkers will allow references to constants to be analyzed in new ways, and for those invalid references to show up as violations in `package_todo.yml`.
|
|
290
296
|
|
|
@@ -327,14 +333,6 @@ require:
|
|
|
327
333
|
- ./path/to/file.rb
|
|
328
334
|
```
|
|
329
335
|
|
|
330
|
-
#### Privacy Checker
|
|
331
|
-
|
|
332
|
-
[`packwerk-extensions`](https://github.com/rubyatscale/packwerk-extensions) (originally extracted from `packwerk`) can be used to help define and enforce public API boundaries of a package. See the README.md for more details. To use this, add it to your `Gemfile` and then require it via `packwerk.yml`:
|
|
333
|
-
```yml
|
|
334
|
-
require:
|
|
335
|
-
- packwerk-extensions
|
|
336
|
-
```
|
|
337
|
-
|
|
338
336
|
### Custom Validators
|
|
339
337
|
|
|
340
338
|
Similar to checkers, you can define your own validator to be executed when `bin/packwerk validate` is invoked. This can be used to support your custom checker (by specifying permitted keys) or to provide any other validations you want to impose on packages.
|
data/dev.yml
CHANGED
data/exe/packwerk
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
unless defined?(Spring)
|
|
5
|
+
require "packwerk/disable_sorbet"
|
|
6
|
+
end
|
|
7
|
+
|
|
5
8
|
require "packwerk"
|
|
6
9
|
|
|
7
10
|
# Needs to be run in test environment in order to have test helper paths available in the autoload paths
|
|
@@ -11,6 +11,9 @@ module Packwerk
|
|
|
11
11
|
class ApplicationValidator
|
|
12
12
|
include Validator
|
|
13
13
|
extend T::Sig
|
|
14
|
+
extend ActiveSupport::Autoload
|
|
15
|
+
|
|
16
|
+
autoload :Helpers
|
|
14
17
|
|
|
15
18
|
sig { params(package_set: PackageSet, configuration: Configuration).returns(Validator::Result) }
|
|
16
19
|
def check_all(package_set, configuration)
|
data/lib/packwerk/checker.rb
CHANGED
|
@@ -13,14 +13,13 @@ module Packwerk
|
|
|
13
13
|
|
|
14
14
|
sig { params(base: Class).void }
|
|
15
15
|
def included(base)
|
|
16
|
-
|
|
17
|
-
@checkers ||= []
|
|
18
|
-
@checkers << base
|
|
16
|
+
checkers << base
|
|
19
17
|
end
|
|
20
18
|
|
|
21
19
|
sig { returns(T::Array[Checker]) }
|
|
22
20
|
def all
|
|
23
|
-
|
|
21
|
+
load_defaults
|
|
22
|
+
T.cast(checkers.map(&:new), T::Array[Checker])
|
|
24
23
|
end
|
|
25
24
|
|
|
26
25
|
sig { params(violation_type: String).returns(Checker) }
|
|
@@ -30,6 +29,16 @@ module Packwerk
|
|
|
30
29
|
|
|
31
30
|
private
|
|
32
31
|
|
|
32
|
+
sig { void }
|
|
33
|
+
def load_defaults
|
|
34
|
+
require("packwerk/reference_checking/checkers/dependency_checker")
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
sig { returns(T::Array[Class]) }
|
|
38
|
+
def checkers
|
|
39
|
+
@checkers ||= T.let([], T.nilable(T::Array[Class]))
|
|
40
|
+
end
|
|
41
|
+
|
|
33
42
|
sig { params(name: String).returns(Checker) }
|
|
34
43
|
def checker_by_violation_type(name)
|
|
35
44
|
@checker_by_violation_type ||= T.let(Checker.all.to_h do |checker|
|
data/lib/packwerk/cli.rb
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# typed: strict
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
require "optparse"
|
|
5
|
-
|
|
6
4
|
module Packwerk
|
|
7
5
|
# A command-line interface to Packwerk.
|
|
8
6
|
class Cli
|
|
@@ -46,184 +44,23 @@ module Packwerk
|
|
|
46
44
|
|
|
47
45
|
sig { params(args: T::Array[String]).returns(T::Boolean) }
|
|
48
46
|
def execute_command(args)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
true
|
|
62
|
-
when nil, "help"
|
|
63
|
-
usage
|
|
64
|
-
else
|
|
65
|
-
@err_out.puts(
|
|
66
|
-
"'#{subcommand}' is not a packwerk command. See `packwerk help`."
|
|
67
|
-
)
|
|
68
|
-
false
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
private
|
|
73
|
-
|
|
74
|
-
sig { returns(T::Boolean) }
|
|
75
|
-
def init
|
|
76
|
-
@out.puts("📦 Initializing Packwerk...")
|
|
77
|
-
|
|
78
|
-
generate_configs
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
sig { returns(T::Boolean) }
|
|
82
|
-
def generate_configs
|
|
83
|
-
configuration_file = Generators::ConfigurationFile.generate(
|
|
84
|
-
root: @configuration.root_path,
|
|
85
|
-
out: @out
|
|
86
|
-
)
|
|
87
|
-
|
|
88
|
-
root_package = Generators::RootPackage.generate(root: @configuration.root_path, out: @out)
|
|
89
|
-
|
|
90
|
-
success = configuration_file && root_package
|
|
91
|
-
|
|
92
|
-
result = if success
|
|
93
|
-
<<~EOS
|
|
94
|
-
|
|
95
|
-
🎉 Packwerk is ready to be used. You can start defining packages and run `bin/packwerk check`.
|
|
96
|
-
For more information on how to use Packwerk, see: https://github.com/Shopify/packwerk/blob/main/USAGE.md
|
|
97
|
-
EOS
|
|
98
|
-
else
|
|
99
|
-
<<~EOS
|
|
100
|
-
|
|
101
|
-
⚠️ Packwerk is not ready to be used.
|
|
102
|
-
Please check output and refer to https://github.com/Shopify/packwerk/blob/main/USAGE.md for more information.
|
|
103
|
-
EOS
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
@out.puts(result)
|
|
107
|
-
success
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
sig { returns(T::Boolean) }
|
|
111
|
-
def usage
|
|
112
|
-
@err_out.puts(<<~USAGE)
|
|
113
|
-
Usage: #{$PROGRAM_NAME} <subcommand>
|
|
114
|
-
|
|
115
|
-
Subcommands:
|
|
116
|
-
init - set up packwerk
|
|
117
|
-
check - run all checks
|
|
118
|
-
update-todo - update package_todo.yml files
|
|
119
|
-
validate - verify integrity of packwerk and package configuration
|
|
120
|
-
version - output packwerk version
|
|
121
|
-
help - display help information about packwerk
|
|
122
|
-
USAGE
|
|
123
|
-
true
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
sig { params(result: Result).returns(T::Boolean) }
|
|
127
|
-
def output_result(result)
|
|
128
|
-
@out.puts
|
|
129
|
-
@out.puts(result.message)
|
|
130
|
-
result.status
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
sig do
|
|
134
|
-
params(
|
|
135
|
-
relative_file_paths: T::Array[String],
|
|
136
|
-
ignore_nested_packages: T::Boolean
|
|
137
|
-
).returns(FilesForProcessing)
|
|
138
|
-
end
|
|
139
|
-
def fetch_files_to_process(relative_file_paths, ignore_nested_packages)
|
|
140
|
-
files_for_processing = FilesForProcessing.fetch(
|
|
141
|
-
relative_file_paths: relative_file_paths,
|
|
142
|
-
ignore_nested_packages: ignore_nested_packages,
|
|
143
|
-
configuration: @configuration
|
|
144
|
-
)
|
|
145
|
-
@out.puts(<<~MSG.squish) if files_for_processing.files.empty?
|
|
146
|
-
No files found or given.
|
|
147
|
-
Specify files or check the include and exclude glob in the config file.
|
|
148
|
-
MSG
|
|
149
|
-
|
|
150
|
-
files_for_processing
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
sig { params(_paths: T::Array[String]).returns(T::Boolean) }
|
|
154
|
-
def validate(_paths)
|
|
155
|
-
result = T.let(nil, T.nilable(Validator::Result))
|
|
156
|
-
|
|
157
|
-
@progress_formatter.started_validation do
|
|
158
|
-
result = validator.check_all(package_set, @configuration)
|
|
159
|
-
|
|
160
|
-
list_validation_errors(result)
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
T.must(result).ok?
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
sig { returns(ApplicationValidator) }
|
|
167
|
-
def validator
|
|
168
|
-
ApplicationValidator.new
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
sig { returns(PackageSet) }
|
|
172
|
-
def package_set
|
|
173
|
-
PackageSet.load_all_from(
|
|
174
|
-
@configuration.root_path,
|
|
175
|
-
package_pathspec: @configuration.package_paths
|
|
176
|
-
)
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
sig { params(result: Validator::Result).void }
|
|
180
|
-
def list_validation_errors(result)
|
|
181
|
-
@out.puts
|
|
182
|
-
if result.ok?
|
|
183
|
-
@out.puts("Validation successful 🎉")
|
|
47
|
+
command = args.shift || "help"
|
|
48
|
+
command_class = Commands.for(command)
|
|
49
|
+
|
|
50
|
+
if command_class
|
|
51
|
+
command_class.new(
|
|
52
|
+
args,
|
|
53
|
+
configuration: @configuration,
|
|
54
|
+
out: @out,
|
|
55
|
+
err_out: @err_out,
|
|
56
|
+
progress_formatter: @progress_formatter,
|
|
57
|
+
offenses_formatter: @offenses_formatter,
|
|
58
|
+
).run
|
|
184
59
|
else
|
|
185
|
-
@
|
|
186
|
-
@out.puts
|
|
187
|
-
@out.puts(result.error_value)
|
|
188
|
-
end
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
sig { params(args: T::Array[String]).returns(ParseRun) }
|
|
192
|
-
def parse_run(args)
|
|
193
|
-
relative_file_paths = T.let([], T::Array[String])
|
|
194
|
-
ignore_nested_packages = nil
|
|
195
|
-
formatter = @offenses_formatter
|
|
60
|
+
@err_out.puts("'#{command}' is not a packwerk command. See `packwerk help`.",)
|
|
196
61
|
|
|
197
|
-
|
|
198
|
-
OptionParser.new do |parser|
|
|
199
|
-
parser.on("--packages=PACKAGESLIST", Array, "package names, comma separated") do |p|
|
|
200
|
-
relative_file_paths = p
|
|
201
|
-
end
|
|
202
|
-
end.parse!(args)
|
|
203
|
-
ignore_nested_packages = true
|
|
204
|
-
else
|
|
205
|
-
relative_file_paths = args
|
|
206
|
-
ignore_nested_packages = false
|
|
207
|
-
end
|
|
208
|
-
|
|
209
|
-
if args.any? { |arg| arg.include?("--offenses-formatter") }
|
|
210
|
-
OptionParser.new do |parser|
|
|
211
|
-
parser.on("--offenses-formatter=FORMATTER", String,
|
|
212
|
-
"identifier of offenses formatter to use") do |formatter_identifier|
|
|
213
|
-
formatter = OffensesFormatter.find(formatter_identifier)
|
|
214
|
-
end
|
|
215
|
-
end.parse!(args)
|
|
62
|
+
false
|
|
216
63
|
end
|
|
217
|
-
|
|
218
|
-
files_for_processing = fetch_files_to_process(relative_file_paths, ignore_nested_packages)
|
|
219
|
-
|
|
220
|
-
ParseRun.new(
|
|
221
|
-
relative_file_set: files_for_processing.files,
|
|
222
|
-
file_set_specified: files_for_processing.files_specified?,
|
|
223
|
-
configuration: @configuration,
|
|
224
|
-
progress_formatter: @progress_formatter,
|
|
225
|
-
offenses_formatter: formatter
|
|
226
|
-
)
|
|
227
64
|
end
|
|
228
65
|
end
|
|
229
66
|
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Packwerk
|
|
5
|
+
module Commands
|
|
6
|
+
class BaseCommand
|
|
7
|
+
extend T::Sig
|
|
8
|
+
extend T::Helpers
|
|
9
|
+
abstract!
|
|
10
|
+
|
|
11
|
+
@description = T.let("", String)
|
|
12
|
+
|
|
13
|
+
class << self
|
|
14
|
+
extend T::Sig
|
|
15
|
+
|
|
16
|
+
sig { params(description: T.nilable(String)).returns(String) }
|
|
17
|
+
def description(description = nil)
|
|
18
|
+
if description
|
|
19
|
+
@description = description
|
|
20
|
+
else
|
|
21
|
+
@description
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
sig do
|
|
27
|
+
params(
|
|
28
|
+
args: T::Array[String],
|
|
29
|
+
configuration: Configuration,
|
|
30
|
+
out: T.any(StringIO, IO),
|
|
31
|
+
err_out: T.any(StringIO, IO),
|
|
32
|
+
progress_formatter: Formatters::ProgressFormatter,
|
|
33
|
+
offenses_formatter: OffensesFormatter,
|
|
34
|
+
).void
|
|
35
|
+
end
|
|
36
|
+
def initialize(args, configuration:, out:, err_out:, progress_formatter:, offenses_formatter:)
|
|
37
|
+
@args = args
|
|
38
|
+
@configuration = configuration
|
|
39
|
+
@out = out
|
|
40
|
+
@err_out = err_out
|
|
41
|
+
@progress_formatter = progress_formatter
|
|
42
|
+
@offenses_formatter = offenses_formatter
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
sig { abstract.returns(T::Boolean) }
|
|
46
|
+
def run; end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
sig { returns(T::Array[String]) }
|
|
51
|
+
attr_reader :args
|
|
52
|
+
|
|
53
|
+
sig { returns(Configuration) }
|
|
54
|
+
attr_reader :configuration
|
|
55
|
+
|
|
56
|
+
sig { returns(T.any(StringIO, IO)) }
|
|
57
|
+
attr_reader :out
|
|
58
|
+
|
|
59
|
+
sig { returns(T.any(StringIO, IO)) }
|
|
60
|
+
attr_reader :err_out
|
|
61
|
+
|
|
62
|
+
sig { returns(Formatters::ProgressFormatter) }
|
|
63
|
+
attr_reader :progress_formatter
|
|
64
|
+
|
|
65
|
+
sig { returns(OffensesFormatter) }
|
|
66
|
+
attr_reader :offenses_formatter
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|