70 lines
2.9 KiB
Bash
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
|