Files
pig/scripts/deploy.sh
T
karti d4d7095605
CI / verify (push) Successful in 2m32s
Migrate before starting the application
2026-08-13 01:48:05 -07:00

87 lines
2.7 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# Deploy PIG. Run on the host that serves it.
#
# ./scripts/deploy.sh
#
# Deliberately a script rather than automated push-to-deploy. Automating it
# would mean putting an SSH key with write access to the production host onto
# the CI runner, which is a meaningful escalation for a project this size. CI
# proves the commit is sound; a human decides when it ships.
#
# Safe to re-run. Migrations are additive and tracked.
set -euo pipefail
cd "$(dirname "$0")/.."
echo "==> Fetching"
git fetch -q origin
BEFORE=$(git rev-parse --short HEAD)
git reset --hard -q origin/main
AFTER=$(git rev-parse --short HEAD)
if [ "$BEFORE" = "$AFTER" ]; then
echo " Already at $AFTER"
else
echo " $BEFORE -> $AFTER"
git --no-pager log --oneline "$BEFORE..$AFTER" | sed 's/^/ /'
fi
echo "==> Backing up the database first"
# Cheap insurance. A migration that goes wrong on a database holding real deal
# data is not something to discover without a dump in hand.
mkdir -p backups
BACKUP="backups/pig-$(date +%Y%m%d-%H%M%S).sql.gz"
sudo docker compose -p pig exec -T db pg_dump -U pig pig | gzip > "$BACKUP"
echo " $BACKUP ($(du -h "$BACKUP" | cut -f1))"
echo "==> Building"
sudo docker compose -p pig build app
echo "==> Starting the database"
sudo docker compose -p pig up -d db
for _ in $(seq 1 60); do
if sudo docker compose -p pig exec -T db pg_isready -U pig -d pig > /dev/null; then break; fi
sleep 1
done
if ! sudo docker compose -p pig exec -T db pg_isready -U pig -d pig > /dev/null; then
echo "ERROR: database did not become ready within 60 seconds" >&2
exit 1
fi
echo "==> Migrating before the schema-dependent app starts"
# A release may query a newly introduced table during startup. Running the
# migration from a one-off container prevents that app from crash-looping
# before an `exec`-based migration can reach it.
sudo docker compose -p pig run --rm --no-deps app npx tsx packages/db/src/migrate.ts
echo "==> Starting the app"
sudo docker compose -p pig up -d app
echo "==> Waiting for health"
for _ in $(seq 1 60); do
if curl -sf http://127.0.0.1:8920/api/health > /dev/null; then break; fi
sleep 1
done
echo "==> Verifying"
if curl -sf http://127.0.0.1:8920/api/health | grep -q '"ok":true'; then
echo " health ok"
else
echo " HEALTH CHECK FAILED"
sudo docker compose -p pig logs app --tail 40
exit 1
fi
# Authentication must be enforced. A deploy that accidentally serves the CRM
# unauthenticated is the one failure worth blocking on.
CODE=$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8920/api/dashboard)
if [ "$CODE" != "401" ]; then
echo " UNAUTHENTICATED REQUEST RETURNED $CODE, EXPECTED 401"
exit 1
fi
echo " auth enforced"
echo "==> Deployed $AFTER"