Files
omarchy-pkgs/bin/release
T
Marcelo Alcantara 91843ab099 Make aarch64 a first-class architecture in the scheduled pipeline
One list, PUBLISHED_ARCHES in helpers/paths.sh (default x86_64,
overridable with OMARCHY_ARCHES), now drives everything the repository
host schedules. check-versions compares PKGBUILDs against each
architecture's channel databases and writes one queue per channel and
architecture; auto-release works through the queues one architecture at
a time, each with its own backoff, so a failing build on one never
blocks the other; advance-channel --arch all re-runs an advance for every
published architecture and omarchy-release uses it for start and ship,
building the pinned pair once per architecture in its rc trigger; the
train observes channels through the reference (first) architecture
instead of a hard-coded x86_64. Queue and backoff files written under
the old per-channel names are treated as x86_64 until consumed.

Two things made an aarch64 builder image impossible to create: the
keyring bootstrap fetched omarchy-keyring from the target architecture's
own channel tree, which does not exist before that architecture has
published anything, and the QEMU probe only knew the x86_64-host,
aarch64-target case. The keyring (arch=any) now always comes from the
x86_64 tree, and the probe compares host and target architectures and
runs a container for the target platform.

clean-repo grouped versions with a regex that only knew any, x86_64 and
i686, so aarch64 packages would never have been pruned.
2026-09-04 23:40:49 -04:00

232 lines
7.4 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)
# Greedy like bin/build: consume every name up to the next --option.
BUILD_ARGS+=("--package")
shift
while [[ $# -gt 0 && ! "$1" =~ ^-- ]]; do
BUILD_ARGS+=("$1")
shift
done
;;
--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 <names> Build only the specified package(s) (space-separated)"
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=$(sync_queue_file "$MIRROR" "$ARCH")
# A queue written under the pre-architecture name belongs to x86_64.
if [[ "$ARCH" == "x86_64" && ! -s "$QUEUE_FILE" && -s "$(legacy_sync_queue_file "$MIRROR")" ]]; then
QUEUE_FILE=$(legacy_sync_queue_file "$MIRROR")
fi
[[ -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!"