Skip to content

Commit b544636

Browse files
committed
administrative: helper script for annual committer review
This script helps with the annual Github committer review. See the README.md for more details. Signed-off-by: Jeff Squyres <[email protected]>
1 parent ee34108 commit b544636

File tree

3 files changed

+176
-0
lines changed

3 files changed

+176
-0
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,9 @@ Scripts used for running the community Jenkins server
2525

2626
Scripts used to build releases, upload to s3, etc. The jenkins and
2727
nightly tarball scripts call these, in addition to direct human use.
28+
29+
## administrative/
30+
31+
Scripts used for administrative purposes. For example, a script to
32+
assist with the annual Github 'open-mpi' organization committer
33+
review.

administrative/README.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
This Python script is useful in generating a spreadsheet for the
2+
annual Open MPI committers review.
3+
4+
It uses the Github Python API to query all the users, repos, and teams
5+
in the "open-mpi" github.com organization.
6+
7+
It generates a CSV with users as rows and repos as columns.
8+
9+
A bunch of information is included for each user in an attempt to help
10+
identify each user.
11+
12+
For each user, if that user has commit access to a given repo, the
13+
github team name that gives them commit access to that repo is listed
14+
in the corresponding cell.
15+
16+
The rationale is that if you need to remove someone's access to a
17+
repo, that tells you exactly which Github team(s) to remove the user
18+
from in order to remove their commit access to that repo.
19+
20+
To run this script:
21+
22+
- You need to have "python3" in your path.
23+
- "pip3 install pygithub"
24+
- Go to https://github.com/settings/tokens and make a personal access
25+
token with full permissions to the repo and org.
26+
- Save that token in a single-line text file named 'oauth-token.txt'
27+
in the same directory as this script (I didn't make the script
28+
feature-full, e.g., to accept a CLI arg telling where the token file
29+
is -- sorry).
30+
31+
Running the script will generate "permissions.csv".
32+
33+
I suggest uploading this CSV to Google Drive (e.g., in the shared Open
34+
MPI folder) and converting it to a Google Sheet. Then you can color
35+
the cells as appropriate, resize columns, wrap text, ...etc., and then
36+
ask the community to validate all the committers.
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
#!/usr/bin/env python3
2+
3+
'''
4+
Requirements:
5+
6+
$ pip3 install pygithub
7+
8+
Go to https://github.com/settings/tokens and make a personal access
9+
token with full permissions to the repo and org.
10+
11+
'''
12+
13+
import csv
14+
15+
from github import Github
16+
from pprint import pprint
17+
18+
#--------------------------------------------------------------------
19+
20+
# Read the oAuth token file.
21+
# (you will need to supply this file yourself -- see the comment at
22+
# the top of this file)
23+
token_filename = 'oauth-token.txt'
24+
with open(token_filename, 'r') as f:
25+
token = f.read().strip()
26+
g = Github(token)
27+
28+
#--------------------------------------------------------------------
29+
30+
print("Getting open-mpi organization...")
31+
org = 'open-mpi'
32+
ompi_org = g.get_organization(org)
33+
34+
#--------------------------------------------------------------------
35+
36+
print("Loading organization repos...")
37+
all_members = dict()
38+
repos = dict()
39+
for repo in ompi_org.get_repos():
40+
print("Found Org Repo: {repo}".format(repo=repo.name))
41+
42+
# For each repo, get the teams on that repo
43+
repo_teams = dict()
44+
for team in repo.get_teams():
45+
out = (" Found team on repo {org}/{repo}: {team} ({perm}) "
46+
.format(org=ompi_org.name, repo=repo.name,
47+
team=team.name, perm=team.permission))
48+
# We only care about teams with push permissions
49+
if team.permission == "pull":
50+
print("{out} -- SKIPPED".format(out=out))
51+
continue
52+
53+
print(out)
54+
55+
# Find all the members of this team
56+
team_members = dict()
57+
member_teams = dict()
58+
for member in team.get_members():
59+
print(" Found member: {name}"
60+
.format(name=member.login))
61+
team_members[member.id] = member
62+
63+
if member.id not in all_members:
64+
all_members[member.id] = {
65+
'member' : member,
66+
'member_teams' : dict(),
67+
}
68+
69+
# Find the member in the org and add this team to them
70+
all_members[member.id]['member_teams'][team.id] = team
71+
72+
# Same the results
73+
repo_teams[team.id] = {
74+
'team' : team,
75+
'team_members' : team_members,
76+
}
77+
78+
# Save the results
79+
repos[repo.id] = {
80+
'repo' : repo,
81+
'repo_teams' : repo_teams,
82+
}
83+
84+
85+
print("All the repos:")
86+
pprint(repos)
87+
pprint(all_members)
88+
89+
#--------------------------------------------------------------------
90+
91+
# Pre-load the field names with info about the user and repo
92+
fieldnames = ['login', 'name', 'email', 'company']
93+
94+
# Add all the repo names
95+
for _, rentry in repos.items():
96+
repo = rentry['repo']
97+
fieldnames.append("{org}/{repo}"
98+
.format(org=ompi_org.login,
99+
repo=repo.name))
100+
101+
#--------------------------------------------------------------------
102+
103+
# Now write out the CSV
104+
outfile = 'permissions.csv'
105+
print("Writing: ".format(outfile=outfile))
106+
with open(outfile, 'w', newline='') as csvfile:
107+
writer = csv.DictWriter(csvfile, fieldnames=fieldnames,
108+
quoting=csv.QUOTE_ALL)
109+
writer.writeheader()
110+
for mid, mentry in all_members.items():
111+
member = mentry['member']
112+
print(" Writing member: {member}".format(member=member.login))
113+
114+
# Initial entries about the user
115+
row = {
116+
'login' : member.login,
117+
'name' : member.name,
118+
'email' : member.email,
119+
'company' : member.company,
120+
}
121+
122+
# Fill in values for each repo
123+
for _, rentry in repos.items():
124+
repo = rentry['repo']
125+
126+
found = list()
127+
for tid, tentry in rentry['repo_teams'].items():
128+
if tid in mentry['member_teams']:
129+
team = tentry['team']
130+
found.append(team.name)
131+
132+
row[repo.full_name] = ', '.join(found)
133+
134+
writer.writerow(row)

0 commit comments

Comments
 (0)