Skip to content

Commit 8010073

Browse files
committed
Only post comment with framework coverage change if it changed or wasn't done before
1 parent 0e91269 commit 8010073

File tree

3 files changed

+121
-17
lines changed

3 files changed

+121
-17
lines changed

misc/scripts/library-coverage/compare-files-comment-pr.py

Lines changed: 114 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,16 @@
33
import settings
44
import difflib
55
import utils
6+
import shutil
7+
import json
8+
import filecmp
69

710
"""
811
This script compares the generated CSV coverage files with the ones in the codebase.
912
"""
1013

14+
artifacts_worflow_name = "Check framework coverage changes"
15+
1116

1217
def check_file_exists(file):
1318
if not os.path.exists(file):
@@ -41,20 +46,27 @@ def compare_files_str(file1, file2):
4146
return ret
4247

4348

44-
def comment_pr(output_file, repo, run_id):
49+
def write_diff_for_run(output_file, repo, run_id):
4550
folder1 = "out_base"
4651
folder2 = "out_merge"
47-
utils.subprocess_run(["gh", "run", "download", "--repo", repo, "--name",
48-
"csv-framework-coverage-base", "--dir", folder1, str(run_id)])
49-
utils.subprocess_run(["gh", "run", "download", "--repo", repo, "--name",
50-
"csv-framework-coverage-merge", "--dir", folder2, str(run_id)])
51-
utils.subprocess_run(["gh", "run", "download", "--repo", repo, "--name",
52-
"pr", "--dir", "pr", str(run_id)])
52+
try:
53+
utils.subprocess_run(["gh", "run", "download", "--repo", repo, "--name",
54+
"csv-framework-coverage-base", "--dir", folder1, str(run_id)])
55+
utils.subprocess_run(["gh", "run", "download", "--repo", repo, "--name",
56+
"csv-framework-coverage-merge", "--dir", folder2, str(run_id)])
57+
utils.subprocess_run(["gh", "run", "download", "--repo", repo, "--name",
58+
"pr", "--dir", "pr", str(run_id)])
59+
60+
compare_folders(folder1, folder2, output_file)
61+
finally:
62+
if os.path.isdir(folder1):
63+
shutil.rmtree(folder1)
5364

54-
with open("pr/NR") as file:
55-
pr_number = int(file.read())
65+
if os.path.isdir(folder2):
66+
shutil.rmtree(folder2)
5667

57-
compare_folders(folder1, folder2, output_file)
68+
69+
def get_comment_text(output_file, repo, run_id):
5870
size = os.path.getsize(output_file)
5971
if size == 0:
6072
print("No difference in the coverage reports")
@@ -74,16 +86,60 @@ def comment_pr(output_file, repo, run_id):
7486
comment += "The differences can be found in the " + \
7587
output_file + " artifact of this job."
7688

77-
# post_comment(comment, repo, pr_number)
89+
return comment
90+
91+
92+
def comment_pr(output_file, repo, run_id):
93+
"""
94+
Generates coverage diff produced by the changes in the current PR. If the diff is not empty, then post it as a comment.
95+
If a workflow run produces the same diff as the directly preceeding one, then don't post a comment.
96+
"""
97+
98+
# Store diff for current run
99+
write_diff_for_run(output_file, repo, run_id)
100+
101+
try:
102+
with open("pr/NR") as file:
103+
pr_number = int(file.read())
104+
finally:
105+
if os.path.isdir("pr"):
106+
shutil.rmtree("pr")
107+
108+
# Try storing diff for previous run:
109+
prev_output_file = "prev_" + output_file
110+
try:
111+
prev_run_id = get_previous_run_id(repo, run_id, pr_number)
112+
write_diff_for_run(prev_output_file, repo, prev_run_id)
113+
114+
if filecmp.cmp(output_file, prev_output_file, shallow=False):
115+
print("Previous run " + str(prev_run_id) +
116+
" resulted in the same diff, so not commenting again.")
117+
return
118+
else:
119+
print("Diff of previous run " +
120+
str(prev_run_id) + " differs, commenting.")
121+
except Exception:
122+
# this is not mecessarily a failure, it can also mean that there was no previous run yet.
123+
print("Couldn't generate diff for previous run:", sys.exc_info()[1])
124+
finally:
125+
if os.path.isfile(prev_output_file):
126+
os.remove(prev_output_file)
127+
128+
comment = get_comment_text(output_file, repo, run_id)
129+
post_comment(comment, repo, pr_number)
78130

79131

80132
def post_comment(comment, repo, pr_number):
81133
print("Posting comment to PR #" + str(pr_number))
82-
utils.subprocess_run(["gh", "pr", "comment", pr_number,
134+
utils.subprocess_run(["gh", "pr", "comment", str(pr_number),
83135
"--repo", repo, "--body", comment])
84136

85137

86138
def compare_folders(folder1, folder2, output_file):
139+
"""
140+
Compares the contents of two folders and writes the differences to the output file.
141+
"""
142+
87143
languages = ['java']
88144

89145
return_md = ""
@@ -137,5 +193,49 @@ def compare_folders(folder1, folder2, output_file):
137193
out.write(return_md)
138194

139195

140-
# comment_pr(sys.argv[1], sys.argv[2], sys.argv[3])
141-
comment_pr("x.md", "dsp-testing/codeql-csv-coverage-pr-commenter", 938931471)
196+
def get_previous_run_id(repo, run_id, pr_number):
197+
"""
198+
Gets the previous run id for a given workflow run, considering that the previous workflow run needs to come from the same PR.
199+
"""
200+
201+
# Get branch and repo from run:
202+
this_run = utils.subprocess_check_output(["gh", "api", "-X", "GET", "repos/" + repo + "/actions/runs/" + str(
203+
run_id), "--jq", "{ head_branch: .head_branch, head_repository: .head_repository.full_name }"])
204+
205+
this_run = json.loads(this_run)
206+
pr_branch = this_run["head_branch"]
207+
pr_repo = this_run["head_repository"]
208+
209+
# Get all previous runs that match branch, repo and workflow name:
210+
ids = utils.subprocess_check_output(["gh", "api", "-X", "GET", "repos/" + repo + "/actions/runs", "-f", "event=pull_request", "-f", "status=success", "-f", "name=\"" + artifacts_worflow_name + "\"", "--jq",
211+
"[.workflow_runs.[] | select(.head_branch==\"" + pr_branch + "\" and .head_repository.full_name==\"" + pr_repo + "\") | { created_at: .created_at, run_id: .id}] | sort_by(.created_at) | reverse | [.[].run_id]"])
212+
213+
ids = json.loads(ids)
214+
if ids[0] != run_id:
215+
raise Exception("Expected to find " + str(run_id) +
216+
" in the list of matching runs.")
217+
218+
for previous_run_id in ids[1:]:
219+
utils.subprocess_run(["gh", "run", "download", "--repo", repo,
220+
"--name", "pr", "--dir", "prev_run_pr", str(previous_run_id)])
221+
222+
try:
223+
with open("prev_run_pr/NR") as file:
224+
prev_pr_number = int(file.read())
225+
print("PR number: " + str(prev_pr_number))
226+
finally:
227+
if os.path.isdir("prev_run_pr"):
228+
shutil.rmtree("prev_run_pr")
229+
230+
# the previous run needs to be coming from the same PR:
231+
if pr_number == prev_pr_number:
232+
return previous_run_id
233+
234+
raise Exception("Couldn't find previous run.")
235+
236+
237+
output_file = sys.argv[1]
238+
repo = sys.argv[2]
239+
run_id = sys.argv[3]
240+
241+
comment_pr(output_file, repo, run_id)

misc/scripts/library-coverage/generate-timeseries.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import subprocess
21
import csv
32
import sys
43
import os
@@ -20,7 +19,7 @@
2019

2120
class Git:
2221
def get_output(arr):
23-
r = subprocess.check_output(arr, text=True, env=os.environ.copy())
22+
r = utils.subprocess_check_output(arr)
2423
return r.strip("\n'")
2524

2625
def get_date(sha):

misc/scripts/library-coverage/utils.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import subprocess
22
import os
33
import csv
4-
import sys
54
import shlex
65

76

@@ -11,6 +10,12 @@ def subprocess_run(cmd):
1110
return subprocess.run(cmd, capture_output=True, text=True, env=os.environ.copy(), check=True)
1211

1312

13+
def subprocess_check_output(cmd):
14+
"""Runs a command through subprocess.check_output and returns its output"""
15+
print(shlex.join(cmd))
16+
return subprocess.check_output(cmd, text=True, env=os.environ.copy())
17+
18+
1419
def create_empty_database(lang, extension, database):
1520
"""Creates an empty database for the given language."""
1621
subprocess_run(["codeql", "database", "init", "--language=" + lang,

0 commit comments

Comments
 (0)