packwerk 1.1.3 → 1.2.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 +6 -5
- data/USAGE.md +17 -16
- data/lib/packwerk.rb +72 -36
- data/lib/packwerk/application_validator.rb +0 -5
- data/lib/packwerk/association_inspector.rb +0 -3
- data/lib/packwerk/checker.rb +2 -8
- data/lib/packwerk/cli.rb +22 -77
- data/lib/packwerk/configuration.rb +5 -0
- data/lib/packwerk/const_node_inspector.rb +0 -2
- data/lib/packwerk/constant_discovery.rb +2 -0
- data/lib/packwerk/constant_name_inspector.rb +0 -1
- data/lib/packwerk/dependency_checker.rb +2 -15
- data/lib/packwerk/deprecated_references.rb +3 -9
- data/lib/packwerk/file_processor.rb +0 -4
- data/lib/packwerk/formatters/offenses_formatter.rb +3 -8
- data/lib/packwerk/formatters/progress_formatter.rb +5 -4
- data/lib/packwerk/generators/configuration_file.rb +0 -1
- data/lib/packwerk/inflector.rb +0 -2
- data/lib/packwerk/node.rb +1 -0
- data/lib/packwerk/node_processor.rb +14 -32
- data/lib/packwerk/node_processor_factory.rb +0 -5
- data/lib/packwerk/node_visitor.rb +1 -4
- data/lib/packwerk/offense.rb +0 -4
- data/lib/packwerk/offense_collection.rb +84 -0
- data/lib/packwerk/offenses_formatter.rb +15 -0
- data/lib/packwerk/package.rb +8 -0
- data/lib/packwerk/package_set.rb +0 -2
- data/lib/packwerk/parse_run.rb +104 -0
- data/lib/packwerk/parsed_constant_definitions.rb +0 -2
- data/lib/packwerk/parsers.rb +0 -2
- data/lib/packwerk/parsers/erb.rb +0 -2
- data/lib/packwerk/parsers/factory.rb +0 -2
- data/lib/packwerk/privacy_checker.rb +2 -15
- data/lib/packwerk/reference_extractor.rb +0 -8
- data/lib/packwerk/reference_offense.rb +49 -0
- data/lib/packwerk/result.rb +9 -0
- data/lib/packwerk/run_context.rb +4 -21
- data/lib/packwerk/sanity_checker.rb +0 -2
- data/lib/packwerk/version.rb +1 -1
- data/lib/packwerk/violation_type.rb +0 -2
- data/packwerk.gemspec +1 -0
- data/service.yml +1 -4
- data/sorbet/rbi/gems/parallel@1.20.1.rbi +111 -2
- data/sorbet/tapioca/require.rb +1 -0
- metadata +22 -12
- data/lib/packwerk/cache_deprecated_references.rb +0 -55
- data/lib/packwerk/checking_deprecated_references.rb +0 -43
- data/lib/packwerk/commands/detect_stale_violations_command.rb +0 -60
- data/lib/packwerk/commands/offense_progress_marker.rb +0 -24
- data/lib/packwerk/commands/result.rb +0 -13
- data/lib/packwerk/commands/update_deprecations_command.rb +0 -81
- data/lib/packwerk/detect_stale_deprecated_references.rb +0 -14
- data/lib/packwerk/reference_lister.rb +0 -23
- data/lib/packwerk/updating_deprecated_references.rb +0 -14
@@ -0,0 +1,104 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "benchmark"
|
5
|
+
require "parallel"
|
6
|
+
|
7
|
+
module Packwerk
|
8
|
+
class ParseRun
|
9
|
+
extend T::Sig
|
10
|
+
|
11
|
+
def initialize(
|
12
|
+
files:,
|
13
|
+
configuration:,
|
14
|
+
progress_formatter: Formatters::ProgressFormatter.new(StringIO.new),
|
15
|
+
offenses_formatter: Formatters::OffensesFormatter.new
|
16
|
+
)
|
17
|
+
@configuration = configuration
|
18
|
+
@progress_formatter = progress_formatter
|
19
|
+
@offenses_formatter = offenses_formatter
|
20
|
+
@files = files
|
21
|
+
end
|
22
|
+
|
23
|
+
def detect_stale_violations
|
24
|
+
offense_collection = find_offenses
|
25
|
+
|
26
|
+
result_status = !offense_collection.stale_violations?
|
27
|
+
message = if result_status
|
28
|
+
"No stale violations detected"
|
29
|
+
else
|
30
|
+
"There were stale violations found, please run `packwerk update-deprecations`"
|
31
|
+
end
|
32
|
+
|
33
|
+
Result.new(message: message, status: result_status)
|
34
|
+
end
|
35
|
+
|
36
|
+
def update_deprecations
|
37
|
+
offense_collection = find_offenses
|
38
|
+
offense_collection.dump_deprecated_references_files
|
39
|
+
|
40
|
+
message = <<~EOS
|
41
|
+
#{@offenses_formatter.show_offenses(offense_collection.errors)}
|
42
|
+
✅ `deprecated_references.yml` has been updated.
|
43
|
+
EOS
|
44
|
+
|
45
|
+
Result.new(message: message, status: offense_collection.errors.empty?)
|
46
|
+
end
|
47
|
+
|
48
|
+
def check
|
49
|
+
offense_collection = find_offenses(show_errors: true)
|
50
|
+
message = @offenses_formatter.show_offenses(offense_collection.outstanding_offenses)
|
51
|
+
Result.new(message: message, status: offense_collection.outstanding_offenses.empty?)
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def find_offenses(show_errors: false)
|
57
|
+
offense_collection = OffenseCollection.new(@configuration.root_path)
|
58
|
+
@progress_formatter.started(@files)
|
59
|
+
|
60
|
+
run_context = Packwerk::RunContext.from_configuration(@configuration)
|
61
|
+
all_offenses = T.let([], T.untyped)
|
62
|
+
|
63
|
+
process_file = -> (path) do
|
64
|
+
run_context.process_file(file: path).tap do |offenses|
|
65
|
+
failed = show_errors && offenses.any? { |offense| !offense_collection.listed?(offense) }
|
66
|
+
update_progress(failed: failed)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
execution_time = Benchmark.realtime do
|
71
|
+
all_offenses = if @configuration.parallel?
|
72
|
+
Parallel.flat_map(@files, &process_file)
|
73
|
+
else
|
74
|
+
serial_find_offenses(&process_file)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
@progress_formatter.finished(execution_time)
|
79
|
+
|
80
|
+
all_offenses.each { |offense| offense_collection.add_offense(offense) }
|
81
|
+
offense_collection
|
82
|
+
end
|
83
|
+
|
84
|
+
def serial_find_offenses
|
85
|
+
all_offenses = T.let([], T.untyped)
|
86
|
+
@files.each do |path|
|
87
|
+
offenses = yield path
|
88
|
+
all_offenses.concat(offenses)
|
89
|
+
end
|
90
|
+
all_offenses
|
91
|
+
rescue Interrupt
|
92
|
+
@progress_formatter.interrupted
|
93
|
+
all_offenses
|
94
|
+
end
|
95
|
+
|
96
|
+
def update_progress(failed: false)
|
97
|
+
if failed
|
98
|
+
@progress_formatter.mark_as_failed
|
99
|
+
else
|
100
|
+
@progress_formatter.mark_as_inspected
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
data/lib/packwerk/parsers.rb
CHANGED
data/lib/packwerk/parsers/erb.rb
CHANGED
@@ -1,9 +1,6 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require "packwerk/violation_type"
|
5
|
-
require "packwerk/checker"
|
6
|
-
|
7
4
|
module Packwerk
|
8
5
|
class PrivacyChecker
|
9
6
|
extend T::Sig
|
@@ -16,10 +13,10 @@ module Packwerk
|
|
16
13
|
|
17
14
|
sig do
|
18
15
|
override
|
19
|
-
.params(reference: Packwerk::Reference
|
16
|
+
.params(reference: Packwerk::Reference)
|
20
17
|
.returns(T::Boolean)
|
21
18
|
end
|
22
|
-
def invalid_reference?(reference
|
19
|
+
def invalid_reference?(reference)
|
23
20
|
return false if reference.constant.public?
|
24
21
|
|
25
22
|
privacy_option = reference.constant.package.enforce_privacy
|
@@ -28,19 +25,9 @@ module Packwerk
|
|
28
25
|
return false unless privacy_option == true ||
|
29
26
|
explicitly_private_constant?(reference.constant, explicitly_private_constants: privacy_option)
|
30
27
|
|
31
|
-
return false if reference_lister.listed?(reference, violation_type: violation_type)
|
32
|
-
|
33
28
|
true
|
34
29
|
end
|
35
30
|
|
36
|
-
sig { override.params(reference: Packwerk::Reference).returns(String) }
|
37
|
-
def message_for(reference)
|
38
|
-
source_desc = reference.source_package ? "'#{reference.source_package}'" : "here"
|
39
|
-
"Privacy violation: '#{reference.constant.name}' is private to '#{reference.constant.package}' but " \
|
40
|
-
"referenced from #{source_desc}.\n" \
|
41
|
-
"Is there a public entrypoint in '#{reference.constant.package.public_path}' that you can use instead?"
|
42
|
-
end
|
43
|
-
|
44
31
|
private
|
45
32
|
|
46
33
|
sig do
|
@@ -1,14 +1,6 @@
|
|
1
1
|
# typed: true
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require "sorbet-runtime"
|
5
|
-
|
6
|
-
require "packwerk/constant_discovery"
|
7
|
-
require "packwerk/constant_name_inspector"
|
8
|
-
require "packwerk/node"
|
9
|
-
require "packwerk/parsed_constant_definitions"
|
10
|
-
require "packwerk/reference"
|
11
|
-
|
12
4
|
module Packwerk
|
13
5
|
# extracts a possible constant reference from a given AST node
|
14
6
|
class ReferenceExtractor
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Packwerk
|
5
|
+
class ReferenceOffense < Offense
|
6
|
+
extend T::Sig
|
7
|
+
extend T::Helpers
|
8
|
+
|
9
|
+
attr_reader :reference, :violation_type
|
10
|
+
|
11
|
+
sig do
|
12
|
+
params(
|
13
|
+
reference: Packwerk::Reference,
|
14
|
+
violation_type: Packwerk::ViolationType,
|
15
|
+
location: T.nilable(Node::Location)
|
16
|
+
)
|
17
|
+
.void
|
18
|
+
end
|
19
|
+
def initialize(reference:, violation_type:, location: nil)
|
20
|
+
super(file: reference.relative_path, message: build_message(reference, violation_type), location: location)
|
21
|
+
@reference = reference
|
22
|
+
@violation_type = violation_type
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def build_message(reference, violation_type)
|
28
|
+
violation_message = case violation_type
|
29
|
+
when ViolationType::Privacy
|
30
|
+
source_desc = reference.source_package ? "'#{reference.source_package}'" : "here"
|
31
|
+
"Privacy violation: '#{reference.constant.name}' is private to '#{reference.constant.package}' but " \
|
32
|
+
"referenced from #{source_desc}.\n" \
|
33
|
+
"Is there a public entrypoint in '#{reference.constant.package.public_path}' that you can use instead?"
|
34
|
+
when ViolationType::Dependency
|
35
|
+
"Dependency violation: #{reference.constant.name} belongs to '#{reference.constant.package}', but " \
|
36
|
+
"'#{reference.source_package}' does not specify a dependency on " \
|
37
|
+
"'#{reference.constant.package}'.\n" \
|
38
|
+
"Are we missing an abstraction?\n" \
|
39
|
+
"Is the code making the reference, and the referenced constant, in the right packages?\n"
|
40
|
+
end
|
41
|
+
|
42
|
+
<<~EOS
|
43
|
+
#{violation_message}
|
44
|
+
Inference details: this is a reference to #{reference.constant.name} which seems to be defined in #{reference.constant.location}.
|
45
|
+
To receive help interpreting or resolving this error message, see: https://github.com/Shopify/packwerk/blob/main/TROUBLESHOOT.md#Troubleshooting-violations
|
46
|
+
EOS
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/packwerk/run_context.rb
CHANGED
@@ -3,17 +3,6 @@
|
|
3
3
|
|
4
4
|
require "constant_resolver"
|
5
5
|
|
6
|
-
require "packwerk/association_inspector"
|
7
|
-
require "packwerk/constant_discovery"
|
8
|
-
require "packwerk/const_node_inspector"
|
9
|
-
require "packwerk/dependency_checker"
|
10
|
-
require "packwerk/file_processor"
|
11
|
-
require "packwerk/inflector"
|
12
|
-
require "packwerk/package_set"
|
13
|
-
require "packwerk/privacy_checker"
|
14
|
-
require "packwerk/reference_extractor"
|
15
|
-
require "packwerk/node_processor_factory"
|
16
|
-
|
17
6
|
module Packwerk
|
18
7
|
class RunContext
|
19
8
|
extend T::Sig
|
@@ -27,23 +16,20 @@ module Packwerk
|
|
27
16
|
:checker_classes,
|
28
17
|
)
|
29
18
|
|
30
|
-
attr_accessor :reference_lister
|
31
|
-
|
32
19
|
DEFAULT_CHECKERS = [
|
33
20
|
::Packwerk::DependencyChecker,
|
34
21
|
::Packwerk::PrivacyChecker,
|
35
22
|
]
|
36
23
|
|
37
24
|
class << self
|
38
|
-
def from_configuration(configuration
|
25
|
+
def from_configuration(configuration)
|
39
26
|
inflector = ::Packwerk::Inflector.from_file(configuration.inflections_file)
|
40
27
|
new(
|
41
28
|
root_path: configuration.root_path,
|
42
29
|
load_paths: configuration.load_paths,
|
43
30
|
package_paths: configuration.package_paths,
|
44
31
|
inflector: inflector,
|
45
|
-
custom_associations: configuration.custom_associations
|
46
|
-
reference_lister: reference_lister,
|
32
|
+
custom_associations: configuration.custom_associations
|
47
33
|
)
|
48
34
|
end
|
49
35
|
end
|
@@ -54,8 +40,7 @@ module Packwerk
|
|
54
40
|
package_paths: nil,
|
55
41
|
inflector: nil,
|
56
42
|
custom_associations: [],
|
57
|
-
checker_classes: DEFAULT_CHECKERS
|
58
|
-
reference_lister:
|
43
|
+
checker_classes: DEFAULT_CHECKERS
|
59
44
|
)
|
60
45
|
@root_path = root_path
|
61
46
|
@load_paths = load_paths
|
@@ -63,7 +48,6 @@ module Packwerk
|
|
63
48
|
@inflector = inflector
|
64
49
|
@custom_associations = custom_associations
|
65
50
|
@checker_classes = checker_classes
|
66
|
-
@reference_lister = reference_lister
|
67
51
|
end
|
68
52
|
|
69
53
|
sig { params(file: String).returns(T::Array[T.nilable(::Packwerk::Offense)]) }
|
@@ -84,8 +68,7 @@ module Packwerk
|
|
84
68
|
context_provider: context_provider,
|
85
69
|
checkers: checkers,
|
86
70
|
root_path: root_path,
|
87
|
-
constant_name_inspectors: constant_name_inspectors
|
88
|
-
reference_lister: reference_lister
|
71
|
+
constant_name_inspectors: constant_name_inspectors
|
89
72
|
)
|
90
73
|
end
|
91
74
|
|
@@ -1,8 +1,6 @@
|
|
1
1
|
# typed: false
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require "packwerk/application_validator"
|
5
|
-
|
6
4
|
module Packwerk
|
7
5
|
# To do: This alias and file should be removed as it is deprecated
|
8
6
|
warn("DEPRECATION WARNING: Packwerk::SanityChecker is deprecated, use Packwerk::ApplicationValidator instead.")
|
data/lib/packwerk/version.rb
CHANGED
data/packwerk.gemspec
CHANGED
data/service.yml
CHANGED
@@ -4,5 +4,114 @@
|
|
4
4
|
|
5
5
|
# typed: true
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
module Parallel
|
8
|
+
extend(::Parallel::ProcessorCount)
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def all?(*args, &block); end
|
12
|
+
def any?(*args, &block); end
|
13
|
+
def each(array, options = T.unsafe(nil), &block); end
|
14
|
+
def each_with_index(array, options = T.unsafe(nil), &block); end
|
15
|
+
def flat_map(*args, &block); end
|
16
|
+
def in_processes(options = T.unsafe(nil), &block); end
|
17
|
+
def in_threads(options = T.unsafe(nil)); end
|
18
|
+
def map(source, options = T.unsafe(nil), &block); end
|
19
|
+
def map_with_index(array, options = T.unsafe(nil), &block); end
|
20
|
+
def worker_number; end
|
21
|
+
def worker_number=(worker_num); end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def add_progress_bar!(job_factory, options); end
|
26
|
+
def call_with_index(item, index, options, &block); end
|
27
|
+
def create_workers(job_factory, options, &block); end
|
28
|
+
def extract_count_from_options(options); end
|
29
|
+
def process_incoming_jobs(read, write, job_factory, options, &block); end
|
30
|
+
def replace_worker(job_factory, workers, i, options, blk); end
|
31
|
+
def with_instrumentation(item, index, options); end
|
32
|
+
def work_direct(job_factory, options, &block); end
|
33
|
+
def work_in_processes(job_factory, options, &blk); end
|
34
|
+
def work_in_threads(job_factory, options, &block); end
|
35
|
+
def worker(job_factory, options, &block); end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class Parallel::Break < ::StandardError
|
40
|
+
def initialize(value = T.unsafe(nil)); end
|
41
|
+
|
42
|
+
def value; end
|
43
|
+
end
|
44
|
+
|
45
|
+
class Parallel::DeadWorker < ::StandardError
|
46
|
+
end
|
47
|
+
|
48
|
+
class Parallel::ExceptionWrapper
|
49
|
+
def initialize(exception); end
|
50
|
+
|
51
|
+
def exception; end
|
52
|
+
end
|
53
|
+
|
54
|
+
class Parallel::JobFactory
|
55
|
+
def initialize(source, mutex); end
|
56
|
+
|
57
|
+
def next; end
|
58
|
+
def pack(item, index); end
|
59
|
+
def size; end
|
60
|
+
def unpack(data); end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def producer?; end
|
65
|
+
def queue_wrapper(array); end
|
66
|
+
end
|
67
|
+
|
68
|
+
class Parallel::Kill < ::Parallel::Break
|
69
|
+
end
|
70
|
+
|
71
|
+
module Parallel::ProcessorCount
|
72
|
+
def physical_processor_count; end
|
73
|
+
def processor_count; end
|
74
|
+
end
|
75
|
+
|
76
|
+
Parallel::Stop = T.let(T.unsafe(nil), Object)
|
77
|
+
|
78
|
+
class Parallel::UndumpableException < ::StandardError
|
79
|
+
def initialize(original); end
|
80
|
+
|
81
|
+
def backtrace; end
|
82
|
+
end
|
83
|
+
|
84
|
+
class Parallel::UserInterruptHandler
|
85
|
+
class << self
|
86
|
+
def kill(thing); end
|
87
|
+
def kill_on_ctrl_c(pids, options); end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def restore_interrupt(old, signal); end
|
92
|
+
def trap_interrupt(signal); end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
Parallel::UserInterruptHandler::INTERRUPT_SIGNAL = T.let(T.unsafe(nil), Symbol)
|
97
|
+
|
98
|
+
Parallel::VERSION = T.let(T.unsafe(nil), String)
|
99
|
+
|
100
|
+
Parallel::Version = T.let(T.unsafe(nil), String)
|
101
|
+
|
102
|
+
class Parallel::Worker
|
103
|
+
def initialize(read, write, pid); end
|
104
|
+
|
105
|
+
def close_pipes; end
|
106
|
+
def pid; end
|
107
|
+
def read; end
|
108
|
+
def stop; end
|
109
|
+
def thread; end
|
110
|
+
def thread=(_arg0); end
|
111
|
+
def work(data); end
|
112
|
+
def write; end
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
def wait; end
|
117
|
+
end
|