From 6cd6ce01eb2669f525f01b078e945d7b59ef630a Mon Sep 17 00:00:00 2001 From: Ami Date: Tue, 21 Apr 2026 17:50:17 +0700 Subject: [PATCH] fix(alembic): always read DATABASE_URL env directly to avoid ini override issues --- apps/api/alembic/env.py | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/apps/api/alembic/env.py b/apps/api/alembic/env.py index 6b3be69..3b4d1c2 100644 --- a/apps/api/alembic/env.py +++ b/apps/api/alembic/env.py @@ -3,7 +3,6 @@ from logging.config import fileConfig from urllib.parse import unquote from sqlalchemy import create_engine, pool -from sqlalchemy.engine.url import make_url from alembic import context from src.models import Base @@ -14,9 +13,9 @@ config = context.config # Override sqlalchemy.url from environment if set database_url = os.environ.get("DATABASE_URL") if database_url: - # Alembic needs the synchronous driver; asyncpg -> psycopg2 + # Alembic/sync driver needs postgresql:// (not postgresql+asyncpg://) database_url = database_url.replace("postgresql+asyncpg://", "postgresql://") - # Decode URL-encoded characters (e.g. %40 -> @) + # Decode URL-encoded characters database_url = unquote(database_url) config.set_main_option("sqlalchemy.url", database_url) @@ -42,15 +41,13 @@ def run_migrations_offline() -> None: def run_migrations_online() -> None: - """Run migrations in 'online' mode. - - Use create_engine directly to bypass ConfigParser URL parsing - which mishandles special characters in passwords. - """ - url = config.get_main_option("sqlalchemy.url") - # Ensure dialect is postgresql (not postgres) - if url.startswith("postgres://"): - url = "postgresql://" + url[len("postgres://"):] + """Run migrations in 'online' mode.""" + # Always use DATABASE_URL env var directly, bypassing alembic.ini + # This avoids ConfigParser mangling special chars in URLs + raw_url = os.environ.get("DATABASE_URL", "") + url = raw_url.replace("postgresql+asyncpg://", "postgresql://") + url = unquote(url) + connectable = create_engine(url, poolclass=pool.NullPool) with connectable.connect() as connection: