code_ownership 1.32.7 → 1.32.8
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/lib/code_ownership/mapper.rb +8 -5
- data/lib/code_ownership/private/codeowners_file.rb +52 -0
- data/lib/code_ownership/private/glob_cache.rb +1 -2
- data/lib/code_ownership/private/ownership_mappers/file_annotations.rb +21 -11
- data/lib/code_ownership/private/ownership_mappers/js_package_ownership.rb +6 -15
- data/lib/code_ownership/private/ownership_mappers/package_ownership.rb +10 -19
- data/lib/code_ownership/private/ownership_mappers/team_globs.rb +14 -7
- data/lib/code_ownership/private/ownership_mappers/team_yml_ownership.rb +14 -7
- data/lib/code_ownership/private.rb +9 -1
- data/lib/code_ownership.rb +2 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 18e702e6635a7d3d264eaae41f61fb6f83e423e8021ca76e92a6972fe5444848
|
4
|
+
data.tar.gz: 90f34b5a02b21a1f78ff781f7ef3e8220a45549e77c4b93b829381a57f37ba7c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f1deba0493c9ebbff4e39b81c0a282ffd634cef6db756f3f4be2b3b91f8c43e0d0f6d9362e03f2779ac5fe302101ae19fa8bf90022c55f24afbd9cd7c3b1fb13
|
7
|
+
data.tar.gz: 0a1a3da4c7c758b0b64b7d9f817a92924c7a5e54fb4918655af2208a5ba8c65f12d41b37f0f568f443a817dd5893d16e351de745be641b3a56d3479e257add45
|
@@ -40,15 +40,18 @@ module CodeOwnership
|
|
40
40
|
#
|
41
41
|
sig do
|
42
42
|
abstract.params(files: T::Array[String]).
|
43
|
-
returns(T::Hash[String,
|
43
|
+
returns(T::Hash[String, ::CodeTeams::Team])
|
44
44
|
end
|
45
|
-
def
|
45
|
+
def globs_to_owner(files)
|
46
46
|
end
|
47
47
|
|
48
|
+
#
|
49
|
+
# This should be fast when run with MANY files
|
50
|
+
#
|
48
51
|
sig do
|
49
|
-
abstract.
|
52
|
+
abstract.params(cache: GlobsToOwningTeamMap, files: T::Array[String]).returns(GlobsToOwningTeamMap)
|
50
53
|
end
|
51
|
-
def
|
54
|
+
def update_cache(cache, files)
|
52
55
|
end
|
53
56
|
|
54
57
|
sig { abstract.returns(String) }
|
@@ -64,7 +67,7 @@ module CodeOwnership
|
|
64
67
|
glob_to_owner_map_by_mapper_description = {}
|
65
68
|
|
66
69
|
Mapper.all.each do |mapper|
|
67
|
-
mapped_files = mapper.
|
70
|
+
mapped_files = mapper.globs_to_owner(Private.tracked_files)
|
68
71
|
mapped_files.each do |glob, owner|
|
69
72
|
next if owner.nil?
|
70
73
|
glob_to_owner_map_by_mapper_description[mapper.description] ||= {}
|
@@ -90,6 +90,58 @@ module CodeOwnership
|
|
90
90
|
def self.path
|
91
91
|
Pathname.pwd.join('.github/CODEOWNERS')
|
92
92
|
end
|
93
|
+
|
94
|
+
sig { params(files: T::Array[String]).void }
|
95
|
+
def self.update_cache!(files)
|
96
|
+
cache = Private.glob_cache
|
97
|
+
# Each mapper returns a new copy of the cache subset related to that mapper,
|
98
|
+
# which is then stored back into the cache.
|
99
|
+
Mapper.all.each do |mapper|
|
100
|
+
existing_cache = cache.raw_cache_contents.fetch(mapper.description, {})
|
101
|
+
updated_cache = mapper.update_cache(existing_cache, files)
|
102
|
+
cache.raw_cache_contents[mapper.description] = updated_cache
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
sig { returns(T::Boolean) }
|
107
|
+
def self.use_codeowners_cache?
|
108
|
+
CodeownersFile.path.exist? && !Private.configuration.skip_codeowners_validation
|
109
|
+
end
|
110
|
+
|
111
|
+
sig { returns(GlobCache) }
|
112
|
+
def self.to_glob_cache
|
113
|
+
github_team_to_code_team_map = T.let({}, T::Hash[String, CodeTeams::Team])
|
114
|
+
CodeTeams.all.each do |team|
|
115
|
+
github_team = TeamPlugins::Github.for(team).github.team
|
116
|
+
github_team_to_code_team_map[github_team] = team
|
117
|
+
end
|
118
|
+
raw_cache_contents = T.let({}, GlobCache::CacheShape)
|
119
|
+
current_mapper = T.let(nil, T.nilable(String))
|
120
|
+
mapper_descriptions = Set.new(Mapper.all.map(&:description))
|
121
|
+
|
122
|
+
path.readlines.each do |line|
|
123
|
+
line_with_no_comment = line.chomp.gsub("# ", "")
|
124
|
+
if mapper_descriptions.include?(line_with_no_comment)
|
125
|
+
current_mapper = line_with_no_comment
|
126
|
+
else
|
127
|
+
next if current_mapper.nil?
|
128
|
+
next if line.chomp == ""
|
129
|
+
# The codeowners file stores paths relative to the root of directory
|
130
|
+
# Since a `/` means root of the file system from the perspective of ruby,
|
131
|
+
# we remove that beginning slash so we can correctly glob the files out.
|
132
|
+
normalized_line = line.gsub(/^# /, '').gsub(/^\//, '')
|
133
|
+
split_line = normalized_line.split
|
134
|
+
# Most lines will be in the format: /path/to/file my-github-team
|
135
|
+
# This will skip over lines that are not of the correct form
|
136
|
+
next if split_line.count > 2
|
137
|
+
entry, github_team = split_line
|
138
|
+
raw_cache_contents[current_mapper] ||= {}
|
139
|
+
raw_cache_contents.fetch(current_mapper)[T.must(entry)] = github_team_to_code_team_map.fetch(T.must(github_team))
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
GlobCache.new(raw_cache_contents)
|
144
|
+
end
|
93
145
|
end
|
94
146
|
end
|
95
147
|
end
|
@@ -7,12 +7,11 @@ module CodeOwnership
|
|
7
7
|
extend T::Sig
|
8
8
|
|
9
9
|
MapperDescription = T.type_alias { String }
|
10
|
-
GlobsByMapper = T.type_alias { T::Hash[String, CodeTeams::Team] }
|
11
10
|
|
12
11
|
CacheShape = T.type_alias do
|
13
12
|
T::Hash[
|
14
13
|
MapperDescription,
|
15
|
-
|
14
|
+
GlobsToOwningTeamMap
|
16
15
|
]
|
17
16
|
end
|
18
17
|
|
@@ -18,7 +18,7 @@ module CodeOwnership
|
|
18
18
|
extend T::Sig
|
19
19
|
include Mapper
|
20
20
|
|
21
|
-
@@map_files_to_owners = T.let({}, T.nilable(T::Hash[String,
|
21
|
+
@@map_files_to_owners = T.let({}, T.nilable(T::Hash[String, ::CodeTeams::Team])) # rubocop:disable Style/ClassVars
|
22
22
|
|
23
23
|
TEAM_PATTERN = T.let(/\A(?:#|\/\/) @team (?<team>.*)\Z/.freeze, Regexp)
|
24
24
|
|
@@ -33,9 +33,9 @@ module CodeOwnership
|
|
33
33
|
sig do
|
34
34
|
override.
|
35
35
|
params(files: T::Array[String]).
|
36
|
-
returns(T::Hash[String,
|
36
|
+
returns(T::Hash[String, ::CodeTeams::Team])
|
37
37
|
end
|
38
|
-
def
|
38
|
+
def globs_to_owner(files)
|
39
39
|
return @@map_files_to_owners if @@map_files_to_owners&.keys && @@map_files_to_owners.keys.count > 0
|
40
40
|
|
41
41
|
@@map_files_to_owners = files.each_with_object({}) do |filename_relative_to_root, mapping| # rubocop:disable Style/ClassVars
|
@@ -46,6 +46,24 @@ module CodeOwnership
|
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
+
sig do
|
50
|
+
override.params(cache: GlobsToOwningTeamMap, files: T::Array[String]).returns(GlobsToOwningTeamMap)
|
51
|
+
end
|
52
|
+
def update_cache(cache, files)
|
53
|
+
cache.merge!(globs_to_owner(files))
|
54
|
+
|
55
|
+
# TODO: Make `tracked_files` return a set
|
56
|
+
fileset = Set.new(Private.tracked_files)
|
57
|
+
invalid_files = cache.keys.select do |file|
|
58
|
+
!fileset.include?(file)
|
59
|
+
end
|
60
|
+
invalid_files.each do |invalid_file|
|
61
|
+
cache.delete(invalid_file)
|
62
|
+
end
|
63
|
+
|
64
|
+
cache
|
65
|
+
end
|
66
|
+
|
49
67
|
sig { params(filename: String).returns(T.nilable(CodeTeams::Team)) }
|
50
68
|
def file_annotation_based_owner(filename)
|
51
69
|
# If for a directory is named with an ownable extension, we need to skip
|
@@ -96,14 +114,6 @@ module CodeOwnership
|
|
96
114
|
end
|
97
115
|
end
|
98
116
|
|
99
|
-
sig do
|
100
|
-
override.returns(T::Hash[String, T.nilable(::CodeTeams::Team)])
|
101
|
-
end
|
102
|
-
def codeowners_lines_to_owners
|
103
|
-
@@map_files_to_owners = nil # rubocop:disable Style/ClassVars
|
104
|
-
map_files_to_owners(Private.tracked_files)
|
105
|
-
end
|
106
|
-
|
107
117
|
sig { override.returns(String) }
|
108
118
|
def description
|
109
119
|
'Annotations at the top of file'
|
@@ -24,20 +24,10 @@ module CodeOwnership
|
|
24
24
|
end
|
25
25
|
|
26
26
|
sig do
|
27
|
-
override.
|
28
|
-
params(files: T::Array[String]).
|
29
|
-
returns(T::Hash[String, T.nilable(::CodeTeams::Team)])
|
27
|
+
override.params(cache: GlobsToOwningTeamMap, files: T::Array[String]).returns(GlobsToOwningTeamMap)
|
30
28
|
end
|
31
|
-
def
|
32
|
-
|
33
|
-
owner = owner_for_package(package)
|
34
|
-
next if owner.nil?
|
35
|
-
|
36
|
-
glob = package.directory.join('**/**').to_s
|
37
|
-
Dir.glob(glob).each do |path|
|
38
|
-
res[path] = owner
|
39
|
-
end
|
40
|
-
end
|
29
|
+
def update_cache(cache, files)
|
30
|
+
globs_to_owner(files)
|
41
31
|
end
|
42
32
|
|
43
33
|
#
|
@@ -49,9 +39,10 @@ module CodeOwnership
|
|
49
39
|
# subset of files, but rather we want code ownership for all files.
|
50
40
|
#
|
51
41
|
sig do
|
52
|
-
override.
|
42
|
+
override.params(files: T::Array[String]).
|
43
|
+
returns(T::Hash[String, ::CodeTeams::Team])
|
53
44
|
end
|
54
|
-
def
|
45
|
+
def globs_to_owner(files)
|
55
46
|
ParseJsPackages.all.each_with_object({}) do |package, res|
|
56
47
|
owner = owner_for_package(package)
|
57
48
|
next if owner.nil?
|
@@ -23,23 +23,6 @@ module CodeOwnership
|
|
23
23
|
owner_for_package(package)
|
24
24
|
end
|
25
25
|
|
26
|
-
sig do
|
27
|
-
override.
|
28
|
-
params(files: T::Array[String]).
|
29
|
-
returns(T::Hash[String, T.nilable(::CodeTeams::Team)])
|
30
|
-
end
|
31
|
-
def map_files_to_owners(files) # rubocop:disable Lint/UnusedMethodArgument
|
32
|
-
Packs.all.each_with_object({}) do |package, res|
|
33
|
-
owner = owner_for_package(package)
|
34
|
-
next if owner.nil?
|
35
|
-
|
36
|
-
glob = package.relative_path.join('**/**').to_s
|
37
|
-
Dir.glob(glob).each do |path|
|
38
|
-
res[path] = owner
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
26
|
#
|
44
27
|
# Package ownership ignores the passed in files when generating code owners lines.
|
45
28
|
# This is because Package ownership knows that the fastest way to find code owners for package based ownership
|
@@ -49,9 +32,10 @@ module CodeOwnership
|
|
49
32
|
# subset of files, but rather we want code ownership for all files.
|
50
33
|
#
|
51
34
|
sig do
|
52
|
-
override.
|
35
|
+
override.params(files: T::Array[String]).
|
36
|
+
returns(T::Hash[String, ::CodeTeams::Team])
|
53
37
|
end
|
54
|
-
def
|
38
|
+
def globs_to_owner(files)
|
55
39
|
Packs.all.each_with_object({}) do |package, res|
|
56
40
|
owner = owner_for_package(package)
|
57
41
|
next if owner.nil?
|
@@ -65,6 +49,13 @@ module CodeOwnership
|
|
65
49
|
'Owner metadata key in package.yml'
|
66
50
|
end
|
67
51
|
|
52
|
+
sig do
|
53
|
+
override.params(cache: GlobsToOwningTeamMap, files: T::Array[String]).returns(GlobsToOwningTeamMap)
|
54
|
+
end
|
55
|
+
def update_cache(cache, files)
|
56
|
+
globs_to_owner(files)
|
57
|
+
end
|
58
|
+
|
68
59
|
sig { params(package: Packs::Pack).returns(T.nilable(CodeTeams::Team)) }
|
69
60
|
def owner_for_package(package)
|
70
61
|
raw_owner_value = package.metadata['owner']
|
@@ -10,15 +10,14 @@ module CodeOwnership
|
|
10
10
|
include Mapper
|
11
11
|
include Validator
|
12
12
|
|
13
|
-
@@map_files_to_owners = T.let(@map_files_to_owners, T.nilable(T::Hash[String,
|
13
|
+
@@map_files_to_owners = T.let(@map_files_to_owners, T.nilable(T::Hash[String, ::CodeTeams::Team])) # rubocop:disable Style/ClassVars
|
14
14
|
@@map_files_to_owners = {} # rubocop:disable Style/ClassVars
|
15
|
-
@@codeowners_lines_to_owners = T.let(@codeowners_lines_to_owners, T.nilable(T::Hash[String,
|
15
|
+
@@codeowners_lines_to_owners = T.let(@codeowners_lines_to_owners, T.nilable(T::Hash[String, ::CodeTeams::Team])) # rubocop:disable Style/ClassVars
|
16
16
|
@@codeowners_lines_to_owners = {} # rubocop:disable Style/ClassVars
|
17
17
|
|
18
18
|
sig do
|
19
|
-
|
20
|
-
|
21
|
-
returns(T::Hash[String, T.nilable(::CodeTeams::Team)])
|
19
|
+
params(files: T::Array[String]).
|
20
|
+
returns(T::Hash[String, ::CodeTeams::Team])
|
22
21
|
end
|
23
22
|
def map_files_to_owners(files) # rubocop:disable Lint/UnusedMethodArgument
|
24
23
|
return @@map_files_to_owners if @@map_files_to_owners&.keys && @@map_files_to_owners.keys.count > 0
|
@@ -93,9 +92,17 @@ module CodeOwnership
|
|
93
92
|
end
|
94
93
|
|
95
94
|
sig do
|
96
|
-
override.
|
95
|
+
override.params(cache: GlobsToOwningTeamMap, files: T::Array[String]).returns(GlobsToOwningTeamMap)
|
97
96
|
end
|
98
|
-
def
|
97
|
+
def update_cache(cache, files)
|
98
|
+
globs_to_owner(files)
|
99
|
+
end
|
100
|
+
|
101
|
+
sig do
|
102
|
+
override.params(files: T::Array[String]).
|
103
|
+
returns(T::Hash[String, ::CodeTeams::Team])
|
104
|
+
end
|
105
|
+
def globs_to_owner(files)
|
99
106
|
return @@codeowners_lines_to_owners if @@codeowners_lines_to_owners&.keys && @@codeowners_lines_to_owners.keys.count > 0
|
100
107
|
|
101
108
|
@@codeowners_lines_to_owners = CodeTeams.all.each_with_object({}) do |team, map| # rubocop:disable Style/ClassVars
|
@@ -9,15 +9,14 @@ module CodeOwnership
|
|
9
9
|
extend T::Sig
|
10
10
|
include Mapper
|
11
11
|
|
12
|
-
@@map_files_to_owners = T.let(@map_files_to_owners, T.nilable(T::Hash[String,
|
12
|
+
@@map_files_to_owners = T.let(@map_files_to_owners, T.nilable(T::Hash[String, ::CodeTeams::Team])) # rubocop:disable Style/ClassVars
|
13
13
|
@@map_files_to_owners = {} # rubocop:disable Style/ClassVars
|
14
|
-
@@codeowners_lines_to_owners = T.let(@codeowners_lines_to_owners, T.nilable(T::Hash[String,
|
14
|
+
@@codeowners_lines_to_owners = T.let(@codeowners_lines_to_owners, T.nilable(T::Hash[String, ::CodeTeams::Team])) # rubocop:disable Style/ClassVars
|
15
15
|
@@codeowners_lines_to_owners = {} # rubocop:disable Style/ClassVars
|
16
16
|
|
17
17
|
sig do
|
18
|
-
|
19
|
-
|
20
|
-
returns(T::Hash[String, T.nilable(::CodeTeams::Team)])
|
18
|
+
params(files: T::Array[String]).
|
19
|
+
returns(T::Hash[String, ::CodeTeams::Team])
|
21
20
|
end
|
22
21
|
def map_files_to_owners(files) # rubocop:disable Lint/UnusedMethodArgument
|
23
22
|
return @@map_files_to_owners if @@map_files_to_owners&.keys && @@map_files_to_owners.keys.count > 0
|
@@ -36,9 +35,10 @@ module CodeOwnership
|
|
36
35
|
end
|
37
36
|
|
38
37
|
sig do
|
39
|
-
override.
|
38
|
+
override.params(files: T::Array[String]).
|
39
|
+
returns(T::Hash[String, ::CodeTeams::Team])
|
40
40
|
end
|
41
|
-
def
|
41
|
+
def globs_to_owner(files)
|
42
42
|
return @@codeowners_lines_to_owners if @@codeowners_lines_to_owners&.keys && @@codeowners_lines_to_owners.keys.count > 0
|
43
43
|
|
44
44
|
@@codeowners_lines_to_owners = CodeTeams.all.each_with_object({}) do |team, map| # rubocop:disable Style/ClassVars
|
@@ -52,6 +52,13 @@ module CodeOwnership
|
|
52
52
|
@@map_files_to_owners = {} # rubocop:disable Style/ClassVars
|
53
53
|
end
|
54
54
|
|
55
|
+
sig do
|
56
|
+
override.params(cache: GlobsToOwningTeamMap, files: T::Array[String]).returns(GlobsToOwningTeamMap)
|
57
|
+
end
|
58
|
+
def update_cache(cache, files)
|
59
|
+
globs_to_owner(files)
|
60
|
+
end
|
61
|
+
|
55
62
|
sig { override.returns(String) }
|
56
63
|
def description
|
57
64
|
'Team YML ownership'
|
@@ -44,6 +44,8 @@ module CodeOwnership
|
|
44
44
|
|
45
45
|
sig { params(files: T::Array[String], autocorrect: T::Boolean, stage_changes: T::Boolean).void }
|
46
46
|
def self.validate!(files:, autocorrect: true, stage_changes: true)
|
47
|
+
CodeownersFile.update_cache!(files) if CodeownersFile.use_codeowners_cache?
|
48
|
+
|
47
49
|
errors = Validator.all.flat_map do |validator|
|
48
50
|
validator.validation_errors(
|
49
51
|
files: files,
|
@@ -92,7 +94,13 @@ module CodeOwnership
|
|
92
94
|
sig { returns(GlobCache) }
|
93
95
|
def self.glob_cache
|
94
96
|
@glob_cache ||= T.let(@glob_cache, T.nilable(GlobCache))
|
95
|
-
@glob_cache ||=
|
97
|
+
@glob_cache ||= begin
|
98
|
+
if CodeownersFile.use_codeowners_cache?
|
99
|
+
CodeownersFile.to_glob_cache
|
100
|
+
else
|
101
|
+
Mapper.to_glob_cache
|
102
|
+
end
|
103
|
+
end
|
96
104
|
end
|
97
105
|
end
|
98
106
|
|
data/lib/code_ownership.rb
CHANGED
@@ -19,6 +19,7 @@ module CodeOwnership
|
|
19
19
|
extend T::Helpers
|
20
20
|
|
21
21
|
requires_ancestor { Kernel }
|
22
|
+
GlobsToOwningTeamMap = T.type_alias { T::Hash[String, CodeTeams::Team] }
|
22
23
|
|
23
24
|
sig { params(file: String).returns(T.nilable(CodeTeams::Team)) }
|
24
25
|
def for_file(file)
|
@@ -50,7 +51,7 @@ module CodeOwnership
|
|
50
51
|
ownership_information << "# Code Ownership Report for `#{team.name}` Team"
|
51
52
|
Mapper.all.each do |mapper|
|
52
53
|
ownership_information << "## #{mapper.description}"
|
53
|
-
codeowners_lines = mapper.
|
54
|
+
codeowners_lines = mapper.globs_to_owner(Private.tracked_files)
|
54
55
|
ownership_for_mapper = []
|
55
56
|
codeowners_lines.each do |line, team_for_line|
|
56
57
|
next if team_for_line.nil?
|
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.32.
|
4
|
+
version: 1.32.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gusto Engineers
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-04-
|
11
|
+
date: 2023-04-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: code_teams
|