archy/scripts/create-release.sh

223 lines
8.2 KiB
Bash
Raw Permalink Normal View History

#!/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
#
# Releases are tarball-only. ISO builds are archived under
# image-recipe/_archived/. Nodes OTA-update from releases/manifest.json.
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 backend"
echo " 4. Build frontend"
echo " 5. Generate changelog from git log"
echo " 6. Create release manifest"
echo " 7. Commit version bump"
echo " 8. 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
fix: wallet receive reliability, bitcoin install self-heal, ElectrumX app tile Fixes three Bitcoin/wallet failures observed across the fleet on v1.7.90-alpha (all nodes were already on the latest build — these were live bugs, not stale builds), plus the missing ElectrumX tile, and adds automated coverage so each can't regress silently. Receive address (".116 receive fails", ".228 false 'wallet is locked'"): - LND publishes its REST API on a host port that can drift from the manifest (a container created when the mapping was 8080 kept publishing 8080 after the manifest moved to 18080). The in-process client connects to the manifest port, gets connection-refused, and wallet init fails forever while the container looks "Up". Add published-port drift detection to the reconciler (container_ports_drifted / host_port_bindings_drifted) that recreates a drifted backend even for restart-sensitive apps — a drifted container is already broken, so leaving it "untouched" only perpetuates the failure. - Receive errors now carry a stable [CODE] token (REST_UNREACHABLE, WALLET_LOCKED, WALLET_UNINITIALIZED, SYNCING) and always start with "Bitcoin address" so they survive the RPC error sanitizer instead of collapsing to the generic "Operation failed". The UI maps the code instead of guessing wallet state from substrings — so an unreachable REST endpoint is no longer mislabelled "locked". Bitcoin install (".198 bitcoin gone / reinstall just stops"): - bitcoin-knots requires the secret bitcoin-rpc-txrelay-rpcauth, which was only generated by the tx-relay flow. Nodes that never used tx-relay lacked it, so secret resolution hard-failed and the whole Bitcoin stack cascaded. Generate it idempotently before bitcoin starts (ensure_app_secrets, reusing ensure_txrelay_credentials), and name the missing secret in the error so a genuine gap is actionable instead of a bare "IO error". ElectrumX app tile missing on every node with it installed: - The catalog generator dropped electrumx because the manifest had no interfaces.main block, so the tile had no launch URL and was hidden. Declare the companion UI port (50002) in the manifest, regenerate the catalog, and let an app with a known launch URL stay launchable while its backend is still "starting" (ElectrumX indexes for 10m+). Test harness: - New lifecycle bats suites: bitcoin-receive, port-drift, secret-completeness (validated live; port-drift catches the real .116 drift). - Rust unit tests for drift detection, the receive reason-code classifier, and the named-missing-secret error; vitest for the UI code mapping. - create-release.sh now runs tests/release/run.sh and aborts the release on failure — previously it ran no tests at all. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 03:12:56 -04:00
# ── Pre-flight test gate ──────────────────────────────────────────────
# A release must not ship if the static/frontend/backend checks fail. This
# runs the release gate harness (cargo fmt/check, catalog drift, vitest, and
# the focused cargo suites — incl. the receive/port-drift/secret regressions).
# Skipped on --dry-run, or set SKIP_RELEASE_TESTS=1 to bypass in an emergency.
# The lifecycle bats harness (tests/lifecycle/run-gate.sh) still runs separately
fix: wallet receive reliability, bitcoin install self-heal, ElectrumX app tile Fixes three Bitcoin/wallet failures observed across the fleet on v1.7.90-alpha (all nodes were already on the latest build — these were live bugs, not stale builds), plus the missing ElectrumX tile, and adds automated coverage so each can't regress silently. Receive address (".116 receive fails", ".228 false 'wallet is locked'"): - LND publishes its REST API on a host port that can drift from the manifest (a container created when the mapping was 8080 kept publishing 8080 after the manifest moved to 18080). The in-process client connects to the manifest port, gets connection-refused, and wallet init fails forever while the container looks "Up". Add published-port drift detection to the reconciler (container_ports_drifted / host_port_bindings_drifted) that recreates a drifted backend even for restart-sensitive apps — a drifted container is already broken, so leaving it "untouched" only perpetuates the failure. - Receive errors now carry a stable [CODE] token (REST_UNREACHABLE, WALLET_LOCKED, WALLET_UNINITIALIZED, SYNCING) and always start with "Bitcoin address" so they survive the RPC error sanitizer instead of collapsing to the generic "Operation failed". The UI maps the code instead of guessing wallet state from substrings — so an unreachable REST endpoint is no longer mislabelled "locked". Bitcoin install (".198 bitcoin gone / reinstall just stops"): - bitcoin-knots requires the secret bitcoin-rpc-txrelay-rpcauth, which was only generated by the tx-relay flow. Nodes that never used tx-relay lacked it, so secret resolution hard-failed and the whole Bitcoin stack cascaded. Generate it idempotently before bitcoin starts (ensure_app_secrets, reusing ensure_txrelay_credentials), and name the missing secret in the error so a genuine gap is actionable instead of a bare "IO error". ElectrumX app tile missing on every node with it installed: - The catalog generator dropped electrumx because the manifest had no interfaces.main block, so the tile had no launch URL and was hidden. Declare the companion UI port (50002) in the manifest, regenerate the catalog, and let an app with a known launch URL stay launchable while its backend is still "starting" (ElectrumX indexes for 10m+). Test harness: - New lifecycle bats suites: bitcoin-receive, port-drift, secret-completeness (validated live; port-drift catches the real .116 drift). - Rust unit tests for drift detection, the receive reason-code classifier, and the named-missing-secret error; vitest for the UI code mapping. - create-release.sh now runs tests/release/run.sh and aborts the release on failure — previously it ran no tests at all. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 03:12:56 -04:00
# against live nodes — see tests/lifecycle/TESTING.md.
if ! $DRY_RUN; then
if [ "${SKIP_RELEASE_TESTS:-0}" = "1" ]; then
echo "WARNING: SKIP_RELEASE_TESTS=1 — bypassing the pre-flight test gate"
elif [ -x "$PROJECT_ROOT/tests/release/run.sh" ]; then
echo "[0/7] Running release gate (tests/release/run.sh)..."
if ! "$PROJECT_ROOT/tests/release/run.sh"; then
echo "Error: release gate failed — aborting release. Fix the failing"
echo " stage, or re-run with SKIP_RELEASE_TESTS=1 to override."
exit 1
fi
else
echo "WARNING: tests/release/run.sh not found/executable — skipping test gate"
fi
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:"
fix: wallet receive reliability, bitcoin install self-heal, ElectrumX app tile Fixes three Bitcoin/wallet failures observed across the fleet on v1.7.90-alpha (all nodes were already on the latest build — these were live bugs, not stale builds), plus the missing ElectrumX tile, and adds automated coverage so each can't regress silently. Receive address (".116 receive fails", ".228 false 'wallet is locked'"): - LND publishes its REST API on a host port that can drift from the manifest (a container created when the mapping was 8080 kept publishing 8080 after the manifest moved to 18080). The in-process client connects to the manifest port, gets connection-refused, and wallet init fails forever while the container looks "Up". Add published-port drift detection to the reconciler (container_ports_drifted / host_port_bindings_drifted) that recreates a drifted backend even for restart-sensitive apps — a drifted container is already broken, so leaving it "untouched" only perpetuates the failure. - Receive errors now carry a stable [CODE] token (REST_UNREACHABLE, WALLET_LOCKED, WALLET_UNINITIALIZED, SYNCING) and always start with "Bitcoin address" so they survive the RPC error sanitizer instead of collapsing to the generic "Operation failed". The UI maps the code instead of guessing wallet state from substrings — so an unreachable REST endpoint is no longer mislabelled "locked". Bitcoin install (".198 bitcoin gone / reinstall just stops"): - bitcoin-knots requires the secret bitcoin-rpc-txrelay-rpcauth, which was only generated by the tx-relay flow. Nodes that never used tx-relay lacked it, so secret resolution hard-failed and the whole Bitcoin stack cascaded. Generate it idempotently before bitcoin starts (ensure_app_secrets, reusing ensure_txrelay_credentials), and name the missing secret in the error so a genuine gap is actionable instead of a bare "IO error". ElectrumX app tile missing on every node with it installed: - The catalog generator dropped electrumx because the manifest had no interfaces.main block, so the tile had no launch URL and was hidden. Declare the companion UI port (50002) in the manifest, regenerate the catalog, and let an app with a known launch URL stay launchable while its backend is still "starting" (ElectrumX indexes for 10m+). Test harness: - New lifecycle bats suites: bitcoin-receive, port-drift, secret-completeness (validated live; port-drift catches the real .116 drift). - Rust unit tests for drift detection, the receive reason-code classifier, and the named-missing-secret error; vitest for the UI code mapping. - create-release.sh now runs tests/release/run.sh and aborts the release on failure — previously it ran no tests at all. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 03:12:56 -04:00
echo " 0. Run pre-flight test gate (tests/release/run.sh) — aborts on failure"
echo " 1. Update core/archipelago/Cargo.toml version to $VERSION"
echo " 2. Update neode-ui/package.json version to $VERSION"
echo " 3. Build backend (cargo build --release -p archipelago)"
echo " 4. Build frontend (npm run build)"
echo " 5. Generate changelog from git log since v${CURRENT_CARGO_VERSION}"
echo " 6. Create release manifest"
echo " 7. Commit: 'chore: release v${VERSION}'"
echo " 8. 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/8] Building backend..."
cd "$PROJECT_ROOT/core"
cargo build --release -p archipelago
cd "$PROJECT_ROOT"
echo "[4/8] Building frontend..."
cd "$PROJECT_ROOT/neode-ui"
npm run build 2>&1 | tail -3
cd "$PROJECT_ROOT"
echo "[5/8] Validating curated changelog..."
CHANGELOG_FILE="$PROJECT_ROOT/CHANGELOG.md"
RELEASE_DATE=$(date +%Y-%m-%d)
if [ ! -f "$CHANGELOG_FILE" ] || ! grep -q "^## v${VERSION} (" "$CHANGELOG_FILE"; then
echo "Error: CHANGELOG.md must already contain curated notes for v${VERSION}."
echo "Add a section like:"
echo ""
echo "## v${VERSION} (${RELEASE_DATE})"
echo ""
echo "- User/operator-facing change ..."
echo "- Another concrete change ..."
echo "- Validation or operational note ..."
exit 1
fi
echo "[6/8] Creating release manifest..."
mkdir -p "$PROJECT_ROOT/releases"
"$SCRIPT_DIR/create-release-manifest.sh" --version "$VERSION" --date "$RELEASE_DATE" --output "$PROJECT_ROOT/releases/manifest.json" 2>&1 | grep -v "^$"
cp "$PROJECT_ROOT/releases/manifest.json" "$PROJECT_ROOT/release-manifest.json"
echo "[6b/8] Staging release artifacts for validation..."
VERSION_DIR="$PROJECT_ROOT/releases/v${VERSION}"
FRONTEND_ARCHIVE="/tmp/archipelago-frontend-${VERSION}.tar.gz"
mkdir -p "$VERSION_DIR"
install -m 0755 "$PROJECT_ROOT/core/target/release/archipelago" "$VERSION_DIR/archipelago"
install -m 0644 "$FRONTEND_ARCHIVE" "$VERSION_DIR/archipelago-frontend-${VERSION}.tar.gz"
"$SCRIPT_DIR/check-release-manifest.sh"
echo "[7/8] Committing version bump..."
git -C "$PROJECT_ROOT" add \
core/archipelago/Cargo.toml \
neode-ui/package.json \
neode-ui/package-lock.json \
CHANGELOG.md \
releases/manifest.json \
release-manifest.json \
2>/dev/null || true
git -C "$PROJECT_ROOT" commit -m "chore: release v${VERSION}"
echo "[8/8] 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: releases/manifest.json"
echo " - Release manifest copy: release-manifest.json"
echo " - Staged artifacts: releases/v${VERSION}/"
echo " - Git tag: v${VERSION}"
echo ""
echo "Next steps:"
echo " 1. Review: git log --oneline -5"
echo " 2. Publish commits, tag, artifacts, and verify download URLs:"
echo " scripts/publish-release-assets.sh ${VERSION} gitea-vps2"
echo " 3. Verify manifest is live on both mirrors:"
echo " curl -fsS http://localhost:3000/lfg2025/archy/raw/branch/main/releases/manifest.json"
echo " curl -fsS http://146.59.87.168:3000/lfg2025/archy/raw/branch/main/releases/manifest.json"