Maciej Szulik added the comment:

Patch with comments from Ezio addressed and additionally supporting closing 
issues.

_______________________________________________________
PSF Meta Tracker <metatrac...@psf.upfronthosting.co.za>
<http://psf.upfronthosting.co.za/roundup/meta/issue611>
_______________________________________________________
diff --git a/roundup/github.py b/roundup/github.py
--- a/roundup/github.py
+++ b/roundup/github.py
@@ -1,5 +1,3 @@
-from roundup.exceptions import *
-
 import hashlib
 import hmac
 import json
@@ -7,6 +5,8 @@
 import os
 import logging
 
+from roundup.exceptions import Unauthorised, MethodNotAllowed, \
+    UnsupportedMediaType, Reject
 
 if hasattr(hmac, 'compare_digest'):
     compare_digest = hmac.compare_digest
@@ -14,8 +14,17 @@
     def compare_digest(a, b):
         return a == b
 
-url_re = re.compile(r'https://github.com/python/cpython/pull/(?P<number>\d+)')
-issue_id_re = re.compile(r'bpo\s*(\d+)', re.I)
+URL_RE = re.compile(r'https://github.com/python/cpython/pull/(?P<number>\d+)')
+ISSUE_GH_RE = re.compile(r'bpo\s*(\d+)', re.I)
+VERBS = r'(?:\b(?P<verb>close[sd]?|closing|)\s+)?'
+ISSUE_BPO_RE = re.compile(r'%s(?:#|\bissue|\bbug)\s*(?P<issue_id>\d+)'
+                           % VERBS, re.I|re.U)
+
+COMMENT_TEMPLATE = u"""\
+New changeset {changeset_id} by {author} in branch '{branch}':
+{commit_msg}
+{changeset_url}
+"""
 
 class GitHubHandler:
     """
@@ -59,6 +68,10 @@
             data = json.loads(self.form.value)
             handler = IssueComment(self.db, data)
             handler.dispatch()
+        elif event == 'push':
+            data = json.loads(self.form.value)
+            handler = Push(self.db, data)
+            handler.dispatch()
 
     def validate_webhook_secret(self):
         """
@@ -93,7 +106,7 @@
 
     def get_event(self):
         """
-        Extracts github event from header field.
+        Extracts GitHub event from header field.
         """
         return self.request.headers.get('X-GitHub-Event', None)
 
@@ -107,24 +120,27 @@
         self.db = db
         self.data = data
 
-    def set_current_user(self):
+    def set_roundup_user(self):
         """
-        Helper method used for setting current user for roundup, based
-        on the information from github about event author.
+        Helper method used for setting the current user for Roundup, based
+        on the information from GitHub about event author.
         """
         github_username = self.get_github_username()
-        user_id = self.db.user.filter(None, {'github': github_username})
-        # TODO set bpobot as userid when none is found
-        if len(user_id) == 1:
-            # TODO what if multiple bpo users have the same github username?
-            username = self.db.user.get(user_id[0], 'username')
-            self.db.setCurrentUser(username)
+        user_ids = self.db.user.filter(None, {'github': github_username})
+        if not user_ids:
+            # set bpobot as userid when none is found
+            user_ids = self.db.user.filter(None, {'username': 'python-dev'})
+            if not user_ids:
+                # python-dev does not exists, anonymous will be used instead
+                return
+        username = self.db.user.get(user_ids[0], 'username')
+        self.db.setCurrentUser(username)
 
     def dispatch(self):
         """
-        Main method responsible for responding to incoming github event.
+        Main method responsible for responding to incoming GitHub event.
         """
-        self.set_current_user()
+        self.set_roundup_user()
         action = self.data.get('action', '').encode('utf-8')
         issue_ids = self.get_issue_ids()
         if not issue_ids:
@@ -220,7 +236,7 @@
             raise Reject()
         title = pull_request.get('title', '').encode('utf-8')
         body = pull_request.get('body', '').encode('utf-8')
-        return list(set(issue_id_re.findall(title) + 
issue_id_re.findall(body)))
+        return list(set(ISSUE_GH_RE.findall(title) + 
ISSUE_GH_RE.findall(body)))
 
     def get_pr_details(self):
         """
@@ -234,7 +250,7 @@
             raise Reject()
         title = pull_request.get('title', '').encode('utf-8')
         status = pull_request.get('state', '').encode('utf-8')
-        # github has two states open and closed, information about pull request
+        # GitHub has two states open and closed, information about pull request
         # being merged in kept in separate field
         if pull_request.get('merged', False):
             status = "merged"
@@ -242,13 +258,14 @@
 
     def get_github_username(self):
         """
-        Extract github username from a pull request.
+        Extract GitHub username from a pull request.
         """
         pull_request = self.data.get('pull_request')
         if pull_request is None:
             raise Reject()
         return pull_request.get('user', {}).get('login', '').encode('utf-8')
 
+
 class IssueComment(Event):
     """
     Class responsible for handling issue comment events, but only within the
@@ -274,7 +291,7 @@
             raise Reject()
         title = issue.get('title', '').encode('utf-8')
         body = comment.get('body', '').encode('utf-8')
-        return list(set(issue_id_re.findall(title) + 
issue_id_re.findall(body)))
+        return list(set(ISSUE_GH_RE.findall(title) + 
ISSUE_GH_RE.findall(body)))
 
     def get_pr_details(self):
         """
@@ -284,16 +301,93 @@
         if issue is None:
             raise Reject()
         url = issue.get('pull_request', {}).get('html_url')
-        number_match = url_re.search(url)
+        number_match = URL_RE.search(url)
         if not number_match:
             return (None, None, None)
         return number_match.group('number'), None, None
 
     def get_github_username(self):
         """
-        Extract github username from a comment.
+        Extract GitHub username from a comment.
         """
         issue = self.data.get('issue')
         if issue is None:
             raise Reject()
         return issue.get('user', {}).get('login', '').encode('utf-8')
+
+
+class Push(Event):
+    """
+    Class responsible for handling push events.
+    """
+
+    def get_github_username(self):
+        """
+        Extract GitHub username from a push event.
+        """
+        return self.data.get('pusher', []).get('name', '').encode('utf-8')
+
+    def dispatch(self):
+        """
+        Main method responsible for responding to incoming GitHub event.
+        """
+        self.set_roundup_user()
+        commits = self.data.get('commits', [])
+        ref = self.data.get('ref', 'refs/heads/master')
+        # messages dictionary maps issue number to a tuple containing
+        # the message to be posted as a comment an boolean flag informing
+        # if the issue should be 'closed'
+        messages = {}
+        # extract commit messages
+        for commit in commits:
+            msgs = self.handle_action(commit, ref)
+            for issue_id, (msg, close) in msgs.iteritems():
+                if issue_id not in messages:
+                    messages[issue_id] = (u'', False)
+                curr_msg, curr_close = messages[issue_id]
+                # we append the new message to the other and do binary OR
+                # on close, so that at least one information will actually
+                # close the issue
+                messages[issue_id] = (curr_msg + u'\n' + msg, curr_close|close)
+        if not messages:
+            return
+        for issue_id, (msg, close) in messages.iteritems():
+            # add comments to appropriate issues...
+            id = issue_id.encode('utf-8')
+            issue_msgs = self.db.issue.get(id, 'messages')
+            newmsg = self.db.msg.create(content=msg.encode('utf-8'), 
author=self.db.getuid())
+            issue_msgs.append(newmsg)
+            self.db.issue.set(id, messages=issue_msgs)
+            # ... and close, if needed
+            if close:
+                self.db.issue.set(id,
+                    status=self.db.status.lookup('closed'))
+                self.db.issue.set(id,
+                    resolution=self.db.resolution.lookup('fixed'))
+                self.db.issue.set(id,
+                    stage=self.db.stage.lookup('resolved'))
+        self.db.commit()
+
+    def handle_action(self, commit, ref):
+        """
+        This is implementing the same logic as the mercurial hook from here:
+        https://hg.python.org/hooks/file/tip/hgroundup.py
+        """
+        branch = ref.split('/')[-1]
+        description = commit.get('message', '')
+        matches = ISSUE_BPO_RE.finditer(description)
+        messages = {}
+        for match in matches:
+            data = match.groupdict()
+            # check for duplicated issue numbers in the same commit msg
+            if data['issue_id'] in messages:
+                continue
+            close = data['verb'] is not None
+            messages[data['issue_id']] = (COMMENT_TEMPLATE.format(
+                author=commit.get('committer', {}).get('name', ''),
+                branch=branch,
+                changeset_id=commit.get('id', ''),
+                changeset_url=commit.get('url', ''),
+                commit_msg=description.splitlines()[0],
+            ), close)
+        return messages
diff --git a/share/roundup/templates/classic/initial_data.py 
b/share/roundup/templates/classic/initial_data.py
--- a/share/roundup/templates/classic/initial_data.py
+++ b/share/roundup/templates/classic/initial_data.py
@@ -17,6 +17,13 @@
 stat.create(name=''"testing", order="6")
 stat.create(name=''"done-cbb", order="7")
 stat.create(name=''"resolved", order="8")
+stat.create(name=''"closed", order="9")
+
+resolution = db.getclass('resolution')
+resolution.create(name=''"fixed", order="1")
+
+stage = db.getclass('stage')
+stage.create(name=''"resolved", order="1")
 
 # create the two default users
 user = db.getclass('user')
diff --git a/share/roundup/templates/classic/schema.py 
b/share/roundup/templates/classic/schema.py
--- a/share/roundup/templates/classic/schema.py
+++ b/share/roundup/templates/classic/schema.py
@@ -21,6 +21,20 @@
                 order=Number())
 stat.setkey("name")
 
+# Stage
+stage = Class(db, 'stage',
+              name = String(),
+              description = String(),
+              order = Number())
+stage.setkey('name')
+
+# Resolution
+resolution = Class(db, "resolution",
+                   name=String(),
+                   description=String(),
+                   order=Number())
+resolution.setkey('name')
+
 # Keywords
 keyword = Class(db, "keyword",
                 name=String())
@@ -84,6 +98,8 @@
                 keyword=Multilink("keyword"),
                 priority=Link("priority"),
                 status=Link("status"),
+                resolution=Link('resolution'),
+                stage=Link('stage'),
                 pull_requests=Multilink('pull_request'))
 
 #
diff --git a/test/data/pushevent.txt b/test/data/pushevent.txt
new file mode 100644
--- /dev/null
+++ b/test/data/pushevent.txt
@@ -0,0 +1,11 @@
+POST /python-dev/pull_request HTTP/1.1
+Host: 3ab1787e.ngrok.io
+Accept: */*
+User-Agent: GitHub-Hookshot/98ea3cc
+X-GitHub-Event: push
+X-GitHub-Delivery: 3d4b5180-5c89-11e6-88fd-1aa99d941991
+content-type: application/json
+X-Hub-Signature: sha1=c760213ddccd47bf3bbd1735b70c787bb8d07724
+Content-Length: 5852
+
+{"ref":"refs/heads/test1","before":"6c5d08240c73014f282bc7336c08fe9ec0b557b0","after":"65c3a074262662a2c55109ff9a2456ee7647fcc9","created":false,"deleted":false,"forced":false,"base_ref":null,"compare":"https://github.com/python/cpython/compare/6c5d08240c73...65c3a0742626","commits":[{"id":"65c3a074262662a2c55109ff9a2456ee7647fcc9","tree_id":"2a35adbb6fce03b51dce23b4ed48526a5a74255a","distinct":true,"message":"#1:
 fix 
tests.","timestamp":"2017-01-19T22:19:07+01:00","url":"https://github.com/python/cpython/commit/65c3a074262662a2c55109ff9a2456ee7647fcc9","author":{"name":"Maciej
 
Szulik","email":"solt...@gmail.com","username":"soltysh"},"committer":{"name":"Maciej
 
Szulik","email":"solt...@gmail.com","username":"soltysh"},"added":[],"removed":[],"modified":["README"]}],"head_commit":{"id":"65c3a074262662a2c55109ff9a2456ee7647fcc9","tree_id":"2a35adbb6fce03b51dce23b4ed48526a5a74255a","distinct":true,"message":"Fixes#1","timestamp":"2017-01-19T22:19:07+01:00","url":"https://githu
 
b.com/python/cpython/commit/65c3a074262662a2c55109ff9a2456ee7647fcc9","author":{"name":"Maciej
 
Szulik","email":"solt...@gmail.com","username":"soltysh"},"committer":{"name":"Maciej
 
Szulik","email":"solt...@gmail.com","username":"soltysh"},"added":[],"removed":[],"modified":["README"]},"repository":{"id":76687672,"name":"cpython","full_name":"python/cpython","owner":{"name":"python"},"private":false,"html_url":"https://github.com/python/cpython","description":"Semi-officialread-onlymirroroftheCPythonMercurialrepository","fork":true,"url":"https://github.com/python/cpython","forks_url":"https://api.github.com/repos/python/cpython/forks","keys_url":"https://api.github.com/repos/python/cpython/keys{/key_id}","collaborators_url":"https://api.github.com/repos/python/cpython/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/python/cpython/teams","hooks_url":"https://api.github.com/repos/python/cpython/hooks","issue_events_url":"https://api.github.com/repos/pyt
 
hon/cpython/issues/events{/number}","events_url":"https://api.github.com/repos/python/cpython/events","assignees_url":"https://api.github.com/repos/python/cpython/assignees{/user}","branches_url":"https://api.github.com/repos/python/cpython/branches{/branch}","tags_url":"https://api.github.com/repos/python/cpython/tags","blobs_url":"https://api.github.com/repos/python/cpython/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/python/cpython/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/python/cpython/git/refs{/sha}","trees_url":"https://api.github.com/repos/python/cpython/git/trees{/sha}","statuses_url":"https://api.github.com/repos/python/cpython/statuses/{sha}","languages_url":"https://api.github.com/repos/python/cpython/languages","stargazers_url":"https://api.github.com/repos/python/cpython/stargazers","contributors_url":"https://api.github.com/repos/python/cpython/contributors","subscribers_url":"https://api.github.com/repos/python/cpython/subs
 
cribers","subscription_url":"https://api.github.com/repos/python/cpython/subscription","commits_url":"https://api.github.com/repos/python/cpython/commits{/sha}","git_commits_url":"https://api.github.com/repos/python/cpython/git/commits{/sha}","comments_url":"https://api.github.com/repos/python/cpython/comments{/number}","issue_comment_url":"https://api.github.com/repos/python/cpython/issues/comments{/number}","contents_url":"https://api.github.com/repos/python/cpython/contents/{+path}","compare_url":"https://api.github.com/repos/python/cpython/compare/{base}...{head}","merges_url":"https://api.github.com/repos/python/cpython/merges","archive_url":"https://api.github.com/repos/python/cpython/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/python/cpython/downloads","issues_url":"https://api.github.com/repos/python/cpython/issues{/number}","pulls_url":"https://api.github.com/repos/python/cpython/pulls{/number}","milestones_url":"https://api.github.com/repo
 
s/python/cpython/milestones{/number}","notifications_url":"https://api.github.com/repos/python/cpython/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/python/cpython/labels{/name}","releases_url":"https://api.github.com/repos/python/cpython/releases{/id}","deployments_url":"https://api.github.com/repos/python/cpython/deployments","created_at":1481924711,"updated_at":"2016-12-16T21:45:35Z","pushed_at":1484860759,"git_url":"git://github.com/python/cpython.git","ssh_url":"g...@github.com:python/cpython.git","clone_url":"https://github.com/python/cpython.git","svn_url":"https://github.com/python/cpython","homepage":"","size":269743,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master","stargazers":0,"master_branch":"master"},"pusher":{"name":"sol
 
tysh","email":"solt...@gmail.com"},"sender":{"login":"soltysh","id":576341,"avatar_url":"https://avatars.githubusercontent.com/u/576341?v=3","gravatar_id":"","url":"https://api.github.com/users/soltysh","html_url":"https://github.com/soltysh","followers_url":"https://api.github.com/users/soltysh/followers","following_url":"https://api.github.com/users/soltysh/following{/other_user}","gists_url":"https://api.github.com/users/soltysh/gists{/gist_id}","starred_url":"https://api.github.com/users/soltysh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/soltysh/subscriptions","organizations_url":"https://api.github.com/users/soltysh/orgs","repos_url":"https://api.github.com/users/soltysh/repos","events_url":"https://api.github.com/users/soltysh/events{/privacy}","received_events_url":"https://api.github.com/users/soltysh/received_events","type":"User","site_admin":false}}
diff --git a/test/data/pushevent1.txt b/test/data/pushevent1.txt
new file mode 100644
--- /dev/null
+++ b/test/data/pushevent1.txt
@@ -0,0 +1,11 @@
+POST /python-dev/pull_request HTTP/1.1
+Host: 3ab1787e.ngrok.io
+Accept: */*
+User-Agent: GitHub-Hookshot/98ea3cc
+X-GitHub-Event: push
+X-GitHub-Delivery: 3d4b5180-5c89-11e6-88fd-1aa99d941991
+content-type: application/json
+X-Hub-Signature: sha1=764b12621ca4b8ef3f71ce414394e8bfd88efdce
+Content-Length: 5860
+
+{"ref":"refs/heads/test1","before":"6c5d08240c73014f282bc7336c08fe9ec0b557b0","after":"65c3a074262662a2c55109ff9a2456ee7647fcc9","created":false,"deleted":false,"forced":false,"base_ref":null,"compare":"https://github.com/python/cpython/compare/6c5d08240c73...65c3a0742626","commits":[{"id":"65c3a074262662a2c55109ff9a2456ee7647fcc9","tree_id":"2a35adbb6fce03b51dce23b4ed48526a5a74255a","distinct":true,"message":"closes
 issue 1: fix 
tests.","timestamp":"2017-01-19T22:19:07+01:00","url":"https://github.com/python/cpython/commit/65c3a074262662a2c55109ff9a2456ee7647fcc9","author":{"name":"Maciej
 
Szulik","email":"solt...@gmail.com","username":"soltysh"},"committer":{"name":"Maciej
 
Szulik","email":"solt...@gmail.com","username":"soltysh"},"added":[],"removed":[],"modified":["README"]}],"head_commit":{"id":"65c3a074262662a2c55109ff9a2456ee7647fcc9","tree_id":"2a35adbb6fce03b51dce23b4ed48526a5a74255a","distinct":true,"message":"Fixes#1","timestamp":"2017-01-19T22:19:07+01:00","url":"h
 
ttps://github.com/python/cpython/commit/65c3a074262662a2c55109ff9a2456ee7647fcc9","author":{"name":"Maciej
 
Szulik","email":"solt...@gmail.com","username":"soltysh"},"committer":{"name":"Maciej
 
Szulik","email":"solt...@gmail.com","username":"soltysh"},"added":[],"removed":[],"modified":["README"]},"repository":{"id":76687672,"name":"cpython","full_name":"python/cpython","owner":{"name":"python"},"private":false,"html_url":"https://github.com/python/cpython","description":"Semi-officialread-onlymirroroftheCPythonMercurialrepository","fork":true,"url":"https://github.com/python/cpython","forks_url":"https://api.github.com/repos/python/cpython/forks","keys_url":"https://api.github.com/repos/python/cpython/keys{/key_id}","collaborators_url":"https://api.github.com/repos/python/cpython/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/python/cpython/teams","hooks_url":"https://api.github.com/repos/python/cpython/hooks","issue_events_url":"https://api.github.c
 
om/repos/python/cpython/issues/events{/number}","events_url":"https://api.github.com/repos/python/cpython/events","assignees_url":"https://api.github.com/repos/python/cpython/assignees{/user}","branches_url":"https://api.github.com/repos/python/cpython/branches{/branch}","tags_url":"https://api.github.com/repos/python/cpython/tags","blobs_url":"https://api.github.com/repos/python/cpython/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/python/cpython/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/python/cpython/git/refs{/sha}","trees_url":"https://api.github.com/repos/python/cpython/git/trees{/sha}","statuses_url":"https://api.github.com/repos/python/cpython/statuses/{sha}","languages_url":"https://api.github.com/repos/python/cpython/languages","stargazers_url":"https://api.github.com/repos/python/cpython/stargazers","contributors_url":"https://api.github.com/repos/python/cpython/contributors","subscribers_url":"https://api.github.com/repos/python/
 
cpython/subscribers","subscription_url":"https://api.github.com/repos/python/cpython/subscription","commits_url":"https://api.github.com/repos/python/cpython/commits{/sha}","git_commits_url":"https://api.github.com/repos/python/cpython/git/commits{/sha}","comments_url":"https://api.github.com/repos/python/cpython/comments{/number}","issue_comment_url":"https://api.github.com/repos/python/cpython/issues/comments{/number}","contents_url":"https://api.github.com/repos/python/cpython/contents/{+path}","compare_url":"https://api.github.com/repos/python/cpython/compare/{base}...{head}","merges_url":"https://api.github.com/repos/python/cpython/merges","archive_url":"https://api.github.com/repos/python/cpython/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/python/cpython/downloads","issues_url":"https://api.github.com/repos/python/cpython/issues{/number}","pulls_url":"https://api.github.com/repos/python/cpython/pulls{/number}","milestones_url":"https://api.git
 
hub.com/repos/python/cpython/milestones{/number}","notifications_url":"https://api.github.com/repos/python/cpython/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/python/cpython/labels{/name}","releases_url":"https://api.github.com/repos/python/cpython/releases{/id}","deployments_url":"https://api.github.com/repos/python/cpython/deployments","created_at":1481924711,"updated_at":"2016-12-16T21:45:35Z","pushed_at":1484860759,"git_url":"git://github.com/python/cpython.git","ssh_url":"g...@github.com:python/cpython.git","clone_url":"https://github.com/python/cpython.git","svn_url":"https://github.com/python/cpython","homepage":"","size":269743,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master","stargazers":0,"master_branch":"master"},"pusher":
 
{"name":"soltysh","email":"solt...@gmail.com"},"sender":{"login":"soltysh","id":576341,"avatar_url":"https://avatars.githubusercontent.com/u/576341?v=3","gravatar_id":"","url":"https://api.github.com/users/soltysh","html_url":"https://github.com/soltysh","followers_url":"https://api.github.com/users/soltysh/followers","following_url":"https://api.github.com/users/soltysh/following{/other_user}","gists_url":"https://api.github.com/users/soltysh/gists{/gist_id}","starred_url":"https://api.github.com/users/soltysh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/soltysh/subscriptions","organizations_url":"https://api.github.com/users/soltysh/orgs","repos_url":"https://api.github.com/users/soltysh/repos","events_url":"https://api.github.com/users/soltysh/events{/privacy}","received_events_url":"https://api.github.com/users/soltysh/received_events","type":"User","site_admin":false}}
diff --git a/test/data/pushevent2.txt b/test/data/pushevent2.txt
new file mode 100644
--- /dev/null
+++ b/test/data/pushevent2.txt
@@ -0,0 +1,11 @@
+POST /python-dev/pull_request HTTP/1.1
+Host: 3ab1787e.ngrok.io
+Accept: */*
+User-Agent: GitHub-Hookshot/98ea3cc
+X-GitHub-Event: push
+X-GitHub-Delivery: 3d4b5180-5c89-11e6-88fd-1aa99d941991
+content-type: application/json
+X-Hub-Signature: sha1=7e52815fdd264f934d60d0dab305d4d2b198a47d
+Content-Length: 6343
+
+{"ref":"refs/heads/test1","before":"6c5d08240c73014f282bc7336c08fe9ec0b557b0","after":"65c3a074262662a2c55109ff9a2456ee7647fcc9","created":false,"deleted":false,"forced":false,"base_ref":null,"compare":"https://github.com/python/cpython/compare/6c5d08240c73...65c3a0742626","commits":[{"id":"65c3a074262662a2c55109ff9a2456ee7647fcc9","tree_id":"2a35adbb6fce03b51dce23b4ed48526a5a74255a","distinct":true,"message":"issue
 1: fix 
tests.","timestamp":"2017-01-19T22:19:07+01:00","url":"https://github.com/python/cpython/commit/65c3a074262662a2c55109ff9a2456ee7647fcc9","author":{"name":"Maciej
 
Szulik","email":"solt...@gmail.com","username":"soltysh"},"committer":{"name":"Maciej
 
Szulik","email":"solt...@gmail.com","username":"soltysh"},"added":[],"removed":[],"modified":["README"]},{"id":"4488ebcdf2d16393d1a78c4105e4a18e4d0d77af","tree_id":"2a35adbb6fce03b51dce23b4ed48526a5a74255a","distinct":true,"message":"#1:
 fix else.","timestamp":"2017-01-19T22:19:07+01:00","url":"https://github.co
 
m/python/cpython/commit/4488ebcdf2d16393d1a78c4105e4a18e4d0d77af","author":{"name":"Maciej
 
Szulik","email":"solt...@gmail.com","username":"soltysh"},"committer":{"name":"Maciej
 
Szulik","email":"solt...@gmail.com","username":"soltysh"},"added":[],"removed":[],"modified":["README"]}],"head_commit":{"id":"65c3a074262662a2c55109ff9a2456ee7647fcc9","tree_id":"2a35adbb6fce03b51dce23b4ed48526a5a74255a","distinct":true,"message":"Fixes#1","timestamp":"2017-01-19T22:19:07+01:00","url":"https://github.com/python/cpython/commit/65c3a074262662a2c55109ff9a2456ee7647fcc9","author":{"name":"Maciej
 
Szulik","email":"solt...@gmail.com","username":"soltysh"},"committer":{"name":"Maciej
 
Szulik","email":"solt...@gmail.com","username":"soltysh"},"added":[],"removed":[],"modified":["README"]},"repository":{"id":76687672,"name":"cpython","full_name":"python/cpython","owner":{"name":"python"},"private":false,"html_url":"https://github.com/python/cpython","description":"Semi-officialread-onlymirrorof
 
theCPythonMercurialrepository","fork":true,"url":"https://github.com/python/cpython","forks_url":"https://api.github.com/repos/python/cpython/forks","keys_url":"https://api.github.com/repos/python/cpython/keys{/key_id}","collaborators_url":"https://api.github.com/repos/python/cpython/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/python/cpython/teams","hooks_url":"https://api.github.com/repos/python/cpython/hooks","issue_events_url":"https://api.github.com/repos/python/cpython/issues/events{/number}","events_url":"https://api.github.com/repos/python/cpython/events","assignees_url":"https://api.github.com/repos/python/cpython/assignees{/user}","branches_url":"https://api.github.com/repos/python/cpython/branches{/branch}","tags_url":"https://api.github.com/repos/python/cpython/tags","blobs_url":"https://api.github.com/repos/python/cpython/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/python/cpython/git/tags{/sha}","git_refs_url":"https:
 
//api.github.com/repos/python/cpython/git/refs{/sha}","trees_url":"https://api.github.com/repos/python/cpython/git/trees{/sha}","statuses_url":"https://api.github.com/repos/python/cpython/statuses/{sha}","languages_url":"https://api.github.com/repos/python/cpython/languages","stargazers_url":"https://api.github.com/repos/python/cpython/stargazers","contributors_url":"https://api.github.com/repos/python/cpython/contributors","subscribers_url":"https://api.github.com/repos/python/cpython/subscribers","subscription_url":"https://api.github.com/repos/python/cpython/subscription","commits_url":"https://api.github.com/repos/python/cpython/commits{/sha}","git_commits_url":"https://api.github.com/repos/python/cpython/git/commits{/sha}","comments_url":"https://api.github.com/repos/python/cpython/comments{/number}","issue_comment_url":"https://api.github.com/repos/python/cpython/issues/comments{/number}","contents_url":"https://api.github.com/repos/python/cpython/contents/{+path}","co
 
mpare_url":"https://api.github.com/repos/python/cpython/compare/{base}...{head}","merges_url":"https://api.github.com/repos/python/cpython/merges","archive_url":"https://api.github.com/repos/python/cpython/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/python/cpython/downloads","issues_url":"https://api.github.com/repos/python/cpython/issues{/number}","pulls_url":"https://api.github.com/repos/python/cpython/pulls{/number}","milestones_url":"https://api.github.com/repos/python/cpython/milestones{/number}","notifications_url":"https://api.github.com/repos/python/cpython/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/python/cpython/labels{/name}","releases_url":"https://api.github.com/repos/python/cpython/releases{/id}","deployments_url":"https://api.github.com/repos/python/cpython/deployments","created_at":1481924711,"updated_at":"2016-12-16T21:45:35Z","pushed_at":1484860759,"git_url":"git://github.com/python/cpython.
 
git","ssh_url":"g...@github.com:python/cpython.git","clone_url":"https://github.com/python/cpython.git","svn_url":"https://github.com/python/cpython","homepage":"","size":269743,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master","stargazers":0,"master_branch":"master"},"pusher":{"name":"soltysh","email":"solt...@gmail.com"},"sender":{"login":"soltysh","id":576341,"avatar_url":"https://avatars.githubusercontent.com/u/576341?v=3","gravatar_id":"","url":"https://api.github.com/users/soltysh","html_url":"https://github.com/soltysh","followers_url":"https://api.github.com/users/soltysh/followers","following_url":"https://api.github.com/users/soltysh/following{/other_user}","gists_url":"https://api.github.com/users/soltysh/gists{/gist_id}","starred_url":"https://api.github.com/use
 
rs/soltysh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/soltysh/subscriptions","organizations_url":"https://api.github.com/users/soltysh/orgs","repos_url":"https://api.github.com/users/soltysh/repos","events_url":"https://api.github.com/users/soltysh/events{/privacy}","received_events_url":"https://api.github.com/users/soltysh/received_events","type":"User","site_admin":false}}
diff --git a/test/data/pushevent3.txt b/test/data/pushevent3.txt
new file mode 100644
--- /dev/null
+++ b/test/data/pushevent3.txt
@@ -0,0 +1,11 @@
+POST /python-dev/pull_request HTTP/1.1
+Host: 3ab1787e.ngrok.io
+Accept: */*
+User-Agent: GitHub-Hookshot/98ea3cc
+X-GitHub-Event: push
+X-GitHub-Delivery: 3d4b5180-5c89-11e6-88fd-1aa99d941991
+content-type: application/json
+X-Hub-Signature: sha1=c521799f81bd30df0a672bfdfb5959ad55ccbb63
+Content-Length: 6351
+
+{"ref":"refs/heads/test1","before":"6c5d08240c73014f282bc7336c08fe9ec0b557b0","after":"65c3a074262662a2c55109ff9a2456ee7647fcc9","created":false,"deleted":false,"forced":false,"base_ref":null,"compare":"https://github.com/python/cpython/compare/6c5d08240c73...65c3a0742626","commits":[{"id":"65c3a074262662a2c55109ff9a2456ee7647fcc9","tree_id":"2a35adbb6fce03b51dce23b4ed48526a5a74255a","distinct":true,"message":"closing
 issue 1: fix 
tests.","timestamp":"2017-01-19T22:19:07+01:00","url":"https://github.com/python/cpython/commit/65c3a074262662a2c55109ff9a2456ee7647fcc9","author":{"name":"Maciej
 
Szulik","email":"solt...@gmail.com","username":"soltysh"},"committer":{"name":"Maciej
 
Szulik","email":"solt...@gmail.com","username":"soltysh"},"added":[],"removed":[],"modified":["README"]},{"id":"4488ebcdf2d16393d1a78c4105e4a18e4d0d77af","tree_id":"2a35adbb6fce03b51dce23b4ed48526a5a74255a","distinct":true,"message":"#1:
 fix else.","timestamp":"2017-01-19T22:19:07+01:00","url":"https://g
 
ithub.com/python/cpython/commit/4488ebcdf2d16393d1a78c4105e4a18e4d0d77af","author":{"name":"Maciej
 
Szulik","email":"solt...@gmail.com","username":"soltysh"},"committer":{"name":"Maciej
 
Szulik","email":"solt...@gmail.com","username":"soltysh"},"added":[],"removed":[],"modified":["README"]}],"head_commit":{"id":"65c3a074262662a2c55109ff9a2456ee7647fcc9","tree_id":"2a35adbb6fce03b51dce23b4ed48526a5a74255a","distinct":true,"message":"Fixes#1","timestamp":"2017-01-19T22:19:07+01:00","url":"https://github.com/python/cpython/commit/65c3a074262662a2c55109ff9a2456ee7647fcc9","author":{"name":"Maciej
 
Szulik","email":"solt...@gmail.com","username":"soltysh"},"committer":{"name":"Maciej
 
Szulik","email":"solt...@gmail.com","username":"soltysh"},"added":[],"removed":[],"modified":["README"]},"repository":{"id":76687672,"name":"cpython","full_name":"python/cpython","owner":{"name":"python"},"private":false,"html_url":"https://github.com/python/cpython","description":"Semi-officialread-only
 
mirroroftheCPythonMercurialrepository","fork":true,"url":"https://github.com/python/cpython","forks_url":"https://api.github.com/repos/python/cpython/forks","keys_url":"https://api.github.com/repos/python/cpython/keys{/key_id}","collaborators_url":"https://api.github.com/repos/python/cpython/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/python/cpython/teams","hooks_url":"https://api.github.com/repos/python/cpython/hooks","issue_events_url":"https://api.github.com/repos/python/cpython/issues/events{/number}","events_url":"https://api.github.com/repos/python/cpython/events","assignees_url":"https://api.github.com/repos/python/cpython/assignees{/user}","branches_url":"https://api.github.com/repos/python/cpython/branches{/branch}","tags_url":"https://api.github.com/repos/python/cpython/tags","blobs_url":"https://api.github.com/repos/python/cpython/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/python/cpython/git/tags{/sha}","git_refs_url";
 
:"https://api.github.com/repos/python/cpython/git/refs{/sha}","trees_url":"https://api.github.com/repos/python/cpython/git/trees{/sha}","statuses_url":"https://api.github.com/repos/python/cpython/statuses/{sha}","languages_url":"https://api.github.com/repos/python/cpython/languages","stargazers_url":"https://api.github.com/repos/python/cpython/stargazers","contributors_url":"https://api.github.com/repos/python/cpython/contributors","subscribers_url":"https://api.github.com/repos/python/cpython/subscribers","subscription_url":"https://api.github.com/repos/python/cpython/subscription","commits_url":"https://api.github.com/repos/python/cpython/commits{/sha}","git_commits_url":"https://api.github.com/repos/python/cpython/git/commits{/sha}","comments_url":"https://api.github.com/repos/python/cpython/comments{/number}","issue_comment_url":"https://api.github.com/repos/python/cpython/issues/comments{/number}","contents_url":"https://api.github.com/repos/python/cpython/contents/{+pa
 
th}","compare_url":"https://api.github.com/repos/python/cpython/compare/{base}...{head}","merges_url":"https://api.github.com/repos/python/cpython/merges","archive_url":"https://api.github.com/repos/python/cpython/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/python/cpython/downloads","issues_url":"https://api.github.com/repos/python/cpython/issues{/number}","pulls_url":"https://api.github.com/repos/python/cpython/pulls{/number}","milestones_url":"https://api.github.com/repos/python/cpython/milestones{/number}","notifications_url":"https://api.github.com/repos/python/cpython/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/python/cpython/labels{/name}","releases_url":"https://api.github.com/repos/python/cpython/releases{/id}","deployments_url":"https://api.github.com/repos/python/cpython/deployments","created_at":1481924711,"updated_at":"2016-12-16T21:45:35Z","pushed_at":1484860759,"git_url":"git://github.com/python/
 
cpython.git","ssh_url":"g...@github.com:python/cpython.git","clone_url":"https://github.com/python/cpython.git","svn_url":"https://github.com/python/cpython","homepage":"","size":269743,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master","stargazers":0,"master_branch":"master"},"pusher":{"name":"soltysh","email":"solt...@gmail.com"},"sender":{"login":"soltysh","id":576341,"avatar_url":"https://avatars.githubusercontent.com/u/576341?v=3","gravatar_id":"","url":"https://api.github.com/users/soltysh","html_url":"https://github.com/soltysh","followers_url":"https://api.github.com/users/soltysh/followers","following_url":"https://api.github.com/users/soltysh/following{/other_user}","gists_url":"https://api.github.com/users/soltysh/gists{/gist_id}","starred_url":"https://api.github
 
.com/users/soltysh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/soltysh/subscriptions","organizations_url":"https://api.github.com/users/soltysh/orgs","repos_url":"https://api.github.com/users/soltysh/repos","events_url":"https://api.github.com/users/soltysh/events{/privacy}","received_events_url":"https://api.github.com/users/soltysh/received_events","type":"User","site_admin":false}}
diff --git a/test/data/pushevent4.txt b/test/data/pushevent4.txt
new file mode 100644
--- /dev/null
+++ b/test/data/pushevent4.txt
@@ -0,0 +1,11 @@
+POST /python-dev/pull_request HTTP/1.1
+Host: 3ab1787e.ngrok.io
+Accept: */*
+User-Agent: GitHub-Hookshot/98ea3cc
+X-GitHub-Event: push
+X-GitHub-Delivery: 3d4b5180-5c89-11e6-88fd-1aa99d941991
+content-type: application/json
+X-Hub-Signature: sha1=9975ce076f3f00558539390b1dc464385b8ae5bb
+Content-Length: 6353
+
+{"ref":"refs/heads/test1","before":"6c5d08240c73014f282bc7336c08fe9ec0b557b0","after":"65c3a074262662a2c55109ff9a2456ee7647fcc9","created":false,"deleted":false,"forced":false,"base_ref":null,"compare":"https://github.com/python/cpython/compare/6c5d08240c73...65c3a0742626","commits":[{"id":"65c3a074262662a2c55109ff9a2456ee7647fcc9","tree_id":"2a35adbb6fce03b51dce23b4ed48526a5a74255a","distinct":true,"message":"closes
 issue 1: fix 
tests.","timestamp":"2017-01-19T22:19:07+01:00","url":"https://github.com/python/cpython/commit/65c3a074262662a2c55109ff9a2456ee7647fcc9","author":{"name":"Maciej
 
Szulik","email":"solt...@gmail.com","username":"soltysh"},"committer":{"name":"Maciej
 
Szulik","email":"solt...@gmail.com","username":"soltysh"},"added":[],"removed":[],"modified":["README"]},{"id":"4488ebcdf2d16393d1a78c4105e4a18e4d0d77af","tree_id":"2a35adbb6fce03b51dce23b4ed48526a5a74255a","distinct":true,"message":"bug
 2: fix else.","timestamp":"2017-01-19T22:19:07+01:00","url":"https:/
 
/github.com/python/cpython/commit/4488ebcdf2d16393d1a78c4105e4a18e4d0d77af","author":{"name":"Maciej
 
Szulik","email":"solt...@gmail.com","username":"soltysh"},"committer":{"name":"Maciej
 
Szulik","email":"solt...@gmail.com","username":"soltysh"},"added":[],"removed":[],"modified":["README"]}],"head_commit":{"id":"65c3a074262662a2c55109ff9a2456ee7647fcc9","tree_id":"2a35adbb6fce03b51dce23b4ed48526a5a74255a","distinct":true,"message":"Fixes#1","timestamp":"2017-01-19T22:19:07+01:00","url":"https://github.com/python/cpython/commit/65c3a074262662a2c55109ff9a2456ee7647fcc9","author":{"name":"Maciej
 
Szulik","email":"solt...@gmail.com","username":"soltysh"},"committer":{"name":"Maciej
 
Szulik","email":"solt...@gmail.com","username":"soltysh"},"added":[],"removed":[],"modified":["README"]},"repository":{"id":76687672,"name":"cpython","full_name":"python/cpython","owner":{"name":"python"},"private":false,"html_url":"https://github.com/python/cpython","description":"Semi-officialread-on
 
lymirroroftheCPythonMercurialrepository","fork":true,"url":"https://github.com/python/cpython","forks_url":"https://api.github.com/repos/python/cpython/forks","keys_url":"https://api.github.com/repos/python/cpython/keys{/key_id}","collaborators_url":"https://api.github.com/repos/python/cpython/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/python/cpython/teams","hooks_url":"https://api.github.com/repos/python/cpython/hooks","issue_events_url":"https://api.github.com/repos/python/cpython/issues/events{/number}","events_url":"https://api.github.com/repos/python/cpython/events","assignees_url":"https://api.github.com/repos/python/cpython/assignees{/user}","branches_url":"https://api.github.com/repos/python/cpython/branches{/branch}","tags_url":"https://api.github.com/repos/python/cpython/tags","blobs_url":"https://api.github.com/repos/python/cpython/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/python/cpython/git/tags{/sha}","git_refs_ur
 
l":"https://api.github.com/repos/python/cpython/git/refs{/sha}","trees_url":"https://api.github.com/repos/python/cpython/git/trees{/sha}","statuses_url":"https://api.github.com/repos/python/cpython/statuses/{sha}","languages_url":"https://api.github.com/repos/python/cpython/languages","stargazers_url":"https://api.github.com/repos/python/cpython/stargazers","contributors_url":"https://api.github.com/repos/python/cpython/contributors","subscribers_url":"https://api.github.com/repos/python/cpython/subscribers","subscription_url":"https://api.github.com/repos/python/cpython/subscription","commits_url":"https://api.github.com/repos/python/cpython/commits{/sha}","git_commits_url":"https://api.github.com/repos/python/cpython/git/commits{/sha}","comments_url":"https://api.github.com/repos/python/cpython/comments{/number}","issue_comment_url":"https://api.github.com/repos/python/cpython/issues/comments{/number}","contents_url":"https://api.github.com/repos/python/cpython/contents/{+
 
path}","compare_url":"https://api.github.com/repos/python/cpython/compare/{base}...{head}","merges_url":"https://api.github.com/repos/python/cpython/merges","archive_url":"https://api.github.com/repos/python/cpython/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/python/cpython/downloads","issues_url":"https://api.github.com/repos/python/cpython/issues{/number}","pulls_url":"https://api.github.com/repos/python/cpython/pulls{/number}","milestones_url":"https://api.github.com/repos/python/cpython/milestones{/number}","notifications_url":"https://api.github.com/repos/python/cpython/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/python/cpython/labels{/name}","releases_url":"https://api.github.com/repos/python/cpython/releases{/id}","deployments_url":"https://api.github.com/repos/python/cpython/deployments","created_at":1481924711,"updated_at":"2016-12-16T21:45:35Z","pushed_at":1484860759,"git_url":"git://github.com/pytho
 
n/cpython.git","ssh_url":"g...@github.com:python/cpython.git","clone_url":"https://github.com/python/cpython.git","svn_url":"https://github.com/python/cpython","homepage":"","size":269743,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master","stargazers":0,"master_branch":"master"},"pusher":{"name":"soltysh","email":"solt...@gmail.com"},"sender":{"login":"soltysh","id":576341,"avatar_url":"https://avatars.githubusercontent.com/u/576341?v=3","gravatar_id":"","url":"https://api.github.com/users/soltysh","html_url":"https://github.com/soltysh","followers_url":"https://api.github.com/users/soltysh/followers","following_url":"https://api.github.com/users/soltysh/following{/other_user}","gists_url":"https://api.github.com/users/soltysh/gists{/gist_id}","starred_url":"https://api.gith
 
ub.com/users/soltysh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/soltysh/subscriptions","organizations_url":"https://api.github.com/users/soltysh/orgs","repos_url":"https://api.github.com/users/soltysh/repos","events_url":"https://api.github.com/users/soltysh/events{/privacy}","received_events_url":"https://api.github.com/users/soltysh/received_events","type":"User","site_admin":false}}
diff --git a/test/test_github.py b/test/test_github.py
--- a/test/test_github.py
+++ b/test/test_github.py
@@ -296,6 +296,125 @@
         status = self.db.pull_request.get(prs[0], 'status')
         self.assertEqual(status, 'closed')
 
+    def testPushEventAddsComment(self):
+        dummy_client = self._make_client('pushevent.txt')
+        handler = GitHubHandler(dummy_client)
+        handler.dispatch()
+        msgs = self.db.issue.get('1', 'messages')
+        self.assertEqual(len(msgs), 1)
+        content = self.db.msg.get(msgs[0], 'content')
+        self.assertIn("""New changeset 
65c3a074262662a2c55109ff9a2456ee7647fcc9 by Maciej Szulik in branch 'test1':
+#1: fix tests.
+https://github.com/python/cpython/commit/65c3a074262662a2c55109ff9a2456ee7647fcc9
+""",
+            content)
+        # issue status
+        status = self.db.issue.get('1', 'status')
+        self.assertNotEqual(self.db.status.get(status, 'name'), 'closed')
+        self.assertIsNone(self.db.issue.get('1', 'resolution'))
+        self.assertIsNone(self.db.issue.get('1', 'stage'))
+
+    def testPushEventAddsCommentAndClose(self):
+        dummy_client = self._make_client('pushevent1.txt')
+        handler = GitHubHandler(dummy_client)
+        handler.dispatch()
+        msgs = self.db.issue.get('1', 'messages')
+        self.assertEqual(len(msgs), 1)
+        content = self.db.msg.get(msgs[0], 'content')
+        self.assertIn("""New changeset 
65c3a074262662a2c55109ff9a2456ee7647fcc9 by Maciej Szulik in branch 'test1':
+closes issue 1: fix tests.
+https://github.com/python/cpython/commit/65c3a074262662a2c55109ff9a2456ee7647fcc9
+""",
+            content)
+        # issue status
+        status = self.db.issue.get('1', 'status')
+        self.assertEqual(self.db.status.get(status, 'name'), 'closed')
+        resolution = self.db.issue.get('1', 'resolution')
+        self.assertEqual(self.db.resolution.get(resolution, 'name'), 'fixed')
+        stage = self.db.issue.get('1', 'stage')
+        self.assertEqual(self.db.stage.get(stage, 'name'), 'resolved')
+
+    def testPushEventWithMultipleCommitsSingleIssue(self):
+        dummy_client = self._make_client('pushevent2.txt')
+        handler = GitHubHandler(dummy_client)
+        handler.dispatch()
+        msgs = self.db.issue.get('1', 'messages')
+        self.assertEqual(len(msgs), 1)
+        content = self.db.msg.get(msgs[0], 'content')
+        self.assertIn("""New changeset 
65c3a074262662a2c55109ff9a2456ee7647fcc9 by Maciej Szulik in branch 'test1':
+issue 1: fix tests.
+https://github.com/python/cpython/commit/65c3a074262662a2c55109ff9a2456ee7647fcc9
+
+New changeset 4488ebcdf2d16393d1a78c4105e4a18e4d0d77af by Maciej Szulik in 
branch 'test1':
+#1: fix else.
+https://github.com/python/cpython/commit/4488ebcdf2d16393d1a78c4105e4a18e4d0d77af
+""",
+            content)
+                # issue status
+        status = self.db.issue.get('1', 'status')
+        self.assertNotEqual(self.db.status.get(status, 'name'), 'closed')
+        self.assertIsNone(self.db.issue.get('1', 'resolution'))
+        self.assertIsNone(self.db.issue.get('1', 'stage'))
+
+    def testPushEventWithMultipleCommitsSingleIssueAndClose(self):
+        dummy_client = self._make_client('pushevent3.txt')
+        handler = GitHubHandler(dummy_client)
+        handler.dispatch()
+        msgs = self.db.issue.get('1', 'messages')
+        self.assertEqual(len(msgs), 1)
+        content = self.db.msg.get(msgs[0], 'content')
+        self.assertIn("""New changeset 
65c3a074262662a2c55109ff9a2456ee7647fcc9 by Maciej Szulik in branch 'test1':
+closing issue 1: fix tests.
+https://github.com/python/cpython/commit/65c3a074262662a2c55109ff9a2456ee7647fcc9
+
+New changeset 4488ebcdf2d16393d1a78c4105e4a18e4d0d77af by Maciej Szulik in 
branch 'test1':
+#1: fix else.
+https://github.com/python/cpython/commit/4488ebcdf2d16393d1a78c4105e4a18e4d0d77af
+""",
+            content)
+        # issue status
+        status = self.db.issue.get('1', 'status')
+        self.assertEqual(self.db.status.get(status, 'name'), 'closed')
+        resolution = self.db.issue.get('1', 'resolution')
+        self.assertEqual(self.db.resolution.get(resolution, 'name'), 'fixed')
+        stage = self.db.issue.get('1', 'stage')
+        self.assertEqual(self.db.stage.get(stage, 'name'), 'resolved')
+
+    def testPushEventWithMultipleCommitsMultipleIssues(self):
+        dummy_client = self._make_client('pushevent4.txt')
+        self.db.issue.create(title="Issue 2")
+        handler = GitHubHandler(dummy_client)
+        handler.dispatch()
+        # first issue messages
+        msgs = self.db.issue.get('1', 'messages')
+        self.assertEqual(len(msgs), 1)
+        content = self.db.msg.get(msgs[0], 'content')
+        self.assertIn("""New changeset 
65c3a074262662a2c55109ff9a2456ee7647fcc9 by Maciej Szulik in branch 'test1':
+closes issue 1: fix tests.
+https://github.com/python/cpython/commit/65c3a074262662a2c55109ff9a2456ee7647fcc9
+""",
+            content)
+        # first issue status
+        status = self.db.issue.get('1', 'status')
+        self.assertEqual(self.db.status.get(status, 'name'), 'closed')
+        resolution = self.db.issue.get('1', 'resolution')
+        self.assertEqual(self.db.resolution.get(resolution, 'name'), 'fixed')
+        stage = self.db.issue.get('1', 'stage')
+        self.assertEqual(self.db.stage.get(stage, 'name'), 'resolved')
+        # second issue messages
+        msgs = self.db.issue.get('2', 'messages')
+        self.assertEqual(len(msgs), 1)
+        content = self.db.msg.get(msgs[0], 'content')
+        self.assertIn("""New changeset 
4488ebcdf2d16393d1a78c4105e4a18e4d0d77af by Maciej Szulik in branch 'test1':
+bug 2: fix else.
+https://github.com/python/cpython/commit/4488ebcdf2d16393d1a78c4105e4a18e4d0d77af
+""",
+            content)
+        # second issue status
+        status = self.db.issue.get('2', 'status')
+        self.assertNotEqual(self.db.status.get(status, 'name'), 'closed')
+        self.assertIsNone(self.db.issue.get('2', 'resolution'))
+        self.assertIsNone(self.db.issue.get('2', 'stage'))
 
 def test_suite():
     suite = unittest.TestSuite()
_______________________________________________
Tracker-discuss mailing list
Tracker-discuss@python.org
https://mail.python.org/mailman/listinfo/tracker-discuss
Code of Conduct: https://www.python.org/psf/codeofconduct/

Reply via email to