Skip to content

Commit 738cc02

Browse files
chmouelzakisk
authored andcommitted
chore: Add github step summaries for e2e test suites
Added a workflow step to generate markdown summaries of test results directly in the continuous integration interface. Providing this information in the summary view helped developers identify failing tests immediately without needing to dig through raw execution logs. Signed-off-by: Chmouel Boudjnah <chmouel@redhat.com>
1 parent 658e9d4 commit 738cc02

File tree

3 files changed

+136
-2
lines changed

3 files changed

+136
-2
lines changed

.github/workflows/e2e.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,13 @@ jobs:
386386
run: |
387387
./hack/gh-workflow-ci.sh run_e2e_tests
388388
389+
- name: Generate GitHub Step Summary
390+
if: ${{ always() }}
391+
env:
392+
TEST_PROVIDER: ${{ matrix.provider }}
393+
run: |
394+
./hack/gh-workflow-ci.sh generate_github_summary
395+
389396
- name: Collect logs
390397
if: ${{ always() }}
391398
env:

hack/generate_github_summary.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#!/usr/bin/env python3
2+
"""Parse gotestsum JSON output and generate a GitHub Step Summary in markdown."""
3+
4+
import collections
5+
import json
6+
import sys
7+
8+
9+
def main():
10+
if len(sys.argv) != 3:
11+
print(f"Usage: {sys.argv[0]} <json-file> <provider-name>", file=sys.stderr)
12+
sys.exit(1)
13+
14+
json_file = sys.argv[1]
15+
target = sys.argv[2]
16+
17+
results = {} # test_name -> {action, elapsed}
18+
test_output = collections.defaultdict(list)
19+
20+
with open(json_file) as fh:
21+
for line in fh:
22+
line = line.strip()
23+
if not line:
24+
continue
25+
try:
26+
entry = json.loads(line)
27+
except json.JSONDecodeError:
28+
continue
29+
test = entry.get("Test")
30+
if not test:
31+
continue
32+
action = entry.get("Action", "")
33+
if action == "output":
34+
test_output[test].append(entry.get("Output", ""))
35+
elif action in ("pass", "fail", "skip"):
36+
results[test] = {
37+
"action": action,
38+
"elapsed": entry.get("Elapsed", 0),
39+
}
40+
41+
passed = sorted([t for t, r in results.items() if r["action"] == "pass"])
42+
failed = sorted([t for t, r in results.items() if r["action"] == "fail"])
43+
skipped = sorted([t for t, r in results.items() if r["action"] == "skip"])
44+
45+
# Filter to top-level tests only (no subtests) for counts
46+
top_passed = [t for t in passed if "/" not in t]
47+
top_failed = [t for t in failed if "/" not in t]
48+
top_skipped = [t for t in skipped if "/" not in t]
49+
50+
status = ":x: FAILED" if top_failed else ":white_check_mark: PASSED"
51+
52+
lines = []
53+
lines.append(f"## E2E Tests: {target} {status}")
54+
lines.append("")
55+
lines.append(
56+
f":white_check_mark: **{len(top_passed)}** passed"
57+
f" | :x: **{len(top_failed)}** failed"
58+
f" | :fast_forward: **{len(top_skipped)}** skipped"
59+
)
60+
lines.append("")
61+
62+
if top_failed:
63+
lines.append("### Failed Tests")
64+
lines.append("")
65+
for t in top_failed:
66+
elapsed = results[t]["elapsed"]
67+
lines.append(f"<details><summary>:x: {t} ({elapsed:.1f}s)</summary>")
68+
lines.append("")
69+
lines.append("```")
70+
output = "".join(test_output.get(t, []))
71+
# Include subtest output too
72+
for sub, r in sorted(results.items()):
73+
if sub.startswith(t + "/") and r["action"] == "fail":
74+
output += "".join(test_output.get(sub, []))
75+
lines.append(output.rstrip())
76+
lines.append("```")
77+
lines.append("")
78+
lines.append("</details>")
79+
lines.append("")
80+
81+
if top_passed:
82+
lines.append("<details><summary>Passed Tests</summary>")
83+
lines.append("")
84+
for t in top_passed:
85+
elapsed = results[t]["elapsed"]
86+
lines.append(f"- :white_check_mark: {t} ({elapsed:.1f}s)")
87+
lines.append("")
88+
lines.append("</details>")
89+
lines.append("")
90+
91+
if top_skipped:
92+
lines.append("<details><summary>Skipped Tests</summary>")
93+
lines.append("")
94+
for t in top_skipped:
95+
lines.append(f"- :fast_forward: {t}")
96+
lines.append("")
97+
lines.append("</details>")
98+
99+
print("\n".join(lines))
100+
101+
102+
if __name__ == "__main__":
103+
main()

hack/gh-workflow-ci.sh

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,8 @@ get_tests() {
115115
# which runs the workflow YAML from main (old target names).
116116
local github_chunk_size github_remainder
117117
if [[ ${#github_tests[@]} -gt 0 ]]; then
118-
github_chunk_size=$(( ${#github_tests[@]} / 2 ))
119-
github_remainder=$(( ${#github_tests[@]} % 2 ))
118+
github_chunk_size=$((${#github_tests[@]} / 2))
119+
github_remainder=$((${#github_tests[@]} % 2))
120120
fi
121121

122122
case "${target}" in
@@ -287,6 +287,23 @@ collect_logs() {
287287
detect_panic
288288
}
289289

290+
generate_github_summary() {
291+
local raw_output="/tmp/logs/e2e-test-output.json"
292+
local target="${TEST_PROVIDER:-unknown}"
293+
294+
if [[ -z "${GITHUB_STEP_SUMMARY:-}" ]]; then
295+
echo "GITHUB_STEP_SUMMARY not set, skipping summary generation"
296+
return 0
297+
fi
298+
299+
if [[ ! -f "${raw_output}" ]]; then
300+
echo "No test output found at ${raw_output}, skipping summary generation"
301+
return 0
302+
fi
303+
304+
python3 ./hack/generate_github_summary.py "${raw_output}" "${target}" >>"${GITHUB_STEP_SUMMARY}"
305+
}
306+
290307
detect_panic() {
291308
# shellcheck disable=SC2016
292309
(find /tmp/logs/ -type f -regex '.*/pipelines-as-code.*/[0-9]\.log$' | xargs -r sed -n '/stderr F panic:.*/,$p' | head -n 80) >/tmp/panic.log
@@ -328,6 +345,10 @@ help() {
328345
Will output logs using snazzy formatting when available or otherwise through a simple
329346
python formatter. This makes debugging easier from the GitHub Actions interface.
330347
348+
generate_github_summary
349+
Parse gotestsum JSON output and write a markdown summary to GITHUB_STEP_SUMMARY.
350+
Required env vars: TEST_PROVIDER, GITHUB_STEP_SUMMARY
351+
331352
print_tests
332353
Print the list of tests that would be run for each provider target.
333354
@@ -350,6 +371,9 @@ collect_logs)
350371
output_logs)
351372
output_logs
352373
;;
374+
generate_github_summary)
375+
generate_github_summary
376+
;;
353377
print_tests)
354378
set +x
355379
for target in github_public github_ghe_1 github_ghe_2 github_ghe_3 gitlab_bitbucket gitea_1 gitea_2 gitea_3 concurrency flaky; do

0 commit comments

Comments
 (0)