Add /docs/ directory with user and technical documentation extracted from README, AGENTS.md, and source code. Add scripts/sync_wiki.py to sync docs to Gitea wiki via API. Add scripts/doc_coverage.py to check CLI commands, modules, and CI scripts are documented. Add sync-wiki.yml workflow for auto-sync on merge and release. Slim down README.md to lean entry point. 28 new unit tests, 100% coverage maintained. Closes GRM-36
4.3 KiB
4.3 KiB
Architecture
GRM consists of two layers:
- Python CLI (
src/gitea_runner_manager/) — built with Click, handles argument parsing, environment loading, i18n translations, and delegates to Ansible via theansible-playbooksubprocess. - Ansible Role (
ansible/roles/gitea-runner/) — idempotent role that creates a dedicated system user, sets up rootless Docker, installs the runner binary, creates a systemd user service, and registers the runner with Gitea.
Component Tree
grm install <host>
└── RunnerManager.install()
└── ansible-playbook ansible/install-runner.yml
└── role: gitea-runner
├── user_setup.yml (create per-runner system user + lingering)
├── rootless_docker.yml (rootless Docker setup under runner user)
├── install_runner.yml (download binary, config, register, service)
├── prune.yml (Docker prune timer)
└── integration_test.yml (validate service is active)
The Ansible role task execution order (from AGENTS.md):
main.yml → systemd_check → user_setup → rootless_docker → install_runner → prune → integration_test
install_runner.ymlhandles: download, config, validate, register, servicemain.ymlhandles: prune, integration_test (NOT install_runner — avoids duplicates)systemctl --usertasks must be guarded bydocker_rootless_setup- Template creation tasks are NOT guarded by
docker_rootless_setup(they just create files)
Per-Runner Isolation
Each runner runs as a systemd user service under a dedicated system user (grm-<name>). Each instance has fully isolated resources:
- User:
grm-<name>(dedicated system user with lingering enabled) - Home:
/home/grm-<name>/ - Data:
/var/lib/gitea-runner/<name>/ - Config:
/etc/gitea-runner/<name>/ - Service:
gitea-runner.service(systemd user service) - Docker socket:
/run/user/<UID>/docker.sock(rootless, per-runner)
Component Interactions
flowchart TD
CLI["Python CLI<br/>src/gitea_runner_manager/<br/>(Click)"]
RM["RunnerManager<br/>runner_manager.py"]
EXEC["Executor<br/>executor.py"]
REG["Registry<br/>registry.py<br/>~/.local/share/grm/runners.json"]
ANS["ansible-playbook subprocess"]
ROLE["Ansible Role<br/>ansible/roles/gitea-runner/"]
USER["user_setup.yml<br/>create system user + lingering"]
DOCKER["rootless_docker.yml<br/>rootless Docker setup"]
INSTALL["install_runner.yml<br/>download, config, register, service"]
PRUNE["prune.yml<br/>Docker prune timer"]
TEST["integration_test.yml<br/>validate service active"]
GITEA["Gitea instance<br/>registration + API"]
SYSTEMD["systemd user service<br/>gitea-runner.service"]
CLI --> RM
RM --> REG
RM --> EXEC
EXEC -->|subprocess| ANS
ANS --> ROLE
ROLE --> USER
ROLE --> DOCKER
ROLE --> INSTALL
ROLE --> PRUNE
ROLE --> TEST
INSTALL -->|register| GITEA
INSTALL --> SYSTEMD
DOCKER --> SYSTEMD
Additional Components
From AGENTS.md, the project also includes:
- CI Scripts (
scripts/) — Automation for auto-merge, post-merge, release, publishing, molecule distribution, PR reviews, failure notifications - Versioning (
cliff.toml) — git-cliff configuration for automated semver versioning from conventional commits
Python Modules
The Python CLI layer (src/gitea_runner_manager/) consists of the following modules:
| Module | Description |
|---|---|
cli.py |
Click-based CLI entry point — defines all commands (install, update, start, stop, enable, disable, status, remove, list) |
runner_manager.py |
Ansible orchestration + registry integration — delegates to executor and manages runner lifecycle |
executor.py |
Ansible subprocess execution — runs ansible-playbook with extra-vars via temp JSON files |
registry.py |
Local JSON runner registry at ~/.local/share/grm/runners.json — stores connection metadata |
i18n.py |
Internationalization translations (en, bg, de, ru, zh) |
exceptions.py |
Custom exceptions (GRMError, APIError) |
api_clients.py |
Gitea and Vikunja API client classes for CI automation scripts |
config.py |
Configuration constants (API URLs, repo owner/name, project IDs) — overridable via environment variables |