danger-packwerk 0.1.0 → 0.1.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cf899d973a7ead8ff19dc6f73f30f63c23bdc7fffc3f043766d8819ffbc088aa
4
- data.tar.gz: 318d88c5243e9e510abef74590fb907ba97dd10afd563cd9fcebb1eea9161f40
3
+ metadata.gz: 8789235e049c26367bdf6a909d22646d76b44adb350fb35e777d2be40ec0e14a
4
+ data.tar.gz: 1bd02af0c72f377ad0a7982681fe9bfdb8bc6e4550fdb6b756ee8e9840cba27b
5
5
  SHA512:
6
- metadata.gz: 33fb31226007f52ddf1248e0d764816014f2371a5e48e1ba981ce6947c6f64eb6b3368e2ac628ea5912c5ec565481f3887e5fd53618ac5227816d27009034769
7
- data.tar.gz: 8d391aea94c4045f26eb5232a177a35ebe597bf62239ab8e1050458b8db89739c2538a7f68cc5791d2b956f01986a1fb9ea23d4e5c72a53dc25e4aa965bbe013
6
+ metadata.gz: 3839e46d7a89a4dbb7dcee0957be8d891a9e151d29485f06e8a53ab21a92af7a7a1a2d4c09da48030e6c95040956c6e4f92d380a663a57c02b48085fa189ff62
7
+ data.tar.gz: ddcb0fec757eafe11d18b5c0146202fb3ea6a655087bf3c11534a3f556f85ccf76a945eca3a86683ba37197f9ca22a8fc1ad92049bdd0b7cfd4a80ff73125bdb
@@ -38,38 +38,66 @@ module DangerPackwerk
38
38
  const :file, String
39
39
  const :to_package_name, String
40
40
  const :type, String
41
- const :location, Location
41
+ const :file_location, Location
42
42
 
43
43
  sig { params(deprecated_references_yml: String).returns(T::Array[BasicReferenceOffense]) }
44
44
  def self.from(deprecated_references_yml)
45
45
  deprecated_references_yml_pathname = Pathname.new(deprecated_references_yml)
46
46
  violations = Private::DeprecatedReferences.from(deprecated_references_yml_pathname).violations
47
47
 
48
+ # See the larger comment below for more information on why we need this information.
49
+ # This is a small optimization that lets us find the location of referenced files within
50
+ # a `deprecated_references.yml` file. Getting this now allows us to avoid reading through the file
51
+ # once for every referenced file in the inner loop below.
52
+ file_reference_to_line_number_index = T.let({}, T::Hash[String, T::Array[Integer]])
53
+ all_referenced_files = violations.flat_map(&:files).uniq
54
+ deprecated_references_yml_pathname.readlines.each_with_index do |line, index|
55
+ # We can use `find` here to exit early since each line will include one path that is unique to that file.
56
+ # Paths should not be substrings of each other, since they are all paths relative to the root.
57
+ file_on_line = all_referenced_files.find { |file| line.include?(file) }
58
+ # Not all lines contain a reference to a file
59
+ if file_on_line
60
+ file_reference_to_line_number_index[file_on_line] ||= []
61
+ file_reference_to_line_number_index.fetch(file_on_line) << index
62
+ end
63
+ end
64
+
48
65
  violations.flat_map do |violation|
49
- # We choose the location of the violation as the reference to the constant within the `deprecated_references.yml` file.
50
- # We simply find the reference to that constant, because we know that each constant reference can occur only once per `deprecated_references.yml` file
66
+ #
67
+ # We identify two locations associated with this violation.
68
+ # First, we find the reference to the constant within the `deprecated_references.yml` file.
69
+ # We know that each constant reference can occur only once per `deprecated_references.yml` file
51
70
  # The reason for this is that we know that only one file in the codebase can define a constant, and packwerk's constant_resolver will actually
52
71
  # raise if this assumption is not true: https://github.com/Shopify/constant_resolver/blob/e78af0c8d5782b06292c068cfe4176e016c51b34/lib/constant_resolver.rb#L74
53
72
  #
73
+ # Second, we find the reference to the specific file that references the constant within the `deprecated_references.yml` file.
74
+ # This can occur multiple times per `deprecated_references.yml` file, but we know that the very first reference to the file after the class name key will be the one we care
75
+ # about, so we take the first instance that occurs after the class is listed.
76
+ #
54
77
  # Note though that since one constant reference in a `deprecated_referencs.yml` can be both a privacy and a dependency violation AND it can occur in many files,
55
78
  # we need to group them. That is -- if `MyPrivateConstant` is both a dependency and a privacy violation AND it occurs in 10 files, that would represent 20 violations.
56
79
  # Therefore we will group all of those 20 into one message to the user rather than providing 20 messages.
57
- _line, line_number = deprecated_references_yml_pathname.readlines.each_with_index.find { |line, _index| line.include?(violation.class_name) }
58
- if line_number.nil?
80
+ #
81
+ _line, class_name_line_number = deprecated_references_yml_pathname.readlines.each_with_index.find { |line, _index| line.include?(violation.class_name) }
82
+ if class_name_line_number.nil?
59
83
  debug_info = { class_name: violation.class_name, to_package_name: violation.to_package_name, type: violation.type }
60
84
  raise "Unable to find reference to violation #{debug_info} in #{deprecated_references_yml}"
61
85
  end
62
86
 
63
- # We add one to the line number since `each_with_index` is zero-based indexed but Github line numbers are one-based indexed
64
- location = Location.new(file: deprecated_references_yml, line_number: line_number + 1)
65
-
66
87
  violation.files.map do |file|
88
+ file_line_numbers = file_reference_to_line_number_index.fetch(file, [])
89
+ file_line_number = file_line_numbers.select { |index| index > class_name_line_number }.min
90
+ raise "Unable to find reference to violation #{{ file: file, to_package_name: violation.to_package_name, type: violation.type }} in #{deprecated_references_yml}" if file_line_number.nil?
91
+
92
+ # We add one to the line number since `each_with_index` is zero-based indexed but Github line numbers are one-based indexed
93
+ file_location = Location.new(file: deprecated_references_yml, line_number: file_line_number + 1)
94
+
67
95
  BasicReferenceOffense.new(
68
96
  class_name: violation.class_name,
69
97
  file: file,
70
98
  to_package_name: violation.to_package_name,
71
99
  type: violation.type,
72
- location: location
100
+ file_location: file_location
73
101
  )
74
102
  end
75
103
  end
@@ -44,9 +44,12 @@ module DangerPackwerk
44
44
  )
45
45
 
46
46
  current_comment_count = 0
47
- violation_diff.added_violations.group_by(&:location).each do |location, violations|
47
+
48
+ violation_diff.added_violations.group_by(&:class_name).each do |_class_name, violations|
48
49
  break if current_comment_count >= max_comments
49
50
 
51
+ location = T.must(violations.first).file_location
52
+
50
53
  markdown(
51
54
  added_offenses_formatter.call(violations),
52
55
  line: location.line_number,
@@ -71,13 +74,13 @@ module DangerPackwerk
71
74
  git.deleted_files.grep(DEPRECATED_REFERENCES_PATTERN).each do |deleted_deprecated_references_yml_file|
72
75
  # Since the file is deleted, we know on the HEAD commit there are no violations related to this pack,
73
76
  # and that all violations from this file are deleted
74
- removed_violations += get_violations_before_patch_for(deleted_deprecated_references_yml_file)
77
+ deleted_violations = get_violations_before_patch_for(deleted_deprecated_references_yml_file)
78
+ removed_violations += deleted_violations
75
79
  end
76
80
 
77
81
  git.modified_files.grep(DEPRECATED_REFERENCES_PATTERN).each do |modified_deprecated_references_yml_file|
78
82
  head_commit_violations = BasicReferenceOffense.from(modified_deprecated_references_yml_file)
79
83
  base_commit_violations = get_violations_before_patch_for(modified_deprecated_references_yml_file)
80
-
81
84
  added_violations += head_commit_violations - base_commit_violations
82
85
  removed_violations += base_commit_violations - head_commit_violations
83
86
  end
@@ -28,8 +28,7 @@ module DangerPackwerk
28
28
  else # violations.any?(&:privacy?)
29
29
  <<~MESSAGE
30
30
  Hi! It looks like the pack defining `#{constant_name}` considers this private API.
31
- #{disclaimer}
32
- #{request_to_add_context}
31
+ #{disclaimer}#{request_to_add_context}
33
32
  MESSAGE
34
33
  end
35
34
  end
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module DangerPackwerk
5
- VERSION = '0.1.0'
5
+ VERSION = '0.1.1'
6
6
  end
data/sorbet/rbi/todo.rbi CHANGED
@@ -1 +1,3 @@
1
- module ::RSpec; end
1
+ module ::RSpec
2
+ module Matchers; end
3
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: danger-packwerk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gusto Engineers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-04-15 00:00:00.000000000 Z
11
+ date: 2022-04-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: danger-plugin-api
@@ -81,35 +81,35 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: rspec
84
+ name: rake
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - "~>"
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
- version: '3.0'
89
+ version: '0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - "~>"
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
- version: '3.0'
96
+ version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: rubocop
98
+ name: rspec
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - ">="
101
+ - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '0'
103
+ version: '3.0'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - ">="
108
+ - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '0'
110
+ version: '3.0'
111
111
  - !ruby/object:Gem::Dependency
112
- name: rubocop-sorbet
112
+ name: rubocop
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - ">="
@@ -123,7 +123,7 @@ dependencies:
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
125
  - !ruby/object:Gem::Dependency
126
- name: sorbet
126
+ name: rubocop-sorbet
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
129
  - - ">="
@@ -137,7 +137,7 @@ dependencies:
137
137
  - !ruby/object:Gem::Version
138
138
  version: '0'
139
139
  - !ruby/object:Gem::Dependency
140
- name: tapioca
140
+ name: sorbet
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
143
  - - ">="
@@ -151,7 +151,7 @@ dependencies:
151
151
  - !ruby/object:Gem::Version
152
152
  version: '0'
153
153
  - !ruby/object:Gem::Dependency
154
- name: rake
154
+ name: tapioca
155
155
  requirement: !ruby/object:Gem::Requirement
156
156
  requirements:
157
157
  - - ">="