#!/usr/bin/env python3 """ Run SQL migrations using DATABASE_URL from .env Usage: python scripts/run_migration.py database/migrations/016_zopk_milestones.sql python scripts/run_migration.py database/migrations/*.sql # Run all """ import os import sys import glob from pathlib import Path # Add parent directory to path for imports sys.path.insert(0, str(Path(__file__).parent.parent)) def load_env(): """Load .env file from project root""" env_path = Path(__file__).parent.parent / '.env' if env_path.exists(): with open(env_path, 'r') as f: for line in f: line = line.strip() if line and not line.startswith('#') and '=' in line: key, value = line.split('=', 1) os.environ[key] = value.strip() if not os.environ.get('DATABASE_URL'): print("ERROR: DATABASE_URL not found in .env") sys.exit(1) def run_migration(sql_file: str) -> bool: """Run a single SQL migration file""" from sqlalchemy import create_engine, text if not os.path.exists(sql_file): print(f"ERROR: File not found: {sql_file}") return False print(f"Running migration: {sql_file}") try: engine = create_engine(os.environ['DATABASE_URL']) with engine.connect() as conn: with open(sql_file, 'r') as f: sql = f.read() conn.execute(text(sql)) conn.commit() print(f"✅ {sql_file} - SUCCESS") return True except Exception as e: print(f"❌ {sql_file} - FAILED: {e}") return False def main(): if len(sys.argv) < 2: print(__doc__) sys.exit(1) load_env() # Handle glob patterns sql_files = [] for arg in sys.argv[1:]: if '*' in arg: sql_files.extend(sorted(glob.glob(arg))) else: sql_files.append(arg) if not sql_files: print("No migration files found") sys.exit(1) print(f"Found {len(sql_files)} migration(s) to run\n") success = 0 failed = 0 for sql_file in sql_files: if run_migration(sql_file): success += 1 else: failed += 1 print(f"\n{'='*50}") print(f"Results: {success} success, {failed} failed") sys.exit(0 if failed == 0 else 1) if __name__ == '__main__': main()