danger-packwerk 0.1.0 → 0.1.1

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: 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
  - - ">="