-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwebhook-handler.py
More file actions
107 lines (96 loc) · 3.45 KB
/
webhook-handler.py
File metadata and controls
107 lines (96 loc) · 3.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import settings
import actions
import hmac
from json import loads, dumps, dump
from flask import Flask, request, abort
from hashlib import sha1
application = Flask(__name__)
@application.route('/github', methods=['POST'])
def handle_web_hook():
# If settigs tell us to check signature, do it
if settings.check_signature:
header_signature = request.headers.get('X-Hub-Signature')
if header_signature is None:
print "No github signature found!"
abort(403)
sha_name, signature = header_signature.split('=')
# Only SHA1 is supported
if sha_name != 'sha1':
abort(501)
# HMAC requires the key to be bytes, but data is string
mac = hmac.new(str(settings.secret), msg=request.data, digestmod=sha1)
if not str(mac.hexdigest()) == str(signature):
print "Invalid github signature"
abort(403)
event = request.headers.get('X-GitHub-Event', 'ping')
# Handle ping event
if event == 'ping':
return dumps({'msg': 'pong'})
# Gather data
try:
payload = loads(request.data)
except ValueError:
abort(400)
# Get repository name and branch
name, branch = get_branch_parameters(payload, event)
# Dump payload, if necessary
if settings.dump_payload:
write_payload(payload)
# Execute action according to recieved event
execute_action(event, name, branch, payload)
# Make a response. It is not really important
response = {
"name": name,
"branch": branch,
"event": event,
}
return dumps(response)
# Given a payload and an event,
# it returns a tuple with repository name and branch
def get_branch_parameters(payload, event):
try:
# Case 1: a ref_type indicates the type of ref.
# This true for create and delete events.
if 'ref_type' in payload:
if payload['ref_type'] == 'branch':
branch = payload['ref']
# Case 2: a pull_request object is involved. This is pull_request and
# pull_request_review_comment events.
elif 'pull_request' in payload:
branch = payload['pull_request']['head']['ref']
elif event in ['push']:
# Push events provide a full Git ref in 'ref' and not a 'ref_type'.
branch = payload['ref'].split('/')[2]
else:
branch = None
except KeyError:
# If the payload structure isn't what we expect, we'll live without
# the branch name
branch = None
# All current events have a repository, but some legacy events do not,
# so let's be safe
try:
name = payload['repository']['name']
except KeyError:
name = None
return (name, branch)
# It will write a payload in a file.
# The file path is given in settings.dump_payload_file
def write_payload(payload):
with open(settings.dump_payload_file, 'a') as json_file:
dump(payload, json_file, indent=2)
# Perform an action, according to event type
def execute_action(event, name, branch, payload):
defined_actions = {
"push": actions.push,
"pull_request": actions.pull_request,
}
try:
action = defined_actions[event]
except KeyError:
print "Ignoring undefined event: '%s'" % event
return None
print "Executing action for event: '%s'" % event
return action(name, branch, payload)
if __name__ == '__main__':
application.run(debug=True, host='0.0.0.0')