T11: tags plugin + permissions plugin + entity links backend — 68 tests, 66.61% coverage

This commit is contained in:
leocrm-bot
2026-06-29 14:01:24 +02:00
parent 700b7a71ad
commit 5d1850768a
26 changed files with 2863 additions and 7 deletions
+18 -6
View File
@@ -23,13 +23,25 @@ class MigrationRunner:
self._engine = engine
self._migrations_dir = Path(migrations_dir or os.path.join(os.path.dirname(__file__), "migrations"))
def _resolve_migration_path(self, filename: str) -> Path:
"""Resolve a migration filename to an absolute path."""
# Try migrations_dir first, then app/plugins/migrations/
def _resolve_migration_path(self, filename: str, plugin_name: str | None = None) -> Path:
"""Resolve a migration filename to an absolute path.
Search order:
1. Plugin-specific migrations dir: app/plugins/builtins/<plugin_name>/migrations/
2. Global migrations_dir (default: app/plugins/migrations/)
3. Shared builtins migrations dir: app/plugins/builtins/migrations/
"""
# 1. Plugin-specific migrations directory
if plugin_name:
plugin_migrations_dir = Path(__file__).parent / "builtins" / plugin_name / "migrations"
candidate = plugin_migrations_dir / filename
if candidate.exists():
return candidate
# 2. Global migrations_dir
candidate = self._migrations_dir / filename
if candidate.exists():
return candidate
# Fallback: builtins directory
# 3. Shared builtins migrations directory
builtins_dir = Path(__file__).parent / "builtins" / "migrations"
candidate2 = builtins_dir / filename
if candidate2.exists():
@@ -61,7 +73,7 @@ class MigrationRunner:
FileNotFoundError: If migration file doesn't exist.
MigrationValidationError: If a created table lacks tenant_id column.
"""
migration_path = self._resolve_migration_path(migration_filename)
migration_path = self._resolve_migration_path(migration_filename, plugin_name)
sql_content = migration_path.read_text(encoding="utf-8")
# Capture existing table names before migration (static analysis of SQL)
@@ -156,7 +168,7 @@ class MigrationRunner:
dropped_tables: list[str] = []
for record in migration_records:
migration_path = self._resolve_migration_path(record.migration_file)
migration_path = self._resolve_migration_path(record.migration_file, plugin_name)
sql_content = migration_path.read_text(encoding="utf-8")
# Parse table names from CREATE TABLE statements