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.
223 lines
7.0 KiB
Bash
Executable File
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!"
|