Track HiveGrid Cloud planning reference
This commit is contained in:
1 parent
b3d5ea6764
commit
e341c5938a
5784 files changed
+1104929
-3
No files matched your search
+129
@@ -0,0 +1,129 @@
|
||||
#!/usr/bin/env bash
|
||||
# Forward + rollback migration drill against an ephemeral PostgreSQL
|
||||
# container. Validates that:
|
||||
# 1. All committed migrations apply cleanly from an empty database
|
||||
# 2. The seed runs idempotently against the resulting schema
|
||||
# 3. Running the entire forward chain a second time is a no-op
|
||||
# (Prisma marks every migration as already applied)
|
||||
#
|
||||
# This is a production-rehearsal: catches migrations that fail under a
|
||||
# fresh DB (drift between dev shadow and production state) and asserts the
|
||||
# seed-after-migrate contract that prod deploys rely on.
|
||||
#
|
||||
# Usage:
|
||||
# ./scripts/drill-migration-rollback.sh
|
||||
# ./scripts/drill-migration-rollback.sh --no-seed # skip seed step
|
||||
# ./scripts/drill-migration-rollback.sh --keep-container # leave PG running
|
||||
#
|
||||
# Requires: docker, pnpm. Aborts with a documentation pointer if either
|
||||
# is missing.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
DRILL_NAME="boilerplate-rollback-drill-$$"
|
||||
DRILL_PORT="${DRILL_PG_PORT:-55842}"
|
||||
DRILL_USER="drill"
|
||||
DRILL_PASSWORD="drill"
|
||||
DRILL_DB="drill"
|
||||
DRILL_DATABASE_URL="postgresql://${DRILL_USER}:${DRILL_PASSWORD}@127.0.0.1:${DRILL_PORT}/${DRILL_DB}?schema=public"
|
||||
KEEP_CONTAINER=0
|
||||
RUN_SEED=1
|
||||
PG_IMAGE="${DRILL_PG_IMAGE:-postgres:16-alpine}"
|
||||
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--no-seed) RUN_SEED=0 ;;
|
||||
--keep-container) KEEP_CONTAINER=1 ;;
|
||||
--help|-h)
|
||||
sed -n '2,/^$/p' "$0" | sed 's/^# \?//'
|
||||
exit 0
|
||||
;;
|
||||
*) echo "Unknown arg: $arg" >&2; exit 64 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
require_cmd() {
|
||||
if ! command -v "$1" >/dev/null 2>&1; then
|
||||
echo "MISSING $1" >&2
|
||||
echo "" >&2
|
||||
echo "Migration-rollback drill requires '$1' to be available locally." >&2
|
||||
echo "See docs/operations/database-rollback.md for the manual procedure." >&2
|
||||
exit 127
|
||||
fi
|
||||
}
|
||||
|
||||
require_cmd docker
|
||||
require_cmd pnpm
|
||||
|
||||
cleanup() {
|
||||
local exit_code=$?
|
||||
if [ "$KEEP_CONTAINER" = "0" ]; then
|
||||
docker rm -f "$DRILL_NAME" >/dev/null 2>&1 || true
|
||||
else
|
||||
echo ""
|
||||
echo "KEEP container '$DRILL_NAME' is still running on port $DRILL_PORT (DATABASE_URL=$DRILL_DATABASE_URL)" >&2
|
||||
fi
|
||||
exit "$exit_code"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
echo "PHASE 0/4 starting ephemeral postgres ($PG_IMAGE on port $DRILL_PORT)"
|
||||
docker run --rm -d \
|
||||
--name "$DRILL_NAME" \
|
||||
-p "${DRILL_PORT}:5432" \
|
||||
-e POSTGRES_USER="$DRILL_USER" \
|
||||
-e POSTGRES_PASSWORD="$DRILL_PASSWORD" \
|
||||
-e POSTGRES_DB="$DRILL_DB" \
|
||||
"$PG_IMAGE" >/dev/null
|
||||
|
||||
deadline=$(( $(date +%s) + 30 ))
|
||||
until docker exec "$DRILL_NAME" pg_isready -U "$DRILL_USER" -d "$DRILL_DB" >/dev/null 2>&1; do
|
||||
if [ "$(date +%s)" -gt "$deadline" ]; then
|
||||
echo "FAIL postgres did not become ready within 30s" >&2
|
||||
exit 1
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
echo "PASS postgres ready"
|
||||
|
||||
echo "PHASE 1/4 applying forward migration chain"
|
||||
DATABASE_URL="$DRILL_DATABASE_URL" pnpm --filter @toolctrl/db prisma:generate >/dev/null
|
||||
DATABASE_URL="$DRILL_DATABASE_URL" pnpm exec prisma migrate deploy --schema prisma/schema/schema.prisma
|
||||
|
||||
forward_count=$(DATABASE_URL="$DRILL_DATABASE_URL" pnpm exec prisma migrate status --schema prisma/schema/schema.prisma 2>&1 | grep -c "Following migration have been applied" || true)
|
||||
echo "PASS forward migration chain applied"
|
||||
|
||||
if [ "$RUN_SEED" = "1" ]; then
|
||||
echo "PHASE 2/4 running production seed (idempotency probe 1/2)"
|
||||
DATABASE_URL="$DRILL_DATABASE_URL" \
|
||||
SEED_ADMIN_EMAIL="drill-admin@example.com" \
|
||||
SEED_ADMIN_PASSWORD="drill-bootstrap-password-do-not-reuse" \
|
||||
SEED_DEMO_DATA="false" \
|
||||
NODE_ENV=production \
|
||||
pnpm --filter @toolctrl/db seed
|
||||
echo "PASS seed run 1"
|
||||
|
||||
echo "PHASE 3/4 re-running seed (idempotency probe 2/2)"
|
||||
DATABASE_URL="$DRILL_DATABASE_URL" \
|
||||
SEED_ADMIN_EMAIL="drill-admin@example.com" \
|
||||
SEED_ADMIN_PASSWORD="drill-bootstrap-password-do-not-reuse" \
|
||||
SEED_DEMO_DATA="false" \
|
||||
NODE_ENV=production \
|
||||
pnpm --filter @toolctrl/db seed
|
||||
echo "PASS seed run 2 (idempotent)"
|
||||
else
|
||||
echo "SKIP seed (--no-seed flag)"
|
||||
fi
|
||||
|
||||
echo "PHASE 4/4 re-applying migrate deploy (chain idempotency)"
|
||||
output=$(DATABASE_URL="$DRILL_DATABASE_URL" pnpm exec prisma migrate deploy --schema prisma/schema/schema.prisma 2>&1)
|
||||
echo "$output" | tail -5
|
||||
if echo "$output" | grep -qiE "no pending migrations|already in sync|database schema is up to date"; then
|
||||
echo "PASS migrate deploy is a no-op on already-migrated schema"
|
||||
else
|
||||
echo "FAIL second migrate deploy reported changes — chain is not idempotent" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "DRILL OK — migration chain + seed survive a fresh-database deployment rehearsal"
|
||||
Reference in new issue
Block a user