blob: 6e9a4f4990a389c4fec3a8913b2c7e7d73e80eac [file] [log] [blame]
#!/usr/bin/env python
## Install info
## $ virtualenv env
## $ source env/bin/activate
## $ pip install PyGithub
## Examples:
## Find the differences from last tag to current
## $ alpha-6 HEAD
import argparse
import re
import os
import subprocess
from github import Github
from github import GithubException
def dprint(*args):
print str(args)
def get_args():
Get command line arguments
parser = argparse.ArgumentParser(description="Find the PR's between two versions")
parser.add_argument("old", help = "old version to use")
parser.add_argument("new", help = "new version to use")
parser.add_argument("-v", "--verbose", help="Enable debug output",
parser.add_argument("-f", "--file",
help="Output file to store results (default:",
return parser.parse_args()
def search_prs(log):
Search lines of text for PR numbers
# Find all matches using regex iterator, using the PR # as the group match
resultlist = [str( for m in re.finditer(r"erge pull request #(\d+)", log)]
return sorted(resultlist)
def get_env(env):
return os.environ[env]
def get_formatted_issue(repo, issue, title, url):
Single place to adjust formatting output of PR data
# Newline support writelines() call which doesn't add newlines
# on its own
return("* {}/{}: [{}]({})\n".format(repo, issue, title, url))
def gh_get_issue_output(org, repo, issuenum):
Look up PR information using the GitHub api
# Attempt to look up the PR, and don't take down the whole
# shebang if a API call fails
# This will fail often on forks who don't have the
# PRs numbers associated with the forked account
# Return empty string on error
repoObj = gh.get_repo(org + "/" + repo)
issue = repoObj.get_issue(int(issuenum))
title = issue.title
html_url = issue.html_url
except GithubException as e:
print "Github error({0}): {1}".format(e.status,
return ""
print "Some github error"
return ""
return(get_formatted_issue(repo, issuenum, title, html_url))
def get_org(repourl):
Simple function to parse the organization out of a GitHub URL
dprint("Current repourl to search: " + repourl)
# GitHub URLs can be:
# http[s]://
# or
pattern = re.compile(r"[/:]+(\w+)/")
m =, repourl)
# Fail fast if this is wrong so we can add a pattern to the search
if m:
raise Exception("Incorrect regex pattern finding repo org")
def get_name(repourl):
Simple function to parse the repository name out of a GitHub URL
dprint("Current repourl to search: " + repourl)
repo_pattern = re.compile(r"[/:]\w+/(\w+)")
m =, repourl)
if m:
raise Exception("Incorrect rexex pattern finding repo url")
def get_repo_url_from_remote():
Function that gets the repository URL from the `git remote` listing
git_remote_bytes = subprocess.check_output(["git", "remote", "-v"])
# check_output returns the command results in raw byte format
remote_string = git_remote_bytes.decode('utf-8')
pattern = re.compile(r"[/:]\w+/\w+")
m =, remote_string)
if m:
raise Exception("Incorrect rexex pattern finding repo url")
def process_log(gitlog, repo_url):
Handles the processing of the gitlog and returns a list
of PRs already formatted for output
pr_list = search_prs(gitlog)
repoorg = get_org(repo_url)
reponame = get_name(repo_url)
pr_buffer = []
for issue in pr_list:
pr_buffer.append(gh_get_issue_output(repoorg, reponame, issue))
return pr_buffer
def fetch_log(old_ver, new_ver):
Function that processes the git log between the old and new versions
dprint("Current working directory", os.getcwd())
gitlogbytes = subprocess.check_output(["git", "log",
str(old_ver + ".." + new_ver)])
return gitlogbytes.decode('utf-8')
def compare_versions(repo_url, old_ver, new_ver):
# Formatted list of all PRs for all repos
pr_out = []
gitlog = fetch_log(old_ver, new_ver)
pr_out.extend(process_log(gitlog, repo_url))
return pr_out
def main():
args = get_args()
# Setup the GitHub object for later use
global gh
gh = Github(get_env("GHAUTH"))
if gh == "":
raise Exception("Env var GHAUTH must be set to a valid GitHub API key")
if args.verbose:
global VERBOSE
dprint("Inspecting difference in between: ", args.old, " and ",
# Find the github URL of the repo we are operating on
repo_url = get_repo_url_from_remote()
# Compare old and new versions
pr_list = compare_versions(repo_url, args.old,
# Writeout PR listing
print "Writing output to file %s" % args.file
with open(args.file, 'w') as output:
if __name__ == "__main__":