docs(merge-gate): confirm post-merge jobs by commit SHA, not run list#75
docs(merge-gate): confirm post-merge jobs by commit SHA, not run list#75CybotTM wants to merge 1 commit into
Conversation
After merge the base branch fires its own runs. Querying them via 'gh run list --jq select(.headSha==SHA)' is unreliable: the list window is small and time-ordered, so a still-running job scrolls out and the filter returns empty — which feeds a 'gh run view ""' 404 and tempts a hand-rolled poll loop that times out. Document the authoritative SHA-addressed check-runs/status API instead, plus the 'prefer gh pr checks --watch' rule and a 'pre-existing red != your regression' check against the parent commit. Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
|
There was a problem hiding this comment.
Code Review
This pull request adds a new section to the merge-gate-watcher.md reference document, detailing how to confirm merge-triggered jobs post-merge using the commit SHA rather than the run list. The review feedback recommends using optional chaining in the jq expressions (such as .mergeCommit?.oid and .check_runs[]?) to gracefully handle missing or null fields and prevent fatal jq errors when parsing GitHub API responses.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| After merge, the base branch (`main`) fires its own runs (CI, release, deploy). To confirm those, query the **commit's** checks keyed on the merge SHA — never filter `gh run list` by `headSha`: | ||
|
|
||
| ```bash | ||
| SHA=$(gh pr view $PR --repo $R --json mergeCommit --jq '.mergeCommit.oid') |
There was a problem hiding this comment.
To prevent fatal jq errors if the pull request is inaccessible or the API response is unexpected, use optional chaining (.mergeCommit?.oid) when parsing the JSON response.
| SHA=$(gh pr view $PR --repo $R --json mergeCommit --jq '.mergeCommit.oid') | |
| SHA=$(gh pr view $PR --repo $R --json mergeCommit --jq '.mergeCommit?.oid') |
References
- When parsing GitHub API responses with jq, use optional chaining to handle potentially null or missing objects gracefully and prevent fatal jq errors.
|
|
||
| ```bash | ||
| SHA=$(gh pr view $PR --repo $R --json mergeCommit --jq '.mergeCommit.oid') | ||
| gh api repos/$R/commits/$SHA/check-runs --jq '.check_runs[]|{name,status,conclusion}' |
There was a problem hiding this comment.
To prevent fatal jq errors (such as Cannot iterate over null) if the API call fails or returns an unexpected response, use optional chaining (.check_runs[]?) when iterating over the check runs.
| gh api repos/$R/commits/$SHA/check-runs --jq '.check_runs[]|{name,status,conclusion}' | |
| gh api repos/$R/commits/$SHA/check-runs --jq '.check_runs[]?|{name,status,conclusion}' |
References
- When parsing GitHub API responses with jq, use optional chaining to handle potentially null or missing objects gracefully and prevent fatal jq errors.
|
|
||
| `gh run list --json … --jq 'select(.headSha=="'$SHA'")'` is unreliable here: the list window is small and time-ordered, so a still-running `main` job scrolls out behind unrelated activity and the filter returns empty — which then feeds a `gh run view ""` (HTTP 404) and tempts a hand-rolled `sleep`-poll loop that just times out. The check-runs/status API is authoritative and SHA-addressed. For PR-head checks, `gh pr checks $PR --watch` already blocks to completion — prefer it over any custom loop. | ||
|
|
||
| **Pre-existing red ≠ your regression.** If a post-merge gate (e.g. SonarCloud "Quality Gate failed" on N Security Hotspots) is red, check the *prior* base commit before owning it: `gh api repos/$R/commits/<prev-sha>/check-runs --jq '.check_runs[]|select(.name=="<gate>")|.conclusion'`. Identical red on the parent + a diff that touched no relevant code = a pre-existing backlog to report, not a regression to fix. |
There was a problem hiding this comment.
To prevent fatal jq errors if the API response is unexpected or the commit is not found, use optional chaining (.check_runs[]?) when filtering the check runs:
gh api repos/$R/commits/<prev-sha>/check-runs --jq '.check_runs[]?|select(.name=="<gate>")|.conclusion'References
- When parsing GitHub API responses with jq, use optional chaining to handle potentially null or missing objects gracefully and prevent fatal jq errors.



Summary
references/merge-gate-watcher.md.gh api repos/$R/commits/$SHA/check-runs(+/status) — authoritative and SHA-addressed — instead ofgh run list --jq 'select(.headSha==SHA)', which is unreliable for post-merge base-branch runs (small, time-ordered list window → still-running jobs scroll out → empty filter →gh run view ""404 → hand-rolled poll loop that times out).gh pr checks --watchover custom loops" rule and a "pre-existing red ≠ your regression" check against the parent commit (e.g. a SonarCloud hotspot gate already red on the base).Motivation
Hit exactly this during a
pr-finishrun: post-mergemainCI watched viagh run list | jq select(headSha)returned empty, cascading into a 404 and a 2-minute timed-out poll loop. The check-runs API resolved it in one call. Complements the existing watcher loop (which is pre-merge) with the post-merge step thatpull-request-workflow.mdstep 6 ("confirm merge-triggered async jobs") relies on.Validation
markdownlint-cli2: 0 errorspre-commit run --files …: all applicable hooks Passed (version-parity skipped — reference-only change, no version bump needed)