Skip to content

Commit 47ff89a

Browse files
Merge remote-tracking branch 'origin/4.7.x' into pre-release
2 parents c03503d + f16e544 commit 47ff89a

1 file changed

Lines changed: 77 additions & 3 deletions

File tree

.github/workflows/ci.yml

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,15 +82,89 @@ jobs:
8282
timeout_minutes: '35'
8383

8484
- name: Check Test Status
85-
if: inputs.skip_tests != true # Temporarily disable tests in CI pipeline
85+
if: always() && inputs.skip_tests != true # Temporarily disable tests in CI pipeline
86+
shell: bash
8687
run: |
87-
if [ "${{ steps.run-tests.outputs.test_status }}" != "success" ]; then
88-
echo "❌ Tests failed with status: ${{ steps.run-tests.outputs.test_status }}"
88+
test_status="${{ steps.run-tests.outputs.test_status }}"
89+
test_status="${test_status:-failed}"
90+
91+
if [ "$test_status" != "success" ]; then
92+
echo "❌ Tests failed with status: $test_status"
8993
echo "📊 Test Results:"
9094
echo " - Total Tests: ${{ steps.run-tests.outputs.test_count }}"
9195
echo " - Failed Tests: ${{ steps.run-tests.outputs.failed_count }}"
9296
echo " - Passed Tests: ${{ steps.run-tests.outputs.passed_count }}"
9397
echo " - Skipped Tests: ${{ steps.run-tests.outputs.skipped_count }}"
98+
echo ""
99+
echo "🔎 Failed test cases:"
100+
101+
python3 <<'PY'
102+
import os
103+
import xml.etree.ElementTree as ET
104+
from pathlib import Path
105+
106+
report_files = sorted(Path(".").glob("**/TEST-*.xml"))
107+
failures = []
108+
109+
for report_file in report_files:
110+
try:
111+
root = ET.parse(report_file).getroot()
112+
except ET.ParseError as exc:
113+
print(f"::warning file={report_file}::Unable to parse test report: {exc}")
114+
continue
115+
116+
for case in root.findall(".//testcase"):
117+
failed_nodes = [node for tag in ("failure", "error") for node in case.findall(tag)]
118+
if not failed_nodes:
119+
continue
120+
121+
classname = (
122+
case.attrib.get("classname")
123+
or case.attrib.get("className")
124+
or root.attrib.get("name")
125+
or report_file.stem.removeprefix("TEST-")
126+
)
127+
name = case.attrib.get("name", "<unknown>")
128+
duration = case.attrib.get("time")
129+
130+
for node in failed_nodes:
131+
raw_message = (node.attrib.get("message") or node.text or "").strip()
132+
message = raw_message.splitlines()[0] if raw_message else "No details provided"
133+
failures.append((str(report_file), classname, name, node.tag, message, duration))
134+
135+
if not failures:
136+
print(" - No per-test failure details were found in TEST-*.xml reports.")
137+
else:
138+
for report_file, classname, name, failure_type, message, duration in failures[:50]:
139+
duration_suffix = f" ({duration}s)" if duration else ""
140+
print(f" - {classname}#{name}{duration_suffix}: {message}")
141+
142+
escaped_message = (
143+
f"{failure_type}: {message}"
144+
.replace("%", "%25")
145+
.replace("\r", "%0D")
146+
.replace("\n", "%0A")
147+
)
148+
print(f"::error file={report_file},title={classname}#{name}::{escaped_message}")
149+
150+
remaining = len(failures) - 50
151+
if remaining > 0:
152+
print(f" - ... and {remaining} more failing test case(s)")
153+
154+
summary_path = os.environ.get("GITHUB_STEP_SUMMARY")
155+
if summary_path:
156+
with open(summary_path, "a", encoding="utf-8") as summary:
157+
summary.write("### ❌ Failed test cases\n\n")
158+
for _, classname, name, failure_type, message, duration in failures[:20]:
159+
duration_suffix = f" ({duration}s)" if duration else ""
160+
summary.write(
161+
f"- `{classname}#{name}`{duration_suffix} - **{failure_type}**: {message}\n"
162+
)
163+
if len(failures) > 20:
164+
summary.write(f"- ... and {len(failures) - 20} more failing test case(s)\n")
165+
summary.write("\n")
166+
PY
167+
94168
exit 1
95169
else
96170
echo "✅ All tests passed successfully"

0 commit comments

Comments
 (0)