Skip to content

Commit 4923dc7

Browse files
authored
Merge pull request #113 from bwrsandman/authenticated-requests
Use PyGithub to reuse auth headers to do requests
2 parents f527341 + baadf42 commit 4923dc7

File tree

2 files changed

+68
-95
lines changed

2 files changed

+68
-95
lines changed

Diff for: post/clang_tidy_review/clang_tidy_review/__init__.py

+68-94
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
from operator import itemgetter
1313
import pprint
1414
import pathlib
15-
import requests
1615
import subprocess
1716
import textwrap
1817
import unidiff
@@ -23,6 +22,7 @@
2322
import io
2423
import zipfile
2524
from github import Github, Auth
25+
from github.GithubException import GithubException
2626
from github.Requester import Requester
2727
from github.PaginatedList import PaginatedList
2828
from github.WorkflowRun import WorkflowRun
@@ -60,6 +60,44 @@ class PRReview(TypedDict):
6060
comments: List[PRReviewComment]
6161

6262

63+
class HashableComment:
64+
def __init__(self, body: str, line: int, path: str, side: str, **kwargs):
65+
self.body = body
66+
self.line = line
67+
self.path = path
68+
self.side = side
69+
70+
def __hash__(self):
71+
return hash(
72+
(
73+
self.body,
74+
self.line,
75+
self.path,
76+
self.side,
77+
)
78+
)
79+
80+
def __eq__(self, other):
81+
return (
82+
type(self) is type(other)
83+
and self.body == other.body
84+
and self.line == self.line
85+
and other.path == other.path
86+
and self.side == other.side
87+
)
88+
89+
def __lt__(self, other):
90+
if self.path != other.path:
91+
return self.path < other.path
92+
if self.line != other.line:
93+
return self.line < other.line
94+
if self.side != other.side:
95+
return self.side < other.side
96+
if self.body != other.body:
97+
return self.body < other.body
98+
return id(self) < id(other)
99+
100+
63101
def add_auth_arguments(parser: argparse.ArgumentParser):
64102
# Token
65103
parser.add_argument("--token", help="github auth token")
@@ -247,26 +285,15 @@ def pull_request(self):
247285
self._pull_request = self.repo.get_pull(int(self.pr_number))
248286
return self._pull_request
249287

250-
def headers(self, media_type: str):
251-
return {
252-
"Accept": f"application/vnd.github.{media_type}",
253-
"Authorization": f"token {self.token}",
254-
}
255-
256-
@property
257-
def base_url(self):
258-
return f"{self.api_url}/repos/{self.repo_name}/pulls/{self.pr_number}"
259-
260-
def get(self, media_type: str, extra: str = "") -> str:
261-
url = f"{self.base_url}{extra}"
262-
response = requests.get(url, headers=self.headers(media_type))
263-
response.raise_for_status()
264-
return response.text
265-
266288
def get_pr_diff(self) -> List[unidiff.PatchSet]:
267289
"""Download the PR diff, return a list of PatchedFile"""
268290

269-
diffs = self.get("v3.diff")
291+
_, data = self.repo._requester.requestJsonAndCheck(
292+
"GET",
293+
self.pull_request.url,
294+
headers={"Accept": f"application/vnd.github.{'v3.diff'}"},
295+
)
296+
diffs = data["data"]
270297

271298
# PatchSet is the easiest way to construct what we want, but the
272299
# diff_line_no property on lines is counted from the top of the
@@ -292,7 +319,7 @@ def get_element(
292319
return PaginatedList(
293320
get_element,
294321
self.pull_request._requester,
295-
f"{self.base_url}/comments",
322+
self.pull_request.review_comments_url,
296323
None,
297324
)
298325

@@ -311,33 +338,9 @@ def post_lgtm_comment(self, body: str):
311338

312339
self.pull_request.create_issue_comment(body)
313340

314-
def post_review(self, review):
341+
def post_review(self, review: PRReview):
315342
"""Submit a completed review"""
316-
headers = {
317-
"Accept": "application/vnd.github.comfort-fade-preview+json",
318-
"Authorization": f"token {self.token}",
319-
}
320-
url = f"{self.base_url}/reviews"
321-
322-
post_review_response = requests.post(url, json=review, headers=headers)
323-
print(post_review_response.text)
324-
try:
325-
post_review_response.raise_for_status()
326-
except requests.exceptions.HTTPError as e:
327-
if e.response.status_code == 403:
328-
print(
329-
"::error title=Missing permissions::This workflow does not have "
330-
"enough permissions to submit a review. This could be because "
331-
"the GitHub token specified for this workflow is invalid or "
332-
"missing permissions, or it could be because this pull request "
333-
"comes from a fork which reduces the default token permissions. "
334-
"To support forked workflows, see the "
335-
"https://github.com/ZedThree/clang-tidy-review#usage-in-fork-environments "
336-
"instructions"
337-
)
338-
339-
# Re-raise the exception, causing an error in the workflow
340-
raise e
343+
self.pull_request.create_review(**review)
341344

342345
def post_annotations(self, review):
343346
headers = {
@@ -346,8 +349,9 @@ def post_annotations(self, review):
346349
}
347350
url = f"{self.api_url}/repos/{self.repo_name}/check-runs"
348351

349-
response = requests.post(url, json=review, headers=headers)
350-
response.raise_for_status()
352+
self.repo._requester.requestJsonAndCheck(
353+
"POST", url, parameters=review, headers=headers
354+
)
351355

352356

353357
@contextlib.contextmanager
@@ -920,14 +924,17 @@ def download_artifacts(pull: PullRequest, workflow_id: int):
920924
)
921925
return None, None
922926

923-
r = requests.get(artifact.archive_download_url, headers=pull.headers("json"))
924-
if not r.ok:
927+
try:
928+
_, data = pull.repo._requester.requestJsonAndCheck(
929+
"GET", artifact.archive_download_url, headers=pull.headers("json")
930+
)
931+
except GithubException as exc:
925932
print(
926-
f"WARNING: Couldn't automatically download artifacts for workflow '{workflow_id}', response was: {r}: {r.reason}"
933+
f"WARNING: Couldn't automatically download artifacts for workflow '{workflow_id}', response was: {exc}"
927934
)
928935
return None, None
929936

930-
contents = b"".join(r.iter_content())
937+
contents = b"".join(data["data"].iter_content())
931938

932939
data = zipfile.ZipFile(io.BytesIO(contents))
933940
filenames = data.namelist()
@@ -983,39 +990,11 @@ def load_and_merge_reviews(review_files: List[pathlib.Path]) -> Optional[PRRevie
983990

984991
result = reviews[0]
985992

986-
class Comment:
987-
def __init__(self, data):
988-
self.data = data
989-
990-
def __hash__(self):
991-
return hash(
992-
(
993-
self.data["body"],
994-
self.data["line"],
995-
self.data["path"],
996-
self.data["side"],
997-
)
998-
)
999-
1000-
def __eq__(self, other):
1001-
return type(other) is Comment and self.data == other.data
1002-
1003-
def __lt__(self, other):
1004-
if self.data["path"] != other.data["path"]:
1005-
return self.data["path"] < other.data["path"]
1006-
if self.data["line"] != other.data["line"]:
1007-
return self.data["line"] < other.data["line"]
1008-
if self.data["side"] != other.data["side"]:
1009-
return self.data["side"] < other.data["side"]
1010-
if self.data["body"] != other.data["body"]:
1011-
return self.data["body"] < other.data["body"]
1012-
return hash(self) < hash(other)
1013-
1014993
comments = set()
1015994
for review in reviews:
1016-
comments.update(map(Comment, review["comments"]))
995+
comments.update(map(lambda c: HashableComment(**c), review["comments"]))
1017996

1018-
result["comments"] = [c.data for c in sorted(comments)]
997+
result["comments"] = [c.__dict__ for c in sorted(comments)]
1019998

1020999
return result
10211000

@@ -1063,19 +1042,14 @@ def cull_comments(pull_request: PullRequest, review, max_comments):
10631042
10641043
"""
10651044

1066-
comments = pull_request.get_pr_comments()
1067-
1068-
for comment in comments:
1069-
review["comments"] = list(
1070-
filter(
1071-
lambda review_comment: not (
1072-
review_comment["path"] == comment["path"]
1073-
and review_comment["line"] == comment["line"]
1074-
and review_comment["body"] == comment["body"]
1075-
),
1076-
review["comments"],
1077-
)
1078-
)
1045+
unposted_comments = set(map(lambda c: HashableComment(**c), review["comments"]))
1046+
posted_comments = set(
1047+
map(lambda c: HashableComment(**c), pull_request.get_pr_comments())
1048+
)
1049+
1050+
review["comments"] = [
1051+
c.__dict__ for c in sorted(unposted_comments - posted_comments)
1052+
]
10791053

10801054
if len(review["comments"]) > max_comments:
10811055
review["body"] += (

Diff for: post/clang_tidy_review/pyproject.toml

-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ license = {text = "MIT"}
1515
dependencies = [
1616
"PyGithub ~= 2.1",
1717
"unidiff ~= 0.6.0",
18-
"requests ~= 2.23",
1918
"pyyaml ~= 6.0.1",
2019
]
2120
keywords = ["C++", "static-analysis"]

0 commit comments

Comments
 (0)