webhooks/server.py
2019-02-06 13:35:09 +01:00

308 lines
12 KiB
Python

import os
import hmac
import hashlib
import subprocess
from sanic import Sanic
from sanic.response import text
from sanic.exceptions import abort
app = Sanic()
secret = open("./github_webhook_secret", "r").read().strip()
gitbot_password = open("./gitbot_password", "r").read().strip()
other_chans = {
"doc": "doc",
}
# TODO
# * choper tous les templates de notification
# * choper tous les evenements à suivre
# * fusionner les 2
# * déployer
def notify(message, chan="dev"):
print(f"{chan} -> {message}")
subprocess.check_call(["python", "./to_room.py", gitbot_password, message, chan])
@app.route("/github", methods=['POST'])
async def github(request):
# Only SHA1 is supported
header_signature = request.headers.get('X-Hub-Signature')
if header_signature is None:
print("no header X-Hub-Signature")
abort(403)
sha_name, signature = header_signature.split('=')
if sha_name != 'sha1':
print("signing algo isn't sha1, it's '%s'" % sha_name)
abort(501)
# HMAC requires the key to be bytes, but data is string
mac = hmac.new(secret.encode(), msg=request.body, digestmod=hashlib.sha1)
if not hmac.compare_digest(str(mac.hexdigest()), str(signature)):
abort(403)
hook_type = request.headers.get("X-Github-Event")
print(f"Hook type: {hook_type}")
# https://developer.github.com/v3/activity/events/types/#pushevent
if hook_type == "push":
repository = request.json["repository"]["name"]
commits = request.json["commits"]
user = request.json["pusher"]["name"]
branch = request.json["ref"].split("/", 2)[2]
if len(commits) == 1:
url = commits[0]["url"]
notify(f"[{repository}] @{user} pushed {len(commits)} commit to {branch}: {url}")
else:
url = request.json["compare"]
notify(f"[{repository}] @{user} pushed {len(commits)} commits to {branch}: {url}")
for commit in commits[-5:]:
author = commit["author"]["name"]
commit_message = commit["message"].replace("\n", " ")
if len(commit_message) > 120:
commit_message = commit_message[120:] + "..."
notify(f"[{repository}/{branch}] {commit_message} - {author}")
# https://developer.github.com/v3/activity/events/types/#commitcommentevent
elif hook_type == "commit_comment":
repository = request.json["repository"]["name"]
user = request.json["comment"]["user"]["login"]
commit_short_id = request.json["comment"]["commit_id"][:7]
comment = request.json["comment"]["body"]
notify(f"[{repository}] @{user} comment on commit {commit_short_id}: {comment} {url}")
# https://developer.github.com/v3/activity/events/types/#createevent
elif hook_type == "create":
kind = request.json["ref_type"]
user = request.json["sender"]["login"]
repository = request.json["repository"]["name"]
if kind == "repository":
notify(f"@{user} created new repository {repository}: {url}")
elif kind == "branch":
branch = request.json["ref"]
notify(f"[{repository}] @{user} created new branch {branch}")
elif kind == "tag":
tag = request.json["ref"]
notify(f"[{repository}] @{user} created new tag {tag}")
else:
print(f"WARNING: unknown 'create' event kind: {kind}")
# https://developer.github.com/v3/activity/events/types/#createevent
elif hook_type == "delete":
kind = request.json["ref_type"]
user = request.json["sender"]["login"]
repository = request.json["repository"]["name"]
ref = request.json["ref"]
notify(f"[{repository}] @{user} deleted {kind} {ref}")
# https://developer.github.com/v3/activity/events/types/#forkevent
elif hook_type == "fork":
repository = request.json["repository"]["name"]
forked_repository = request.json["forkee"]["full_name"]
user = request.json["sender"]["login"]
url = request.json["forkee"]["html_url"]
notify(f"@{user} forked {repository} to {forked_repository}: {url}")
# https://developer.github.com/v3/activity/events/types/#issuecommentevent
elif hook_type == "issue_comment":
repository = request.json["repository"]["name"]
user = request.json["sender"]["login"]
url = request.json["comment"]["html_url"]
issue_number = request.json["issue"]["number"]
issue_title = request.json["issue"]["title"]
comment = request.json["comment"]["body"]
if len(comment) > 120:
comment = comment[:120] + "..."
notify(f"[{repository}] @{user} commented on issue #{issue_number} {issue_title}: {comment} {url}")
# https://developer.github.com/v3/activity/events/types/#issuesevent
elif hook_type == "issues":
action = request.json["action"]
repository = request.json["repository"]["name"]
user = request.json["sender"]["login"]
issue_number = request.json["issue"]["number"]
url = request.json["issue"]["html_url"]
issue_title = request.json["issue"]["title"]
if action == "opened":
notify(f"[{repository}] @{user} {action} issue #{issue_number}: {issue_title} {url}")
elif action in ("edited", "deleted", "transferred", "pinned",
"unpinned", "closed", "reopened"):
notify(f"[{repository}] @{user} {action} issue #{issue_number}: {issue_title} {url}")
elif action in ("assigned", "unassigned"):
assigned_user = request.json["assignee"]
notify(f"[{repository}] @{user} {action} {assigned_user} on issue #{issue_number}: {issue_title} {url}")
elif action in ("labeled", "unlabeled"):
label = request.json["label"]
notify(f"[{repository}] @{user} {action} {label} on issue #{issue_number}: {issue_title} {url}")
elif action == "milestoned":
milestone = request.json["issue"]["milestone"]
notify(f"[{repository}] @{user} {action} {milestone} issue #{issue_number}: {issue_title} {url}")
elif action == "demilestoned":
notify(f"[{repository}] @{user} {action} issue #{issue_number}: {issue_title} {url}")
else:
notify(f"WARNING: unknown 'issues' action: {action}")
# https://developer.github.com/v3/activity/events/types/#labelevent
elif hook_type == "label":
action = request.json["action"]
label = request.json["label"]
repository = request.json["repository"]["name"]
user = request.json["sender"]["login"]
notify(f"[{repository}] @{user} {action} label {label}")
# https://developer.github.com/v3/activity/events/types/#milestoneevent
elif hook_type == "milestone":
action = request.json["action"]
repository = request.json["repository"]["name"]
user = request.json["sender"]["login"]
milestone = request.json["milestone"]["title"]
notify(f"[{repository}] @{user} {action} milestone {milestone}")
# https://developer.github.com/v3/activity/events/types/#pullrequestreviewcommentevent
elif hook_type == "pull_request_review_comment":
action = request.json["action"]
repository = request.json["repository"]["name"]
user = request.json["sender"]["login"]
pull_request_number = request.json["pull_request"]["number"]
comment = request.json["comment"]["body"]
url = request.json["comment"]["html_url"]
if len(comment) > 120:
comment = comment[:120] + "..."
notify(f"[{repository}] @{user} {action} a comment on pull request #{pull_request_number}: {comment} {url}")
# https://developer.github.com/v3/activity/events/types/#pullrequestreviewevent
elif hook_type == "pull_request_review":
action = request.json["action"]
repository = request.json["repository"]["name"]
user = request.json["sender"]["login"]
pull_request_number = request.json["pull_request"]["number"]
pull_request_title = request.json["pull_request"]["title"]
if action == "submitted":
state = request.json["review"]["state"]
comment = request.json["review"]["body"]
if comment and len(comment) > 120:
comment = ": " + comment[:120] + "..."
elif not comment:
comment = ""
else:
comment = ": " + comment
notify(f"[{repository}] @{user} {state} pull request #{pull_request_number} {pull_request_title}{comment} {url}")
else:
notify(f"[{repository}] @{user} {action} review pull request #{pull_request_number}: {pull_request_title} {url}")
# https://developer.github.com/v3/activity/events/types/#pullrequestevent
elif hook_type == "pull_request":
action = request.json["action"]
repository = request.json["repository"]["name"]
user = request.json["sender"]["login"]
pull_request_number = request.json["pull_request"]["number"]
pull_request_title = request.json["pull_request"]["title"]
url = request.json["pull_request"]["html_url"]
comment = request.json["comment"]["body"]
if action in ("opened", "edited", "deleted", "transferred", "pinned",
"unpinned", "reopened"):
notify(f"[{repository}] @{user} {action} pull_request #{pull_request_number}: {pull_request_title} {url}")
elif action in ("labeled", "unlabeled"):
label = request.json["label"]
notify(f"[{repository}] @{user} {action} {label} on issue #{issue_number}: {issue_title} {url}")
elif action == "closed":
if request.json["pull_request"]["merged"]:
action = "merged"
notify(f"[{repository}] @{user} {action} {milestone} pull_request #{pull_request_number}: {pull_request_title} {url}")
# super weird, this action is not supposed to be possible for pull_request :|
elif action == "milestoned":
milestone = request.json["pull_request"]["milestone"]
notify(f"[{repository}] @{user} {action} {milestone} pull_request #{pull_request_number}: {pull_request_title} {url}")
# super weird, this action is not supposed to be possible for pull_request :|
elif action == "demilestoned":
notify(f"[{repository}] @{user} {action} pull_request #{pull_request_number}: {pull_request_title} {url}")
elif action in ("review_requested", "review_request_removed"):
pass # we don't care about those...
else:
notify(f"WARNING: unknown 'pull_requests' action: {action}")
# https://developer.github.com/v3/activity/events/types/#repositoryevent
elif hook_type == "repository":
action = request.json["action"]
repository = request.json["repository"]["name"]
user = request.json["sender"]["login"]
url = request.json["repository"]["html_url"]
description = request.json["repository"]["description"]
if not description:
description = ""
else:
description = ": " + description
notify(f"@{user} {action} repository {repository}{description} {url}")
# https://developer.github.com/v3/activity/events/types/#releaseevent
elif hook_type == "release":
action = request.json["action"]
repository = request.json["repository"]["name"]
user = request.json["sender"]["login"]
url = request.json["release"]["html_url"]
release_tag = request.json["release"]["tag_name"]
release_title = request.json["release"]["name"]
notify(f"[repository] @{user} {action} new release #{release_tag} {release_title} {url}")
# https://developer.github.com/v3/activity/events/types/#statusevent
elif hook_type == "status":
state = request.json["state"]
description = request.json["description"]
target_url = request.json["target_url"]
repository = request.json["repository"]["name"]
user = request.json["sender"]["login"]
url = request.json["commit"]["html_url"]
print(f"Status weird stuff: [{repository}] @{user} state: {state}, description: {description}, target_url: {target_url} - {url}")
return text("ok")
@app.route("/")
async def index(request):
return text("Webhooks server.")
if __name__ == '__main__':
app.run('localhost', port="4567", debug=True)