Anish Shah added the comment:
new tests:
- secret key missing
- Github event missing in header
- non json body
- multiple references in PR body
- CREATE_ISSUE is not set and no issue is reference in PR
- if github field of user is set, then PR/issue is assigned to that user or
else anonymous
_______________________________________________________
PSF Meta Tracker <metatrac...@psf.upfronthosting.co.za>
<http://psf.upfronthosting.co.za/roundup/meta/issue589>
_______________________________________________________
commit a565735c6ebbb0a664cd7f9e5b68a406094ecf0f
Author: Anish Shah <shah.anis...@gmail.com>
Date: Wed Jul 27 00:03:46 2016 +0530
Add GitHub PR to bpo using webhooks
diff --git a/roundup/cgi/client.py b/roundup/cgi/client.py
index e71983d..abfbf51 100644
--- a/roundup/cgi/client.py
+++ b/roundup/cgi/client.py
@@ -22,6 +22,7 @@ from roundup.cgi.form_parser import FormParser
from roundup.mailer import Mailer, MessageSendError, encode_quopri
from roundup.cgi import accept_language
from roundup import xmlrpc
+from roundup.pull_request import GitHubHandler
from roundup.anypy.cookie_ import CookieError, BaseCookie, SimpleCookie, \
get_cookie_date
@@ -378,6 +379,8 @@ class Client:
try:
if self.path == 'xmlrpc':
self.handle_xmlrpc()
+ elif self.path == 'pull_request':
+ self.handle_pull_request()
else:
self.inner_main()
finally:
@@ -385,6 +388,34 @@ class Client:
self.db.close()
+ def handle_pull_request(self):
+ # Set the charset and language, since other parts of
+ # Roundup may depend upon that.
+ self.determine_charset()
+ self.determine_language()
+ # Open the database as the correct user.
+ self.determine_user()
+ self.check_anonymous_access()
+
+ try:
+ handler = GitHubHandler(self)
+ handler.dispatch()
+ except Unauthorised, message:
+ self.response_code = 403
+ self.write(message)
+ except UnsupportedMediaType, message:
+ self.response_code = 415
+ self.write(message)
+ except MethodNotAllowed, message:
+ self.response_code = 405
+ self.write(message)
+ except Reject, message:
+ self.response_code = 400
+ self.write(message)
+ else:
+ self.write("Done!")
+
+
def handle_xmlrpc(self):
if self.env.get('CONTENT_TYPE') != 'text/xml':
self.write("This is the endpoint of Roundup <a href='" +
diff --git a/roundup/exceptions.py b/roundup/exceptions.py
index 629516d..00da39c 100644
--- a/roundup/exceptions.py
+++ b/roundup/exceptions.py
@@ -21,6 +21,12 @@ class Reject(Exception):
"""
pass
+class UnsupportedMediaType(Exception):
+ pass
+
+class MethodNotAllowed(Exception):
+ pass
+
class UsageError(ValueError):
pass
diff --git a/roundup/pull_request.py b/roundup/pull_request.py
new file mode 100644
index 0000000..06e317a
--- /dev/null
+++ b/roundup/pull_request.py
@@ -0,0 +1,171 @@
+from roundup.exceptions import *
+
+import hashlib
+import hmac
+import json
+import re
+import os
+import logging
+
+
+if hasattr(hmac, "compare_digest"):
+ compare_digest = hmac.compare_digest
+else:
+ def compare_digest(a, b):
+ return a == b
+
+
+class GitHubHandler:
+
+ def __init__(self, client):
+ self.db = client.db
+ self.request = client.request
+ self.form = client.form
+ self.env = client.env
+
+ def dispatch(self):
+ try:
+ self._verify_request()
+ self._validate_webhook_secret()
+ self._extract()
+ except Unauthorised, message:
+ logging.error(message, exc_info=True)
+ raise Unauthorised(message)
+ except MethodNotAllowed, message:
+ logging.error(message, exc_info=True)
+ raise MethodNotAllowed(message)
+ except UnsupportedMediaType, message:
+ logging.error(message, exc_info=True)
+ raise UnsupportedMediaType(message)
+ except Exception, message:
+ logging.error(message, exc_info=True)
+ raise Reject('Invalid Request')
+
+ def _extract(self):
+ event = self._get_event()
+ if event not in ('pull_request', 'issue_comment'):
+ raise Reject('Unkown X-GitHub-Event {}'.format(event))
+ data = json.loads(self.form.value)
+ if event == 'pull_request':
+ handler = PullRequest(self.db, data)
+ handler.dispatch()
+ elif event == 'issue_comment':
+ handler = IssueComment(self.db, data)
+ handler.dispatch()
+
+ def _validate_webhook_secret(self):
+ key = os.environ['SECRET_KEY']
+ data = self.form.value
+ signature = "sha1=" + hmac.new(key, data,
+ hashlib.sha1).hexdigest()
+ header_signature = self.request.headers.get('X-Hub-Signature', '')
+ if not compare_digest(signature, header_signature):
+ raise Unauthorised("The provided secret does not match")
+
+ def _verify_request(self):
+ method = self.env.get('REQUEST_METHOD', None)
+ if method != 'POST':
+ raise MethodNotAllowed('unsupported HTTP method %s' % method)
+ content_type = self.env.get('CONTENT_TYPE', None)
+ if content_type != 'application/json':
+ raise UnsupportedMediaType('unsupported Content-Type %s' %
+ content_type)
+ event = self._get_event()
+ if event is None:
+ raise Reject('missing X-GitHub-Event header')
+
+ def _get_event(self):
+ return self.request.headers.get('X-GitHub-Event', None)
+
+
+class Event:
+
+ issue_re = re.compile(r'fixes\s+(?:bpo(\d+))(?:,\s*bpo(\d+))*', re.I)
+ issue_id_re = re.compile(r'bpo(\d+)', re.I)
+
+ def handle_create(self, url, issue_ids):
+ issue_exists = len(self.db.issue.filter(None, {'id': issue_ids})) ==
len(issue_ids)
+ if issue_exists:
+ for issue_id in issue_ids:
+ url_id = self.db.pull_request.create(url=url)
+ urls = self.db.issue.get(issue_id, 'pull_requests')
+ urls.append(url_id)
+ self.db.issue.set(issue_id, pull_requests=urls)
+ self.db.commit()
+
+ def _get_issue_ids(self):
+ raise NotImplementedError
+
+ def _get_url(self):
+ raise NotImplementedError
+
+
+class PullRequest(Event):
+
+ def __init__(self, db, data):
+ self.db = db
+ self.data = data
+
+ def dispatch(self):
+ github_username = self._get_github_username()
+ user_id = self.db.user.filter(None, {'github': github_username})
+ if len(user_id) == 1:
+ username = self.db.user.get(user_id[0], 'username')
+ self.db.setCurrentUser(username)
+ action = self.data['action'].encode('utf-8')
+ issue_id = self._get_issue_ids()
+ url = self._get_url()
+ if action == 'opened' and issue_id is not None:
+ self.handle_create(url, issue_id)
+
+ def _get_issue_ids(self):
+ title = self.data['pull_request']['title'].encode('utf-8')
+ body = self.data['pull_request']['body'].encode('utf-8')
+ match = self.issue_re.search(body) or self.issue_re.search(title)
+ if match:
+ return self.issue_id_re.findall(match.group())
+ # No issue id found
+ create_issue = os.environ.get('CREATE_ISSUE', False)
+ if create_issue:
+ return [self.db.issue.create(title=title)]
+ return None
+
+ def _get_url(self):
+ return self.data['pull_request']['html_url'].encode('utf-8')
+
+ def _get_github_username(self):
+ return self.data['pull_request']['user']['login'].encode('utf-8')
+
+
+class IssueComment(Event):
+
+ def __init__(self, db, data):
+ self.db = db
+ self.data = data
+
+ def dispatch(self):
+ github_username = self._get_github_username()
+ user_id = self.db.user.filter(None, {'github': github_username})
+ if len(user_id) == 1:
+ username = self.db.user.get(user_id[0], 'username')
+ self.db.setCurrentUser(username)
+ action = self.data['action'].encode('utf-8')
+ issue_id = self._get_issue_ids()
+ url = self._get_url()
+ if action == 'created' and issue_id is not None:
+ self.handle_create(url, issue_id)
+
+ def _get_issue_ids(self):
+ body = self.data['comment']['body'].encode('utf-8')
+ match = self.issue_re.search(body)
+ if match:
+ return self.issue_id_re.findall(match.group())
+ return None
+
+ def _get_url(self):
+ if 'pull_request' in self.data['issue']:
+ return self.data['issue']['pull_request']['html_url']\
+ .encode('utf-8')
+
+ def _get_github_username(self):
+ return self.data['issue']['user']['login'].encode('utf-8')
diff --git a/share/roundup/templates/classic/detectors/pull_request.py
b/share/roundup/templates/classic/detectors/pull_request.py
new file mode 100644
index 0000000..3624232
--- /dev/null
+++ b/share/roundup/templates/classic/detectors/pull_request.py
@@ -0,0 +1,25 @@
+# Auditor for GitHub URLs
+# Check if it is a valid GitHub Pull Request URL and extract PR number
+
+import re
+import urlparse
+
+
+def validate_github_url(db, cl, nodeid, newvalues):
+ url = newvalues.get('url', '')
+ if url == '':
+ return
+ parsed_url = urlparse.urlparse(url)
+ if parsed_url.scheme == '':
+ url = 'https://' + url
+ parsed_url = urlparse.urlparse(url)
+ if parsed_url.scheme not in ('http', 'https'):
+ raise ValueError("Invalid URL scheme in GitHub PR")
+ if 'github.com' not in parsed_url.netloc or 'pull' not in parsed_url.path:
+ raise ValueError("Invalid GitHub PR")
+ newvalues['url'] = parsed_url.geturl()
+
+
+def init(db):
+ db.pull_request.audit('create', validate_github_url)
+ db.pull_request.audit('set', validate_github_url)
diff --git a/share/roundup/templates/classic/schema.py
b/share/roundup/templates/classic/schema.py
index 924e69a..4ccb9f2 100644
--- a/share/roundup/templates/classic/schema.py
+++ b/share/roundup/templates/classic/schema.py
@@ -45,7 +45,8 @@ user = Class(db, "user",
alternate_addresses=String(),
queries=Multilink('query'),
roles=String(), # comma-separated string of Role names
- timezone=String())
+ timezone=String(),
+ github=String())
user.setkey("username")
db.security.addPermission(name='Register', klass='user',
description='User is allowed to register new user')
@@ -65,6 +66,9 @@ msg = FileClass(db, "msg",
file = FileClass(db, "file",
name=String())
+pull_request = Class(db, "pull_request",
+ url=String())
+
# IssueClass automatically gets these properties in addition to the Class ones:
# title = String()
# messages = Multilink("msg")
@@ -75,7 +79,8 @@ issue = IssueClass(db, "issue",
assignedto=Link("user"),
keyword=Multilink("keyword"),
priority=Link("priority"),
- status=Link("status"))
+ status=Link("status"),
+ pull_requests=Multilink('pull_request'))
#
# TRACKER SECURITY SETTINGS
@@ -92,7 +97,7 @@ db.security.addPermissionToRole('User', 'Email Access')
# Assign the access and edit Permissions for issue, file and message
# to regular users now
-for cl in 'issue', 'file', 'msg', 'keyword':
+for cl in 'issue', 'file', 'msg', 'keyword', 'pull_request':
db.security.addPermissionToRole('User', 'View', cl)
db.security.addPermissionToRole('User', 'Edit', cl)
db.security.addPermissionToRole('User', 'Create', cl)
@@ -101,7 +106,7 @@ for cl in 'priority', 'status':
# May users view other user information? Comment these lines out
# if you don't want them to
-p = db.security.addPermission(name='View', klass='user',
+p = db.security.addPermission(name='View', klass='user',
properties=('id', 'organisation', 'phone', 'realname', 'timezone',
'username'))
db.security.addPermissionToRole('User', p)
@@ -167,7 +172,7 @@ db.security.addPermissionToRole('Anonymous', 'Register',
'user')
# Allow anonymous users access to view issues (and the related, linked
# information)
-for cl in 'issue', 'file', 'msg', 'keyword', 'priority', 'status':
+for cl in 'issue', 'file', 'msg', 'keyword', 'priority', 'status',
'pull_request':
db.security.addPermissionToRole('Anonymous', 'View', cl)
# [OPTIONAL]
diff --git a/test/data/issuecommentevent.txt b/test/data/issuecommentevent.txt
new file mode 100644
index 0000000..118b0ab
--- /dev/null
+++ b/test/data/issuecommentevent.txt
@@ -0,0 +1,11 @@
+POST /python-dev/pull_request HTTP/1.1
+Host: 2f3784dc.ngrok.io
+Accept: */*
+User-Agent: GitHub-Hookshot/9667e0c
+X-GitHub-Event: issue_comment
+X-GitHub-Delivery: c6d12700-270e-11e6-86c5-8e9c9c898175
+content-type: application/json
+X-Hub-Signature: sha1=899e0fc0db5ed1a27215adb2f9d04351154bcaa1
+Content-Length: 8647
+
+{"action":"created","issue":{"url":"https://api.github.com/repos/AnishShah/cpython/issues/1","repository_url":"https://api.github.com/repos/AnishShah/cpython","labels_url":"https://api.github.com/repos/AnishShah/cpython/issues/1/labels{/name}","comments_url":"https://api.github.com/repos/AnishShah/cpython/issues/1/comments","events_url":"https://api.github.com/repos/AnishShah/cpython/issues/1/events","html_url":"https://github.com/AnishShah/cpython/pull/1","id":156471938,"number":1,"title":"Test","user":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/sta
rred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"milestone":null,"comments":1,"created_at":"2016-05-24T10:22:11Z","updated_at":"2016-05-31T09:05:10Z","closed_at":"2016-05-24T10:23:56Z","pull_request":{"url":"https://api.github.com/repos/AnishShah/cpython/pulls/1","html_url":"https://github.com/AnishShah/cpython/pull/1","diff_url":"https://github.com/AnishShah/cpython/pull/1.diff","patch_url":"https://github.com/AnishShah/cpython/pull/1.patch"},"body":""},"comment":{"url":"https://api.github.com/repos/AnishShah/cpython/issues/comments/222632341","html_url":"https://g
ithub.com/AnishShah/cpython/pull/1#issuecomment-222632341","issue_url":"https://api.github.com/repos/AnishShah/cpython/issues/1","id":222632341,"user":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/rece
ived_events","type":"User","site_admin":false},"created_at":"2016-05-31T09:05:10Z","updated_at":"2016-05-31T09:05:10Z","body":"fixes
bpo1"},"repository":{"id":59477756,"name":"cpython","full_name":"AnishShah/cpython","owner":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/pr
ivacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/AnishShah/cpython","description":"Semi-official
read-only mirror of the CPython Mercurial
repository","fork":true,"url":"https://api.github.com/repos/AnishShah/cpython","forks_url":"https://api.github.com/repos/AnishShah/cpython/forks","keys_url":"https://api.github.com/repos/AnishShah/cpython/keys{/key_id}","collaborators_url":"https://api.github.com/repos/AnishShah/cpython/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/AnishShah/cpython/teams","hooks_url":"https://api.github.com/repos/AnishShah/cpython/hooks","issue_events_url":"https://api.github.com/repos/AnishShah/cpython/issues/events{/number}","events_url":"https://api.github.com/repos/AnishShah/cpython/events","assignees_url":"https://api.github.com/repos/AnishShah/cpython/assignees{/user}","branches_url":"https://api.github.co
m/repos/AnishShah/cpython/branches{/branch}","tags_url":"https://api.github.com/repos/AnishShah/cpython/tags","blobs_url":"https://api.github.com/repos/AnishShah/cpython/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/AnishShah/cpython/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/AnishShah/cpython/git/refs{/sha}","trees_url":"https://api.github.com/repos/AnishShah/cpython/git/trees{/sha}","statuses_url":"https://api.github.com/repos/AnishShah/cpython/statuses/{sha}","languages_url":"https://api.github.com/repos/AnishShah/cpython/languages","stargazers_url":"https://api.github.com/repos/AnishShah/cpython/stargazers","contributors_url":"https://api.github.com/repos/AnishShah/cpython/contributors","subscribers_url":"https://api.github.com/repos/AnishShah/cpython/subscribers","subscription_url":"https://api.github.com/repos/AnishShah/cpython/subscription","commits_url":"https://api.github.com/repos/AnishShah/cpython/commits{/sha}","git_commits_url":
"https://api.github.com/repos/AnishShah/cpython/git/commits{/sha}","comments_url":"https://api.github.com/repos/AnishShah/cpython/comments{/number}","issue_comment_url":"https://api.github.com/repos/AnishShah/cpython/issues/comments{/number}","contents_url":"https://api.github.com/repos/AnishShah/cpython/contents/{+path}","compare_url":"https://api.github.com/repos/AnishShah/cpython/compare/{base}...{head}","merges_url":"https://api.github.com/repos/AnishShah/cpython/merges","archive_url":"https://api.github.com/repos/AnishShah/cpython/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/AnishShah/cpython/downloads","issues_url":"https://api.github.com/repos/AnishShah/cpython/issues{/number}","pulls_url":"https://api.github.com/repos/AnishShah/cpython/pulls{/number}","milestones_url":"https://api.github.com/repos/AnishShah/cpython/milestones{/number}","notifications_url":"https://api.github.com/repos/AnishShah/cpython/notifications{?since,all,participating}"
,"labels_url":"https://api.github.com/repos/AnishShah/cpython/labels{/name}","releases_url":"https://api.github.com/repos/AnishShah/cpython/releases{/id}","deployments_url":"https://api.github.com/repos/AnishShah/cpython/deployments","created_at":"2016-05-23T11:39:11Z","updated_at":"2016-05-23T11:39:38Z","pushed_at":"2016-05-24T13:18:37Z","git_url":"git://github.com/AnishShah/cpython.git","ssh_url":"g...@github.com:AnishShah/cpython.git","clone_url":"https://github.com/AnishShah/cpython.git","svn_url":"https://github.com/AnishShah/cpython","homepage":"","size":276521,"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"},"sender":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/us
ers/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false}}
diff --git a/test/data/no-github-event-header.txt
b/test/data/no-github-event-header.txt
new file mode 100644
index 0000000..2e604cd
--- /dev/null
+++ b/test/data/no-github-event-header.txt
@@ -0,0 +1,8 @@
+POST /python-dev/pull_request HTTP/1.1
+Host: 2f3784dc.ngrok.io
+Accept: */*
+User-Agent: GitHub-Hookshot/9667e0c
+X-GitHub-Delivery: 94a54100-20e0-11e6-8756-bf8bf3b91449
+content-type: application/json
+X-Hub-Signature: sha1=ffda9754ba91e91ec414c2308bd25cd151c69960
+Content-Length: 6217
diff --git a/test/data/non-json-body.txt b/test/data/non-json-body.txt
new file mode 100644
index 0000000..8fa8294
--- /dev/null
+++ b/test/data/non-json-body.txt
@@ -0,0 +1,10 @@
+POST /python-dev/pull_request HTTP/1.1
+Host: 2f3784dc.ngrok.io
+Accept: */*
+User-Agent: GitHub-Hookshot/9667e0c
+X-GitHub-Event: ping
+X-GitHub-Delivery: 94a54100-20e0-11e6-8756-bf8bf3b91449
+content-type: application/json
+X-Hub-Signature: sha1=ad0482a2678d7c0fbc3fde65cb0ec961b827324b
+
+hello:world
diff --git a/test/data/pingevent.txt b/test/data/pingevent.txt
new file mode 100644
index 0000000..bf27133
--- /dev/null
+++ b/test/data/pingevent.txt
@@ -0,0 +1,11 @@
+POST /python-dev/pull_request HTTP/1.1
+Host: 2f3784dc.ngrok.io
+Accept: */*
+User-Agent: GitHub-Hookshot/9667e0c
+X-GitHub-Event: ping
+X-GitHub-Delivery: 94a54100-20e0-11e6-8756-bf8bf3b91449
+content-type: application/json
+X-Hub-Signature: sha1=ffda9754ba91e91ec414c2308bd25cd151c69960
+Content-Length: 6217
+
+{"zen":"Mind your words, they are
important.","hook_id":8488302,"hook":{"type":"Repository","id":8488302,"name":"web","active":true,"events":["issue_comment","pull_request"],"config":{"content_type":"json","insecure_ssl":"0","secret":"********","url":"http://90dedf29.ngrok.io/python-dev/github_pullrequest_url"},"updated_at":"2016-05-23T12:19:22Z","created_at":"2016-05-23T12:19:22Z","url":"https://api.github.com/repos/AnishShah/cpython/hooks/8488302","test_url":"https://api.github.com/repos/AnishShah/cpython/hooks/8488302/test","ping_url":"https://api.github.com/repos/AnishShah/cpython/hooks/8488302/pings","last_response":{"code":null,"status":"unused","message":null}},"repository":{"id":59477756,"name":"cpython","full_name":"AnishShah/cpython","owner":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"htt
ps://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/AnishShah/cpython","description":"Semi-official
read-only mirror of the CPython Mercurial
repository","fork":true,"url":"https://api.github.com/repos/AnishShah/cpython","forks_url":"https://api.github.com/repos/AnishShah/cpython/forks","keys_url":"https://api.github.com/repos/AnishSh
ah/cpython/keys{/key_id}","collaborators_url":"https://api.github.com/repos/AnishShah/cpython/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/AnishShah/cpython/teams","hooks_url":"https://api.github.com/repos/AnishShah/cpython/hooks","issue_events_url":"https://api.github.com/repos/AnishShah/cpython/issues/events{/number}","events_url":"https://api.github.com/repos/AnishShah/cpython/events","assignees_url":"https://api.github.com/repos/AnishShah/cpython/assignees{/user}","branches_url":"https://api.github.com/repos/AnishShah/cpython/branches{/branch}","tags_url":"https://api.github.com/repos/AnishShah/cpython/tags","blobs_url":"https://api.github.com/repos/AnishShah/cpython/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/AnishShah/cpython/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/AnishShah/cpython/git/refs{/sha}","trees_url":"https://api.github.com/repos/AnishShah/cpython/git/trees{/sha}","statuses_url":"https://api.gi
thub.com/repos/AnishShah/cpython/statuses/{sha}","languages_url":"https://api.github.com/repos/AnishShah/cpython/languages","stargazers_url":"https://api.github.com/repos/AnishShah/cpython/stargazers","contributors_url":"https://api.github.com/repos/AnishShah/cpython/contributors","subscribers_url":"https://api.github.com/repos/AnishShah/cpython/subscribers","subscription_url":"https://api.github.com/repos/AnishShah/cpython/subscription","commits_url":"https://api.github.com/repos/AnishShah/cpython/commits{/sha}","git_commits_url":"https://api.github.com/repos/AnishShah/cpython/git/commits{/sha}","comments_url":"https://api.github.com/repos/AnishShah/cpython/comments{/number}","issue_comment_url":"https://api.github.com/repos/AnishShah/cpython/issues/comments{/number}","contents_url":"https://api.github.com/repos/AnishShah/cpython/contents/{+path}","compare_url":"https://api.github.com/repos/AnishShah/cpython/compare/{base}...{head}","merges_url":"https://api.github.com/repo
s/AnishShah/cpython/merges","archive_url":"https://api.github.com/repos/AnishShah/cpython/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/AnishShah/cpython/downloads","issues_url":"https://api.github.com/repos/AnishShah/cpython/issues{/number}","pulls_url":"https://api.github.com/repos/AnishShah/cpython/pulls{/number}","milestones_url":"https://api.github.com/repos/AnishShah/cpython/milestones{/number}","notifications_url":"https://api.github.com/repos/AnishShah/cpython/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/AnishShah/cpython/labels{/name}","releases_url":"https://api.github.com/repos/AnishShah/cpython/releases{/id}","deployments_url":"https://api.github.com/repos/AnishShah/cpython/deployments","created_at":"2016-05-23T11:39:11Z","updated_at":"2016-05-23T11:39:38Z","pushed_at":"2016-05-23T06:00:19Z","git_url":"git://github.com/AnishShah/cpython.git","ssh_url":"g...@github.com:AnishShah/cpython.git","clone_url"
:"https://github.com/AnishShah/cpython.git","svn_url":"https://github.com/AnishShah/cpython","homepage":"","size":335381,"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"},"sender":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https
://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false}}
diff --git a/test/data/pullrequestevent.txt b/test/data/pullrequestevent.txt
new file mode 100644
index 0000000..2fe68ca
--- /dev/null
+++ b/test/data/pullrequestevent.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: pull_request
+X-GitHub-Delivery: 3d4b5180-5c89-11e6-88fd-1aa99d941991
+content-type: application/json
+X-Hub-Signature: sha1=2c74c307193b7276fef7b1776956da2288034e5b
+Content-Length: 19681
+
+{"action":"opened","number":11,"pull_request":{"url":"https://api.github.com/repos/AnishShah/cpython/pulls/11","id":80363608,"html_url":"https://github.com/AnishShah/cpython/pull/11","diff_url":"https://github.com/AnishShah/cpython/pull/11.diff","patch_url":"https://github.com/AnishShah/cpython/pull/11.patch","issue_url":"https://api.github.com/repos/AnishShah/cpython/issues/11","number":11,"state":"open","locked":false,"title":"fixes
bpo1","user":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.git
hub.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false},"body":"","created_at":"2016-08-07T10:25:19Z","updated_at":"2016-08-07T10:25:19Z","closed_at":null,"merged_at":null,"merge_commit_sha":null,"assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/AnishShah/cpython/pulls/11/commits","review_comments_url":"https://api.github.com/repos/AnishShah/cpython/pulls/11/comments","review_comment_url":"https://api.github.com/repos/AnishShah/cpython/pulls/comments{/number}","comments_url":"https://api.github.com/repos/AnishShah/cpython/issues/11/comments","statuses_url":"https://api.github.com/repos/AnishShah/cpython/statuses/170f8a1f0ffbb733de656cd4a332ecea0c5
26d53","head":{"label":"AnishShah:master","ref":"master","sha":"170f8a1f0ffbb733de656cd4a332ecea0c526d53","user":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin
":false},"repo":{"id":59477756,"name":"cpython","full_name":"AnishShah/cpython","owner":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false},"private":false,
"html_url":"https://github.com/AnishShah/cpython","description":"Semi-official
read-only mirror of the CPython Mercurial
repository","fork":true,"url":"https://api.github.com/repos/AnishShah/cpython","forks_url":"https://api.github.com/repos/AnishShah/cpython/forks","keys_url":"https://api.github.com/repos/AnishShah/cpython/keys{/key_id}","collaborators_url":"https://api.github.com/repos/AnishShah/cpython/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/AnishShah/cpython/teams","hooks_url":"https://api.github.com/repos/AnishShah/cpython/hooks","issue_events_url":"https://api.github.com/repos/AnishShah/cpython/issues/events{/number}","events_url":"https://api.github.com/repos/AnishShah/cpython/events","assignees_url":"https://api.github.com/repos/AnishShah/cpython/assignees{/user}","branches_url":"https://api.github.com/repos/AnishShah/cpython/branches{/branch}","tags_url":"https://api.github.com/repos/AnishShah/cpython/tags","blobs_url":"https://api.gi
thub.com/repos/AnishShah/cpython/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/AnishShah/cpython/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/AnishShah/cpython/git/refs{/sha}","trees_url":"https://api.github.com/repos/AnishShah/cpython/git/trees{/sha}","statuses_url":"https://api.github.com/repos/AnishShah/cpython/statuses/{sha}","languages_url":"https://api.github.com/repos/AnishShah/cpython/languages","stargazers_url":"https://api.github.com/repos/AnishShah/cpython/stargazers","contributors_url":"https://api.github.com/repos/AnishShah/cpython/contributors","subscribers_url":"https://api.github.com/repos/AnishShah/cpython/subscribers","subscription_url":"https://api.github.com/repos/AnishShah/cpython/subscription","commits_url":"https://api.github.com/repos/AnishShah/cpython/commits{/sha}","git_commits_url":"https://api.github.com/repos/AnishShah/cpython/git/commits{/sha}","comments_url":"https://api.github.com/repos/AnishShah/cpython/comment
s{/number}","issue_comment_url":"https://api.github.com/repos/AnishShah/cpython/issues/comments{/number}","contents_url":"https://api.github.com/repos/AnishShah/cpython/contents/{+path}","compare_url":"https://api.github.com/repos/AnishShah/cpython/compare/{base}...{head}","merges_url":"https://api.github.com/repos/AnishShah/cpython/merges","archive_url":"https://api.github.com/repos/AnishShah/cpython/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/AnishShah/cpython/downloads","issues_url":"https://api.github.com/repos/AnishShah/cpython/issues{/number}","pulls_url":"https://api.github.com/repos/AnishShah/cpython/pulls{/number}","milestones_url":"https://api.github.com/repos/AnishShah/cpython/milestones{/number}","notifications_url":"https://api.github.com/repos/AnishShah/cpython/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/AnishShah/cpython/labels{/name}","releases_url":"https://api.github.com/repos/AnishShah/cpyth
on/releases{/id}","deployments_url":"https://api.github.com/repos/AnishShah/cpython/deployments","created_at":"2016-05-23T11:39:11Z","updated_at":"2016-05-23T11:39:38Z","pushed_at":"2016-08-07T10:25:19Z","git_url":"git://github.com/AnishShah/cpython.git","ssh_url":"g...@github.com:AnishShah/cpython.git","clone_url":"https://github.com/AnishShah/cpython.git","svn_url":"https://github.com/AnishShah/cpython","homepage":"","size":205407,"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":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"}},"base":{"label":"AnishShah:revert-1-test","ref":"revert-1-test","sha":"886390c8473a1d52e07d20fd97176a56c153b9a1","user":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url"
:"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false},"repo":{"id":59477756,"name":"cpython","full_name":"AnishShah/cpython","owner":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/Anis
hShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/AnishShah/cpython","description":"Semi-official
read-only mirror of the CPython Mercurial
repository","fork":true,"url":"https://api.github.com/repos/AnishShah/cpython","forks_url":"https://api.github.com/repos/AnishShah/cpython/forks","keys_url":"https://a
pi.github.com/repos/AnishShah/cpython/keys{/key_id}","collaborators_url":"https://api.github.com/repos/AnishShah/cpython/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/AnishShah/cpython/teams","hooks_url":"https://api.github.com/repos/AnishShah/cpython/hooks","issue_events_url":"https://api.github.com/repos/AnishShah/cpython/issues/events{/number}","events_url":"https://api.github.com/repos/AnishShah/cpython/events","assignees_url":"https://api.github.com/repos/AnishShah/cpython/assignees{/user}","branches_url":"https://api.github.com/repos/AnishShah/cpython/branches{/branch}","tags_url":"https://api.github.com/repos/AnishShah/cpython/tags","blobs_url":"https://api.github.com/repos/AnishShah/cpython/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/AnishShah/cpython/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/AnishShah/cpython/git/refs{/sha}","trees_url":"https://api.github.com/repos/AnishShah/cpython/git/trees{/sha}","st
atuses_url":"https://api.github.com/repos/AnishShah/cpython/statuses/{sha}","languages_url":"https://api.github.com/repos/AnishShah/cpython/languages","stargazers_url":"https://api.github.com/repos/AnishShah/cpython/stargazers","contributors_url":"https://api.github.com/repos/AnishShah/cpython/contributors","subscribers_url":"https://api.github.com/repos/AnishShah/cpython/subscribers","subscription_url":"https://api.github.com/repos/AnishShah/cpython/subscription","commits_url":"https://api.github.com/repos/AnishShah/cpython/commits{/sha}","git_commits_url":"https://api.github.com/repos/AnishShah/cpython/git/commits{/sha}","comments_url":"https://api.github.com/repos/AnishShah/cpython/comments{/number}","issue_comment_url":"https://api.github.com/repos/AnishShah/cpython/issues/comments{/number}","contents_url":"https://api.github.com/repos/AnishShah/cpython/contents/{+path}","compare_url":"https://api.github.com/repos/AnishShah/cpython/compare/{base}...{head}","merges_url":"
https://api.github.com/repos/AnishShah/cpython/merges","archive_url":"https://api.github.com/repos/AnishShah/cpython/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/AnishShah/cpython/downloads","issues_url":"https://api.github.com/repos/AnishShah/cpython/issues{/number}","pulls_url":"https://api.github.com/repos/AnishShah/cpython/pulls{/number}","milestones_url":"https://api.github.com/repos/AnishShah/cpython/milestones{/number}","notifications_url":"https://api.github.com/repos/AnishShah/cpython/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/AnishShah/cpython/labels{/name}","releases_url":"https://api.github.com/repos/AnishShah/cpython/releases{/id}","deployments_url":"https://api.github.com/repos/AnishShah/cpython/deployments","created_at":"2016-05-23T11:39:11Z","updated_at":"2016-05-23T11:39:38Z","pushed_at":"2016-08-07T10:25:19Z","git_url":"git://github.com/AnishShah/cpython.git","ssh_url":"g...@github.com:AnishSh
ah/cpython.git","clone_url":"https://github.com/AnishShah/cpython.git","svn_url":"https://github.com/AnishShah/cpython","homepage":"","size":205407,"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":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/AnishShah/cpython/pulls/11"},"html":{"href":"https://github.com/AnishShah/cpython/pull/11"},"issue":{"href":"https://api.github.com/repos/AnishShah/cpython/issues/11"},"comments":{"href":"https://api.github.com/repos/AnishShah/cpython/issues/11/comments"},"review_comments":{"href":"https://api.github.com/repos/AnishShah/cpython/pulls/11/comments"},"review_comment":{"href":"https://api.github.com/repos/AnishShah/cpython/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/AnishShah/cpython/pulls/11/comm
its"},"statuses":{"href":"https://api.github.com/repos/AnishShah/cpython/statuses/170f8a1f0ffbb733de656cd4a332ecea0c526d53"}},"merged":false,"mergeable":null,"mergeable_state":"unknown","merged_by":null,"comments":0,"review_comments":0,"commits":1,"additions":2,"deletions":0,"changed_files":1},"repository":{"id":59477756,"name":"cpython","full_name":"AnishShah/cpython","owner":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.
github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/AnishShah/cpython","description":"Semi-official
read-only mirror of the CPython Mercurial
repository","fork":true,"url":"https://api.github.com/repos/AnishShah/cpython","forks_url":"https://api.github.com/repos/AnishShah/cpython/forks","keys_url":"https://api.github.com/repos/AnishShah/cpython/keys{/key_id}","collaborators_url":"https://api.github.com/repos/AnishShah/cpython/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/AnishShah/cpython/teams","hooks_url":"https://api.github.com/repos/AnishShah/cpython/hooks","issue_events_url":"https://api.github.com/repos/AnishShah/cpython/issues/events{/number}","events_url":"https://api.github.
com/repos/AnishShah/cpython/events","assignees_url":"https://api.github.com/repos/AnishShah/cpython/assignees{/user}","branches_url":"https://api.github.com/repos/AnishShah/cpython/branches{/branch}","tags_url":"https://api.github.com/repos/AnishShah/cpython/tags","blobs_url":"https://api.github.com/repos/AnishShah/cpython/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/AnishShah/cpython/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/AnishShah/cpython/git/refs{/sha}","trees_url":"https://api.github.com/repos/AnishShah/cpython/git/trees{/sha}","statuses_url":"https://api.github.com/repos/AnishShah/cpython/statuses/{sha}","languages_url":"https://api.github.com/repos/AnishShah/cpython/languages","stargazers_url":"https://api.github.com/repos/AnishShah/cpython/stargazers","contributors_url":"https://api.github.com/repos/AnishShah/cpython/contributors","subscribers_url":"https://api.github.com/repos/AnishShah/cpython/subscribers","subscription_url":"h
ttps://api.github.com/repos/AnishShah/cpython/subscription","commits_url":"https://api.github.com/repos/AnishShah/cpython/commits{/sha}","git_commits_url":"https://api.github.com/repos/AnishShah/cpython/git/commits{/sha}","comments_url":"https://api.github.com/repos/AnishShah/cpython/comments{/number}","issue_comment_url":"https://api.github.com/repos/AnishShah/cpython/issues/comments{/number}","contents_url":"https://api.github.com/repos/AnishShah/cpython/contents/{+path}","compare_url":"https://api.github.com/repos/AnishShah/cpython/compare/{base}...{head}","merges_url":"https://api.github.com/repos/AnishShah/cpython/merges","archive_url":"https://api.github.com/repos/AnishShah/cpython/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/AnishShah/cpython/downloads","issues_url":"https://api.github.com/repos/AnishShah/cpython/issues{/number}","pulls_url":"https://api.github.com/repos/AnishShah/cpython/pulls{/number}","milestones_url":"https://api.github.co
m/repos/AnishShah/cpython/milestones{/number}","notifications_url":"https://api.github.com/repos/AnishShah/cpython/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/AnishShah/cpython/labels{/name}","releases_url":"https://api.github.com/repos/AnishShah/cpython/releases{/id}","deployments_url":"https://api.github.com/repos/AnishShah/cpython/deployments","created_at":"2016-05-23T11:39:11Z","updated_at":"2016-05-23T11:39:38Z","pushed_at":"2016-08-07T10:25:19Z","git_url":"git://github.com/AnishShah/cpython.git","ssh_url":"g...@github.com:AnishShah/cpython.git","clone_url":"https://github.com/AnishShah/cpython.git","svn_url":"https://github.com/AnishShah/cpython","homepage":"","size":205407,"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":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"},"sen
der":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false}}
diff --git a/test/data/pullrequestevent1.txt b/test/data/pullrequestevent1.txt
new file mode 100644
index 0000000..bcda453
--- /dev/null
+++ b/test/data/pullrequestevent1.txt
@@ -0,0 +1,11 @@
+POST /python-dev/pull_request HTTP/1.1
+Host: 2f3784dc.ngrok.io
+Accept: */*
+User-Agent: GitHub-Hookshot/9667e0c
+X-GitHub-Event: pull_request
+X-GitHub-Delivery: 251f6480-3640-11e6-97d9-1d57a5a69e84
+content-type: application/json
+X-Hub-Signature: sha1=33bf2b45321cd67fe671587f33b3f6bbde22268b
+Content-Length: 19656
+
+{"action":"opened","number":3,"pull_request":{"url":"https://api.github.com/repos/AnishShah/cpython/pulls/3","id":74368420,"html_url":"https://github.com/AnishShah/cpython/pull/3","diff_url":"https://github.com/AnishShah/cpython/pull/3.diff","patch_url":"https://github.com/AnishShah/cpython/pull/3.patch","issue_url":"https://api.github.com/repos/AnishShah/cpython/issues/3","number":3,"state":"open","locked":false,"title":"Created
using GitHub
API","user":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://
api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false},"body":"Fixes
bpo1","created_at":"2016-06-19T17:06:21Z","updated_at":"2016-06-19T17:06:21Z","closed_at":null,"merged_at":null,"merge_commit_sha":null,"assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/AnishShah/cpython/pulls/3/commits","review_comments_url":"https://api.github.com/repos/AnishShah/cpython/pulls/3/comments","review_comment_url":"https://api.github.com/repos/AnishShah/cpython/pulls/comments{/number}","comments_url":"https://api.github.com/repos/AnishShah/cpython/issues/3/comments","statuses_url":"https://api.github.com/repos/AnishShah/cpython/statuses/17f854a76947193fadde6837d7d92123f47d
7e16","head":{"label":"AnishShah:test","ref":"test","sha":"17f854a76947193fadde6837d7d92123f47d7e16","user":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":fal
se},"repo":{"id":59477756,"name":"cpython","full_name":"AnishShah/cpython","owner":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false},"private":false,"html
_url":"https://github.com/AnishShah/cpython","description":"Semi-official
read-only mirror of the CPython Mercurial
repository","fork":true,"url":"https://api.github.com/repos/AnishShah/cpython","forks_url":"https://api.github.com/repos/AnishShah/cpython/forks","keys_url":"https://api.github.com/repos/AnishShah/cpython/keys{/key_id}","collaborators_url":"https://api.github.com/repos/AnishShah/cpython/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/AnishShah/cpython/teams","hooks_url":"https://api.github.com/repos/AnishShah/cpython/hooks","issue_events_url":"https://api.github.com/repos/AnishShah/cpython/issues/events{/number}","events_url":"https://api.github.com/repos/AnishShah/cpython/events","assignees_url":"https://api.github.com/repos/AnishShah/cpython/assignees{/user}","branches_url":"https://api.github.com/repos/AnishShah/cpython/branches{/branch}","tags_url":"https://api.github.com/repos/AnishShah/cpython/tags","blobs_url":"https://api.github.
com/repos/AnishShah/cpython/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/AnishShah/cpython/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/AnishShah/cpython/git/refs{/sha}","trees_url":"https://api.github.com/repos/AnishShah/cpython/git/trees{/sha}","statuses_url":"https://api.github.com/repos/AnishShah/cpython/statuses/{sha}","languages_url":"https://api.github.com/repos/AnishShah/cpython/languages","stargazers_url":"https://api.github.com/repos/AnishShah/cpython/stargazers","contributors_url":"https://api.github.com/repos/AnishShah/cpython/contributors","subscribers_url":"https://api.github.com/repos/AnishShah/cpython/subscribers","subscription_url":"https://api.github.com/repos/AnishShah/cpython/subscription","commits_url":"https://api.github.com/repos/AnishShah/cpython/commits{/sha}","git_commits_url":"https://api.github.com/repos/AnishShah/cpython/git/commits{/sha}","comments_url":"https://api.github.com/repos/AnishShah/cpython/comments{/nu
mber}","issue_comment_url":"https://api.github.com/repos/AnishShah/cpython/issues/comments{/number}","contents_url":"https://api.github.com/repos/AnishShah/cpython/contents/{+path}","compare_url":"https://api.github.com/repos/AnishShah/cpython/compare/{base}...{head}","merges_url":"https://api.github.com/repos/AnishShah/cpython/merges","archive_url":"https://api.github.com/repos/AnishShah/cpython/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/AnishShah/cpython/downloads","issues_url":"https://api.github.com/repos/AnishShah/cpython/issues{/number}","pulls_url":"https://api.github.com/repos/AnishShah/cpython/pulls{/number}","milestones_url":"https://api.github.com/repos/AnishShah/cpython/milestones{/number}","notifications_url":"https://api.github.com/repos/AnishShah/cpython/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/AnishShah/cpython/labels{/name}","releases_url":"https://api.github.com/repos/AnishShah/cpython/re
leases{/id}","deployments_url":"https://api.github.com/repos/AnishShah/cpython/deployments","created_at":"2016-05-23T11:39:11Z","updated_at":"2016-05-23T11:39:38Z","pushed_at":"2016-06-15T19:43:02Z","git_url":"git://github.com/AnishShah/cpython.git","ssh_url":"g...@github.com:AnishShah/cpython.git","clone_url":"https://github.com/AnishShah/cpython.git","svn_url":"https://github.com/AnishShah/cpython","homepage":"","size":205466,"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":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"}},"base":{"label":"AnishShah:master","ref":"master","sha":"170f8a1f0ffbb733de656cd4a332ecea0c526d53","user":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.co
m/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false},"repo":{"id":59477756,"name":"cpython","full_name":"AnishShah/cpython","owner":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_u
rl":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/AnishShah/cpython","description":"Semi-official
read-only mirror of the CPython Mercurial
repository","fork":true,"url":"https://api.github.com/repos/AnishShah/cpython","forks_url":"https://api.github.com/repos/AnishShah/cpython/forks","keys_url":"https://api.github.com/repos
/AnishShah/cpython/keys{/key_id}","collaborators_url":"https://api.github.com/repos/AnishShah/cpython/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/AnishShah/cpython/teams","hooks_url":"https://api.github.com/repos/AnishShah/cpython/hooks","issue_events_url":"https://api.github.com/repos/AnishShah/cpython/issues/events{/number}","events_url":"https://api.github.com/repos/AnishShah/cpython/events","assignees_url":"https://api.github.com/repos/AnishShah/cpython/assignees{/user}","branches_url":"https://api.github.com/repos/AnishShah/cpython/branches{/branch}","tags_url":"https://api.github.com/repos/AnishShah/cpython/tags","blobs_url":"https://api.github.com/repos/AnishShah/cpython/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/AnishShah/cpython/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/AnishShah/cpython/git/refs{/sha}","trees_url":"https://api.github.com/repos/AnishShah/cpython/git/trees{/sha}","statuses_url":"https:
//api.github.com/repos/AnishShah/cpython/statuses/{sha}","languages_url":"https://api.github.com/repos/AnishShah/cpython/languages","stargazers_url":"https://api.github.com/repos/AnishShah/cpython/stargazers","contributors_url":"https://api.github.com/repos/AnishShah/cpython/contributors","subscribers_url":"https://api.github.com/repos/AnishShah/cpython/subscribers","subscription_url":"https://api.github.com/repos/AnishShah/cpython/subscription","commits_url":"https://api.github.com/repos/AnishShah/cpython/commits{/sha}","git_commits_url":"https://api.github.com/repos/AnishShah/cpython/git/commits{/sha}","comments_url":"https://api.github.com/repos/AnishShah/cpython/comments{/number}","issue_comment_url":"https://api.github.com/repos/AnishShah/cpython/issues/comments{/number}","contents_url":"https://api.github.com/repos/AnishShah/cpython/contents/{+path}","compare_url":"https://api.github.com/repos/AnishShah/cpython/compare/{base}...{head}","merges_url":"https://api.github.
com/repos/AnishShah/cpython/merges","archive_url":"https://api.github.com/repos/AnishShah/cpython/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/AnishShah/cpython/downloads","issues_url":"https://api.github.com/repos/AnishShah/cpython/issues{/number}","pulls_url":"https://api.github.com/repos/AnishShah/cpython/pulls{/number}","milestones_url":"https://api.github.com/repos/AnishShah/cpython/milestones{/number}","notifications_url":"https://api.github.com/repos/AnishShah/cpython/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/AnishShah/cpython/labels{/name}","releases_url":"https://api.github.com/repos/AnishShah/cpython/releases{/id}","deployments_url":"https://api.github.com/repos/AnishShah/cpython/deployments","created_at":"2016-05-23T11:39:11Z","updated_at":"2016-05-23T11:39:38Z","pushed_at":"2016-06-15T19:43:02Z","git_url":"git://github.com/AnishShah/cpython.git","ssh_url":"g...@github.com:AnishShah/cpython.git","cl
one_url":"https://github.com/AnishShah/cpython.git","svn_url":"https://github.com/AnishShah/cpython","homepage":"","size":205466,"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":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/AnishShah/cpython/pulls/3"},"html":{"href":"https://github.com/AnishShah/cpython/pull/3"},"issue":{"href":"https://api.github.com/repos/AnishShah/cpython/issues/3"},"comments":{"href":"https://api.github.com/repos/AnishShah/cpython/issues/3/comments"},"review_comments":{"href":"https://api.github.com/repos/AnishShah/cpython/pulls/3/comments"},"review_comment":{"href":"https://api.github.com/repos/AnishShah/cpython/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/AnishShah/cpython/pulls/3/commits"},"statuses":{"href":
"https://api.github.com/repos/AnishShah/cpython/statuses/17f854a76947193fadde6837d7d92123f47d7e16"}},"merged":false,"mergeable":null,"mergeable_state":"unknown","merged_by":null,"comments":0,"review_comments":0,"commits":1,"additions":2,"deletions":0,"changed_files":1},"repository":{"id":59477756,"name":"cpython","full_name":"AnishShah/cpython","owner":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishSha
h/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/AnishShah/cpython","description":"Semi-official
read-only mirror of the CPython Mercurial
repository","fork":true,"url":"https://api.github.com/repos/AnishShah/cpython","forks_url":"https://api.github.com/repos/AnishShah/cpython/forks","keys_url":"https://api.github.com/repos/AnishShah/cpython/keys{/key_id}","collaborators_url":"https://api.github.com/repos/AnishShah/cpython/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/AnishShah/cpython/teams","hooks_url":"https://api.github.com/repos/AnishShah/cpython/hooks","issue_events_url":"https://api.github.com/repos/AnishShah/cpython/issues/events{/number}","events_url":"https://api.github.com/repos/AnishShah/cpyth
on/events","assignees_url":"https://api.github.com/repos/AnishShah/cpython/assignees{/user}","branches_url":"https://api.github.com/repos/AnishShah/cpython/branches{/branch}","tags_url":"https://api.github.com/repos/AnishShah/cpython/tags","blobs_url":"https://api.github.com/repos/AnishShah/cpython/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/AnishShah/cpython/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/AnishShah/cpython/git/refs{/sha}","trees_url":"https://api.github.com/repos/AnishShah/cpython/git/trees{/sha}","statuses_url":"https://api.github.com/repos/AnishShah/cpython/statuses/{sha}","languages_url":"https://api.github.com/repos/AnishShah/cpython/languages","stargazers_url":"https://api.github.com/repos/AnishShah/cpython/stargazers","contributors_url":"https://api.github.com/repos/AnishShah/cpython/contributors","subscribers_url":"https://api.github.com/repos/AnishShah/cpython/subscribers","subscription_url":"https://api.github.com/rep
os/AnishShah/cpython/subscription","commits_url":"https://api.github.com/repos/AnishShah/cpython/commits{/sha}","git_commits_url":"https://api.github.com/repos/AnishShah/cpython/git/commits{/sha}","comments_url":"https://api.github.com/repos/AnishShah/cpython/comments{/number}","issue_comment_url":"https://api.github.com/repos/AnishShah/cpython/issues/comments{/number}","contents_url":"https://api.github.com/repos/AnishShah/cpython/contents/{+path}","compare_url":"https://api.github.com/repos/AnishShah/cpython/compare/{base}...{head}","merges_url":"https://api.github.com/repos/AnishShah/cpython/merges","archive_url":"https://api.github.com/repos/AnishShah/cpython/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/AnishShah/cpython/downloads","issues_url":"https://api.github.com/repos/AnishShah/cpython/issues{/number}","pulls_url":"https://api.github.com/repos/AnishShah/cpython/pulls{/number}","milestones_url":"https://api.github.com/repos/AnishShah/cpython
/milestones{/number}","notifications_url":"https://api.github.com/repos/AnishShah/cpython/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/AnishShah/cpython/labels{/name}","releases_url":"https://api.github.com/repos/AnishShah/cpython/releases{/id}","deployments_url":"https://api.github.com/repos/AnishShah/cpython/deployments","created_at":"2016-05-23T11:39:11Z","updated_at":"2016-05-23T11:39:38Z","pushed_at":"2016-06-15T19:43:02Z","git_url":"git://github.com/AnishShah/cpython.git","ssh_url":"g...@github.com:AnishShah/cpython.git","clone_url":"https://github.com/AnishShah/cpython.git","svn_url":"https://github.com/AnishShah/cpython","homepage":"","size":205466,"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":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"},"sender":{"login":"AnishShah"
,"id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false}}
diff --git a/test/data/pullrequestevent2.txt b/test/data/pullrequestevent2.txt
new file mode 100644
index 0000000..d16d58b
--- /dev/null
+++ b/test/data/pullrequestevent2.txt
@@ -0,0 +1,11 @@
+POST /python-dev/pull_request HTTP/1.1
+Host: 8900ffb8.ngrok.io
+Accept: */*
+User-Agent: GitHub-Hookshot/0269732
+X-GitHub-Event: pull_request
+X-GitHub-Delivery: 60418b80-2199-11e6-98bc-9ed2b8e584c9
+content-type: application/json
+X-Hub-Signature: sha1=7d7354a77f1c8f4ad954065f7d193228209813a2
+Content-Length: 19626
+
+{"action":"opened","number":1,"pull_request":{"url":"https://api.github.com/repos/AnishShah/cpython/pulls/1","id":71194519,"html_url":"https://github.com/AnishShah/cpython/pull/1","diff_url":"https://github.com/AnishShah/cpython/pull/1.diff","patch_url":"https://github.com/AnishShah/cpython/pull/1.patch","issue_url":"https://api.github.com/repos/AnishShah/cpython/issues/1","number":1,"state":"open","locked":false,"title":"Test","user":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users
/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false},"body":"","created_at":"2016-05-24T10:22:11Z","updated_at":"2016-05-24T10:22:11Z","closed_at":null,"merged_at":null,"merge_commit_sha":null,"assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/AnishShah/cpython/pulls/1/commits","review_comments_url":"https://api.github.com/repos/AnishShah/cpython/pulls/1/comments","review_comment_url":"https://api.github.com/repos/AnishShah/cpython/pulls/comments{/number}","comments_url":"https://api.github.com/repos/AnishShah/cpython/issues/1/comments","statuses_url":"https://api.github.com/repos/AnishShah/cpython/statuses/17f854a76947193fadde6837d7d92123f47d7e16","head":{"label":"AnishSh
ah:test","ref":"test","sha":"17f854a76947193fadde6837d7d92123f47d7e16","user":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false},"repo":{"id":59477756,"nam
e":"cpython","full_name":"AnishShah/cpython","owner":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/Anis
hShah/cpython","description":"Semi-official read-only mirror of the CPython
Mercurial
repository","fork":true,"url":"https://api.github.com/repos/AnishShah/cpython","forks_url":"https://api.github.com/repos/AnishShah/cpython/forks","keys_url":"https://api.github.com/repos/AnishShah/cpython/keys{/key_id}","collaborators_url":"https://api.github.com/repos/AnishShah/cpython/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/AnishShah/cpython/teams","hooks_url":"https://api.github.com/repos/AnishShah/cpython/hooks","issue_events_url":"https://api.github.com/repos/AnishShah/cpython/issues/events{/number}","events_url":"https://api.github.com/repos/AnishShah/cpython/events","assignees_url":"https://api.github.com/repos/AnishShah/cpython/assignees{/user}","branches_url":"https://api.github.com/repos/AnishShah/cpython/branches{/branch}","tags_url":"https://api.github.com/repos/AnishShah/cpython/tags","blobs_url":"https://api.github.com/repos/AnishShah/cpython/gi
t/blobs{/sha}","git_tags_url":"https://api.github.com/repos/AnishShah/cpython/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/AnishShah/cpython/git/refs{/sha}","trees_url":"https://api.github.com/repos/AnishShah/cpython/git/trees{/sha}","statuses_url":"https://api.github.com/repos/AnishShah/cpython/statuses/{sha}","languages_url":"https://api.github.com/repos/AnishShah/cpython/languages","stargazers_url":"https://api.github.com/repos/AnishShah/cpython/stargazers","contributors_url":"https://api.github.com/repos/AnishShah/cpython/contributors","subscribers_url":"https://api.github.com/repos/AnishShah/cpython/subscribers","subscription_url":"https://api.github.com/repos/AnishShah/cpython/subscription","commits_url":"https://api.github.com/repos/AnishShah/cpython/commits{/sha}","git_commits_url":"https://api.github.com/repos/AnishShah/cpython/git/commits{/sha}","comments_url":"https://api.github.com/repos/AnishShah/cpython/comments{/number}","issue_comment_url":"ht
tps://api.github.com/repos/AnishShah/cpython/issues/comments{/number}","contents_url":"https://api.github.com/repos/AnishShah/cpython/contents/{+path}","compare_url":"https://api.github.com/repos/AnishShah/cpython/compare/{base}...{head}","merges_url":"https://api.github.com/repos/AnishShah/cpython/merges","archive_url":"https://api.github.com/repos/AnishShah/cpython/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/AnishShah/cpython/downloads","issues_url":"https://api.github.com/repos/AnishShah/cpython/issues{/number}","pulls_url":"https://api.github.com/repos/AnishShah/cpython/pulls{/number}","milestones_url":"https://api.github.com/repos/AnishShah/cpython/milestones{/number}","notifications_url":"https://api.github.com/repos/AnishShah/cpython/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/AnishShah/cpython/labels{/name}","releases_url":"https://api.github.com/repos/AnishShah/cpython/releases{/id}","deployments_url"
:"https://api.github.com/repos/AnishShah/cpython/deployments","created_at":"2016-05-23T11:39:11Z","updated_at":"2016-05-23T11:39:38Z","pushed_at":"2016-05-24T10:19:54Z","git_url":"git://github.com/AnishShah/cpython.git","ssh_url":"g...@github.com:AnishShah/cpython.git","clone_url":"https://github.com/AnishShah/cpython.git","svn_url":"https://github.com/AnishShah/cpython","homepage":"","size":276517,"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":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"}},"base":{"label":"AnishShah:master","ref":"master","sha":"b998f589f341718f24013cc79e8358bec03dfde3","user":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"
https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false},"repo":{"id":59477756,"name":"cpython","full_name":"AnishShah/cpython","owner":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/us
ers/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/AnishShah/cpython","description":"Semi-official
read-only mirror of the CPython Mercurial
repository","fork":true,"url":"https://api.github.com/repos/AnishShah/cpython","forks_url":"https://api.github.com/repos/AnishShah/cpython/forks","keys_url":"https://api.github.com/repos/AnishShah/cpython/keys{/key_i
d}","collaborators_url":"https://api.github.com/repos/AnishShah/cpython/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/AnishShah/cpython/teams","hooks_url":"https://api.github.com/repos/AnishShah/cpython/hooks","issue_events_url":"https://api.github.com/repos/AnishShah/cpython/issues/events{/number}","events_url":"https://api.github.com/repos/AnishShah/cpython/events","assignees_url":"https://api.github.com/repos/AnishShah/cpython/assignees{/user}","branches_url":"https://api.github.com/repos/AnishShah/cpython/branches{/branch}","tags_url":"https://api.github.com/repos/AnishShah/cpython/tags","blobs_url":"https://api.github.com/repos/AnishShah/cpython/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/AnishShah/cpython/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/AnishShah/cpython/git/refs{/sha}","trees_url":"https://api.github.com/repos/AnishShah/cpython/git/trees{/sha}","statuses_url":"https://api.github.com/repos/AnishSh
ah/cpython/statuses/{sha}","languages_url":"https://api.github.com/repos/AnishShah/cpython/languages","stargazers_url":"https://api.github.com/repos/AnishShah/cpython/stargazers","contributors_url":"https://api.github.com/repos/AnishShah/cpython/contributors","subscribers_url":"https://api.github.com/repos/AnishShah/cpython/subscribers","subscription_url":"https://api.github.com/repos/AnishShah/cpython/subscription","commits_url":"https://api.github.com/repos/AnishShah/cpython/commits{/sha}","git_commits_url":"https://api.github.com/repos/AnishShah/cpython/git/commits{/sha}","comments_url":"https://api.github.com/repos/AnishShah/cpython/comments{/number}","issue_comment_url":"https://api.github.com/repos/AnishShah/cpython/issues/comments{/number}","contents_url":"https://api.github.com/repos/AnishShah/cpython/contents/{+path}","compare_url":"https://api.github.com/repos/AnishShah/cpython/compare/{base}...{head}","merges_url":"https://api.github.com/repos/AnishShah/cpython/me
rges","archive_url":"https://api.github.com/repos/AnishShah/cpython/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/AnishShah/cpython/downloads","issues_url":"https://api.github.com/repos/AnishShah/cpython/issues{/number}","pulls_url":"https://api.github.com/repos/AnishShah/cpython/pulls{/number}","milestones_url":"https://api.github.com/repos/AnishShah/cpython/milestones{/number}","notifications_url":"https://api.github.com/repos/AnishShah/cpython/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/AnishShah/cpython/labels{/name}","releases_url":"https://api.github.com/repos/AnishShah/cpython/releases{/id}","deployments_url":"https://api.github.com/repos/AnishShah/cpython/deployments","created_at":"2016-05-23T11:39:11Z","updated_at":"2016-05-23T11:39:38Z","pushed_at":"2016-05-24T10:19:54Z","git_url":"git://github.com/AnishShah/cpython.git","ssh_url":"g...@github.com:AnishShah/cpython.git","clone_url":"https://github.com/A
nishShah/cpython.git","svn_url":"https://github.com/AnishShah/cpython","homepage":"","size":276517,"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":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/AnishShah/cpython/pulls/1"},"html":{"href":"https://github.com/AnishShah/cpython/pull/1"},"issue":{"href":"https://api.github.com/repos/AnishShah/cpython/issues/1"},"comments":{"href":"https://api.github.com/repos/AnishShah/cpython/issues/1/comments"},"review_comments":{"href":"https://api.github.com/repos/AnishShah/cpython/pulls/1/comments"},"review_comment":{"href":"https://api.github.com/repos/AnishShah/cpython/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/AnishShah/cpython/pulls/1/commits"},"statuses":{"href":"https://api.github.com/repos/
AnishShah/cpython/statuses/17f854a76947193fadde6837d7d92123f47d7e16"}},"merged":false,"mergeable":null,"mergeable_state":"unknown","merged_by":null,"comments":0,"review_comments":0,"commits":1,"additions":2,"deletions":0,"changed_files":1},"repository":{"id":59477756,"name":"cpython","full_name":"AnishShah/cpython","owner":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://a
pi.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/AnishShah/cpython","description":"Semi-official
read-only mirror of the CPython Mercurial
repository","fork":true,"url":"https://api.github.com/repos/AnishShah/cpython","forks_url":"https://api.github.com/repos/AnishShah/cpython/forks","keys_url":"https://api.github.com/repos/AnishShah/cpython/keys{/key_id}","collaborators_url":"https://api.github.com/repos/AnishShah/cpython/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/AnishShah/cpython/teams","hooks_url":"https://api.github.com/repos/AnishShah/cpython/hooks","issue_events_url":"https://api.github.com/repos/AnishShah/cpython/issues/events{/number}","events_url":"https://api.github.com/repos/AnishShah/cpython/events","assignees_url":"ht
tps://api.github.com/repos/AnishShah/cpython/assignees{/user}","branches_url":"https://api.github.com/repos/AnishShah/cpython/branches{/branch}","tags_url":"https://api.github.com/repos/AnishShah/cpython/tags","blobs_url":"https://api.github.com/repos/AnishShah/cpython/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/AnishShah/cpython/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/AnishShah/cpython/git/refs{/sha}","trees_url":"https://api.github.com/repos/AnishShah/cpython/git/trees{/sha}","statuses_url":"https://api.github.com/repos/AnishShah/cpython/statuses/{sha}","languages_url":"https://api.github.com/repos/AnishShah/cpython/languages","stargazers_url":"https://api.github.com/repos/AnishShah/cpython/stargazers","contributors_url":"https://api.github.com/repos/AnishShah/cpython/contributors","subscribers_url":"https://api.github.com/repos/AnishShah/cpython/subscribers","subscription_url":"https://api.github.com/repos/AnishShah/cpython/subscript
ion","commits_url":"https://api.github.com/repos/AnishShah/cpython/commits{/sha}","git_commits_url":"https://api.github.com/repos/AnishShah/cpython/git/commits{/sha}","comments_url":"https://api.github.com/repos/AnishShah/cpython/comments{/number}","issue_comment_url":"https://api.github.com/repos/AnishShah/cpython/issues/comments{/number}","contents_url":"https://api.github.com/repos/AnishShah/cpython/contents/{+path}","compare_url":"https://api.github.com/repos/AnishShah/cpython/compare/{base}...{head}","merges_url":"https://api.github.com/repos/AnishShah/cpython/merges","archive_url":"https://api.github.com/repos/AnishShah/cpython/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/AnishShah/cpython/downloads","issues_url":"https://api.github.com/repos/AnishShah/cpython/issues{/number}","pulls_url":"https://api.github.com/repos/AnishShah/cpython/pulls{/number}","milestones_url":"https://api.github.com/repos/AnishShah/cpython/milestones{/number}","notific
ations_url":"https://api.github.com/repos/AnishShah/cpython/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/AnishShah/cpython/labels{/name}","releases_url":"https://api.github.com/repos/AnishShah/cpython/releases{/id}","deployments_url":"https://api.github.com/repos/AnishShah/cpython/deployments","created_at":"2016-05-23T11:39:11Z","updated_at":"2016-05-23T11:39:38Z","pushed_at":"2016-05-24T10:19:54Z","git_url":"git://github.com/AnishShah/cpython.git","ssh_url":"g...@github.com:AnishShah/cpython.git","clone_url":"https://github.com/AnishShah/cpython.git","svn_url":"https://github.com/AnishShah/cpython","homepage":"","size":276517,"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":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"},"sender":{"login":"AnishShah","id":3175743,"avatar_url":"ht
tps://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false}}
diff --git a/test/data/pullrequestevent3.txt b/test/data/pullrequestevent3.txt
new file mode 100644
index 0000000..107323b
--- /dev/null
+++ b/test/data/pullrequestevent3.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: pull_request
+X-GitHub-Delivery: afc32e00-5c97-11e6-8ffa-5bf6b88808be
+content-type: application/json
+X-Hub-Signature: sha1=648010d96d23da6ca7851d9a467731702f558aad
+Content-Length: 19693
+
+{"action":"opened","number":13,"pull_request":{"url":"https://api.github.com/repos/AnishShah/cpython/pulls/13","id":80365455,"html_url":"https://github.com/AnishShah/cpython/pull/13","diff_url":"https://github.com/AnishShah/cpython/pull/13.diff","patch_url":"https://github.com/AnishShah/cpython/pull/13.patch","issue_url":"https://api.github.com/repos/AnishShah/cpython/issues/13","number":13,"state":"open","locked":false,"title":"fixes
bpo1, bpo2,
bpo3","user":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"htt
ps://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false},"body":"","created_at":"2016-08-07T12:08:44Z","updated_at":"2016-08-07T12:08:44Z","closed_at":null,"merged_at":null,"merge_commit_sha":null,"assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/AnishShah/cpython/pulls/13/commits","review_comments_url":"https://api.github.com/repos/AnishShah/cpython/pulls/13/comments","review_comment_url":"https://api.github.com/repos/AnishShah/cpython/pulls/comments{/number}","comments_url":"https://api.github.com/repos/AnishShah/cpython/issues/13/comments","statuses_url":"https://api.github.com/repos/AnishShah/cpython/statuses/170f8a1f0ffbb733de656cd
4a332ecea0c526d53","head":{"label":"AnishShah:master","ref":"master","sha":"170f8a1f0ffbb733de656cd4a332ecea0c526d53","user":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User"
,"site_admin":false},"repo":{"id":59477756,"name":"cpython","full_name":"AnishShah/cpython","owner":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false},"pri
vate":false,"html_url":"https://github.com/AnishShah/cpython","description":"Semi-official
read-only mirror of the CPython Mercurial
repository","fork":true,"url":"https://api.github.com/repos/AnishShah/cpython","forks_url":"https://api.github.com/repos/AnishShah/cpython/forks","keys_url":"https://api.github.com/repos/AnishShah/cpython/keys{/key_id}","collaborators_url":"https://api.github.com/repos/AnishShah/cpython/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/AnishShah/cpython/teams","hooks_url":"https://api.github.com/repos/AnishShah/cpython/hooks","issue_events_url":"https://api.github.com/repos/AnishShah/cpython/issues/events{/number}","events_url":"https://api.github.com/repos/AnishShah/cpython/events","assignees_url":"https://api.github.com/repos/AnishShah/cpython/assignees{/user}","branches_url":"https://api.github.com/repos/AnishShah/cpython/branches{/branch}","tags_url":"https://api.github.com/repos/AnishShah/cpython/tags","blobs_url":"ht
tps://api.github.com/repos/AnishShah/cpython/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/AnishShah/cpython/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/AnishShah/cpython/git/refs{/sha}","trees_url":"https://api.github.com/repos/AnishShah/cpython/git/trees{/sha}","statuses_url":"https://api.github.com/repos/AnishShah/cpython/statuses/{sha}","languages_url":"https://api.github.com/repos/AnishShah/cpython/languages","stargazers_url":"https://api.github.com/repos/AnishShah/cpython/stargazers","contributors_url":"https://api.github.com/repos/AnishShah/cpython/contributors","subscribers_url":"https://api.github.com/repos/AnishShah/cpython/subscribers","subscription_url":"https://api.github.com/repos/AnishShah/cpython/subscription","commits_url":"https://api.github.com/repos/AnishShah/cpython/commits{/sha}","git_commits_url":"https://api.github.com/repos/AnishShah/cpython/git/commits{/sha}","comments_url":"https://api.github.com/repos/AnishShah/cpy
thon/comments{/number}","issue_comment_url":"https://api.github.com/repos/AnishShah/cpython/issues/comments{/number}","contents_url":"https://api.github.com/repos/AnishShah/cpython/contents/{+path}","compare_url":"https://api.github.com/repos/AnishShah/cpython/compare/{base}...{head}","merges_url":"https://api.github.com/repos/AnishShah/cpython/merges","archive_url":"https://api.github.com/repos/AnishShah/cpython/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/AnishShah/cpython/downloads","issues_url":"https://api.github.com/repos/AnishShah/cpython/issues{/number}","pulls_url":"https://api.github.com/repos/AnishShah/cpython/pulls{/number}","milestones_url":"https://api.github.com/repos/AnishShah/cpython/milestones{/number}","notifications_url":"https://api.github.com/repos/AnishShah/cpython/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/AnishShah/cpython/labels{/name}","releases_url":"https://api.github.com/repos/Ani
shShah/cpython/releases{/id}","deployments_url":"https://api.github.com/repos/AnishShah/cpython/deployments","created_at":"2016-05-23T11:39:11Z","updated_at":"2016-05-23T11:39:38Z","pushed_at":"2016-08-07T12:07:47Z","git_url":"git://github.com/AnishShah/cpython.git","ssh_url":"g...@github.com:AnishShah/cpython.git","clone_url":"https://github.com/AnishShah/cpython.git","svn_url":"https://github.com/AnishShah/cpython","homepage":"","size":205407,"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":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"}},"base":{"label":"AnishShah:revert-1-test","ref":"revert-1-test","sha":"886390c8473a1d52e07d20fd97176a56c153b9a1","user":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah
","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false},"repo":{"id":59477756,"name":"cpython","full_name":"AnishShah/cpython","owner":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://git
hub.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/AnishShah/cpython","description":"Semi-official
read-only mirror of the CPython Mercurial
repository","fork":true,"url":"https://api.github.com/repos/AnishShah/cpython","forks_url":"https://api.github.com/repos/AnishShah/cpython/forks","keys_url
":"https://api.github.com/repos/AnishShah/cpython/keys{/key_id}","collaborators_url":"https://api.github.com/repos/AnishShah/cpython/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/AnishShah/cpython/teams","hooks_url":"https://api.github.com/repos/AnishShah/cpython/hooks","issue_events_url":"https://api.github.com/repos/AnishShah/cpython/issues/events{/number}","events_url":"https://api.github.com/repos/AnishShah/cpython/events","assignees_url":"https://api.github.com/repos/AnishShah/cpython/assignees{/user}","branches_url":"https://api.github.com/repos/AnishShah/cpython/branches{/branch}","tags_url":"https://api.github.com/repos/AnishShah/cpython/tags","blobs_url":"https://api.github.com/repos/AnishShah/cpython/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/AnishShah/cpython/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/AnishShah/cpython/git/refs{/sha}","trees_url":"https://api.github.com/repos/AnishShah/cpython/git/tree
s{/sha}","statuses_url":"https://api.github.com/repos/AnishShah/cpython/statuses/{sha}","languages_url":"https://api.github.com/repos/AnishShah/cpython/languages","stargazers_url":"https://api.github.com/repos/AnishShah/cpython/stargazers","contributors_url":"https://api.github.com/repos/AnishShah/cpython/contributors","subscribers_url":"https://api.github.com/repos/AnishShah/cpython/subscribers","subscription_url":"https://api.github.com/repos/AnishShah/cpython/subscription","commits_url":"https://api.github.com/repos/AnishShah/cpython/commits{/sha}","git_commits_url":"https://api.github.com/repos/AnishShah/cpython/git/commits{/sha}","comments_url":"https://api.github.com/repos/AnishShah/cpython/comments{/number}","issue_comment_url":"https://api.github.com/repos/AnishShah/cpython/issues/comments{/number}","contents_url":"https://api.github.com/repos/AnishShah/cpython/contents/{+path}","compare_url":"https://api.github.com/repos/AnishShah/cpython/compare/{base}...{head}","m
erges_url":"https://api.github.com/repos/AnishShah/cpython/merges","archive_url":"https://api.github.com/repos/AnishShah/cpython/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/AnishShah/cpython/downloads","issues_url":"https://api.github.com/repos/AnishShah/cpython/issues{/number}","pulls_url":"https://api.github.com/repos/AnishShah/cpython/pulls{/number}","milestones_url":"https://api.github.com/repos/AnishShah/cpython/milestones{/number}","notifications_url":"https://api.github.com/repos/AnishShah/cpython/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/AnishShah/cpython/labels{/name}","releases_url":"https://api.github.com/repos/AnishShah/cpython/releases{/id}","deployments_url":"https://api.github.com/repos/AnishShah/cpython/deployments","created_at":"2016-05-23T11:39:11Z","updated_at":"2016-05-23T11:39:38Z","pushed_at":"2016-08-07T12:07:47Z","git_url":"git://github.com/AnishShah/cpython.git","ssh_url":"git@github
.com:AnishShah/cpython.git","clone_url":"https://github.com/AnishShah/cpython.git","svn_url":"https://github.com/AnishShah/cpython","homepage":"","size":205407,"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":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/AnishShah/cpython/pulls/13"},"html":{"href":"https://github.com/AnishShah/cpython/pull/13"},"issue":{"href":"https://api.github.com/repos/AnishShah/cpython/issues/13"},"comments":{"href":"https://api.github.com/repos/AnishShah/cpython/issues/13/comments"},"review_comments":{"href":"https://api.github.com/repos/AnishShah/cpython/pulls/13/comments"},"review_comment":{"href":"https://api.github.com/repos/AnishShah/cpython/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/AnishShah/cpython/p
ulls/13/commits"},"statuses":{"href":"https://api.github.com/repos/AnishShah/cpython/statuses/170f8a1f0ffbb733de656cd4a332ecea0c526d53"}},"merged":false,"mergeable":null,"mergeable_state":"unknown","merged_by":null,"comments":0,"review_comments":0,"commits":1,"additions":2,"deletions":0,"changed_files":1},"repository":{"id":59477756,"name":"cpython","full_name":"AnishShah/cpython","owner":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"
https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/AnishShah/cpython","description":"Semi-official
read-only mirror of the CPython Mercurial
repository","fork":true,"url":"https://api.github.com/repos/AnishShah/cpython","forks_url":"https://api.github.com/repos/AnishShah/cpython/forks","keys_url":"https://api.github.com/repos/AnishShah/cpython/keys{/key_id}","collaborators_url":"https://api.github.com/repos/AnishShah/cpython/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/AnishShah/cpython/teams","hooks_url":"https://api.github.com/repos/AnishShah/cpython/hooks","issue_events_url":"https://api.github.com/repos/AnishShah/cpython/issues/events{/number}","events_url":"https:/
/api.github.com/repos/AnishShah/cpython/events","assignees_url":"https://api.github.com/repos/AnishShah/cpython/assignees{/user}","branches_url":"https://api.github.com/repos/AnishShah/cpython/branches{/branch}","tags_url":"https://api.github.com/repos/AnishShah/cpython/tags","blobs_url":"https://api.github.com/repos/AnishShah/cpython/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/AnishShah/cpython/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/AnishShah/cpython/git/refs{/sha}","trees_url":"https://api.github.com/repos/AnishShah/cpython/git/trees{/sha}","statuses_url":"https://api.github.com/repos/AnishShah/cpython/statuses/{sha}","languages_url":"https://api.github.com/repos/AnishShah/cpython/languages","stargazers_url":"https://api.github.com/repos/AnishShah/cpython/stargazers","contributors_url":"https://api.github.com/repos/AnishShah/cpython/contributors","subscribers_url":"https://api.github.com/repos/AnishShah/cpython/subscribers","subscrip
tion_url":"https://api.github.com/repos/AnishShah/cpython/subscription","commits_url":"https://api.github.com/repos/AnishShah/cpython/commits{/sha}","git_commits_url":"https://api.github.com/repos/AnishShah/cpython/git/commits{/sha}","comments_url":"https://api.github.com/repos/AnishShah/cpython/comments{/number}","issue_comment_url":"https://api.github.com/repos/AnishShah/cpython/issues/comments{/number}","contents_url":"https://api.github.com/repos/AnishShah/cpython/contents/{+path}","compare_url":"https://api.github.com/repos/AnishShah/cpython/compare/{base}...{head}","merges_url":"https://api.github.com/repos/AnishShah/cpython/merges","archive_url":"https://api.github.com/repos/AnishShah/cpython/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/AnishShah/cpython/downloads","issues_url":"https://api.github.com/repos/AnishShah/cpython/issues{/number}","pulls_url":"https://api.github.com/repos/AnishShah/cpython/pulls{/number}","milestones_url":"https://a
pi.github.com/repos/AnishShah/cpython/milestones{/number}","notifications_url":"https://api.github.com/repos/AnishShah/cpython/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/AnishShah/cpython/labels{/name}","releases_url":"https://api.github.com/repos/AnishShah/cpython/releases{/id}","deployments_url":"https://api.github.com/repos/AnishShah/cpython/deployments","created_at":"2016-05-23T11:39:11Z","updated_at":"2016-05-23T11:39:38Z","pushed_at":"2016-08-07T12:07:47Z","git_url":"git://github.com/AnishShah/cpython.git","ssh_url":"g...@github.com:AnishShah/cpython.git","clone_url":"https://github.com/AnishShah/cpython.git","svn_url":"https://github.com/AnishShah/cpython","homepage":"","size":205407,"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":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"m
aster"},"sender":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false}}
diff --git a/test/data/pullrequestevent4.txt b/test/data/pullrequestevent4.txt
new file mode 100644
index 0000000..24fc60a
--- /dev/null
+++ b/test/data/pullrequestevent4.txt
@@ -0,0 +1,11 @@
+POST /python-dev/pull_request HTTP/1.1
+Host: 7a1eec53.ngrok.io
+Accept: */*
+User-Agent: GitHub-Hookshot/c80b888
+X-GitHub-Event: pull_request
+X-GitHub-Delivery: 95867d00-5e5c-11e6-97c7-ddc89938af3a
+content-type: application/json
+X-Hub-Signature: sha1=7298f5c2d7fc531f347b7dcf074c0d040b6cbc86
+Content-Length: 19710
+
+{"action":"opened","number":14,"pull_request":{"url":"https://api.github.com/repos/AnishShah/cpython/pulls/14","id":80667637,"html_url":"https://github.com/AnishShah/cpython/pull/14","diff_url":"https://github.com/AnishShah/cpython/pull/14.diff","patch_url":"https://github.com/AnishShah/cpython/pull/14.patch","issue_url":"https://api.github.com/repos/AnishShah/cpython/issues/14","number":14,"state":"open","locked":false,"title":"update
.gitignore","user":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://
api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false},"body":"fixes
bpo1, bpo2,
bpo3","created_at":"2016-08-09T18:10:42Z","updated_at":"2016-08-09T18:10:42Z","closed_at":null,"merged_at":null,"merge_commit_sha":null,"assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/AnishShah/cpython/pulls/14/commits","review_comments_url":"https://api.github.com/repos/AnishShah/cpython/pulls/14/comments","review_comment_url":"https://api.github.com/repos/AnishShah/cpython/pulls/comments{/number}","comments_url":"https://api.github.com/repos/AnishShah/cpython/issues/14/comments","statuses_url":"https://api.github.com/repos/AnishShah/cpython/statuses/170f8a
1f0ffbb733de656cd4a332ecea0c526d53","head":{"label":"AnishShah:master","ref":"master","sha":"170f8a1f0ffbb733de656cd4a332ecea0c526d53","user":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_even
ts","type":"User","site_admin":false},"repo":{"id":59477756,"name":"cpython","full_name":"AnishShah/cpython","owner":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_a
dmin":false},"private":false,"html_url":"https://github.com/AnishShah/cpython","description":"Semi-official
read-only mirror of the CPython Mercurial
repository","fork":true,"url":"https://api.github.com/repos/AnishShah/cpython","forks_url":"https://api.github.com/repos/AnishShah/cpython/forks","keys_url":"https://api.github.com/repos/AnishShah/cpython/keys{/key_id}","collaborators_url":"https://api.github.com/repos/AnishShah/cpython/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/AnishShah/cpython/teams","hooks_url":"https://api.github.com/repos/AnishShah/cpython/hooks","issue_events_url":"https://api.github.com/repos/AnishShah/cpython/issues/events{/number}","events_url":"https://api.github.com/repos/AnishShah/cpython/events","assignees_url":"https://api.github.com/repos/AnishShah/cpython/assignees{/user}","branches_url":"https://api.github.com/repos/AnishShah/cpython/branches{/branch}","tags_url":"https://api.github.com/repos/AnishShah/cpython/tags
","blobs_url":"https://api.github.com/repos/AnishShah/cpython/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/AnishShah/cpython/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/AnishShah/cpython/git/refs{/sha}","trees_url":"https://api.github.com/repos/AnishShah/cpython/git/trees{/sha}","statuses_url":"https://api.github.com/repos/AnishShah/cpython/statuses/{sha}","languages_url":"https://api.github.com/repos/AnishShah/cpython/languages","stargazers_url":"https://api.github.com/repos/AnishShah/cpython/stargazers","contributors_url":"https://api.github.com/repos/AnishShah/cpython/contributors","subscribers_url":"https://api.github.com/repos/AnishShah/cpython/subscribers","subscription_url":"https://api.github.com/repos/AnishShah/cpython/subscription","commits_url":"https://api.github.com/repos/AnishShah/cpython/commits{/sha}","git_commits_url":"https://api.github.com/repos/AnishShah/cpython/git/commits{/sha}","comments_url":"https://api.github.com/re
pos/AnishShah/cpython/comments{/number}","issue_comment_url":"https://api.github.com/repos/AnishShah/cpython/issues/comments{/number}","contents_url":"https://api.github.com/repos/AnishShah/cpython/contents/{+path}","compare_url":"https://api.github.com/repos/AnishShah/cpython/compare/{base}...{head}","merges_url":"https://api.github.com/repos/AnishShah/cpython/merges","archive_url":"https://api.github.com/repos/AnishShah/cpython/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/AnishShah/cpython/downloads","issues_url":"https://api.github.com/repos/AnishShah/cpython/issues{/number}","pulls_url":"https://api.github.com/repos/AnishShah/cpython/pulls{/number}","milestones_url":"https://api.github.com/repos/AnishShah/cpython/milestones{/number}","notifications_url":"https://api.github.com/repos/AnishShah/cpython/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/AnishShah/cpython/labels{/name}","releases_url":"https://api.git
hub.com/repos/AnishShah/cpython/releases{/id}","deployments_url":"https://api.github.com/repos/AnishShah/cpython/deployments","created_at":"2016-05-23T11:39:11Z","updated_at":"2016-05-23T11:39:38Z","pushed_at":"2016-08-09T18:10:42Z","git_url":"git://github.com/AnishShah/cpython.git","ssh_url":"g...@github.com:AnishShah/cpython.git","clone_url":"https://github.com/AnishShah/cpython.git","svn_url":"https://github.com/AnishShah/cpython","homepage":"","size":205407,"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":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"}},"base":{"label":"AnishShah:revert-1-test","ref":"revert-1-test","sha":"886390c8473a1d52e07d20fd97176a56c153b9a1","user":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.co
m/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false},"repo":{"id":59477756,"name":"cpython","full_name":"AnishShah/cpython","owner":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_
url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/AnishShah/cpython","description":"Semi-official
read-only mirror of the CPython Mercurial
repository","fork":true,"url":"https://api.github.com/repos/AnishShah/cpython","forks_url":"https://api.github.com/repos/AnishShah/cpython
/forks","keys_url":"https://api.github.com/repos/AnishShah/cpython/keys{/key_id}","collaborators_url":"https://api.github.com/repos/AnishShah/cpython/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/AnishShah/cpython/teams","hooks_url":"https://api.github.com/repos/AnishShah/cpython/hooks","issue_events_url":"https://api.github.com/repos/AnishShah/cpython/issues/events{/number}","events_url":"https://api.github.com/repos/AnishShah/cpython/events","assignees_url":"https://api.github.com/repos/AnishShah/cpython/assignees{/user}","branches_url":"https://api.github.com/repos/AnishShah/cpython/branches{/branch}","tags_url":"https://api.github.com/repos/AnishShah/cpython/tags","blobs_url":"https://api.github.com/repos/AnishShah/cpython/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/AnishShah/cpython/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/AnishShah/cpython/git/refs{/sha}","trees_url":"https://api.github.com/repos/AnishShah
/cpython/git/trees{/sha}","statuses_url":"https://api.github.com/repos/AnishShah/cpython/statuses/{sha}","languages_url":"https://api.github.com/repos/AnishShah/cpython/languages","stargazers_url":"https://api.github.com/repos/AnishShah/cpython/stargazers","contributors_url":"https://api.github.com/repos/AnishShah/cpython/contributors","subscribers_url":"https://api.github.com/repos/AnishShah/cpython/subscribers","subscription_url":"https://api.github.com/repos/AnishShah/cpython/subscription","commits_url":"https://api.github.com/repos/AnishShah/cpython/commits{/sha}","git_commits_url":"https://api.github.com/repos/AnishShah/cpython/git/commits{/sha}","comments_url":"https://api.github.com/repos/AnishShah/cpython/comments{/number}","issue_comment_url":"https://api.github.com/repos/AnishShah/cpython/issues/comments{/number}","contents_url":"https://api.github.com/repos/AnishShah/cpython/contents/{+path}","compare_url":"https://api.github.com/repos/AnishShah/cpython/compare/{b
ase}...{head}","merges_url":"https://api.github.com/repos/AnishShah/cpython/merges","archive_url":"https://api.github.com/repos/AnishShah/cpython/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/AnishShah/cpython/downloads","issues_url":"https://api.github.com/repos/AnishShah/cpython/issues{/number}","pulls_url":"https://api.github.com/repos/AnishShah/cpython/pulls{/number}","milestones_url":"https://api.github.com/repos/AnishShah/cpython/milestones{/number}","notifications_url":"https://api.github.com/repos/AnishShah/cpython/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/AnishShah/cpython/labels{/name}","releases_url":"https://api.github.com/repos/AnishShah/cpython/releases{/id}","deployments_url":"https://api.github.com/repos/AnishShah/cpython/deployments","created_at":"2016-05-23T11:39:11Z","updated_at":"2016-05-23T11:39:38Z","pushed_at":"2016-08-09T18:10:42Z","git_url":"git://github.com/AnishShah/cpython.git","ssh
_url":"g...@github.com:AnishShah/cpython.git","clone_url":"https://github.com/AnishShah/cpython.git","svn_url":"https://github.com/AnishShah/cpython","homepage":"","size":205407,"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":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/AnishShah/cpython/pulls/14"},"html":{"href":"https://github.com/AnishShah/cpython/pull/14"},"issue":{"href":"https://api.github.com/repos/AnishShah/cpython/issues/14"},"comments":{"href":"https://api.github.com/repos/AnishShah/cpython/issues/14/comments"},"review_comments":{"href":"https://api.github.com/repos/AnishShah/cpython/pulls/14/comments"},"review_comment":{"href":"https://api.github.com/repos/AnishShah/cpython/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/An
ishShah/cpython/pulls/14/commits"},"statuses":{"href":"https://api.github.com/repos/AnishShah/cpython/statuses/170f8a1f0ffbb733de656cd4a332ecea0c526d53"}},"merged":false,"mergeable":null,"mergeable_state":"unknown","merged_by":null,"comments":0,"review_comments":0,"commits":1,"additions":2,"deletions":0,"changed_files":1},"repository":{"id":59477756,"name":"cpython","full_name":"AnishShah/cpython","owner":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","org
anizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/AnishShah/cpython","description":"Semi-official
read-only mirror of the CPython Mercurial
repository","fork":true,"url":"https://api.github.com/repos/AnishShah/cpython","forks_url":"https://api.github.com/repos/AnishShah/cpython/forks","keys_url":"https://api.github.com/repos/AnishShah/cpython/keys{/key_id}","collaborators_url":"https://api.github.com/repos/AnishShah/cpython/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/AnishShah/cpython/teams","hooks_url":"https://api.github.com/repos/AnishShah/cpython/hooks","issue_events_url":"https://api.github.com/repos/AnishShah/cpython/issues/events{/number}","eve
nts_url":"https://api.github.com/repos/AnishShah/cpython/events","assignees_url":"https://api.github.com/repos/AnishShah/cpython/assignees{/user}","branches_url":"https://api.github.com/repos/AnishShah/cpython/branches{/branch}","tags_url":"https://api.github.com/repos/AnishShah/cpython/tags","blobs_url":"https://api.github.com/repos/AnishShah/cpython/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/AnishShah/cpython/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/AnishShah/cpython/git/refs{/sha}","trees_url":"https://api.github.com/repos/AnishShah/cpython/git/trees{/sha}","statuses_url":"https://api.github.com/repos/AnishShah/cpython/statuses/{sha}","languages_url":"https://api.github.com/repos/AnishShah/cpython/languages","stargazers_url":"https://api.github.com/repos/AnishShah/cpython/stargazers","contributors_url":"https://api.github.com/repos/AnishShah/cpython/contributors","subscribers_url":"https://api.github.com/repos/AnishShah/cpython/subsc
ribers","subscription_url":"https://api.github.com/repos/AnishShah/cpython/subscription","commits_url":"https://api.github.com/repos/AnishShah/cpython/commits{/sha}","git_commits_url":"https://api.github.com/repos/AnishShah/cpython/git/commits{/sha}","comments_url":"https://api.github.com/repos/AnishShah/cpython/comments{/number}","issue_comment_url":"https://api.github.com/repos/AnishShah/cpython/issues/comments{/number}","contents_url":"https://api.github.com/repos/AnishShah/cpython/contents/{+path}","compare_url":"https://api.github.com/repos/AnishShah/cpython/compare/{base}...{head}","merges_url":"https://api.github.com/repos/AnishShah/cpython/merges","archive_url":"https://api.github.com/repos/AnishShah/cpython/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/AnishShah/cpython/downloads","issues_url":"https://api.github.com/repos/AnishShah/cpython/issues{/number}","pulls_url":"https://api.github.com/repos/AnishShah/cpython/pulls{/number}","milestone
s_url":"https://api.github.com/repos/AnishShah/cpython/milestones{/number}","notifications_url":"https://api.github.com/repos/AnishShah/cpython/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/AnishShah/cpython/labels{/name}","releases_url":"https://api.github.com/repos/AnishShah/cpython/releases{/id}","deployments_url":"https://api.github.com/repos/AnishShah/cpython/deployments","created_at":"2016-05-23T11:39:11Z","updated_at":"2016-05-23T11:39:38Z","pushed_at":"2016-08-09T18:10:42Z","git_url":"git://github.com/AnishShah/cpython.git","ssh_url":"g...@github.com:AnishShah/cpython.git","clone_url":"https://github.com/AnishShah/cpython.git","svn_url":"https://github.com/AnishShah/cpython","homepage":"","size":205407,"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":1,"forks":0,"open_issues":1,"watchers":0,"d
efault_branch":"master"},"sender":{"login":"AnishShah","id":3175743,"avatar_url":"https://avatars.githubusercontent.com/u/3175743?v=3","gravatar_id":"","url":"https://api.github.com/users/AnishShah","html_url":"https://github.com/AnishShah","followers_url":"https://api.github.com/users/AnishShah/followers","following_url":"https://api.github.com/users/AnishShah/following{/other_user}","gists_url":"https://api.github.com/users/AnishShah/gists{/gist_id}","starred_url":"https://api.github.com/users/AnishShah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnishShah/subscriptions","organizations_url":"https://api.github.com/users/AnishShah/orgs","repos_url":"https://api.github.com/users/AnishShah/repos","events_url":"https://api.github.com/users/AnishShah/events{/privacy}","received_events_url":"https://api.github.com/users/AnishShah/received_events","type":"User","site_admin":false}}
diff --git a/test/test_pull_request.py b/test/test_pull_request.py
new file mode 100644
index 0000000..f2a2c07
--- /dev/null
+++ b/test/test_pull_request.py
@@ -0,0 +1,219 @@
+import unittest
+import os
+import db_test_base
+import cgi
+from BaseHTTPServer import BaseHTTPRequestHandler
+from StringIO import StringIO
+from roundup.cgi import client
+from roundup.backends import list_backends
+from roundup.pull_request import GitHubHandler
+from roundup.exceptions import *
+
+NEEDS_INSTANCE = 1
+
+
+class HTTPRequest(BaseHTTPRequestHandler):
+ def __init__(self, filename):
+ path = os.path.dirname(os.path.abspath(__file__)) + "/data/" + filename
+ request_file = open(path, 'r')
+ request_text = request_file.read()
+ request_file.close()
+ self.rfile = StringIO(request_text)
+ self.raw_requestline = self.rfile.readline()
+ self.error_code = self.error_message = None
+ self.parse_request()
+
+
+class TestCase(unittest.TestCase):
+
+ backend = None
+
+ def setUp(self):
+ # instance
+ self.dirname = '_test_pull_request'
+ self.instance = db_test_base.setupTracker(self.dirname, self.backend)
+ self.env = {
+ 'PATH_INFO': 'http://localhost/pull_request',
+ 'HTTP_HOST': 'localhost',
+ 'TRACKER_NAME': 'test',
+ 'REQUEST_METHOD': 'POST',
+ 'CONTENT_TYPE': 'application/json'
+ }
+ os.environ['SECRET_KEY'] = "abcd"
+ os.environ['CREATE_ISSUE'] = 'yes'
+
+ def _make_client(self, filename):
+ request = HTTPRequest(filename)
+ form = cgi.FieldStorage(fp=request.rfile, environ=self.env,
+ headers=request.headers)
+ dummy_client = client.Client(self.instance, request, self.env, form)
+ dummy_client.opendb("anonymous")
+ self.db = dummy_client.db
+ self.db.issue.create(title="Hello")
+ return dummy_client
+
+ def testMissingSecretKey(self):
+ os.environ.pop('SECRET_KEY')
+ dummy_client = self._make_client("pingevent.txt")
+ with self.assertRaises(Reject) as context:
+ handler = GitHubHandler(dummy_client)
+ handler.dispatch()
+ self.assertEqual(str(context.exception),
+ "Invalid Request")
+
+ def testMissingGitHubEventHeader(self):
+ dummy_client = self._make_client("no-github-event-header.txt")
+ with self.assertRaises(Reject) as context:
+ handler = GitHubHandler(dummy_client)
+ handler.dispatch()
+ self.assertEqual(str(context.exception),
+ "Invalid Request")
+
+ def testNonJSONRequestBody(self):
+ dummy_client = self._make_client("non-json-body.txt")
+ with self.assertRaises(Reject) as context:
+ handler = GitHubHandler(dummy_client)
+ handler.dispatch()
+ self.assertEqual(str(context.exception),
+ "Invalid Request")
+
+ def testSecretKey(self):
+ os.environ['SECRET_KEY'] = "1234"
+ dummy_client = self._make_client("pingevent.txt")
+ with self.assertRaises(Unauthorised) as context:
+ handler = GitHubHandler(dummy_client)
+ handler.dispatch()
+ self.assertEqual(str(context.exception),
+ "The provided secret does not match")
+
+ def testUnsupportedMediaType(self):
+ dummy_client = self._make_client("pingevent.txt")
+ dummy_client.env['CONTENT_TYPE'] = 'application/xml'
+ with self.assertRaises(UnsupportedMediaType) as context:
+ handler = GitHubHandler(dummy_client)
+ handler.dispatch()
+ self.assertEqual(str(context.exception),
+ "unsupported Content-Type application/xml")
+
+ def testMethodNotAllowed(self):
+ dummy_client = self._make_client("pingevent.txt")
+ dummy_client.env['REQUEST_METHOD'] = 'GET'
+ with self.assertRaises(MethodNotAllowed) as context:
+ handler = GitHubHandler(dummy_client)
+ handler.dispatch()
+ self.assertEqual(str(context.exception),
+ "unsupported HTTP method GET")
+
+ def testPingEvent(self):
+ dummy_client = self._make_client("pingevent.txt")
+ with self.assertRaises(Reject) as context:
+ handler = GitHubHandler(dummy_client)
+ handler.dispatch()
+ self.assertEqual(str(context.exception), "Invalid Request")
+
+ def testIssueCommentEvent(self):
+ dummy_client = self._make_client("issuecommentevent.txt")
+ self.db.user.create(username="anish.shah", github="AnishShah")
+ handler = GitHubHandler(dummy_client)
+ handler.dispatch()
+ urls = self.db.issue.get('1', 'pull_requests')
+ self.assertTrue(len(urls) == 1)
+ url = self.db.pull_request.get(urls[0], 'url')
+ self.assertEqual(url, 'https://github.com/AnishShah/cpython/pull/1')
+ user_id = self.db.pull_request.get(urls[0], 'creator')
+ self.assertEqual(self.db.user.get(user_id, 'github'), 'AnishShah')
+
+ def testPullRequestEventForTitle(self):
+ # When the title of a PR has string "fixes bpo123"
+ dummy_client = self._make_client("pullrequestevent.txt")
+ handler = GitHubHandler(dummy_client)
+ handler.dispatch()
+ urls = self.db.issue.get('1', 'pull_requests')
+ self.assertTrue(len(urls) == 1)
+ url = self.db.pull_request.get(urls[0], 'url')
+ self.assertEqual(url, 'https://github.com/AnishShah/cpython/pull/11')
+ user_id = self.db.pull_request.get(urls[0], 'creator')
+ self.assertEqual(self.db.user.get(user_id, 'username'), 'anonymous')
+
+ def testPullRequestEventForBody(self):
+ # When the body of a PR has string "fixes bpo123"
+ dummy_client = self._make_client("pullrequestevent1.txt")
+ self.db.user.create(username="anish.shah", github="AnishShah")
+ handler = GitHubHandler(dummy_client)
+ handler.dispatch()
+ urls = self.db.issue.get('1', 'pull_requests')
+ self.assertTrue(len(urls) == 1)
+ url = self.db.pull_request.get(urls[0], 'url')
+ self.assertEqual(url, 'https://github.com/AnishShah/cpython/pull/3')
+ user_id = self.db.pull_request.get(urls[0], 'creator')
+ self.assertEqual(self.db.user.get(user_id, 'github'), 'AnishShah')
+
+ def testPullRequestEventForMultipleIssueReferenceInTitle(self):
+ dummy_client = self._make_client("pullrequestevent3.txt")
+ self.db.issue.create(title="Python")
+ self.db.issue.create(title="CPython")
+ handler = GitHubHandler(dummy_client)
+ handler.dispatch()
+ for i in range(1, 4):
+ urls = self.db.issue.get(str(i), 'pull_requests')
+ self.assertTrue(len(urls) == 1)
+ url = self.db.pull_request.get(urls[0], 'url')
+ self.assertEqual(url,
+ 'https://github.com/AnishShah/cpython/pull/13')
+
+ def testPullRequestEventForMultipleIssueReferenceInBody(self):
+ dummy_client = self._make_client("pullrequestevent4.txt")
+ self.db.issue.create(title="Python")
+ self.db.issue.create(title="CPython")
+ handler = GitHubHandler(dummy_client)
+ handler.dispatch()
+ for i in range(1, 4):
+ urls = self.db.issue.get(str(i), 'pull_requests')
+ self.assertTrue(len(urls) == 1)
+ url = self.db.pull_request.get(urls[0], 'url')
+ self.assertEqual(url,
+ 'https://github.com/AnishShah/cpython/pull/14')
+
+ def testPullRequestEventWithoutIssueReference(self):
+ # When no issue is referenced in PR and environment variable is set
+ dummy_client = self._make_client("pullrequestevent2.txt")
+ self.assertEqual(self.db.issue.count(), 1)
+ handler = GitHubHandler(dummy_client)
+ handler.dispatch()
+ self.assertEqual(self.db.issue.count(), 2)
+ user_id = self.db.issue.get('2', 'creator')
+ self.assertEqual(self.db.user.get(user_id, 'username'), 'anonymous')
+
+ def testPullRequestFromGitHubUserWithoutIssueReference(self):
+ # When no issue is referenced in PR and environment variable is set
+ # and Github field of b.p.o user is set
+ dummy_client = self._make_client("pullrequestevent2.txt")
+ self.db.user.create(username="anish.shah", github="AnishShah")
+ self.assertEqual(self.db.issue.count(), 1)
+ handler = GitHubHandler(dummy_client)
+ handler.dispatch()
+ self.assertEqual(self.db.issue.count(), 2)
+ user_id = self.db.issue.get('2', 'creator')
+ self.assertEqual(self.db.user.get(user_id, 'username'), 'anish.shah')
+
+ def testPullRequestEventWithoutIssueReferenceAndEnvVariable(self):
+ # When no issue is referenced in PR and no environment variable is set
+ os.environ.pop('CREATE_ISSUE')
+ dummy_client = self._make_client("pullrequestevent2.txt")
+ self.assertEqual(self.db.issue.count(), 1)
+ handler = GitHubHandler(dummy_client)
+ handler.dispatch()
+ self.assertEqual(self.db.issue.count(), 1)
+
+
+def test_suite():
+ suite = unittest.TestSuite()
+ for l in list_backends():
+ dct = dict(backend=l)
+ subcls = type(TestCase)('TestCase_%s' % l, (TestCase,), dct)
+ suite.addTest(unittest.makeSuite(subcls))
+ return suite
+
+if __name__ == '__main__':
+ runner = unittest.TextTestRunner()
+ unittest.main(testRunner=runner)
_______________________________________________
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/