@@ -41,10 +41,12 @@ def _parse_ninja_log(ninja_log: list[str]) -> list[tuple[str, str]]:
4141 # touch test/4.stamp
4242 #
4343 # index will point to the line that starts with Failed:. The progress
44- # indicator is the line before this ([4/5] test/4.stamp) and contains a pretty
45- # printed version of the target being built (test/4.stamp). We use this line
46- # and remove the progress information to get a succinct name for the target.
47- failing_action = ninja_log [index - 1 ].split ("] " )[1 ]
44+ # indicator is sometimes the line before this ([4/5] test/4.stamp) and
45+ # will contain a pretty printed version of the target being built
46+ # (test/4.stamp) when accurate. We instead parse the failed line rather
47+ # than the progress indicator as the progress indicator may not be
48+ # aligned with the failure.
49+ failing_action = ninja_log [index ].split ("FAILED: " )[1 ]
4850 failure_log = []
4951 while (
5052 index < len (ninja_log )
@@ -99,6 +101,24 @@ def _format_ninja_failures(ninja_failures: list[tuple[str, str]]) -> list[str]:
99101 return output
100102
101103
104+ def get_failures (junit_objects ) -> dict [str , list [tuple [str , str ]]]:
105+ failures = {}
106+ for results in junit_objects :
107+ for testsuite in results :
108+ for test in testsuite :
109+ if (
110+ not test .is_passed
111+ and test .result
112+ and isinstance (test .result [0 ], Failure )
113+ ):
114+ if failures .get (testsuite .name ) is None :
115+ failures [testsuite .name ] = []
116+ failures [testsuite .name ].append (
117+ (test .classname + "/" + test .name , test .result [0 ].text )
118+ )
119+ return failures
120+
121+
102122# Set size_limit to limit the byte size of the report. The default is 1MB as this
103123# is the most that can be put into an annotation. If the generated report exceeds
104124# this limit and failures are listed, it will be generated again without failures
@@ -113,7 +133,7 @@ def generate_report(
113133 size_limit = 1024 * 1024 ,
114134 list_failures = True ,
115135):
116- failures = {}
136+ failures = get_failures ( junit_objects )
117137 tests_run = 0
118138 tests_skipped = 0
119139 tests_failed = 0
@@ -124,18 +144,6 @@ def generate_report(
124144 tests_skipped += testsuite .skipped
125145 tests_failed += testsuite .failures
126146
127- for test in testsuite :
128- if (
129- not test .is_passed
130- and test .result
131- and isinstance (test .result [0 ], Failure )
132- ):
133- if failures .get (testsuite .name ) is None :
134- failures [testsuite .name ] = []
135- failures [testsuite .name ].append (
136- (test .classname + "/" + test .name , test .result [0 ].text )
137- )
138-
139147 report = [f"# { title } " , "" ]
140148
141149 if tests_run == 0 :
@@ -258,7 +266,7 @@ def plural(num_tests):
258266 return report
259267
260268
261- def generate_report_from_files ( title , return_code , build_log_files ):
269+ def load_info_from_files ( build_log_files ):
262270 junit_files = [
263271 junit_file for junit_file in build_log_files if junit_file .endswith (".xml" )
264272 ]
@@ -271,6 +279,9 @@ def generate_report_from_files(title, return_code, build_log_files):
271279 ninja_logs .append (
272280 [log_line .strip () for log_line in ninja_log_file_handle .readlines ()]
273281 )
274- return generate_report (
275- title , return_code , [JUnitXml .fromfile (p ) for p in junit_files ], ninja_logs
276- )
282+ return [JUnitXml .fromfile (p ) for p in junit_files ], ninja_logs
283+
284+
285+ def generate_report_from_files (title , return_code , build_log_files ):
286+ junit_objects , ninja_logs = load_info_from_files (build_log_files )
287+ return generate_report (title , return_code , junit_objects , ninja_logs )
0 commit comments