packwerk 3.0.1 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
![](static/packwerk_check.gif)
|
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
|