8000 Add support for fetching pull request reviews · pythonthings/github3.py@8e9ca00 · GitHub
[go: up one dir, main page]

Skip to content

Commit 8e9ca00

Browse files
committed
Add support for fetching pull request reviews
This is in preview upstream. Allows fetching the reviews for a given pull request, and the user that provided the review. Partially implements sigmavirus24#666 Signed-off-by: Jesse Keating <jkeating@j2solutions.net>
1 parent 1edaca3 commit 8e9ca00

File tree

4 files changed

+95
-0
lines changed

4 files changed

+95
-0
lines changed

github3/pulls.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,21 @@ def review_comments(self, number=-1, etag=None):
408408
url = self._build_url('comments', base_url=self._api)
409409
return self._iter(int(number), url, ReviewComment, etag=etag)
410410

411+
def reviews(self, number=-1, etag=None):
412+
r"""Iterate over the reviews associated with this pull request.
413+
414+
:param int number: (optional), number of reviews to return. Default:
415+
-1 returns all available files.
416+
:param str etag: (optional), ETag from a previous request to the same
417+
endpoint
418+
:returns: generator of :class:`PullReview <PullReview>`\ s
419+
"""
420+
# Accept the preview headers for reviews
421+
headers = {'Accept': 'application/vnd.github.black-cat-preview+json'}
422+
url = self._build_url('reviews', base_url=self._api)
423+
return self._iter(int(number), url, PullReview, etag=etag,
424+
headers=headers)
425+
411426
@requires_auth
412427
8000 def update(self, title=None, body=None, state=None):
413428
"""Update this pull request.
@@ -430,6 +445,41 @@ def update(self, title=None, body=None, state=None):
430445
return False
431446

432447

448+
class PullReview(models.GitHubCore):
449+
450+
"""The :class:`PullReview <PullReview>` object.
451+
452+
See also: https://developer.github.com/v3/pulls/reviews/
453+
"""
454+
455+
def _update_attributes(self, preview):
456+
#: ID of the review
457+
self.id = self._get_attribute(preview, 'id')
458+
459+
#: SHA of the commit the review is on
460+
self.commit_id = self._get_attribute(preview, 'commit_id')
461+
462+
#: :class:`User <github3.users.User>` who made the comment
463+
self.user = self._class_attribute(preview, 'user', User, self)
464+
465+
#: State of the review
466+
self.state = self._get_attribute(preview, 'state')
467+
468+
#: datetime object representing when the event was created.
469+
self.created_at = self._strptime_attribute(preview, 'created_at')
470+
471+
#: Body text of the review
472+
self.body = self._get_attribute(preview, 'body')
473+
474+
#: API URL for the Pull Request
475+
self.pull_request_url = self._get_attribute(
476+
preview, 'pull_request_url'
477+
)
478+
479+
def _repr(self):
480+
return '<Pull Request Review [{0}]>'.format(self.id)
481+
482+
433483
class ReviewComment(models.BaseComment):
434484

435485
"""The :class:`ReviewComment <ReviewComment>` object.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"http_interactions": [{"recorded_at": "2017-01-26T21:20:01", "response": {"headers": {"ETag": "W/\"7471cf763435127e2b3ee39680a8d92a\"", "Transfer-Encoding": "chunked", "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload", "X-Served-By": "0e17b94a265a427d9cafe798ceea7c02", "Date": "Thu, 26 Jan 2017 21:19:58 GMT", "X-RateLimit-Reset": "1485468031", "Content-Type": "application/json; charset=utf-8", "X-XSS-Protection": "1; mode=block", "Access-Control-Expose-Headers": "ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval", "X-Content-Type-Options": "nosniff", "Content-Security-Policy": "default-src 'none'", "Access-Control-Allow-Origin": "*", "Status": "200 OK", "X-GitHub-Request-Id": "CC3D:6972:85BFE21:9F84A2A:588A67FE", "Cache-Control": "public, max-age=60, s-maxage=60", "Last-Modified": "Thu, 26 Jan 2017 19:58:51 GMT", "X-RateLimit-Remaining": "58", "X-Frame-Options": "deny", "Vary": "Accept", "Server": "GitHub.com", "X-RateLimit-Limit": "60", "X-GitHub-Media-Type": "github.v3; param=full; format=json", "Content-Encoding": "gzip"}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/671", "body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "status": {"message": "OK", "code": 200}}, "request": {"method": "GET", "headers": {"Accept-Charset": "utf-8", "Accept-Encoding": "gzip, deflate", "User-Agent": "github3.py/1.0.0a4", "Accept": "application/vnd.github.v3.full+json", "Connection": "keep-alive", "Content-Type": "application/json"}, "body": {"string": "", "encoding": "utf-8"}, "uri": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/671"}}, {"recorded_at": "2017-01-26T21:20:01", "response": {"headers": {"ETag": "W/\"a02d9791b92bad6db552e666d498f99c\"", "Transfer-Encoding": "chunked", "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload", "X-Served-By": "bae57931a6fe678a3dffe9be8e7819c8", "Date": "Thu, 26 Jan 2017 21:19:58 GMT", "X-RateLimit-Reset": "1485468031", "Content-Type": "application/json; charset=utf-8", "X-XSS-Protection": "1; mode=block", "Access-Control-Expose-Headers": "ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval", "X-Content-Type-Options": "nosniff", "Content-Security-Policy": "default-src 'none'", "Access-Control-Allow-Origin": "*", "Status": "200 OK", "X-GitHub-Request-Id": "CC3D:6972:85BFE54:9F84A57:588A67FE", "Cache-Control": "public, max-age=60, s-maxage=60", "X-RateLimit-Remaining": "57", "X-Frame-Options": "deny", "Vary": "Accept", "Server": "GitHub.com", "X-RateLimit-Limit": "60", "X-GitHub-Media-Type": "github.black-cat-preview; format=json", "Content-Encoding": "gzip"}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/671/reviews?per_page=100", "body": {"string": "", "base64_string": "H4sIAAAAAAAAA92WS4+bMBSF/wvdJgHzDEhVF+0sp91MN62qyIBD3PKqbYjSKP+915iMEmeSGUKk0cwqBHyOD9f3fuLn1qCpEaG57zsocCdGwwkzoq2RVxktjcjgNCtwS1nDbdeYdItt15o71sTALRaYLRqWw7qVEDWPTFPd5NYso2LVxNIuqUpBSjFLqsJsTKX+1H50wC5jvYn0NeCGZlbT3keJwYybWqKVKHItg9q6k2iLl1WeV2tw0VM/t5H5qISQ6pqW2ZUuoNyalVgRKB680k4WgnIxPFSn2pryZ0FT6cPhRBhJBwfrdRBrXUKirclIXXWGTcwTRmtBq3J4wCM1uFUswyX9h69zAzUHExlteJROBWrSQi8OlyvZ1qwZbXGykaVhJCG0hWJfaanpwVFsagJz8F3OIJSeCrLAaSHncIlzTnYTI67SjZoU6O6CymOHvz6JQytGxEqTgGDbIU7oeFZMktB1kyC1lgjFMUKeahAh9/j87f7+7uvD3Re49/IRglaTU+3M6o1ZN3lu+gH6IC8Y+dsQLhhpKVlP9zgBb/lw0T+93JXdAR0NrL4bl9uB5yKn5R8uKSWTd7+MLA8gdAYAut9z6aHeh/Gf2Agfc+Olr7ADZxgNOD8B7YMFRLctFEwtNLX9B+RHjhfZ8x/GbrLHc2AFPvJP8fzb5lUOJZFt4NmOPQ8ucxmd5bJSj+DyPsrlbtqvGkTiTnQ9gg/lY9irfEZBV1ncjra93yGkoRsGY1bZDOWrUg0Hq9Ldhqj7DEcoflcoVaP/VlHap38tlIaRG0SuhtIwDAGT+pcuFbwgBRYiWTVl1jM1cLw5suzLULXPQrWXj6DqSarLeD1ZPoizx+rrgfukzxjyaoajEKx53Y7FuvFYKGt+Q+msyYdjWjO4Da9PUr1ncEvQvF1wd+lfD9zePPIQfAP/+g8gGKPqpBAAAA==", "encoding": "utf-8"}, "status": {"message": "OK", "code": 200}}, "request": {"method": "GET", "headers": {"Accept-Charset": "utf-8", "Accept-Encoding": "gzip, deflate", "User-Agent": "github3.py/1.0.0a4", "Accept": "application/vnd.github.black-cat-preview+json", "Connection": "keep-alive", "Content-Type": "application/json"}, "body": {"string": "", "encoding": "utf-8"}, "uri": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/671/reviews?per_page=100"}}], "recorded_with": "betamax/0.8.0"}

tests/integration/test_pulls.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,14 @@ def test_patch(self):
106106
assert isinstance(patch, bytes)
107107
assert len(patch) > 0
108108

109+
def test_pull_reviews(self):
110+
"""Show that one can iterate over a PR's reviews."""
111+
cassette_name = self.cassette_name('pull_reviews')
112+
with self.recorder.use_cassette(cassette_name):
113+
p = self.get_pull_request(num=671)
114+
for pull_review in p.reviews():
115+
assert isinstance(pull_review, github3.pulls.PullReview)
116+
109117
def test_reopen(self):
110118
"""Show that one can reopen an open Pull Request."""
111119
self.basic_login()
@@ -139,6 +147,31 @@ def test_repository(self):
139147
assert p.repository == ('sigmavirus24', 'github3.py')
140148

141149

150+
class TestPullReview(IntegrationHelper):
151+
"""Integration tests for the PullFile object."""
152+
def get_pull_request_review(self, owner, repo, pull_number, review):
153+
p = self.gh.pull_request(owner, repo, pull_number)
154+
155+
for pull_review in p.reviews():
156+
if pull_review.id == review:
157+
break
158+
else:
159+
assert False, "Could not find '{0}'".format(review)
160+
161+
return pull_review
162+
163+
def test_user(self):
164+
"""Show that a user can retrieve the user of a PR review."""
165+
cassette_name = self.cassette_name('pull_reviews')
166+
with self.recorder.use_cassette(cassette_name):
167+
pull_review = self.get_pull_request_review(
168+
owner='sigmavirus24', repo='github3.py', pull_number=671,
169+
review=18663174
170+
)
171+
user = pull_review.user
172+
assert isinstance(user, github3.users.User)
173+
174+
142175
class TestReviewComment(IntegrationHelper):
143176

144177
"""Integration tests for the ReviewComment object."""

tests/unit/test_pulls.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,17 @@ def test_review_comments(self):
228228
headers={}
229229
)
230230

231+
def test_reviews(self):
232+
"""Show that a user can retrieve the reviews from a Pull Request."""
233+
i = self.instance.reviews()
234+
self.get_next(i)
235+
236+
self.session.get.assert_called_once_with(
237+
url_for('reviews'),
238+
params={'per_page': 100},
239+
headers={'Accept': 'application/vnd.github.black-cat-preview+json'}
240+
)
241+
231242

232243
class TestReviewComment(helper.UnitHelper):
233244
"""Unit tests for the ReviewComment class."""

0 commit comments

Comments
 (0)
0