code_ownership 1.32.7 → 1.32.8
Sign up to get free protection for your applications and to get access to all the features.
- 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
|