Files
.pouch/skills/builder/templates/ci-status/curl.sh
T
laily 9ba9b3da0f feat(builder): query CI via project status script
When BUILD_VENUE=ci, init confirms tea/glab/gh/curl (or a custom
command) and writes .pouch/builder/ci-status.sh. wait_ci.sh only
polls that script and no longer guesses forge CLIs.
2026-10-15 09:56:51 +08:00

100 lines
3.4 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
# Query Gitea Actions for an exact SHA via curl. Output STATUS= keys.
# Auth: GITEA_TOKEN in the environment or .env.builder. GITEA_API_URL optional.
sha=
while (($#)); do
case "$1" in
--sha) sha=$2; shift 2 ;;
*) echo "Usage: ci-status.sh --sha SHA" >&2; exit 2 ;;
esac
done
[[ -n "$sha" ]] || { echo "Usage: ci-status.sh --sha SHA" >&2; exit 2; }
if ! command -v curl >/dev/null 2>&1; then
echo "Error: curl is required" >&2
exit 3
fi
root=${BUILDER_PROJECT_ROOT:-$(git rev-parse --show-toplevel)}
origin=$(git -C "$root" remote get-url origin 2>/dev/null || true)
[[ -n "$origin" ]] || { echo "Error: no origin remote" >&2; exit 3; }
read -r host path base <<<"$(WAIT_CI_ORIGIN=$origin python3 -c '
import os, re
url = os.environ["WAIT_CI_ORIGIN"].strip()
url = re.sub(r"^git@([^:]+):", r"ssh://git@\1/", url)
url = re.sub(r"^ssh://git@([^/]+):", r"ssh://git@\1/", url)
if re.match(r"^https?://", url):
m = re.match(r"^(https?)://([^/]+)(?:/(.*))?$", url)
scheme, host, path = (m.group(1), m.group(2), m.group(3) or "") if m else ("", "", "")
else:
m = re.match(r"^ssh://git@([^/]+)/(.+)$", url)
scheme, host, path = ("https", m.group(1), m.group(2)) if m else ("", "", "")
path = re.sub(r"\.git$", "", path)
print(host, path, (scheme or "https") + "://" + host)
')"
api=${GITEA_API_URL:-$base/api/v1}
api=${api%/}
[[ "$api" == */api/v1 ]] || api+=/api/v1
repo=$(WAIT_CI_PATH=$path python3 -c 'import os,urllib.parse; print(urllib.parse.quote(os.environ["WAIT_CI_PATH"], safe="/"))')
gitea_curl() {
if [[ -n "${GITEA_TOKEN:-}" ]]; then
curl -fsS --retry 2 --connect-timeout 10 --max-time 30 \
--config <(printf 'header = "Authorization: token %s"\n' "$GITEA_TOKEN") "$1"
else
curl -fsS --retry 2 --connect-timeout 10 --max-time 30 "$1"
fi
}
set +e
runs=$(gitea_curl "${api}/repos/${repo}/actions/runs?head_sha=${sha}&limit=20&page=1")
rc=$?
set -e
if [[ $rc -ne 0 ]]; then
echo "Error: curl cannot read Gitea Actions for $path" >&2
exit 3
fi
python3 -c '
import json, sys
sha = sys.argv[1]
try:
data = json.loads(sys.stdin.read())
except json.JSONDecodeError:
print("STATUS=error")
raise SystemExit(0)
if isinstance(data, dict) and data.get("message") and not (data.get("workflow_runs") or data.get("runs")):
print("STATUS=error")
raise SystemExit(0)
runs = data.get("workflow_runs", data.get("runs", [])) if isinstance(data, dict) else data
if not isinstance(runs, list) or not runs:
print("STATUS=empty")
raise SystemExit(0)
matched = []
for run in runs:
head = run.get("head_sha") or run.get("headSha") or (run.get("head_commit") or {}).get("id")
if head and head.lower() == sha.lower() and (run.get("id") or run.get("database_id")):
matched.append(run)
if not matched:
print("STATUS=empty")
raise SystemExit(0)
run = matched[0]
run_id = run.get("id") or run.get("database_id")
url = run.get("html_url") or run.get("web_url") or run.get("url") or "-"
status = str(run.get("status") or "").lower()
conclusion = str(run.get("conclusion") or run.get("result") or "").lower()
if conclusion in ("failure", "failed", "cancelled", "canceled", "skipped", "timed_out"):
state = "failed"
elif status in ("completed", "success") and conclusion in ("", "success", "succeeded"):
state = "success"
elif status == "completed" and conclusion:
state = "failed"
else:
state = "running"
print("STATUS=%s ID=%s PIPELINE=%s" % (state, run_id, url))
' "$sha" <<<"$runs"