Release v4928.1.4.2 stable

This commit is contained in:
2026-06-09 22:55:58 +01:00
commit 6445044ac6
280 changed files with 41775 additions and 0 deletions

86
scripts/apply_migrations.py Executable file
View File

@@ -0,0 +1,86 @@
#!/usr/bin/env python3
"""Apply SQL migrations stored in ./migrations.
Usage:
python scripts/apply_migrations.py
python scripts/apply_migrations.py --dry-run
"""
from __future__ import annotations
import argparse
from pathlib import Path
import os
import sys
PROJECT_ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(PROJECT_ROOT))
os.chdir(PROJECT_ROOT)
from sqlalchemy import text
from app.db import engine
ROOT = Path(__file__).resolve().parents[1]
MIGRATIONS_DIR = ROOT / "migrations"
def ensure_ledger(conn) -> None:
conn.execute(text("""
CREATE TABLE IF NOT EXISTS schema_migrations (
version TEXT PRIMARY KEY,
name TEXT NOT NULL,
applied_at TIMESTAMPTZ NOT NULL DEFAULT now()
)
"""))
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--dry-run", action="store_true", help="List pending migrations without applying them.")
args = parser.parse_args()
files = sorted(MIGRATIONS_DIR.glob("*.sql"))
if not files:
print("No migrations found.")
return 0
with engine.begin() as conn:
ensure_ledger(conn)
applied = {
row[0]
for row in conn.execute(text("SELECT version FROM schema_migrations"))
}
pending = []
for path in files:
version = path.stem.split("_", 1)[0]
if version not in applied:
pending.append((version, path))
if not pending:
print("No pending migrations.")
return 0
print("Pending migrations:")
for version, path in pending:
print(f"- {version}: {path.name}")
if args.dry_run:
return 0
for version, path in pending:
sql = path.read_text()
print(f"Applying {path.name}...")
conn.execute(text(sql))
conn.execute(text("""
INSERT INTO schema_migrations(version, name)
VALUES (:version, :name)
ON CONFLICT (version) DO NOTHING
"""), {"version": version, "name": path.name})
print("Migrations applied.")
return 0
if __name__ == "__main__":
raise SystemExit(main())