Skip to content

Commit ffe973a

Browse files
[CI] Make premerge advisor exit with code 0 if failures are explained
This will mark the CI as green if the premerge advisor is able to explain all of the failures. We have seen many false negatives (failures not explained that should be), but no false positives (failures explained that should not be) so far. Reviewers: cmtice Pull Request: #172394
1 parent 6738917 commit ffe973a

File tree

3 files changed

+93
-41
lines changed

3 files changed

+93
-41
lines changed

.ci/generate_test_report_lib.py

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,17 @@ def get_failures(junit_objects) -> dict[str, list[tuple[str, str]]]:
158158
return failures
159159

160160

161+
def are_all_failures_explained(
162+
failures: list[tuple[str, str]], failure_explanations: dict[str, FailureExplanation]
163+
) -> bool:
164+
for failed_action, _ in failures:
165+
if failed_action not in failure_explanations:
166+
return False
167+
else:
168+
assert failure_explanations[failed_action]["explained"]
169+
return True
170+
171+
161172
# Set size_limit to limit the byte size of the report. The default is 1MB as this
162173
# is the most that can be put into an annotation. If the generated report exceeds
163174
# this limit and failures are listed, it will be generated again without failures
@@ -172,7 +183,7 @@ def generate_report(
172183
size_limit=1024 * 1024,
173184
list_failures=True,
174185
failure_explanations_list: list[FailureExplanation] = [],
175-
):
186+
) -> tuple[str, bool]:
176187
failures = get_failures(junit_objects)
177188
tests_run = 0
178189
tests_skipped = 0
@@ -183,6 +194,12 @@ def generate_report(
183194
if not failure_explanation["explained"]:
184195
continue
185196
failure_explanations[failure_explanation["name"]] = failure_explanation
197+
all_failures_explained = True
198+
if failures:
199+
for _, failures_list in failures.items():
200+
all_failures_explained &= are_all_failures_explained(
201+
failures_list, failure_explanations
202+
)
186203

187204
for results in junit_objects:
188205
for testsuite in results:
@@ -202,7 +219,11 @@ def generate_report(
202219
)
203220
else:
204221
ninja_failures = find_failure_in_ninja_logs(ninja_logs)
222+
all_failures_explained &= are_all_failures_explained(
223+
ninja_failures, failure_explanations
224+
)
205225
if not ninja_failures:
226+
all_failures_explained = False
206227
report.extend(
207228
[
208229
"The build failed before running any tests. Detailed "
@@ -229,7 +250,7 @@ def generate_report(
229250
UNRELATED_FAILURES_STR,
230251
]
231252
)
232-
return "\n".join(report)
253+
return ("\n".join(report), all_failures_explained)
233254

234255
tests_passed = tests_run - tests_skipped - tests_failed
235256

@@ -264,6 +285,7 @@ def plural(num_tests):
264285
# attention.
265286
ninja_failures = find_failure_in_ninja_logs(ninja_logs)
266287
if not ninja_failures:
288+
all_failures_explained = False
267289
report.extend(
268290
[
269291
"",
@@ -275,6 +297,9 @@ def plural(num_tests):
275297
]
276298
)
277299
else:
300+
all_failures_explained &= are_all_failures_explained(
301+
ninja_failures, failure_explanations
302+
)
278303
report.extend(
279304
[
280305
"",
@@ -303,7 +328,7 @@ def plural(num_tests):
303328
list_failures=False,
304329
)
305330

306-
return report
331+
return (report, all_failures_explained)
307332

308333

309334
def load_info_from_files(build_log_files):

.ci/generate_test_report_lib_test.py

Lines changed: 52 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -191,26 +191,32 @@ def test_ninja_log_mismatched_failed(self):
191191
def test_title_only(self):
192192
self.assertEqual(
193193
generate_test_report_lib.generate_report("Foo", 0, [], []),
194-
dedent(
195-
"""\
194+
(
195+
dedent(
196+
"""\
196197
# Foo
197198
198199
:white_check_mark: The build succeeded and no tests ran. This is expected in some build configurations."""
200+
),
201+
True,
199202
),
200203
)
201204

202205
def test_title_only_failure(self):
203206
self.assertEqual(
204207
generate_test_report_lib.generate_report("Foo", 1, [], []),
205-
dedent(
206-
"""\
208+
(
209+
dedent(
210+
"""\
207211
# Foo
208212
209213
The build failed before running any tests. Detailed information about the build failure could not be automatically obtained.
210214
211215
Download the build's log file to see the details.
212216
213217
If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the `infrastructure` label."""
218+
),
219+
False,
214220
),
215221
)
216222

@@ -233,8 +239,9 @@ def test_title_only_failure_ninja_log(self):
233239
]
234240
],
235241
),
236-
dedent(
237-
"""\
242+
(
243+
dedent(
244+
"""\
238245
# Foo
239246
240247
The build failed before running any tests. Click on a failure below to see the details.
@@ -250,6 +257,8 @@ def test_title_only_failure_ninja_log(self):
250257
</details>
251258
252259
If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the `infrastructure` label."""
260+
),
261+
False,
253262
),
254263
)
255264

@@ -272,15 +281,18 @@ def test_no_tests_in_testsuite(self):
272281
],
273282
[],
274283
),
275-
dedent(
276-
"""\
284+
(
285+
dedent(
286+
"""\
277287
# Foo
278288
279289
The build failed before running any tests. Detailed information about the build failure could not be automatically obtained.
280290
281291
Download the build's log file to see the details.
282292
283293
If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the `infrastructure` label."""
294+
),
295+
False,
284296
),
285297
)
286298

@@ -312,7 +324,8 @@ def test_no_failures(self):
312324
* 1 test passed
313325
314326
:white_check_mark: The build succeeded and all tests passed."""
315-
)
327+
),
328+
True,
316329
),
317330
)
318331

@@ -348,7 +361,8 @@ def test_no_failures_build_failed(self):
348361
Download the build's log file to see the details.
349362
350363
If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the `infrastructure` label."""
351-
)
364+
),
365+
False,
352366
),
353367
)
354368

@@ -403,7 +417,8 @@ def test_no_failures_build_failed_ninja_log(self):
403417
</details>
404418
405419
If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the `infrastructure` label."""
406-
)
420+
),
421+
False,
407422
),
408423
)
409424

@@ -466,7 +481,8 @@ def test_no_failures_multiple_build_failed_ninja_log(self):
466481
</details>
467482
468483
If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the `infrastructure` label."""
469-
)
484+
),
485+
False,
470486
),
471487
)
472488

@@ -528,7 +544,8 @@ def test_report_single_file_single_testsuite(self):
528544
</details>
529545
530546
If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the `infrastructure` label."""
531-
)
547+
),
548+
False,
532549
),
533550
)
534551

@@ -595,7 +612,7 @@ def test_report_single_file_multiple_testsuites(self):
595612
],
596613
[],
597614
),
598-
self.MULTI_SUITE_OUTPUT,
615+
(self.MULTI_SUITE_OUTPUT, False),
599616
)
600617

601618
def test_report_multiple_files_multiple_testsuites(self):
@@ -637,7 +654,7 @@ def test_report_multiple_files_multiple_testsuites(self):
637654
],
638655
[],
639656
),
640-
self.MULTI_SUITE_OUTPUT,
657+
(self.MULTI_SUITE_OUTPUT, False),
641658
)
642659

643660
def test_report_dont_list_failures(self):
@@ -673,7 +690,8 @@ def test_report_dont_list_failures(self):
673690
Failed tests and their output was too large to report. Download the build's log file to see the details.
674691
675692
If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the `infrastructure` label."""
676-
)
693+
),
694+
False,
677695
),
678696
)
679697

@@ -710,7 +728,8 @@ def test_report_dont_list_failures_link_to_log(self):
710728
Failed tests and their output was too large to report. Download the build's log file to see the details.
711729
712730
If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the `infrastructure` label."""
713-
)
731+
),
732+
False,
714733
),
715734
)
716735

@@ -750,7 +769,8 @@ def test_report_size_limit(self):
750769
Failed tests and their output was too large to report. Download the build's log file to see the details.
751770
752771
If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the `infrastructure` label."""
753-
)
772+
),
773+
False,
754774
),
755775
)
756776

@@ -780,8 +800,9 @@ def test_report_ninja_explanation(self):
780800
}
781801
],
782802
),
783-
dedent(
784-
"""\
803+
(
804+
dedent(
805+
"""\
785806
# Foo
786807
787808
The build failed before running any tests. Click on a failure below to see the details.
@@ -798,6 +819,8 @@ def test_report_ninja_explanation(self):
798819
</details>
799820
800821
If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the `infrastructure` label."""
822+
),
823+
True,
801824
),
802825
)
803826

@@ -851,7 +874,8 @@ def test_report_test_failure_explanation(self):
851874
</details>
852875
853876
If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the `infrastructure` label."""
854-
)
877+
),
878+
True,
855879
),
856880
)
857881

@@ -904,7 +928,8 @@ def test_report_test_failure_have_explanation_explained_false(self):
904928
</details>
905929
906930
If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the `infrastructure` label."""
907-
)
931+
),
932+
False,
908933
),
909934
)
910935

@@ -942,8 +967,9 @@ def test_generate_report_end_to_end(self):
942967
generate_test_report_lib.generate_report_from_files(
943968
"Foo", 1, [junit_xml_file, ninja_log_file]
944969
),
945-
dedent(
946-
"""\
970+
(
971+
dedent(
972+
"""\
947973
# Foo
948974
949975
* 1 test passed
@@ -961,5 +987,7 @@ def test_generate_report_end_to_end(self):
961987
</details>
962988
963989
If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the `infrastructure` label."""
990+
),
991+
False,
964992
),
965993
)

.ci/premerge_advisor_explain.py

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def main(
5353
github_token: str,
5454
pr_number: int,
5555
return_code: int,
56-
):
56+
) -> bool:
5757
"""The main entrypoint for the script.
5858
5959
This function parses failures from files, requests information from the
@@ -112,19 +112,14 @@ def main(
112112
advisor_explanations = advisor_response.json()
113113
else:
114114
print(advisor_response.reason)
115-
comments.append(
116-
get_comment(
117-
github_token,
118-
pr_number,
119-
generate_test_report_lib.generate_report(
120-
generate_test_report_lib.compute_platform_title(),
121-
return_code,
122-
junit_objects,
123-
ninja_logs,
124-
failure_explanations_list=advisor_explanations,
125-
),
126-
)
115+
report, failures_explained = generate_test_report_lib.generate_report(
116+
generate_test_report_lib.compute_platform_title(),
117+
return_code,
118+
junit_objects,
119+
ninja_logs,
120+
failure_explanations_list=advisor_explanations,
127121
)
122+
comments.append(get_comment(github_token, pr_number, report))
128123
if return_code == 0 and "id" not in comments[0]:
129124
# If the job succeeds and there is not an existing comment, we
130125
# should not write one to reduce noise.
@@ -133,6 +128,7 @@ def main(
133128
with open(comments_file_name, "w") as comment_file_handle:
134129
json.dump(comments, comment_file_handle)
135130
print(f"Wrote comments to {comments_file_name}")
131+
return failures_explained
136132

137133

138134
if __name__ == "__main__":
@@ -151,12 +147,15 @@ def main(
151147
if platform.machine() == "arm64" or platform.machine() == "aarch64":
152148
sys.exit(0)
153149

154-
main(
150+
failures_explained = main(
155151
args.commit_sha,
156152
args.build_log_files,
157153
args.github_token,
158154
args.pr_number,
159155
args.return_code,
160156
)
161157

158+
if failures_explained:
159+
sys.exit(0)
160+
162161
sys.exit(args.return_code)

0 commit comments

Comments
 (0)