Harden multi-architecture release pipeline
This commit is contained in:
23 files changed
+557
-271
No files matched your search
+75
-50
@@ -28,11 +28,9 @@ ISO_REPO="${OMARCHY_ISO_REPO:-omacom-io/omarchy-iso}"
|
||||
DEV_BRANCH="${OMARCHY_DEV_BRANCH:-quattro}"
|
||||
|
||||
PKGS_DB_BASE="${OMARCHY_PKGS_DB_BASE:-https://pkgs.omarchy.org}"
|
||||
# The train observes channels through the reference architecture (the first
|
||||
# published one). The pair is pinned to one version for every architecture and
|
||||
# built for all of them in one rc trigger, so one architecture's database is
|
||||
# the state of the release; per-architecture drift is a build failure the
|
||||
# scheduled pipeline reports, not something the train has to poll for.
|
||||
# The first published architecture supplies the version-ordering floor when
|
||||
# cutting pins. Readiness checks below still verify every published
|
||||
# architecture before an RC or final release can move forward.
|
||||
OBSERVED_ARCH=$(reference_arch)
|
||||
RC_DB_URL="$PKGS_DB_BASE/rc/$OBSERVED_ARCH/omarchy.db.tar.zst"
|
||||
|
||||
@@ -187,12 +185,12 @@ ensure_work_clone() {
|
||||
# Prints omarchy's published version in a channel; empty when absent, rc 2 when
|
||||
# the database cannot be read (callers must not mistake an outage for absence).
|
||||
published_version() {
|
||||
local channel="$1" tmp descs
|
||||
local channel="$1" arch="${2:-$OBSERVED_ARCH}" tmp descs
|
||||
tmp=$(mktemp) || return 2
|
||||
# A unique query string busts the CDN cache: right after a sync the plain
|
||||
# URL can keep serving the previous db for a while, which reads as "not
|
||||
# published yet" to status, the wait loop, and ship's pre-checks.
|
||||
if ! curl -sf "$PKGS_DB_BASE/$channel/$OBSERVED_ARCH/omarchy.db.tar.zst?$(date +%s%N)" -o "$tmp"; then
|
||||
if ! curl -sf "$PKGS_DB_BASE/$channel/$arch/omarchy.db.tar.zst?$(date +%s%N)" -o "$tmp"; then
|
||||
rm -f "$tmp"
|
||||
return 2
|
||||
fi
|
||||
@@ -213,6 +211,14 @@ published_version() {
|
||||
' <<<"$descs"
|
||||
}
|
||||
|
||||
all_arches_at_version() { # all_arches_at_version <channel> <pkgver>
|
||||
local channel="$1" want="$2" arch got
|
||||
for arch in $(published_arches); do
|
||||
got=$(published_version "$channel" "$arch" 2>/dev/null) || return 1
|
||||
[[ "${got%-*}" == "$want" ]] || return 1
|
||||
done
|
||||
}
|
||||
|
||||
# The rc branch of THIS repo carries the current pins. Read them without
|
||||
# touching the working tree.
|
||||
rc_branch_pin() { # prints "pkgver commit", empty when no rc branch
|
||||
@@ -297,12 +303,16 @@ host_advance() { # host_advance <from> <to> [extra args...]
|
||||
}
|
||||
|
||||
wait_for_published() { # wait_for_published <channel> <version> [timeout-seconds]
|
||||
local channel="$1" want="$2" timeout="${3:-3600}" waited=0 got
|
||||
print_info "Waiting for $want to appear in the $channel channel (up to $((timeout / 60))m)..."
|
||||
local channel="$1" want="$2" timeout="${3:-3600}" waited=0 arch got pending
|
||||
print_info "Waiting for $want in $channel for: $(published_arches | tr '\n' ' ')"
|
||||
while ((waited < timeout)); do
|
||||
got=$(published_version "$channel" 2>/dev/null) || got=""
|
||||
if [[ "${got%-*}" == "$want" ]]; then
|
||||
print_success "$channel now serves omarchy $got"
|
||||
pending=""
|
||||
for arch in $(published_arches); do
|
||||
got=$(published_version "$channel" "$arch" 2>/dev/null) || got=""
|
||||
[[ "${got%-*}" == "$want" ]] || pending+=" $arch=${got:-unreachable}"
|
||||
done
|
||||
if [[ -z "$pending" ]]; then
|
||||
print_success "$channel now serves omarchy $want on every published architecture"
|
||||
return 0
|
||||
fi
|
||||
sleep 60
|
||||
@@ -310,7 +320,7 @@ wait_for_published() { # wait_for_published <channel> <version> [timeout-seconds
|
||||
printf '.' >&2
|
||||
done
|
||||
echo "" >&2
|
||||
print_warning "Timed out waiting for $want in $channel (currently: ${got:-unknown})"
|
||||
print_warning "Timed out waiting for $want in $channel (pending:$pending)"
|
||||
print_info "The build may still be running — re-run this command to resume."
|
||||
return 1
|
||||
}
|
||||
@@ -674,15 +684,13 @@ cmd_rc() {
|
||||
if [[ -n "$pin" ]]; then
|
||||
local pin_ver="${pin%% *}" pin_commit="${pin##* }"
|
||||
if [[ "$pin_commit" == "$head" && "$pin_ver" =~ ^${version//./\\.}rc[0-9]+$ ]]; then
|
||||
local pub
|
||||
pub=$(published_version rc 2>/dev/null) || pub=""
|
||||
if [[ "${pub%-*}" == "$pin_ver" ]]; then
|
||||
print_success "$pin_ver is already cut from this head and published to rc"
|
||||
if all_arches_at_version rc "$pin_ver"; then
|
||||
print_success "$pin_ver is already cut from this head and published to rc on every architecture"
|
||||
maybe_iso "$pin_ver" rc "$iso_mode"
|
||||
return 0
|
||||
fi
|
||||
print_info "$pin_ver is pinned from this head but not published yet — re-triggering the build"
|
||||
trigger_rc_build || true
|
||||
trigger_rc_build || return 1
|
||||
[[ "$wait" == true ]] && wait_for_published rc "$pin_ver"
|
||||
maybe_iso "$pin_ver" rc "$iso_mode"
|
||||
return 0
|
||||
@@ -698,7 +706,7 @@ cmd_rc() {
|
||||
new_ver="${new_pin%% *}"
|
||||
print_success "Pinned $new_ver (rc branch pushed)"
|
||||
|
||||
trigger_rc_build || true
|
||||
trigger_rc_build || return 1
|
||||
if [[ "$wait" == true ]]; then
|
||||
wait_for_published rc "$new_ver" || return 1
|
||||
fi
|
||||
@@ -720,9 +728,7 @@ cmd_ship() {
|
||||
exit 1
|
||||
fi
|
||||
version=$(branch_to_version "$branch")
|
||||
local stable_now
|
||||
stable_now=$(published_version stable 2>/dev/null) || stable_now=""
|
||||
if [[ "${stable_now%-*}" == "$version" ]] &&
|
||||
if all_arches_at_version stable "$version" &&
|
||||
gh release view "v$version" --repo "$UPSTREAM_REPO" >/dev/null 2>&1; then
|
||||
print_success "Nothing to ship — $version is tagged, released, and live on stable"
|
||||
exit 0
|
||||
@@ -764,10 +770,8 @@ cmd_ship() {
|
||||
echo " omarchy-release rc"
|
||||
exit 1
|
||||
fi
|
||||
local pub
|
||||
pub=$(published_version rc 2>/dev/null) || pub=""
|
||||
if [[ "${pub%-*}" != "$pin_ver" ]]; then
|
||||
print_error "$pin_ver is pinned but rc serves '${pub:-nothing}' — the candidate build hasn't published"
|
||||
if ! all_arches_at_version rc "$pin_ver"; then
|
||||
print_error "$pin_ver is pinned but is not published for every architecture"
|
||||
echo "Wait for it (or re-run: omarchy-release rc), then ship."
|
||||
exit 1
|
||||
fi
|
||||
@@ -811,10 +815,9 @@ cmd_ship() {
|
||||
|
||||
# 2. Final pins into rc. Resolve the tag we just established so the final
|
||||
# PKGBUILDs record both its provenance and its exact commit.
|
||||
local rc_pub stable_pub
|
||||
rc_pub=$(published_version rc 2>/dev/null) || rc_pub=""
|
||||
if [[ "${rc_pub%-*}" == "$version" ]]; then
|
||||
print_success "2/7 Final $version already published to rc"
|
||||
local stable_pub
|
||||
if all_arches_at_version rc "$version"; then
|
||||
print_success "2/7 Final $version already published to rc on every architecture"
|
||||
else
|
||||
if [[ "$pin_ver" != "$version" ]]; then
|
||||
print_info "2/7 Pinning final $version from tag v$version..."
|
||||
@@ -822,22 +825,21 @@ cmd_ship() {
|
||||
else
|
||||
print_info "2/7 Final $version pinned — re-triggering build"
|
||||
fi
|
||||
trigger_rc_build || true
|
||||
trigger_rc_build || exit 1
|
||||
wait_for_published rc "$version" || exit 1
|
||||
fi
|
||||
|
||||
# 3. Promote rc -> stable
|
||||
stable_pub=$(published_version stable 2>/dev/null) || stable_pub=""
|
||||
if [[ "${stable_pub%-*}" == "$version" ]]; then
|
||||
print_success "3/7 Stable already serves $version"
|
||||
if all_arches_at_version stable "$version"; then
|
||||
print_success "3/7 Stable already serves $version on every architecture"
|
||||
else
|
||||
host_advance rc stable || exit 1
|
||||
stable_pub=$(published_version stable 2>/dev/null) || stable_pub=""
|
||||
if [[ "${stable_pub%-*}" != "$version" ]]; then
|
||||
print_error "Promotion ran but stable serves '${stable_pub:-nothing}' — investigate before continuing"
|
||||
if ! all_arches_at_version stable "$version"; then
|
||||
print_error "Promotion ran but stable does not serve $version on every architecture"
|
||||
exit 1
|
||||
fi
|
||||
print_success "3/7 Promoted to stable: omarchy $stable_pub"
|
||||
stable_pub=$(published_version stable 2>/dev/null) || stable_pub="$version"
|
||||
print_success "3/7 Promoted to stable: omarchy $stable_pub on every architecture"
|
||||
fi
|
||||
|
||||
# 4. Final pins onto master (keeps edge overlap publishing and the repo record)
|
||||
@@ -920,7 +922,7 @@ next_step() { # prints "<command>|<description>"
|
||||
last=$(newest_release_branch 2>/dev/null) || last=""
|
||||
if [[ -n "$last" && "$STABLE_VER" != "<unreachable>" ]]; then
|
||||
last_ver=$(branch_to_version "$last")
|
||||
if [[ "${STABLE_VER%-*}" != "$last_ver" ]] ||
|
||||
if ! all_arches_at_version stable "$last_ver" ||
|
||||
{ command -v gh >/dev/null && ! gh release view "v$last_ver" --repo "$UPSTREAM_REPO" >/dev/null 2>&1; }; then
|
||||
echo "ship|$last_ver is tagged but not fully shipped — resume ship"
|
||||
return
|
||||
@@ -936,7 +938,7 @@ next_step() { # prints "<command>|<description>"
|
||||
echo "ship|Final $TRAIN_VER is pinned — finish shipping (re-runs are safe)"
|
||||
elif [[ "$pin_commit" != "$TRAIN_HEAD" ]]; then
|
||||
echo "rc|$TRAIN has commits newer than $pin_ver — cut the next candidate"
|
||||
elif [[ "${RC_VER%-*}" != "$pin_ver" ]]; then
|
||||
elif ! all_arches_at_version rc "$pin_ver"; then
|
||||
echo "rc|$pin_ver is pinned but not published — re-run rc to re-trigger/wait"
|
||||
else
|
||||
echo "ship|$pin_ver is published to rc — test it, then ship"
|
||||
@@ -1006,20 +1008,24 @@ cmd_doctor() {
|
||||
check "makepkg available (checksums)" command -v makepkg
|
||||
check "curl available" command -v curl
|
||||
check "upstream reachable ($UPSTREAM_URL)" git ls-remote "$UPSTREAM_URL" HEAD
|
||||
local ch
|
||||
local ch arch
|
||||
for ch in edge stable; do
|
||||
if published_version "$ch" >/dev/null 2>&1; then
|
||||
print_success "$ch channel db readable"
|
||||
for arch in $(published_arches); do
|
||||
if published_version "$ch" "$arch" >/dev/null 2>&1; then
|
||||
print_success "$ch/$arch channel db readable"
|
||||
else
|
||||
print_error "$ch/$arch channel db readable"
|
||||
failures=$((failures + 1))
|
||||
fi
|
||||
done
|
||||
done
|
||||
for arch in $(published_arches); do
|
||||
if published_version rc "$arch" >/dev/null 2>&1; then
|
||||
print_success "rc/$arch channel db readable"
|
||||
else
|
||||
print_error "$ch channel db readable"
|
||||
failures=$((failures + 1))
|
||||
print_warning "rc/$arch channel db not readable — bootstrap it first: bin/repo bootstrap-rc (on the build host)"
|
||||
fi
|
||||
done
|
||||
if published_version rc >/dev/null 2>&1; then
|
||||
print_success "rc channel db readable"
|
||||
else
|
||||
print_warning "rc channel db not readable — bootstrap it first: bin/repo bootstrap-rc (on the build host)"
|
||||
fi
|
||||
local host
|
||||
if host=$(repo_host); then
|
||||
check "build host ssh ($host)" ssh -o ConnectTimeout=10 "$host" true
|
||||
@@ -1066,6 +1072,25 @@ cmd_self_test() {
|
||||
expect "version_is_patch 5.0.0" "$(version_is_patch 5.0.0 && echo yes || echo no)" "no"
|
||||
expect "previous_patch_tag 4.0.2" "$(previous_patch_tag 4.0.2)" "v4.0.1"
|
||||
expect "previous_patch_tag 4.0.10" "$(previous_patch_tag 4.0.10)" "v4.0.9"
|
||||
|
||||
# Keep release readiness fail-closed when only one architecture has reached
|
||||
# the requested version. This replaces the network reader for this process;
|
||||
# self-test exits immediately afterwards.
|
||||
published_version() {
|
||||
case "$2" in
|
||||
x86_64) echo "${TEST_X86_VERSION:-4.0.2-1}" ;;
|
||||
aarch64) echo "${TEST_ARM_VERSION:-4.0.2-1}" ;;
|
||||
esac
|
||||
}
|
||||
PUBLISHED_ARCHES=x86_64
|
||||
expect "x86-only readiness" "$(all_arches_at_version rc 4.0.2 && echo ready || echo blocked)" "ready"
|
||||
PUBLISHED_ARCHES=aarch64
|
||||
expect "ARM-only readiness" "$(all_arches_at_version rc 4.0.2 && echo ready || echo blocked)" "ready"
|
||||
PUBLISHED_ARCHES="x86_64 aarch64"
|
||||
TEST_ARM_VERSION=4.0.1-1
|
||||
expect "mixed versions block release" "$(all_arches_at_version rc 4.0.2 && echo ready || echo blocked)" "blocked"
|
||||
TEST_ARM_VERSION=4.0.2-1
|
||||
expect "both architectures ready" "$(all_arches_at_version rc 4.0.2 && echo ready || echo blocked)" "ready"
|
||||
echo ""
|
||||
if ((failures == 0)); then
|
||||
print_success "Self-test passed"
|
||||
|
||||
Reference in new issue
Block a user