Created
February 6, 2018 22:53
-
-
Save gene1wood/c3214412cc9873a1a555bebb9b1c61c2 to your computer and use it in GitHub Desktop.
For a given user, identify all repos in a given org for which that user has admin rights, then report the shortest list of team names of teams which are also administrative for those repos.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# This uses pagination functionality not yet present in master of agithub | |
import agithub.GitHub | |
import json | |
from pprint import pprint | |
def persist_to_file(file_name): | |
def decorator(original_func): | |
try: | |
cache = json.load(open(file_name, 'r')) | |
except (IOError, ValueError): | |
cache = {} | |
def new_func(param): | |
if param not in cache: | |
cache[param] = original_func(param) | |
json.dump(cache, open(file_name, 'w')) | |
return cache[param] | |
return new_func | |
return decorator | |
ag = agithub.GitHub.GitHub( | |
token='TOKEN GOES HERE', | |
paginate=True) | |
user = 'octocat' | |
org = 'mozilla' | |
@persist_to_file('repos.json') | |
def get_org_repos(org): | |
status, repos = ag.orgs[org].repos.get(per_page=100) | |
return repos | |
@persist_to_file('collaborators.json') | |
def get_collaborators(org): | |
# ~ 2000 calls | |
repos = get_org_repos(org) | |
collaborator_map = {} | |
for repo_name in [x['name'] for x in repos]: | |
print('Fetching collaborators for %s' % repo_name) | |
status, collaborators = ag.repos[org][repo_name].collaborators.get( | |
per_page=100) | |
collaborator_map[repo_name] = collaborators | |
return collaborator_map | |
@persist_to_file('org_owners.json') | |
def get_org_owners(org): | |
# ~ 20 calls | |
status, org_owners = ag.orgs[org].members.get( | |
role='admin', | |
per_page=100) | |
return org_owners | |
@persist_to_file('repo_teams.json') | |
def get_repo_teams(repo): | |
# ~ 5 calls | |
# no nested teams | |
status, teams = ag.repos[org][repo].teams.get(per_page=100) | |
return teams | |
def main(): | |
"""For a given user, identify all repos in a given org for which that user | |
has admin rights, then report the shortest list of team names of teams | |
which are also administrative for those repos. | |
With this list of organization teams, one can contact the teams with | |
GitHub team discussions to ask them to confirm that the user in question | |
should indeed have admin rights on the list of repos that that team | |
administers | |
:return: | |
""" | |
status, ratelimit = ag.rate_limit.get() | |
print("Ratelimit is : %s" % ratelimit['rate']) | |
# List org repos | |
# https://developer.github.com/v3/repos/#list-organization-repositories | |
repos = get_org_repos(org) | |
print("%s repos found" % len(repos)) | |
# For each repo list collaborators | |
# https://developer.github.com/v3/repos/collaborators/#list-collaborators | |
collaborators = get_collaborators(org) | |
print("collaborators on %s repos found" % len(collaborators)) | |
# Determine org owners | |
org_owners = get_org_owners(org) | |
print("%s org owners found" % len(org_owners)) | |
teams_to_contact = {} | |
for repo in collaborators: | |
repo_admins = [x['login'] for x in collaborators[repo] | |
if x['login'] not in [y['login'] for y in org_owners] | |
and x['permissions']['admin']] | |
if user in repo_admins: | |
teams = get_repo_teams(repo) | |
admin_teams = [x['slug'] for x in teams | |
if x['permission'] == 'admin'] | |
if len(admin_teams) > 0: | |
for team in admin_teams: | |
if team not in teams_to_contact: | |
teams_to_contact[team] = [] | |
teams_to_contact[team].append(repo) | |
else: | |
raise Exception('Repo %s has no teams which have admin rights ' | |
'on it' % repo) | |
teams_to_contact_order = sorted( | |
teams_to_contact.keys(), | |
key=lambda x: len(teams_to_contact[x]), | |
reverse=True) | |
for team in teams_to_contact_order: | |
for repo in teams_to_contact[team]: | |
for other_team in [x for x in teams_to_contact if x != team]: | |
if repo in teams_to_contact[other_team]: | |
teams_to_contact[other_team].remove(repo) | |
if len(teams_to_contact[team]) == 0: | |
del teams_to_contact[team] | |
else: | |
pprint({team: teams_to_contact[team]}) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment