wrolpi/modules/repos/schema.py
lrnselfreliance 93d878952c
Add a Repos module that mirrors git repositories (#783)
Repos keeps local mirrors of git repositories, cloned over https and kept up to date on a schedule.

- A Repo is a Collection (kind='repo') plus a `repository` row.  The new `git` downloader clones it, then updates it
  (weekly by default, or Never: the clone is kept as it is and only updated on request).
- Repos are saved in `repos/<tag>/<name>` (the Repos Directory, ignored by default) or a directory the user chooses.
  An existing clone can be imported where it is.  repos.yaml is the source of truth.
- A GitHub-like page shows each repo's README, files, and history, with a ZIP download.  READMEs are searchable
  under the global search's Other tab.
- git is hardened against hostile repos and configs: https only, pinned addresses with no private addresses (for the
  repo and its submodules), sanitized configs, no hooks or links, and only clones WROLPi made or imported are
  updated.
- Tagging a Repo moves its clone as one directory.  Repo changes wait for repos.yaml to be imported at startup.
- The file mover groups unindexed files with no primary file as one FileGroup, and never replaces a file at the
  destination.  A failed tag move restores the Collection's tag.  A Collection's directory cannot leave the media
  directory.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 15:16:58 -06:00

55 lines
1.3 KiB
Python

from dataclasses import dataclass, field
from typing import Optional, List
@dataclass
class RepoCreateRequest:
url: str
# Relative to the media directory; empty clones it into the Repos directory.
directory: Optional[str] = None
tag_name: Optional[str] = None
frequency: Optional[int] = None
mode: Optional[str] = None
branch: Optional[str] = None
name: Optional[str] = None
description: Optional[str] = None
submodules: bool = False
@dataclass
class RepoSearchRequest:
search_str: Optional[str] = None
tag_names: List[str] = field(default_factory=list)
limit: int = 20
offset: int = 0
@dataclass
class RepoUpdateRequest:
description: Optional[str] = None
frequency: Optional[int] = None
mode: Optional[str] = None
branch: Optional[str] = None
submodules: Optional[bool] = None
@dataclass
class RepoImportInspectRequest:
directory: str
name: Optional[str] = None
tag_name: Optional[str] = None
url: Optional[str] = None
@dataclass
class RepoImportRequest:
directory: str
confirm: bool = False
url: Optional[str] = None
tag_name: Optional[str] = None
frequency: Optional[int] = None
mode: Optional[str] = None
branch: Optional[str] = None
submodules: bool = False
name: Optional[str] = None
description: Optional[str] = None