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
+24 -11
View File
@@ -7,15 +7,18 @@ Examples::
uv run python -m scripts.import_docs --prune # also drop deleted/out-of-scope files
uv run python -m scripts.import_docs --limit 5 # debug: first 5 files only
Source resolution (phase 28), in precedence order:
Source resolution (phase 28, extended in phase 35), in precedence order:
1. ``--source PATH`` — explicit manual directories (repeatable) always win;
``BOR_GIT_SOURCES`` is ignored when this flag is used.
2. ``BOR_GIT_SOURCES`` (comma-separated git URLs) — each repo is cloned
(first run, shallow ``--depth 1``) or fast-forwarded (``git pull
--ff-only``) into ``BOR_SOURCES_DIR/<repo-name>/`` (default
``~/bor-sources``) and the resulting checkouts are imported. A failing
clone/pull aborts the whole run *before* anything is imported.
git sources are ignored when this flag is used.
2. The effective git sources — the admin-managed ``git_sources`` table
rows, else the ``BOR_GIT_SOURCES`` (comma-separated) fallback
(:func:`app.rag.git_sources.effective_git_sources`, the same shared
resolver the in-app Sync button uses) — each repo is cloned (first
run, shallow ``--depth 1``) or fast-forwarded (``git pull --ff-only``)
into ``BOR_SOURCES_DIR/<repo-name>/`` (default ``~/bor-sources``) and
the resulting checkouts are imported. A failing clone/pull aborts the
whole run *before* anything is imported.
3. Fallback — the legacy ``DEFAULT_SOURCES`` (``~/Homelab`` +
``~/Deployments``), kept for backwards compatibility.
@@ -53,6 +56,7 @@ from app.core.debugging import configure_debugging
from app.core.logging import configure_logging
from app.db import SessionLocal
from app.models import KbOverview
from app.rag.git_sources import effective_git_sources
from app.rag.importer import ImportSummary, import_sources
from app.rag.llm import LLMClient
from app.rag.overview import regenerate_overview
@@ -111,20 +115,29 @@ def repo_name(url: str) -> str:
def _resolve_sources(cli_sources: list[Path] | None, settings: Settings) -> list[Path]:
"""Resolve the directories to import (phase 28).
"""Resolve the directories to import (phase 28, extended in phase 35).
Precedence: ``--source`` (explicit manual paths — always wins) >
``BOR_GIT_SOURCES`` (each URL cloned/pulled via
the effective git sources — the ``git_sources`` DB rows, else the
``BOR_GIT_SOURCES`` fallback
(:func:`app.rag.git_sources.effective_git_sources`; the import needs
the database anyway, so resolution opens a short session and there
is no DB-down branch) — each URL cloned/pulled via
:func:`scripts.git_sync.clone_or_pull` into
``BOR_SOURCES_DIR/<repo-name>/``) > the legacy ``DEFAULT_SOURCES``.
``BOR_SOURCES_DIR/<repo-name>/`` > the legacy ``DEFAULT_SOURCES``.
A :class:`GitSyncError` from a failing clone/pull propagates to
:func:`main`, which aborts the run before importing anything.
"""
if cli_sources:
return [path.expanduser() for path in cli_sources]
git_urls = settings.git_source_list
db = SessionLocal()
try:
git_urls, origin = effective_git_sources(db)
finally:
db.close()
if git_urls:
logger.info("git sources: %d repo(s) origin=%s", len(git_urls), origin)
sources_root = Path(settings.sources_dir).expanduser()
return [clone_or_pull(url, sources_root / repo_name(url)) for url in git_urls]
return [path.expanduser() for path in DEFAULT_SOURCES]