feat: two-phase migrations, DB settings loading in create_app

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-18 20:33:36 -04:00
parent 03bbd8d0fa
commit c5dff7ec8c
2 changed files with 86 additions and 43 deletions
+21 -13
View File
@@ -1,3 +1,4 @@
# fablednetmon/core/migration_runner.py
from __future__ import annotations
import logging
from pathlib import Path
@@ -5,13 +6,26 @@ from pathlib import Path
logger = logging.getLogger(__name__)
def run_migrations(db_url: str, plugin_migration_dirs: list[Path] | None = None) -> None:
"""Run core + plugin Alembic migrations synchronously.
def run_core_migrations(db_url: str) -> None:
"""Run only core Alembic migrations (no plugin dirs).
Called during create_app() before the event loop starts.
Applies all pending migrations in dependency order.
Plugin migration dirs are included via Alembic's version_locations.
Called first so the app_settings table exists before loading settings.
"""
_run(db_url, plugin_migration_dirs=[])
def run_plugin_migrations(db_url: str, plugin_migration_dirs: list[Path]) -> None:
"""Run plugin Alembic migrations after settings are loaded."""
if plugin_migration_dirs:
_run(db_url, plugin_migration_dirs=plugin_migration_dirs)
def run_migrations(db_url: str, plugin_migration_dirs: list[Path] | None = None) -> None:
"""Run core + plugin Alembic migrations (single-phase convenience wrapper)."""
_run(db_url, plugin_migration_dirs=plugin_migration_dirs or [])
def _run(db_url: str, plugin_migration_dirs: list[Path]) -> None:
from alembic import command
from alembic.config import Config
@@ -22,9 +36,8 @@ def run_migrations(db_url: str, plugin_migration_dirs: list[Path] | None = None)
cfg.set_main_option("script_location", str(core_migrations))
cfg.set_main_option("sqlalchemy.url", db_url)
# Build version_locations: core + any plugin version directories
version_locs = [str(core_versions)]
for plugin_dir in (plugin_migration_dirs or []):
for plugin_dir in plugin_migration_dirs:
pv = plugin_dir / "versions"
if pv.exists():
version_locs.append(str(pv))
@@ -37,12 +50,7 @@ def run_migrations(db_url: str, plugin_migration_dirs: list[Path] | None = None)
def get_plugin_migration_dirs(plugin_dir: Path, plugins_cfg: dict) -> list[Path]:
"""Return migration directories for all enabled plugins that have one.
Does not import any Python code — filesystem scan only.
Used to collect migration dirs before importing plugins, so migrations
can run before plugin Python code is loaded.
"""
"""Return migration directories for enabled plugins (filesystem scan only)."""
dirs = []
for name, cfg in plugins_cfg.items():
if not cfg.get("enabled", False):