code_ownership 1.29.2 → 1.30.0
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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9810b0bbef35bf354841da08d53391f864e213540ebb61fa5117b98df3b20ba9
|
4
|
+
data.tar.gz: 70dd498844898d361494a86a0c57da788d69cbd7c03eb7e3883c0d4520781089
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d17b0680d21a907fb5581fa98adc16255984580ac2336a2170d69ab1d11b281d9d180e68e2866435ed5aab8dec1dab90f5849d8431311ddaa3d9014c6a961e9d
|
7
|
+
data.tar.gz: 3e1d9cf9e16234c199085f1de858590af922c7416a219a84fbc3c55c274a1eff59c7b6dba95e66b46f141328dcbd82005cbdaa55cb45b5d0dac32d2778156602
|
@@ -31,6 +31,58 @@ module CodeOwnership
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
+
class MappingContext < T::Struct
|
35
|
+
const :glob, String
|
36
|
+
const :team, CodeTeams::Team
|
37
|
+
end
|
38
|
+
|
39
|
+
class GlobOverlap < T::Struct
|
40
|
+
extend T::Sig
|
41
|
+
|
42
|
+
const :mapping_contexts, T::Array[MappingContext]
|
43
|
+
|
44
|
+
sig { returns(String) }
|
45
|
+
def description
|
46
|
+
# These are sorted only to prevent non-determinism in output between local and CI environments.
|
47
|
+
sorted_contexts = mapping_contexts.sort_by{|context| context.team.config_yml.to_s }
|
48
|
+
description_args = sorted_contexts.map do |context|
|
49
|
+
"`#{context.glob}` (from `#{context.team.config_yml}`)"
|
50
|
+
end
|
51
|
+
|
52
|
+
description_args.join(', ')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
sig do
|
57
|
+
returns(T::Array[GlobOverlap])
|
58
|
+
end
|
59
|
+
def find_overlapping_globs
|
60
|
+
mapped_files = T.let({}, T::Hash[String, T::Array[MappingContext]])
|
61
|
+
CodeTeams.all.each_with_object({}) do |team, map| # rubocop:disable Style/ClassVars
|
62
|
+
TeamPlugins::Ownership.for(team).owned_globs.each do |glob|
|
63
|
+
Dir.glob(glob).each do |filename|
|
64
|
+
mapped_files[filename] ||= []
|
65
|
+
T.must(mapped_files[filename]) << MappingContext.new(glob: glob, team: team)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
overlaps = T.let([], T::Array[GlobOverlap])
|
71
|
+
mapped_files.each do |filename, mapping_contexts|
|
72
|
+
if mapping_contexts.count > 1
|
73
|
+
overlaps << GlobOverlap.new(mapping_contexts: mapping_contexts)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
deduplicated_overlaps = overlaps.uniq do |glob_overlap|
|
78
|
+
glob_overlap.mapping_contexts.map do |context|
|
79
|
+
[context.glob, context.team.name]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
deduplicated_overlaps
|
84
|
+
end
|
85
|
+
|
34
86
|
sig do
|
35
87
|
override.params(file: String).
|
36
88
|
returns(T.nilable(::CodeTeams::Team))
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# typed: strict
|
2
|
+
|
3
|
+
module CodeOwnership
|
4
|
+
module Private
|
5
|
+
module Validations
|
6
|
+
class NoOverlappingGlobs
|
7
|
+
extend T::Sig
|
8
|
+
extend T::Helpers
|
9
|
+
include Interface
|
10
|
+
|
11
|
+
sig { override.params(files: T::Array[String], autocorrect: T::Boolean, stage_changes: T::Boolean).returns(T::Array[String]) }
|
12
|
+
def validation_errors(files:, autocorrect: true, stage_changes: true)
|
13
|
+
overlapping_globs = OwnershipMappers::TeamGlobs.new.find_overlapping_globs
|
14
|
+
|
15
|
+
errors = T.let([], T::Array[String])
|
16
|
+
|
17
|
+
if overlapping_globs.any?
|
18
|
+
errors << <<~MSG
|
19
|
+
`owned_globs` cannot overlap between teams. The following globs overlap:
|
20
|
+
|
21
|
+
#{overlapping_globs.map { |overlap| "- #{overlap.description}"}.join("\n")}
|
22
|
+
MSG
|
23
|
+
end
|
24
|
+
|
25
|
+
errors
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -10,6 +10,7 @@ require 'code_ownership/private/validations/interface'
|
|
10
10
|
require 'code_ownership/private/validations/files_have_owners'
|
11
11
|
require 'code_ownership/private/validations/github_codeowners_up_to_date'
|
12
12
|
require 'code_ownership/private/validations/files_have_unique_owners'
|
13
|
+
require 'code_ownership/private/validations/no_overlapping_globs'
|
13
14
|
require 'code_ownership/private/ownership_mappers/interface'
|
14
15
|
require 'code_ownership/private/ownership_mappers/file_annotations'
|
15
16
|
require 'code_ownership/private/ownership_mappers/team_globs'
|
@@ -39,6 +40,7 @@ module CodeOwnership
|
|
39
40
|
Validations::FilesHaveOwners.new,
|
40
41
|
Validations::FilesHaveUniqueOwners.new,
|
41
42
|
Validations::GithubCodeownersUpToDate.new,
|
43
|
+
Validations::NoOverlappingGlobs.new,
|
42
44
|
]
|
43
45
|
|
44
46
|
errors = validators.flat_map do |validator|
|
data/lib/code_ownership.rb
CHANGED
@@ -58,7 +58,6 @@ module CodeOwnership
|
|
58
58
|
ownership_information += ownership_for_mapper
|
59
59
|
end
|
60
60
|
|
61
|
-
|
62
61
|
ownership_information << ""
|
63
62
|
end
|
64
63
|
|
@@ -93,7 +92,25 @@ module CodeOwnership
|
|
93
92
|
# first line that corresponds to a file with assigned ownership
|
94
93
|
sig { params(backtrace: T.nilable(T::Array[String]), excluded_teams: T::Array[::CodeTeams::Team]).returns(T.nilable(::CodeTeams::Team)) }
|
95
94
|
def for_backtrace(backtrace, excluded_teams: [])
|
96
|
-
|
95
|
+
first_owned_file_for_backtrace(backtrace, excluded_teams: excluded_teams)&.first
|
96
|
+
end
|
97
|
+
|
98
|
+
# Given a backtrace from either `Exception#backtrace` or `caller`, find the
|
99
|
+
# first owned file in it, useful for figuring out which file is being blamed.
|
100
|
+
sig { params(backtrace: T.nilable(T::Array[String]), excluded_teams: T::Array[::CodeTeams::Team]).returns(T.nilable([::CodeTeams::Team, String])) }
|
101
|
+
def first_owned_file_for_backtrace(backtrace, excluded_teams: [])
|
102
|
+
backtrace_with_ownership(backtrace).each do |(team, file)|
|
103
|
+
if team && !excluded_teams.include?(team)
|
104
|
+
return [team, file]
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
nil
|
109
|
+
end
|
110
|
+
|
111
|
+
sig { params(backtrace: T.nilable(T::Array[String])).returns(T::Enumerable[[T.nilable(::CodeTeams::Team), String]]) }
|
112
|
+
def backtrace_with_ownership(backtrace)
|
113
|
+
return [] unless backtrace
|
97
114
|
|
98
115
|
# The pattern for a backtrace hasn't changed in forever and is considered
|
99
116
|
# stable: https://github.com/ruby/ruby/blob/trunk/vm_backtrace.c#L303-L317
|
@@ -110,18 +127,19 @@ module CodeOwnership
|
|
110
127
|
`(?<function>.*)' # Matches "`block (3 levels) in create'"
|
111
128
|
\z}x
|
112
129
|
|
113
|
-
backtrace.
|
130
|
+
backtrace.lazy.filter_map do |line|
|
114
131
|
match = line.match(backtrace_line)
|
132
|
+
next unless match
|
115
133
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
134
|
+
file = T.must(match[:file])
|
135
|
+
|
136
|
+
[
|
137
|
+
CodeOwnership.for_file(file),
|
138
|
+
file,
|
139
|
+
]
|
122
140
|
end
|
123
|
-
nil
|
124
141
|
end
|
142
|
+
private_class_method(:backtrace_with_ownership)
|
125
143
|
|
126
144
|
sig { params(klass: T.nilable(T.any(Class, Module))).returns(T.nilable(::CodeTeams::Team)) }
|
127
145
|
def for_class(klass)
|
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.
|
4
|
+
version: 1.30.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gusto Engineers
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-02-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: code_teams
|
@@ -148,6 +148,7 @@ files:
|
|
148
148
|
- lib/code_ownership/private/validations/files_have_unique_owners.rb
|
149
149
|
- lib/code_ownership/private/validations/github_codeowners_up_to_date.rb
|
150
150
|
- lib/code_ownership/private/validations/interface.rb
|
151
|
+
- lib/code_ownership/private/validations/no_overlapping_globs.rb
|
151
152
|
- sorbet/config
|
152
153
|
- sorbet/rbi/gems/code_teams@1.0.0.rbi
|
153
154
|
- sorbet/rbi/gems/packs@0.0.2.rbi
|