Skip to content

Commit 4cd1711

Browse files
authored
Merge pull request #56 from github/team-improvements
Team Improvements
2 parents c95e417 + 4555b4b commit 4cd1711

File tree

11 files changed

+195
-128
lines changed

11 files changed

+195
-128
lines changed

Gemfile.lock

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
PATH
22
remote: .
33
specs:
4-
entitlements-github-plugin (0.6.0)
4+
entitlements-github-plugin (0.7.0)
55
contracts (~> 0.17.0)
66
faraday (~> 2.0)
77
faraday-retry (~> 2.0)
@@ -34,7 +34,7 @@ GEM
3434
diff-lcs (1.5.1)
3535
docile (1.4.0)
3636
drb (2.2.1)
37-
entitlements-app (0.3.1)
37+
entitlements-app (0.3.3)
3838
concurrent-ruby (= 1.1.9)
3939
faraday (~> 2.0)
4040
net-ldap (~> 0.17)
@@ -64,6 +64,7 @@ GEM
6464
parser (3.3.0.5)
6565
ast (~> 2.4.1)
6666
racc
67+
prism (0.29.0)
6768
public_suffix (5.0.5)
6869
racc (1.7.3)
6970
rack (3.0.10)
@@ -110,6 +111,10 @@ GEM
110111
rack (>= 1.1)
111112
rubocop (>= 1.33.0, < 2.0)
112113
rubocop-ast (>= 1.31.1, < 2.0)
114+
ruby-lsp (0.16.7)
115+
language_server-protocol (~> 3.17.0)
116+
prism (>= 0.29.0, < 0.30)
117+
sorbet-runtime (>= 0.5.10782)
113118
ruby-progressbar (1.13.0)
114119
rugged (1.7.2)
115120
sawyer (0.9.2)
@@ -123,6 +128,7 @@ GEM
123128
simplecov (< 1.0)
124129
simplecov-html (0.12.3)
125130
simplecov_json_formatter (0.1.4)
131+
sorbet-runtime (0.5.11388)
126132
strscan (3.1.0)
127133
tzinfo (2.0.6)
128134
concurrent-ruby (~> 1.0)
@@ -146,6 +152,7 @@ DEPENDENCIES
146152
rubocop (= 1.63.3)
147153
rubocop-github (= 0.20.0)
148154
rubocop-performance (= 1.21.0)
155+
ruby-lsp (~> 0.16.7)
149156
rugged (~> 1.7, >= 1.7.2)
150157
simplecov (= 0.22.0)
151158
simplecov-erb (= 1.0.1)

entitlements-github-plugin.gemspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Gem::Specification.new do |s|
2626
s.add_development_dependency "rubocop", "= 1.63.3"
2727
s.add_development_dependency "rubocop-github", "= 0.20.0"
2828
s.add_development_dependency "rubocop-performance", "= 1.21.0"
29+
s.add_development_dependency "ruby-lsp", "~> 0.16.7"
2930
s.add_development_dependency "rugged", "~> 1.7", ">= 1.7.2"
3031
s.add_development_dependency "simplecov", "= 0.22.0"
3132
s.add_development_dependency "simplecov-erb", "= 1.0.1"

lib/entitlements/backend/github_team/service.rb

Lines changed: 55 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class TeamNotFound < RuntimeError; end
3232
ou: String,
3333
ignore_not_found: C::Maybe[C::Bool],
3434
] => C::Any
35-
def initialize(addr: nil, org:, token:, ou:, ignore_not_found: false)
35+
def initialize(org:, token:, ou:, addr: nil, ignore_not_found: false)
3636
super
3737
Entitlements.cache[:github_team_members] ||= {}
3838
Entitlements.cache[:github_team_members][org_signature] ||= {}
@@ -107,8 +107,8 @@ def read_team(entitlement_group)
107107
end
108108

109109
maintainers = teamdata[:members].select { |u| teamdata[:roles][u] == "maintainer" }
110-
team_metadata = team_metadata || {}
111-
team_metadata = team_metadata.merge({"team_maintainers" => maintainers.any? ? maintainers.join(",") : nil})
110+
team_metadata ||= {}
111+
team_metadata = team_metadata.merge({ "team_maintainers" => maintainers.any? ? maintainers.join(",") : nil })
112112

113113
team = Entitlements::Backend::GitHubTeam::Models::Team.new(
114114
team_id: teamdata[:team_id],
@@ -139,7 +139,7 @@ def read_team(entitlement_group)
139139
def from_predictive_cache?(entitlement_group)
140140
team_identifier = entitlement_group.cn.downcase
141141
read_team(entitlement_group) unless @team_cache[team_identifier]
142-
(@team_cache[team_identifier] && @team_cache[team_identifier][:cache]) ? true : false
142+
@team_cache[team_identifier] && @team_cache[team_identifier][:cache] ? true : false
143143
end
144144

145145
# Declare the entry to be invalid for a specific team, and if the prior knowledge
@@ -192,7 +192,7 @@ def sync_team(desired_state, current_state)
192192
if desired_metadata["parent_team_name"].nil?
193193
Entitlements.logger.debug "sync_team(team=#{current_state.team_name}): IGNORING GitHub Parent Team DELETE"
194194
else
195-
# :nocov:
195+
# :nocov:
196196
Entitlements.logger.debug "sync_team(#{current_state.team_name}=#{current_state.team_id}): Parent team change found - From #{current_metadata["parent_team_name"] || "No Parent Team"} to #{desired_metadata["parent_team_name"]}"
197197
desired_parent_team_id = team_by_name(org_name: org, team_name: desired_metadata["parent_team_name"])[:id]
198198
unless desired_parent_team_id.nil?
@@ -240,17 +240,20 @@ def sync_team(desired_state, current_state)
240240
Entitlements.logger.debug "sync_team(#{current_state.team_name}=#{current_state.team_id}): Textual change but no semantic change in maintainers. It is remains: #{current_maintainers.to_a}."
241241
else
242242
Entitlements.logger.debug "sync_team(#{current_state.team_name}=#{current_state.team_id}): Maintainer members change found - From #{current_maintainers.to_a} to #{desired_maintainers.to_a}"
243-
added_maintainers.select! { |username| add_user_to_team(user: username, team: current_state, role: "maintainer") }
243+
added_maintainers.select! do |username|
244+
add_user_to_team(user: username, team: current_state, role: "maintainer")
245+
end
244246

245247
## We only touch previous maintainers who are actually still going to be members of the team
246248
removed_maintainers = removed_maintainers.intersection(desired_team_members)
247249
## Downgrade membership to default (role: "member")
248-
removed_maintainers.select! { |username| add_user_to_team(user: username, team: current_state, role: "member") }
250+
removed_maintainers.select! do |username|
251+
add_user_to_team(user: username, team: current_state, role: "member")
252+
end
249253
end
250254
end
251255
end
252256

253-
254257
Entitlements.logger.debug "sync_team(#{current_state.team_name}=#{current_state.team_id}): Added #{added_members.count}, removed #{removed_members.count}"
255258
added_members.any? || removed_members.any? || added_maintainers.any? || removed_maintainers.any? || changed_parent_team
256259
end
@@ -264,28 +267,41 @@ def sync_team(desired_state, current_state)
264267
entitlement_group: Entitlements::Models::Group,
265268
] => C::Bool
266269
def create_team(entitlement_group:)
270+
team_name = entitlement_group.cn.downcase
271+
team_options = { name: team_name, repo_names: [], privacy: "closed" }
272+
267273
begin
268-
team_name = entitlement_group.cn.downcase
269-
team_options = { name: team_name, repo_names: [], privacy: "closed" }
274+
entitlement_metadata = entitlement_group.metadata
275+
unless entitlement_metadata["parent_team_name"].nil?
270276

271-
begin
272-
entitlement_metadata = entitlement_group.metadata
273-
unless entitlement_metadata["parent_team_name"].nil?
277+
begin
274278
parent_team_data = graphql_team_data(entitlement_metadata["parent_team_name"])
275279
team_options[:parent_team_id] = parent_team_data[:team_id]
276-
Entitlements.logger.debug "create_team(team=#{team_name}) Parent team #{entitlement_metadata["parent_team_name"]} with id #{parent_team_data[:team_id]} found"
280+
rescue TeamNotFound
281+
# if the parent team does not exist, create it (think `mkdir -p` logic here)
282+
result = octokit.create_team(
283+
org,
284+
{ name: entitlement_metadata["parent_team_name"], repo_names: [], privacy: "closed" }
285+
)
286+
287+
Entitlements.logger.debug "created parent team #{entitlement_metadata["parent_team_name"]} with id #{result[:id]}"
288+
289+
team_options[:parent_team_id] = result[:id]
277290
end
278-
rescue Entitlements::Models::Group::NoMetadata
279-
Entitlements.logger.debug "create_team(team=#{team_name}) No metadata found"
280-
end
281291

282-
Entitlements.logger.debug "create_team(team=#{team_name})"
283-
octokit.create_team(org, team_options)
284-
true
285-
rescue Octokit::UnprocessableEntity => e
286-
Entitlements.logger.debug "create_team(team=#{team_name}) ERROR - #{e.message}"
287-
false
292+
Entitlements.logger.debug "create_team(team=#{team_name}) Parent team #{entitlement_metadata["parent_team_name"]} with id #{team_options[:parent_team_id]} found"
293+
end
294+
rescue Entitlements::Models::Group::NoMetadata
295+
Entitlements.logger.debug "create_team(team=#{team_name}) No metadata found"
288296
end
297+
298+
Entitlements.logger.debug "create_team(team=#{team_name})"
299+
result = octokit.create_team(org, team_options)
300+
Entitlements.logger.debug "created team #{team_name} with id #{result[:id]}"
301+
true
302+
rescue Octokit::UnprocessableEntity => e
303+
Entitlements.logger.debug "create_team(team=#{team_name}) ERROR - #{e.message}"
304+
false
289305
end
290306

291307
# Update a team
@@ -298,15 +314,14 @@ def create_team(entitlement_group:)
298314
metadata: C::Or[Hash, nil]
299315
] => C::Bool
300316
def update_team(team:, metadata: {})
301-
begin
302-
Entitlements.logger.debug "update_team(team=#{team.team_name})"
303-
options = { name: team.team_name, repo_names: [], privacy: "closed", parent_team_id: metadata[:parent_team_id] }
304-
octokit.update_team(team.team_id, options)
305-
true
306-
rescue Octokit::UnprocessableEntity => e
307-
Entitlements.logger.debug "update_team(team=#{team.team_name}) ERROR - #{e.message}"
308-
false
309-
end
317+
Entitlements.logger.debug "update_team(team=#{team.team_name})"
318+
options = { name: team.team_name, repo_names: [], privacy: "closed",
319+
parent_team_id: metadata[:parent_team_id] }
320+
octokit.update_team(team.team_id, options)
321+
true
322+
rescue Octokit::UnprocessableEntity => e
323+
Entitlements.logger.debug "update_team(team=#{team.team_name}) ERROR - #{e.message}"
324+
false
310325
end
311326

312327
# Gets a team by name
@@ -332,7 +347,8 @@ def team_by_name(org_name:, team_name:)
332347
# team_slug - Identifier of the team to retrieve.
333348
#
334349
# Returns a data structure with team data.
335-
Contract String => { members: C::ArrayOf[String], team_id: Integer, parent_team_name: C::Or[String, nil], roles: C::HashOf[String => String] }
350+
Contract String => { members: C::ArrayOf[String], team_id: Integer, parent_team_name: C::Or[String, nil],
351+
roles: C::HashOf[String => String] }
336352
def graphql_team_data(team_slug)
337353
cursor = nil
338354
team_id = nil
@@ -370,9 +386,7 @@ def graphql_team_data(team_slug)
370386
end
371387

372388
team = response[:data].fetch("data").fetch("organization").fetch("team")
373-
if team.nil?
374-
raise TeamNotFound, "Requested team #{team_slug} does not exist in #{org}!"
375-
end
389+
raise TeamNotFound, "Requested team #{team_slug} does not exist in #{org}!" if team.nil?
376390

377391
team_id = team.fetch("databaseId")
378392
parent_team_name = team.dig("parentTeam", "slug")
@@ -390,6 +404,7 @@ def graphql_team_data(team_slug)
390404

391405
cursor = edges.last.fetch("cursor")
392406
next if cursor && buffer.size == max_graphql_results
407+
393408
break
394409
end
395410

@@ -415,6 +430,7 @@ def validate_team_id_and_slug!(team_id, team_slug)
415430
team_data[:slug]
416431
end
417432
return if @validation_cache[team_id] == team_slug
433+
418434
raise "validate_team_id_and_slug! mismatch: team_id=#{team_id} expected=#{team_slug.inspect} got=#{@validation_cache[team_id].inspect}"
419435
end
420436

@@ -432,10 +448,11 @@ def validate_team_id_and_slug!(team_id, team_slug)
432448
] => C::Bool
433449
def add_user_to_team(user:, team:, role: "member")
434450
return false unless org_members.include?(user.downcase)
435-
unless role == "member" || role == "maintainer"
451+
unless ["member", "maintainer"].include?(role)
436452
# :nocov:
437453
raise "add_user_to_team role mismatch: team_id=#{team.team_id} user=#{user} expected role=maintainer/member got=#{role}"
438454
end
455+
439456
Entitlements.logger.debug "#{identifier} add_user_to_team(user=#{user}, org=#{org}, team_id=#{team.team_id}, role=#{role})"
440457
validate_team_id_and_slug!(team.team_id, team.team_name)
441458

@@ -462,6 +479,7 @@ def add_user_to_team(user:, team:, role: "member")
462479
] => C::Bool
463480
def remove_user_from_team(user:, team:)
464481
return false unless org_members.include?(user.downcase)
482+
465483
Entitlements.logger.debug "#{identifier} remove_user_from_team(user=#{user}, org=#{org}, team_id=#{team.team_id})"
466484
validate_team_id_and_slug!(team.team_id, team.team_name)
467485
octokit.remove_team_membership(team.team_id, user)

lib/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22

33
module Entitlements
44
module Version
5-
VERSION = "0.6.0"
5+
VERSION = "0.7.0"
66
end
77
end

spec/acceptance/github-server/web.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,8 @@ def graphql_pending_query(query)
377377
File.open(TEAM_MAP_FILE, "w") do |f|
378378
f.write(JSON.pretty_generate(tmp_map))
379379
end
380-
halt 201
380+
381+
[201, { "Content-Type" => "application/json" }, [JSON.generate(teamdata)]]
381382
end
382383

383384
send :get, "/orgs/:org_name/teams/:team_name" do

0 commit comments

Comments
 (0)