Files
TimeTrack/migrations/run_postgres_migrations.py

147 lines
4.5 KiB
Python
Executable File

#!/usr/bin/env python3
"""
PostgreSQL-only migration runner
Manages migration state and runs migrations in order
"""
import os
import sys
import json
import subprocess
from datetime import datetime
from pathlib import Path
# Migration state file
MIGRATION_STATE_FILE = '/data/postgres_migrations_state.json'
# List of PostgreSQL migrations in order
POSTGRES_MIGRATIONS = [
'postgres_only_migration.py', # Main migration from commit 4214e88 onward
'add_note_sharing.sql', # Add note sharing functionality
]
def load_migration_state():
"""Load the migration state from file"""
if os.path.exists(MIGRATION_STATE_FILE):
try:
with open(MIGRATION_STATE_FILE, 'r') as f:
return json.load(f)
except:
return {}
return {}
def save_migration_state(state):
"""Save the migration state to file"""
os.makedirs(os.path.dirname(MIGRATION_STATE_FILE), exist_ok=True)
with open(MIGRATION_STATE_FILE, 'w') as f:
json.dump(state, f, indent=2)
def run_migration(migration_file):
"""Run a single migration script"""
script_path = os.path.join(os.path.dirname(__file__), migration_file)
if not os.path.exists(script_path):
print(f"⚠️ Migration {migration_file} not found, skipping...")
return False
print(f"\n🔄 Running migration: {migration_file}")
try:
# Check if it's a SQL file
if migration_file.endswith('.sql'):
# Run SQL file using psql
import os
db_host = os.environ.get('POSTGRES_HOST', 'db')
db_name = os.environ.get('POSTGRES_DB', 'timetrack')
db_user = os.environ.get('POSTGRES_USER', 'timetrack')
result = subprocess.run(
['psql', '-h', db_host, '-U', db_user, '-d', db_name, '-f', script_path],
capture_output=True,
text=True,
env={**os.environ, 'PGPASSWORD': os.environ.get('POSTGRES_PASSWORD', 'timetrack')}
)
else:
# Run Python migration script
result = subprocess.run(
[sys.executable, script_path],
capture_output=True,
text=True
)
if result.returncode == 0:
print(f"{migration_file} completed successfully")
if result.stdout:
print(result.stdout)
return True
else:
print(f"{migration_file} failed with return code {result.returncode}")
if result.stderr:
print(f"Error output: {result.stderr}")
if result.stdout:
print(f"Standard output: {result.stdout}")
return False
except Exception as e:
print(f"❌ Error running {migration_file}: {e}")
return False
def main():
"""Run all PostgreSQL migrations"""
print("=== PostgreSQL Database Migrations ===")
print(f"Running {len(POSTGRES_MIGRATIONS)} migrations...")
# Load migration state
state = load_migration_state()
success_count = 0
failed_count = 0
skipped_count = 0
for migration in POSTGRES_MIGRATIONS:
# Check if migration has already been run successfully
if state.get(migration, {}).get('status') == 'success':
print(f"\n⏭️ Skipping {migration} (already completed)")
skipped_count += 1
continue
# Run the migration
success = run_migration(migration)
# Update state
state[migration] = {
'status': 'success' if success else 'failed',
'timestamp': datetime.now().isoformat(),
'attempts': state.get(migration, {}).get('attempts', 0) + 1
}
if success:
success_count += 1
else:
failed_count += 1
# Save state after each migration
save_migration_state(state)
# Summary
print("\n" + "="*50)
print("PostgreSQL Migration Summary:")
print(f"✅ Successful: {success_count}")
print(f"❌ Failed: {failed_count}")
print(f"⏭️ Skipped: {skipped_count}")
print(f"📊 Total: {len(POSTGRES_MIGRATIONS)}")
if failed_count > 0:
print("\n⚠️ Some migrations failed. Check the logs above for details.")
return 1
else:
print("\n✨ All PostgreSQL migrations completed successfully!")
return 0
if __name__ == "__main__":
sys.exit(main())