code_ownership 1.37.0 → 1.38.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: c854c774447149078df69925e183be064e8ac92ea464da9eea83cec2cfb10931
4
- data.tar.gz: 5a42650db0cdc8f14fd8878a0c70587b21a722a284a45104051062464f73a4a7
3
+ metadata.gz: 8319ea8a2a73ecec20a28193627b25b877ae9983b206dae6ff9422d5be157625
4
+ data.tar.gz: 13228207fa0b9042fe5f87e53c80234e862a476ef4a3888bce7f4bbdfb64e970
5
5
  SHA512:
6
- metadata.gz: 25025e91fa585614f864ab1f84d829037b5769cd491dcca93bf822e25ecb3222388d8d9315bf7dd3fe5a645645855c391028a9df01592199ce0857d47276656e
7
- data.tar.gz: 8f8035f102b184ac7ea866df6bff7cee92f0bd2fe5337b49956c85e2ead483a5868c0969030392c63dda1575f9bf33ae085058c0114ef027140b3bf629a60895
6
+ metadata.gz: a80e615b1d6e7cc8ec795a7b2ffdb20f0ffb8b0e8027cd70e8361542ff5650f195fca4fdf4ece8e0f1331e987dcef9e2d1106c7125925a43d16403e6e9ed0a78
7
+ data.tar.gz: 8fabc79d074c2491c49a3cdc1b0caf24f009dbab3e81b7cdcb84ac4b6d563d6ac7e32c83ec6494a3df81d8293afa01c7674e87b0b05878515177e757a4df0fe3
@@ -73,7 +73,26 @@ module CodeOwnership
73
73
 
74
74
  next if ownership_entries.none?
75
75
 
76
- codeowners_file_lines += ['', "# #{mapper_description}", *ownership_entries.sort]
76
+ # When we have a special character at the beginning of a folder name, then this character
77
+ # may be prioritized over *. However, we want the most specific folder to be listed last
78
+ # in the CODEOWNERS file, so we should prioritize any character above an asterisk in the
79
+ # same position.
80
+ if mapper_description == OwnershipMappers::FileAnnotations::DESCRIPTION
81
+ # individually owned files definitely won't have globs so we don't need to do special sorting
82
+ sorted_ownership_entries = ownership_entries.sort
83
+ else
84
+ sorted_ownership_entries = ownership_entries.sort do |entry1, entry2|
85
+ if entry2.start_with?(entry1.split('**').first)
86
+ -1
87
+ elsif entry1.start_with?(entry2.split('**').first)
88
+ 1
89
+ else
90
+ entry1 <=> entry2
91
+ end
92
+ end
93
+ end
94
+
95
+ codeowners_file_lines += ['', "# #{mapper_description}", *sorted_ownership_entries]
77
96
  end
78
97
 
79
98
  [
@@ -39,7 +39,8 @@ module CodeOwnership
39
39
  owner = file_annotation_based_owner(filename_relative_to_root)
40
40
  next unless owner
41
41
 
42
- mapping[filename_relative_to_root] = owner
42
+ escaped_filename = escaped_path_for_codeowners_file(filename_relative_to_root)
43
+ mapping[escaped_filename] = owner
43
44
  end
44
45
  end
45
46
 
@@ -55,7 +56,8 @@ module CodeOwnership
55
56
 
56
57
  invalid_files = cache.keys.select do |file|
57
58
  # If a file is not tracked, it should be removed from the cache
58
- !Private.file_tracked?(file) ||
59
+ unescaped_file = unescaped_path_for_codeowners_file(file)
60
+ !Private.file_tracked?(unescaped_file) ||
59
61
  # If a file no longer has a file annotation (i.e. `globs_to_owner` doesn't map it)
60
62
  # it should be removed from the cache
61
63
  # We make sure to only apply this to the input files since otherwise `updated_cache_for_files.key?(file)` would always return `false` when files == []
@@ -126,6 +128,32 @@ module CodeOwnership
126
128
 
127
129
  sig { override.void }
128
130
  def bust_caches!; end
131
+
132
+ sig { params(filename: String).returns(String) }
133
+ def escaped_path_for_codeowners_file(filename)
134
+ # Globs can contain certain regex characters, like "[" and "]".
135
+ # However, when we are generating a glob from a file annotation, we
136
+ # need to escape bracket characters and interpret them literally.
137
+ # Otherwise the resulting glob will not actually match the directory
138
+ # containing the file.
139
+ #
140
+ # Example
141
+ # filename: "/some/[xId]/myfile.tsx"
142
+ # matches: "/some/1/file"
143
+ # matches: "/some/2/file"
144
+ # matches: "/some/3/file"
145
+ # does not match!: "/some/[xId]/myfile.tsx"
146
+ filename.gsub(/[\[\]]/) { |x| "\\#{x}" }
147
+ end
148
+
149
+ sig { params(filename: String).returns(String) }
150
+ def unescaped_path_for_codeowners_file(filename)
151
+ # Globs can contain certain regex characters, like "[" and "]".
152
+ # We escape bracket characters and interpret them literally for
153
+ # the CODEOWNERS file. However, we want to compare the unescaped
154
+ # glob to the actual file path when we check if the file was deleted.
155
+ filename.gsub(/\\([\[\]])/, '\1')
156
+ end
129
157
  end
130
158
  end
131
159
  end
@@ -99,6 +99,7 @@ module CodeOwnership
99
99
  in_unowned_globs = configuration.unowned_globs.any? do |unowned_glob|
100
100
  File.fnmatch?(unowned_glob, file, File::FNM_PATHNAME | File::FNM_EXTGLOB)
101
101
  end
102
+
102
103
  in_owned_globs && !in_unowned_globs && File.exist?(file)
103
104
  end
104
105
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: code_ownership
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.37.0
4
+ version: 1.38.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: 2024-08-13 00:00:00.000000000 Z
11
+ date: 2024-11-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: code_teams
@@ -220,7 +220,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
220
220
  - !ruby/object:Gem::Version
221
221
  version: '0'
222
222
  requirements: []
223
- rubygems_version: 3.5.11
223
+ rubygems_version: 3.5.22
224
224
  signing_key:
225
225
  specification_version: 4
226
226
  summary: A gem to help engineering teams declare ownership of code