Initial import with GitLab CI/CD and registry deploy flow
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
from sqlalchemy.exc import OperationalError, ProgrammingError
|
||||
from sqlalchemy import text
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
if str(ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(ROOT))
|
||||
|
||||
from services.shared.db import engine
|
||||
from services.shared.schema_migrations import (
|
||||
MIGRATIONS_DIR,
|
||||
applied_migration_versions,
|
||||
database_backend_name,
|
||||
ensure_schema_migrations_table,
|
||||
list_migration_files,
|
||||
)
|
||||
|
||||
|
||||
def _split_statements(sql: str) -> list[str]:
|
||||
chunks = []
|
||||
for part in sql.split(";"):
|
||||
stmt = part.strip()
|
||||
if stmt:
|
||||
chunks.append(stmt)
|
||||
return chunks
|
||||
|
||||
|
||||
def _apply_file(path: Path) -> None:
|
||||
# Some checked-in SQL files may contain a UTF-8 BOM; accept them for both
|
||||
# local SQLite runs and Postgres migration jobs.
|
||||
statements = _split_statements(path.read_text(encoding="utf-8-sig"))
|
||||
with engine.begin() as conn:
|
||||
for stmt in statements:
|
||||
try:
|
||||
conn.execute(text(stmt))
|
||||
except (OperationalError, ProgrammingError) as exc:
|
||||
message = str(exc).lower()
|
||||
duplicate_markers = [
|
||||
"duplicate column name",
|
||||
"already exists",
|
||||
"duplicate key value violates unique constraint",
|
||||
]
|
||||
if any(marker in message for marker in duplicate_markers):
|
||||
continue
|
||||
raise
|
||||
conn.execute(
|
||||
text("INSERT INTO schema_migrations(version, applied_at) VALUES (:v, CURRENT_TIMESTAMP)"),
|
||||
{"v": path.name},
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
files = list_migration_files()
|
||||
if not files:
|
||||
raise RuntimeError(f"No migration files found for dialect in {MIGRATIONS_DIR}")
|
||||
|
||||
ensure_schema_migrations_table()
|
||||
applied = applied_migration_versions()
|
||||
|
||||
applied_now = []
|
||||
for file_path in files:
|
||||
if file_path.name in applied:
|
||||
continue
|
||||
_apply_file(file_path)
|
||||
applied_now.append(file_path.name)
|
||||
|
||||
print(f"Dialect: {database_backend_name()}")
|
||||
if applied_now:
|
||||
print("Applied migrations:")
|
||||
for m in applied_now:
|
||||
print(f"- {m}")
|
||||
else:
|
||||
print("No new migrations to apply")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user