#!/bin/bash # ci-queue-wait.sh - Wait until project CI queue is clear (no running/queued pipeline on branch head) # Usage: ci-queue-wait.sh [-B branch] [-t timeout_sec] [-i interval_sec] [--purpose push|merge] [--require-status] set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/detect-platform.sh" BRANCH="main" TIMEOUT_SEC=900 INTERVAL_SEC=15 PURPOSE="merge" REQUIRE_STATUS=0 usage() { cat <&2 usage >&2 exit 1 ;; esac done if ! [[ "$TIMEOUT_SEC" =~ ^[0-9]+$ ]] || ! [[ "$INTERVAL_SEC" =~ ^[0-9]+$ ]]; then echo "Error: timeout and interval must be integer seconds." >&2 exit 1 fi OWNER=$(get_repo_owner) REPO=$(get_repo_name) detect_platform > /dev/null PLATFORM="${PLATFORM:-unknown}" if [[ "$PLATFORM" == "github" ]]; then if ! command -v gh >/dev/null 2>&1; then echo "Error: gh CLI is required for GitHub CI queue guard." >&2 exit 1 fi HEAD_SHA=$(github_get_branch_head_sha "$OWNER" "$REPO" "$BRANCH") if [[ -z "$HEAD_SHA" ]]; then echo "Error: Could not resolve ${BRANCH} head SHA." >&2 exit 1 fi echo "[ci-queue-wait] platform=github purpose=${PURPOSE} branch=${BRANCH} sha=${HEAD_SHA}" elif [[ "$PLATFORM" == "gitea" ]]; then HOST=$(get_remote_host) || { echo "Error: Could not determine remote host." >&2 exit 1 } TOKEN=$(get_gitea_token "$HOST") || { echo "Error: Gitea token not found. Set GITEA_TOKEN or configure ~/.git-credentials." >&2 exit 1 } HEAD_SHA=$(gitea_get_branch_head_sha "$HOST" "$OWNER/$REPO" "$BRANCH" "$TOKEN") if [[ -z "$HEAD_SHA" ]]; then echo "Error: Could not resolve ${BRANCH} head SHA." >&2 exit 1 fi echo "[ci-queue-wait] platform=gitea purpose=${PURPOSE} branch=${BRANCH} sha=${HEAD_SHA}" else echo "Error: Unsupported platform '${PLATFORM}'." >&2 exit 1 fi START_TS=$(date +%s) DEADLINE_TS=$((START_TS + TIMEOUT_SEC)) while true; do NOW_TS=$(date +%s) if (( NOW_TS > DEADLINE_TS )); then echo "Error: Timed out waiting for CI queue to clear on ${BRANCH} after ${TIMEOUT_SEC}s." >&2 exit 124 fi if [[ "$PLATFORM" == "github" ]]; then STATUS_JSON=$(github_get_commit_status_json "$OWNER" "$REPO" "$HEAD_SHA") else STATUS_JSON=$(gitea_get_commit_status_json "$HOST" "$OWNER/$REPO" "$HEAD_SHA" "$TOKEN") fi STATE=$(printf '%s' "$STATUS_JSON" | get_state_from_status_json) echo "[ci-queue-wait] state=${STATE} purpose=${PURPOSE} branch=${BRANCH}" case "$STATE" in pending) printf '%s' "$STATUS_JSON" | print_pending_contexts sleep "$INTERVAL_SEC" ;; no-status) if [[ "$REQUIRE_STATUS" -eq 1 ]]; then echo "Error: No CI status contexts found for ${BRANCH} while --require-status is set." >&2 exit 1 fi echo "[ci-queue-wait] no status contexts present; proceeding." exit 0 ;; terminal-success|terminal-failure|unknown) # Queue guard only blocks on pending/running/queued states. exit 0 ;; *) echo "[ci-queue-wait] unrecognized state '${STATE}', proceeding conservatively." exit 0 ;; esac done