We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Bitbucket Cloud web hook returns 500
Started three weeks ago (missed it due to vacations), my guess is that Bitbucket changed something. Error log looks like this:

```
2019-07-02 14:33:40+0300 [_GenericHTTPChannelProtocol,13,18.234.32.226] adding changes from web hook
        Traceback (most recent call last):
          File "/home/buildbot/sandbox/lib/python3.5/site-packages/twisted/internet/defer.py", line 1418, in _inlineCallbacks
            result = g.send(result)
          File "/home/buildbot/sandbox/lib/python3.5/site-packages/buildbot/www/change_hook.py", line 106, in getAndSubmitChanges
            changes, src = yield self.getChanges(request)
          File "/home/buildbot/sandbox/lib/python3.5/site-packages/twisted/internet/defer.py", line 1613, in unwindGenerator
            return _cancellableInlineCallbacks(gen)
          File "/home/buildbot/sandbox/lib/python3.5/site-packages/twisted/internet/defer.py", line 1529, in _cancellableInlineCallbacks
            _inlineCallbacks(None, g, status)
        --- <exception caught here> ---
          File "/home/buildbot/sandbox/lib/python3.5/site-packages/buildbot/www/change_hook.py", line 106, in getAndSubmitChanges
            changes, src = yield self.getChanges(request)
          File "/home/buildbot/sandbox/lib/python3.5/site-packages/twisted/internet/defer.py", line 1418, in _inlineCallbacks
            result = g.send(result)
          File "/home/buildbot/sandbox/lib/python3.5/site-packages/buildbot/www/change_hook.py", line 167, in getChanges
            changes, src = yield handler.getChanges(request)
          File "/home/buildbot/sandbox/lib/python3.5/site-packages/buildbot/www/hooks/bitbucketcloud.py", line 163, in getChanges
            return self.process(request)
          File "/home/buildbot/sandbox/lib/python3.5/site-packages/buildbot/www/hooks/bitbucketcloud.py", line 54, in process
            return handler(payload)
          File "/home/buildbot/sandbox/lib/python3.5/site-packages/buildbot/www/hooks/bitbucketcloud.py", line 97, in handle_repo_push
            payload['actor']['username']),
        builtins.KeyError: 'username'
```

Last line reveals the culprit.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `master/buildbot/www/hooks/bitbucketcloud.py`
Content:
```
1 # This file is part of Buildbot.  Buildbot is free software: you can
2 # redistribute it and/or modify it under the terms of the GNU General Public
3 # License as published by the Free Software Foundation, version 2.
4 #
5 # This program is distributed in the hope that it will be useful, but WITHOUT
6 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
7 # FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
8 # details.
9 #
10 # You should have received a copy of the GNU General Public License along with
11 # this program; if not, write to the Free Software Foundation, Inc., 51
12 # Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
13 #
14 # Copyright Buildbot Team Members
15 # Copyright Mamba Team
16 
17 
18 import json
19 
20 from twisted.python import log
21 
22 from buildbot.util import bytes2unicode
23 
24 GIT_BRANCH_REF = "refs/heads/{}"
25 GIT_MERGE_REF = "refs/pull-requests/{}/merge"
26 GIT_TAG_REF = "refs/tags/{}"
27 
28 _HEADER_EVENT = b'X-Event-Key'
29 
30 
31 class BitbucketCloudEventHandler:
32 
33     def __init__(self, master, options=None):
34         if options is None:
35             options = {}
36         self.master = master
37         if not isinstance(options, dict):
38             options = {}
39         self.options = options
40         self._codebase = self.options.get('codebase', None)
41 
42     def process(self, request):
43         payload = self._get_payload(request)
44         event_type = request.getHeader(_HEADER_EVENT)
45         event_type = bytes2unicode(event_type)
46         log.msg("Processing event {header}: {event}"
47                 .format(header=_HEADER_EVENT, event=event_type))
48         event_type = event_type.replace(":", "_")
49         handler = getattr(self, 'handle_{}'.format(event_type), None)
50 
51         if handler is None:
52             raise ValueError('Unknown event: {}'.format(event_type))
53 
54         return handler(payload)
55 
56     def _get_payload(self, request):
57         content = request.content.read()
58         content = bytes2unicode(content)
59         content_type = request.getHeader(b'Content-Type')
60         content_type = bytes2unicode(content_type)
61         if content_type.startswith('application/json'):
62             payload = json.loads(content)
63         else:
64             raise ValueError('Unknown content type: {}'
65                              .format(content_type))
66 
67         log.msg("Payload: {}".format(payload))
68 
69         return payload
70 
71     def handle_repo_push(self, payload):
72         changes = []
73         project = payload['repository']['project']['name']
74         repo_url = payload['repository']['links']['self']['href']
75         web_url = payload['repository']['links']['html']['href']
76 
77         for payload_change in payload['push']['changes']:
78             if payload_change['new']:
79                 age = 'new'
80                 category = 'push'
81             else:  # when new is null the ref is deleted
82                 age = 'old'
83                 category = 'ref-deleted'
84 
85             commit_hash = payload_change[age]['target']['hash']
86 
87             if payload_change[age]['type'] == 'branch':
88                 branch = GIT_BRANCH_REF.format(payload_change[age]['name'])
89             elif payload_change[age]['type'] == 'tag':
90                 branch = GIT_TAG_REF.format(payload_change[age]['name'])
91 
92             change = {
93                 'revision': commit_hash,
94                 'revlink': '{}/commits/{}'.format(web_url, commit_hash),
95                 'repository': repo_url,
96                 'author': '{} <{}>'.format(payload['actor']['display_name'],
97                                            payload['actor']['username']),
98                 'comments': 'Bitbucket Cloud commit {}'.format(commit_hash),
99                 'branch': branch,
100                 'project': project,
101                 'category': category
102             }
103 
104             if callable(self._codebase):
105                 change['codebase'] = self._codebase(payload)
106             elif self._codebase is not None:
107                 change['codebase'] = self._codebase
108 
109             changes.append(change)
110 
111         return (changes, payload['repository']['scm'])
112 
113     def handle_pullrequest_created(self, payload):
114         return self.handle_pullrequest(
115             payload,
116             GIT_MERGE_REF.format(int(payload['pullrequest']['id'])),
117             "pull-created")
118 
119     def handle_pullrequest_updated(self, payload):
120         return self.handle_pullrequest(
121             payload,
122             GIT_MERGE_REF.format(int(payload['pullrequest']['id'])),
123             "pull-updated")
124 
125     def handle_pullrequest_fulfilled(self, payload):
126         return self.handle_pullrequest(
127             payload,
128             GIT_BRANCH_REF.format(
129                 payload['pullrequest']['toRef']['branch']['name']),
130             "pull-fulfilled")
131 
132     def handle_pullrequest_rejected(self, payload):
133         return self.handle_pullrequest(
134             payload,
135             GIT_BRANCH_REF.format(
136                 payload['pullrequest']['fromRef']['branch']['name']),
137             "pull-rejected")
138 
139     def handle_pullrequest(self, payload, refname, category):
140         pr_number = int(payload['pullrequest']['id'])
141         repo_url = payload['repository']['links']['self']['href']
142         change = {
143             'revision': payload['pullrequest']['fromRef']['commit']['hash'],
144             'revlink': payload['pullrequest']['link'],
145             'repository': repo_url,
146             'author': '{} <{}>'.format(payload['actor']['display_name'],
147                                        payload['actor']['username']),
148             'comments': 'Bitbucket Cloud Pull Request #{}'.format(pr_number),
149             'branch': refname,
150             'project': payload['repository']['project']['name'],
151             'category': category,
152             'properties': {'pullrequesturl': payload['pullrequest']['link']}
153         }
154 
155         if callable(self._codebase):
156             change['codebase'] = self._codebase(payload)
157         elif self._codebase is not None:
158             change['codebase'] = self._codebase
159 
160         return [change], payload['repository']['scm']
161 
162     def getChanges(self, request):
163         return self.process(request)
164 
165 
166 bitbucketcloud = BitbucketCloudEventHandler
167
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/master/buildbot/www/hooks/bitbucketcloud.py b/master/buildbot/www/hooks/bitbucketcloud.py
--- a/master/buildbot/www/hooks/bitbucketcloud.py
+++ b/master/buildbot/www/hooks/bitbucketcloud.py
@@ -70,7 +70,7 @@
 
     def handle_repo_push(self, payload):
         changes = []
-        project = payload['repository']['project']['name']
+        project = payload['repository'].get('project', {'name': 'none'})['name']
         repo_url = payload['repository']['links']['self']['href']
         web_url = payload['repository']['links']['html']['href']
 
@@ -94,7 +94,7 @@
                 'revlink': '{}/commits/{}'.format(web_url, commit_hash),
                 'repository': repo_url,
                 'author': '{} <{}>'.format(payload['actor']['display_name'],
-                                           payload['actor']['username']),
+                                           payload['actor']['nickname']),
                 'comments': 'Bitbucket Cloud commit {}'.format(commit_hash),
                 'branch': branch,
                 'project': project,
@@ -139,15 +139,16 @@
     def handle_pullrequest(self, payload, refname, category):
         pr_number = int(payload['pullrequest']['id'])
         repo_url = payload['repository']['links']['self']['href']
+        project = payload['repository'].get('project', {'name': 'none'})['name']
         change = {
             'revision': payload['pullrequest']['fromRef']['commit']['hash'],
             'revlink': payload['pullrequest']['link'],
             'repository': repo_url,
             'author': '{} <{}>'.format(payload['actor']['display_name'],
-                                       payload['actor']['username']),
+                                       payload['actor']['nickname']),
             'comments': 'Bitbucket Cloud Pull Request #{}'.format(pr_number),
             'branch': refname,
-            'project': payload['repository']['project']['name'],
+            'project': project,
             'category': category,
             'properties': {'pullrequesturl': payload['pullrequest']['link']}
         }

{"golden_diff": "diff --git a/master/buildbot/www/hooks/bitbucketcloud.py b/master/buildbot/www/hooks/bitbucketcloud.py\n--- a/master/buildbot/www/hooks/bitbucketcloud.py\n+++ b/master/buildbot/www/hooks/bitbucketcloud.py\n@@ -70,7 +70,7 @@\n \n     def handle_repo_push(self, payload):\n         changes = []\n-        project = payload['repository']['project']['name']\n+        project = payload['repository'].get('project', {'name': 'none'})['name']\n         repo_url = payload['repository']['links']['self']['href']\n         web_url = payload['repository']['links']['html']['href']\n \n@@ -94,7 +94,7 @@\n                 'revlink': '{}/commits/{}'.format(web_url, commit_hash),\n                 'repository': repo_url,\n                 'author': '{} <{}>'.format(payload['actor']['display_name'],\n-                                           payload['actor']['username']),\n+                                           payload['actor']['nickname']),\n                 'comments': 'Bitbucket Cloud commit {}'.format(commit_hash),\n                 'branch': branch,\n                 'project': project,\n@@ -139,15 +139,16 @@\n     def handle_pullrequest(self, payload, refname, category):\n         pr_number = int(payload['pullrequest']['id'])\n         repo_url = payload['repository']['links']['self']['href']\n+        project = payload['repository'].get('project', {'name': 'none'})['name']\n         change = {\n             'revision': payload['pullrequest']['fromRef']['commit']['hash'],\n             'revlink': payload['pullrequest']['link'],\n             'repository': repo_url,\n             'author': '{} <{}>'.format(payload['actor']['display_name'],\n-                                       payload['actor']['username']),\n+                                       payload['actor']['nickname']),\n             'comments': 'Bitbucket Cloud Pull Request #{}'.format(pr_number),\n             'branch': refname,\n-            'project': payload['repository']['project']['name'],\n+            'project': project,\n             'category': category,\n             'properties': {'pullrequesturl': payload['pullrequest']['link']}\n         }\n", "issue": "Bitbucket Cloud web hook returns 500\nStarted three weeks ago (missed it due to vacations), my guess is that Bitbucket changed something. Error log looks like this:\r\n\r\n```\r\n2019-07-02 14:33:40+0300 [_GenericHTTPChannelProtocol,13,18.234.32.226] adding changes from web hook\r\n        Traceback (most recent call last):\r\n          File \"/home/buildbot/sandbox/lib/python3.5/site-packages/twisted/internet/defer.py\", line 1418, in _inlineCallbacks\r\n            result = g.send(result)\r\n          File \"/home/buildbot/sandbox/lib/python3.5/site-packages/buildbot/www/change_hook.py\", line 106, in getAndSubmitChanges\r\n            changes, src = yield self.getChanges(request)\r\n          File \"/home/buildbot/sandbox/lib/python3.5/site-packages/twisted/internet/defer.py\", line 1613, in unwindGenerator\r\n            return _cancellableInlineCallbacks(gen)\r\n          File \"/home/buildbot/sandbox/lib/python3.5/site-packages/twisted/internet/defer.py\", line 1529, in _cancellableInlineCallbacks\r\n            _inlineCallbacks(None, g, status)\r\n        --- <exception caught here> ---\r\n          File \"/home/buildbot/sandbox/lib/python3.5/site-packages/buildbot/www/change_hook.py\", line 106, in getAndSubmitChanges\r\n            changes, src = yield self.getChanges(request)\r\n          File \"/home/buildbot/sandbox/lib/python3.5/site-packages/twisted/internet/defer.py\", line 1418, in _inlineCallbacks\r\n            result = g.send(result)\r\n          File \"/home/buildbot/sandbox/lib/python3.5/site-packages/buildbot/www/change_hook.py\", line 167, in getChanges\r\n            changes, src = yield handler.getChanges(request)\r\n          File \"/home/buildbot/sandbox/lib/python3.5/site-packages/buildbot/www/hooks/bitbucketcloud.py\", line 163, in getChanges\r\n            return self.process(request)\r\n          File \"/home/buildbot/sandbox/lib/python3.5/site-packages/buildbot/www/hooks/bitbucketcloud.py\", line 54, in process\r\n            return handler(payload)\r\n          File \"/home/buildbot/sandbox/lib/python3.5/site-packages/buildbot/www/hooks/bitbucketcloud.py\", line 97, in handle_repo_push\r\n            payload['actor']['username']),\r\n        builtins.KeyError: 'username'\r\n```\r\n\r\nLast line reveals the culprit.\n", "before_files": [{"content": "# This file is part of Buildbot.  Buildbot is free software: you can\n# redistribute it and/or modify it under the terms of the GNU General Public\n# License as published by the Free Software Foundation, version 2.\n#\n# This program is distributed in the hope that it will be useful, but WITHOUT\n# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\n# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more\n# details.\n#\n# You should have received a copy of the GNU General Public License along with\n# this program; if not, write to the Free Software Foundation, Inc., 51\n# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n#\n# Copyright Buildbot Team Members\n# Copyright Mamba Team\n\n\nimport json\n\nfrom twisted.python import log\n\nfrom buildbot.util import bytes2unicode\n\nGIT_BRANCH_REF = \"refs/heads/{}\"\nGIT_MERGE_REF = \"refs/pull-requests/{}/merge\"\nGIT_TAG_REF = \"refs/tags/{}\"\n\n_HEADER_EVENT = b'X-Event-Key'\n\n\nclass BitbucketCloudEventHandler:\n\n    def __init__(self, master, options=None):\n        if options is None:\n            options = {}\n        self.master = master\n        if not isinstance(options, dict):\n            options = {}\n        self.options = options\n        self._codebase = self.options.get('codebase', None)\n\n    def process(self, request):\n        payload = self._get_payload(request)\n        event_type = request.getHeader(_HEADER_EVENT)\n        event_type = bytes2unicode(event_type)\n        log.msg(\"Processing event {header}: {event}\"\n                .format(header=_HEADER_EVENT, event=event_type))\n        event_type = event_type.replace(\":\", \"_\")\n        handler = getattr(self, 'handle_{}'.format(event_type), None)\n\n        if handler is None:\n            raise ValueError('Unknown event: {}'.format(event_type))\n\n        return handler(payload)\n\n    def _get_payload(self, request):\n        content = request.content.read()\n        content = bytes2unicode(content)\n        content_type = request.getHeader(b'Content-Type')\n        content_type = bytes2unicode(content_type)\n        if content_type.startswith('application/json'):\n            payload = json.loads(content)\n        else:\n            raise ValueError('Unknown content type: {}'\n                             .format(content_type))\n\n        log.msg(\"Payload: {}\".format(payload))\n\n        return payload\n\n    def handle_repo_push(self, payload):\n        changes = []\n        project = payload['repository']['project']['name']\n        repo_url = payload['repository']['links']['self']['href']\n        web_url = payload['repository']['links']['html']['href']\n\n        for payload_change in payload['push']['changes']:\n            if payload_change['new']:\n                age = 'new'\n                category = 'push'\n            else:  # when new is null the ref is deleted\n                age = 'old'\n                category = 'ref-deleted'\n\n            commit_hash = payload_change[age]['target']['hash']\n\n            if payload_change[age]['type'] == 'branch':\n                branch = GIT_BRANCH_REF.format(payload_change[age]['name'])\n            elif payload_change[age]['type'] == 'tag':\n                branch = GIT_TAG_REF.format(payload_change[age]['name'])\n\n            change = {\n                'revision': commit_hash,\n                'revlink': '{}/commits/{}'.format(web_url, commit_hash),\n                'repository': repo_url,\n                'author': '{} <{}>'.format(payload['actor']['display_name'],\n                                           payload['actor']['username']),\n                'comments': 'Bitbucket Cloud commit {}'.format(commit_hash),\n                'branch': branch,\n                'project': project,\n                'category': category\n            }\n\n            if callable(self._codebase):\n                change['codebase'] = self._codebase(payload)\n            elif self._codebase is not None:\n                change['codebase'] = self._codebase\n\n            changes.append(change)\n\n        return (changes, payload['repository']['scm'])\n\n    def handle_pullrequest_created(self, payload):\n        return self.handle_pullrequest(\n            payload,\n            GIT_MERGE_REF.format(int(payload['pullrequest']['id'])),\n            \"pull-created\")\n\n    def handle_pullrequest_updated(self, payload):\n        return self.handle_pullrequest(\n            payload,\n            GIT_MERGE_REF.format(int(payload['pullrequest']['id'])),\n            \"pull-updated\")\n\n    def handle_pullrequest_fulfilled(self, payload):\n        return self.handle_pullrequest(\n            payload,\n            GIT_BRANCH_REF.format(\n                payload['pullrequest']['toRef']['branch']['name']),\n            \"pull-fulfilled\")\n\n    def handle_pullrequest_rejected(self, payload):\n        return self.handle_pullrequest(\n            payload,\n            GIT_BRANCH_REF.format(\n                payload['pullrequest']['fromRef']['branch']['name']),\n            \"pull-rejected\")\n\n    def handle_pullrequest(self, payload, refname, category):\n        pr_number = int(payload['pullrequest']['id'])\n        repo_url = payload['repository']['links']['self']['href']\n        change = {\n            'revision': payload['pullrequest']['fromRef']['commit']['hash'],\n            'revlink': payload['pullrequest']['link'],\n            'repository': repo_url,\n            'author': '{} <{}>'.format(payload['actor']['display_name'],\n                                       payload['actor']['username']),\n            'comments': 'Bitbucket Cloud Pull Request #{}'.format(pr_number),\n            'branch': refname,\n            'project': payload['repository']['project']['name'],\n            'category': category,\n            'properties': {'pullrequesturl': payload['pullrequest']['link']}\n        }\n\n        if callable(self._codebase):\n            change['codebase'] = self._codebase(payload)\n        elif self._codebase is not None:\n            change['codebase'] = self._codebase\n\n        return [change], payload['repository']['scm']\n\n    def getChanges(self, request):\n        return self.process(request)\n\n\nbitbucketcloud = BitbucketCloudEventHandler\n", "path": "master/buildbot/www/hooks/bitbucketcloud.py"}], "after_files": [{"content": "# This file is part of Buildbot.  Buildbot is free software: you can\n# redistribute it and/or modify it under the terms of the GNU General Public\n# License as published by the Free Software Foundation, version 2.\n#\n# This program is distributed in the hope that it will be useful, but WITHOUT\n# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\n# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more\n# details.\n#\n# You should have received a copy of the GNU General Public License along with\n# this program; if not, write to the Free Software Foundation, Inc., 51\n# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n#\n# Copyright Buildbot Team Members\n# Copyright Mamba Team\n\n\nimport json\n\nfrom twisted.python import log\n\nfrom buildbot.util import bytes2unicode\n\nGIT_BRANCH_REF = \"refs/heads/{}\"\nGIT_MERGE_REF = \"refs/pull-requests/{}/merge\"\nGIT_TAG_REF = \"refs/tags/{}\"\n\n_HEADER_EVENT = b'X-Event-Key'\n\n\nclass BitbucketCloudEventHandler:\n\n    def __init__(self, master, options=None):\n        if options is None:\n            options = {}\n        self.master = master\n        if not isinstance(options, dict):\n            options = {}\n        self.options = options\n        self._codebase = self.options.get('codebase', None)\n\n    def process(self, request):\n        payload = self._get_payload(request)\n        event_type = request.getHeader(_HEADER_EVENT)\n        event_type = bytes2unicode(event_type)\n        log.msg(\"Processing event {header}: {event}\"\n                .format(header=_HEADER_EVENT, event=event_type))\n        event_type = event_type.replace(\":\", \"_\")\n        handler = getattr(self, 'handle_{}'.format(event_type), None)\n\n        if handler is None:\n            raise ValueError('Unknown event: {}'.format(event_type))\n\n        return handler(payload)\n\n    def _get_payload(self, request):\n        content = request.content.read()\n        content = bytes2unicode(content)\n        content_type = request.getHeader(b'Content-Type')\n        content_type = bytes2unicode(content_type)\n        if content_type.startswith('application/json'):\n            payload = json.loads(content)\n        else:\n            raise ValueError('Unknown content type: {}'\n                             .format(content_type))\n\n        log.msg(\"Payload: {}\".format(payload))\n\n        return payload\n\n    def handle_repo_push(self, payload):\n        changes = []\n        project = payload['repository'].get('project', {'name': 'none'})['name']\n        repo_url = payload['repository']['links']['self']['href']\n        web_url = payload['repository']['links']['html']['href']\n\n        for payload_change in payload['push']['changes']:\n            if payload_change['new']:\n                age = 'new'\n                category = 'push'\n            else:  # when new is null the ref is deleted\n                age = 'old'\n                category = 'ref-deleted'\n\n            commit_hash = payload_change[age]['target']['hash']\n\n            if payload_change[age]['type'] == 'branch':\n                branch = GIT_BRANCH_REF.format(payload_change[age]['name'])\n            elif payload_change[age]['type'] == 'tag':\n                branch = GIT_TAG_REF.format(payload_change[age]['name'])\n\n            change = {\n                'revision': commit_hash,\n                'revlink': '{}/commits/{}'.format(web_url, commit_hash),\n                'repository': repo_url,\n                'author': '{} <{}>'.format(payload['actor']['display_name'],\n                                           payload['actor']['nickname']),\n                'comments': 'Bitbucket Cloud commit {}'.format(commit_hash),\n                'branch': branch,\n                'project': project,\n                'category': category\n            }\n\n            if callable(self._codebase):\n                change['codebase'] = self._codebase(payload)\n            elif self._codebase is not None:\n                change['codebase'] = self._codebase\n\n            changes.append(change)\n\n        return (changes, payload['repository']['scm'])\n\n    def handle_pullrequest_created(self, payload):\n        return self.handle_pullrequest(\n            payload,\n            GIT_MERGE_REF.format(int(payload['pullrequest']['id'])),\n            \"pull-created\")\n\n    def handle_pullrequest_updated(self, payload):\n        return self.handle_pullrequest(\n            payload,\n            GIT_MERGE_REF.format(int(payload['pullrequest']['id'])),\n            \"pull-updated\")\n\n    def handle_pullrequest_fulfilled(self, payload):\n        return self.handle_pullrequest(\n            payload,\n            GIT_BRANCH_REF.format(\n                payload['pullrequest']['toRef']['branch']['name']),\n            \"pull-fulfilled\")\n\n    def handle_pullrequest_rejected(self, payload):\n        return self.handle_pullrequest(\n            payload,\n            GIT_BRANCH_REF.format(\n                payload['pullrequest']['fromRef']['branch']['name']),\n            \"pull-rejected\")\n\n    def handle_pullrequest(self, payload, refname, category):\n        pr_number = int(payload['pullrequest']['id'])\n        repo_url = payload['repository']['links']['self']['href']\n        project = payload['repository'].get('project', {'name': 'none'})['name']\n        change = {\n            'revision': payload['pullrequest']['fromRef']['commit']['hash'],\n            'revlink': payload['pullrequest']['link'],\n            'repository': repo_url,\n            'author': '{} <{}>'.format(payload['actor']['display_name'],\n                                       payload['actor']['nickname']),\n            'comments': 'Bitbucket Cloud Pull Request #{}'.format(pr_number),\n            'branch': refname,\n            'project': project,\n            'category': category,\n            'properties': {'pullrequesturl': payload['pullrequest']['link']}\n        }\n\n        if callable(self._codebase):\n            change['codebase'] = self._codebase(payload)\n        elif self._codebase is not None:\n            change['codebase'] = self._codebase\n\n        return [change], payload['repository']['scm']\n\n    def getChanges(self, request):\n        return self.process(request)\n\n\nbitbucketcloud = BitbucketCloudEventHandler\n", "path": "master/buildbot/www/hooks/bitbucketcloud.py"}]}