Files
omarchy-pkgs/bin/release
T
Ryan Hughes dbb5e72051 Build fast-ring for rc as rc, instead of copying stable's artifacts
The rc channel's Arch base can sit anywhere between stable's snapshot and
edge's, so a package built against stable's libraries is not necessarily
correct for rc. Copying stable's fast-ring artifacts into rc therefore shipped
possibly-mislinked packages to RC testers. Fast-ring packages now build
natively for all three channels, each in its own image against its own base
mirror, and the stable release's replication step is gone.

That required separating 'may be built here' from 'whose version wins'. The
release pair is now marked "pinned": its version is set per release on the rc
branch, so it builds for rc only from that branch's worktree
(OMARCHY_RC_PINS=1, set by omarchy-release rc) — master's shipped pins can
never overwrite an in-flight RC, even though check-versions now discovers rc
work like it does for edge and stable.
2026-08-27 12:39:29 -04:00

223 lines
7.0 KiB
Bash
Executable File

#!/bin/bash
# Run the complete release workflow: build, sign, promote, clean, sync
set -e
BUILD_ROOT=$(realpath "${BASH_SOURCE[0]%/*}/..")
source "$BUILD_ROOT/helpers/message-helpers.sh"
source "$BUILD_ROOT/helpers/paths.sh"
source "$BUILD_ROOT/helpers/lock-helpers.sh"
source "$BUILD_ROOT/helpers/basecamp-notifier.sh"
SYNC_REMOTE=""
SKIP_PROD_CHECK=false
DRY_RUN=false
print_header "Complete Release Workflow"
echo ""
print_info "This will run the complete release workflow:"
echo " 1. Build packages"
echo " 2. Sign packages"
echo " 3. Promote to production"
echo " 4. Clean old versions"
echo " 5. Update repository database"
echo " 6. Sync to remote"
echo ""
# Parse arguments
BUILD_ARGS=()
while [[ $# -gt 0 ]]; do
case $1 in
--arch)
ARCH="$2"
BUILD_ARGS+=("--arch" "$2")
update_arch_paths
shift 2
;;
--mirror)
MIRROR="$2"
BUILD_ARGS+=("--mirror" "$2")
update_arch_paths
shift 2
;;
--package)
BUILD_ARGS+=("--package" "$2")
shift 2
;;
--sync-remote)
SYNC_REMOTE="$2"
shift 2
;;
--skip-prod-check)
SKIP_PROD_CHECK=true
shift
;;
--dry-run)
DRY_RUN=true
BUILD_ARGS+=("--dry-run")
shift
;;
-h | --help)
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Options:"
echo " --arch <arch> Target architecture (x86_64 or aarch64, default: x86_64)"
echo " --mirror <mirror> Mirror to use (edge, rc, or stable, default: edge)"
echo " --package <name> Build only the specified package"
echo " --sync-remote <path> Rclone remote for sync (default: pkgs.omarchy.org:omarchy-pkgs)"
echo " --skip-prod-check Skip production environment check during sync
--dry-run Show build plan only; do not sign/promote/clean/update/sync"
echo " -h, --help Show this help message"
echo ""
echo "This script runs the complete workflow:"
echo " build → sign → promote → clean → sync"
exit 0
;;
*)
print_error "Unknown option: $1"
exit 1
;;
esac
done
echo ""
print_info "Target architecture: $ARCH"
print_info "Mirror: $MIRROR"
print_info "Build workspace: $BUILD_OUTPUT_DIR"
# One channel mutation at a time: a timer firing mid-run or a second operator
# waits here instead of interleaving a partial publish.
if [[ "$DRY_RUN" != true ]]; then
acquire_release_lock || exit 1
fi
# --- reporting ---------------------------------------------------------------
RELEASE_STARTED_AT=$(date +%s)
RELEASE_COMMIT=$(git -C "$BUILD_ROOT" rev-parse --short HEAD 2>/dev/null || echo "unknown")
RELEASE_COMMIT_SUBJECT=$(git -C "$BUILD_ROOT" log -1 --pretty=%s 2>/dev/null || echo "")
RELEASE_CONTEXT="Channel: <strong>$MIRROR</strong> · Arch: $ARCH · $(hostname -s 2>/dev/null || echo host)"
if [[ "$RELEASE_COMMIT" != "unknown" ]]; then
RELEASE_CONTEXT+="<br>Commit: <code>$RELEASE_COMMIT</code> $(basecamp_html_escape <<<"$RELEASE_COMMIT_SUBJECT")"
fi
# Captured after the build step: promote MOVES these files out of build-output,
# so the list has to be taken while they are still there.
BUILT_FILES=""
# What the scheduled version check queued, when it was the one that asked for
# this run. Absent for a manual run, which is fine — the report just omits it.
QUEUED_PACKAGES=""
QUEUE_FILE="${OMARCHY_STATE_DIR:-/root/.state}/.sync-needed-$MIRROR"
[[ -s "$QUEUE_FILE" ]] && QUEUED_PACKAGES=$(grep -c '' "$QUEUE_FILE")
if [[ "$DRY_RUN" != true ]]; then
start_details="$RELEASE_CONTEXT"
if [[ -n "$QUEUED_PACKAGES" && "$QUEUED_PACKAGES" != "0" ]]; then
start_details+="<br><br><strong>$QUEUED_PACKAGES package(s) queued:</strong><br>"
start_details+="$(head -25 "$QUEUE_FILE" | tr '\n' ' ' | basecamp_html_escape)"
((QUEUED_PACKAGES > 25)) && start_details+=" …and $((QUEUED_PACKAGES - 25)) more"
fi
notify_start "Release started: $MIRROR" "$start_details"
fi
# Step 1: Build
echo ""
if [[ "$DRY_RUN" == true ]]; then
print_info "Step 1/6: Planning build..."
else
print_info "Step 1/6: Building packages..."
fi
"$BUILD_ROOT/bin/build" "${BUILD_ARGS[@]}" || {
print_error "Build failed"
notify_error "Release failed: Build step failed" "$RELEASE_CONTEXT"
exit 1
}
if [[ "$DRY_RUN" == true ]]; then
echo ""
print_success "Release dry run complete (build plan only)."
exit 0
fi
BUILT_FILES=$(built_package_files "$BUILD_OUTPUT_DIR")
BUILT_COUNT=$(grep -c '' <<<"$BUILT_FILES")
[[ -z "$BUILT_FILES" ]] && BUILT_COUNT=0
print_info "Built $BUILT_COUNT package(s) this run"
# Step 2: Sign
echo ""
print_info "Step 2/6: Signing packages..."
"$BUILD_ROOT/bin/sign" --arch "$ARCH" --mirror "$MIRROR" || {
print_error "Signing failed"
notify_error "Release failed: Signing step failed" "$RELEASE_CONTEXT"
exit 1
}
# Step 3: Promote
echo ""
print_info "Step 3/6: Promoting to production..."
"$BUILD_ROOT/bin/promote-build" --arch "$ARCH" --mirror "$MIRROR" || {
print_error "Promotion failed"
notify_error "Release failed: Promotion step failed" "$RELEASE_CONTEXT"
exit 1
}
# Step 4: Clean
echo ""
print_info "Step 4/6: Cleaning old versions..."
"$BUILD_ROOT/bin/clean-repo" --arch "$ARCH" --mirror "$MIRROR" || {
print_error "Cleaning failed"
notify_error "Release failed: Clean step failed" "$RELEASE_CONTEXT"
exit 1
}
# Step 5: Update DB
echo ""
print_info "Step 5/6: Updating repository database..."
"$BUILD_ROOT/bin/update-repo" --arch "$ARCH" --mirror "$MIRROR" || {
print_error "Database update failed"
notify_error "Release failed: Database update step failed" "$RELEASE_CONTEXT"
exit 1
}
# Step 6: Sync
echo ""
print_info "Step 6/6: Syncing to remote..."
SYNC_ARGS=("--mirror" "$MIRROR" "--arch" "$ARCH")
if [[ -n "$SYNC_REMOTE" ]]; then
SYNC_ARGS+=("--remote" "$SYNC_REMOTE")
fi
if [[ "$SKIP_PROD_CHECK" == true ]]; then
SYNC_ARGS+=("--skip-prod-check")
fi
"$BUILD_ROOT/bin/sync-repo" "${SYNC_ARGS[@]}" || {
print_error "Sync failed"
notify_error "Release failed: Sync step failed" "$RELEASE_CONTEXT"
exit 1
}
duration=$(format_duration $(($(date +%s) - RELEASE_STARTED_AT)))
summary="$RELEASE_CONTEXT<br>Duration: $duration"
if ((BUILT_COUNT > 0)); then
summary+="<br><br><strong>$BUILT_COUNT package(s) published:</strong>"
summary+="$(format_package_list_html "$BUILT_FILES")"
summary+="<br><br>Live at https://pkgs.omarchy.org/$MIRROR/$ARCH/"
notify_success "Release published: $MIRROR" "$summary"
else
# Rare by construction: a release only runs when the version check queued
# work, so publishing nothing means the check and the builder disagreed
# about what needs building. Worth reporting for exactly that reason — if
# these start recurring, something is flagging a package that never builds.
summary+="<br>No packages needed building — the version check and the"
summary+=" builder disagree about what is out of date."
if [[ -n "$QUEUED_PACKAGES" && "$QUEUED_PACKAGES" != "0" ]]; then
summary+="<br>Queued but not built: $(head -25 "$QUEUE_FILE" | tr '\n' ' ' | basecamp_html_escape)"
fi
notify_info "Release ran with nothing to publish: $MIRROR" "$summary"
fi
echo ""
print_success "Release workflow completed successfully!"