entitlements-github-plugin 0.0.1
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 +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
|