#!/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