packwerk 1.0.2 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3b54c31e7c1902a03feb01304c85c9f2363b769fdb5f3c3cea7f38c67ff77af3
4
- data.tar.gz: efefa11bf554021227ce63a876c891d5466ee7bcd173e319deb086c8ec9732a5
3
+ metadata.gz: 91ec92f15d9d87fa8c54861afd424fe6149ef8f8e05f114b6ee04559fa6053fc
4
+ data.tar.gz: b83cc17ff9cd7d2d37db4456017d429b4a8f8e45766cdfa4551ace2e32c58183
5
5
  SHA512:
6
- metadata.gz: 5765e07827c5c5fc6d297f916e80c6cd2a6e09984ba91a1f2186ce1209d7965c7d906b6ff06a6b50fd37c299cdb9f82188d57273faf6e0fe7c654983ff8c0e8d
7
- data.tar.gz: b44c1ba5e1c5b61dd2d3e4755b5c215f245cb412a05f272513a6eba83e561097d6f6e624d65f5e8fa7021479616433f0e37ca9b818f00363efd11f24f8b6bca6
6
+ metadata.gz: 596f4f1a6b026e96ab6299e9ba7ceb63b7d709bd49c0629390f50e62e751174e4a92557243bef3a8f7f36aaf416e54fbf1fdb9f368fc2e478eb033e208358dc6
7
+ data.tar.gz: fdca4107315ea6140d7b92e5cd7b53216a73f65fac4c1c3147c798a1d407f75d3898b31517bec6bf2452e7ca0a3d1ad87599142250cf75684ccc9a48436bcd91
@@ -85,7 +85,7 @@ GIT
85
85
  PATH
86
86
  remote: .
87
87
  specs:
88
- packwerk (1.0.2)
88
+ packwerk (1.1.0)
89
89
  activesupport (>= 5.2)
90
90
  ast
91
91
  better_html
data/USAGE.md CHANGED
@@ -63,10 +63,31 @@ Packwerk reads from the `packwerk.yml` configuration file in the root directory.
63
63
  |----------------------|-------------------------------------------|--------------|
64
64
  | include | **/*.{rb,rake,erb} | list of patterns for folder paths to include |
65
65
  | exclude | {bin,node_modules,script,tmp,vendor}/**/* | list of patterns for folder paths to exclude |
66
- | package_paths | **/ | patterns to find package configuration files, see: Defining packages |
66
+ | package_paths | **/ | a single pattern or a list of patterns to find package configuration files, see: [Defining packages](#Defining-packages) |
67
67
  | load_paths | All application autoload paths | list of load paths |
68
68
  | custom_associations | N/A | list of custom associations, if any |
69
69
 
70
+ ### Using a custom ERB parser
71
+
72
+ You can specify a custom ERB parser if needed. For example, if you're using `<%graphql>` tags from https://github.com/github/graphql-client in your ERBs, you can use a custom parser subclass to comment them out so that Packwerk can parse the rest of the file:
73
+
74
+ ```ruby
75
+ class CustomParser < Packwerk::Parsers::Erb
76
+ def parse_buffer(buffer, file_path:)
77
+ preprocessed_source = buffer.source
78
+
79
+ # Comment out <%graphql ... %> tags. They won't contain any object
80
+ # references anyways.
81
+ preprocessed_source = preprocessed_source.gsub(/<%graphql/, "<%#")
82
+
83
+ preprocessed_buffer = Parser::Source::Buffer.new(file_path)
84
+ preprocessed_buffer.source = preprocessed_source
85
+ super(preprocessed_buffer, file_path: file_path)
86
+ end
87
+ end
88
+
89
+ Packwerk::Parsers::Factory.instance.erb_parser_class = CustomParser
90
+ ```
70
91
 
71
92
  ### Inflections
72
93
 
@@ -32,7 +32,7 @@ module Packwerk
32
32
  check_acyclic_graph,
33
33
  check_package_manifest_paths,
34
34
  check_valid_package_dependencies,
35
- check_root_package_exist,
35
+ check_root_package_exists,
36
36
  ]
37
37
 
38
38
  results.reject!(&:ok?)
@@ -207,7 +207,7 @@ module Packwerk
207
207
  end
208
208
 
209
209
  def check_acyclic_graph
210
- packages = Packwerk::PackageSet.load_all_from(".")
210
+ packages = Packwerk::PackageSet.load_all_from(@configuration.root_path)
211
211
 
212
212
  edges = packages.flat_map do |package|
213
213
  package.dependencies.map { |dependency| [package, packages.fetch(dependency)] }
@@ -297,7 +297,7 @@ module Packwerk
297
297
  end
298
298
  end
299
299
 
300
- def check_root_package_exist
300
+ def check_root_package_exists
301
301
  root_package_path = File.join(@configuration.root_path, "package.yml")
302
302
  all_packages_manifests = package_manifests(package_glob)
303
303
 
@@ -0,0 +1,47 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ require "packwerk/deprecated_references"
7
+ require "packwerk/reference"
8
+ require "packwerk/reference_lister"
9
+ require "packwerk/violation_type"
10
+
11
+ module Packwerk
12
+ class CacheDeprecatedReferences
13
+ extend T::Sig
14
+ extend T::Helpers
15
+ include ReferenceLister
16
+ abstract!
17
+
18
+ def initialize(root_path, deprecated_references = {})
19
+ @root_path = root_path
20
+ @deprecated_references = T.let(deprecated_references, T::Hash[String, Packwerk::DeprecatedReferences])
21
+ end
22
+
23
+ sig do
24
+ params(reference: Packwerk::Reference, violation_type: ViolationType)
25
+ .returns(T::Boolean)
26
+ .override
27
+ end
28
+ def listed?(reference, violation_type:)
29
+ deprecated_references = deprecated_references_for(reference.source_package)
30
+ deprecated_references.add_entries(reference, violation_type.serialize)
31
+ true
32
+ end
33
+
34
+ private
35
+
36
+ def deprecated_references_for(package)
37
+ @deprecated_references[package] ||= Packwerk::DeprecatedReferences.new(
38
+ package,
39
+ deprecated_references_file_for(package),
40
+ )
41
+ end
42
+
43
+ def deprecated_references_file_for(package)
44
+ File.join(@root_path, package.name, "deprecated_references.yml")
45
+ end
46
+ end
47
+ end
@@ -12,10 +12,13 @@ require "packwerk/output_styles"
12
12
  require "packwerk/run_context"
13
13
  require "packwerk/updating_deprecated_references"
14
14
  require "packwerk/checking_deprecated_references"
15
+ require "packwerk/commands/detect_stale_violations_command"
16
+ require "packwerk/commands/offense_progress_marker"
15
17
 
16
18
  module Packwerk
17
19
  class Cli
18
20
  extend T::Sig
21
+ include OffenseProgressMarker
19
22
 
20
23
  def initialize(run_context: nil, configuration: nil, out: $stdout, err_out: $stderr, style: OutputStyles::Plain)
21
24
  @out = out
@@ -45,6 +48,8 @@ module Packwerk
45
48
  generate_configs
46
49
  when "check"
47
50
  check(args)
51
+ when "detect-stale-violations"
52
+ detect_stale_violations(args)
48
53
  when "update"
49
54
  update(args)
50
55
  when "update-deprecations"
@@ -142,7 +147,9 @@ module Packwerk
142
147
  all_offenses = T.let([], T.untyped)
143
148
  execution_time = Benchmark.realtime do
144
149
  all_offenses = files.flat_map do |path|
145
- @run_context.process_file(file: path).tap { |offenses| mark_progress(offenses) }
150
+ @run_context.process_file(file: path).tap do |offenses|
151
+ mark_progress(offenses: offenses, progress_formatter: @progress_formatter)
152
+ end
146
153
  end
147
154
 
148
155
  updating_deprecated_references.dump_deprecated_references_files
@@ -165,7 +172,7 @@ module Packwerk
165
172
  execution_time = Benchmark.realtime do
166
173
  files.each do |path|
167
174
  @run_context.process_file(file: path).tap do |offenses|
168
- mark_progress(offenses)
175
+ mark_progress(offenses: offenses, progress_formatter: @progress_formatter)
169
176
  all_offenses.concat(offenses)
170
177
  end
171
178
  end
@@ -181,6 +188,18 @@ module Packwerk
181
188
  all_offenses.empty?
182
189
  end
183
190
 
191
+ def detect_stale_violations(paths)
192
+ detect_stale_violations = DetectStaleViolationsCommand.new(
193
+ files: fetch_files_to_process(paths),
194
+ configuration: @configuration,
195
+ progress_formatter: @progress_formatter
196
+ )
197
+ result = detect_stale_violations.run
198
+ @out.puts
199
+ @out.puts(result.message)
200
+ result.status
201
+ end
202
+
184
203
  def fetch_files_to_process(paths)
185
204
  files = FilesForProcessing.fetch(paths: paths, configuration: @configuration)
186
205
  abort("No files found or given. "\
@@ -188,14 +207,6 @@ module Packwerk
188
207
  files
189
208
  end
190
209
 
191
- def mark_progress(offenses)
192
- if offenses.empty?
193
- @progress_formatter.mark_as_inspected
194
- else
195
- @progress_formatter.mark_as_failed
196
- end
197
- end
198
-
199
210
  def validate(_paths)
200
211
  warn("`packwerk validate` should be run within the application. "\
201
212
  "Generate the bin script using `packwerk init` and"\
@@ -0,0 +1,63 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+ require "packwerk/cli"
4
+ require "sorbet-runtime"
5
+ require "benchmark"
6
+ require "packwerk/configuration"
7
+ require "packwerk/formatters/progress_formatter"
8
+ require "packwerk/run_context"
9
+ require "packwerk/detect_stale_deprecated_references"
10
+ require "packwerk/commands/offense_progress_marker"
11
+
12
+ module Packwerk
13
+ class DetectStaleViolationsCommand
14
+ extend T::Sig
15
+ include OffenseProgressMarker
16
+ Result = Struct.new(:message, :status)
17
+
18
+ def initialize(files:, configuration:, run_context: nil, progress_formatter: nil, reference_lister: nil)
19
+ @configuration = configuration
20
+ @run_context = run_context
21
+ @reference_lister = reference_lister
22
+ @progress_formatter = progress_formatter
23
+ @files = files
24
+ end
25
+
26
+ sig { returns(Result) }
27
+ def run
28
+ @progress_formatter.started(@files)
29
+
30
+ all_offenses = T.let([], T.untyped)
31
+ execution_time = Benchmark.realtime do
32
+ all_offenses = @files.flat_map do |path|
33
+ run_context.process_file(file: path).tap do |offenses|
34
+ mark_progress(offenses: offenses, progress_formatter: @progress_formatter)
35
+ end
36
+ end
37
+ end
38
+
39
+ @progress_formatter.finished(execution_time)
40
+ calculate_result
41
+ end
42
+
43
+ private
44
+
45
+ def run_context
46
+ @run_context ||= Packwerk::RunContext.from_configuration(@configuration, reference_lister: reference_lister)
47
+ end
48
+
49
+ def reference_lister
50
+ @reference_lister ||= ::Packwerk::DetectStaleDeprecatedReferences.new(@configuration.root_path)
51
+ end
52
+
53
+ sig { returns Result }
54
+ def calculate_result
55
+ result_status = !reference_lister.stale_violations?
56
+ message = "There were stale violations found, please run `packwerk update`"
57
+ if result_status
58
+ message = "No stale violations detected"
59
+ end
60
+ Result.new(message, result_status)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+ # typed: strict
3
+ require "sorbet-runtime"
4
+ require "packwerk/formatters/progress_formatter"
5
+
6
+ module Packwerk
7
+ module OffenseProgressMarker
8
+ extend T::Sig
9
+
10
+ sig do
11
+ params(
12
+ offenses: T::Array[T.nilable(::Packwerk::Offense)],
13
+ progress_formatter: ::Packwerk::Formatters::ProgressFormatter
14
+ ).void
15
+ end
16
+ def mark_progress(offenses:, progress_formatter:)
17
+ if offenses.empty?
18
+ progress_formatter.mark_as_inspected
19
+ else
20
+ progress_formatter.mark_as_failed
21
+ end
22
+ end
23
+ end
24
+ end
@@ -3,6 +3,7 @@
3
3
 
4
4
  require "sorbet-runtime"
5
5
  require "yaml"
6
+ require "sorbet-runtime"
6
7
 
7
8
  require "packwerk/reference"
8
9
  require "packwerk/reference_lister"
@@ -47,6 +48,24 @@ module Packwerk
47
48
  @new_entries[reference.constant.package.name] = package_violations
48
49
  end
49
50
 
51
+ sig { returns(T::Boolean) }
52
+ def stale_violations?
53
+ prepare_entries_for_dump
54
+ deprecated_references.any? do |package, package_violations|
55
+ package_violations.any? do |constant_name, entries_for_file|
56
+ new_entries_violation_types = @new_entries.dig(package, constant_name, "violations")
57
+ return true if new_entries_violation_types.nil?
58
+ if entries_for_file["violations"].all? { |type| new_entries_violation_types.include?(type) }
59
+ stale_violations =
60
+ entries_for_file["files"] - Array(@new_entries.dig(package, constant_name, "files"))
61
+ stale_violations.present?
62
+ else
63
+ return true
64
+ end
65
+ end
66
+ end
67
+ end
68
+
50
69
  def dump
51
70
  if @new_entries.empty?
52
71
  File.delete(@filepath) if File.exist?(@filepath)
@@ -0,0 +1,14 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "packwerk/cache_deprecated_references"
5
+
6
+ module Packwerk
7
+ class DetectStaleDeprecatedReferences < CacheDeprecatedReferences
8
+ extend T::Sig
9
+ sig { returns(T::Boolean) }
10
+ def stale_violations?
11
+ @deprecated_references.values.any?(&:stale_violations?)
12
+ end
13
+ end
14
+ end
@@ -28,8 +28,12 @@ module Packwerk
28
28
  def package_paths(root_path, package_pathspec)
29
29
  bundle_path_match = Bundler.bundle_path.join("**").to_s
30
30
 
31
- Dir.glob(File.join(root_path, package_pathspec, PACKAGE_CONFIG_FILENAME))
32
- .map { |path| Pathname.new(path) }
31
+ glob_patterns = Array(package_pathspec).map do |pathspec|
32
+ File.join(root_path, pathspec, PACKAGE_CONFIG_FILENAME)
33
+ end
34
+
35
+ Dir.glob(glob_patterns)
36
+ .map { |path| Pathname.new(path).cleanpath }
33
37
  .reject { |path| path.realpath.fnmatch(bundle_path_match) }
34
38
  end
35
39
 
@@ -19,6 +19,10 @@ module Packwerk
19
19
  def call(io:, file_path: "<unknown>")
20
20
  buffer = Parser::Source::Buffer.new(file_path)
21
21
  buffer.source = io.read
22
+ parse_buffer(buffer, file_path: file_path)
23
+ end
24
+
25
+ def parse_buffer(buffer, file_path:)
22
26
  parser = @parser_class.new(buffer, template_language: :html)
23
27
  to_ruby_ast(parser.ast, file_path)
24
28
  rescue EncodingError => e
@@ -26,9 +26,18 @@ module Packwerk
26
26
  when RUBY_REGEX
27
27
  @ruby_parser ||= Ruby.new
28
28
  when ERB_REGEX
29
- @erb_parser ||= Erb.new
29
+ @erb_parser ||= erb_parser_class.new
30
30
  end
31
31
  end
32
+
33
+ def erb_parser_class
34
+ @erb_parser_class || Erb
35
+ end
36
+
37
+ def erb_parser_class=(klass)
38
+ @erb_parser_class = klass
39
+ @erb_parser = nil
40
+ end
32
41
  end
33
42
  end
34
43
  end
@@ -25,9 +25,10 @@ module Packwerk
25
25
  :inflector,
26
26
  :custom_associations,
27
27
  :checker_classes,
28
- :reference_lister,
29
28
  )
30
29
 
30
+ attr_accessor :reference_lister
31
+
31
32
  DEFAULT_CHECKERS = [
32
33
  ::Packwerk::DependencyChecker,
33
34
  ::Packwerk::PrivacyChecker,
@@ -1,51 +1,14 @@
1
1
  # typed: true
2
2
  # frozen_string_literal: true
3
3
 
4
- require "sorbet-runtime"
5
-
6
- require "packwerk/deprecated_references"
7
- require "packwerk/reference"
8
- require "packwerk/reference_lister"
9
- require "packwerk/violation_type"
4
+ require "packwerk/cache_deprecated_references"
10
5
 
11
6
  module Packwerk
12
- class UpdatingDeprecatedReferences
13
- extend T::Sig
14
- include ReferenceLister
15
-
16
- def initialize(root_path, deprecated_references = {})
17
- @root_path = root_path
18
- @deprecated_references = deprecated_references
19
- end
20
-
21
- sig do
22
- params(reference: Packwerk::Reference, violation_type: ViolationType)
23
- .returns(T::Boolean)
24
- .override
25
- end
26
- def listed?(reference, violation_type:)
27
- deprecated_references = deprecated_references_for(reference.source_package)
28
- deprecated_references.add_entries(reference, violation_type.serialize)
29
- true
30
- end
31
-
7
+ class UpdatingDeprecatedReferences < CacheDeprecatedReferences
32
8
  def dump_deprecated_references_files
33
9
  @deprecated_references.each do |_, deprecated_references_file|
34
10
  deprecated_references_file.dump
35
11
  end
36
12
  end
37
-
38
- private
39
-
40
- def deprecated_references_for(package)
41
- @deprecated_references[package] ||= Packwerk::DeprecatedReferences.new(
42
- package,
43
- deprecated_references_file_for(package),
44
- )
45
- end
46
-
47
- def deprecated_references_file_for(package)
48
- File.join(@root_path, package.name, "deprecated_references.yml")
49
- end
50
13
  end
51
14
  end
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Packwerk
5
- VERSION = "1.0.2"
5
+ VERSION = "1.1.0"
6
6
  end
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: 1.0.2
4
+ version: 1.1.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: 2020-11-16 00:00:00.000000000 Z
11
+ date: 2020-11-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -186,15 +186,19 @@ files:
186
186
  - lib/packwerk/application_load_paths.rb
187
187
  - lib/packwerk/application_validator.rb
188
188
  - lib/packwerk/association_inspector.rb
189
+ - lib/packwerk/cache_deprecated_references.rb
189
190
  - lib/packwerk/checker.rb
190
191
  - lib/packwerk/checking_deprecated_references.rb
191
192
  - lib/packwerk/cli.rb
193
+ - lib/packwerk/commands/detect_stale_violations_command.rb
194
+ - lib/packwerk/commands/offense_progress_marker.rb
192
195
  - lib/packwerk/configuration.rb
193
196
  - lib/packwerk/const_node_inspector.rb
194
197
  - lib/packwerk/constant_discovery.rb
195
198
  - lib/packwerk/constant_name_inspector.rb
196
199
  - lib/packwerk/dependency_checker.rb
197
200
  - lib/packwerk/deprecated_references.rb
201
+ - lib/packwerk/detect_stale_deprecated_references.rb
198
202
  - lib/packwerk/file_processor.rb
199
203
  - lib/packwerk/files_for_processing.rb
200
204
  - lib/packwerk/formatters/progress_formatter.rb