#!/usr/bin/env bash # Build unsigned pending artifacts from an already reviewed, versioned, # annotated source tag. Never change source after recording BUILD-INFO. set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" if [ "${1:-}" = --backend-only ]; then [ "$#" = 2 ] && [[ "$2" =~ ^[0-9a-f]{64}$ ]] || { echo 'Exact Cargo.lock SHA256 required' >&2; exit 1; } cd "$PROJECT_ROOT/core" [ -f Cargo.lock ] && [ ! -L Cargo.lock ] || exit 1 ACTUAL=$(sha256sum Cargo.lock) [ "${ACTUAL%% *}" = "$2" ] || { echo 'Cargo.lock mismatch' >&2; exit 1; } exec cargo build --release -p archipelago --locked --offline fi VERSION="${1:-}" DRY_RUN="${2:-}" [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]] \ && [ "$#" -le 2 ] && [[ "$DRY_RUN" = '' || "$DRY_RUN" = --dry-run ]] \ || { echo "Usage: $0 VERSION [--dry-run]" >&2; exit 1; } [ "${SKIP_RELEASE_TESTS:-0}" = 0 ] || { echo 'Release gate bypass is forbidden' >&2; exit 1; } SOURCE_COMMIT=$(python3 "$SCRIPT_DIR/release_payload.py" source --version "$VERSION") OS_PLAN=${ARCHIPELAGO_OS_RELEASE_PLAN:?Set ARCHIPELAGO_OS_RELEASE_PLAN to the reviewed exact OS transaction JSON} [ -f "$OS_PLAN" ] && [ ! -L "$OS_PLAN" ] || { echo 'OS release plan must be a regular file' >&2; exit 1; } OS_PLAN=$(realpath "$OS_PLAN") PENDING="$PROJECT_ROOT/releases/pending/v$VERSION/manifest.json" ARTIFACTS="$PROJECT_ROOT/releases/v$VERSION" [ ! -e "$PENDING" ] && [ ! -e "$ARTIFACTS" ] || { echo 'Existing candidate retained; use its verification/signing steps rather than rebuilding over it' >&2; exit 1; } if [ "$DRY_RUN" = --dry-run ]; then echo "Build backend/UI/AIUI/radio from $SOURCE_COMMIT; stage unsigned $PENDING." echo 'Run under flock /tmp/opencode/release-heavy.lock. Source/tag creation and signing are separate operator steps.' exit 0 fi cd "$PROJECT_ROOT" bash tests/release/run.sh python3 scripts/release_payload.py companion (cd core && cargo build --release -p archipelago --locked --offline) (cd neode-ui && npm ci && npm run build) bash scripts/build-aiui.sh rm -rf web/dist/neode-ui/aiui cp -r aiui/packages/app/dist web/dist/neode-ui/aiui (cd reticulum-daemon && ./build.sh) test "$SOURCE_COMMIT" = "$(python3 scripts/release_payload.py source --version "$VERSION")" mkdir -p "$(dirname "$PENDING")" "$ARTIFACTS" install -m 0644 "$OS_PLAN" "$ARTIFACTS/os-update-plan.json" bash scripts/create-release-manifest.sh --version "$VERSION" --output "$PENDING" --os-plan "$ARTIFACTS/os-update-plan.json" install -m 0755 core/target/release/archipelago "$ARTIFACTS/archipelago" install -m 0644 "/tmp/archipelago-frontend-$VERSION.tar.gz" "$ARTIFACTS/archipelago-frontend-$VERSION.tar.gz" bash scripts/check-release-manifest.sh "$PENDING" echo "Unsigned candidate staged from $SOURCE_COMMIT; no commit, tag, signature or feed promotion performed." echo "Operator signing command (inputs now exist): bash scripts/sign-manifest.sh '$PENDING'"