#!/usr/bin/python # Quick and dirty webhook to accept merge request events from gitlab and turn them into buildbot try requests # Obsolete; see newer version https://github.com/buildbot/buildbot/pull/1820 import os import shutil import simplejson # for when you want better error messages import subprocess import tempfile import traceback import sys import urllib from sys import version as python_version from cgi import parse_header, parse_multipart if python_version.startswith('3'): from urllib.parse import parse_qs from http.server import BaseHTTPRequestHandler, HTTPServer else: from urlparse import parse_qs from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer def my_quote(s): return urllib.quote(s).replace("%20", " ") def verbose_system(s): print(s) sys.stdout.flush() try: subprocess.check_call('( '+ s + ') > log.txt 2>&1', shell=True) except: print("Failed! Log:") os.system("cat log.txt") raise def do_try(project, comment, surl, sbranch, uurl, ubranch, who): print("project is " + project) print("comment is " + comment) secrets = simplejson.load(open(os.path.expanduser("~/gitlab-try-secrets.json"))) try_server = secrets["try_server"] try_user = secrets["try_user"] try_pass = secrets["try_pass"] builders_str = subprocess.check_output("buildbot try -c pb --username=%s --passwd=%s -m %s --get-builder-names | grep -w '%s.*%s'" % (try_user, try_pass, try_server, project, ubranch), shell=True) print("builders_str is " + builders_str) opts=" ".join(["-b " + x for x in builders_str.split()]) print("opts is " + opts) dirpath = tempfile.mkdtemp() verbose_system("git clone -b %s %s %s" % (ubranch, uurl, dirpath)) verbose_system("cd %s && git remote add downstream %s && git fetch downstream" % (dirpath, surl)) verbose_system("cd %s && git checkout -b branch-to-try--%s downstream/%s" % (dirpath, sbranch, sbranch)) verbose_system("cd %s && git format-patch -M -B origin/%s --stdout > change.patch" % (dirpath, ubranch)) verbose_system("cd %s && buildbot try -c pb --username=%s --who='%s' --passwd=%s -m %s --diff=change.patch --patchlevel 1 %s --comment '%s'" % (dirpath, try_user, my_quote(who), try_pass, try_server, opts, my_quote(comment))) shutil.rmtree(dirpath) def do_merge_request(postvars): print("object_kind is " + postvars['object_kind']) print("username is " + postvars['user']['username']) print("name is " + postvars['user']['name']) o = postvars['object_attributes'] printf("author is " + o['source']['last_commit']['author']['name']) printf("email is " + o['source']['last_commit']['author']['email']) print("title is " + o['title']) print("description is " + o['description']) print("source_branch is " + o['source_branch']) print("source_url is " + o['source']['ssh_url']) print("target_branch is " + o['target_branch']) print("target_url is " + o['target']['ssh_url']) print("target_name is " + o['target']['name']) print("state is " + o['state']) print("merge_status is " + o['merge_status']) if o['state'] == 'closed' or o['merge_status'] != 'unchecked': print("skipping to avoid multiple runs on same merge request") sys.stdout.flush() return sys.stdout.flush() do_try(project = o['target']['name'], surl = o['source']['ssh_url'], sbranch = o['source_branch'], uurl = o['target']['ssh_url'], ubranch = o['target_branch'], comment=o['title'], who=o['source']['last_commit']['author']['email']) class RequestHandler(BaseHTTPRequestHandler): def reply_fail(self, val=400, reason='unknown'): message = 'Error: ' + reason self.send_response(val) self.send_header('Content-type', 'text') self.send_header("Content-length", str(len(message))) self.end_headers() self.wfile.write(message) def reply_ok(self): message = 'OK' self.send_response(200) self.send_header('Content-type', 'text') self.send_header("Content-length", str(len(message))) self.end_headers() self.wfile.write(message) def parse_POST(self): ctype, pdict = parse_header(self.headers['content-type']) if ctype == 'application/json': length = int(self.headers['content-length']) post = self.rfile.read(length) print("Got " + post) postvars = simplejson.loads(post) else: postvars = {} return postvars def do_POST(self): postvars = self.parse_POST() if postvars == {} or 'object_kind' not in postvars: self.reply_fail(400, reason='parse error') elif postvars['object_kind'] == "merge_request": try: # Have to reply immediately or gitlab will resend self.reply_ok() do_merge_request(postvars) except: traceback.print_exc() else: self.reply_fail(400, reason='cannot handle object_kind=%s' % postvars['object_kind']) def run(server_class=HTTPServer, handler_class=RequestHandler, port=80): server_address = ('', port) httpd = server_class(server_address, handler_class) print 'Starting httpd...' sys.stdout.flush() httpd.serve_forever() if __name__ == "__main__": from sys import argv if len(argv) == 6: do_try(argv[1], argv[2], argv[3], argv[4], argv[5]) elif len(argv) == 2: run(port=int(argv[1])) else: run()