Skip to content

[CI] Enable Build Failure Reporting #152622

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .ci/generate_test_report_github.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("return_code", help="The build's return code.", type=int)
parser.add_argument("junit_files", help="Paths to JUnit report files.", nargs="*")
parser.add_argument(
"build_test_logs", help="Paths to JUnit report files and ninja logs.", nargs="*"
)
args = parser.parse_args()

report = generate_test_report_lib.generate_report_from_files(
PLATFORM_TITLES[platform.system()], args.return_code, args.junit_files
PLATFORM_TITLES[platform.system()], args.return_code, args.build_test_logs
)

print(report)
105 changes: 84 additions & 21 deletions .ci/generate_test_report_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,25 @@ def find_failure_in_ninja_logs(ninja_logs: list[list[str]]) -> list[tuple[str, s
return failures


def _format_ninja_failures(ninja_failures: list[tuple[str, str]]) -> list[str]:
"""Formats ninja failures into summary views for the report."""
output = []
for build_failure in ninja_failures:
failed_action, failure_message = build_failure
output.extend(
[
"<details>",
f"<summary>{failed_action}</summary>",
"",
"```",
failure_message,
"```",
"</details>",
]
)
return output


# Set size_limit to limit the byte size of the report. The default is 1MB as this
# is the most that can be put into an annotation. If the generated report exceeds
# this limit and failures are listed, it will be generated again without failures
Expand All @@ -83,6 +102,7 @@ def generate_report(
title,
return_code,
junit_objects,
ninja_logs: list[list[str]],
size_limit=1024 * 1024,
list_failures=True,
):
Expand Down Expand Up @@ -120,15 +140,34 @@ def generate_report(
]
)
else:
report.extend(
[
"The build failed before running any tests.",
"",
SEE_BUILD_FILE_STR,
"",
UNRELATED_FAILURES_STR,
]
)
ninja_failures = find_failure_in_ninja_logs(ninja_logs)
if not ninja_failures:
report.extend(
[
"The build failed before running any tests. Detailed "
"information about the build failure could not be "
"automatically obtained.",
"",
SEE_BUILD_FILE_STR,
"",
UNRELATED_FAILURES_STR,
]
)
else:
report.extend(
[
"The build failed before running any tests. Click on a "
"failure below to see the details.",
"",
]
)
report.extend(_format_ninja_failures(ninja_failures))
report.extend(
[
"",
UNRELATED_FAILURES_STR,
]
)
return "\n".join(report)

tests_passed = tests_run - tests_skipped - tests_failed
Expand Down Expand Up @@ -173,14 +212,28 @@ def plural(num_tests):
elif return_code != 0:
# No tests failed but the build was in a failed state. Bring this to the user's
# attention.
report.extend(
[
"",
"All tests passed but another part of the build **failed**.",
"",
SEE_BUILD_FILE_STR,
]
)
ninja_failures = find_failure_in_ninja_logs(ninja_logs)
if not ninja_failures:
report.extend(
[
"",
"All tests passed but another part of the build **failed**. "
"Information about the build failure could not be automatically "
"obtained.",
"",
SEE_BUILD_FILE_STR,
]
)
else:
report.extend(
[
"",
"All tests passed but another part of the build **failed**. Click on "
"a failure below to see the details.",
"",
]
)
report.extend(_format_ninja_failures(ninja_failures))

if failures or return_code != 0:
report.extend(["", UNRELATED_FAILURES_STR])
Expand All @@ -198,9 +251,19 @@ def plural(num_tests):
return report


def generate_report_from_files(title, return_code, junit_files):
def generate_report_from_files(title, return_code, build_log_files):
junit_files = [
junit_file for junit_file in build_log_files if junit_file.endswith(".xml")
]
ninja_log_files = [
ninja_log for ninja_log in build_log_files if ninja_log.endswith(".log")
]
ninja_logs = []
for ninja_log_file in ninja_log_files:
with open(ninja_log_file, "r") as ninja_log_file_handle:
ninja_logs.append(
[log_line.strip() for log_line in ninja_log_file_handle.readlines()]
)
return generate_report(
title,
return_code,
[JUnitXml.fromfile(p) for p in junit_files],
title, return_code, [JUnitXml.fromfile(p) for p in junit_files], ninja_logs
)
Loading
Loading