From 4d3f2470bc7a9e67da549da663802ee2844d088a Mon Sep 17 00:00:00 2001 From: Paul Nothaft Date: Tue, 19 May 2026 22:53:30 +0200 Subject: [PATCH] ci(schema-drift): handle absent migrations table in precondition (#530) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First CI run failed at the precondition check because the SQL `CASE WHEN to_regclass(...) IS NULL THEN 0 ELSE (SELECT count(*) FROM migrations)` expression doesn't short-circuit at parse time — Postgres parses the subquery against `migrations` even when the outer guard would skip it, fails the run with "relation 'migrations' does not exist". initializeDatabase() doesn't create the `migrations` tracking table — that's the migrate:safe runner's responsibility — so in the recovery scenario the table genuinely doesn't exist yet. Both "absent table" and "present but empty table" are valid recovery states. Split the check into two shell steps: to_regclass first, then count only if the table exists. Avoids the parse-time subquery error and accepts either state. --- .github/workflows/schema-drift.yml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/.github/workflows/schema-drift.yml b/.github/workflows/schema-drift.yml index 367ee25a..8811d77b 100644 --- a/.github/workflows/schema-drift.yml +++ b/.github/workflows/schema-drift.yml @@ -116,12 +116,23 @@ jobs: psql -h localhost -U picpeak -d picpeak_drift -c "SELECT tablename FROM pg_tables WHERE schemaname='public' ORDER BY tablename" exit 1 fi - migrations_count=$(psql -h localhost -U picpeak -d picpeak_drift -tAc "SELECT CASE WHEN to_regclass('public.migrations') IS NULL THEN 0 ELSE (SELECT count(*) FROM migrations) END") + # initializeDatabase() doesn't create the `migrations` tracking + # table — that's the migrate:safe runner's job. So in the recovery + # scenario, the table either (a) doesn't exist yet or (b) exists + # but is empty (e.g. someone created it but didn't populate it). + # Both are valid recovery states; check via to_regclass first so + # we don't parse a SELECT against a nonexistent table. + has_migrations_table=$(psql -h localhost -U picpeak -d picpeak_drift -tAc "SELECT to_regclass('public.migrations')::text") + if [ -z "$has_migrations_table" ]; then + migrations_count=0 + else + migrations_count=$(psql -h localhost -U picpeak -d picpeak_drift -tAc "SELECT count(*) FROM migrations") + fi if [ "$migrations_count" != "0" ]; then echo "FAIL: migrations table should be empty for the recovery scenario; has $migrations_count rows." exit 1 fi - echo "ok: recovery state confirmed (bootstrap tables present, migrations table empty)." + echo "ok: recovery state confirmed (bootstrap tables present, migrations table empty or absent)." # Step 2: run migrate:safe — the test. Before #530's fix in # detectExistingSchema, this died at core/029 with a "column