Last active
August 29, 2015 14:01
-
-
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
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
.idea/ | |
*.pyc |
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 | |
# 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)) |
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
# 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