112 lines
3.0 KiB
Python
112 lines
3.0 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
run_production_migration.py
|
|
─────────────────────────────────────────────────────────────────────────────
|
|
Execute migrate_production.sql against the configured DATABASE_URL.
|
|
|
|
Usage
|
|
─────
|
|
python run_production_migration.py # normal run
|
|
python run_production_migration.py --dry-run # parse SQL but do NOT commit
|
|
|
|
Environment variables read from .env (or already in shell):
|
|
DATABASE_URL postgresql://user:pass@host:port/dbname
|
|
|
|
Exit codes:
|
|
0 success
|
|
1 error
|
|
"""
|
|
|
|
import argparse
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import psycopg2
|
|
from dotenv import load_dotenv
|
|
|
|
MIGRATION_FILE = Path(__file__).parent / "migrate_production.sql"
|
|
|
|
|
|
def parse_args():
|
|
p = argparse.ArgumentParser(description="Run Invy production migration")
|
|
p.add_argument(
|
|
"--dry-run",
|
|
action="store_true",
|
|
help="Parse and validate the SQL but roll back instead of committing.",
|
|
)
|
|
return p.parse_args()
|
|
|
|
|
|
def main():
|
|
args = parse_args()
|
|
load_dotenv()
|
|
|
|
db_url = os.getenv(
|
|
"DATABASE_URL",
|
|
"postgresql://wedding_admin:Aa123456@localhost:5432/wedding_guests",
|
|
)
|
|
|
|
if not MIGRATION_FILE.exists():
|
|
print(f"❌ Migration file not found: {MIGRATION_FILE}")
|
|
sys.exit(1)
|
|
|
|
sql = MIGRATION_FILE.read_text(encoding="utf-8")
|
|
|
|
print(f"{'[DRY-RUN] ' if args.dry_run else ''}Connecting to database …")
|
|
try:
|
|
conn = psycopg2.connect(db_url)
|
|
except Exception as exc:
|
|
print(f"❌ Cannot connect: {exc}")
|
|
sys.exit(1)
|
|
|
|
conn.autocommit = False
|
|
cursor = conn.cursor()
|
|
|
|
# Capture NOTICE messages from PL/pgSQL RAISE NOTICE
|
|
import warnings
|
|
conn.notices = []
|
|
|
|
def _notice_handler(diag):
|
|
msg = diag.message_primary or str(diag)
|
|
conn.notices.append(msg)
|
|
print(f" [DB] {msg}")
|
|
|
|
conn.add_notice_handler(_notice_handler)
|
|
|
|
try:
|
|
print("Running migration …")
|
|
cursor.execute(sql)
|
|
|
|
# Print the summary SELECT result
|
|
try:
|
|
row = cursor.fetchone()
|
|
if row:
|
|
print(
|
|
f"\n📊 Summary after migration:\n"
|
|
f" users : {row[0]}\n"
|
|
f" events : {row[1]}\n"
|
|
f" guests_v2 : {row[2]}\n"
|
|
)
|
|
except Exception:
|
|
pass
|
|
|
|
if args.dry_run:
|
|
conn.rollback()
|
|
print("✅ Dry-run complete — rolled back (no changes written).")
|
|
else:
|
|
conn.commit()
|
|
print("✅ Migration committed successfully.")
|
|
|
|
except Exception as exc:
|
|
conn.rollback()
|
|
print(f"\n❌ Migration failed — rolled back.\n Error: {exc}")
|
|
sys.exit(1)
|
|
finally:
|
|
cursor.close()
|
|
conn.close()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|