feat(sources): admin page to add and remove git sources (TODO.md L4)

This commit is contained in:
2026-08-26 18:42:28 -04:00
parent b2d8696741
commit 1925bb66a8
30 changed files with 2673 additions and 110 deletions
+110
View File
@@ -0,0 +1,110 @@
"""Unit: the shared git-source resolver (phase 35, task 03).
``effective_git_sources`` is driven with a stubbed session (no Postgres)
and a fresh ``Settings(_env_file=None)`` env (monkeypatched into the
resolver's module — the dev ``.env`` never leaks in, same pattern as the
integration suites): DB rows win in ``(added_at, id)`` order (env
ignored), the ``BOR_GIT_SOURCES`` list is a fallback only while the
table is empty (phase-28 CSV parse reused), and both-empty yields
``([], "env")`` so the callers keep their fail-loud behavior.
"""
from __future__ import annotations
import re
from typing import Any
import pytest
from app.config import Settings
from app.models import GitSource
from app.rag import git_sources as resolver
class _FakeScalars:
"""The ``.scalars(stmt).all()`` tail of the resolver's query."""
def __init__(self, rows: list[GitSource]) -> None:
self._rows = rows
def all(self) -> list[GitSource]:
return self._rows
class _FakeSession:
"""Just enough of a SQLAlchemy session for the resolver (test_steering
pattern). Records the statement so the ordering can be asserted."""
def __init__(self, rows: list[GitSource]) -> None:
self._rows = rows
self.statements: list[Any] = []
def scalars(self, stmt: Any) -> _FakeScalars:
self.statements.append(stmt)
return _FakeScalars(self._rows)
def _stub_env(monkeypatch: pytest.MonkeyPatch, git_sources: str) -> None:
"""Point the resolver's env fallback at a fresh Settings (no .env)."""
monkeypatch.setattr(
resolver,
"get_settings",
lambda: Settings(_env_file=None, git_sources=git_sources), # pyright: ignore[reportCallIssue]
)
# --- the three branches ----------------------------------------------------
def test_db_rows_win_over_env(monkeypatch: pytest.MonkeyPatch) -> None:
"""Seeded table + env set → the DB list, origin ``db`` (env ignored)."""
_stub_env(monkeypatch, "https://env.example/ignored.git")
session = _FakeSession([GitSource(url="https://db.example/a.git"), GitSource(url="https://db.example/b.git")])
urls, origin = resolver.effective_git_sources(session) # pyright: ignore[reportArgumentType]
assert urls == ["https://db.example/a.git", "https://db.example/b.git"]
assert origin == "db"
def test_env_fallback_while_table_empty(monkeypatch: pytest.MonkeyPatch) -> None:
"""Empty table + env set → the env list, origin ``env``.
The CSV parse is ``Settings.git_source_list`` itself (phase 28):
whitespace-trimmed, empty entries dropped, order preserved.
"""
_stub_env(monkeypatch, " https://env.example/one.git , ,git@env.example:two.git ")
session = _FakeSession([])
urls, origin = resolver.effective_git_sources(session) # pyright: ignore[reportArgumentType]
assert urls == ["https://env.example/one.git", "git@env.example:two.git"]
assert origin == "env"
def test_both_empty_returns_empty_env(monkeypatch: pytest.MonkeyPatch) -> None:
"""Empty table + unset env → ``([], "env")`` — the callers fail loudly."""
_stub_env(monkeypatch, " , ") # whitespace-only is just as unconfigured as empty
session = _FakeSession([])
urls, origin = resolver.effective_git_sources(session) # pyright: ignore[reportArgumentType]
assert urls == []
assert origin == "env"
# --- the ordering ----------------------------------------------------------
def test_db_rows_ordered_by_added_at_then_id(monkeypatch: pytest.MonkeyPatch) -> None:
"""The statement orders by ``(added_at, id)`` — oldest first, the id
tie-break deciding same-timestamp inserts (matches the API's GET)."""
_stub_env(monkeypatch, "")
session = _FakeSession([GitSource(url="https://db.example/a.git")])
resolver.effective_git_sources(session) # pyright: ignore[reportArgumentType]
assert len(session.statements) == 1
compiled = str(session.statements[0].compile(compile_kwargs={"literal_binds": True}))
assert re.search(
r"ORDER BY\s+git_sources\.added_at ASC,\s+git_sources\.id ASC", compiled
), compiled