commitbot.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. # -*- coding: utf-8 -*-
  2. from http.server import BaseHTTPRequestHandler,HTTPServer
  3. import json
  4. import sys
  5. import irc
  6. # Attributes of the server this bot will run on
  7. SERVER_HOST = 'server.url.or.ip'
  8. SERVER_PORT = 11022
  9. # Attributes of the IRC connection
  10. IRC_SERVER = '127.0.0.1'
  11. IRC_PORT = 6667
  12. IRC_CHANNEL = ['#dev']
  13. IRC_NICK = 'commits-notifier'
  14. # Set the password for your registered empty, leave empty if not applicable
  15. # Note: freenode(and potentially other servers) want password to be of the form
  16. # "nick:pass", so for ex. IRC_PASS = 'WfTestBot:mypass123'
  17. IRC_PASS = ''
  18. # a dictionary of branches push-related events should be enabled for, or empty if all are enabled
  19. GH_PUSH_ENABLED_BRANCHES = [] # for example, ['master', 'testing', 'author/repo:branch']
  20. # a dictionary of branches push-related events should be ignored for, or empty if all are enabled
  21. GH_PUSH_IGNORE_BRANCHES = ['gh-pages']
  22. # a list of push-related events the bot should post notifications for
  23. GH_PUSH_ENABLED_EVENTS = ['push'] # no others supported for now
  24. # a list of PR-related events the bot should post notifications for
  25. # notice 'merged' is just a special case of 'closed'
  26. GH_PR_ENABLED_EVENTS = ['opened', 'closed', 'reopened'] # could also add 'synchronized', 'labeled', etc.
  27. # handle POST events from github server
  28. # We should also make sure to ignore requests from the IRC, which can clutter
  29. # the output with errors
  30. CONTENT_TYPE = 'content-type'
  31. CONTENT_LEN = 'content-length'
  32. EVENT_TYPE = 'x-github-event'
  33. ircc = irc.IRC()
  34. ircc.connect(IRC_SERVER, IRC_PORT, IRC_CHANNEL, IRC_NICK)
  35. def handle_push_event(irc, data):
  36. if GH_PUSH_ENABLED_BRANCHES:
  37. branch = get_branch_name_from_push_event(data)
  38. repo = data['repository']['full_name']
  39. repobranch = repo + ':' + branch
  40. if not branch in GH_PUSH_ENABLED_BRANCHES:
  41. if not repobranch in GH_PUSH_ENABLED_BRANCHES:
  42. return
  43. if GH_PUSH_IGNORE_BRANCHES:
  44. branch = get_branch_name_from_push_event(data)
  45. if branch in GH_PUSH_IGNORE_BRANCHES:
  46. return
  47. if 'push' in GH_PUSH_ENABLED_EVENTS:
  48. handle_forward_push(irc, data)
  49. def handle_pull_request(irc, data):
  50. author = data['sender']['login']
  51. if not data['action'] in GH_PR_ENABLED_EVENTS:
  52. return
  53. action = data['action']
  54. merged = data['pull_request']['merged']
  55. action = 'merged' if action == 'closed' and merged else action
  56. pr_num = '#' + str(data['number'])
  57. title = data['pull_request']['title']
  58. print("PR event:")
  59. print(f"@{author} {action} pull request {pr_num}: {title}")
  60. print("==============================================")
  61. irc.send("#dev", f"@{author} {action} pull request {pr_num}: {title}")
  62. def get_branch_name_from_push_event(data):
  63. return data['ref'].split('/')[-1]
  64. def handle_forward_push(irc, data):
  65. author = data['commits'][0]['author']['name']
  66. num_commits = len(data['commits'])
  67. num_commits = str(num_commits) + " commit" + ('s' if num_commits > 1 else '')
  68. branch = get_branch_name_from_push_event(data)
  69. commits = list(map(fmt_commit, data['commits']))
  70. for commit in commits:
  71. print("Push event:")
  72. print(f"@{author} pushed {num_commits} to {branch}: {commit}")
  73. print("==============================================")
  74. irc.send("#dev", f"@{author} pushed {num_commits} to {branch}: {commit}")
  75. def fmt_commit(cmt):
  76. hsh = cmt['id'][:10]
  77. # author = cmt['author']['name']
  78. message = cmt['message'].split("\n")
  79. message = message[0] \
  80. + ('...' if len(message) > 1 else '')
  81. return '{}: {}'.format(hsh, message)
  82. class MyHandler(BaseHTTPRequestHandler):
  83. def do_GET(self):
  84. pass
  85. def do_CONNECT(self):
  86. pass
  87. def do_POST(self):
  88. if not all(x in self.headers for x in [CONTENT_TYPE, CONTENT_LEN, EVENT_TYPE]):
  89. return
  90. content_type = self.headers['content-type']
  91. content_len = int(self.headers['content-length'])
  92. event_type = self.headers['x-github-event']
  93. if content_type != "application/json":
  94. self.send_error(400, "Bad Request", "Expected a JSON request")
  95. return
  96. data = self.rfile.read(content_len)
  97. if sys.version_info < (3, 6):
  98. data = data.decode()
  99. self.send_response(200)
  100. self.send_header('content-type', 'text/html')
  101. self.end_headers()
  102. self.wfile.write(bytes('OK', 'utf-8'))
  103. if event_type == 'push':
  104. handle_push_event(ircc, json.loads(data))
  105. elif event_type == 'pull_request':
  106. handle_pull_request(ircc, json.loads(data))
  107. return
  108. # Run Github webhook handling server
  109. try:
  110. server = HTTPServer((SERVER_HOST, SERVER_PORT), MyHandler)
  111. server.serve_forever()
  112. except KeyboardInterrupt:
  113. print("Exiting")
  114. server.socket.close()