-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathcode_teams.rb
More file actions
131 lines (107 loc) · 3.13 KB
/
code_teams.rb
File metadata and controls
131 lines (107 loc) · 3.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# frozen_string_literal: true
# typed: strict
require 'yaml'
require 'pathname'
require 'sorbet-runtime'
require 'code_teams/plugin'
require 'code_teams/plugins/identity'
module CodeTeams
extend T::Sig
class IncorrectPublicApiUsageError < StandardError; end
UNKNOWN_TEAM_STRING = 'Unknown Team'
sig { returns(T::Array[Team]) }
def self.all
@all = T.let(@all, T.nilable(T::Array[Team]))
@all ||= for_directory('config/teams')
end
sig { params(name: String).returns(T.nilable(Team)) }
def self.find(name)
@index_by_name = T.let(@index_by_name, T.nilable(T::Hash[String, CodeTeams::Team]))
@index_by_name ||= begin
result = {}
all.each { |t| result[t.name] = t }
result
end
@index_by_name[name]
end
sig { params(dir: String).returns(T::Array[Team]) }
def self.for_directory(dir)
Pathname.new(dir).glob('**/*.yml').map do |path|
Team.from_yml(path.to_s)
rescue Psych::SyntaxError
raise IncorrectPublicApiUsageError, "The YML in #{path} has a syntax error!"
end
end
sig { params(teams: T::Array[Team]).returns(T::Array[String]) }
def self.validation_errors(teams)
Plugin.all_plugins.flat_map do |plugin|
plugin.validation_errors(teams)
end
end
sig { params(string: String).returns(String) }
def self.tag_value_for(string)
string.tr('&', ' ').gsub(/\s+/, '_').downcase
end
# Generally, you should not ever need to do this, because once your ruby process loads, cached content should not change.
# Namely, the YML files that are the source of truth for teams should not change, so we should not need to look at the YMLs again to verify.
# The primary reason this is helpful is for clients of CodeTeams who want to test their code, and each test context has different set of teams
sig { void }
def self.bust_caches!
Plugin.bust_caches!
@all = nil
@index_by_name = nil
end
class Team
extend T::Sig
sig { params(config_yml: String).returns(Team) }
def self.from_yml(config_yml)
hash = YAML.load_file(config_yml)
new(
config_yml: config_yml,
raw_hash: hash
)
end
sig { params(raw_hash: T::Hash[T.untyped, T.untyped]).returns(Team) }
def self.from_hash(raw_hash)
new(
config_yml: nil,
raw_hash: raw_hash
)
end
sig { returns(T::Hash[T.untyped, T.untyped]) }
attr_reader :raw_hash
sig { returns(T.nilable(String)) }
attr_reader :config_yml
sig do
params(
config_yml: T.nilable(String),
raw_hash: T::Hash[T.untyped, T.untyped]
).void
end
def initialize(config_yml:, raw_hash:)
@config_yml = config_yml
@raw_hash = raw_hash
end
sig { returns(String) }
def name
Plugins::Identity.for(self).identity.name
end
sig { returns(String) }
def to_tag
CodeTeams.tag_value_for(name)
end
sig { params(other: Object).returns(T::Boolean) }
def ==(other)
if other.is_a?(CodeTeams::Team)
name == other.name
else
false
end
end
alias eql? ==
sig { returns(Integer) }
def hash
name.hash
end
end
end