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
+44
View File
@@ -0,0 +1,44 @@
"""The shared git-source resolver (phase 35, task 03).
One function, two callers: the in-app Sync pipeline
(``app/api/sync.py::_run_sync``) and the CLI
(``scripts/import_docs.py::_resolve_sources``) — both resolve the repo
URLs to clone/pull through :func:`effective_git_sources`, so the
admin-managed ``git_sources`` table is what actually gets cloned and
indexed from either entry point (the API's ``GET /api/git-sources``
fallback list is the only other place that reads the env list — task 02).
Precedence (the phase's locked decision — the env var is demoted, not
removed): ``git_sources`` DB rows win, in ``(added_at, id)`` order;
``BOR_GIT_SOURCES`` is a fallback only while the table is empty; both
empty → ``([], "env")`` and each caller keeps its existing fail-loud
behavior (sync: ``GitSyncError``; CLI: the legacy ``DEFAULT_SOURCES``
fallback).
"""
from __future__ import annotations
from typing import Literal
from sqlalchemy import select
from sqlalchemy.orm import Session
from app.config import get_settings
from app.models import GitSource
def effective_git_sources(db: Session) -> tuple[list[str], Literal["db", "env"]]:
"""``(urls, origin)`` — the repo URLs to clone, and where they came from.
``"db"``: the ``git_sources`` rows in ``(added_at, id)`` order (oldest
first, id tie-break for same-timestamp inserts) — once the table has
any row, ``BOR_GIT_SOURCES`` is ignored entirely.
``"env"``: the ``BOR_GIT_SOURCES`` list — ``Settings.git_source_list``,
the phase-28 CSV parse, reused not re-implemented — used only while
the table is empty; both empty → ``([], "env")``.
"""
rows = db.scalars(
select(GitSource).order_by(GitSource.added_at.asc(), GitSource.id.asc())
).all()
if rows:
return [row.url for row in rows], "db"
return list(get_settings().git_source_list), "env"