33import settings
44import difflib
55import utils
6+ import shutil
7+ import json
8+ import filecmp
69
710"""
811This 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
1217def 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
80132def 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
86138def 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 )
0 commit comments