9ba9b3da0f
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.
81 lines
2.6 KiB
Bash
Executable File
81 lines
2.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# Query Gitea Actions for an exact SHA via tea. Output STATUS= keys.
|
|
|
|
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 tea >/dev/null 2>&1; then
|
|
echo "Error: tea 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; }
|
|
path=$(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)
|
|
path = m.group(1) if m else ""
|
|
else:
|
|
m = re.match(r"^ssh://git@[^/]+/(.+)$", url)
|
|
path = m.group(1) if m else ""
|
|
print(re.sub(r"\.git$", "", path or ""))
|
|
')
|
|
[[ -n "$path" ]] || { echo "Error: cannot parse origin" >&2; exit 3; }
|
|
|
|
set +e
|
|
runs=$(tea api "repos/${path}/actions/runs?head_sha=${sha}&limit=20")
|
|
rc=$?
|
|
set -e
|
|
if [[ $rc -ne 0 ]]; then
|
|
echo "Error: tea cannot read 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 = [run for run in runs if str(run.get("head_sha") or run.get("headSha") or "").lower() == sha.lower()]
|
|
if not matched:
|
|
print("STATUS=empty")
|
|
raise SystemExit(0)
|
|
run = matched[0]
|
|
run_id = run.get("id") or run.get("database_id") or "-"
|
|
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"
|