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>
90 lines
3.2 KiB
Bash
Executable File
90 lines
3.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# FuelAlert deploy script — run on the VPS from the project root:
|
|
#
|
|
# ./deploy.sh # deploy the latest main
|
|
# ./deploy.sh v0.1.3 # deploy a specific tag
|
|
#
|
|
# It puts the site in maintenance mode, updates the code, runs migrations and
|
|
# cache rebuilds, restarts the queue, then brings the site back up. The SPA is
|
|
# always rebuilt; the heavier dependency installs (composer install, npm ci)
|
|
# only run when their lockfiles changed or the installed dir is missing. If any
|
|
# 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.
|
|
set -euo pipefail
|
|
|
|
cd "$(dirname "$0")"
|
|
|
|
REF="${1:-main}"
|
|
echo "==> Deploying ref: ${REF}"
|
|
|
|
# Baseline for change detection: the last *fully* deployed commit, recorded at
|
|
# 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"
|
|
php artisan down --retry=15
|
|
|
|
git fetch --tags --prune origin
|
|
git checkout "${REF}"
|
|
|
|
# Fast-forward to the remote only when on a branch (a tag leaves a detached HEAD).
|
|
if git symbolic-ref -q HEAD >/dev/null; then
|
|
git pull --ff-only
|
|
fi
|
|
|
|
AFTER="$(git rev-parse HEAD)"
|
|
CHANGED="$(git diff --name-only "${BEFORE}" "${AFTER}" || true)"
|
|
|
|
# Reinstall PHP deps only when the lockfile moved or vendor is missing.
|
|
if grep -q '^composer\.lock$' <<<"${CHANGED}" || [ ! -d vendor ]; then
|
|
echo "==> Installing PHP deps (composer.lock changed or vendor missing)"
|
|
composer install --no-dev --optimize-autoloader
|
|
else
|
|
echo "==> composer.lock unchanged — skipping composer install"
|
|
fi
|
|
|
|
# Install JS deps only when the lockfile moved or node_modules is missing.
|
|
if grep -qE '^package(-lock)?\.json$' <<<"${CHANGED}" || [ ! -d node_modules ]; then
|
|
echo "==> Installing JS deps (lockfile changed or node_modules missing)"
|
|
npm ci
|
|
else
|
|
echo "==> JS deps unchanged — skipping npm ci"
|
|
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"
|
|
php artisan migrate --force
|
|
|
|
echo "==> Rebuilding caches"
|
|
php artisan config:cache
|
|
php artisan route:cache
|
|
php artisan view:cache
|
|
php artisan event:cache
|
|
|
|
echo "==> Restarting queue workers"
|
|
php artisan queue:restart
|
|
|
|
echo "==> Maintenance mode off"
|
|
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"
|
|
php artisan about
|