9ca07a3f81
- collections.py resolution helpers (default_collection_id, type, initial_state) - registry mirror writes project grouping fields + default-collection corpus fields - auth.project_of_rfc joins collections; project_member_role reads memberships - cache/api_*/funder writers+readers re-keyed to collection_id (cached_prs + denormalised project_id tags unchanged); api_deployment reads type/initial_state from the default collection - projects.py restamp detects bootstrap via collections; initial_state via collection - tests updated to the three-tier schema; test_migration_028 retired (superseded by 029) - add @S1 acceptance test (collection grain + N=1 serving) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
60 lines
2.2 KiB
Python
60 lines
2.2 KiB
Python
"""Migration 027 — additive §22 M3 schema (projects.type/initial_state, the
|
|
deployment singleton, cached_rfcs review columns). No table rebuilds in Plan A."""
|
|
from __future__ import annotations
|
|
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
from app import db
|
|
from app.config import Config
|
|
|
|
|
|
def _fresh_config() -> Config:
|
|
tmp = Path(tempfile.mkdtemp(prefix="mig027-")) / "t.db"
|
|
return Config(
|
|
gitea_url="x", gitea_bot_user="x", gitea_bot_token="x", gitea_org="x",
|
|
registry_repo="registry",
|
|
oauth_client_id="x", oauth_client_secret="x", app_url="x",
|
|
secret_key="x", database_path=tmp, owner_gitea_login="x",
|
|
webhook_secret="x",
|
|
)
|
|
|
|
|
|
def test_027_adds_project_type_and_initial_state():
|
|
# 027 added type/initial_state to `projects`; migration 029 (three-tier)
|
|
# moved those per-corpus fields *down* onto `collections`. After the full
|
|
# migration chain they live on the collection, not the project.
|
|
cfg = _fresh_config()
|
|
db.run_migrations(cfg)
|
|
conn = db.connect(cfg.database_path)
|
|
proj_cols = {r["name"] for r in conn.execute("PRAGMA table_info(projects)")}
|
|
assert "type" not in proj_cols and "initial_state" not in proj_cols
|
|
coll_cols = {r["name"]: r for r in conn.execute("PRAGMA table_info(collections)")}
|
|
assert "type" in coll_cols and coll_cols["type"]["dflt_value"] == "'document'"
|
|
assert "initial_state" in coll_cols and coll_cols["initial_state"]["dflt_value"] == "'super-draft'"
|
|
conn.close()
|
|
|
|
|
|
def test_027_creates_deployment_singleton():
|
|
cfg = _fresh_config()
|
|
db.run_migrations(cfg)
|
|
conn = db.connect(cfg.database_path)
|
|
rows = list(conn.execute("SELECT id FROM deployment"))
|
|
assert [r["id"] for r in rows] == [1]
|
|
try:
|
|
conn.execute("INSERT INTO deployment (id) VALUES (2)")
|
|
raised = False
|
|
except Exception:
|
|
raised = True
|
|
assert raised
|
|
conn.close()
|
|
|
|
|
|
def test_027_adds_review_columns_to_cached_rfcs():
|
|
cfg = _fresh_config()
|
|
db.run_migrations(cfg)
|
|
conn = db.connect(cfg.database_path)
|
|
cols = {r["name"] for r in conn.execute("PRAGMA table_info(cached_rfcs)")}
|
|
assert {"unreviewed", "reviewed_at", "reviewed_by"} <= cols
|
|
conn.close()
|