Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/maintenance/17276-phase0-build-preflight.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- **chore(release):** `scripts/release/preflight-build.sh` runs, before the release freeze, the checks that only explode on the tag — README/llm.txt version claims, root and `electron/` lockfile sync (`npm ci --dry-run`), vitest, `build:cli` + `check:pack-boot`, and a 2-minute smoke of the Bun `runner-web` apt list on the Bun base image (`preflight-bun-apt-smoke.sh`) ([#17276](https://github.com/diegosouzapw/OmniRoute/pull/17276))
93 changes: 93 additions & 0 deletions scripts/release/preflight-build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#!/usr/bin/env bash
# scripts/release/preflight-build.sh — /generate-release Phase 0: the build checks that explode
# only on the tag, run BEFORE the freeze (v3.8.52 lessons, 2026-10-20).
#
# Why this exists: the PR CI never exercises the three surfaces that broke the v3.8.52 tag —
# • `npm ci` in electron/ (electron-release.yml installs with `ci`; the CI smoke uses `install`,
# which repairs a stale lock silently — #15157 on v3.8.51, #17212 on v3.8.52);
# • the Bun `runner-web` image's apt list (best-effort stage, `continue-on-error` — dead packages
# only surfaced through the manifest guard on the release run, #17223 / #17236);
# • the README/llm.txt current-version claims the cycle bump used to skip (#17237).
# plus the packaging path npm-publish runs (build:cli → check:pack-boot) and the vitest suite.
#
# Usage:
# scripts/release/preflight-build.sh # everything (build:cli can take 25–55 min locally)
# scripts/release/preflight-build.sh --quick # lockfiles + version claims only (~20 s)
# scripts/release/preflight-build.sh --no-build # skip build:cli / pack-boot (CI artifact already proven)
# scripts/release/preflight-build.sh --no-docker# skip the Dockerfile.bun apt smoke (needs ssh to the .113)
# Logs: _artifacts/preflight/<check>.log (gitignored). Exit 1 on the first class of failure, after
# running every check, so one run lists everything to fix.

set -uo pipefail
ROOT=$(git rev-parse --show-toplevel)
cd "$ROOT"
QUICK=0
BUILD=1
DOCKER=1
for a in "$@"; do
case "$a" in
--quick) QUICK=1 ;;
--no-build) BUILD=0 ;;
--no-docker) DOCKER=0 ;;
-h | --help)
sed -n '2,20p' "$0"
exit 0
;;
esac
done
VERSION=$(node -p "require('./package.json').version")
LOGDIR="$ROOT/_artifacts/preflight"
mkdir -p "$LOGDIR"
FAIL=0
ROWS=()

run() {
# run <name> <timeout-seconds> <command...>
local name=$1 to=$2
shift 2
local slug log t0 st rc
slug=$(printf '%s' "$name" | tr -c 'A-Za-z0-9' '_')
log="$LOGDIR/$slug.log"
t0=$(date +%s)
if timeout "$to" "$@" > "$log" 2>&1; then
st=PASS
else
rc=$?
st="FAIL(rc=$rc)"
FAIL=1
fi
ROWS+=("| $name | $st | $(( $(date +%s) - t0 ))s | $log |")
echo "[$st] $name ($(( $(date +%s) - t0 ))s)"
}

echo "preflight-build v$VERSION — $(date -u +%Y-%m-%dT%H:%M:%SZ) — quick=$QUICK build=$BUILD docker=$DOCKER"

run "version claims (README.md, llm.txt)" 60 \
node scripts/release/bump-version-claims.mjs --check --to "$VERSION"
run "root lockfile in sync (npm ci --dry-run)" 300 \
npm ci --dry-run --ignore-scripts
run "electron lockfile in sync (npm ci --dry-run)" 300 \
bash -c 'cd electron && npm ci --dry-run --ignore-scripts'

if [ "$QUICK" -eq 0 ]; then
run "vitest (MCP, autoCombo, cache)" 1200 npm run test:vitest
if [ "$BUILD" -eq 1 ]; then
run "build:cli (standalone + CLI bundle)" 4000 npm run build:cli
run "pack-boot (the tarball users install boots)" 900 npm run check:pack-boot
fi
if [ "$DOCKER" -eq 1 ]; then
run "Dockerfile.bun runner-web apt smoke (.113)" 900 \
scripts/release/preflight-bun-apt-smoke.sh
fi
fi

echo
echo "| Check | Result | Time | Log |"
echo "| --- | --- | ---: | --- |"
printf '%s\n' "${ROWS[@]}"
echo
if [ "$FAIL" -ne 0 ]; then
echo "❌ preflight-build: at least one check failed — fix on the release branch BEFORE the freeze."
exit 1
fi
echo "✅ preflight-build: every check passed for v$VERSION."
48 changes: 48 additions & 0 deletions scripts/release/preflight-bun-apt-smoke.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/usr/bin/env bash
# scripts/release/preflight-bun-apt-smoke.sh — proves the apt list of Dockerfile.bun's `runner-web`
# stage installs on the Bun base image, WITHOUT the 12 GB Next build the real stage sits on.
#
# The stage is `continue-on-error` in docker-publish.yml, so a dead package (gconf-service,
# stdc++6, fonts-kacst on v3.8.52 — #17236) never fails the build job; it only surfaced when the
# manifest guard tripped over the missing bun-web digest (#17223). This smoke runs the same
# `apt-get install` block in a throwaway image on a Docker host (default: the .113 build VPS, which
# the devbox reaches over ssh; set PREFLIGHT_DOCKER_HOST="" to build locally) and asks the installed
# Chromium for its version.
#
# Usage: scripts/release/preflight-bun-apt-smoke.sh [Dockerfile.bun]
# Env: PREFLIGHT_DOCKER_HOST ssh target with Docker (default root@192.168.0.113); "" = local docker
set -euo pipefail
ROOT=$(git rev-parse --show-toplevel)
DOCKERFILE=${1:-"$ROOT/Dockerfile.bun"}
HOST=${PREFLIGHT_DOCKER_HOST-root@192.168.0.113}
OUT="$ROOT/_artifacts/preflight"
mkdir -p "$OUT"
SMOKE="$OUT/bun-apt-smoke.Dockerfile"

BASE=$(awk '/^FROM .* AS runner-base$/ { print $2; exit }' "$DOCKERFILE")
[ -n "$BASE" ] || { echo "runner-base FROM line not found in $DOCKERFILE" >&2; exit 2; }
# The RUN apt-get … block of the runner-web stage, verbatim (first RUN after its FROM).
APT_BLOCK=$(awk '
/^FROM runner-base AS runner-web$/ { stage = 1; next }
stage && /^RUN apt-get/ { grab = 1 }
grab { print }
grab && !/\\$/ { exit }
' "$DOCKERFILE")
[ -n "$APT_BLOCK" ] || { echo "runner-web apt block not found in $DOCKERFILE" >&2; exit 2; }

{
echo "FROM $BASE"
echo "USER root"
printf '%s\n' "$APT_BLOCK"
echo 'RUN /usr/bin/chromium --version'
} > "$SMOKE"

echo "[bun-apt-smoke] base=$BASE host=${HOST:-local}"
if [ -z "$HOST" ]; then
docker build --no-cache -f "$SMOKE" -t omniroute-bun-apt-smoke "$OUT"
else
scp -q -o BatchMode=yes "$SMOKE" "$HOST:/tmp/omniroute-bun-apt-smoke.Dockerfile"
# shellcheck disable=SC2029
ssh -o BatchMode=yes "$HOST" 'cd /tmp && docker build --no-cache -f omniroute-bun-apt-smoke.Dockerfile -t omniroute-bun-apt-smoke . 2>&1 | grep -E "^#[0-9]+ (DONE|ERROR)|E: |Chromium [0-9]|Package .* (is not|has no)" ; exit ${PIPESTATUS[0]}'
fi
echo "[bun-apt-smoke] ✅ the runner-web apt list installs on $BASE"
Loading