fix(automation): reset test-db schema before restore to avoid P3009
All checks were successful
PR checks / checks (pull_request) Successful in 41s
PR checks / integration (pull_request) Successful in 30s

refresh-test-db.sh mirrored prod with `pg_dump --clean`, which only drops objects
that exist in prod. Objects created on pelagia_test by a previously-applied
UNRELEASED migration (e.g. crewing tables/types not yet released to prod) survived
as leftovers, then collided with the `migrate deploy` replay ("type already
exists", P3009) — blocking every later migration and 500-ing the staging app.

Drop+recreate `public` before the restore so the test DB starts from exactly
prod's objects and unreleased migrations apply cleanly. Adds a guard that refuses
to run unless the derived target is the expected test DB.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hardik 2026-06-23 20:18:24 +05:30
parent f7e38fc60c
commit 81744d1fa8

View file

@ -26,11 +26,22 @@ if [ "$TEST_URL" = "$PROD_URL" ]; then
fi
log "Refreshing $TEST_DB from $PROD_DB ..."
# --clean --if-exists drops+recreates each object in place (first run on an empty
# DB is a no-op for the DROPs). --no-owner/--no-privileges keep it portable.
# Safety: only ever drop/restore the derived TEST database, never prod.
TEST_DBNAME=$(printf '%s' "$TEST_URL" | sed -E 's#.*/([^/?]+)([?].*)?$#\1#')
[ "$TEST_DBNAME" = "$TEST_DB" ] || { log "ERROR: refusing to refresh '$TEST_DBNAME' (expected '$TEST_DB')"; exit 1; }
# Fully reset the test schema BEFORE restoring. `pg_dump --clean` only drops the
# objects that exist in PROD, so anything created on the test DB by a previously
# applied UNRELEASED migration (e.g. crewing tables/types/enum values not yet in
# prod) would survive as a leftover — and then collide with the `migrate deploy`
# replay below ("type already exists", P3009), blocking every later migration.
# Dropping the schema first guarantees the restore brings exactly prod's objects
# and the unreleased migrations apply cleanly. (No-op on an already-empty DB.)
errfile=$(mktemp)
pg_dump --clean --if-exists --no-owner --no-privileges "$PROD_URL" \
| psql "$TEST_URL" >/dev/null 2>"$errfile"
psql "$TEST_URL" -v ON_ERROR_STOP=1 -c "DROP SCHEMA public CASCADE; CREATE SCHEMA public;" >/dev/null 2>"$errfile"
pg_dump --no-owner --no-privileges "$PROD_URL" \
| psql "$TEST_URL" >/dev/null 2>>"$errfile"
prod_tables=$(psql -tAc "SELECT count(*) FROM information_schema.tables WHERE table_schema='public';" "$PROD_URL")
test_tables=$(psql -tAc "SELECT count(*) FROM information_schema.tables WHERE table_schema='public';" "$TEST_URL")