Fix deploy.sh skipping SPA build on same-ref/aborted deploys
The build was gated on `git diff BEFORE AFTER`, where BEFORE was HEAD before checkout. Re-deploying the same ref (or re-running after an aborted deploy) made BEFORE == AFTER, so the diff was empty and the SPA build silently skipped — shipping stale assets while migrations still ran. - Always rebuild the SPA; only gate the heavy dep installs. - npm ci / composer install also run when node_modules / vendor are missing. - Track the last successfully deployed commit in .deploy-last-commit and diff against that, so an aborted run never advances the baseline. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -24,4 +24,5 @@ yarn-error.log
|
|||||||
/.zed
|
/.zed
|
||||||
/.tmp/
|
/.tmp/
|
||||||
/.worktrees/
|
/.worktrees/
|
||||||
|
/.deploy-last-commit
|
||||||
/ONSPD_Online_Latest_Centroids_*.csv
|
/ONSPD_Online_Latest_Centroids_*.csv
|
||||||
|
|||||||
45
deploy.sh
45
deploy.sh
@@ -6,10 +6,11 @@
|
|||||||
# ./deploy.sh v0.1.3 # deploy a specific tag
|
# ./deploy.sh v0.1.3 # deploy a specific tag
|
||||||
#
|
#
|
||||||
# It puts the site in maintenance mode, updates the code, runs migrations and
|
# It puts the site in maintenance mode, updates the code, runs migrations and
|
||||||
# cache rebuilds, restarts the queue, then brings the site back up. composer
|
# cache rebuilds, restarts the queue, then brings the site back up. The SPA is
|
||||||
# install and npm build only run when their inputs actually changed, so most
|
# always rebuilt; the heavier dependency installs (composer install, npm ci)
|
||||||
# deploys skip them. If any step fails the script aborts and the site stays in
|
# only run when their lockfiles changed or the installed dir is missing. If any
|
||||||
# maintenance mode on purpose — fix the issue, then re-run.
|
# step fails the script aborts and the site stays in maintenance mode on
|
||||||
|
# purpose — fix the issue, then re-run.
|
||||||
#
|
#
|
||||||
# See docs/ops/deployment.md for first-time setup and troubleshooting.
|
# See docs/ops/deployment.md for first-time setup and troubleshooting.
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
@@ -19,8 +20,13 @@ cd "$(dirname "$0")"
|
|||||||
REF="${1:-main}"
|
REF="${1:-main}"
|
||||||
echo "==> Deploying ref: ${REF}"
|
echo "==> Deploying ref: ${REF}"
|
||||||
|
|
||||||
# Remember the current commit so we can see what changed after checkout.
|
# Baseline for change detection: the last *fully* deployed commit, recorded at
|
||||||
BEFORE="$(git rev-parse HEAD)"
|
# the end of a successful run (falls back to current HEAD the first time). Using
|
||||||
|
# a persisted marker instead of the pre-checkout HEAD keeps the diff honest even
|
||||||
|
# when the same ref is re-deployed or a previous run aborted partway — both of
|
||||||
|
# which otherwise make BEFORE == AFTER and silently skip build/install steps.
|
||||||
|
MARKER=".deploy-last-commit"
|
||||||
|
BEFORE="$(cat "${MARKER}" 2>/dev/null || git rev-parse HEAD)"
|
||||||
|
|
||||||
echo "==> Maintenance mode on"
|
echo "==> Maintenance mode on"
|
||||||
php artisan down --retry=15
|
php artisan down --retry=15
|
||||||
@@ -36,23 +42,29 @@ fi
|
|||||||
AFTER="$(git rev-parse HEAD)"
|
AFTER="$(git rev-parse HEAD)"
|
||||||
CHANGED="$(git diff --name-only "${BEFORE}" "${AFTER}" || true)"
|
CHANGED="$(git diff --name-only "${BEFORE}" "${AFTER}" || true)"
|
||||||
|
|
||||||
# Reinstall PHP deps only if the lockfile moved.
|
# Reinstall PHP deps only when the lockfile moved or vendor is missing.
|
||||||
if grep -q '^composer\.lock$' <<<"${CHANGED}"; then
|
if grep -q '^composer\.lock$' <<<"${CHANGED}" || [ ! -d vendor ]; then
|
||||||
echo "==> composer.lock changed — installing PHP deps"
|
echo "==> Installing PHP deps (composer.lock changed or vendor missing)"
|
||||||
composer install --no-dev --optimize-autoloader
|
composer install --no-dev --optimize-autoloader
|
||||||
else
|
else
|
||||||
echo "==> composer.lock unchanged — skipping composer install"
|
echo "==> composer.lock unchanged — skipping composer install"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Rebuild the Vue SPA only if frontend sources or the JS lockfile moved.
|
# Install JS deps only when the lockfile moved or node_modules is missing.
|
||||||
if grep -qE '^(package(-lock)?\.json|vite\.config\.|resources/(js|css)/)' <<<"${CHANGED}"; then
|
if grep -qE '^package(-lock)?\.json$' <<<"${CHANGED}" || [ ! -d node_modules ]; then
|
||||||
echo "==> Frontend changed — rebuilding SPA"
|
echo "==> Installing JS deps (lockfile changed or node_modules missing)"
|
||||||
npm ci
|
npm ci
|
||||||
npm run build
|
|
||||||
else
|
else
|
||||||
echo "==> No frontend changes — skipping npm build"
|
echo "==> JS deps unchanged — skipping npm ci"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Always rebuild the SPA. The build is cheap (a few seconds), and gating it on a
|
||||||
|
# git diff silently shipped stale assets whenever BEFORE == AFTER — re-deploying
|
||||||
|
# the same ref, or re-running after an aborted deploy. Correctness over the few
|
||||||
|
# seconds saved.
|
||||||
|
echo "==> Building SPA"
|
||||||
|
npm run build
|
||||||
|
|
||||||
echo "==> Running migrations"
|
echo "==> Running migrations"
|
||||||
php artisan migrate --force
|
php artisan migrate --force
|
||||||
|
|
||||||
@@ -68,5 +80,10 @@ php artisan queue:restart
|
|||||||
echo "==> Maintenance mode off"
|
echo "==> Maintenance mode off"
|
||||||
php artisan up
|
php artisan up
|
||||||
|
|
||||||
|
# Record the just-deployed commit as the baseline for the next run. Only reached
|
||||||
|
# on full success — `set -e` aborts earlier on any failure, so a broken deploy
|
||||||
|
# never advances the baseline and the next run re-evaluates from the last good one.
|
||||||
|
git rev-parse HEAD > "${MARKER}"
|
||||||
|
|
||||||
echo "==> Deploy complete"
|
echo "==> Deploy complete"
|
||||||
php artisan about
|
php artisan about
|
||||||
|
|||||||
Reference in New Issue
Block a user