Files
MoShiro/ci/wait-for-checks.sh
T
justme 5c00ec434e
ci/woodpecker/push/web-build Pipeline was successful
ci/woodpecker/push/verify Pipeline was successful
ci/woodpecker/push/dev-image Pipeline was successful
fix(ci): read the commit status from the public Gitea address [CI]
2026-10-19 14:03:46 +08:00

70 lines
2.9 KiB
Bash

#!/usr/bin/env bash
# 推镜像之前的闸门:等这个提交的 verify(后端快速测试)和 web-build 两个 workflow 都成功。
# 镜像构建不再等它们(开发镜像的构建和测试并行跑,关键路径少了测试那一段);构建好之后、推送之前才来这里等结果,
# 任何一个失败就不推(和以前「测试没过不出镜像」一样)。
# 用法:wait-for-checks.sh (环境:CI_COMMIT_SHA、CI_REPO 是 Woodpecker 提供的;MOSHIRO_FORGE_URL 可选)
set -euo pipefail
sha="${CI_COMMIT_SHA:?CI_COMMIT_SHA is required}"
repo="${CI_REPO:?CI_REPO is required}"
# CI_FORGE_URL 是 Woodpecker 到 Gitea 的内部地址(http://gitea:3000),构建步骤的环境里解析不了;用公开地址
forge="${MOSHIRO_FORGE_URL:-https://git.oeo.one}"
required=("ci/woodpecker/push/verify" "ci/woodpecker/push/web-build")
# 总共最多等这么久(秒);一个 workflow 在这么久之后还没出现,说明它没有被触发,当作失败,免得一直挂着
timeout_s="${MOSHIRO_CHECKS_TIMEOUT:-1200}"
interval_s="${MOSHIRO_CHECKS_INTERVAL:-5}"
auth=()
[[ -n "${GITEA_TOKEN:-}" ]] && auth=(-H "Authorization: token $GITEA_TOKEN")
status_of() {
# 每个 context 的最新状态;没有这个 context 输出 absent
local body="$1" context="$2"
python3 - "$context" "$body" <<'PY'
import json, sys
context, body = sys.argv[1], sys.argv[2]
try:
statuses = json.loads(body).get("statuses") or []
except ValueError:
print("unknown"); sys.exit(0)
matches = [s for s in statuses if s.get("context") == context]
print(matches[0].get("status", "unknown") if matches else "absent")
PY
}
deadline=$((SECONDS + timeout_s))
last=""
unreachable=0
while :; do
# 先直连(git.oeo.one 就在这台机器上,走代理回环反而可能不通),不行再用环境里的代理
url="$forge/api/v1/repos/$repo/commits/$sha/status"
body="$(curl -fsS --noproxy "*" --max-time 20 "${auth[@]}" "$url" 2>/dev/null || curl -fsS --max-time 20 "${auth[@]}" "$url" 2>/dev/null || true)"
if [[ -z "$body" ]]; then
unreachable=$((unreachable + 1))
if ((unreachable >= 12)); then echo "could not read the commit status from $forge; not pushing the images" >&2; exit 1; fi
sleep "$interval_s"
continue
fi
unreachable=0
summary=""
pending=0
for context in "${required[@]}"; do
state="$(status_of "$body" "$context")"
summary+="${context##*/}=$state "
case "$state" in
success) ;;
failure|error|killed|declined)
echo "check $context did not pass ($state); not pushing the images" >&2
exit 1
;;
*) pending=1 ;;
esac
done
[[ "$summary" == "$last" ]] || { echo "checks: $summary"; last="$summary"; }
[[ "$pending" == 0 ]] && exit 0
if ((SECONDS >= deadline)); then
echo "checks did not finish within ${timeout_s}s ($summary); not pushing the images" >&2
exit 1
fi
sleep "$interval_s"
done