danger-packwerk 0.7.1 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,60 @@
1
+ # typed: strict
2
+
3
+ require 'code_ownership'
4
+
5
+ module DangerPackwerk
6
+ module Private
7
+ class OwnershipInformation < T::Struct
8
+ extend T::Sig
9
+
10
+ const :owning_team, T.nilable(CodeTeams::Team)
11
+ const :github_team, T.nilable(String)
12
+ const :slack_channel, T.nilable(String)
13
+ const :org_name, T.nilable(String)
14
+
15
+ sig { params(package: ParsePackwerk::Package, org_name: String).returns(OwnershipInformation) }
16
+ def self.for_package(package, org_name)
17
+ team = CodeOwnership.for_package(package)
18
+
19
+ if team.nil?
20
+ OwnershipInformation.new
21
+ else
22
+ OwnershipInformation.new(
23
+ owning_team: team,
24
+ github_team: team.raw_hash.fetch('github', {}).fetch('team', nil),
25
+ slack_channel: team.raw_hash.fetch('slack', {}).fetch('room_for_humans', nil),
26
+ org_name: org_name
27
+ )
28
+ end
29
+ end
30
+
31
+ sig { returns(String) }
32
+ def ownership_copy
33
+ github_team_flow_sensitive = github_team
34
+ slack_channel_flow_sensitive = slack_channel
35
+
36
+ if owning_team && github_team_flow_sensitive && slack_channel_flow_sensitive
37
+ team_slack_link = markdown_link_to_slack_room
38
+ "- Owned by #{markdown_link_to_github_members_no_tag} (Slack: #{team_slack_link})"
39
+ else
40
+ '- This pack is unowned.'
41
+ end
42
+ end
43
+
44
+ sig { returns(String) }
45
+ def markdown_link_to_slack_room
46
+ "[<ins>#{slack_channel}</ins>](https://slack.com/app_redirect?channel=#{T.must(slack_channel).delete('#')})"
47
+ end
48
+
49
+ #
50
+ # Note this will NOT tag the team on Github, but it will link
51
+ # to the mentioned team's members page. If you want to tag and
52
+ # link the team, simply use the string and Github will handle it.
53
+ #
54
+ sig { returns(String) }
55
+ def markdown_link_to_github_members_no_tag
56
+ "[<ins>#{github_team}</ins>](https://github.com/orgs/#{org_name}/teams/#{T.must(github_team).gsub("@#{org_name}/", '')}/members)"
57
+ end
58
+ end
59
+ end
60
+ end
@@ -3,7 +3,7 @@
3
3
  module DangerPackwerk
4
4
  module Private
5
5
  #
6
- # The `Violation` and `DeprecatedReferences` classes come from Gusto's private `ParsePackwerk` gem.
6
+ # The `Violation` and `PackageTodo` classes come from Gusto's private `ParsePackwerk` gem.
7
7
  # Until we decide to open source that gem, we inline these as a private implementation detail of `DangerPackwerk` for now.
8
8
  #
9
9
  class Violation < T::Struct
@@ -25,22 +25,22 @@ module DangerPackwerk
25
25
  end
26
26
  end
27
27
 
28
- class DeprecatedReferences < T::Struct
28
+ class PackageTodo < T::Struct
29
29
  extend T::Sig
30
30
 
31
31
  const :pathname, Pathname
32
32
  const :violations, T::Array[Violation]
33
33
 
34
- sig { params(pathname: Pathname).returns(DeprecatedReferences) }
34
+ sig { params(pathname: Pathname).returns(PackageTodo) }
35
35
  def self.from(pathname)
36
36
  if pathname.exist?
37
- deprecated_references_loaded_yml = YAML.load_file(pathname)
37
+ package_todo_loaded_yml = YAML.load_file(pathname)
38
38
 
39
39
  all_violations = []
40
- deprecated_references_loaded_yml&.each_key do |to_package_name|
41
- deprecated_references_per_package = deprecated_references_loaded_yml[to_package_name]
42
- deprecated_references_per_package.each_key do |class_name|
43
- symbol_usage = deprecated_references_per_package[class_name]
40
+ package_todo_loaded_yml&.each_key do |to_package_name|
41
+ package_todo_per_package = package_todo_loaded_yml[to_package_name]
42
+ package_todo_per_package.each_key do |class_name|
43
+ symbol_usage = package_todo_per_package[class_name]
44
44
  files = symbol_usage['files']
45
45
  violations = symbol_usage['violations']
46
46
  all_violations << Violation.new(type: 'dependency', to_package_name: to_package_name, class_name: class_name, files: files) if violations.include? 'dependency'
@@ -1,7 +1,7 @@
1
1
  # typed: strict
2
2
 
3
- require 'danger-packwerk/private/deprecated_references'
4
- require 'danger-packwerk/private/default_offenses_formatter'
3
+ require 'danger-packwerk/private/package_todo'
4
+ require 'danger-packwerk/private/ownership_information'
5
5
  require 'constant_resolver'
6
6
 
7
7
  module DangerPackwerk
@@ -0,0 +1,67 @@
1
+ # typed: strict
2
+
3
+ module DangerPackwerk
4
+ module Update
5
+ class DefaultFormatter
6
+ extend T::Sig
7
+ include OffensesFormatter
8
+
9
+ sig do
10
+ params(
11
+ custom_help_message: T.nilable(String)
12
+ ).void
13
+ end
14
+ def initialize(custom_help_message: nil)
15
+ @custom_help_message = custom_help_message
16
+ end
17
+
18
+ sig { override.params(offenses: T::Array[BasicReferenceOffense], repo_link: String, org_name: String).returns(String) }
19
+ def format_offenses(offenses, repo_link, org_name)
20
+ violation = T.must(offenses.first)
21
+ referencing_file_pack = ParsePackwerk.package_from_path(violation.file)
22
+ # We remove leading double colons as they feel like an implementation detail of packwerk.
23
+ constant_name = violation.class_name.delete_prefix('::')
24
+ constant_source_package_name = violation.to_package_name
25
+
26
+ constant_source_package = T.must(ParsePackwerk.find(constant_source_package_name))
27
+ constant_source_package_owner = Private::OwnershipInformation.for_package(constant_source_package, org_name)
28
+
29
+ package_referring_to_constant_owner = Private::OwnershipInformation.for_package(referencing_file_pack, org_name)
30
+
31
+ disclaimer = 'We noticed you ran `bin/packwerk update-deprecations`. Check out [the docs](https://github.com/Shopify/packwerk/blob/main/RESOLVING_VIOLATIONS.md) to see other ways to resolve violations.'
32
+ pluralized_violation = offenses.count > 1 ? 'these violations' : 'this violation'
33
+ request_to_add_context = "- Could you add some context as a reply here about why we needed to add #{pluralized_violation}?\n"
34
+
35
+ dependency_violation_message = "- cc #{package_referring_to_constant_owner.github_team} (#{package_referring_to_constant_owner.markdown_link_to_slack_room}) for the dependency violation.\n" if package_referring_to_constant_owner.owning_team
36
+
37
+ privacy_violation_message = "- cc #{constant_source_package_owner.github_team} (#{constant_source_package_owner.markdown_link_to_slack_room}) for the privacy violation.\n" if constant_source_package_owner.owning_team
38
+
39
+ if offenses.any?(&:dependency?) && offenses.any?(&:privacy?)
40
+ <<~MESSAGE.chomp
41
+ Hi again! It looks like `#{constant_name}` is private API of `#{constant_source_package_name}`, which is also not in `#{referencing_file_pack.name}`'s list of dependencies.
42
+ #{disclaimer}
43
+
44
+ #{request_to_add_context}#{dependency_violation_message}#{privacy_violation_message}
45
+ #{@custom_help_message}
46
+ MESSAGE
47
+ elsif offenses.any?(&:dependency?)
48
+ <<~MESSAGE.chomp
49
+ Hi again! It looks like `#{constant_name}` belongs to `#{constant_source_package_name}`, which is not in `#{referencing_file_pack.name}`'s list of dependencies.
50
+ #{disclaimer}
51
+
52
+ #{request_to_add_context}#{dependency_violation_message}
53
+ #{@custom_help_message}
54
+ MESSAGE
55
+ else # violations.any?(&:privacy?)
56
+ <<~MESSAGE.chomp
57
+ Hi again! It looks like `#{constant_name}` is private API of `#{constant_source_package_name}`.
58
+ #{disclaimer}
59
+
60
+ #{request_to_add_context}#{privacy_violation_message}
61
+ #{@custom_help_message}
62
+ MESSAGE
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,23 @@
1
+ # typed: strict
2
+
3
+ require 'code_ownership'
4
+
5
+ module DangerPackwerk
6
+ module Update
7
+ module OffensesFormatter
8
+ extend T::Sig
9
+ extend T::Helpers
10
+
11
+ interface!
12
+
13
+ sig do
14
+ abstract.params(
15
+ offenses: T::Array[BasicReferenceOffense],
16
+ repo_link: String,
17
+ org_name: String
18
+ ).returns(String)
19
+ end
20
+ def format_offenses(offenses, repo_link, org_name); end
21
+ end
22
+ end
23
+ end
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module DangerPackwerk
5
- VERSION = '0.7.1'
5
+ VERSION = '0.9.0'
6
6
  end
@@ -5,8 +5,14 @@
5
5
  require 'sorbet-runtime'
6
6
 
7
7
  module DangerPackwerk
8
- DEPRECATED_REFERENCES_PATTERN = T.let(/.*?deprecated_references\.yml\z/.freeze, Regexp)
8
+ PACKAGE_TODO_PATTERN = T.let(/.*?package_todo\.yml\z/.freeze, Regexp)
9
+ DEPENDENCY_VIOLATION_TYPE = 'dependency'
10
+ PRIVACY_VIOLATION_TYPE = 'privacy'
9
11
 
10
12
  require 'danger-packwerk/danger_packwerk'
11
- require 'danger-packwerk/danger_deprecated_references_yml_changes'
13
+ require 'danger-packwerk/danger_package_todo_yml_changes'
14
+ require 'danger-packwerk/check/offenses_formatter'
15
+ require 'danger-packwerk/check/default_formatter'
16
+ require 'danger-packwerk/update/offenses_formatter'
17
+ require 'danger-packwerk/update/default_formatter'
12
18
  end
@@ -0,0 +1,336 @@
1
+ # typed: true
2
+
3
+ # DO NOT EDIT MANUALLY
4
+ # This is an autogenerated file for types exported from the `code_ownership` gem.
5
+ # Please instead update this file by running `bin/tapioca gem code_ownership`.
6
+
7
+ module CodeOwnership
8
+ extend ::CodeOwnership
9
+
10
+ requires_ancestor { Kernel }
11
+
12
+ sig do
13
+ params(
14
+ backtrace: T.nilable(T::Array[::String]),
15
+ excluded_teams: T::Array[::CodeTeams::Team]
16
+ ).returns(T.nilable(::CodeTeams::Team))
17
+ end
18
+ def for_backtrace(backtrace, excluded_teams: T.unsafe(nil)); end
19
+
20
+ sig { params(klass: T.nilable(T.any(::Class, ::Module))).returns(T.nilable(::CodeTeams::Team)) }
21
+ def for_class(klass); end
22
+
23
+ sig { params(file: ::String).returns(T.nilable(::CodeTeams::Team)) }
24
+ def for_file(file); end
25
+
26
+ sig { params(package: ::ParsePackwerk::Package).returns(T.nilable(::CodeTeams::Team)) }
27
+ def for_package(package); end
28
+
29
+ sig { params(team: T.any(::CodeTeams::Team, ::String)).returns(::String) }
30
+ def for_team(team); end
31
+
32
+ sig { params(files: T::Array[::String], autocorrect: T::Boolean, stage_changes: T::Boolean).void }
33
+ def validate!(files: T.unsafe(nil), autocorrect: T.unsafe(nil), stage_changes: T.unsafe(nil)); end
34
+
35
+ class << self
36
+ sig { void }
37
+ def bust_caches!; end
38
+
39
+ sig { params(filename: ::String).void }
40
+ def remove_file_annotation!(filename); end
41
+ end
42
+ end
43
+
44
+ class CodeOwnership::Cli
45
+ class << self
46
+ def for_file(argv); end
47
+ def for_team(argv); end
48
+ def run!(argv); end
49
+
50
+ private
51
+
52
+ def validate!(argv); end
53
+ end
54
+ end
55
+
56
+ class CodeOwnership::InvalidCodeOwnershipConfigurationError < ::StandardError; end
57
+
58
+ module CodeOwnership::Private
59
+ class << self
60
+ sig { void }
61
+ def bust_caches!; end
62
+
63
+ sig { returns(::CodeOwnership::Private::Configuration) }
64
+ def configuration; end
65
+
66
+ sig { returns(::CodeOwnership::Private::OwnershipMappers::FileAnnotations) }
67
+ def file_annotations_mapper; end
68
+
69
+ sig { params(files: T::Array[::String]).returns(T::Hash[::String, T::Array[::String]]) }
70
+ def files_by_mapper(files); end
71
+
72
+ sig { params(team_name: ::String, location_of_reference: ::String).returns(::CodeTeams::Team) }
73
+ def find_team!(team_name, location_of_reference); end
74
+
75
+ sig { returns(T::Array[::CodeOwnership::Private::OwnershipMappers::Interface]) }
76
+ def mappers; end
77
+
78
+ sig { params(klass: T.nilable(T.any(::Class, ::Module))).returns(T.nilable(::String)) }
79
+ def path_from_klass(klass); end
80
+
81
+ sig { returns(T::Array[::String]) }
82
+ def tracked_files; end
83
+
84
+ sig { params(files: T::Array[::String], autocorrect: T::Boolean, stage_changes: T::Boolean).void }
85
+ def validate!(files:, autocorrect: T.unsafe(nil), stage_changes: T.unsafe(nil)); end
86
+ end
87
+ end
88
+
89
+ class CodeOwnership::Private::Configuration < ::T::Struct
90
+ const :js_package_paths, T::Array[::String]
91
+ const :owned_globs, T::Array[::String]
92
+ const :skip_codeowners_validation, T::Boolean
93
+ const :unowned_globs, T::Array[::String]
94
+
95
+ class << self
96
+ sig { returns(::CodeOwnership::Private::Configuration) }
97
+ def fetch; end
98
+
99
+ def inherited(s); end
100
+
101
+ sig { params(config_hash: T::Hash[T.untyped, T.untyped]).returns(T::Array[::String]) }
102
+ def js_package_paths(config_hash); end
103
+ end
104
+ end
105
+
106
+ CodeOwnership::Private::Configuration::DEFAULT_JS_PACKAGE_PATHS = T.let(T.unsafe(nil), Array)
107
+ module CodeOwnership::Private::OwnershipMappers; end
108
+
109
+ class CodeOwnership::Private::OwnershipMappers::FileAnnotations
110
+ include ::CodeOwnership::Private::OwnershipMappers::Interface
111
+
112
+ sig { override.void }
113
+ def bust_caches!; end
114
+
115
+ sig { override.returns(T::Hash[::String, T.nilable(::CodeTeams::Team)]) }
116
+ def codeowners_lines_to_owners; end
117
+
118
+ sig { override.returns(::String) }
119
+ def description; end
120
+
121
+ sig { params(filename: ::String).returns(T.nilable(::CodeTeams::Team)) }
122
+ def file_annotation_based_owner(filename); end
123
+
124
+ sig { override.params(file: ::String).returns(T.nilable(::CodeTeams::Team)) }
125
+ def map_file_to_owner(file); end
126
+
127
+ sig { override.params(files: T::Array[::String]).returns(T::Hash[::String, T.nilable(::CodeTeams::Team)]) }
128
+ def map_files_to_owners(files); end
129
+
130
+ sig { params(filename: ::String).void }
131
+ def remove_file_annotation!(filename); end
132
+ end
133
+
134
+ CodeOwnership::Private::OwnershipMappers::FileAnnotations::TEAM_PATTERN = T.let(T.unsafe(nil), Regexp)
135
+
136
+ module CodeOwnership::Private::OwnershipMappers::Interface
137
+ interface!
138
+
139
+ sig { abstract.void }
140
+ def bust_caches!; end
141
+
142
+ sig { abstract.returns(T::Hash[::String, T.nilable(::CodeTeams::Team)]) }
143
+ def codeowners_lines_to_owners; end
144
+
145
+ sig { abstract.returns(::String) }
146
+ def description; end
147
+
148
+ sig { abstract.params(file: ::String).returns(T.nilable(::CodeTeams::Team)) }
149
+ def map_file_to_owner(file); end
150
+
151
+ sig { abstract.params(files: T::Array[::String]).returns(T::Hash[::String, T.nilable(::CodeTeams::Team)]) }
152
+ def map_files_to_owners(files); end
153
+ end
154
+
155
+ class CodeOwnership::Private::OwnershipMappers::JsPackageOwnership
156
+ include ::CodeOwnership::Private::OwnershipMappers::Interface
157
+
158
+ sig { override.void }
159
+ def bust_caches!; end
160
+
161
+ sig { override.returns(T::Hash[::String, T.nilable(::CodeTeams::Team)]) }
162
+ def codeowners_lines_to_owners; end
163
+
164
+ sig { override.returns(::String) }
165
+ def description; end
166
+
167
+ sig { override.params(file: ::String).returns(T.nilable(::CodeTeams::Team)) }
168
+ def map_file_to_owner(file); end
169
+
170
+ sig { override.params(files: T::Array[::String]).returns(T::Hash[::String, T.nilable(::CodeTeams::Team)]) }
171
+ def map_files_to_owners(files); end
172
+
173
+ sig { params(package: ::CodeOwnership::Private::ParseJsPackages::Package).returns(T.nilable(::CodeTeams::Team)) }
174
+ def owner_for_package(package); end
175
+
176
+ private
177
+
178
+ sig { params(file: ::String).returns(T.nilable(::CodeOwnership::Private::ParseJsPackages::Package)) }
179
+ def map_file_to_relevant_package(file); end
180
+ end
181
+
182
+ class CodeOwnership::Private::OwnershipMappers::PackageOwnership
183
+ include ::CodeOwnership::Private::OwnershipMappers::Interface
184
+
185
+ sig { override.void }
186
+ def bust_caches!; end
187
+
188
+ sig { override.returns(T::Hash[::String, T.nilable(::CodeTeams::Team)]) }
189
+ def codeowners_lines_to_owners; end
190
+
191
+ sig { override.returns(::String) }
192
+ def description; end
193
+
194
+ sig { override.params(file: ::String).returns(T.nilable(::CodeTeams::Team)) }
195
+ def map_file_to_owner(file); end
196
+
197
+ sig { override.params(files: T::Array[::String]).returns(T::Hash[::String, T.nilable(::CodeTeams::Team)]) }
198
+ def map_files_to_owners(files); end
199
+
200
+ sig { params(package: ::ParsePackwerk::Package).returns(T.nilable(::CodeTeams::Team)) }
201
+ def owner_for_package(package); end
202
+ end
203
+
204
+ class CodeOwnership::Private::OwnershipMappers::TeamGlobs
205
+ include ::CodeOwnership::Private::OwnershipMappers::Interface
206
+
207
+ sig { override.void }
208
+ def bust_caches!; end
209
+
210
+ sig { override.returns(T::Hash[::String, T.nilable(::CodeTeams::Team)]) }
211
+ def codeowners_lines_to_owners; end
212
+
213
+ sig { override.returns(::String) }
214
+ def description; end
215
+
216
+ sig { override.params(file: ::String).returns(T.nilable(::CodeTeams::Team)) }
217
+ def map_file_to_owner(file); end
218
+
219
+ sig { override.params(files: T::Array[::String]).returns(T::Hash[::String, T.nilable(::CodeTeams::Team)]) }
220
+ def map_files_to_owners(files); end
221
+ end
222
+
223
+ module CodeOwnership::Private::ParseJsPackages
224
+ class << self
225
+ sig { returns(T::Array[::CodeOwnership::Private::ParseJsPackages::Package]) }
226
+ def all; end
227
+ end
228
+ end
229
+
230
+ CodeOwnership::Private::ParseJsPackages::METADATA = T.let(T.unsafe(nil), String)
231
+ CodeOwnership::Private::ParseJsPackages::PACKAGE_JSON_NAME = T.let(T.unsafe(nil), String)
232
+
233
+ class CodeOwnership::Private::ParseJsPackages::Package < ::T::Struct
234
+ const :metadata, T::Hash[::String, T.untyped]
235
+ const :name, ::String
236
+
237
+ sig { returns(::Pathname) }
238
+ def directory; end
239
+
240
+ class << self
241
+ sig { params(pathname: ::Pathname).returns(::CodeOwnership::Private::ParseJsPackages::Package) }
242
+ def from(pathname); end
243
+
244
+ def inherited(s); end
245
+ end
246
+ end
247
+
248
+ CodeOwnership::Private::ParseJsPackages::ROOT_PACKAGE_NAME = T.let(T.unsafe(nil), String)
249
+ module CodeOwnership::Private::TeamPlugins; end
250
+
251
+ class CodeOwnership::Private::TeamPlugins::Github < ::CodeTeams::Plugin
252
+ sig { returns(::CodeOwnership::Private::TeamPlugins::Github::GithubStruct) }
253
+ def github; end
254
+ end
255
+
256
+ class CodeOwnership::Private::TeamPlugins::Github::GithubStruct < ::Struct
257
+ def do_not_add_to_codeowners_file; end
258
+ def do_not_add_to_codeowners_file=(_); end
259
+ def team; end
260
+ def team=(_); end
261
+
262
+ class << self
263
+ def [](*_arg0); end
264
+ def inspect; end
265
+ def members; end
266
+ def new(*_arg0); end
267
+ end
268
+ end
269
+
270
+ class CodeOwnership::Private::TeamPlugins::Ownership < ::CodeTeams::Plugin
271
+ sig { returns(T::Array[::String]) }
272
+ def owned_globs; end
273
+ end
274
+
275
+ module CodeOwnership::Private::Validations; end
276
+
277
+ class CodeOwnership::Private::Validations::FilesHaveOwners
278
+ include ::CodeOwnership::Private::Validations::Interface
279
+
280
+ sig do
281
+ override
282
+ .params(
283
+ files: T::Array[::String],
284
+ autocorrect: T::Boolean,
285
+ stage_changes: T::Boolean
286
+ ).returns(T::Array[::String])
287
+ end
288
+ def validation_errors(files:, autocorrect: T.unsafe(nil), stage_changes: T.unsafe(nil)); end
289
+ end
290
+
291
+ class CodeOwnership::Private::Validations::FilesHaveUniqueOwners
292
+ include ::CodeOwnership::Private::Validations::Interface
293
+
294
+ sig do
295
+ override
296
+ .params(
297
+ files: T::Array[::String],
298
+ autocorrect: T::Boolean,
299
+ stage_changes: T::Boolean
300
+ ).returns(T::Array[::String])
301
+ end
302
+ def validation_errors(files:, autocorrect: T.unsafe(nil), stage_changes: T.unsafe(nil)); end
303
+ end
304
+
305
+ class CodeOwnership::Private::Validations::GithubCodeownersUpToDate
306
+ include ::CodeOwnership::Private::Validations::Interface
307
+
308
+ sig do
309
+ override
310
+ .params(
311
+ files: T::Array[::String],
312
+ autocorrect: T::Boolean,
313
+ stage_changes: T::Boolean
314
+ ).returns(T::Array[::String])
315
+ end
316
+ def validation_errors(files:, autocorrect: T.unsafe(nil), stage_changes: T.unsafe(nil)); end
317
+
318
+ private
319
+
320
+ sig { returns(T::Array[::String]) }
321
+ def codeowners_file_lines; end
322
+ end
323
+
324
+ module CodeOwnership::Private::Validations::Interface
325
+ interface!
326
+
327
+ sig do
328
+ abstract
329
+ .params(
330
+ files: T::Array[::String],
331
+ autocorrect: T::Boolean,
332
+ stage_changes: T::Boolean
333
+ ).returns(T::Array[::String])
334
+ end
335
+ def validation_errors(files:, autocorrect: T.unsafe(nil), stage_changes: T.unsafe(nil)); end
336
+ end
@@ -0,0 +1,120 @@
1
+ # typed: true
2
+
3
+ # DO NOT EDIT MANUALLY
4
+ # This is an autogenerated file for types exported from the `code_teams` gem.
5
+ # Please instead update this file by running `bin/tapioca gem code_teams`.
6
+
7
+ module CodeTeams
8
+ class << self
9
+ sig { returns(T::Array[::CodeTeams::Team]) }
10
+ def all; end
11
+
12
+ sig { void }
13
+ def bust_caches!; end
14
+
15
+ sig { params(name: ::String).returns(T.nilable(::CodeTeams::Team)) }
16
+ def find(name); end
17
+
18
+ sig { params(dir: ::String).returns(T::Array[::CodeTeams::Team]) }
19
+ def for_directory(dir); end
20
+
21
+ sig { params(string: ::String).returns(::String) }
22
+ def tag_value_for(string); end
23
+
24
+ sig { params(teams: T::Array[::CodeTeams::Team]).returns(T::Array[::String]) }
25
+ def validation_errors(teams); end
26
+ end
27
+ end
28
+
29
+ class CodeTeams::IncorrectPublicApiUsageError < ::StandardError; end
30
+
31
+ class CodeTeams::Plugin
32
+ abstract!
33
+
34
+ sig { params(team: ::CodeTeams::Team).void }
35
+ def initialize(team); end
36
+
37
+ class << self
38
+ sig { returns(T::Array[T.class_of(CodeTeams::Plugin)]) }
39
+ def all_plugins; end
40
+
41
+ sig { params(team: ::CodeTeams::Team).returns(T.attached_class) }
42
+ def for(team); end
43
+
44
+ sig { params(base: T.untyped).void }
45
+ def inherited(base); end
46
+
47
+ sig { params(team: ::CodeTeams::Team, key: ::String).returns(::String) }
48
+ def missing_key_error_message(team, key); end
49
+
50
+ sig { params(teams: T::Array[::CodeTeams::Team]).returns(T::Array[::String]) }
51
+ def validation_errors(teams); end
52
+
53
+ private
54
+
55
+ sig { params(team: ::CodeTeams::Team).returns(T.attached_class) }
56
+ def register_team(team); end
57
+
58
+ sig { returns(T::Hash[T.nilable(::String), T::Hash[::Class, ::CodeTeams::Plugin]]) }
59
+ def registry; end
60
+ end
61
+ end
62
+
63
+ module CodeTeams::Plugins; end
64
+
65
+ class CodeTeams::Plugins::Identity < ::CodeTeams::Plugin
66
+ sig { returns(::CodeTeams::Plugins::Identity::IdentityStruct) }
67
+ def identity; end
68
+
69
+ class << self
70
+ sig { override.params(teams: T::Array[::CodeTeams::Team]).returns(T::Array[::String]) }
71
+ def validation_errors(teams); end
72
+ end
73
+ end
74
+
75
+ class CodeTeams::Plugins::Identity::IdentityStruct < ::Struct
76
+ def name; end
77
+ def name=(_); end
78
+
79
+ class << self
80
+ def [](*_arg0); end
81
+ def inspect; end
82
+ def members; end
83
+ def new(*_arg0); end
84
+ end
85
+ end
86
+
87
+ class CodeTeams::Team
88
+ sig { params(config_yml: T.nilable(::String), raw_hash: T::Hash[T.untyped, T.untyped]).void }
89
+ def initialize(config_yml:, raw_hash:); end
90
+
91
+ sig { params(other: ::Object).returns(T::Boolean) }
92
+ def ==(other); end
93
+
94
+ sig { returns(T.nilable(::String)) }
95
+ def config_yml; end
96
+
97
+ def eql?(*args, &blk); end
98
+
99
+ sig { returns(::Integer) }
100
+ def hash; end
101
+
102
+ sig { returns(::String) }
103
+ def name; end
104
+
105
+ sig { returns(T::Hash[T.untyped, T.untyped]) }
106
+ def raw_hash; end
107
+
108
+ sig { returns(::String) }
109
+ def to_tag; end
110
+
111
+ class << self
112
+ sig { params(raw_hash: T::Hash[T.untyped, T.untyped]).returns(::CodeTeams::Team) }
113
+ def from_hash(raw_hash); end
114
+
115
+ sig { params(config_yml: ::String).returns(::CodeTeams::Team) }
116
+ def from_yml(config_yml); end
117
+ end
118
+ end
119
+
120
+ CodeTeams::UNKNOWN_TEAM_STRING = T.let(T.unsafe(nil), String)