chore: track ask-minimax-run, bg-model-call, wait-for-version, auto-draft (+spec/data) — were untracked
Claude-Session: https://claude.ai/code/session_015nXvGNNNixJPFwZKZHNyha
This commit is contained in:
209
scripts/wait-for-version
Executable file
209
scripts/wait-for-version
Executable file
@@ -0,0 +1,209 @@
|
||||
#!/usr/bin/env bash
|
||||
set -uo pipefail
|
||||
|
||||
DEFAULT_SERVER="https://gitea.oreillyit.nz"
|
||||
DEFAULT_TIMEOUT=300
|
||||
DEFAULT_INTERVAL=15
|
||||
DEFAULT_WORKFLOW="version"
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage: wait-for-version [OPTIONS] REPO
|
||||
|
||||
Poll a Gitea repo's Actions runs until the CI workflow for HEAD of main
|
||||
completes successfully, then print the latest release tag.
|
||||
|
||||
Arguments:
|
||||
REPO owner/name (e.g. skynet/hugo-accelerator)
|
||||
|
||||
Options:
|
||||
-t, --token TOKEN Gitea access token (else $GITEA_TOKEN / $GITHUB_TOKEN)
|
||||
--workflow NAME Workflow name to wait for (default: version)
|
||||
--timeout SECONDS Max total wait time (default: 300; 0 = poll once)
|
||||
--interval SECONDS Polling interval (default: 15; min: 1)
|
||||
--server URL Gitea base URL (else $GITHUB_SERVER_URL, else
|
||||
https://gitea.oreillyit.nz)
|
||||
-v, --verbose Print polling progress to stderr
|
||||
-n, --dryrun Show resolved configuration without making API calls
|
||||
-h, --help Show this help
|
||||
|
||||
Exit codes:
|
||||
0 CI succeeded; latest release tag printed to stdout
|
||||
1 timeout expired, CI failed, or no release tag found
|
||||
2 usage error
|
||||
3 terminal API error (401, 403, 404)
|
||||
EOF
|
||||
}
|
||||
|
||||
timeout=$DEFAULT_TIMEOUT
|
||||
interval=$DEFAULT_INTERVAL
|
||||
server="${GITHUB_SERVER_URL:-$DEFAULT_SERVER}"
|
||||
token="${GITEA_TOKEN:-${GITHUB_TOKEN:-}}"
|
||||
workflow="$DEFAULT_WORKFLOW"
|
||||
verbose=false
|
||||
dryrun=false
|
||||
repo=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-h|--help) usage; exit 0 ;;
|
||||
-n|--dryrun) dryrun=true; shift ;;
|
||||
-v|--verbose) verbose=true; shift ;;
|
||||
-t|--token)
|
||||
[[ $# -lt 2 ]] && { echo "Error: --token requires a value" >&2; exit 2; }
|
||||
token="$2"; shift 2 ;;
|
||||
--workflow)
|
||||
[[ $# -lt 2 ]] && { echo "Error: --workflow requires a value" >&2; exit 2; }
|
||||
workflow="$2"; shift 2 ;;
|
||||
--timeout)
|
||||
[[ $# -lt 2 ]] && { echo "Error: --timeout requires a value" >&2; exit 2; }
|
||||
timeout="$2"; shift 2 ;;
|
||||
--interval)
|
||||
[[ $# -lt 2 ]] && { echo "Error: --interval requires a value" >&2; exit 2; }
|
||||
interval="$2"; shift 2 ;;
|
||||
--server)
|
||||
[[ $# -lt 2 ]] && { echo "Error: --server requires a value" >&2; exit 2; }
|
||||
server="$2"; shift 2 ;;
|
||||
--) shift; break ;;
|
||||
-*) echo "Error: Unknown option: $1" >&2; exit 2 ;;
|
||||
*)
|
||||
if [[ -z "$repo" ]]; then repo="$1"
|
||||
else echo "Error: Unexpected argument: $1" >&2; exit 2
|
||||
fi
|
||||
shift ;;
|
||||
esac
|
||||
done
|
||||
|
||||
[[ -z "$repo" ]] && { echo "Error: REPO is required" >&2; echo >&2; usage >&2; exit 2; }
|
||||
[[ "$repo" != */* ]] && { echo "Error: REPO must be in 'owner/name' form (got: $repo)" >&2; exit 2; }
|
||||
[[ ! "$timeout" =~ ^[0-9]+$ ]] && { echo "Error: --timeout must be a non-negative integer (got: $timeout)" >&2; exit 2; }
|
||||
[[ ! "$interval" =~ ^[0-9]+$ ]] && { echo "Error: --interval must be a positive integer (got: $interval)" >&2; exit 2; }
|
||||
(( interval < 1 )) && { echo "Error: --interval must be >= 1" >&2; exit 2; }
|
||||
|
||||
api_base="${server%/}/api/v1/repos/${repo}"
|
||||
|
||||
if $dryrun; then
|
||||
echo "[dryrun] Server: ${server}"
|
||||
echo "[dryrun] Repo: ${repo}"
|
||||
echo "[dryrun] Workflow: ${workflow}"
|
||||
echo "[dryrun] Timeout: ${timeout}s"
|
||||
echo "[dryrun] Interval: ${interval}s"
|
||||
if [[ -n "$token" ]]; then
|
||||
echo "[dryrun] Auth: yes"
|
||||
else
|
||||
echo "[dryrun] Auth: no"
|
||||
fi
|
||||
echo "[dryrun] Actions API: ${api_base}/actions/runs"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
curl_args=(-sS -m 30 -w $'\n%{http_code}')
|
||||
[[ -n "$token" ]] && curl_args+=(-H "Authorization: token ${token}")
|
||||
|
||||
sha_response="$(curl "${curl_args[@]}" "${api_base}/branches/main" 2>/dev/null)"
|
||||
sha_rc=$?
|
||||
sha_http="${sha_response##*$'\n'}"
|
||||
sha_body="${sha_response%$'\n'*}"
|
||||
|
||||
if (( sha_rc != 0 )); then
|
||||
echo "Error: curl failed resolving HEAD SHA for ${repo} (rc=${sha_rc})" >&2
|
||||
exit 3
|
||||
fi
|
||||
|
||||
case "$sha_http" in
|
||||
200)
|
||||
sha="$(printf '%s' "$sha_body" | jq -r '.commit.id // empty' 2>/dev/null)"
|
||||
[[ -z "$sha" ]] && { echo "Error: could not extract HEAD SHA from branch response" >&2; exit 3; }
|
||||
;;
|
||||
401|403) echo "Error: Gitea API authentication failed (HTTP ${sha_http}) for ${repo}" >&2; exit 3 ;;
|
||||
404) echo "Error: repo not found: ${repo} (HTTP 404)" >&2; exit 3 ;;
|
||||
*) echo "Error: unexpected HTTP ${sha_http} resolving HEAD SHA for ${repo}" >&2; exit 3 ;;
|
||||
esac
|
||||
|
||||
echo "Waiting for '${workflow}' CI on ${repo} @ ${sha:0:8}..." >&2
|
||||
|
||||
start=$(date +%s)
|
||||
deadline=$(( start + timeout ))
|
||||
poll=0
|
||||
|
||||
while true; do
|
||||
poll=$(( poll + 1 ))
|
||||
|
||||
runs_response="$(curl "${curl_args[@]}" \
|
||||
"${api_base}/actions/runs?head_sha=${sha}&limit=50" 2>/dev/null)"
|
||||
runs_rc=$?
|
||||
|
||||
if (( runs_rc != 0 )); then
|
||||
$verbose && echo "wait-for-version: poll ${poll}: curl error (rc=${runs_rc})" >&2
|
||||
else
|
||||
http_code="${runs_response##*$'\n'}"
|
||||
body="${runs_response%$'\n'*}"
|
||||
|
||||
case "$http_code" in
|
||||
200)
|
||||
status="$(printf '%s' "$body" | jq -r \
|
||||
--arg w "$workflow" \
|
||||
'[.workflow_runs[] | select(.path | test($w + "\\.ya?ml"))] | first | .status // "pending"' \
|
||||
2>/dev/null)"
|
||||
conclusion="$(printf '%s' "$body" | jq -r \
|
||||
--arg w "$workflow" \
|
||||
'[.workflow_runs[] | select(.path | test($w + "\\.ya?ml"))] | first | .conclusion // ""' \
|
||||
2>/dev/null)"
|
||||
|
||||
if [[ "$status" == "completed" ]]; then
|
||||
if [[ "$conclusion" == "success" ]]; then
|
||||
# Resolve tag by SHA match — avoids races with release creation
|
||||
# and works regardless of whether the repo uses Gitea releases.
|
||||
# When multiple tags share the SHA (e.g. v0.0.8 and v0.0.8.14),
|
||||
# prefer the 3-component semver root (fewest dot-components).
|
||||
tag_response="$(curl "${curl_args[@]}" "${api_base}/tags?limit=50" 2>/dev/null)"
|
||||
tag_http="${tag_response##*$'\n'}"
|
||||
tag_body="${tag_response%$'\n'*}"
|
||||
if [[ "$tag_http" != "200" ]]; then
|
||||
echo "Error: could not fetch tags for ${repo} (HTTP ${tag_http})" >&2
|
||||
exit 1
|
||||
fi
|
||||
tag="$(printf '%s' "$tag_body" | jq -r --arg sha "$sha" \
|
||||
'[.[] | select(.commit.sha == $sha)] |
|
||||
sort_by(.name | ltrimstr("v") | split(".") | length) |
|
||||
first | .name // empty' 2>/dev/null)"
|
||||
if [[ -n "$tag" ]]; then
|
||||
$verbose && echo "wait-for-version: poll ${poll}: success, tag=${tag}" >&2
|
||||
echo "$tag"
|
||||
exit 0
|
||||
else
|
||||
echo "Error: no tag found for ${repo} @ ${sha:0:8}" >&2
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "Error: CI failed for ${repo} @ ${sha:0:8} (conclusion: ${conclusion})" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
$verbose && echo "wait-for-version: poll ${poll}: status=${status:-pending}, retrying" >&2
|
||||
;;
|
||||
401|403)
|
||||
echo "Error: Gitea API authentication failed (HTTP ${http_code}) for ${repo}" >&2
|
||||
exit 3 ;;
|
||||
404)
|
||||
echo "Error: repo not found: ${repo} (HTTP 404)" >&2
|
||||
exit 3 ;;
|
||||
*)
|
||||
$verbose && echo "wait-for-version: poll ${poll}: HTTP ${http_code}, retrying" >&2
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
now=$(date +%s)
|
||||
if (( now >= deadline )); then
|
||||
break
|
||||
fi
|
||||
remaining=$(( deadline - now ))
|
||||
sleep_time=$interval
|
||||
(( sleep_time > remaining )) && sleep_time=$remaining
|
||||
$verbose && echo "wait-for-version: poll ${poll}: sleeping ${sleep_time}s (${remaining}s remaining)" >&2
|
||||
sleep "$sleep_time"
|
||||
done
|
||||
|
||||
echo "Error: timeout after ${timeout}s waiting for '${workflow}' CI on ${repo} @ ${sha:0:8}" >&2
|
||||
exit 1
|
||||
Reference in New Issue
Block a user