packwerk 3.0.1 → 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 +11 -6
- data/README.md +4 -2
- data/Rakefile +10 -1
- data/USAGE.md +6 -0
- data/dev.yml +1 -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 +87 -60
- data/lib/packwerk/parse_run.rb +42 -82
- 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.0
|
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
|
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/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/USAGE.md
CHANGED
@@ -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.
|
data/dev.yml
CHANGED
@@ -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
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Packwerk
|
5
|
+
module Commands
|
6
|
+
class CheckCommand < BaseCommand
|
7
|
+
extend T::Sig
|
8
|
+
include UsesParseRun
|
9
|
+
|
10
|
+
description "run all checks"
|
11
|
+
|
12
|
+
sig { override.returns(T::Boolean) }
|
13
|
+
def run
|
14
|
+
if @files_for_processing.files.empty?
|
15
|
+
out.puts(<<~MSG.squish)
|
16
|
+
No files found or given.
|
17
|
+
Specify files or check the include and exclude glob in the config file.
|
18
|
+
MSG
|
19
|
+
|
20
|
+
true
|
21
|
+
end
|
22
|
+
|
23
|
+
all_offenses = T.let([], T::Array[Offense])
|
24
|
+
on_interrupt = T.let(-> { progress_formatter.interrupted }, T.proc.void)
|
25
|
+
|
26
|
+
progress_formatter.started_inspection(@files_for_processing.files) do
|
27
|
+
all_offenses = parse_run.find_offenses(run_context, on_interrupt: on_interrupt) do |offenses|
|
28
|
+
failed = offenses.any? { |offense| !offense_collection.listed?(offense) }
|
29
|
+
progress_formatter.increment_progress(failed)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
offense_collection.add_offenses(all_offenses)
|
33
|
+
|
34
|
+
messages = [
|
35
|
+
offenses_formatter.show_offenses(offense_collection.outstanding_offenses),
|
36
|
+
offenses_formatter.show_stale_violations(offense_collection, @files_for_processing.files),
|
37
|
+
offenses_formatter.show_strict_mode_violations(offense_collection.strict_mode_violations),
|
38
|
+
]
|
39
|
+
|
40
|
+
out.puts(messages.select(&:present?).join("\n") + "\n")
|
41
|
+
|
42
|
+
offense_collection.outstanding_offenses.empty? &&
|
43
|
+
!offense_collection.stale_violations?(@files_for_processing.files) &&
|
44
|
+
offense_collection.strict_mode_violations.empty?
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
sig { returns(RunContext) }
|
50
|
+
def run_context
|
51
|
+
@run_context ||= T.let(RunContext.from_configuration(configuration), T.nilable(RunContext))
|
52
|
+
end
|
53
|
+
|
54
|
+
sig { returns(OffenseCollection) }
|
55
|
+
def offense_collection
|
56
|
+
@offense_collection ||= T.let(OffenseCollection.new(configuration.root_path), T.nilable(OffenseCollection))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Packwerk
|
5
|
+
module Commands
|
6
|
+
class HelpCommand < BaseCommand
|
7
|
+
extend T::Sig
|
8
|
+
|
9
|
+
description "display help information about packwerk"
|
10
|
+
|
11
|
+
sig { override.returns(T::Boolean) }
|
12
|
+
def run
|
13
|
+
err_out.puts(<<~USAGE)
|
14
|
+
Usage: #{$PROGRAM_NAME} <subcommand>
|
15
|
+
|
16
|
+
Subcommands:
|
17
|
+
#{command_help_lines}
|
18
|
+
USAGE
|
19
|
+
|
20
|
+
true
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
sig { returns(String) }
|
26
|
+
def command_help_lines
|
27
|
+
Commands.all.map do |command|
|
28
|
+
" #{command.name} - #{command.description}"
|
29
|
+
end.join("\n")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Packwerk
|
5
|
+
module Commands
|
6
|
+
class InitCommand < BaseCommand
|
7
|
+
extend T::Sig
|
8
|
+
|
9
|
+
description "set up packwerk"
|
10
|
+
|
11
|
+
sig { override.returns(T::Boolean) }
|
12
|
+
def run
|
13
|
+
out.puts("📦 Initializing Packwerk...")
|
14
|
+
|
15
|
+
configuration_file = Generators::ConfigurationFile.generate(
|
16
|
+
root: configuration.root_path,
|
17
|
+
out: out
|
18
|
+
)
|
19
|
+
|
20
|
+
root_package = Generators::RootPackage.generate(root: configuration.root_path, out: out)
|
21
|
+
|
22
|
+
success = configuration_file && root_package
|
23
|
+
|
24
|
+
if success
|
25
|
+
out.puts(<<~EOS)
|
26
|
+
|
27
|
+
🎉 Packwerk is ready to be used. You can start defining packages and run `bin/packwerk check`.
|
28
|
+
For more information on how to use Packwerk, see: https://github.com/Shopify/packwerk/blob/main/USAGE.md
|
29
|
+
EOS
|
30
|
+
else
|
31
|
+
out.puts(<<~EOS)
|
32
|
+
|
33
|
+
⚠️ Packwerk is not ready to be used.
|
34
|
+
Please check output and refer to https://github.com/Shopify/packwerk/blob/main/USAGE.md for more information.
|
35
|
+
EOS
|
36
|
+
end
|
37
|
+
|
38
|
+
success
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|