entitlements-github-plugin 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/VERSION +1 -0
- data/lib/entitlements/backend/github_org/controller.rb +468 -0
- data/lib/entitlements/backend/github_org/provider.rb +136 -0
- data/lib/entitlements/backend/github_org/service.rb +88 -0
- data/lib/entitlements/backend/github_org.rb +26 -0
- data/lib/entitlements/backend/github_team/controller.rb +126 -0
- data/lib/entitlements/backend/github_team/models/team.rb +36 -0
- data/lib/entitlements/backend/github_team/provider.rb +208 -0
- data/lib/entitlements/backend/github_team/service.rb +402 -0
- data/lib/entitlements/backend/github_team.rb +6 -0
- data/lib/entitlements/service/github.rb +394 -0
- metadata +325 -0
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../../service/github"
|
4
|
+
|
5
|
+
module Entitlements
|
6
|
+
class Backend
|
7
|
+
class GitHubOrg
|
8
|
+
class Service < Entitlements::Service::GitHub
|
9
|
+
include ::Contracts::Core
|
10
|
+
C = ::Contracts
|
11
|
+
|
12
|
+
# Sync the members of an organization in a given role to match the member list.
|
13
|
+
#
|
14
|
+
# implementation - An Hash of { action: :add/:remove, person: <person DN> }
|
15
|
+
# role - A String with the role, matching a key of Entitlements::Backend::GitHubOrg::ORGANIZATION_ROLES.
|
16
|
+
#
|
17
|
+
# Returns true if it succeeded, false if it did not.
|
18
|
+
Contract C::ArrayOf[{ action: C::Or[:add, :remove], person: String }], String => C::Bool
|
19
|
+
def sync(implementation, role)
|
20
|
+
added_members = []
|
21
|
+
removed_members = []
|
22
|
+
|
23
|
+
implementation.each do |instruction|
|
24
|
+
username = Entitlements::Util::Util.first_attr(instruction[:person]).downcase
|
25
|
+
if instruction[:action] == :add
|
26
|
+
added_members << username if add_user_to_organization(username, role)
|
27
|
+
else
|
28
|
+
removed_members << username if remove_user_from_organization(username)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
Entitlements.logger.debug "sync(#{role}): Added #{added_members.count}, removed #{removed_members.count}"
|
33
|
+
added_members.any? || removed_members.any?
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
# Upsert a user with a role to the organization.
|
39
|
+
#
|
40
|
+
# user: A String with the (GitHub) username of the person to add or modify.
|
41
|
+
# role: A String with the role, matching a key of Entitlements::Backend::GitHubOrg::ORGANIZATION_ROLES.
|
42
|
+
#
|
43
|
+
# Returns true if the user was added to the organization, false otherwise.
|
44
|
+
Contract String, String => C::Bool
|
45
|
+
def add_user_to_organization(user, role)
|
46
|
+
Entitlements.logger.debug "#{identifier} add_user_to_organization(user=#{user}, org=#{org}, role=#{role})"
|
47
|
+
new_membership = octokit.update_organization_membership(org, user: user, role: role)
|
48
|
+
|
49
|
+
# Happy path
|
50
|
+
if new_membership[:role] == role
|
51
|
+
if new_membership[:state] == "pending"
|
52
|
+
pending_members.add(user)
|
53
|
+
return true
|
54
|
+
elsif new_membership[:state] == "active"
|
55
|
+
org_members[user] = role
|
56
|
+
return true
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
Entitlements.logger.debug new_membership.inspect
|
61
|
+
Entitlements.logger.error "Failed to adjust membership for #{user} in organization #{org} with role #{role}!"
|
62
|
+
false
|
63
|
+
end
|
64
|
+
|
65
|
+
# Remove a user from the organization.
|
66
|
+
#
|
67
|
+
# user: A String with the (GitHub) username of the person to remove.
|
68
|
+
#
|
69
|
+
# Returns true if the user was removed, false otherwise.
|
70
|
+
Contract String => C::Bool
|
71
|
+
def remove_user_from_organization(user)
|
72
|
+
Entitlements.logger.debug "#{identifier} remove_user_from_organization(user=#{user}, org=#{org})"
|
73
|
+
result = octokit.remove_organization_membership(org, user: user)
|
74
|
+
|
75
|
+
# If we removed the user, remove them from the cache of members, so that any GitHub team
|
76
|
+
# operations in this organization will ignore this user.
|
77
|
+
if result
|
78
|
+
org_members.delete(user)
|
79
|
+
pending_members.delete(user)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Return the result, true or false
|
83
|
+
result
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Entitlements
|
4
|
+
class Backend
|
5
|
+
class GitHubOrg
|
6
|
+
include ::Contracts::Core
|
7
|
+
C = ::Contracts
|
8
|
+
|
9
|
+
# There are certain supported roles (which are mutually exclusive): admin, billing manager, member.
|
10
|
+
# Define these in this one central place to be consumed everywhere.
|
11
|
+
# The key is the name of the Entitlement, and that data is how this role appears on dotcom.
|
12
|
+
ORGANIZATION_ROLES = {
|
13
|
+
"admin" => "ADMIN",
|
14
|
+
# `billing-manager` is currently not supported
|
15
|
+
"member" => "MEMBER"
|
16
|
+
}
|
17
|
+
|
18
|
+
# Error classes
|
19
|
+
class DuplicateUserError < RuntimeError; end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
require_relative "github_org/controller"
|
25
|
+
require_relative "github_org/provider"
|
26
|
+
require_relative "github_org/service"
|
@@ -0,0 +1,126 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Entitlements
|
4
|
+
class Backend
|
5
|
+
class GitHubTeam
|
6
|
+
class Controller < Entitlements::Backend::BaseController
|
7
|
+
# Controller priority and registration
|
8
|
+
def self.priority
|
9
|
+
40
|
10
|
+
end
|
11
|
+
|
12
|
+
register
|
13
|
+
|
14
|
+
include ::Contracts::Core
|
15
|
+
C = ::Contracts
|
16
|
+
|
17
|
+
# Constructor. Generic constructor that takes a hash of configuration options.
|
18
|
+
#
|
19
|
+
# group_name - Name of the corresponding group in the entitlements configuration file.
|
20
|
+
# config - Optionally, a Hash of configuration information (configuration is referenced if empty).
|
21
|
+
Contract String, C::Maybe[C::HashOf[String => C::Any]] => C::Any
|
22
|
+
def initialize(group_name, config = nil)
|
23
|
+
super
|
24
|
+
@provider = Entitlements::Backend::GitHubTeam::Provider.new(config: @config)
|
25
|
+
end
|
26
|
+
|
27
|
+
def prefetch
|
28
|
+
teams = Entitlements::Data::Groups::Calculated.read_all(group_name, config)
|
29
|
+
teams.each do |team_slug|
|
30
|
+
entitlement_group = Entitlements::Data::Groups::Calculated.read(team_slug)
|
31
|
+
provider.read(entitlement_group)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Calculation routines.
|
36
|
+
#
|
37
|
+
# Takes no arguments.
|
38
|
+
#
|
39
|
+
# Returns a list of @actions.
|
40
|
+
Contract C::None => C::Any
|
41
|
+
def calculate
|
42
|
+
added = []
|
43
|
+
changed = []
|
44
|
+
teams = Entitlements::Data::Groups::Calculated.read_all(group_name, config)
|
45
|
+
teams.each do |team_slug|
|
46
|
+
group = Entitlements::Data::Groups::Calculated.read(team_slug)
|
47
|
+
|
48
|
+
# Anyone who is not a member of the organization is ignored in the diff calculation.
|
49
|
+
# This avoids adding an organization membership for someone by virtue of adding them
|
50
|
+
# to a team, without declaring them as an administrator or a member of the org. Also
|
51
|
+
# this avoids having a pending member show up in diffs until they accept their invite.
|
52
|
+
ignored_users = provider.auto_generate_ignored_users(group)
|
53
|
+
|
54
|
+
# "diff" includes a call to GitHub API to read the team as it currently exists there.
|
55
|
+
# Returns a hash { added: Set(members), removed: Set(members) }
|
56
|
+
diff = provider.diff(group, ignored_users)
|
57
|
+
|
58
|
+
if diff[:added].empty? && diff[:removed].empty? && diff[:metadata].nil?
|
59
|
+
logger.debug "UNCHANGED: No GitHub team changes for #{group_name}:#{team_slug}"
|
60
|
+
next
|
61
|
+
end
|
62
|
+
|
63
|
+
if diff[:metadata] && diff[:metadata][:create_team]
|
64
|
+
added << Entitlements::Models::Action.new(team_slug, provider.read(group), group, group_name, ignored_users: ignored_users)
|
65
|
+
else
|
66
|
+
changed << Entitlements::Models::Action.new(team_slug, provider.read(group), group, group_name, ignored_users: ignored_users)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
print_differences(key: group_name, added: added, removed: [], changed: changed)
|
70
|
+
|
71
|
+
@actions = added + changed
|
72
|
+
end
|
73
|
+
|
74
|
+
# Apply changes.
|
75
|
+
#
|
76
|
+
# action - Action array.
|
77
|
+
#
|
78
|
+
# Returns nothing.
|
79
|
+
Contract Entitlements::Models::Action => C::Any
|
80
|
+
def apply(action)
|
81
|
+
unless action.updated.is_a?(Entitlements::Models::Group)
|
82
|
+
logger.fatal "#{action.dn}: GitHub entitlements interface does not support removing a team at this point"
|
83
|
+
raise RuntimeError, "Invalid Operation"
|
84
|
+
end
|
85
|
+
|
86
|
+
if provider.change_ignored?(action)
|
87
|
+
logger.debug "SKIP: GitHub team #{action.dn} only changes organization non-members or pending members"
|
88
|
+
return
|
89
|
+
end
|
90
|
+
|
91
|
+
if provider.commit(action.updated)
|
92
|
+
logger.debug "APPLY: Updating GitHub team #{action.dn}"
|
93
|
+
else
|
94
|
+
logger.warn "DID NOT APPLY: Changes not needed to #{action.dn}"
|
95
|
+
logger.debug "Old: #{action.existing.inspect}"
|
96
|
+
logger.debug "New: #{action.updated.inspect}"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Validate configuration options.
|
101
|
+
#
|
102
|
+
# key - String with the name of the group.
|
103
|
+
# data - Hash with the configuration data.
|
104
|
+
#
|
105
|
+
# Returns nothing.
|
106
|
+
# :nocov:
|
107
|
+
Contract String, C::HashOf[String => C::Any] => nil
|
108
|
+
def validate_config!(key, data)
|
109
|
+
spec = COMMON_GROUP_CONFIG.merge({
|
110
|
+
"base" => { required: true, type: String },
|
111
|
+
"addr" => { required: false, type: String },
|
112
|
+
"org" => { required: true, type: String },
|
113
|
+
"token" => { required: true, type: String }
|
114
|
+
})
|
115
|
+
text = "GitHub group #{key.inspect}"
|
116
|
+
Entitlements::Util::Util.validate_attr!(spec, data, text)
|
117
|
+
end
|
118
|
+
# :nocov:
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
attr_reader :provider
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Entitlements
|
4
|
+
class Backend
|
5
|
+
class GitHubTeam
|
6
|
+
class Models
|
7
|
+
class Team < Entitlements::Models::Group
|
8
|
+
include ::Contracts::Core
|
9
|
+
C = ::Contracts
|
10
|
+
|
11
|
+
attr_reader :team_id, :team_name, :team_dn
|
12
|
+
|
13
|
+
# Constructor.
|
14
|
+
#
|
15
|
+
# team_id - Integer with the team ID
|
16
|
+
# team_name - String with the team name
|
17
|
+
# members - Set of String with member UID
|
18
|
+
# ou - A String with the base OU
|
19
|
+
Contract C::KeywordArgs[
|
20
|
+
team_id: Integer,
|
21
|
+
team_name: String,
|
22
|
+
members: C::SetOf[String],
|
23
|
+
ou: String,
|
24
|
+
metadata: C::Or[C::HashOf[String => C::Any], nil]
|
25
|
+
] => C::Any
|
26
|
+
def initialize(team_id:, team_name:, members:, ou:, metadata:)
|
27
|
+
@team_id = team_id
|
28
|
+
@team_name = team_name.downcase
|
29
|
+
@team_dn = ["cn=#{team_name.downcase}", ou].join(",")
|
30
|
+
super(dn: @team_dn, members: Set.new(members.map { |m| m.downcase }), metadata: metadata)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,208 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "service"
|
4
|
+
|
5
|
+
require "set"
|
6
|
+
require "uri"
|
7
|
+
|
8
|
+
module Entitlements
|
9
|
+
class Backend
|
10
|
+
class GitHubTeam
|
11
|
+
class Provider < Entitlements::Backend::BaseProvider
|
12
|
+
include ::Contracts::Core
|
13
|
+
C = ::Contracts
|
14
|
+
|
15
|
+
# Constructor.
|
16
|
+
#
|
17
|
+
# config - Configuration provided for the controller instantiation
|
18
|
+
Contract C::KeywordArgs[
|
19
|
+
config: C::HashOf[String => C::Any],
|
20
|
+
] => C::Any
|
21
|
+
def initialize(config:)
|
22
|
+
@github = Entitlements::Backend::GitHubTeam::Service.new(
|
23
|
+
org: config.fetch("org"),
|
24
|
+
addr: config.fetch("addr", nil),
|
25
|
+
token: config.fetch("token"),
|
26
|
+
ou: config.fetch("base")
|
27
|
+
)
|
28
|
+
|
29
|
+
@github_team_cache = {}
|
30
|
+
end
|
31
|
+
|
32
|
+
# Read in a specific GitHub.com Team and enumerate its members. Results are cached
|
33
|
+
# for future runs.
|
34
|
+
#
|
35
|
+
# team_identifier - Entitlements::Models::Group representing the entitlement
|
36
|
+
#
|
37
|
+
# Returns a Entitlements::Models::Group object representing the GitHub group or nil if the GitHub.com Team does not exist
|
38
|
+
Contract Entitlements::Models::Group => C::Maybe[Entitlements::Models::Group]
|
39
|
+
def read(entitlement_group)
|
40
|
+
slug = Entitlements::Util::Util.any_to_cn(entitlement_group.cn.downcase)
|
41
|
+
return @github_team_cache[slug] if @github_team_cache[slug]
|
42
|
+
|
43
|
+
github_team = github.read_team(entitlement_group)
|
44
|
+
|
45
|
+
# We should not cache a team which does not exist
|
46
|
+
return nil if github_team.nil?
|
47
|
+
|
48
|
+
Entitlements.logger.debug "Loaded #{github_team.team_dn} (id=#{github_team.team_id}) with #{github_team.member_strings.count} member(s)"
|
49
|
+
@github_team_cache[github_team.team_name] = github_team
|
50
|
+
end
|
51
|
+
|
52
|
+
# Dry run of committing changes. Returns a list of users added or removed.
|
53
|
+
#
|
54
|
+
# group - An Entitlements::Models::Group object.
|
55
|
+
#
|
56
|
+
# Returns added / removed hash.
|
57
|
+
Contract Entitlements::Models::Group, C::Maybe[C::SetOf[String]] => Hash[added: C::SetOf[String], removed: C::SetOf[String]]
|
58
|
+
def diff(entitlement_group, ignored_users = Set.new)
|
59
|
+
# The current value of the team from `read` might be based on the predictive cache
|
60
|
+
# or on an actual API call. At this stage we don't care.
|
61
|
+
team_identifier = entitlement_group.cn.downcase
|
62
|
+
github_team_group = read(entitlement_group)
|
63
|
+
if github_team_group.nil?
|
64
|
+
github_team_group = create_github_team_group(entitlement_group)
|
65
|
+
end
|
66
|
+
|
67
|
+
result = diff_existing_updated(github_team_group, entitlement_group, ignored_users)
|
68
|
+
|
69
|
+
# If there are no differences, return. (If we read from the predictive cache, we just saved ourselves a call
|
70
|
+
# to the API. Hurray.)
|
71
|
+
return result unless result[:added].any? || result[:removed].any? || result[:metadata]
|
72
|
+
|
73
|
+
# If the group doesn't exist yet, we know we're not using the cache and we can save on any further API calls
|
74
|
+
unless github_team_group.metadata_fetch_if_exists("team_id") == -999
|
75
|
+
# There are differences so we don't want to use the predictive cache. Call to `from_predictive_cache?`
|
76
|
+
# to determine whether our source of "current state" came from the predictive cache or from the API.
|
77
|
+
# If it returns false, it came from the API, and we should just return what we got
|
78
|
+
# (since pulling the data from the API again would be pointless).
|
79
|
+
return result unless github.from_predictive_cache?(entitlement_group)
|
80
|
+
|
81
|
+
# If `from_predictive_cache?` returned true, the data came from the predictive cache. We need
|
82
|
+
# to invalidate the predictive cache entry, clean up the instance variable and re-read the refreshed data.
|
83
|
+
github.invalidate_predictive_cache(entitlement_group)
|
84
|
+
@github_team_cache.delete(team_identifier)
|
85
|
+
github_team_group = read(entitlement_group)
|
86
|
+
end
|
87
|
+
|
88
|
+
# And finally, we have to calculate a new diff, which this time uses the fresh data from the API as
|
89
|
+
# its basis, rather than the predictive cache.
|
90
|
+
diff_existing_updated(github_team_group, entitlement_group, ignored_users)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Dry run of committing changes. Returns a list of users added or removed and a hash explaining metadata changes
|
94
|
+
# Takes an existing and an updated group object, avoiding a lookup in the backend.
|
95
|
+
#
|
96
|
+
# existing_group - An Entitlements::Models::Group object.
|
97
|
+
# group - An Entitlements::Models::Group object.
|
98
|
+
# ignored_users - Optionally, a Set of lower-case Strings of users to ignore.
|
99
|
+
Contract Entitlements::Models::Group, Entitlements::Models::Group, C::Maybe[C::SetOf[String]] => Hash[added: C::SetOf[String], removed: C::SetOf[String], metadata: C::Maybe[Hash[]]]
|
100
|
+
def diff_existing_updated(existing_group, group, ignored_users = Set.new)
|
101
|
+
diff_existing_updated_metadata(existing_group, group, super)
|
102
|
+
end
|
103
|
+
|
104
|
+
# Determine if a change needs to be ignored. This will return true if the
|
105
|
+
# user being added or removed is ignored.
|
106
|
+
#
|
107
|
+
# action - Entitlements::Models::Action object
|
108
|
+
#
|
109
|
+
# Returns true if the change should be ignored, false otherwise.
|
110
|
+
Contract Entitlements::Models::Action => C::Bool
|
111
|
+
def change_ignored?(action)
|
112
|
+
return false if action.existing.nil?
|
113
|
+
|
114
|
+
result = diff_existing_updated(action.existing, action.updated, action.ignored_users)
|
115
|
+
result[:added].empty? && result[:removed].empty? && result[:metadata].nil?
|
116
|
+
end
|
117
|
+
|
118
|
+
# Commit changes.
|
119
|
+
#
|
120
|
+
# group - An Entitlements::Models::Group object.
|
121
|
+
#
|
122
|
+
# Returns true if a change was made, false if no change was made.
|
123
|
+
Contract Entitlements::Models::Group => C::Bool
|
124
|
+
def commit(entitlement_group)
|
125
|
+
github_team = github.read_team(entitlement_group)
|
126
|
+
|
127
|
+
# Create the new team and invalidate the cache
|
128
|
+
if github_team.nil?
|
129
|
+
team_name = entitlement_group.cn.downcase
|
130
|
+
github.create_team(entitlement_group: entitlement_group)
|
131
|
+
github.invalidate_predictive_cache(entitlement_group)
|
132
|
+
@github_team_cache.delete(team_name)
|
133
|
+
github_team = github.read_team(entitlement_group)
|
134
|
+
end
|
135
|
+
github.sync_team(entitlement_group, github_team)
|
136
|
+
end
|
137
|
+
|
138
|
+
# Automatically generate ignored users for a group. Find all members listed in the group who are not
|
139
|
+
# admins or members of the GitHub organization in question.
|
140
|
+
#
|
141
|
+
# group - An Entitlements::Models::Group object.
|
142
|
+
#
|
143
|
+
# Returns a set of strings with usernames meeting the criteria.
|
144
|
+
Contract Entitlements::Models::Group => C::SetOf[String]
|
145
|
+
def auto_generate_ignored_users(entitlement_group)
|
146
|
+
org_members = github.org_members.keys.map(&:downcase)
|
147
|
+
group_members = entitlement_group.member_strings.map(&:downcase)
|
148
|
+
Set.new(group_members - org_members)
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
|
+
# Construct an Entitlements::Models::Group for a new group and team
|
154
|
+
#
|
155
|
+
# group - An Entitlements::Models::Group object representing the defined group
|
156
|
+
#
|
157
|
+
# Returns an Entitlements::Models::Group for a new group
|
158
|
+
Contract Entitlements::Models::Group => Entitlements::Models::Group
|
159
|
+
def create_github_team_group(entitlement_group)
|
160
|
+
begin
|
161
|
+
metadata = entitlement_group.metadata
|
162
|
+
metadata["team_id"] = -999
|
163
|
+
rescue Entitlements::Models::Group::NoMetadata
|
164
|
+
metadata = {"team_id" => -999}
|
165
|
+
end
|
166
|
+
Entitlements::Backend::GitHubTeam::Models::Team.new(
|
167
|
+
team_id: -999,
|
168
|
+
team_name: entitlement_group.cn.downcase,
|
169
|
+
members: Set.new,
|
170
|
+
ou: github.ou,
|
171
|
+
metadata: metadata
|
172
|
+
)
|
173
|
+
end
|
174
|
+
|
175
|
+
# Returns a diff hash of group metadata
|
176
|
+
# Takes an existing and an updated group object, avoiding a lookup in the backend.
|
177
|
+
#
|
178
|
+
# existing_group - An Entitlements::Models::Group object.
|
179
|
+
# group - An Entitlements::Models::Group object.
|
180
|
+
# base_diff - Hash representing the base diff from diff_existing_updated
|
181
|
+
Contract Entitlements::Models::Group, Entitlements::Models::Group, Hash[added: C::SetOf[String], removed: C::SetOf[String], metadata: C::Or[Hash[], nil]] => Hash[added: C::SetOf[String], removed: C::SetOf[String], metadata: C::Or[Hash[], nil]]
|
182
|
+
def diff_existing_updated_metadata(existing_group, group, base_diff)
|
183
|
+
if existing_group.metadata_fetch_if_exists("team_id") == -999
|
184
|
+
base_diff[:metadata] = { create_team: true }
|
185
|
+
end
|
186
|
+
existing_parent_team = existing_group.metadata_fetch_if_exists("parent_team_name")
|
187
|
+
changed_parent_team = group.metadata_fetch_if_exists("parent_team_name")
|
188
|
+
|
189
|
+
if existing_parent_team != changed_parent_team
|
190
|
+
if existing_parent_team.nil? && !changed_parent_team.nil?
|
191
|
+
base_diff[:metadata] = { parent_team: "add" }
|
192
|
+
Entitlements.logger.info "ADD github_parent_team #{changed_parent_team} to #{existing_group.dn} in #{github.org}"
|
193
|
+
elsif !existing_parent_team.nil? && changed_parent_team.nil?
|
194
|
+
base_diff[:metadata] = { parent_team: "remove" }
|
195
|
+
Entitlements.logger.info "REMOVE (NOOP) github_parent_team #{existing_parent_team} from #{existing_group.dn} in #{github.org}"
|
196
|
+
else
|
197
|
+
base_diff[:metadata] = { parent_team: "change" }
|
198
|
+
Entitlements.logger.info "CHANGE github_parent_team from #{existing_parent_team} to #{changed_parent_team} for #{existing_group.dn} in #{github.org}"
|
199
|
+
end
|
200
|
+
end
|
201
|
+
base_diff
|
202
|
+
end
|
203
|
+
|
204
|
+
attr_reader :github
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|