fix(git-tools): ci-queue-wait mishandles Gitea statuses:null — push guard hard-fails on any repo without CI
ci/woodpecker/pr/ci Pipeline failed
ci/woodpecker/pr/ci Pipeline failed
Gitea's combined-status endpoint returns statuses:null (not []) plus a synthetic aggregate state of "pending" for a commit with zero status contexts (captured live 2026-08-09). The bash parser called that payload malformed -> ASSERTED_NOT_READY exit 3, blocking every push to a CI-less repo; hit twice by velma on two independent clones (shared checkout + fresh sparse clone), proving it environment-independent. - treat statuses:null as empty (both .sh and .ps1) - classify zero contexts as no-status BEFORE consulting the synthetic aggregate state (both twins; honoring it would poll to timeout) - no-status on --purpose push without --require-status is now queue-clear exit 0 (a repo with no CI has no queue), mirroring record_cannot_assert dispositions (push=degraded-pass, merge=hold); merge + --require-status stay fail-closed at exit 3 - red-first regression harness test-ci-queue-wait-no-status.sh (5 cases, incl. the verbatim live Gitea payload and a genuine-pending guard); branch-absent harness still green Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_013SAYFkRhQfhguY7AHfiUC8
This commit is contained in:
co-authored by
Claude Fable 5
parent
4df478cdd1
commit
74b3b9e869
@@ -52,7 +52,11 @@ except Exception:
|
||||
print("malformed")
|
||||
raise SystemExit(0)
|
||||
|
||||
# Gitea returns "statuses": null (not []) for a commit with zero status
|
||||
# contexts -- e.g. any repo with no CI configured. Treat null as empty.
|
||||
raw_statuses = payload.get("statuses", [])
|
||||
if raw_statuses is None:
|
||||
raw_statuses = []
|
||||
raw_state = payload.get("state", "")
|
||||
if not isinstance(raw_statuses, list) or not isinstance(raw_state, str):
|
||||
print("malformed")
|
||||
@@ -75,14 +79,18 @@ for item in statuses:
|
||||
raise SystemExit(0)
|
||||
values.append(raw_value.lower())
|
||||
|
||||
if any(value in pending_values for value in values) or state in pending_values:
|
||||
# Zero contexts is classified FIRST: Gitea reports a synthetic aggregate
|
||||
# state of "pending" alongside total_count:0, and an aggregate with no
|
||||
# contexts behind it must not read as an in-flight pipeline (it would poll
|
||||
# to the timeout). With zero contexts there is nothing to wait on.
|
||||
if not values:
|
||||
print("no-status")
|
||||
elif any(value in pending_values for value in values) or state in pending_values:
|
||||
print("pending")
|
||||
elif any(value in failure_values for value in values) or state in failure_values:
|
||||
print("terminal-failure")
|
||||
elif values and all(value in success_values for value in values) and state in {"", "success"}:
|
||||
elif all(value in success_values for value in values) and state in {"", "success"}:
|
||||
print("terminal-success")
|
||||
elif not values:
|
||||
print("no-status")
|
||||
else:
|
||||
print("unknown")
|
||||
'
|
||||
@@ -465,9 +473,18 @@ while true; do
|
||||
no-status)
|
||||
if [[ "$REQUIRE_STATUS" -eq 1 ]]; then
|
||||
echo "Error: ASSERTED_NOT_READY state=no-status; --require-status was set for ${BRANCH}." >&2
|
||||
else
|
||||
echo "Error: ASSERTED_NOT_READY state=no-status purpose=${PURPOSE} branch=${BRANCH}." >&2
|
||||
exit 3
|
||||
fi
|
||||
# A head with zero status contexts has no CI queue to wait on.
|
||||
# For push, that is queue-clear (a repo with no CI must remain
|
||||
# pushable) -- mirroring record_cannot_assert's dispositions
|
||||
# (push=degraded-pass, merge=hold). Merge stays fail-closed:
|
||||
# no-status there may just mean CI has not reported yet.
|
||||
if [[ "$PURPOSE" == "push" ]]; then
|
||||
echo "[ci-queue-wait] no status contexts on ${BRANCH} head (state=no-status) — no CI queue to wait on; queue clear."
|
||||
exit 0
|
||||
fi
|
||||
echo "Error: ASSERTED_NOT_READY state=no-status purpose=${PURPOSE} branch=${BRANCH}." >&2
|
||||
exit 3
|
||||
;;
|
||||
terminal-failure|malformed|unknown)
|
||||
|
||||
Reference in New Issue
Block a user