Skip to content

Commit c7c88ba

Browse files
authored
Also find PRs from check_suite. (#46)
1 parent d4d966c commit c7c88ba

File tree

5 files changed

+322
-34
lines changed

5 files changed

+322
-34
lines changed

pydocteur/github_api.py

Lines changed: 21 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,14 @@
22

33
import requests
44
from requests.auth import HTTPBasicAuth
5-
from github import GithubException
65
from github import Github
76

87
from pydocteur.settings import GH_TOKEN
98
from pydocteur.settings import GH_USERNAME
109
from pydocteur.settings import REPOSITORY_NAME
1110

1211
logger = logging.getLogger("pydocteur")
13-
gh = Github(GH_TOKEN)
12+
gh = Github(GH_TOKEN if GH_TOKEN else None)
1413

1514

1615
def get_rest_api(url: str) -> requests.Response:
@@ -24,37 +23,31 @@ def get_graphql_api(query: str) -> requests.Response:
2423
return resp
2524

2625

26+
def get_pull_request_from_checks(commit_sha):
27+
prs_for_commit = gh.search_issues(f"type:pr repo:{REPOSITORY_NAME} sha:{commit_sha}")
28+
if prs_for_commit.totalCount != 1:
29+
logger.error("Should be exactly one PR for this sha: %s, found %s", commit_sha, prs_for_commit.totalCount)
30+
return prs_for_commit[0]
31+
32+
2733
def get_pull_request(payload):
28-
logger.debug("Getting repository")
2934
gh_repo = gh.get_repo(REPOSITORY_NAME)
30-
logger.info("Trying to find PR number from payload")
35+
logger.info("Trying to find PR from %s", payload.get("action", "A payload with: " + ", ".join(payload.keys())))
3136

32-
is_run = payload.get("check_run", False)
33-
is_suite = payload.get("check_suite", False)
37+
head_sha = payload.get("check_suite", {}).get("head_sha")
38+
if head_sha:
39+
return get_pull_request_from_checks(head_sha)
3440

35-
if is_run or is_suite:
36-
logger.info("Payload is from checks, ignoring")
37-
return None
41+
pr_number = payload.get("pull_request", {}).get("number")
42+
if pr_number:
43+
return gh_repo.get_pull(pr_number)
3844

39-
try:
40-
try:
41-
pr_number = payload["pull_request"]["number"]
42-
logger.debug(f"Found PR {pr_number} first try")
43-
except KeyError:
44-
issue_number = payload["issue"]["number"]
45-
logger.debug(f"Found issue {issue_number} from payload")
46-
try:
47-
repo = gh_repo.get_pull(issue_number)
48-
logger.info(f"Found PR #{repo.number}")
49-
return repo
50-
except GithubException:
51-
logger.debug(f"Found issue {issue_number}, returning None")
52-
return None
53-
except Exception: # noqa
54-
logger.warning("Unknown payload, returning None")
55-
logger.debug(payload)
56-
return None
57-
return gh_repo.get_pull(pr_number)
45+
issue_number = payload.get("issue", {}).get("number")
46+
if issue_number:
47+
return gh_repo.get_pull(issue_number)
48+
49+
logger.warning("Unknown payload, (action: %s)", payload.get("action", ""))
50+
return None
5851

5952

6053
def get_trad_team_members() -> set:

pydocteur/pr_status.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,14 @@ def sort_reviews_key(review):
4848
return review.user.login, review.submitted_at
4949

5050
last_reviews = []
51-
for author, reviews in groupby(sorted(pr_reviews, key=sort_reviews_key), key=lambda review: review.user.login):
51+
for _, reviews in groupby(sorted(pr_reviews, key=sort_reviews_key), key=lambda review: review.user.login):
5252
last_reviews.append(list(reviews)[-1])
5353
is_approved = all(review.state == "APPROVED" for review in last_reviews)
5454
logger.info(
55-
f"is_approved for PR #{pr.number} is {is_approved}: "
56-
+ ", ".join(f"{review.user.login} has {review.state}" for review in last_reviews)
55+
"is_pr_approved(%s): %s (%s)",
56+
pr.number,
57+
is_approved,
58+
", ".join(f"{review.user.login} has {review.state}" for review in last_reviews),
5759
)
5860
return is_approved
5961

Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
interactions:
2+
- request:
3+
body: null
4+
headers:
5+
Accept:
6+
- '*/*'
7+
Accept-Encoding:
8+
- gzip, deflate
9+
Connection:
10+
- keep-alive
11+
User-Agent:
12+
- PyGithub/Python
13+
method: GET
14+
uri: https://api.github.com/repos/python/python-docs-fr
15+
response:
16+
body:
17+
string: !!binary |
18+
H4sIAAAAAAAAA+1Y32/iOBD+Vyper2AIzbZEqvYqbbe6k1rudru6VV+Qkxji4sSR7cBB1P/9xnZ+
19+
Qe+g1A/30pcWjL/Pnyczk5kpezTuBRNvOLn0x/55L+Mxmeml3v2X2/WU/c6iu8kW//y2irKlf/98
20+
4z9sf2wf/ry+7sFmnBLYmW9UwrN+zCPZnwtYnxeMzXZ+RK/25IKusAL4HDNJznt8nRHRC8oe4wua
21+
NazAptWMfM+fXI329G2my8nmyfta4J95Et+xVfh8O7p//uFPv9xqfRhOwGJWCAZ8iVK5DBCyi3I8
22+
WFCVFGEhiYh4pkimBhFPUYGqsz6vri+AYyEqFmMUWNhjy2lFZNHAJqvLwt5EpWzveHuq2Wxtou3F
23+
GeNrQO5L/W9y1GAaPM0WJ+MBUyKuEgJWAukv+sJUqlOEmP0l0v/AcTSDBKMLEp8gpkKAFO0FLyUS
24+
JOeGqghlJGiuKM9OEbWDAx4uFjijW3wqD+AkwLWcU443+wFHVuBWpwAtoEQmOqKNNoEgEaErMOfJ
25+
ZHtI4FKbXAfstGMNbWSqyAzHqQ47E40vb/Pc10Edk+ZpwTFfBcmi5EwJnElmTH/G52fgbGd/mIxx
26+
BhmjSMFC5rcBKJlzsWwywsFAMxauBLzWoXmOmP0AAcQWwEHOkmwcWDS6RPC3CosIohyHXGDFj0X6
27+
IXE7NCXqftXuoghOHUQbONAknLtY0MCBhkpZkDd57qErGxaJ6uDIijS0ueotIXGI2OJBJ5aSLjJC
28+
HCzXUJSoTqUheH6UuJDWDCWyn8wTxgsHmRoNJCHjoQMLvMWQoSiRTLB9baiZmzLNqRl2KAWZO8rU
29+
DA2lEk7P2EjUFA0hvLkUPG4HjTUDKitLMpwtCrxw4Wwo4Enrd+sCb49WF4fipOUAQl0tCRoWrmms
30+
ZdEq7Yse4trFlC1JS2lqh8O1yMGrdyoQc/k0pcde6Yf4KoIdJ3cm1X65T6y/H68+jknVDCVqM65N
31+
6BX3+61aZfRaY/eEqhh3cIOaAZW/5FglOjvBQTkW5P2CKwJUhhjqo8FgUCYEm2o3JcIpVi0eiLCI
32+
Eij03q+xrBmgfkmxMmX0XEuMoaxmHMcONm0ogM4+vPfrtPjuM8+hYXQQZ+BdvpQyIhXPXHJoy9Fl
33+
zriicxq9pZE4FFo7NOVnSbOInGPGzsFLFY0o+C20ZvrZQclIXGxj8XAF6NVtO8EIuLCDtQWxDCWy
34+
7V5McsY3jrmmQ6LDVRCYDcQzrKCN8Iajy/7Q73veozcMLoaBf/UEe4o87u7xhv2R1x96jyM/GF0G
35+
F5d6T17IpKVpt3wKhsPAMzSQOitPhk8wHnjVn+91F7rbB5iUSQv7tQUFtqn/d1DEwCX34uat5632
36+
32HHgCAy4SnJoZLoTD/0kGZgNQ6guUVzgfRt6BY2jf1PV+OdgiHiRQaPYOzB8horqGXh9dxdrAsN
37+
OOEeL8kc4k6fi+XMBnkvUKKA6Y5eyQV/JpGS3bU2rXQ2rumS7gB1MdS0hba3q0R4Y5gJpVQIXo15
38+
MkgFTSqFiU01XYqpxCEj7QLPSVZprC/kAxWjEckk2KLUzR/cysxG4ErVNGtafZV5/Lcdkz1Mb75/
39+
v/32+Nv0QTulHjVZDd1JWvTp8Y49P/3lb58eb6570F/bFjMw+jtaeoFWUZu6snxM5rhgamZbABA1
40+
HkzgLEXSfGZdSvElgebdHtyddXwM1HZnfx8DtY+B2v8zUMuIWsNYqU42JvC7TU+dVUcv/wAuj38g
41+
kxcAAA==
42+
headers:
43+
Accept-Ranges:
44+
- bytes
45+
Content-Length:
46+
- '1315'
47+
X-GitHub-Request-Id:
48+
- 998E:DAEA:42E9D86:4D53DD3:5FC7BDEC
49+
X-Ratelimit-Limit:
50+
- '60'
51+
X-Ratelimit-Remaining:
52+
- '57'
53+
X-Ratelimit-Reset:
54+
- '1606929236'
55+
X-Ratelimit-Used:
56+
- '3'
57+
access-control-allow-origin:
58+
- '*'
59+
access-control-expose-headers:
60+
- ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining,
61+
X-RateLimit-Used, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes,
62+
X-Poll-Interval, X-GitHub-Media-Type, Deprecation, Sunset
63+
cache-control:
64+
- public, max-age=60, s-maxage=60
65+
content-encoding:
66+
- gzip
67+
content-security-policy:
68+
- default-src 'none'
69+
content-type:
70+
- application/json; charset=utf-8
71+
date:
72+
- Wed, 02 Dec 2020 16:16:44 GMT
73+
etag:
74+
- W/"24d977b9e4582f04b3f9ae01a0d39a62359d71ace777aa7e07d8cd5eaeaedef4"
75+
last-modified:
76+
- Wed, 02 Dec 2020 15:17:47 GMT
77+
referrer-policy:
78+
- origin-when-cross-origin, strict-origin-when-cross-origin
79+
server:
80+
- GitHub.com
81+
status:
82+
- 200 OK
83+
strict-transport-security:
84+
- max-age=31536000; includeSubdomains; preload
85+
vary:
86+
- Accept, Accept-Encoding, Accept, X-Requested-With, Accept-Encoding
87+
x-content-type-options:
88+
- nosniff
89+
x-frame-options:
90+
- deny
91+
x-github-media-type:
92+
- github.v3; format=json
93+
x-xss-protection:
94+
- 1; mode=block
95+
status:
96+
code: 200
97+
message: OK
98+
- request:
99+
body: null
100+
headers:
101+
Accept:
102+
- '*/*'
103+
Accept-Encoding:
104+
- gzip, deflate
105+
Connection:
106+
- keep-alive
107+
User-Agent:
108+
- PyGithub/Python
109+
method: GET
110+
uri: https://api.github.com/search/issues?q=type%3Apr+repo%3Apython%2Fpython-docs-fr+sha%3A390a392633a4692ee96ebd8d122cfdcd602224e0&per_page=1
111+
response:
112+
body:
113+
string: !!binary |
114+
H4sIAAAAAAAAA61V227jNhD9FYELv8UWJd8SAUWRvWSxD3barNKmWSwEWhrJTChSS1JOHMO/sa99
115+
6Qf2EzqUL3WMhbdx90k2OefMcDg8Z0GsskwkqaqlJVFwQrhMVVkJsJBoMLWwhkQ5EwZwy0KJ/z4t
116+
SK0FicjU2spEvs8q3im4ndaTDmJ9DZUyfjW3UyXXn3amUtPOtc+NqcH4QW8QkBPSRHKr9Dw5lhFZ
117+
BJuAMEcz7Nbkr7gWvmQlLJEbz1OCtD+IfcOGxDD7cbQrLiSd2lLs9WHnXr59I1UtxOY+eEaiYdjv
118+
DU77Yf+ESJVB4tbI6O27x0vxOpi8f/x4e3MR3N6M6Tg+D8d3993R0/0T5pZ1OQGNI4RXe0IstwIQ
119+
GGuW1anlSnoZeDn74hcgQTPRqRSCauMgCyJUwaXLw2XGQQjccnkHQUj7/dPweSm/Dn67GYv07o/H
120+
0d15MI6LOYazGbNM7w9Bs2i66+l02VIlLXa+GdTa3yT4efZTD0kKvaZpDu3qOzTnjs74OyUfbv9O
121+
YK6EUA+I3q/3+UN6nsDforCw1W8uiyMYELXwlZ0CtguP4Ma84OZ7M75XTINY+O6DI+I4DLZaQ/ai
122+
gtYYLOcBp2K5aLSjIasnJtW8cpPzsi49QyKT0gWT/Im9nAmRBgkakXrRqRoEIv/LG99r6wqy8CvN
123+
Zyydu1ZoSIHPsLFH0O1hkc3OK/cur93DwzajpCcsK93ja0R+uZHTRubdMwj73dMgHJ7RPUG4HsTv
124+
L/jt7w/zcTzqjeIP3cv43In6wTdzyBtW2uu3Lmjr7KJ13mudDVohZbVVJegCkNqpMhb/959/ffV2
125+
11MlFOoIoXQwGfYxMIOcoXVtnSuD7TQ5UZqC98uV98CF8CbQMHlNiowsPzeDbF0aVYFELqHSe9zZ
126+
mCAzhhcSMECicqLwrP87Y0RwyQUYq+R2f6v50RDtRANyZwnD0khIQ9oOaDukcRBEtBt1+7euf1W2
127+
HxO2aRgHg4jSKBy6mFQos6ZZV1Gj2+oEi1Epb2YdE7y5HMdXH15fx5dXiGEowzNI3HHQ2ZlxIStw
128+
pln+b6+cIWDAF/RpXPwfXu+ItlZ/WBu/b00Zz/Ojra3j0NiCitl0ejxLAyf4RCYqm7v+ulsw3iu0
129+
POo5etC50iVezIyzZOW8CauqTZ9NqjTORdChy8/LfwBesmWBegkAAA==
130+
headers:
131+
Accept-Ranges:
132+
- bytes
133+
Transfer-Encoding:
134+
- chunked
135+
X-GitHub-Request-Id:
136+
- 998E:DAEA:42E9DD5:4D53E2C:5FC7BDEC
137+
X-Ratelimit-Limit:
138+
- '10'
139+
X-Ratelimit-Remaining:
140+
- '8'
141+
X-Ratelimit-Reset:
142+
- '1606925835'
143+
X-Ratelimit-Used:
144+
- '2'
145+
access-control-allow-origin:
146+
- '*'
147+
access-control-expose-headers:
148+
- ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining,
149+
X-RateLimit-Used, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes,
150+
X-Poll-Interval, X-GitHub-Media-Type, Deprecation, Sunset
151+
cache-control:
152+
- no-cache
153+
content-encoding:
154+
- gzip
155+
content-security-policy:
156+
- default-src 'none'
157+
content-type:
158+
- application/json; charset=utf-8
159+
date:
160+
- Wed, 02 Dec 2020 16:16:44 GMT
161+
referrer-policy:
162+
- origin-when-cross-origin, strict-origin-when-cross-origin
163+
server:
164+
- GitHub.com
165+
status:
166+
- 200 OK
167+
strict-transport-security:
168+
- max-age=31536000; includeSubdomains; preload
169+
vary:
170+
- Accept, Accept-Encoding, Accept, X-Requested-With, Accept-Encoding
171+
x-content-type-options:
172+
- nosniff
173+
x-frame-options:
174+
- deny
175+
x-github-media-type:
176+
- github.v3; format=json
177+
x-xss-protection:
178+
- 1; mode=block
179+
status:
180+
code: 200
181+
message: OK
182+
- request:
183+
body: null
184+
headers:
185+
Accept:
186+
- '*/*'
187+
Accept-Encoding:
188+
- gzip, deflate
189+
Connection:
190+
- keep-alive
191+
User-Agent:
192+
- PyGithub/Python
193+
method: GET
194+
uri: https://api.github.com/search/issues?q=type%3Apr+repo%3Apython%2Fpython-docs-fr+sha%3A390a392633a4692ee96ebd8d122cfdcd602224e0
195+
response:
196+
body:
197+
string: !!binary |
198+
H4sIAAAAAAAAA61V227jNhD9FYELv8UWJd8SAUWRvWSxD3barNKmWSwEWhrJTChSS1JOHMO/sa99
199+
6Qf2EzqUL3WMhbdx90k2OefMcDg8Z0GsskwkqaqlJVFwQrhMVVkJsJBoMLWwhkQ5EwZwy0KJ/z4t
200+
SK0FicjU2spEvs8q3im4ndaTDmJ9DZUyfjW3UyXXn3amUtPOtc+NqcH4QW8QkBPSRHKr9Dw5lhFZ
201+
BJuAMEcz7Nbkr7gWvmQlLJEbz1OCtD+IfcOGxDD7cbQrLiSd2lLs9WHnXr59I1UtxOY+eEaiYdjv
202+
DU77Yf+ESJVB4tbI6O27x0vxOpi8f/x4e3MR3N6M6Tg+D8d3993R0/0T5pZ1OQGNI4RXe0IstwIQ
203+
GGuW1anlSnoZeDn74hcgQTPRqRSCauMgCyJUwaXLw2XGQQjccnkHQUj7/dPweSm/Dn67GYv07o/H
204+
0d15MI6LOYazGbNM7w9Bs2i66+l02VIlLXa+GdTa3yT4efZTD0kKvaZpDu3qOzTnjs74OyUfbv9O
205+
YK6EUA+I3q/3+UN6nsDforCw1W8uiyMYELXwlZ0CtguP4Ma84OZ7M75XTINY+O6DI+I4DLZaQ/ai
206+
gtYYLOcBp2K5aLSjIasnJtW8cpPzsi49QyKT0gWT/Im9nAmRBgkakXrRqRoEIv/LG99r6wqy8CvN
207+
Zyydu1ZoSIHPsLFH0O1hkc3OK/cur93DwzajpCcsK93ja0R+uZHTRubdMwj73dMgHJ7RPUG4HsTv
208+
L/jt7w/zcTzqjeIP3cv43In6wTdzyBtW2uu3Lmjr7KJ13mudDVohZbVVJegCkNqpMhb/959/ffV2
209+
11MlFOoIoXQwGfYxMIOcoXVtnSuD7TQ5UZqC98uV98CF8CbQMHlNiowsPzeDbF0aVYFELqHSe9zZ
210+
mCAzhhcSMECicqLwrP87Y0RwyQUYq+R2f6v50RDtRANyZwnD0khIQ9oOaDukcRBEtBt1+7euf1W2
211+
HxO2aRgHg4jSKBy6mFQos6ZZV1Gj2+oEi1Epb2YdE7y5HMdXH15fx5dXiGEowzNI3HHQ2ZlxIStw
212+
pln+b6+cIWDAF/RpXPwfXu+ItlZ/WBu/b00Zz/Ojra3j0NiCitl0ejxLAyf4RCYqm7v+ulsw3iu0
213+
POo5etC50iVezIyzZOW8CauqTZ9NqjTORdChy8/LfwBesmWBegkAAA==
214+
headers:
215+
Accept-Ranges:
216+
- bytes
217+
Transfer-Encoding:
218+
- chunked
219+
X-GitHub-Request-Id:
220+
- 998E:DAEA:42E9E4A:4D53EB6:5FC7BDEC
221+
X-Ratelimit-Limit:
222+
- '10'
223+
X-Ratelimit-Remaining:
224+
- '7'
225+
X-Ratelimit-Reset:
226+
- '1606925835'
227+
X-Ratelimit-Used:
228+
- '3'
229+
access-control-allow-origin:
230+
- '*'
231+
access-control-expose-headers:
232+
- ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining,
233+
X-RateLimit-Used, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes,
234+
X-Poll-Interval, X-GitHub-Media-Type, Deprecation, Sunset
235+
cache-control:
236+
- no-cache
237+
content-encoding:
238+
- gzip
239+
content-security-policy:
240+
- default-src 'none'
241+
content-type:
242+
- application/json; charset=utf-8
243+
date:
244+
- Wed, 02 Dec 2020 16:16:45 GMT
245+
referrer-policy:
246+
- origin-when-cross-origin, strict-origin-when-cross-origin
247+
server:
248+
- GitHub.com
249+
status:
250+
- 200 OK
251+
strict-transport-security:
252+
- max-age=31536000; includeSubdomains; preload
253+
vary:
254+
- Accept, Accept-Encoding, Accept, X-Requested-With, Accept-Encoding
255+
x-content-type-options:
256+
- nosniff
257+
x-frame-options:
258+
- deny
259+
x-github-media-type:
260+
- github.v3; format=json
261+
x-xss-protection:
262+
- 1; mode=block
263+
status:
264+
code: 200
265+
message: OK
266+
version: 1

tests/conftest.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import os
22

3-
os.environ["GH_TOKEN"] = "dummy"
4-
os.environ["REPOSITORY_NAME"] = "dummy"
5-
os.environ["GH_USERNAME"] = "dummy"
3+
os.environ["GH_TOKEN"] = ""
4+
os.environ["REPOSITORY_NAME"] = "python/python-docs-fr"
5+
os.environ["GH_USERNAME"] = "PyDocTeur"

tests/test_find_pr.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import pytest
2+
from pydocteur.github_api import get_pull_request
3+
4+
5+
@pytest.mark.vcr()
6+
def test_get_pr_from_check_suite():
7+
payload = {
8+
"action": "completed",
9+
"check_suite": {
10+
"id": 1487327954,
11+
"node_id": "MDg6Q2hlY2tSdW4xNDg3MzI3OTU0",
12+
"head_sha": "390a392633a4692ee96ebd8d122cfdcd602224e0",
13+
"external_id": "d133e080-687a-5f71-4d25-419e05f66c84",
14+
"url": "https://api.github.com/repos/python/python-docs-fr/check-runs/1487327954",
15+
"html_url": "https://github.com/python/python-docs-fr/runs/1487327954",
16+
"details_url": "https://github.com/python/python-docs-fr/runs/1487327954",
17+
"status": "completed",
18+
"conclusion": "success",
19+
"started_at": "2020-12-02T16:00:51Z",
20+
"completed_at": "2020-12-02T16:05:22Z",
21+
"output": {
22+
"annotations_count": 0,
23+
},
24+
},
25+
}
26+
pr = get_pull_request(payload)
27+
assert pr.number == 1461

0 commit comments

Comments
 (0)