-
Notifications
You must be signed in to change notification settings - Fork 199
Print summary of test failures #5966
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
Open
janniklasrose
wants to merge
6
commits into
main
Choose a base branch
from
janniklasrose/summarize-failed-tests-in-ci
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+108
−0
Open
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
cd5ee7c
Print summary of test failures
janniklasrose 6d8cd67
Force some test failures
janniklasrose e6b01bb
Revert "Force some test failures"
janniklasrose 2b460b9
Use tools script instead of inline bash
janniklasrose 7497a34
Force some test failures
janniklasrose ebe3bd7
Revert "Force some test failures"
janniklasrose File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| #!/usr/bin/env python3 | ||
| # /// script | ||
| # requires-python = ">=3.12" | ||
| # /// | ||
| """ | ||
| Summarize failed tests from a gotestsum --jsonfile output for a GitHub job summary. | ||
|
|
||
| `task test` prints a lot of output that GitHub is slow to render, so this surfaces | ||
| just the failed test names as a Markdown table. It reads the concatenated | ||
| gotestsum --jsonfile output (go test -json events, one JSON object per line) and | ||
| prints Markdown to stdout; the workflow tees that into $GITHUB_STEP_SUMMARY. | ||
| """ | ||
|
|
||
| import argparse | ||
| import json | ||
|
|
||
| # go test -json result actions. Only these mark the terminal state of a test or | ||
| # package; intermediate actions like "run" and "output" are ignored. | ||
| RESULT_ACTIONS = ("pass", "fail", "skip") | ||
|
|
||
|
|
||
| def load_events(path): | ||
| """Yield the result events (parsed JSON objects) from a gotestsum jsonfile.""" | ||
| with open(path, encoding="utf-8") as f: | ||
| for line in f: | ||
| line = line.strip() | ||
| if not line: | ||
| continue | ||
| event = json.loads(line) | ||
| if event.get("Action") in RESULT_ACTIONS: | ||
| yield event | ||
|
|
||
|
|
||
| def last_action_by_key(events, key): | ||
| """Map each key to the Action of its last event.""" | ||
| last = {} | ||
| for event in events: | ||
| last[key(event)] = event["Action"] | ||
| return last | ||
|
|
||
|
|
||
| def failed_tests(events): | ||
| """Return sorted (package, test) pairs whose last result was a failure. | ||
|
|
||
| A test can appear more than once because of --rerun-fails, so we group by | ||
| package+test and keep only those whose last result was a failure (recovered | ||
| flakes end on "pass"). | ||
| """ | ||
| test_events = [e for e in events if e.get("Test") is not None] | ||
| last = last_action_by_key(test_events, lambda e: (e["Package"], e["Test"])) | ||
| return sorted(key for key, action in last.items() if action == "fail") | ||
|
|
||
|
|
||
| def failed_packages_without_test(events, failed_test_packages): | ||
| """Return sorted packages that failed with no failing test (build error / panic). | ||
|
|
||
| A build error or panic surfaces as a package-level "fail" event (Test == null) | ||
| with no failing test in the package. go test -json also emits a package-level | ||
| "fail" for every package that merely has a failing test, so exclude packages | ||
| already reported via failed_tests; otherwise those get double-reported here as | ||
| spurious build errors. | ||
| """ | ||
| package_events = [e for e in events if e.get("Test") is None] | ||
| last = last_action_by_key(package_events, lambda e: e["Package"]) | ||
| return sorted( | ||
| package for package, action in last.items() if action == "fail" and package not in failed_test_packages | ||
| ) | ||
|
|
||
|
|
||
| def render(tests, packages): | ||
| lines = ["## Failed tests"] | ||
| if tests: | ||
| lines += ["", "| Package | Test |", "| --- | --- |"] | ||
| lines += [f"| {package} | `{test}` |" for package, test in tests] | ||
| if packages: | ||
| lines += ["", "### Packages that failed without a test (build error / panic)", "", "```"] | ||
| lines += packages | ||
| lines += ["```"] | ||
| if not tests and not packages: | ||
| lines += ["", "No failed tests found in test-output.json (the failure may be outside the test run)."] | ||
| return "\n".join(lines) | ||
|
|
||
|
|
||
| def main(): | ||
| parser = argparse.ArgumentParser(description=__doc__) | ||
| parser.add_argument("jsonfile", help="Path to the gotestsum --jsonfile output") | ||
| args = parser.parse_args() | ||
|
|
||
| try: | ||
| events = list(load_events(args.jsonfile)) | ||
| except FileNotFoundError: | ||
| print(f"{args.jsonfile} not found; skipping failed-test summary") | ||
| return | ||
|
|
||
| tests = failed_tests(events) | ||
| packages = failed_packages_without_test(events, {package for package, _ in tests}) | ||
| print(render(tests, packages)) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.