Skip to content

feat(gpush): print what a failed CI run reported - #372

Merged
twistedmelonman merged 1 commit into
mainfrom
claude/feat-gpush-failure-detail-8a854048
Sep 25, 2026
Merged

twistedmelonman merged 1 commit into
mainfrom
claude/feat-gpush-failure-detail-8a854048

Conversation

@twistedmelonman

Copy link
Copy Markdown
Owner

What

When CI failed, gpush printed one line: CI failed (Standards Check: failure). To see which linter failed, you had to open the run in a browser.

gpush now prints what each failed job reported before that line:

[gpush] Standards Check / standards-check / run-standards-check reported:
    shellcheck found problems
    standards-check: 1 linter(s) failed
    Details: https://github.com/twistedmelonman/claude-config/actions/runs/35944355297/job/107458893019

That is real output from the new helper, run against a real failed run from 2026-09-24.

How it works (_gpush_print_failure_detail in bash/gpush-wrapper.sh):

  1. Lists the run's jobs that did not succeed. A job's databaseId is also its check-run id.
  2. Reads that check run's annotations. It keeps failure and warning levels and sorts them by start_line, because the API returns them newest first. It drops notices and the runner's Process completed with exit code N line. When an annotation has a title, it prints the title first. Since feat(standards): name what failed, not just that something did smartwatermelon/github-workflows#176, the title is the linter name and the message holds up to 20 lines of findings.
  3. If a job has no readable annotations, it prints the ##[error] lines from gh run view --job <id> --log-failed. The raw log is never printed. For this run it was 549 lines, almost all checkout output.
  4. Stops at 40 lines per job and says how many lines it left out. The job URL comes last.

The CI failed (...) line and the exit code have not changed. A failed read in the helper only means less output. It can't change how gpush exits.

Token check

Fine-grained PATs can't read some Checks endpoints, so I tested this one before writing any code. With the twistedmelonman fine-grained PAT (github_pat_ prefix), against twistedmelonman/claude-config run 35944355297, job 107458893019:

  • gh api repos/.../check-runs/107458893019/annotations returned all 7 annotations.
  • gh run view --job 107458893019 --log-failed returned the log, including 3 ##[error] lines.

So this annotations endpoint reads fine with that token type. (An earlier dev-env note records that GraphQL CheckRuns come back null under a fine-grained PAT. I did not re-measure that here.)

Not verified: gpush in an interactive shell with no GH_TOKEN set, which uses the keyring identity. I can't test that path, since agents are barred from the keychain. An OAuth token should have at least the same access, but no one has measured it.

The live run above predates #176, so its annotations have no titles and no findings. No run in the new format has failed yet, so I couldn't observe one live. What the live run proves is the mechanism: the endpoint, the token, and the job-to-check-run id mapping. The test fixture covers the new format: a titled annotation with findings on several lines.

Tests

New bash/tests/test-gpush-wrapper-failure-detail.sh runs gpush end to end with stub git and gh binaries on PATH. The stub gh passes the wrapper's own -q/--jq expressions through real jq. That way the test checks the real filters, not copies of them. Fixture shapes come from the live run above.

Against origin/main's gpush-wrapper.sh, 6 of its 11 checks fail (known-bad):

  • linter annotation title and finding are printed
  • final error annotation is printed
  • annotations are printed oldest first
  • failed job URL is printed
  • empty annotations fall back to the log's error lines only
  • long annotations are cut to the line limit with a count

The other five are guards and pass on both: the exit code, the summary line, dropped notices, no query for successful jobs, and a passing run printing nothing extra.

The full suite ran in pre-push: 35 passed, 0 failed. shellcheck -S info is clean on both files.

test-my-prs-issues.sh failed once when I ran the suite with the shell's cwd outside the repo. It fails the same way on the clean main checkout (caller cwd unchanged — expected [.../dotfiles], got [.../dev-env]), so this change didn't cause it. It passed in the pre-push run.

Closes smartwatermelon/dev-env#113

When a CI run failed, gpush printed only "CI failed (Standards Check:
failure)", so finding the failed linter meant opening the run in a browser.

For each failed job, gpush now prints the job's check-run annotations,
at most 40 lines per job, followed by the job URL. It prints failure and
warning levels only, sorted by start_line: the API returns them newest
first. Notices and the runner's "Process completed with exit code N"
line are dropped. When a job has no readable annotations, gpush prints
the "##[error]" lines of its failed-step log instead. It never prints
the raw log, which is mostly checkout noise.

The "CI failed (...)" line and the exit code are unchanged. The added
calls cannot change the exit path; a failed read just prints less.

Measured 2026-09-25 with a fine-grained PAT against
twistedmelonman/claude-config run 35944355297: the annotations endpoint
and `gh run view --job <id> --log-failed` both returned data, and the
job's databaseId is the check-run id.

Test: bash/tests/test-gpush-wrapper-failure-detail.sh runs gpush end to
end against stub git and gh (the stub gh runs the wrapper's jq filters
through real jq). Against origin/main's wrapper, 6 of its 11 checks fail.

Closes smartwatermelon/dev-env#113
@claude

This comment has been minimized.

@claude

claude Bot commented Sep 25, 2026

Copy link
Copy Markdown

No blocking issues found. The new failure-detail function correctly filters and displays CI annotations, gracefully degrades on API errors, and integrates safely into the existing gpush flow. Array handling under set -u is correct, and output formatting is secure.

VERDICT: PASS

@twistedmelonman
twistedmelonman merged commit 8b68da2 into main Sep 25, 2026
5 checks passed
@twistedmelonman
twistedmelonman deleted the claude/feat-gpush-failure-detail-8a854048 branch September 25, 2026 22:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

standards check must describe actual failure rather than just pass or fail

1 participant