Created
January 26, 2022 00:57
-
-
Save Roach/589e863c60e97bd08e1c37670b286d34 to your computer and use it in GitHub Desktop.
Fetch GitHub org members with role and verified domain email
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
import csv | |
import os | |
import requests | |
import sys | |
# Verify the org name variable has been passed | |
sys_args = sys.argv | |
if len(sys_args)==1: | |
print("Please provide the GitHub org name") | |
print("{} <github-org>".format(sys_args[0])) | |
exit() | |
else: | |
github_org = "slackhq" | |
# Your github admin token, store this in an environment variable | |
# or pass it in when you invoke the script | |
# GITHUB_TOKEN="<your OWNER token>" python3 fetch-verified-emails.py | |
github_api_token = os.getenv('GITHUB_TOKEN', '') | |
headers = {"Authorization": "token {}".format(github_api_token)} | |
# Create the members_list array and add the column headers | |
member_list = [["name", "username", "role", "Verified emails"]] | |
def run_query(query): | |
# Query the GraphQL API | |
request = requests.post('https://api.github.com/graphql', json={'query': query}, headers=headers) | |
if request.status_code == 200: | |
return request.json() | |
else: | |
raise Exception("Query failed to run by returning code of {}. {}".format(request.status_code, query)) | |
def fetch_user_data(org_name, cursor="null"): | |
# Get a paginated list of GitHub org members, including membership role and verified domain emails | |
# The GraphQL query, defined as a multi-line string. | |
query_template = """ | |
{ | |
organization(login: "%s") { | |
membersWithRole(first: 100, after: %s) { | |
edges { | |
cursor | |
node { | |
login | |
name | |
organizationVerifiedDomainEmails(login:"%s") | |
} | |
role | |
} | |
} | |
} | |
rateLimit { | |
limit | |
cost | |
remaining | |
resetAt | |
} | |
} | |
""" | |
# Add org name and cursor vars to the query template and run the query | |
query = query_template%(org_name, cursor, org_name) | |
result = run_query(query) | |
# If the results contain errors, log out the results | |
if "errors" in result: | |
print("⚠️ QUERY RETURNED WITH ERRORS") | |
print(result) | |
# Typical success and error response: | |
# For errors, membersWithRole will be None | |
# For success, 'errors' won't be present | |
# { | |
# 'data': { | |
# 'organization': { | |
# 'membersWithRole': { | |
# [{ | |
# 'cursor': 'Y3Vyc29yOnYyOpHNESc=', | |
# 'node': { | |
# 'login': 'roach', | |
# 'name': 'Jason Roche', | |
# 'organizationVerifiedDomainEmails': [ | |
# '[email protected]', | |
# '[email protected]' | |
# ] | |
# }, | |
# 'role': 'OWNER'}] | |
# } | |
# }, | |
# 'rateLimit': { | |
# 'limit': 5000, 'cost': 1, 'remaining': 4992, 'resetAt': '2022-01-26T00:14:27Z' | |
# } | |
# }, | |
# 'errors': [ | |
# { | |
# 'type': 'INVALID_CURSOR_ARGUMENTS', | |
# 'path': ['organization', 'membersWithRole', 'edges'], | |
# 'locations': [{'line': 5, 'column': 11}], | |
# 'message': '`null` does not appear to be a valid cursor.' | |
# } | |
# ] | |
# } | |
# Print the remaining rate limit count and reset timestamp | |
# rate_limit = result["data"]["rateLimit"] | |
# print("Remaining rate limit: {}, resets at: {}".format(rate_limit["remaining"],rate_limit["resetAt"])) | |
# Iterate through the org members | |
org_members = result["data"]["organization"]["membersWithRole"]["edges"] | |
for member_node in org_members: | |
member_info = member_node["node"] | |
# Flatten the organizationVerifiedDomainEmails list | |
member_emails = "" | |
if member_info["organizationVerifiedDomainEmails"]: | |
# print("Verified domain emails: {}".format(" ".join(member_info["organizationVerifiedDomainEmails"]))) | |
member_emails = ", ".join(member_info["organizationVerifiedDomainEmails"]) | |
member_list.append([member_info["login"], member_info["name"], member_node["role"], member_emails]) | |
if org_members and "cursor" in org_members[-1]: | |
current_cursor = '"{}"'.format(org_members[-1]["cursor"]) | |
# print("LOADING MORE MEMBERS") | |
fetch_user_data(org_name, current_cursor) | |
# Fetch the users and export to CSV | |
fetch_user_data(github_org) | |
# Verify that the member list contains more than just the header row and export to CSV | |
if len(member_list) > 1: | |
print("Found {} org members".format(len(member_list)-1)) | |
# Export to CSV with the org name in the filename, ex: github_org_members_slackhq.csv | |
with open("github_org_members_{}.csv".format(github_org),"w+") as my_csv: | |
csvWriter = csv.writer(my_csv,delimiter=',') | |
csvWriter.writerows(member_list) | |
print("Exported CSV") | |
else: | |
print("Member list is empty.") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment