diff --git a/.gitea/workflows/nas-compose-deploy.yml b/.gitea/workflows/nas-compose-deploy.yml index ce03082..d2c37ba 100644 --- a/.gitea/workflows/nas-compose-deploy.yml +++ b/.gitea/workflows/nas-compose-deploy.yml @@ -122,6 +122,77 @@ jobs: chmod 700 ~/.ssh ssh-keyscan -p "${NAS_PORT}" "${NAS_HOST}" >> ~/.ssh/known_hosts + - name: Validate migrations on empty Postgres + run: | + set -eu + + test_name="geo-migration-preflight-${GITHUB_RUN_ID:-manual}-${GITHUB_RUN_NUMBER:-0}" + network_name="${test_name}-net" + postgres_name="${test_name}-postgres" + migrate_image="${test_name}-migrate" + + cleanup() { + docker rm -f "${postgres_name}" >/dev/null 2>&1 || true + docker network rm "${network_name}" >/dev/null 2>&1 || true + docker image rm "${migrate_image}" >/dev/null 2>&1 || true + } + trap cleanup EXIT INT TERM + + docker network create "${network_name}" >/dev/null + docker run -d \ + --name "${postgres_name}" \ + --network "${network_name}" \ + -e POSTGRES_DB=geo \ + -e POSTGRES_USER=geo \ + -e POSTGRES_PASSWORD=geo_dev \ + postgres:16-alpine >/dev/null + + echo "Waiting for empty Postgres..." + for i in $(seq 1 60); do + if docker exec "${postgres_name}" pg_isready -U geo -d geo >/dev/null 2>&1; then + break + fi + if [ "${i}" -eq 60 ]; then + docker logs "${postgres_name}" || true + echo "::error::Postgres did not become ready" + exit 1 + fi + sleep 1 + done + + docker exec "${postgres_name}" createdb -U geo geo_monitoring + + echo "Building migration image..." + DOCKER_BUILDKIT=1 docker build \ + --target migrate \ + --tag "${migrate_image}" \ + -f server/Dockerfile \ + server/ + + database_url="postgres://geo:geo_dev@${postgres_name}:5432/geo?sslmode=disable" + monitoring_database_url="postgres://geo:geo_dev@${postgres_name}:5432/geo_monitoring?sslmode=disable" + ops_database_url="postgres://geo:geo_dev@${postgres_name}:5432/geo?sslmode=disable&x-migrations-table=schema_migrations_ops" + + echo "Running tenant migrations on an empty database..." + docker run --rm --network "${network_name}" "${migrate_image}" \ + -path /migrations \ + -database "${database_url}" \ + up + + echo "Running monitoring migrations on an empty database..." + docker run --rm --network "${network_name}" "${migrate_image}" \ + -path /migrations_monitoring \ + -database "${monitoring_database_url}" \ + up + + echo "Running ops migrations on an empty database..." + docker run --rm --network "${network_name}" "${migrate_image}" \ + -path /migrations_ops \ + -database "${ops_database_url}" \ + up + + echo "Migration preflight passed." + - name: Upload release to NAS run: | set -eu diff --git a/server/migrations/20260408110000_flatten_brand_questions.up.sql b/server/migrations/20260408110000_flatten_brand_questions.up.sql index 707e458..bc1585a 100644 --- a/server/migrations/20260408110000_flatten_brand_questions.up.sql +++ b/server/migrations/20260408110000_flatten_brand_questions.up.sql @@ -1,24 +1,60 @@ ALTER TABLE brand_questions ADD COLUMN IF NOT EXISTS question_text TEXT; -UPDATE brand_questions q -SET question_text = COALESCE( - ( - SELECT v.question_text - FROM brand_question_versions v - WHERE v.id = q.current_version_id - LIMIT 1 - ), - ( - SELECT v.question_text - FROM brand_question_versions v - WHERE v.question_id = q.id - ORDER BY v.version_no DESC, v.id DESC - LIMIT 1 - ), - '' -) -WHERE q.question_text IS NULL; +DO $$ +BEGIN + IF to_regclass('public.brand_question_versions') IS NOT NULL + AND EXISTS ( + SELECT 1 + FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'brand_questions' + AND column_name = 'current_version_id' + ) + THEN + EXECUTE $sql$ + UPDATE brand_questions q + SET question_text = COALESCE( + ( + SELECT v.question_text + FROM brand_question_versions v + WHERE v.id = q.current_version_id + LIMIT 1 + ), + ( + SELECT v.question_text + FROM brand_question_versions v + WHERE v.question_id = q.id + ORDER BY v.version_no DESC, v.id DESC + LIMIT 1 + ), + q.question_text, + '' + ) + WHERE q.question_text IS NULL + $sql$; + ELSIF to_regclass('public.brand_question_versions') IS NOT NULL THEN + EXECUTE $sql$ + UPDATE brand_questions q + SET question_text = COALESCE( + ( + SELECT v.question_text + FROM brand_question_versions v + WHERE v.question_id = q.id + ORDER BY v.version_no DESC, v.id DESC + LIMIT 1 + ), + q.question_text, + '' + ) + WHERE q.question_text IS NULL + $sql$; + END IF; +END $$; + +UPDATE brand_questions +SET question_text = '' +WHERE question_text IS NULL; ALTER TABLE brand_questions ALTER COLUMN question_text SET NOT NULL;