Created
October 29, 2018 15:36
-
-
Save lukpueh/498ff3489321bdc7106c05a2fd5b941c to your computer and use it in GitHub Desktop.
Flask app to listen for a GitHub push webhook request on one repo and trigger a Travis build on another repo.
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
""" | |
Tiny flask app that listens for incoming requests from a "GitHub webhook", | |
and, if the webhook was triggered by a push to the "native_client" repo, | |
calls the "Travis API" to trigger a build for the "lind_project" repo. | |
""" | |
import os | |
import json | |
import hmac | |
import hashlib | |
import requests | |
from flask import Flask, request, abort | |
app = Flask(__name__) | |
# Make sure that you have exported your GitHub and Travis authentication tokens | |
# export TRAVIS_SECRET=<Travis API token> | |
# export GITHUB_SECRET=<GitHub webhook secret> | |
GITHUB_SECRET = os.environ["GITHUB_SECRET"] | |
TRAVIS_SECRET = os.environ["TRAVIS_SECRET"] | |
# Travis API endpoint to be called | |
TRAVIS_ENDPOINT = "https://api.travis-ci.com/repo/Lind-Project%2Flind_project/requests" | |
# Required headers for Travis API | |
TRAVIS_HEADERS = { | |
"Accept": "application/json", | |
"Content-Type": "application/json", | |
"Travis-API-Version": "3", | |
"Authorization": "token " + TRAVIS_SECRET | |
} | |
# IMPORTANT: Make sure to specify this route (https://<this server>/myhook) on | |
# GitHub's webhook configuration page as "Payload URL". | |
@app.route("/myhook", methods=['POST']) | |
def github_webhook_endpoint(): | |
"""Endpoint for a GitHub webhook, calling Travis API to trigger a build. | |
""" | |
# Extract signature header | |
signature = request.headers.get("X-Hub-Signature") | |
if not signature or not signature.startswith("sha1="): | |
abort(400, "X-Hub-Signature required") | |
# Create local hash of payload | |
digest = hmac.new(GITHUB_SECRET.encode(), | |
request.data, hashlib.sha1).hexdigest() | |
# Verify signature | |
if not hmac.compare_digest(signature, "sha1=" + digest): | |
abort(400, "Invalid signature") | |
# The ignature was fine, let's parse the data | |
request_data = request.get_json() | |
# We are only interested in push events from the a certain repo | |
if request_data.get("repository", {}).get("name") != "native_client": | |
return "I do not care about this event." | |
# If the push came indeed from that repo, we call the Travis API | |
# We use the following data to trigger a build of the latest commit on the | |
# master branch of the target repo (see TRAVIS_ENDPOINT). | |
# NOTE: We could send more complex things to Travis, e.g. based on what we | |
# received form GitHub, see the corresponding docs at: | |
# https://docs.travis-ci.com/user/triggering-builds/ | |
# https://developer.github.com/webhooks/ | |
data = { | |
"request": { | |
"branch":"master" | |
} | |
} | |
# NOTE: Travis does not understand the data if we pass it using `request`'s | |
# `json` parameter. With `data` it works. | |
travis_response = requests.post(TRAVIS_ENDPOINT, headers=TRAVIS_HEADERS, | |
data=json.dumps(data)) | |
# NOTE: The Travis API call will most likely take so long that GitHub's | |
# request times out. If we want to return a proper answer in time, we could | |
# perform the Travis API call in a background task, e.g. using `celery`. | |
# http://flask.pocoo.org/docs/1.0/patterns/celery/ | |
return "Okay, thank you, if you still care." | |
if __name__ == "__main__": | |
app.run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment