#!/usr/bin/env bash set -euo pipefail ROOT="$(cd "$(dirname "$0")/.." && pwd)" BASE_REF="${BASE_REF:-}" SKIP_FETCH=0 usage() { cat <<'EOF' Usage: bash scripts/check-release-ready.sh [--skip-fetch] Blocks releases unless the repository is on a named branch, the branch is not behind origin/main, and the worktree is clean. Environment: BASE_REF Base ref to compare against. Defaults to origin/main when available. ALLOW_MAIN_RELEASE=1 Allow publishing directly from main/master. EOF } while [[ $# -gt 0 ]]; do case "$1" in --skip-fetch) SKIP_FETCH=1 ;; -h|--help) usage exit 0 ;; *) echo "Unknown argument: $1" >&2 usage >&2 exit 1 ;; esac shift done git -C "${ROOT}" rev-parse --is-inside-work-tree >/dev/null branch="$(git -C "${ROOT}" branch --show-current)" if [[ -z "${branch}" ]]; then echo "Release check failed: detached HEAD is not a release source." >&2 exit 1 fi case "${branch}" in main|master) if [[ "${ALLOW_MAIN_RELEASE:-0}" != "1" ]]; then echo "Release check failed: publish from a dedicated release/feature branch, not ${branch}." >&2 echo "Set ALLOW_MAIN_RELEASE=1 only for an explicitly approved mainline release." >&2 exit 1 fi ;; esac relevant_status="$( git -C "${ROOT}" status --porcelain=v1 --untracked-files=all )" if [[ -n "${relevant_status}" ]]; then echo "Release check failed: worktree has uncommitted or untracked changes." >&2 printf '%s\n' "${relevant_status}" >&2 exit 1 fi if [[ "${SKIP_FETCH}" -eq 1 ]]; then bash "${ROOT}/scripts/check-branch-baseline.sh" --skip-fetch else bash "${ROOT}/scripts/check-branch-baseline.sh" fi effective_base="${BASE_REF}" if [[ -z "${effective_base}" ]]; then for candidate in origin/main origin/master main master; do if git -C "${ROOT}" rev-parse --verify --quiet "${candidate}" >/dev/null; then effective_base="${candidate}" break fi done fi head_sha="$(git -C "${ROOT}" rev-parse --short HEAD)" echo "Release check passed: ${branch} @ ${head_sha} is clean and current with ${effective_base}."