packwerk 2.2.2 → 2.3.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/Gemfile.lock +1 -1
- data/RESOLVING_VIOLATIONS.md +7 -7
- data/TROUBLESHOOT.md +1 -1
- data/USAGE.md +11 -11
- data/lib/packwerk/cli.rb +11 -1
- data/lib/packwerk/formatters/offenses_formatter.rb +1 -1
- data/lib/packwerk/offense_collection.rb +38 -26
- data/lib/packwerk/{deprecated_references.rb → package_todo.rb} +18 -8
- data/lib/packwerk/parse_run.rb +3 -3
- data/lib/packwerk/version.rb +1 -1
- data/lib/packwerk.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 94a6e793dd2c071a7bfb9a739fb6aaf2e07b0d2183bf743afb38da5e3847f0e2
|
4
|
+
data.tar.gz: dd779094dad5572746476d25d63e26f29819cf0b57519f73a4f693610cfd238e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9ff4d2a2aa7b6cb34e59362321ea3fb22826d10430addeef1b6143408d1a1b510ff8915105f2e74e9173334dfcfbd0a76610ea00242a2720c6feb9c75b53556f
|
7
|
+
data.tar.gz: 7ed4cbe3376821d54a5a58e2bc25ac3baf1f03a84928e027c0e1e1f39d52a14df4e18cc8d9ecfa50de3756507f46c0e9687d04464d3ec149037a7fdecb8eed0e
|
data/Gemfile.lock
CHANGED
data/RESOLVING_VIOLATIONS.md
CHANGED
@@ -3,27 +3,27 @@
|
|
3
3
|
Violations can be [recorded as a deprecation](#recording-violations) or (better!) [eliminated](#eliminating-violations).
|
4
4
|
|
5
5
|
## Recording Violations
|
6
|
-
💡 New privacy and dependency violations are never hard-blocked. There are many very valid reasons to run `bin/packwerk update-
|
6
|
+
💡 New privacy and 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?
|
10
10
|
|
11
|
-
➡️ Simply run `bin/packwerk update-
|
11
|
+
➡️ Simply run `bin/packwerk update-todo`, and address the violation when the customer issue is resolved.
|
12
12
|
|
13
13
|
### Improving System Design
|
14
14
|
❔ Are you improving system boundaries by renaming or moving a file, class, constant,` or module?
|
15
15
|
|
16
|
-
➡️ Simply run `bin/packwerk update-
|
16
|
+
➡️ Simply run `bin/packwerk update-todo`. We've improved how our system is organized, so the new violations are natural.
|
17
17
|
|
18
18
|
### Making Things Explicit
|
19
19
|
❔ Are you making something that was implicit (hidden to Packwerk) explicit, such as adding a Sorbet signature, using a class instead of a method call, or something similar?
|
20
20
|
|
21
|
-
➡️ Simply run `bin/packwerk update-
|
21
|
+
➡️ Simply run `bin/packwerk update-todo`. Making something implicit explicit and capturing that as a new violation is a strict improvement.
|
22
22
|
|
23
23
|
### Temporary State
|
24
24
|
❔ Is the violation temporary because you will soon delete the code or is it part of a refactor to improve system boundaries and reduce violations overall?
|
25
25
|
|
26
|
-
➡️ Simply run `bin/packwerk update-
|
26
|
+
➡️ Simply run `bin/packwerk update-todo`. Sometimes things get "worse" before they get better.
|
27
27
|
|
28
28
|
### Delivering Features
|
29
29
|
❔ Are you in a rush to get a feature out and product, your manager, or an internal sense of urgency has made you feel like you can't resolve system design issues?
|
@@ -57,7 +57,7 @@ An explicit and implementation-hiding public API is a cornerstone of well-modula
|
|
57
57
|
|
58
58
|
➡️ Work together on a new public API and use that instead! If the thing we're using should be public, move it to the public folder to make it public!
|
59
59
|
|
60
|
-
⛈️ If working with the package's owner to improve the API is not possible, run `bin/packwerk update-
|
60
|
+
⛈️ If working with the package's owner to improve the API is not possible, run `bin/packwerk update-todo`. Add some context to your PR about why it's not possible.
|
61
61
|
|
62
62
|
### Dependency Violations
|
63
63
|
💡 Packwerk thinks something is a dependency violation if you're referencing a constant, class, module defined ANYWHERE but your package doesn't list it as an explicit dependency in its `package.yml`. We care about these because it allows us to be systematically intentional about what our code needs to run and helps us untangle and remove dependency cycles from our system.
|
@@ -78,4 +78,4 @@ Thoughtful dependency management is another cornerstone of well-modularized code
|
|
78
78
|
|
79
79
|
➡️ Work with the owners of the relevant packages, as well as your team, to think through a design that doesn't include the unwanted dependency.
|
80
80
|
|
81
|
-
⛈️ If this is not possible within the scope of your changes (think hard about this one!), run `bin/packwerk update-
|
81
|
+
⛈️ If this is not possible within the scope of your changes (think hard about this one!), run `bin/packwerk update-todo`. Add some context to your PR about why it's not possible, and any additional context you may have, such as a possible solution.
|
data/TROUBLESHOOT.md
CHANGED
@@ -16,7 +16,7 @@ You can specify folders or packages in Packwerk commands for a shorter run time:
|
|
16
16
|
|
17
17
|
bin/packwerk check components/your_package
|
18
18
|
|
19
|
-
bin/packwerk update-
|
19
|
+
bin/packwerk update-todo components/your_package
|
20
20
|
|
21
21
|
_Note: You cannot specify folders or packages for `bin/packwerk validate` because the command runs for the entire application._
|
22
22
|
|
data/USAGE.md
CHANGED
@@ -20,7 +20,7 @@
|
|
20
20
|
* [Resolving new violations](#resolving-new-violations)
|
21
21
|
* [Understanding how to respond to new violations](#understanding-how-to-respond-to-new-violations)
|
22
22
|
* [Recording existing violations](#recording-existing-violations)
|
23
|
-
* [Understanding the
|
23
|
+
* [Understanding the package todo file](#understanding-the-package-todo-file)
|
24
24
|
|
25
25
|
## What problem does Packwerk solve?
|
26
26
|
|
@@ -235,28 +235,28 @@ See: [RESOLVING_VIOLATIONS.md](RESOLVING_VIOLATIONS.md)
|
|
235
235
|
|
236
236
|
For existing codebases, packages are likely to have existing boundary violations.
|
237
237
|
|
238
|
-
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 [
|
238
|
+
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 [todo list](#understanding-the-package-todo-file) by executing:
|
239
239
|
|
240
|
-
bin/packwerk update-
|
240
|
+
bin/packwerk update-todo
|
241
241
|
|
242
|
-
Similar to `bin/packwerk check`, you may also run `bin/packwerk update-
|
242
|
+
Similar to `bin/packwerk check`, you may also run `bin/packwerk update-todo` on folders or packages:
|
243
243
|
|
244
|
-
bin/packwerk update-
|
244
|
+
bin/packwerk update-todo components/your_package
|
245
245
|
|
246
246
|

|
247
247
|
|
248
248
|
_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._
|
249
249
|
|
250
|
-
`bin/packwerk update-
|
250
|
+
`bin/packwerk update-todo` should only be run to record existing violations and to remove violations that have been worked off. Running `bin/packwerk update-todo` to resolve a violation should be the very last resort.
|
251
251
|
|
252
252
|
See: [TROUBLESHOOT.md - Troubleshooting violations](TROUBLESHOOT.md#Troubleshooting_violations)
|
253
253
|
|
254
254
|
|
255
|
-
### Understanding the
|
255
|
+
### Understanding the package todo file
|
256
256
|
|
257
|
-
The
|
257
|
+
The package TODO list is called `package_todo.yml` and can be found in the package folder. The list outlines the constant violations of the package, where the violation is located, and the file defining the violation.
|
258
258
|
|
259
|
-
The
|
259
|
+
The package TODO list should not be added to, but worked off over time.
|
260
260
|
|
261
261
|
```yaml
|
262
262
|
components/merchant:
|
@@ -267,11 +267,11 @@ components/merchant:
|
|
267
267
|
- components/merchant/app/public/merchant/generate_order.rb
|
268
268
|
```
|
269
269
|
|
270
|
-
Above is an example of a constant violation entry in `
|
270
|
+
Above is an example of a constant violation entry in `package_todo.yml`.
|
271
271
|
|
272
272
|
* `components/merchant` - package where the constant violation is found
|
273
273
|
* `::Checkouts::Core::CheckoutId` - violated constant in question
|
274
274
|
* `dependency` - type of violation, either dependency or privacy
|
275
275
|
* `components/merchant/app/public/merchant/generate_order.rb` - path to the file containing the violated constant
|
276
276
|
|
277
|
-
Violations exist within the package that makes a violating reference. This means privacy violations of your package can be found listed in `
|
277
|
+
Violations exist within the package that makes a violating reference. This means privacy violations of your package can be found listed in `package_todo.yml` files in the packages with the reference to a private constant.
|
data/lib/packwerk/cli.rb
CHANGED
@@ -55,7 +55,17 @@ module Packwerk
|
|
55
55
|
when "detect-stale-violations"
|
56
56
|
output_result(parse_run(args).detect_stale_violations)
|
57
57
|
when "update-deprecations"
|
58
|
-
|
58
|
+
warning = <<~WARNING.squish
|
59
|
+
DEPRECATION WARNING: `update-deprecations` is deprecated in favor of
|
60
|
+
`update-todo`.
|
61
|
+
WARNING
|
62
|
+
|
63
|
+
warn(warning)
|
64
|
+
output_result(parse_run(args).update_todo)
|
65
|
+
when "update-todo"
|
66
|
+
output_result(parse_run(args).update_todo)
|
67
|
+
when "update"
|
68
|
+
output_result(parse_run(args).update_todo)
|
59
69
|
when "validate"
|
60
70
|
validate(args)
|
61
71
|
when nil, "help"
|
@@ -26,7 +26,7 @@ module Packwerk
|
|
26
26
|
sig { override.params(offense_collection: Packwerk::OffenseCollection, fileset: T::Set[String]).returns(String) }
|
27
27
|
def show_stale_violations(offense_collection, fileset)
|
28
28
|
if offense_collection.stale_violations?(fileset)
|
29
|
-
"There were stale violations found, please run `packwerk update-
|
29
|
+
"There were stale violations found, please run `packwerk update-todo`"
|
30
30
|
else
|
31
31
|
"No stale violations detected"
|
32
32
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require "pathname"
|
5
|
+
|
4
6
|
module Packwerk
|
5
7
|
class OffenseCollection
|
6
8
|
extend T::Sig
|
@@ -9,12 +11,12 @@ module Packwerk
|
|
9
11
|
sig do
|
10
12
|
params(
|
11
13
|
root_path: String,
|
12
|
-
|
14
|
+
package_todo: T::Hash[Packwerk::Package, Packwerk::PackageTodo]
|
13
15
|
).void
|
14
16
|
end
|
15
|
-
def initialize(root_path,
|
17
|
+
def initialize(root_path, package_todo = {})
|
16
18
|
@root_path = root_path
|
17
|
-
@
|
19
|
+
@package_todo = T.let(package_todo, T::Hash[Packwerk::Package, Packwerk::PackageTodo])
|
18
20
|
@new_violations = T.let([], T::Array[Packwerk::ReferenceOffense])
|
19
21
|
@errors = T.let([], T::Array[Packwerk::Offense])
|
20
22
|
end
|
@@ -33,7 +35,7 @@ module Packwerk
|
|
33
35
|
return false unless offense.is_a?(ReferenceOffense)
|
34
36
|
|
35
37
|
reference = offense.reference
|
36
|
-
|
38
|
+
package_todo_for(reference.source_package).listed?(reference, violation_type: offense.violation_type)
|
37
39
|
end
|
38
40
|
|
39
41
|
sig do
|
@@ -44,23 +46,23 @@ module Packwerk
|
|
44
46
|
@errors << offense
|
45
47
|
return
|
46
48
|
end
|
47
|
-
|
48
|
-
unless
|
49
|
+
package_todo = package_todo_for(offense.reference.source_package)
|
50
|
+
unless package_todo.add_entries(offense.reference, offense.violation_type)
|
49
51
|
new_violations << offense
|
50
52
|
end
|
51
53
|
end
|
52
54
|
|
53
55
|
sig { params(for_files: T::Set[String]).returns(T::Boolean) }
|
54
56
|
def stale_violations?(for_files)
|
55
|
-
@
|
56
|
-
|
57
|
+
@package_todo.values.any? do |package_todo|
|
58
|
+
package_todo.stale_violations?(for_files)
|
57
59
|
end
|
58
60
|
end
|
59
61
|
|
60
62
|
sig { params(package_set: Packwerk::PackageSet).void }
|
61
|
-
def
|
62
|
-
|
63
|
-
|
63
|
+
def persist_package_todo_files(package_set)
|
64
|
+
dump_package_todo_files
|
65
|
+
cleanup_extra_package_todo_files(package_set)
|
64
66
|
end
|
65
67
|
|
66
68
|
sig { returns(T::Array[Packwerk::Offense]) }
|
@@ -68,36 +70,46 @@ module Packwerk
|
|
68
70
|
errors + new_violations
|
69
71
|
end
|
70
72
|
|
73
|
+
sig { void }
|
74
|
+
def dump_package_todo_files
|
75
|
+
@package_todo.each_value(&:dump)
|
76
|
+
end
|
77
|
+
|
71
78
|
private
|
72
79
|
|
73
80
|
sig { params(package_set: Packwerk::PackageSet).void }
|
74
|
-
def
|
75
|
-
packages_without_todos = (package_set.packages.values - @
|
81
|
+
def cleanup_extra_package_todo_files(package_set)
|
82
|
+
packages_without_todos = (package_set.packages.values - @package_todo.keys)
|
76
83
|
|
77
84
|
packages_without_todos.each do |package|
|
78
|
-
Packwerk::
|
85
|
+
Packwerk::PackageTodo.new(
|
79
86
|
package,
|
80
|
-
|
87
|
+
package_todo_file_for(package),
|
81
88
|
).delete_if_exists
|
82
89
|
end
|
83
90
|
end
|
84
91
|
|
85
|
-
sig {
|
86
|
-
def
|
87
|
-
@
|
88
|
-
end
|
89
|
-
|
90
|
-
sig { params(package: Packwerk::Package).returns(Packwerk::DeprecatedReferences) }
|
91
|
-
def deprecated_references_for(package)
|
92
|
-
@deprecated_references[package] ||= Packwerk::DeprecatedReferences.new(
|
92
|
+
sig { params(package: Packwerk::Package).returns(Packwerk::PackageTodo) }
|
93
|
+
def package_todo_for(package)
|
94
|
+
@package_todo[package] ||= Packwerk::PackageTodo.new(
|
93
95
|
package,
|
94
|
-
|
96
|
+
package_todo_file_for(package),
|
95
97
|
)
|
96
98
|
end
|
97
99
|
|
98
100
|
sig { params(package: Packwerk::Package).returns(String) }
|
99
|
-
def
|
100
|
-
|
101
|
+
def package_todo_file_for(package)
|
102
|
+
if Pathname.new(@root_path).join(package.name, "deprecated_references.yml").exist?
|
103
|
+
warning = <<~WARNING.squish
|
104
|
+
DEPRECATION WARNING: `deprecated_references.yml` files have been renamed to `package_todo.yml`.
|
105
|
+
Run `packwerk update-todo` to rename files automatically.
|
106
|
+
WARNING
|
107
|
+
|
108
|
+
warn(warning)
|
109
|
+
File.join(@root_path, package.name, "deprecated_references.yml")
|
110
|
+
else
|
111
|
+
File.join(@root_path, package.name, "package_todo.yml")
|
112
|
+
end
|
101
113
|
end
|
102
114
|
end
|
103
115
|
end
|
@@ -4,7 +4,7 @@
|
|
4
4
|
require "yaml"
|
5
5
|
|
6
6
|
module Packwerk
|
7
|
-
class
|
7
|
+
class PackageTodo
|
8
8
|
extend T::Sig
|
9
9
|
|
10
10
|
EntriesType = T.type_alias do
|
@@ -16,7 +16,7 @@ module Packwerk
|
|
16
16
|
@package = package
|
17
17
|
@filepath = filepath
|
18
18
|
@new_entries = T.let({}, EntriesType)
|
19
|
-
@
|
19
|
+
@todo_list = T.let(nil, T.nilable(EntriesType))
|
20
20
|
end
|
21
21
|
|
22
22
|
sig do
|
@@ -24,7 +24,7 @@ module Packwerk
|
|
24
24
|
.returns(T::Boolean)
|
25
25
|
end
|
26
26
|
def listed?(reference, violation_type:)
|
27
|
-
violated_constants_found =
|
27
|
+
violated_constants_found = todo_list.dig(reference.constant.package.name, reference.constant.name)
|
28
28
|
return false unless violated_constants_found
|
29
29
|
|
30
30
|
violated_constant_in_file = violated_constants_found.fetch("files", []).include?(reference.relative_path)
|
@@ -52,7 +52,7 @@ module Packwerk
|
|
52
52
|
def stale_violations?(for_files)
|
53
53
|
prepare_entries_for_dump
|
54
54
|
|
55
|
-
|
55
|
+
todo_list.any? do |package, package_violations|
|
56
56
|
package_violations_for_files = {}
|
57
57
|
package_violations.each do |constant_name, entries_for_constant|
|
58
58
|
entries_for_files = for_files & entries_for_constant["files"]
|
@@ -83,6 +83,8 @@ module Packwerk
|
|
83
83
|
|
84
84
|
sig { void }
|
85
85
|
def dump
|
86
|
+
delete_old_deprecated_references
|
87
|
+
|
86
88
|
if @new_entries.empty?
|
87
89
|
delete_if_exists
|
88
90
|
else
|
@@ -93,9 +95,11 @@ module Packwerk
|
|
93
95
|
#
|
94
96
|
# You can regenerate this file using the following command:
|
95
97
|
#
|
96
|
-
# bin/packwerk update-
|
98
|
+
# bin/packwerk update-todo #{@package.name}
|
97
99
|
MESSAGE
|
98
|
-
File.
|
100
|
+
package_todo_filepath = File.join(File.dirname(@filepath), "package_todo.yml")
|
101
|
+
|
102
|
+
File.open(package_todo_filepath, "w") do |f|
|
99
103
|
f.write(message)
|
100
104
|
f.write(@new_entries.to_yaml)
|
101
105
|
end
|
@@ -109,6 +113,12 @@ module Packwerk
|
|
109
113
|
|
110
114
|
private
|
111
115
|
|
116
|
+
sig { void }
|
117
|
+
def delete_old_deprecated_references
|
118
|
+
deprecated_references_filepath = File.join(File.dirname(@filepath), "deprecated_references.yml")
|
119
|
+
File.delete(deprecated_references_filepath) if File.exist?(deprecated_references_filepath)
|
120
|
+
end
|
121
|
+
|
112
122
|
sig { returns(EntriesType) }
|
113
123
|
def prepare_entries_for_dump
|
114
124
|
@new_entries.each do |package_name, package_violations|
|
@@ -123,8 +133,8 @@ module Packwerk
|
|
123
133
|
end
|
124
134
|
|
125
135
|
sig { returns(EntriesType) }
|
126
|
-
def
|
127
|
-
@
|
136
|
+
def todo_list
|
137
|
+
@todo_list ||= if File.exist?(@filepath)
|
128
138
|
load_yaml(@filepath)
|
129
139
|
else
|
130
140
|
{}
|
data/lib/packwerk/parse_run.rb
CHANGED
@@ -49,14 +49,14 @@ module Packwerk
|
|
49
49
|
end
|
50
50
|
|
51
51
|
sig { returns(Result) }
|
52
|
-
def
|
52
|
+
def update_todo
|
53
53
|
run_context = Packwerk::RunContext.from_configuration(@configuration)
|
54
54
|
offense_collection = find_offenses(run_context)
|
55
|
-
offense_collection.
|
55
|
+
offense_collection.persist_package_todo_files(run_context.package_set)
|
56
56
|
|
57
57
|
message = <<~EOS
|
58
58
|
#{@offenses_formatter.show_offenses(offense_collection.errors)}
|
59
|
-
✅ `
|
59
|
+
✅ `package_todo.yml` has been updated.
|
60
60
|
EOS
|
61
61
|
|
62
62
|
Result.new(message: message, status: offense_collection.errors.empty?)
|
data/lib/packwerk/version.rb
CHANGED
data/lib/packwerk.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: packwerk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-02-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -188,7 +188,6 @@ files:
|
|
188
188
|
- lib/packwerk/const_node_inspector.rb
|
189
189
|
- lib/packwerk/constant_discovery.rb
|
190
190
|
- lib/packwerk/constant_name_inspector.rb
|
191
|
-
- lib/packwerk/deprecated_references.rb
|
192
191
|
- lib/packwerk/file_processor.rb
|
193
192
|
- lib/packwerk/files_for_processing.rb
|
194
193
|
- lib/packwerk/formatters/offenses_formatter.rb
|
@@ -211,6 +210,7 @@ files:
|
|
211
210
|
- lib/packwerk/output_styles/plain.rb
|
212
211
|
- lib/packwerk/package.rb
|
213
212
|
- lib/packwerk/package_set.rb
|
213
|
+
- lib/packwerk/package_todo.rb
|
214
214
|
- lib/packwerk/parse_run.rb
|
215
215
|
- lib/packwerk/parsed_constant_definitions.rb
|
216
216
|
- lib/packwerk/parsers.rb
|