forked from mozilla/github-org-scripts
-
Notifications
You must be signed in to change notification settings - Fork 0
/
team_update.py
executable file
·154 lines (132 loc) · 4.57 KB
/
team_update.py
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#!/usr/bin/env python
"""Update the membership of a team based on GitHub attributes.
e.g. make a team of 'owners' or 'members'. The team must already exist -
see --help output for names
"""
import argparse
import logging
import sys
from client import get_github3_client
import github3
TEAM = "admin-all-org-"
VERBOSE = False
logger = logging.getLogger(__name__)
def team_name(user_type):
global TEAM
team_name = TEAM
if team_name[-1] in "-_":
team_name = TEAM + user_type
return team_name
def get_or_create_team(org, team_name):
try:
team = [x for x in org.teams() if x.name == team_name][0]
except IndexError:
# no such team
team = org.create_team(team_name)
logger.warn(f"created team {team_name} in {org.login}")
return team
def update_team_membership(org, new_member_list, team_name=None, do_update=False):
# we're using a team to communicate with these folks, update
# that team to contain exactly new_member_list members
# team must already exist in the org
team = get_or_create_team(org, team_name)
# get set of current members
current = {x.login for x in team.members()}
# get set of new members
new = {x.login for x in new_member_list}
to_remove = current - new
to_add = new - current
no_change = new & current
update_success = True
if VERBOSE:
print("%5d unchanged" % len(no_change))
for login in no_change:
print(f" {login} is unchanged")
print("%5d alumni" % len(to_remove))
for login in to_remove:
if do_update and not team.remove_member(login):
logger.warn(
"Failed to remove a member" " - you need 'admin:org' permissions"
)
update_success = False
break
if VERBOSE:
print(f" {login} has departed")
print("%5d new" % len(to_add))
for login in to_add:
if VERBOSE:
print(f" {login} is new")
try:
if do_update and not team.add_member(login):
logger.warn(
"Failed to add a member" " - you need 'admin:org' permissions"
)
update_success = False
break
except github3.exceptions.ForbiddenError:
# this occurs occasionally, don't stop work
logger.warn(f"Failed to add member '{login}'")
update_success = False
print("%5d no change" % len(no_change))
# if we're running in the ipython notebook, the log message isn't
# displayed. Output something useful
if not update_success:
print(f"Updates were not all made to team '{team_name}' in '{org.name}'.")
print(
"Make sure your API token has 'admin:org' permissions for that organization."
)
def check_users(gh, org_name, admins_only=True, update_team=False):
try:
org = gh.organization(org_name)
except github3.exceptions.NotFoundError:
print(f"Org '{org_name}' does not exist")
sys.exit(1)
role = "admin" if admins_only else "all"
user_type = "owners" if admins_only else "members"
members = list(org.members(role=role))
if members:
print("There are %d %s for org %s:" % (len(members), user_type, org_name))
else:
print(f"Error: no {user_type} found for {org_name}")
if update_team or VERBOSE:
update_team_membership(org, members, team_name(user_type), update_team)
def parse_args():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
"--owners",
action="store_true",
help="Report only for org owners (default all members)",
)
parser.add_argument(
"orgs",
nargs="*",
default=[
"mozilla",
],
help="github organizations to check (defaults to mozilla)",
)
parser.add_argument(
"--team",
default=TEAM,
help='update membership of team "%s{owners,members}"' % TEAM,
)
parser.add_argument(
"--update-team", action="store_true", help="apply changes to GitHub"
)
parser.add_argument(
"--verbose", action="store_true", help="print logins for all changes"
)
return parser.parse_args()
def main():
args = parse_args()
global VERBOSE
VERBOSE = args.verbose
global TEAM
TEAM = args.team
if args.orgs:
gh = get_github3_client()
for org in args.orgs:
check_users(gh, org, args.owners, args.update_team)
if __name__ == "__main__":
logging.basicConfig(level=logging.WARN, format="%(asctime)s %(message)s")
main()