test(test_db_schema_migration.py): ci/cd test to enforce schema migrations are documented in .sql files

This commit is contained in:
Krrish Dholakia 2025-03-26 16:59:50 -07:00
parent 37265c8b1c
commit d4adc9764b

View file

@ -3,6 +3,8 @@ import os
import subprocess import subprocess
from pathlib import Path from pathlib import Path
from pytest_postgresql import factories from pytest_postgresql import factories
import shutil
import tempfile
# Create postgresql fixture # Create postgresql fixture
postgresql_my_proc = factories.postgresql_proc(port=None) postgresql_my_proc = factories.postgresql_proc(port=None)
@ -19,44 +21,63 @@ def test_schema_migration_check(schema_setup):
"""Test to check if schema requires migration""" """Test to check if schema requires migration"""
# Set test database URL # Set test database URL
test_db_url = f"postgresql://{schema_setup.info.user}:@{schema_setup.info.host}:{schema_setup.info.port}/{schema_setup.info.dbname}" test_db_url = f"postgresql://{schema_setup.info.user}:@{schema_setup.info.host}:{schema_setup.info.port}/{schema_setup.info.dbname}"
# test_db_url = "postgresql://neondb_owner:npg_JiZPS0DAhRn4@ep-delicate-wave-a55cvbuc.us-east-2.aws.neon.tech/neondb?sslmode=require"
os.environ["DATABASE_URL"] = test_db_url os.environ["DATABASE_URL"] = test_db_url
deploy_dir = Path("./deploy") deploy_dir = Path("../../deploy")
migrations_dir = deploy_dir / "migrations" source_migrations_dir = deploy_dir / "migrations"
schema_path = Path("../../schema.prisma")
print(migrations_dir) # Create temporary migrations directory next to schema.prisma
if not migrations_dir.exists() or not any(migrations_dir.iterdir()): temp_migrations_dir = schema_path.parent / "migrations"
try:
# Copy migrations to correct location
if temp_migrations_dir.exists():
shutil.rmtree(temp_migrations_dir)
shutil.copytree(source_migrations_dir, temp_migrations_dir)
if not temp_migrations_dir.exists() or not any(temp_migrations_dir.iterdir()):
print("No existing migrations found - first migration needed") print("No existing migrations found - first migration needed")
pytest.fail("No existing migrations found - first migration needed") pytest.fail("No existing migrations found - first migration needed")
# If migrations exist, check for changes # Apply all existing migrations
result = subprocess.run( subprocess.run(
["prisma", "migrate", "status"], capture_output=True, text=True ["prisma", "migrate", "deploy", "--schema", str(schema_path)], check=True
) )
status_output = result.stdout.lower() # Compare current database state against schema
needs_migration = any(
state in status_output for state in ["drift detected", "pending"]
)
if needs_migration:
print("Schema changes detected. New migration needed.")
# Show the differences
diff_result = subprocess.run( diff_result = subprocess.run(
[ [
"prisma", "prisma",
"migrate", "migrate",
"diff", "diff",
"--from-migrations", "--from-url",
test_db_url,
"--to-schema-datamodel", "--to-schema-datamodel",
"schema.prisma", str(schema_path),
"--script", # Show the SQL diff
"--exit-code", # Return exit code 2 if there are differences
], ],
capture_output=True, capture_output=True,
text=True, text=True,
) )
print("Exit code:", diff_result.returncode)
print("Stdout:", diff_result.stdout)
print("Stderr:", diff_result.stderr)
if diff_result.returncode == 2:
print("Schema changes detected. New migration needed.")
print("Schema differences:") print("Schema differences:")
print(diff_result.stdout) print(diff_result.stdout)
pytest.fail(
"Schema changes detected - new migration required. Run 'prisma migrate dev' to create new migration."
)
else: else:
print("No schema changes detected. Migration not needed.") print("No schema changes detected. Migration not needed.")
assert not needs_migration, "Schema changes detected - new migration required" finally:
# Clean up: remove temporary migrations directory
if temp_migrations_dir.exists():
shutil.rmtree(temp_migrations_dir)