refactor(migrations): squash 75 migrations into 12 per-module initial migrations
The old migration chain was broken (downgrade path through vendor->merchant rename made rollbacks impossible). This squashes everything into fresh per-module migrations with zero schema drift, verified by autogenerate. Changes: - Replace 75 accumulated migrations with 12 per-module initial migrations (core, billing, catalog, marketplace, cms, customers, orders, inventory, cart, messaging, loyalty, dev_tools) in a linear chain - Fix make db-reset to use SQL DROP SCHEMA instead of alembic downgrade base - Enable migration autodiscovery for all modules (migrations_path in definitions) - Rewrite alembic/env.py to import all 75 model tables across 13 modules - Fix AdminNotification import (was incorrectly from tenancy, now from messaging) - Update squash_migrations.py to handle all module migration directories Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
"""
|
||||
Migration Squash Script
|
||||
|
||||
This script squashes all existing migrations into a single initial migration.
|
||||
This script squashes all existing migrations into fresh per-module initial migrations.
|
||||
Run this after setting up PostgreSQL to simplify the migration history.
|
||||
|
||||
Prerequisites:
|
||||
@@ -13,13 +13,13 @@ Usage:
|
||||
python scripts/squash_migrations.py
|
||||
|
||||
What this script does:
|
||||
1. Backs up existing migrations to alembic/versions_backup_YYYYMMDD/
|
||||
1. Backs up existing migrations from all version_locations to a timestamped backup
|
||||
2. Creates a fresh initial migration from current models
|
||||
3. Stamps the database as being at the new migration
|
||||
|
||||
After running:
|
||||
1. Review the new migration in alembic/versions/
|
||||
2. Test with: make migrate-up (on a fresh database)
|
||||
1. Review the new migration files
|
||||
2. Test with: make db-reset (drops schema, runs all migrations, seeds data)
|
||||
3. If satisfied, delete the backup directory
|
||||
"""
|
||||
|
||||
@@ -36,6 +36,22 @@ sys.path.insert(0, str(project_root))
|
||||
|
||||
VERSIONS_DIR = project_root / "alembic" / "versions"
|
||||
|
||||
# All migration version directories (core + modules)
|
||||
MODULE_MIGRATION_DIRS = [
|
||||
project_root / "alembic" / "versions",
|
||||
project_root / "app" / "modules" / "billing" / "migrations" / "versions",
|
||||
project_root / "app" / "modules" / "cart" / "migrations" / "versions",
|
||||
project_root / "app" / "modules" / "catalog" / "migrations" / "versions",
|
||||
project_root / "app" / "modules" / "cms" / "migrations" / "versions",
|
||||
project_root / "app" / "modules" / "customers" / "migrations" / "versions",
|
||||
project_root / "app" / "modules" / "dev_tools" / "migrations" / "versions",
|
||||
project_root / "app" / "modules" / "inventory" / "migrations" / "versions",
|
||||
project_root / "app" / "modules" / "loyalty" / "migrations" / "versions",
|
||||
project_root / "app" / "modules" / "marketplace" / "migrations" / "versions",
|
||||
project_root / "app" / "modules" / "messaging" / "migrations" / "versions",
|
||||
project_root / "app" / "modules" / "orders" / "migrations" / "versions",
|
||||
]
|
||||
|
||||
|
||||
def check_prerequisites():
|
||||
"""Verify PostgreSQL is configured."""
|
||||
@@ -53,28 +69,42 @@ def check_prerequisites():
|
||||
|
||||
|
||||
def backup_migrations():
|
||||
"""Backup existing migrations."""
|
||||
"""Backup existing migrations from all version locations."""
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
backup_dir = project_root / "alembic" / f"versions_backup_{timestamp}"
|
||||
backup_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
if not VERSIONS_DIR.exists():
|
||||
print("No existing migrations to backup")
|
||||
total_backed_up = 0
|
||||
|
||||
for versions_dir in MODULE_MIGRATION_DIRS:
|
||||
if not versions_dir.exists():
|
||||
continue
|
||||
|
||||
migration_files = [f for f in versions_dir.glob("*.py") if f.name != "__init__.py"]
|
||||
if not migration_files:
|
||||
continue
|
||||
|
||||
# Create a subdirectory in backup matching the source path
|
||||
rel_path = versions_dir.relative_to(project_root)
|
||||
target_dir = backup_dir / str(rel_path).replace("/", "_")
|
||||
target_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
for f in migration_files:
|
||||
shutil.copy2(f, target_dir / f.name)
|
||||
total_backed_up += 1
|
||||
|
||||
# Remove migration files from source (keep __init__.py)
|
||||
for f in migration_files:
|
||||
f.unlink()
|
||||
|
||||
if total_backed_up > 0:
|
||||
print(f"Backed up {total_backed_up} migrations to {backup_dir.name}/")
|
||||
return backup_dir
|
||||
else:
|
||||
print("No migration files found to backup")
|
||||
backup_dir.rmdir()
|
||||
return None
|
||||
|
||||
migration_files = list(VERSIONS_DIR.glob("*.py"))
|
||||
if not migration_files:
|
||||
print("No migration files found")
|
||||
return None
|
||||
|
||||
print(f"Backing up {len(migration_files)} migrations to {backup_dir.name}/")
|
||||
shutil.copytree(VERSIONS_DIR, backup_dir)
|
||||
|
||||
# Clear versions directory (keep __pycache__ if exists)
|
||||
for f in VERSIONS_DIR.glob("*.py"):
|
||||
f.unlink()
|
||||
|
||||
return backup_dir
|
||||
|
||||
|
||||
def create_fresh_migration():
|
||||
"""Generate fresh initial migration from models."""
|
||||
@@ -116,7 +146,6 @@ def clean_migration_file(migration_path: Path):
|
||||
# Remove batch_alter_table references (not needed for PostgreSQL)
|
||||
if "batch_alter_table" in content:
|
||||
print("Note: Migration contains batch_alter_table - this is not needed for PostgreSQL")
|
||||
# We don't auto-remove as it might be intentional
|
||||
|
||||
print(f"Review migration at: {migration_path}")
|
||||
|
||||
@@ -178,14 +207,14 @@ def main():
|
||||
print(f"Backup location: {backup_dir}")
|
||||
print("")
|
||||
print("Next steps:")
|
||||
print("1. Review the new migration file")
|
||||
print("2. On a fresh database, run: make migrate-up")
|
||||
print("1. Review the new migration files")
|
||||
print("2. On a fresh database, run: make db-reset")
|
||||
print("3. Verify all tables are created correctly")
|
||||
print("4. If satisfied, delete the backup directory")
|
||||
print("")
|
||||
print("To restore from backup:")
|
||||
print(f" rm -rf alembic/versions/*.py")
|
||||
print(f" cp -r {backup_dir}/* alembic/versions/")
|
||||
if backup_dir:
|
||||
print("To restore from backup:")
|
||||
print(f" Check {backup_dir}/ for backed up migration files")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user