diff --git a/.scripts/release.sh b/.scripts/release.sh new file mode 100755 index 0000000..5c7538d --- /dev/null +++ b/.scripts/release.sh @@ -0,0 +1,99 @@ +#!/usr/bin/env bash +# Create a CalVer release tag and push to trigger CI. +# +# Usage: +# .scripts/release.sh # auto-generates next version (YYYY.M.BUILD) +# .scripts/release.sh 2026.3.11 # explicit version +# .scripts/release.sh -y # auto-generate + skip confirmation + +set -euo pipefail + +SKIP_CONFIRM=false +VERSION="" + +for arg in "$@"; do + case "$arg" in + -y) SKIP_CONFIRM=true ;; + *) VERSION="$arg" ;; + esac +done + +# --- Ensure we're on main and up to date --- + +BRANCH=$(git rev-parse --abbrev-ref HEAD) +if [[ "$BRANCH" != "main" ]]; then + echo "ERROR: Must be on main branch (currently on ${BRANCH})" + exit 1 +fi + +echo "==> Fetching latest..." +git fetch origin main --tags --quiet +LOCAL=$(git rev-parse HEAD) +REMOTE=$(git rev-parse origin/main) +if [[ "$LOCAL" != "$REMOTE" ]]; then + echo "ERROR: Local main is not up to date with origin. Run: git pull" + exit 1 +fi + +# --- Determine version --- + +YEAR=$(date +%Y) +MONTH=$(date +%-m) # no leading zero + +if [[ -z "$VERSION" ]]; then + # Find the highest build number for this year.month + LAST_BUILD=$(git tag --list "${YEAR}.${MONTH}.*" --sort=-v:refname | head -1 | awk -F. '{print $3}') + NEXT_BUILD=$((${LAST_BUILD:-0} + 1)) + VERSION="${YEAR}.${MONTH}.${NEXT_BUILD}" +fi + +# Validate format +if [[ ! "$VERSION" =~ ^20[0-9]{2}\.[0-9]+\.[0-9]+$ ]]; then + echo "ERROR: Invalid version format '${VERSION}'. Expected YYYY.M.BUILD (e.g., 2026.3.11)" + exit 1 +fi + +# Check tag doesn't already exist +if git rev-parse "refs/tags/${VERSION}" &>/dev/null; then + echo "ERROR: Tag ${VERSION} already exists" + exit 1 +fi + +# --- Show what's being released --- + +LAST_TAG=$(git tag --sort=-v:refname | head -1) +echo "" +echo "Version: ${VERSION}" +echo "Previous: ${LAST_TAG:-none}" +echo "Commit: $(git log -1 --format='%h %s')" +echo "" + +if [[ -n "$LAST_TAG" ]]; then + COMMIT_COUNT=$(git rev-list "${LAST_TAG}..HEAD" --count) + echo "Changes since ${LAST_TAG} (${COMMIT_COUNT} commits):" + git log "${LAST_TAG}..HEAD" --oneline --no-merges + echo "" +fi + +# --- Confirm --- + +if [[ "$SKIP_CONFIRM" != true ]]; then + read -rp "Create tag ${VERSION} and trigger release? [y/N] " answer + [[ "$answer" =~ ^[Yy]$ ]] || { + echo "Aborted." + exit 0 + } + echo "" +fi + +# --- Tag and push --- + +git tag "$VERSION" +git push origin tag "$VERSION" + +echo "" +echo "==> Tag ${VERSION} pushed. CI will build:" +echo " - manticorum67/major-domo-discordapp:${VERSION}" +echo " - manticorum67/major-domo-discordapp:production" +echo "" +echo "Deploy with: .scripts/deploy.sh"