|
10 | 10 | what each phase cost - only the two runs it is given come from two branches. |
11 | 11 | """ |
12 | 12 |
|
13 | | -import argparse, codecs, datetime, html, os, re, time |
| 13 | +import argparse, codecs, datetime, html, json, os, re, subprocess, time |
| 14 | +import urllib.error, urllib.request |
14 | 15 | import shared, resultsdb |
15 | 16 | from omcommon import friendlyStr, multiple_replace |
16 | 17 |
|
|
24 | 25 | parser.add_argument('--historypath', default="history") |
25 | 26 | parser.add_argument('--githuburl', default="https://github.com/OpenModelica/OpenModelica") |
26 | 27 | parser.add_argument('--markdown', default="", help='where to write the summary to comment on the pull request with (default: <historypath>/<branch>/00_comment.md)') |
| 28 | +parser.add_argument('--comment', action='store_true', help='post that summary on the pull request, replacing the one posted by an earlier run') |
27 | 29 | resultsdb.addArgument(parser) |
28 | 30 | args = parser.parse_args() |
29 | 31 |
|
|
45 | 47 | branch = "pr-%s" % pr |
46 | 48 | baseline = args.baseline.split("/")[-1] |
47 | 49 | prurl = "%s/pull/%s" % (args.githuburl, pr) |
| 50 | +repo = args.githuburl.split("github.com/")[-1].strip("/") |
48 | 51 |
|
49 | 52 | db = resultsdb.connect(args.db) |
50 | 53 | cursor = db.cursor() |
@@ -213,6 +216,54 @@ def classify(group, times): |
213 | 216 | return (colour, " ".join(msgs), |
214 | 217 | "performance improved" if colour == "betterPerformance" else "performance regression") |
215 | 218 |
|
| 219 | +# A run of the same pull request replaces the comment of the one before it |
| 220 | +# rather than adding to a pile; this is how it recognises its own. |
| 221 | +COMMENTMARKER = "<!-- openmodelica-library-testing: pull request report -->" |
| 222 | + |
| 223 | +def githubToken(): |
| 224 | + """A token to post with: the environment, or whoever gh is logged in as.""" |
| 225 | + for var in ["GITHUB_TOKEN", "GH_TOKEN"]: |
| 226 | + if os.environ.get(var): |
| 227 | + return os.environ[var] |
| 228 | + try: |
| 229 | + return subprocess.check_output(["gh", "auth", "token"], |
| 230 | + stderr=subprocess.DEVNULL).decode("utf-8").strip() |
| 231 | + except Exception: |
| 232 | + return None |
| 233 | + |
| 234 | +def github(url, token, data=None, method=None): |
| 235 | + request = urllib.request.Request( |
| 236 | + url, method=method, |
| 237 | + data=json.dumps(data).encode("utf-8") if data is not None else None, |
| 238 | + headers={"Accept": "application/vnd.github+json", |
| 239 | + "Authorization": "Bearer %s" % token, |
| 240 | + "Content-Type": "application/json"}) |
| 241 | + return json.loads(urllib.request.urlopen(request).read().decode("utf-8")) |
| 242 | + |
| 243 | +def postComment(number, body): |
| 244 | + """Post the summary on the pull request, or update the one already there.""" |
| 245 | + token = githubToken() |
| 246 | + if not token: |
| 247 | + return ("No token to comment with: set GITHUB_TOKEN, or log in with gh. " |
| 248 | + "The comment is in %s." % markdownname) |
| 249 | + api = "https://api.github.com/repos/%s/issues" % repo |
| 250 | + try: |
| 251 | + page = 1 |
| 252 | + while True: |
| 253 | + comments = github("%s/%s/comments?per_page=100&page=%d" % (api, number, page), token) |
| 254 | + for comment in comments: |
| 255 | + if COMMENTMARKER in (comment.get("body") or ""): |
| 256 | + github(comment["url"], token, {"body": body}, method="PATCH") |
| 257 | + return "Updated %s" % comment["html_url"] |
| 258 | + if len(comments) < 100: |
| 259 | + break |
| 260 | + page += 1 |
| 261 | + return "Commented on %s" % github("%s/%s/comments" % (api, number), token, |
| 262 | + {"body": body})["html_url"] |
| 263 | + except urllib.error.HTTPError as e: |
| 264 | + raise SystemExit("Could not comment on %s#%s: %s\n%s" |
| 265 | + % (repo, number, e, e.read().decode("utf-8", "replace"))) |
| 266 | + |
216 | 267 | counts = {"improved": 0, "regression": 0, "performance improved": 0, "performance regression": 0} |
217 | 268 | rows = [] |
218 | 269 | markdownrows = [] |
@@ -337,8 +388,12 @@ def classify(group, times): |
337 | 388 | markdown += ["- %s" % c.replace("→", "->") for c in caveats + [note]] |
338 | 389 | markdown += ["", "</details>", "", "---", "Generated by the OpenModelica library testing"] |
339 | 390 | markdownname = args.markdown or os.path.join(historydir, "00_comment.md") |
| 391 | +comment = "\n".join([COMMENTMARKER] + markdown) + "\n" |
340 | 392 | with codecs.open(markdownname, "w", encoding="utf-8") as fout: |
341 | | - fout.write("\n".join(markdown) + "\n") |
| 393 | + fout.write(comment) |
| 394 | + |
| 395 | +if args.comment: |
| 396 | + print(postComment(pr, comment)) |
342 | 397 |
|
343 | 398 | print("%s: %s" % (branch, summary)) |
344 | 399 | print("Report: %s" % os.path.join(historydir, reportname)) |
|
0 commit comments