Created
August 10, 2017 00:12
-
-
Save BenTheElder/de2688f28069e7289cd6ba4997446c88 to your computer and use it in GitHub Desktop.
find contributors that are not members of an organization
This file contains 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 | |
from __future__ import print_function | |
import re | |
import json | |
import argparse | |
from collections import defaultdict | |
import requests | |
parser = argparse.ArgumentParser( | |
description="find non-members of a GitHub org by contributions to repos") | |
parser.add_argument("--token", nargs="?", type=str, help="GitHub API token") | |
parser.add_argument("--org", nargs="?", type=str, default="kubernetes", | |
help="the GitHub org to find non-member contirbutions for") | |
def get_pagination(response): | |
if "Link" not in response.headers: | |
return None | |
parts = response.headers["Link"].split(",") | |
res = {} | |
for part in parts: | |
match = re.search('<(.*)>; rel="(.*)"', part) | |
if match: | |
res[match.group(2)] = match.group(1) | |
return res | |
def get_all_paginated(url, token=None): | |
res = [] | |
while True: | |
headers = {"Accept": "application/vnd.github.v3+json"} | |
if token is not None: | |
headers["Authorization"] = "token "+token | |
r = requests.get(url, headers=headers, params={"per_page": "100"}) | |
res.extend(r.json()) | |
pagination = get_pagination(r) | |
if pagination is None or "next" not in pagination: | |
break | |
url = pagination["next"] | |
return res | |
def get_members(org, token=None): | |
url = "https://api.github.com/orgs/%s/members" % org | |
return get_all_paginated(url, token) | |
def get_contributors(repo, token=None): | |
url = "https://api.github.com/repos/%s/stats/contributors" % repo | |
return get_all_paginated(url, token) | |
def get_repos(org, token=None): | |
url = "https://api.github.com/orgs/%s/repos" % org | |
return get_all_paginated(url, token) | |
def main(args): | |
org = "kubernetes" | |
members_json = get_members(org, args.token) | |
members = set(m["login"] for m in members_json) | |
repos_json = get_repos(org, args.token) | |
repos = [r["full_name"] for r in repos_json] | |
# TODO: this is naive, we're just taking the "total" returned by GitHub | |
non_member_contributions = defaultdict(int) | |
for repo in repos: | |
print("getting results for repo: %s ..." % repo) | |
contributors = get_contributors(repo, args.token) | |
for c in contributors: | |
login = c["author"]["login"] | |
if login not in members: | |
non_member_contributions[login.encode("utf-8")] += int(c["total"]) | |
by_contributions = sorted( | |
((k, v) for k,v in non_member_contributions.iteritems()), key=lambda v: -v[1]) | |
print("Non-Member GitHub Logins sorted by total contributions in %s:" % args.org) | |
for nm in by_contributions: | |
print("@{: <25}| {: >4} total contributions".format(*nm)) | |
if __name__ == "__main__": | |
args = parser.parse_args() | |
main(args) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
You should get the collaborators not the members in order to include outside collaborators who are still valid for assigning.