Skip to content

Instantly share code, notes, and snippets.

@nocnokneo
Last active August 29, 2015 14:01
Show Gist options
  • Save nocnokneo/ea6a8420c7f524e3c935 to your computer and use it in GitHub Desktop.
Save nocnokneo/ea6a8420c7f524e3c935 to your computer and use it in GitHub Desktop.
Helper script to contribute commits from an MITK fork to the MITK mainline master
.idea/
*.pyc
#!/usr/bin/env python
# Python script to help automate the MITK contribution process:
#
# 1) Fix an MITK bug my MITK branch. Commit it. (e.g. commit 1234567)
# 2) Create a bug report at bugs.mitk.org [2]
# 3) `git fetch upstream`
# 4) `git checkout -b bug-XXXXX-foo-bar upstream/master`
# 5) `git cherry-pick --signoff 1234567`
# 6) `git push origin bug-XXXXX-foo-bar`
# 7) Create a pull request from github.com [3]
# 8) Update bugzilla bug report with pull request URL and has_patch flag
#
# Example usage should look something like:
#
# $ mitk-contribute.py [--summary <msg>] <commit>...
# Full bug description report read from stdin
# <ctrl-d>
# MITK bug report: http://bugs.mitk.org/show_bug.cgi?id=XXXXX
# GitHub pull request: https://github.com/MITK/MITK/pull/YYY
#
# Trove classifiers:
# Programming Language :: Python :: 2.7
# Recommended future imports for proper Python 2 and 3 support
# See: https://docs.python.org/3/howto/pyporting.html
from __future__ import print_function
from __future__ import unicode_literals
from __future__ import absolute_import
from bugzilla import Bugzilla4
import git
import github3
import os, socket, errno
import sys
import re
from getpass import getpass
__version__ = 0.1
# From: http://stackoverflow.com/a/600612/471839
def mkdir_p(path):
try:
os.makedirs(path)
except OSError as exc: # Python >2.5
if exc.errno == errno.EEXIST and os.path.isdir(path):
pass
else:
raise
def select_choice(choices, prompt="Select choice"):
for i, c in enumerate(choices):
print('(%s) %s' % (i+1, c))
choice = int(raw_input('%s [1-%d]: ' % (prompt, len(choices))))
return choices[choice-1]
def create_bugzilla_bug(bug_summary):
bz = Bugzilla4()
bz.user = raw_input('Bugzilla username: ').strip()
bz.password = getpass('Bugzilla password: ').strip()
bz.connect('http://bugs.mitk.org/xmlrpc.cgi')
product = b'MITK'
components = bz.getcomponents(product)
component = select_choice(components)
versions = []
for p in bz.getproducts():
if p['name'] == product:
for v in p['versions']:
if v['is_active']:
versions.append(v['name'])
break
version = select_choice(versions)
bug_description = ''
if not bug_description:
bug_description = raw_input('Bug description: ').strip()
bz_bug = bz.createbug(product=product, component=component, version=version,
summary=bug_summary, description=bug_description)
bug_url = "http://bugs.mitk.org/show_bug.cgi?id=%d" % bz_bug.id
return bz_bug.id, bug_url
def fetch_upstream(repo_path='.', remote_name='upstream'):
"""
Fetch latest upstream
"""
# TODO: Verify working directory is clean before starting
repo = git.Repo(repo_path)
git.remote.Remote(repo, remote_name).fetch()
def cherry_pick_into_bug_branch(bug_id, bug_summary, commits, repo_path='.'):
"""
Create a bug branch off of upstream/master then cherry pick the desired
commits into that new branch.
"""
# Create bug branch
g = git.Git(repo_path)
branch_summary = "-".join(bug_summary.split())
branch_summary = re.sub(r'[^a-zA-Z_-]', '', branch_summary)
bug_branch = 'bug-%d-%s' % (bug_id, branch_summary)
g.checkout('upstream/master', b=bug_branch)
# TODO: Cherry pick commits into this bug branch
# ...
return bug_branch
def create_github_pull_request(title, branch_name):
gh_token_file = os.path.expanduser(b"~/.config/mitk-contribute/github.token")
gh_token = ''
gh_user = raw_input('GitHub username: ')
while not gh_token:
try:
gh_token = open(gh_token_file).read().strip()
except IOError:
pass
if not gh_token:
gh_pass = getpass('GitHub password: ')
if not gh_pass:
sys.exit()
gh_auth_note = b'mitk-contribute.py on %s' % socket.getfqdn()
gh_auth = github3.api.authorize(gh_user, gh_pass,
scopes=['repo', ],
note=gh_auth_note)
mkdir_p(os.path.dirname(gh_token_file))
with open(gh_token_file, 'wb') as f:
# make the sensitive token file read-only
mode = os.stat(gh_token_file).st_mode
os.chmod(gh_token_file, mode & 0600)
f.write(gh_auth.token)
gh = github3.login(token=gh_token)
mitk_gh_repo = gh.repository(owner='MITK', repository='MITK')
gh_pull = mitk_gh_repo.create_pull(title=title,
base="%s:%s" % (gh_user, branch_name),
head="master")
return gh_pull.id, gh_pull.html_url
def main(argv):
print("== mitk-contribute v%s ==" % __version__)
# TODO: Command line opts, saved preferences
bug_summary = ''
if not bug_summary:
bug_summary = raw_input('Bug summary: ').strip()
repo_path = os.path.expanduser("~/git/MITK")
upstream_remote = "upstream"
print("Fetching latest from '%s' ..." % upstream_remote)
fetch_upstream(repo_path, upstream_remote)
print("Creating Bugzilla bug report ...")
(bug_id, bug_url) = create_bugzilla_bug(bug_summary)
print("Created Bugzilla bug %d" % bug_id)
commits = [1234567, 9876543]
print("Creating contribution branch ...")
contribute_branch = cherry_pick_into_bug_branch(bug_id, bug_summary, commits, repo_path)
print("Created branch %s" % contribute_branch)
# TODO: Push contribute_branch
print("Creating GitHub pull request ...")
(pull_id, pull_url) = create_github_pull_request(bug_summary, contribute_branch)
print("Created pull request %d" % pull_id)
print("\nSuccess!")
print("\tMITK bug report: %s" % bug_url)
print("\tGitHub pull request: %s" % pull_url)
if __name__ == "__main__":
sys.exit(main(sys.argv))
# Install dependencies from this file with pip like so:
# $ pip install -r requirements.txt
github3.py
python-bugzilla
# Version of GitPython in pip is old. Why?? For now, use easy_install which
# has the latest version:
# $ easy_install gitpython
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment