X-Git-Url: https://git.ralfj.de/git-mirror.git/blobdiff_plain/503462ba4433cef0cf10deaf9595a431157832ee..HEAD:/webhook-core.py diff --git a/webhook-core.py b/webhook-core.py index 93b138c..90432c8 100755 --- a/webhook-core.py +++ b/webhook-core.py @@ -1,5 +1,5 @@ #!/usr/bin/python3 -# Copyright (c) 2014, Ralf Jung +# Copyright (c) 2015, Ralf Jung # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -23,44 +23,72 @@ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #============================================================================== -# This is the hook called by git post-commit. It updats all mirrors to the status of the local repository. -import sys, traceback +# This is the hook called by GitHub as webhook. It updats the local repository, and then all the other mirrors. +import sys, traceback, json from git_mirror import * +def get_github_payload(repo, signature): + '''Return the github-style JSON encoded payload (as if we were called as a github webhook)''' + data = sys.stdin.buffer.read() + verify_signature = repo.compute_hmac(data) + if signature != "sha1="+verify_signature: + raise Exception("You are not GitHub!") + try: + data = json.loads(data.decode('utf-8')) + return data + except ValueError: + return {} # nothing read + + if __name__ == "__main__": + # call this with: repo = None # we will try to use this during exception handling try: repos = load_repos() - reponame = sys.argv[1] if len(sys.argv) > 1 else None + if len(sys.argv) < 4: + raise Exception("Usage: {} ".format(os.path.basename(sys.argv[0]))) + reponame = sys.argv[1] + githubEvent = sys.argv[2] + githubSignature = sys.argv[3] if reponame not in repos: - raise Exception("Repository missing or not found.") + raise Exception("Repository {} missing or not found.".format(reponame)) repo = repos[reponame] # now sync this repository - data = get_github_payload() - ref = data["ref"] - oldsha = data["before"] - newsha = data["after"] - # validate the ref name - if re.match('refs/[a-z/]+', ref) is None: - raise Exception("Invalid ref name {0}".format(ref)) - # collect URLs of this repository, to find the mirror name - urls = [] - for key in ("git_url", "ssh_url", "clone_url"): - urls.append(data["repository"][key]) - mirror = repo.find_mirror_by_url(urls) - if mirror is None: - raise Exception("Could not find the mirror.") - repo.update_ref_from_mirror(ref, oldsha, newsha, mirror, suppress_stderr = True) - # print an answer - print("Content-Type: text/plain") - print() - print("Updated {0}:{1} from mirror {2} from {3} to {4}".format(reponame, ref, mirror, oldsha, newsha)) + data = get_github_payload(repo, githubSignature) + if githubEvent == 'ping': + # github sends this initially + print("Content-Type: text/plain") + print() + print("Pong!") + sys.exit(0) + elif githubEvent == 'push': + ref = data["ref"] + oldsha = data["before"] + newsha = data["after"] + # validate the ref name + if re.match('refs/[a-z/]+', ref) is None: + raise Exception("Invalid ref name {}".format(ref)) + # collect URLs of this repository, to find the mirror name + urls = [] + for key in ("git_url", "ssh_url", "clone_url"): + urls.append(data["repository"][key]) + mirror = repo.find_mirror_by_url(urls) + if mirror is None: + raise Exception("Could not find the mirror.") + stdout = repo.update_ref_from_mirror(ref, oldsha, newsha, mirror, suppress_stderr = True) + # print an answer + print("Content-Type: text/plain") + print() + print("Updated {}:{} from mirror {} from {} to {}".format(reponame, ref, mirror, oldsha, newsha)) + print(stdout) + else: + raise Exception("Unexpected github event {}.".format(githubEvent)) except Exception as e: if repo is not None: - repo.mail_owner("There was a problem running the git-mirror webhook:\n\n{0}".format(traceback.format_exc())) + repo.mail_owner("There was a problem running the git-mirror webhook:\n\n{}".format(traceback.format_exc())) # do not print all the details print("Status: 500 Internal Server Error") print("Content-Type: text/plain") print() - print("We have a problem:\n{0}".format('\n'.join(traceback.format_exception_only(type(e), e)))) + print("git-mirror: We have a problem:\n{}".format('\n'.join(traceback.format_exception_only(type(e), e))))