Skip to content

Commit 4dc43e2

Browse files
[𝘀𝗽𝗿] initial version
Created using spr 1.3.7
2 parents 0b5a00a + 2fbb8cb commit 4dc43e2

File tree

2 files changed

+141
-20
lines changed

2 files changed

+141
-20
lines changed

.ci/generate_test_report_lib.py

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,19 @@
33
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
44
"""Library to parse JUnit XML files and return a markdown report."""
55

6+
from typing import TypedDict
7+
68
from junitparser import JUnitXml, Failure
79

10+
11+
# This data structure should match the definition in llvm-zorg in
12+
# premerge/advisor/advisor_lib.py
13+
class FailureExplanation(TypedDict):
14+
name: str
15+
explained: bool
16+
reason: str | None
17+
18+
819
SEE_BUILD_FILE_STR = "Download the build's log file to see the details."
920
UNRELATED_FAILURES_STR = (
1021
"If these failures are unrelated to your changes (for example "
@@ -82,16 +93,29 @@ def find_failure_in_ninja_logs(ninja_logs: list[list[str]]) -> list[tuple[str, s
8293
return failures
8394

8495

85-
def _format_ninja_failures(ninja_failures: list[tuple[str, str]]) -> list[str]:
86-
"""Formats ninja failures into summary views for the report."""
96+
def _format_failures(
97+
failures: list[tuple[str, str]], failure_explanations: dict[str, FailureExplanation]
98+
) -> list[str]:
99+
"""Formats failures into summary views for the report."""
87100
output = []
88-
for build_failure in ninja_failures:
101+
for build_failure in failures:
89102
failed_action, failure_message = build_failure
103+
failure_explanation = None
104+
if failed_action in failure_explanations:
105+
failure_explanation = failure_explanations[failed_action]
106+
output.append("<details>")
107+
if failure_explanation:
108+
output.extend(
109+
[
110+
f"<summary>{failed_action} (Likely Already Failing)</summary>" "",
111+
failure_explanation["reason"],
112+
"",
113+
]
114+
)
115+
else:
116+
output.extend([f"<summary>{failed_action}</summary>", ""])
90117
output.extend(
91118
[
92-
"<details>",
93-
f"<summary>{failed_action}</summary>",
94-
"",
95119
"```",
96120
failure_message,
97121
"```",
@@ -132,12 +156,19 @@ def generate_report(
132156
ninja_logs: list[list[str]],
133157
size_limit=1024 * 1024,
134158
list_failures=True,
159+
failure_explanations_list: list[FailureExplanation] = [],
135160
):
136161
failures = get_failures(junit_objects)
137162
tests_run = 0
138163
tests_skipped = 0
139164
tests_failed = 0
140165

166+
failure_explanations: dict[str, FailureExplanation] = {}
167+
for failure_explanation in failure_explanations_list:
168+
if not failure_explanation["explained"]:
169+
continue
170+
failure_explanations[failure_explanation["name"]] = failure_explanation
171+
141172
for results in junit_objects:
142173
for testsuite in results:
143174
tests_run += testsuite.tests
@@ -176,7 +207,7 @@ def generate_report(
176207
"",
177208
]
178209
)
179-
report.extend(_format_ninja_failures(ninja_failures))
210+
report.extend(_format_failures(ninja_failures, failure_explanations))
180211
report.extend(
181212
[
182213
"",
@@ -212,18 +243,7 @@ def plural(num_tests):
212243

213244
for testsuite_name, failures in failures.items():
214245
report.extend(["", f"### {testsuite_name}"])
215-
for name, output in failures:
216-
report.extend(
217-
[
218-
"<details>",
219-
f"<summary>{name}</summary>",
220-
"",
221-
"```",
222-
output,
223-
"```",
224-
"</details>",
225-
]
226-
)
246+
report.extend(_format_failures(failures, failure_explanations))
227247
elif return_code != 0:
228248
# No tests failed but the build was in a failed state. Bring this to the user's
229249
# attention.
@@ -248,7 +268,7 @@ def plural(num_tests):
248268
"",
249269
]
250270
)
251-
report.extend(_format_ninja_failures(ninja_failures))
271+
report.extend(_format_failures(ninja_failures, failure_explanations))
252272

253273
if failures or return_code != 0:
254274
report.extend(["", UNRELATED_FAILURES_STR])

.ci/generate_test_report_lib_test.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -781,6 +781,107 @@ def test_report_size_limit(self):
781781
),
782782
)
783783

784+
def test_report_ninja_explanation(self):
785+
self.assertEqual(
786+
generate_test_report_lib.generate_report(
787+
"Foo",
788+
1,
789+
[],
790+
[
791+
[
792+
"[1/5] test/1.stamp",
793+
"[2/5] test/2.stamp",
794+
"[3/5] test/3.stamp",
795+
"[4/5] test/4.stamp",
796+
"FAILED: test/4.stamp",
797+
"touch test/4.stamp",
798+
"Half Moon Bay.",
799+
"[5/5] test/5.stamp",
800+
]
801+
],
802+
failure_explanations_list=[
803+
{
804+
"name": "test/4.stamp",
805+
"explained": True,
806+
"reason": "Failing at head",
807+
}
808+
],
809+
),
810+
dedent(
811+
"""\
812+
# Foo
813+
814+
The build failed before running any tests. Click on a failure below to see the details.
815+
816+
<details>
817+
<summary>test/4.stamp (Likely Already Failing)</summary>
818+
Failing at head
819+
820+
```
821+
FAILED: test/4.stamp
822+
touch test/4.stamp
823+
Half Moon Bay.
824+
```
825+
</details>
826+
827+
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."""
828+
),
829+
)
830+
831+
def test_report_test_failure_explanation(self):
832+
self.assertEqual(
833+
generate_test_report_lib.generate_report(
834+
"Foo",
835+
1,
836+
[
837+
junit_from_xml(
838+
dedent(
839+
"""\
840+
<?xml version="1.0" encoding="UTF-8"?>
841+
<testsuites time="8.89">
842+
<testsuite name="Bar" tests="1" failures="1" skipped="0" time="410.63">
843+
<testcase classname="Bar/test_3" name="test_3" time="0.02">
844+
<failure><![CDATA[Error! Expected Big Sur to be next to the ocean.]]></failure>
845+
</testcase>
846+
</testsuite>
847+
</testsuites>"""
848+
)
849+
)
850+
],
851+
[],
852+
failure_explanations_list=[
853+
{
854+
"name": "Bar/test_3/test_3",
855+
"explained": True,
856+
"reason": "Big Sur is next to the Pacific.",
857+
}
858+
],
859+
),
860+
(
861+
dedent(
862+
"""\
863+
# Foo
864+
865+
* 1 test failed
866+
867+
## Failed Tests
868+
(click on a test name to see its output)
869+
870+
### Bar
871+
<details>
872+
<summary>Bar/test_3/test_3 (Likely Already Failing)</summary>
873+
Big Sur is next to the Pacific.
874+
875+
```
876+
Error! Expected Big Sur to be next to the ocean.
877+
```
878+
</details>
879+
880+
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."""
881+
)
882+
),
883+
)
884+
784885
def test_generate_report_end_to_end(self):
785886
with tempfile.TemporaryDirectory() as temp_dir:
786887
junit_xml_file = os.path.join(temp_dir, "junit.xml")

0 commit comments

Comments
 (0)