#!/usr/bin/env python import contextlib import git import github import json import lockfile import os import re import sys def system(x): r = os.system(x) if r != 0: raise RuntimeError("%r: Exited with status %d" % (x, r)) workdir = '/home/jepler/src/python-github-webhooks/workdir' lockfilename = '/home/jepler/src/python-github-webhooks/workdir/.lock' with open('/home/jepler/.github-credentials', 'r') as f: github_credentials = f.read().strip().split(':', 1) with open(sys.argv[1], 'r') as jsf: payload = json.loads(jsf.read()) ### Do something with the payload g = github.Github(*github_credentials) pu = payload['pull_request']['base']['user']['login'] if pu != github_credentials[0]: raise RuntimeError("surprising user %r in pull request base" % (pu,)) pu = payload['pull_request']['base']['repo']['full_name'] if pu != 'jepler/linuxcnc': raise RuntimeError("surprising repo %r in pull request base" % (pu,)) u = g.get_user() r = u.get_repo('linuxcnc') head_ref = payload['pull_request']['head']['ref'] c = r.get_commit(head_ref) @contextlib.contextmanager def status_update(commit, args): args['state'] = 'pending' print >>sys.stderr, "create_status", commit, args commit.create_status(**args) args['state'] = 'error' try: yield finally: print >>sys.stderr, "create_status", commit, args commit.create_status(**args) status_args = dict( target_url = 'http://linuxcnc.org/docs/2.7/html/code/contributing-to-linuxcnc.html#_signed_off_by_policy', description = 'Do commits conform to policy', context = 'linuxcnc.org/signed-off-by' ) # October 5, 2014 cutoff_date = 1412485200 def is_old(c): return c.authored_date < cutoff_date def is_merge(c): return len(c.parents) > 1 def is_sob(c): return re.search('^Signed-off-by:', c.message, re.M) failed = [] with lockfile.FileLock(lockfilename), status_update(c, status_args): os.chdir(workdir) system("git fetch -f %s %s:base" % ( payload['pull_request']['base']['repo']['clone_url'], payload['pull_request']['base']['ref'])) system("git fetch -f %s %s:head" % ( payload['pull_request']['head']['repo']['clone_url'], payload['pull_request']['head']['ref'])) git_repo = git.repo.Repo('.') for c in git_repo.iter_commits('base..head'): if is_old(c): continue if is_merge(c): continue if is_sob(c): continue failed.append(c.hexsha) if failed: status_args['description'] = "Commits do not conform to signed-off-by policy: %s" % ( " ".join(failed)) status_args['state'] = 'failure' else: status_args['description'] = "All commits conform to signed-off-by policy" status_args['state'] = 'success'