Archived
A release that published nothing is not news, and at a 5-minute cadence those messages would bury the ones that matter — the log and bin/repo timers still show the run happened. Removing it would have left a start report with no follow-up, so the start report now carries its own answer: check-versions writes the package names it queued into the state file instead of touching an empty one, and the release run reads them. 'A build is running' becomes 'your package is in this build', which is the question the reports exist to answer.
237 lines
7.5 KiB
Bash
Executable File
237 lines
7.5 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
|
|
}
|
|
|
|
# Step 7 (stable only): fast-ring packages publish to rc and stable together,
|
|
# so rc never falls behind what stable users actually run. Skipped until the
|
|
# rc channel has been bootstrapped.
|
|
if [[ "$MIRROR" == "stable" ]]; then
|
|
echo ""
|
|
if [[ -f "$REPO_ROOT/rc/$ARCH/omarchy.db.tar.zst" ]]; then
|
|
print_info "Step 7: Replicating fast-ring packages to rc (parity)..."
|
|
REPLICATE_ARGS=(--from stable --to rc --fast-ring --arch "$ARCH")
|
|
[[ -n "$SYNC_REMOTE" ]] && REPLICATE_ARGS+=(--sync-remote "$SYNC_REMOTE")
|
|
[[ "$SKIP_PROD_CHECK" == true ]] && REPLICATE_ARGS+=(--skip-prod-check)
|
|
"$BUILD_ROOT/bin/advance-channel" "${REPLICATE_ARGS[@]}" || {
|
|
print_error "Fast-ring replication to rc failed"
|
|
notify_error "Release failed: rc parity replication failed" "$RELEASE_CONTEXT"
|
|
exit 1
|
|
}
|
|
else
|
|
print_info "rc channel not bootstrapped; skipping fast-ring replication"
|
|
fi
|
|
fi
|
|
|
|
echo ""
|
|
print_success "Release workflow completed successfully!"
|
|
|
|
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
|
|
# Deliberately silent in chat: a run that published nothing is not news, and
|
|
# at a 5-minute cadence those messages would bury the ones that matter. The
|
|
# log and `bin/repo timers` still show the run happened.
|
|
print_info "Nothing was published — the channel was already current"
|
|
fi
|