/ doc / examples / Webhook.rst
Webhook.rst
  1  Webhook
  2  =======
  3  
  4  Creating and Listening to Webhooks with PyGithub and Pyramid
  5  ------------------------------------------------------------
  6  
  7  To receive a continuous stream of events, one can set up a wsgiref app using Pyramid to handle
  8  incoming POST requests.
  9  
 10  The below code sets up a listener which creates and utilizes a webhook. Using
 11  'pull_request' and 'push' for the EVENT attributes, any time a PR is opened, closed, merged, or synced, or a commit is pushed,
 12  Github sends a POST containing a payload with information about the PR/push and its state.
 13  
 14  The below example was drawn largely from `Github's Examples <https://github.com/github/platform-samples/blob/master/api/python/building-a-ci-server/server.py>`__
 15  on working with Webhooks. A list of all applicable event types for Webhooks can be found in `Github's documentation <https://developer.github.com/v3/issues/events/>`__
 16  
 17  .. code-block:: python
 18  
 19      from wsgiref.simple_server import make_server
 20      from pyramid.config import Configurator
 21      from pyramid.view import view_config, view_defaults
 22      from pyramid.response import Response
 23      from github import Github
 24  
 25      ENDPOINT = "webhook"
 26  
 27      @view_defaults(
 28          route_name=ENDPOINT, renderer="json", request_method="POST"
 29      )
 30      class PayloadView(object):
 31          """
 32          View receiving of Github payload. By default, this view it's fired only if
 33          the request is json and method POST.
 34          """
 35  
 36          def __init__(self, request):
 37              self.request = request
 38              # Payload from Github, it's a dict
 39              self.payload = self.request.json
 40  
 41          @view_config(header="X-Github-Event:push")
 42          def payload_push(self):
 43              """This method is a continuation of PayloadView process, triggered if
 44              header HTTP-X-Github-Event type is Push"""
 45              print("No. commits in push:", len(self.payload['commits']))
 46              return Response("success")
 47  
 48          @view_config(header="X-Github-Event:pull_request")
 49          def payload_pull_request(self):
 50              """This method is a continuation of PayloadView process, triggered if
 51              header HTTP-X-Github-Event type is Pull Request"""
 52              print("PR", self.payload['action'])
 53              print("No. Commits in PR:", self.payload['pull_request']['commits'])
 54  
 55              return Response("success")
 56  
 57          @view_config(header="X-Github-Event:ping")
 58          def payload_else(self):
 59              print("Pinged! Webhook created with id {}!".format(self.payload["hook"]["id"]))
 60              return {"status": 200}
 61  
 62  
 63      def create_webhook():
 64          """ Creates a webhook for the specified repository.
 65  
 66          This is a programmatic approach to creating webhooks with PyGithub's API. If you wish, this can be done
 67          manually at your repository's page on Github in the "Settings" section. There is a option there to work with
 68          and configure Webhooks.
 69          """
 70  
 71          USERNAME = ""
 72          PASSWORD = ""
 73          OWNER = ""
 74          REPO_NAME = ""
 75          EVENTS = ["push", "pull_request"]
 76          HOST = ""
 77  
 78          config = {
 79              "url": "http://{host}/{endpoint}".format(host=HOST, endpoint=ENDPOINT),
 80              "content_type": "json"
 81          }
 82  
 83          g = Github(USERNAME, PASSWORD)
 84          repo = g.get_repo("{owner}/{repo_name}".format(owner=OWNER, repo_name=REPO_NAME))
 85          repo.create_hook("web", config, EVENTS, active=True)
 86  
 87  
 88      if __name__ == "__main__":
 89          config = Configurator()
 90  
 91          create_webhook()
 92  
 93          config.add_route(ENDPOINT, "/{}".format(ENDPOINT))
 94          config.scan()
 95  
 96          app = config.make_wsgi_app()
 97          server = make_server("0.0.0.0", 80, app)
 98          server.serve_forever()
 99  
100  
101  Outputs from a server configured as above:
102  
103  .. code-block:: console
104  
105      x.y.w.z - - [15/Oct/2018 23:49:19] "POST /webhook HTTP/1.1" 200 15
106      Pinged! Webhook created with id <redacted id>!
107      No. commits in push: 1
108      x.y.w.z - - [15/Oct/2018 23:49:32] "POST /webhook HTTP/1.1" 200 7
109      PR synchronize
110      x.y.w.z - - [15/Oct/2018 23:49:33] "POST /webhook HTTP/1.1" 200 7
111      No. Commits in PR: 10
112      PR closed
113      x.y.w.z - - [15/Oct/2018 23:49:56] "POST /webhook HTTP/1.1" 200 7
114      No. Commits in PR: 10
115      x.y.w.z - - [15/Oct/2018 23:50:00] "POST /webhook HTTP/1.1" 200 7
116      PR reopened
117      No. Commits in PR: 10