Skip to content

Instantly share code, notes, and snippets.

@lukpueh
Created October 29, 2018 15:36
Show Gist options
  • Save lukpueh/498ff3489321bdc7106c05a2fd5b941c to your computer and use it in GitHub Desktop.
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.
"""
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