Mark superseded commits honestly instead of skipped (closes #152)
Some checks failed
check / check (push) Superseded by a newer commit; never tested
Some checks failed
check / check (push) Superseded by a newer commit; never tested
Gitea records a cancelled run as failure, and the #119 repair rewrote that to skipped. Gitea's Combine() folds skipped into success, so a commit nothing ever tested reported a combined green — observed on three commits on next, including the very change a prior integration review had failed a PR for. Superseded commits are now marked failure with an honest description, so never-tested no longer reads as passed and git bisect archaeology can tell "passed", "failed" and "never ran" apart. Option 1, re-running the superseded commit, was verified unreachable for automation on Gitea 1.25.4: no rerun endpoint, dispatches takes a ref not a SHA and lands under a different context, and CancelPreviousJobs is unconditional. The rewrite moves out of the workflow into script/ci-mark-superseded so the tested artifact is the shipped one, and every failure path in it is loud: an unparseable or empty ANCESTOR_LIMIT, an unreadable ancestor status, and a shallow clone all abort rather than exiting 0 having marked nothing. Each has a regression test. The status context is derived rather than hardcoded, which also closes #147 item 2; item 1 remains open. Independently reviewed four times. The final reviewer confirmed the shallow-clone test is genuinely shallow — a file:// URL is load-bearing, since git silently ignores --depth on a local path — and that deleting the guard fails that one test out of 331 and cannot pass for the wrong reason. They also reproduced deterministically that go test's cache serves a stale PASS after a script-only edit, which internal/ciscript's doc.go now records.
This commit was merged in pull request #161.
This commit is contained in:
@@ -13,39 +13,19 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 2024-10-23
|
||||
with:
|
||||
# The fingerprint step below needs history to find the last commit
|
||||
# that touched the Docker build context.
|
||||
# that touched the Docker build context, and the superseded-status
|
||||
# step needs it to walk ancestors (it aborts on a shallow clone).
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Neutralize superseded run statuses
|
||||
- name: Mark superseded run statuses
|
||||
# Gitea cancels the in-flight run when another commit is pushed to the
|
||||
# same branch and records the cancellation as `failure`, so a commit
|
||||
# that was never tested reads red. The cancellation is unconditional
|
||||
# server-side for push events and cannot be disabled from a workflow
|
||||
# file, so the superseding run rewrites those statuses to `skipped`.
|
||||
# Only the exact cancellation status is touched; a real failure is
|
||||
# left alone.
|
||||
# that was never tested reads as a test result. The script rewrites
|
||||
# those statuses to say what happened. See its header for why the
|
||||
# state stays `failure` and not `skipped`.
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
run: |
|
||||
set -eu
|
||||
api="${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}"
|
||||
ctx='check / check (push)'
|
||||
for sha in $(git rev-list --max-count=20 "${GITHUB_SHA}^" || true); do
|
||||
latest="$(curl -sf "${api}/commits/${sha}/status" | jq -r \
|
||||
--arg c "$ctx" \
|
||||
'[.statuses[] | select(.context == $c)][0] // empty
|
||||
| "\(.status)|\(.description)"')" || continue
|
||||
[ "$latest" = 'failure|Has been cancelled' ] || continue
|
||||
curl -sf -X POST "${api}/statuses/${sha}" \
|
||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d "$(jq -nc --arg c "$ctx" '{
|
||||
context: $c,
|
||||
state: "skipped",
|
||||
description: "Superseded by a newer commit; never tested"
|
||||
}')" >/dev/null
|
||||
echo "neutralized superseded status on ${sha}"
|
||||
done
|
||||
run: script/ci-mark-superseded
|
||||
|
||||
- name: Fingerprint the build context
|
||||
# `.dockerignore` keeps docs out of the build context, so a docs-only
|
||||
|
||||
Reference in New Issue
Block a user