2019-02-06 00:57:47 +01:00
import os
2019-02-05 20:51:40 +01:00
import hmac
import hashlib
2020-05-04 14:14:27 +02:00
import asyncio
2019-02-06 00:57:47 +01:00
import subprocess
2019-02-05 20:51:40 +01:00
from sanic import Sanic
from sanic . response import text
from sanic . exceptions import abort
app = Sanic ( )
2019-02-06 00:55:19 +01:00
secret = open ( " ./github_webhook_secret " , " r " ) . read ( ) . strip ( )
2019-02-06 00:58:50 +01:00
gitbot_password = open ( " ./gitbot_password " , " r " ) . read ( ) . strip ( )
2019-02-06 00:55:19 +01:00
2019-02-05 20:51:40 +01:00
other_chans = {
" doc " : " doc " ,
2019-02-06 17:23:49 +01:00
" apps " : " apps " ,
" package_linter " : " apps " ,
" CI_package_check " : " apps " ,
" package_check " : " apps " ,
" test_apps " : " apps " ,
2019-02-05 20:51:40 +01:00
}
# TODO
# * choper tous les templates de notification
# * choper tous les evenements à suivre
# * fusionner les 2
# * déployer
2020-05-04 14:16:45 +02:00
async def notify ( message , repository = " dev " ) :
2019-02-06 17:23:49 +01:00
if repository . endswith ( " _ynh " ) :
chan = " apps "
else :
chan = other_chans . get ( repository , " dev " )
2019-02-05 20:51:40 +01:00
print ( f " { chan } -> { message } " )
2020-05-04 14:14:27 +02:00
proc = await asyncio . create_subprocess_shell ( f " python ./to_room.py ' { gitbot_password } ' ' { message } ' ' { chan } ' " )
await proc . communicate ( )
await proc . wait ( )
2019-02-05 20:51:40 +01:00
2019-02-07 14:11:57 +01:00
@app.route ( " /github " , methods = [ ' GET ' ] )
async def github_get ( request ) :
return text ( " You aren ' t supposed to go on this page using a browser, it ' s for webhooks push instead. " )
2019-02-05 20:51:40 +01:00
@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
2019-02-05 23:17:23 +01:00
mac = hmac . new ( secret . encode ( ) , msg = request . body , digestmod = hashlib . sha1 )
2019-02-05 20:51:40 +01:00
if not hmac . compare_digest ( str ( mac . hexdigest ( ) ) , str ( signature ) ) :
abort ( 403 )
hook_type = request . headers . get ( " X-Github-Event " )
2019-02-06 13:53:57 +01:00
print ( )
2019-02-05 20:51:40 +01:00
print ( f " Hook type: { hook_type } " )
2019-02-06 13:56:49 +01:00
try :
# 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 " ]
2019-02-07 14:05:29 +01:00
commit_message = commits [ 0 ] [ " message " ] . replace ( " \r \n " , " " ) . replace ( " \n " , " " )
2019-02-06 13:16:20 +01:00
if len ( commit_message ) > 120 :
commit_message = commit_message [ 120 : ] + " ... "
2020-05-04 14:16:45 +02:00
await notify ( f " [ { repository } ] @ { user } pushed { len ( commits ) } commit to { branch } : { commit_message } { url } " , repository = repository )
2019-02-06 23:12:11 +01:00
elif len ( commits ) > 1 :
2019-02-06 13:56:49 +01:00
url = request . json [ " compare " ]
2020-05-04 14:16:45 +02:00
await notify ( f " [ { repository } ] @ { user } pushed { len ( commits ) } commits to { branch } : { url } " , repository = repository )
2019-02-07 15:47:39 +01:00
for commit in commits [ - 3 : ] :
2019-02-06 13:56:49 +01:00
author = commit [ " author " ] [ " name " ]
2019-02-07 14:05:29 +01:00
commit_message = commit [ " message " ] . replace ( " \r \n " , " " ) . replace ( " \n " , " " )
2019-02-06 13:56:49 +01:00
if len ( commit_message ) > 120 :
commit_message = commit_message [ 120 : ] + " ... "
2020-05-04 14:16:45 +02:00
await notify ( f " [ { repository } / { branch } ] { commit_message } - { author } " , repository = repository )
2019-02-06 23:12:11 +01:00
else :
. . . # case of 0 which means branch deletion
2019-02-06 13:56:49 +01:00
# 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 " ] . replace ( " \r \n " , " " )
2019-02-13 22:02:42 +01:00
url = request . json [ " comment " ] [ " html_url " ]
2019-02-06 13:56:49 +01:00
2020-05-04 14:16:45 +02:00
await notify ( f " [ { repository } ] @ { user } comment on commit { commit_short_id } : { comment } { url } " , repository = repository )
2019-02-06 13:56:49 +01:00
# 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 " :
2020-05-04 14:16:45 +02:00
await notify ( f " @ { user } created new repository { repository } : { url } " , repository = repository )
2019-02-06 13:56:49 +01:00
elif kind == " branch " :
branch = request . json [ " ref " ]
2020-05-04 14:16:45 +02:00
await notify ( f " [ { repository } ] @ { user } created new branch { branch } " , repository = repository )
2019-02-06 13:56:49 +01:00
elif kind == " tag " :
tag = request . json [ " ref " ]
2020-05-04 14:16:45 +02:00
await notify ( f " [ { repository } ] @ { user } created new tag { tag } " , repository = repository )
2019-02-06 13:56:49 +01:00
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 " ]
2020-05-04 14:16:45 +02:00
await notify ( f " [ { repository } ] @ { user } deleted { kind } { ref } " , repository = repository )
2019-02-06 13:56:49 +01:00
# 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 " ]
2020-05-04 14:16:45 +02:00
await notify ( f " @ { user } forked { repository } to { forked_repository } : { url } " , repository = repository )
2019-02-06 13:56:49 +01:00
# 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 " ] . replace ( " \r \n " , " " )
if len ( comment ) > 120 :
comment = comment [ : 120 ] + " ... "
2020-05-04 14:16:45 +02:00
await notify ( f " [ { repository } ] @ { user } commented on issue # { issue_number } { issue_title } : { comment } { url } " , repository = repository )
2019-02-06 13:56:49 +01:00
# 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 " :
2020-05-04 14:16:45 +02:00
await notify ( f " [ { repository } ] @ { user } { action } issue # { issue_number } : { issue_title } { url } " , repository = repository )
2019-02-06 13:56:49 +01:00
elif action in ( " edited " , " deleted " , " transferred " , " pinned " ,
" unpinned " , " closed " , " reopened " ) :
2020-05-04 14:16:45 +02:00
await notify ( f " [ { repository } ] @ { user } { action } issue # { issue_number } : { issue_title } { url } " , repository = repository )
2019-02-06 13:56:49 +01:00
elif action in ( " assigned " , " unassigned " ) :
2019-02-06 18:00:54 +01:00
assigned_user = request . json [ " assignee " ] [ " login " ]
2020-05-04 14:16:45 +02:00
await notify ( f " [ { repository } ] @ { user } { action } { assigned_user } on issue # { issue_number } : { issue_title } { url } " , repository = repository )
2019-02-06 13:56:49 +01:00
elif action in ( " labeled " , " unlabeled " ) :
2019-02-08 16:42:14 +01:00
label = request . json [ " label " ] [ " name " ]
2020-05-04 14:16:45 +02:00
await notify ( f " [ { repository } ] @ { user } { action } { label } on issue # { issue_number } : { issue_title } { url } " , repository = repository )
2019-02-06 13:56:49 +01:00
elif action == " milestoned " :
2019-02-06 23:02:18 +01:00
milestone = request . json [ " issue " ] [ " milestone " ] [ " title " ]
2020-05-04 14:16:45 +02:00
await notify ( f " [ { repository } ] @ { user } set { milestone } on issue # { issue_number } : { issue_title } { url } " , repository = repository )
2019-02-06 13:56:49 +01:00
elif action == " demilestoned " :
2020-05-04 14:16:45 +02:00
await notify ( f " [ { repository } ] @ { user } { action } issue # { issue_number } : { issue_title } { url } " , repository = repository )
2019-02-06 13:00:17 +01:00
2019-02-06 13:56:49 +01:00
else :
2020-05-04 14:16:45 +02:00
await notify ( f " [ { repository } ] WARNING: unknown ' issues ' action: { action } " , repository = repository )
2019-02-06 13:00:17 +01:00
2019-02-06 13:56:49 +01:00
# https://developer.github.com/v3/activity/events/types/#labelevent
elif hook_type == " label " :
action = request . json [ " action " ]
2019-02-12 22:26:08 +01:00
label = request . json [ " label " ] [ " name " ]
2019-02-06 13:56:49 +01:00
repository = request . json [ " repository " ] [ " name " ]
user = request . json [ " sender " ] [ " login " ]
2020-05-04 14:16:45 +02:00
await notify ( f " [ { repository } ] @ { user } { action } label { label } " , repository = repository )
2019-02-06 13:56:49 +01:00
# 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 " ]
2020-05-04 14:16:45 +02:00
await notify ( f " [ { repository } ] @ { user } { action } milestone { milestone } " , repository = repository )
2019-02-06 13:56:49 +01:00
# 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 " ]
2019-02-08 16:10:40 +01:00
pull_request_title = request . json [ " pull_request " ] [ " title " ]
2019-02-06 13:56:49 +01:00
comment = request . json [ " comment " ] [ " body " ] . replace ( " \r \n " , " " )
url = request . json [ " comment " ] [ " html_url " ]
if len ( comment ) > 120 :
comment = comment [ : 120 ] + " ... "
2019-02-20 23:16:11 +01:00
if action == " created " :
2020-05-04 14:16:45 +02:00
await notify ( f " [ { repository } ] @ { user } commented on pull request # { pull_request_number } { pull_request_title } : { comment } { url } " , repository = repository )
2019-02-20 23:16:11 +01:00
else :
2020-05-04 14:16:45 +02:00
await notify ( f " [ { repository } ] @ { user } { action } a comment on pull request # { pull_request_number } { pull_request_title } : { comment } { url } " , repository = repository )
2019-02-06 13:56:49 +01:00
# 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 " ]
url = request . json [ " review " ] [ " html_url " ]
if action == " submitted " :
state = request . json [ " review " ] [ " state " ]
comment = request . json [ " review " ] [ " body " ]
if comment and len ( comment ) > 120 :
comment = " : " + comment [ : 120 ] . replace ( " \r \n " , " " ) + " ... "
elif not comment :
comment = " "
else :
comment = " : " + comment . replace ( " \r \n " , " " )
2019-02-20 23:14:58 +01:00
# to avoid duplicated with pull_request_review_comment event
if state == " commented " and not comment :
pass
else :
2020-05-04 14:16:45 +02:00
await notify ( f " [ { repository } ] @ { user } { state } pull request # { pull_request_number } { pull_request_title } { comment } { url } " , repository = repository )
2019-02-06 13:19:09 +01:00
2019-02-06 13:56:49 +01:00
else :
2020-05-04 14:16:45 +02:00
await notify ( f " [ { repository } ] @ { user } { action } review pull request # { pull_request_number } : { pull_request_title } { url } " , repository = repository )
2019-02-06 13:56:49 +01:00
# 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 " ]
2019-02-06 17:34:10 +01:00
comment = request . json [ " pull_request " ] [ " body " ]
if comment and len ( comment ) > 120 :
comment = " : " + comment [ : 120 ] . replace ( " \r \n " , " " ) + " ... "
elif not comment :
comment = " "
else :
comment = " : " + comment . replace ( " \r \n " , " " )
2019-02-06 13:56:49 +01:00
if action in ( " opened " , " edited " , " deleted " , " transferred " , " pinned " ,
" unpinned " , " reopened " ) :
2020-05-04 14:16:45 +02:00
await notify ( f " [ { repository } ] @ { user } { action } pull request # { pull_request_number } : { pull_request_title } { url } " , repository = repository )
2019-02-06 13:56:49 +01:00
elif action in ( " labeled " , " unlabeled " ) :
2019-02-08 16:42:14 +01:00
label = request . json [ " label " ] [ " name " ]
2020-05-04 14:16:45 +02:00
await notify ( f " [ { repository } ] @ { user } { action } { label } on pull request # { pull_request_number } : { pull_request_title } { url } " , repository = repository )
2019-02-06 13:56:49 +01:00
elif action == " closed " :
if request . json [ " pull_request " ] [ " merged " ] :
action = " merged "
2020-05-04 14:16:45 +02:00
await notify ( f " [ { repository } ] @ { user } { action } pull request # { pull_request_number } : { pull_request_title } { url } " , repository = repository )
2019-02-06 13:56:49 +01:00
2020-02-17 00:38:41 +01:00
elif action == " ready_for_review " :
2020-05-04 14:16:45 +02:00
await notify ( f " [ { repository } ] @ { user } just made pull request # { pull_request_number } ready for review: { pull_request_title } { url } " , repository = repository )
2020-02-17 00:38:41 +01:00
2019-02-06 13:56:49 +01:00
# super weird, this action is not supposed to be possible for pull_request :|
elif action == " milestoned " :
milestone = request . json [ " pull_request " ] [ " milestone " ]
2020-05-04 14:16:45 +02:00
await notify ( f " [ { repository } ] @ { user } set { milestone } pull request # { pull_request_number } : { pull_request_title } { url } " , repository = repository )
2019-02-06 13:56:49 +01:00
# super weird, this action is not supposed to be possible for pull_request :|
elif action == " demilestoned " :
2020-05-04 14:16:45 +02:00
await notify ( f " [ { repository } ] @ { user } { action } pull request # { pull_request_number } : { pull_request_title } { url } " , repository = repository )
2019-02-06 13:56:49 +01:00
elif action in ( " review_requested " , " review_request_removed " , " synchronize " ) :
pass # we don't care about those...
2019-02-06 13:19:09 +01:00
2019-02-06 13:56:49 +01:00
else :
2020-05-04 14:16:45 +02:00
await notify ( f " WARNING: unknown ' pull_request ' action: { action } " , repository = repository )
2019-02-06 13:56:49 +01:00
# 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
2020-05-04 14:16:45 +02:00
await notify ( f " @ { user } { action } repository { repository } { description } { url } " , repository = repository )
2019-02-06 13:56:49 +01:00
# 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 " ]
2020-05-04 14:16:45 +02:00
await notify ( f " [repository] @ { user } { action } new release # { release_tag } { release_title } { url } " , repository = repository )
2019-02-06 13:56:49 +01:00
# 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 " ]
2019-02-20 23:09:52 +01:00
if state not in ( " success " , " pending " ) :
2020-05-04 14:16:45 +02:00
await notify ( f " [ { repository } ] { description } { target_url } on commit { url } " )
2019-02-20 23:06:47 +01:00
else :
print ( f " Status weird stuff: [ { repository } ] @ { user } state: { state } , description: { description } , target_url: { target_url } - { url } " )
2019-02-06 13:56:49 +01:00
return text ( " ok " )
except Exception as e :
import traceback
traceback . print_exc ( )
2020-05-04 14:16:45 +02:00
await notify ( f " Error in Webhooks: exception { e } on { hook_type } webhooks, please see logs " )
2019-02-06 13:56:49 +01:00
abort ( 500 )
2019-02-05 20:51:40 +01:00
@app.route ( " / " )
async def index ( request ) :
return text ( " Webhooks server. " )
if __name__ == ' __main__ ' :
2019-02-06 17:44:25 +01:00
app . run ( ' localhost ' , port = " 4567 " )