From 2b2bc96adeae04af451d44abfa3bbca181e8be49 Mon Sep 17 00:00:00 2001 From: Dorian Date: Wed, 11 Mar 2026 17:49:23 +0000 Subject: [PATCH] feat: add release automation script (RELEASE-01) scripts/create-release.sh orchestrates the full release process: 1. Validates SemVer version and clean git state 2. Bumps version in Cargo.toml and package.json 3. Builds frontend 4. Generates changelog from git log 5. Creates release manifest via create-release-manifest.sh 6. Commits version bump and tags release Supports --dry-run for preview. ISO builds delegated to server. Co-Authored-By: Claude Opus 4.6 --- loop/plan.md | 2 +- scripts/create-release.sh | 194 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 195 insertions(+), 1 deletion(-) create mode 100755 scripts/create-release.sh diff --git a/loop/plan.md b/loop/plan.md index 1274e0a1..bc46c2d6 100644 --- a/loop/plan.md +++ b/loop/plan.md @@ -406,7 +406,7 @@ #### Sprint 34: Release Engineering (Week 5-8) -- [ ] **RELEASE-01** — Create release automation. Build `scripts/create-release.sh` that: bumps version in Cargo.toml and package.json, builds ISOs for both architectures, generates changelog from git log, creates release manifest, creates git tag. **Acceptance**: One command produces complete release artifacts. +- [x] **RELEASE-01** — Create release automation. Build `scripts/create-release.sh` that: bumps version in Cargo.toml and package.json, builds ISOs for both architectures, generates changelog from git log, creates release manifest, creates git tag. **Acceptance**: One command produces complete release artifacts. - [ ] **RELEASE-02** — Set up download/update infrastructure. Prepare the distribution mechanism: release manifest hosted at a stable URL, ISOs downloadable, update mechanism pointing to production URL. **Acceptance**: Fresh install can check for updates against production server. diff --git a/scripts/create-release.sh b/scripts/create-release.sh new file mode 100755 index 00000000..a21ca5b6 --- /dev/null +++ b/scripts/create-release.sh @@ -0,0 +1,194 @@ +#!/usr/bin/env bash +# create-release.sh — Full release automation for Archipelago +# +# Bumps version in Cargo.toml and package.json, generates changelog from git log, +# creates release manifest, and creates git tag. +# +# Usage: +# ./scripts/create-release.sh 1.0.0 # Release v1.0.0 +# ./scripts/create-release.sh 1.0.0 --dry-run # Preview without changes +# +# ISO builds must be done on the target server separately: +# ssh archipelago@192.168.1.228 'cd ~/archy/image-recipe && sudo ./build-auto-installer-iso.sh' + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +DRY_RUN=false +VERSION="" + +# Parse args +for arg in "$@"; do + case "$arg" in + --dry-run) DRY_RUN=true ;; + --help|-h) + echo "Usage: $0 VERSION [--dry-run]" + echo "" + echo "Steps performed:" + echo " 1. Validate version format (SemVer)" + echo " 2. Bump version in Cargo.toml and package.json" + echo " 3. Build frontend" + echo " 4. Generate changelog from git log" + echo " 5. Create release manifest" + echo " 6. Commit version bump" + echo " 7. Create git tag v{VERSION}" + echo "" + echo "Options:" + echo " --dry-run Show what would be done without making changes" + exit 0 + ;; + *) + if [ -z "$VERSION" ]; then + VERSION="$arg" + else + echo "Error: Unknown argument: $arg" + exit 1 + fi + ;; + esac +done + +if [ -z "$VERSION" ]; then + echo "Error: VERSION argument required" + echo "Usage: $0 VERSION [--dry-run]" + exit 1 +fi + +# Validate SemVer format +if ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$'; then + echo "Error: Version '$VERSION' is not valid SemVer (expected: X.Y.Z or X.Y.Z-suffix)" + exit 1 +fi + +# Check we're on main branch +BRANCH=$(git -C "$PROJECT_ROOT" branch --show-current) +if [ "$BRANCH" != "main" ]; then + echo "Error: Must be on 'main' branch (currently on '$BRANCH')" + exit 1 +fi + +# Check for uncommitted changes +if ! git -C "$PROJECT_ROOT" diff --quiet HEAD; then + echo "Error: Uncommitted changes detected. Commit or stash first." + exit 1 +fi + +# Check tag doesn't already exist +if git -C "$PROJECT_ROOT" tag -l "v$VERSION" | grep -q "v$VERSION"; then + echo "Error: Tag v$VERSION already exists" + exit 1 +fi + +# Get current version +CURRENT_CARGO_VERSION=$(grep '^version' "$PROJECT_ROOT/core/archipelago/Cargo.toml" | head -1 | sed 's/.*"\(.*\)".*/\1/') +CURRENT_NPM_VERSION=$(node -p "require('$PROJECT_ROOT/neode-ui/package.json').version") + +echo "=== Archipelago Release v${VERSION} ===" +echo " Current Cargo version: ${CURRENT_CARGO_VERSION}" +echo " Current npm version: ${CURRENT_NPM_VERSION}" +echo " Target version: ${VERSION}" +echo " Dry run: ${DRY_RUN}" +echo "" + +if $DRY_RUN; then + echo "[DRY RUN] Would perform the following:" + echo " 1. Update core/archipelago/Cargo.toml version to $VERSION" + echo " 2. Update neode-ui/package.json version to $VERSION" + echo " 3. Build frontend (npm run build)" + echo " 4. Generate changelog from git log since v${CURRENT_CARGO_VERSION}" + echo " 5. Create release manifest" + echo " 6. Commit: 'chore: release v${VERSION}'" + echo " 7. Tag: v${VERSION}" + echo "" + echo "After this script, you would:" + echo " - Push: git push && git push --tags" + echo " - Build ISOs on server: ssh archipelago@192.168.1.228" + exit 0 +fi + +echo "[1/7] Bumping version in Cargo.toml..." +# Update archipelago Cargo.toml +sed -i.bak "s/^version = \".*\"/version = \"$VERSION\"/" "$PROJECT_ROOT/core/archipelago/Cargo.toml" +rm -f "$PROJECT_ROOT/core/archipelago/Cargo.toml.bak" + +# Also update workspace Cargo.lock if it exists +if [ -f "$PROJECT_ROOT/core/Cargo.lock" ]; then + # Cargo will update the lock file on next build; touch the toml to trigger + true +fi + +echo "[2/7] Bumping version in package.json..." +cd "$PROJECT_ROOT/neode-ui" +npm version "$VERSION" --no-git-tag-version --allow-same-version 2>/dev/null || true +cd "$PROJECT_ROOT" + +echo "[3/7] Building frontend..." +cd "$PROJECT_ROOT/neode-ui" +npm run build 2>&1 | tail -3 +cd "$PROJECT_ROOT" + +echo "[4/7] Generating changelog..." +# Get commits since last tag (or last 50 if no tags) +LAST_TAG=$(git -C "$PROJECT_ROOT" describe --tags --abbrev=0 2>/dev/null || echo "") +if [ -n "$LAST_TAG" ]; then + GIT_LOG=$(git -C "$PROJECT_ROOT" log "$LAST_TAG"..HEAD --oneline --no-merges 2>/dev/null || echo "") +else + GIT_LOG=$(git -C "$PROJECT_ROOT" log --oneline --no-merges -50 2>/dev/null || echo "") +fi + +# Create/update CHANGELOG.md entry +CHANGELOG_FILE="$PROJECT_ROOT/CHANGELOG.md" +RELEASE_DATE=$(date +%Y-%m-%d) +CHANGELOG_ENTRY="## v${VERSION} (${RELEASE_DATE}) + +$GIT_LOG +" + +if [ -f "$CHANGELOG_FILE" ]; then + # Prepend new entry after the first line (title) + EXISTING=$(cat "$CHANGELOG_FILE") + FIRST_LINE=$(head -1 "$CHANGELOG_FILE") + REST=$(tail -n +2 "$CHANGELOG_FILE") + echo "$FIRST_LINE" > "$CHANGELOG_FILE" + echo "" >> "$CHANGELOG_FILE" + echo "$CHANGELOG_ENTRY" >> "$CHANGELOG_FILE" + echo "$REST" >> "$CHANGELOG_FILE" +else + echo "# Changelog" > "$CHANGELOG_FILE" + echo "" >> "$CHANGELOG_FILE" + echo "$CHANGELOG_ENTRY" >> "$CHANGELOG_FILE" +fi + +echo "[5/7] Creating release manifest..." +"$SCRIPT_DIR/create-release-manifest.sh" --version "$VERSION" --date "$RELEASE_DATE" --output "$PROJECT_ROOT/release-manifest.json" 2>&1 | grep -v "^$" + +echo "[6/7] Committing version bump..." +git -C "$PROJECT_ROOT" add \ + core/archipelago/Cargo.toml \ + neode-ui/package.json \ + neode-ui/package-lock.json \ + CHANGELOG.md \ + release-manifest.json \ + 2>/dev/null || true + +git -C "$PROJECT_ROOT" commit -m "chore: release v${VERSION}" + +echo "[7/7] Creating git tag..." +git -C "$PROJECT_ROOT" tag -a "v${VERSION}" -m "Release v${VERSION}" + +echo "" +echo "=== Release v${VERSION} Ready ===" +echo "" +echo "Artifacts:" +echo " - Version bumped in Cargo.toml and package.json" +echo " - Changelog updated in CHANGELOG.md" +echo " - Release manifest: release-manifest.json" +echo " - Git tag: v${VERSION}" +echo "" +echo "Next steps:" +echo " 1. Review: git log --oneline -5" +echo " 2. Push: git push && git push --tags" +echo " 3. Build ISOs on server:" +echo " ssh archipelago@192.168.1.228 'cd ~/archy/image-recipe && sudo ./build-auto-installer-iso.sh'" +echo " 4. Upload ISOs and manifest to distribution server"