Compare commits

...
10 Commits
Author SHA1 Message Date
grm-ci-bot e5b0e17ec3 release: v0.12.4 [skip ci] 2026-06-29 11:55:20 +00:00
emil dc5e1431b5 GRM-121: fix: use hardcoded matrix array for Gitea 1.26 compatibility
Post-merge / detect-type (push) Successful in 1m12s
Post-merge / release (push) Successful in 48s
Post-merge / validate-commit-msg (push) Successful in 1m41s
Post-merge / vikunja (push) Successful in 1m38s
Post-merge / configure-repo (push) Successful in 1m37s
Post-merge / badges (push) Successful in 1m48s
Post-merge / publish (push) Successful in 1m11s
Post-merge / sync-wiki (push) Successful in 2m10s
2026-06-29 11:53:22 +00:00
gitea-actions-bot dfa8d77bfa chore: update badge URLs to commit 26565ddc [skip ci] 2026-06-29 11:39:57 +00:00
emil a178b1b5d2 GRM-120: chore: pin devx to 0.27.2 for dynamic runner matrix support
Post-merge / detect-type (push) Successful in 53s
Post-merge / release (push) Successful in 1m13s
Post-merge / validate-commit-msg (push) Successful in 1m44s
Post-merge / publish (push) Has been skipped
Post-merge / badges (push) Successful in 1m53s
Post-merge / vikunja (push) Successful in 1m52s
Post-merge / sync-wiki (push) Successful in 2m10s
Post-merge / configure-repo (push) Successful in 1m34s
2026-06-29 11:37:03 +00:00
gitea-actions-bot 99529a57af chore: update badge URLs to commit f731a4a7 [skip ci] 2026-06-29 10:41:23 +00:00
grm-ci-bot 0eb033419f release: v0.12.3 [skip ci] 2026-06-29 10:40:45 +00:00
emil df4b7f2a19 GRM-118: fix: improve runner service stability and deregistration
Post-merge / detect-type (push) Successful in 1m16s
Post-merge / release (push) Successful in 1m12s
Post-merge / validate-commit-msg (push) Successful in 1m27s
Post-merge / configure-repo (push) Successful in 1m27s
Post-merge / vikunja (push) Successful in 1m31s
Post-merge / badges (push) Successful in 1m33s
Post-merge / sync-wiki (push) Successful in 1m43s
Post-merge / publish (push) Successful in 46s
2026-06-29 10:38:32 +00:00
gitea-actions-bot 312a706d39 chore: update badge URLs to commit 695921d6 [skip ci] 2026-06-28 17:09:22 +00:00
emil ea2f0cc600 GRM-117: fix: fix wiki link URLs, heading hierarchy, quote pip install vars
Post-merge / detect-type (push) Successful in 51s
Post-merge / release (push) Successful in 54s
Post-merge / validate-commit-msg (push) Successful in 1m5s
Post-merge / publish (push) Has been skipped
Post-merge / badges (push) Successful in 1m17s
Post-merge / vikunja (push) Successful in 1m26s
Post-merge / configure-repo (push) Successful in 1m12s
Post-merge / sync-wiki (push) Successful in 1m34s
2026-06-28 17:07:11 +00:00
gitea-actions-bot bd8e13ee66 chore: update badge URLs to commit 622165d8 [skip ci] 2026-06-28 15:06:01 +00:00
17 changed files with 110 additions and 72 deletions
+14 -1
View File
@@ -30,6 +30,17 @@ jobs:
run: |
. .venv/bin/activate
make pytest-cov
- name: Documentation lint check
env:
PYTHONPATH: src
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
CI_GITEA_USERNAME: ${{ vars.CI_GITEA_USERNAME }}
run: |
. .venv/bin/activate
pip install --upgrade devx \
--index-url "https://${CI_GITEA_USERNAME}:${CI_GITEA_TOKEN}@git.oblachno.oblachno.fyi/api/packages/oblachno-oss/pypi/simple/" \
--no-deps
python3 -m devx.ci.lint_docs --root .
- name: Translation completeness check
run: |
. .venv/bin/activate
@@ -147,8 +158,10 @@ jobs:
container: git.oblachno.oblachno.fyi/oblachno-oss/runner-images/ci-full:latest
timeout-minutes: 10
strategy:
fail-fast: true
max-parallel: 3
matrix:
runner-index: [1, 2, 3]
runner-index: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
steps:
- uses: actions/checkout@v4
- name: Set up environment
+13
View File
@@ -2,6 +2,19 @@
All notable changes to this project will be documented in this file.
## [0.12.4] - 2026-06-29
### Bug Fixes
- Use hardcoded matrix array for Gitea 1.26 compatibility
## [0.12.3] - 2026-06-29
### Bug Fixes
- Fix wiki link URLs, heading hierarchy, quote pip install vars
- Improve runner service stability and deregistration
## [0.12.2] - 2026-06-28
### Bug Fixes
+2
View File
@@ -1,5 +1,7 @@
# Contributing to GRM
For the full contributing guide, see the [Contributing wiki page](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/wiki/Contributing).
Thank you for contributing to Gitea Runner Manager (GRM)!
## Branch Naming
+6 -6
View File
@@ -8,12 +8,12 @@ Each runner runs in an isolated **rootless Docker** environment under a dedicate
[![CI](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions/workflows/ci.yml/badge.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
[![License: GPL-3.0](https://img.shields.io/badge/license-GPL--3.0-blue)](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/src/branch/master/LICENSE)
[![Coverage](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/raw/commit/ab26a799a78b18da47d4da71d2a763517b2e2143/coverage.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
[![Tests](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/raw/commit/ab26a799a78b18da47d4da71d2a763517b2e2143/tests.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
[![Docs](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/raw/commit/ab26a799a78b18da47d4da71d2a763517b2e2143/docs.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/wiki)
[![Code Quality](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/raw/commit/ab26a799a78b18da47d4da71d2a763517b2e2143/quality.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
[![Version](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/raw/commit/ab26a799a78b18da47d4da71d2a763517b2e2143/version.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/releases)
[![Python](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/raw/commit/ab26a799a78b18da47d4da71d2a763517b2e2143/python.svg)](https://www.python.org/downloads/)
[![Coverage](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/raw/commit/26565ddc9d567598da7e631765d969ccb16df74f/coverage.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
[![Tests](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/raw/commit/26565ddc9d567598da7e631765d969ccb16df74f/tests.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
[![Docs](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/raw/commit/26565ddc9d567598da7e631765d969ccb16df74f/docs.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/wiki)
[![Code Quality](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/raw/commit/26565ddc9d567598da7e631765d969ccb16df74f/quality.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
[![Version](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/raw/commit/26565ddc9d567598da7e631765d969ccb16df74f/version.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/releases)
[![Python](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/raw/commit/26565ddc9d567598da7e631765d969ccb16df74f/python.svg)](https://www.python.org/downloads/)
## Why GRM?
+1 -15
View File
@@ -1,17 +1,3 @@
# Troubleshooting
| Symptom | Likely Cause | Solution |
|---------|-------------|----------|
| Pre-commit rejects commit message | Missing conventional format or GRM-N prefix present | Use `feat: description` format without `GRM-N:` |
| `make molecule` fails with `runner_name is undefined` | Verify playbook missing variable | Fixed in Phase 1.1; ensure you're on latest master |
| CI molecule job fails | Docker not available on runner host | Ensure Gitea runner host has Docker installed and running |
| Auto-merge doesn't trigger | Label not exactly `ready-to-merge` or CI checks not all green | Verify label spelling; check CI status |
| Vikunja task not updated after merge | VIKUNJA_TOKEN expired or task ID missing from commit | Regenerate token; verify merge commit has `GRM-N:` prefix |
| Post-merge can't find Vikunja task | Task not in project 6 or identifier mismatch | Verify task exists in Vikunja project 6 with correct identifier |
| `make pytest-cov` fails | Coverage below 100% | Add tests for new code paths |
| `devx.tools.configure_repo` fails | CI_GITEA_TOKEN missing or invalid | Set token with repo admin scope and re-run |
| `configure_repo` sets wrong status checks | Stale `BRANCH_PROTECTION_CONFIG` | Updated to include `(pull_request)` suffix; re-run `configure_repo` |
| Token visible in `ps aux` during install | Old version passed tokens via command line | Fixed: tokens now passed via temp file with `0600` permissions |
| `remove-runner.yml` leaves lingering enabled | Old version didn't disable lingering | Fixed: now runs `loginctl disable-linger` and removes subuid/subgid |
| apt cache update always reports `changed` | `cache_valid_time: 0` forced update every run | Fixed: changed to `cache_valid_time: 3600` |
| Prune/service templates created even when `docker_rootless_setup: false` | Template tasks not guarded | Fixed: template creation now guarded by `docker_rootless_setup` |
See the [Troubleshooting guide](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/wiki/Troubleshooting) in the wiki.
@@ -24,6 +24,11 @@ gitea_runner_prune_label: "gitea-runner=true"
# Service configuration
gitea_runner_service_restart_sec: "5"
# Admin token for runner deregistration via Gitea API.
# If not set, falls back to registration_token (which likely lacks admin scope).
# Set this to a token with admin scope to enable automatic runner cleanup on removal.
gitea_admin_token: ""
# Removal defaults
remove_systemd_template: true
remove_runner_user: true
@@ -30,7 +30,10 @@
that:
- "'Type=simple' in service_template.content | b64decode"
- "'ExecStart={{ gitea_runner_binary_path }}' in service_template.content | b64decode"
- "'Restart=on-failure' in service_template.content | b64decode"
- "'Restart=always' in service_template.content | b64decode"
- "'Requires=docker.service' in service_template.content | b64decode"
- "'PartOf=docker.service' in service_template.content | b64decode"
- "'StartLimitBurst=10' in service_template.content | b64decode"
- "'DOCKER_HOST=unix:///run/user' in service_template.content | b64decode"
- "'XDG_RUNTIME_DIR=/run/user' in service_template.content | b64decode"
fail_msg: "User service template is missing expected directives"
@@ -18,13 +18,11 @@
else {} }}
when: runner_file_stat.stat.exists | default(false) | bool
- name: Deregister runner with Gitea via CLI
- name: Deregister runner from Gitea via API
ansible.builtin.command: >
{{ gitea_runner_binary_path }} delete
--token {{ registration_token }}
--name {{ runner_name }}
--instance {{ gitea_url }}
--no-interactive
curl -sf --connect-timeout 5 --max-time 10 -X DELETE
-H "Authorization: token {{ gitea_admin_token | default(registration_token) }}"
"{{ gitea_url }}/api/v1/admin/actions/runners/{{ runner_reg.id }}"
args:
chdir: "{{ gitea_runner_data_dir }}"
become: true
@@ -35,10 +33,24 @@
when:
- runner_file_stat.stat.exists | default(false) | bool
- not skip_runner_registration
- runner_reg.id is defined
register: deregister_output
changed_when: deregister_output.rc == 0
failed_when: false
- name: Warn if deregistration failed
ansible.builtin.debug:
msg: >-
WARNING: Runner deregistration from Gitea failed (rc={{ deregister_output.rc | default('N/A') }}).
The runner entry may remain in Gitea's admin UI as offline.
Use an admin token (gitea_admin_token var) to enable automatic cleanup,
or remove it manually from {{ gitea_url }}/-/admin/actions/runners
when:
- runner_file_stat.stat.exists | default(false) | bool
- not skip_runner_registration
- deregister_output is defined
- deregister_output.rc | default(1) != 0
- name: Remove runner registration file
ansible.builtin.file:
path: "{{ gitea_runner_data_dir }}/.runner"
@@ -6,4 +6,4 @@ Type=oneshot
Environment=DOCKER_HOST=unix:///run/user/{{ gitea_runner_uid }}/docker.sock
Environment=XDG_RUNTIME_DIR=/run/user/{{ gitea_runner_uid }}
ExecStart=/usr/bin/docker system prune -f --filter "label={{ gitea_runner_prune_label }}" --filter "until={{ gitea_runner_prune_until }}"
ExecStart=/usr/bin/docker volume prune -f --filter "label={{ gitea_runner_prune_label }}" --filter "until={{ gitea_runner_prune_until }}"
ExecStart=/usr/bin/docker volume prune -f --filter "label={{ gitea_runner_prune_label }}"
@@ -1,6 +1,8 @@
[Unit]
Description=Gitea Actions Runner (rootless)
After=docker.service
Requires=docker.service
PartOf=docker.service
[Service]
Type=simple
@@ -10,8 +12,10 @@ Environment=DOCKER_HOST=unix:///run/user/{{ gitea_runner_uid }}/docker.sock
Environment=XDG_RUNTIME_DIR=/run/user/{{ gitea_runner_uid }}
ExecStop=/bin/kill -TERM $MAINPID
TimeoutStopSec=30
Restart=on-failure
Restart=always
RestartSec={{ gitea_runner_service_restart_sec }}
StartLimitIntervalSec=300
StartLimitBurst=10
[Install]
WantedBy=default.target
+13 -13
View File
@@ -8,12 +8,12 @@ Each runner runs in an isolated **rootless Docker** environment under a dedicate
[![CI](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions/workflows/ci.yml/badge.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
[![License: GPL-3.0](https://img.shields.io/badge/license-GPL--3.0-blue)](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/src/branch/master/LICENSE)
[![Coverage](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/raw/commit/ab26a799a78b18da47d4da71d2a763517b2e2143/coverage.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
[![Tests](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/raw/commit/ab26a799a78b18da47d4da71d2a763517b2e2143/tests.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
[![Docs](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/raw/commit/ab26a799a78b18da47d4da71d2a763517b2e2143/docs.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/wiki)
[![Code Quality](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/raw/commit/ab26a799a78b18da47d4da71d2a763517b2e2143/quality.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
[![Version](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/raw/commit/ab26a799a78b18da47d4da71d2a763517b2e2143/version.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/releases)
[![Python](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/raw/commit/ab26a799a78b18da47d4da71d2a763517b2e2143/python.svg)](https://www.python.org/downloads/)
[![Coverage](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/raw/commit/26565ddc9d567598da7e631765d969ccb16df74f/coverage.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
[![Tests](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/raw/commit/26565ddc9d567598da7e631765d969ccb16df74f/tests.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
[![Docs](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/raw/commit/26565ddc9d567598da7e631765d969ccb16df74f/docs.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/wiki)
[![Code Quality](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/raw/commit/26565ddc9d567598da7e631765d969ccb16df74f/quality.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
[![Version](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/raw/commit/26565ddc9d567598da7e631765d969ccb16df74f/version.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/releases)
[![Python](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/raw/commit/26565ddc9d567598da7e631765d969ccb16df74f/python.svg)](https://www.python.org/downloads/)
## Overview
@@ -42,20 +42,20 @@ All supported OSes are tested in CI via Molecule scenarios on every PR that chan
## User Documentation
- [Getting Started](Getting-Started.-) — Installation, quick start, token setup, first run, log viewing
- [Getting Started](Getting-Started) — Installation, quick start, token setup, first run, log viewing
- [Installation](Installation) — Prerequisites, setup methods, multiple instances, runner registry
- [CLI Commands](CLI-Commands.-) — All commands with arguments, options, and examples
- [CLI Commands](CLI-Commands) — All commands with arguments, options, and examples
- [Troubleshooting](Troubleshooting) — Common issues, diagnostics, and solutions
- [FAQ](FAQ) — Frequently asked questions
## Technical Documentation
- [Architecture](Architecture) — High-level design, component diagram, data flow, security model, per-runner isolation
- [Development Setup](Development-Setup.-) — Environment setup, project structure, dependencies, linting, testing
- [CI/CD Workflow](CI-CD-Workflow.-) — PR workflow, branch protection, release pipeline, change classification, badge generation
- [Testing Strategy](Testing-Strategy.-) — Unit tests, Molecule scenarios, integration tests, CI distribution
- [Decision Log](Decision-Log.-) — Key technical decisions and rationale (ADRs)
- [Contributing Guide](Contributing-Guide.-) — Coding standards, PR workflow, commit conventions, Ansible role conventions
- [Development Setup](Development-Setup) — Environment setup, project structure, dependencies, linting, testing
- [CI/CD Workflow](CI-CD-Workflow) — PR workflow, branch protection, release pipeline, change classification, badge generation
- [Testing Strategy](Testing-Strategy) — Unit tests, Molecule scenarios, integration tests, CI distribution
- [Decision Log](Decision-Log) — Key technical decisions and rationale (ADRs)
- [Contributing Guide](Contributing-Guide) — Coding standards, PR workflow, commit conventions, Ansible role conventions
## Quick Links
+1 -1
View File
@@ -299,5 +299,5 @@ All CLI options can be set via environment variables (loaded from `.env` via pyt
| `GITEA_RUNNER_USER` | `install`, `update` | Default SSH user |
| `GITEA_RUNNER_KEY` | `install`, `update` | Default SSH key path |
| `GITEA_RUNNER_LABELS` | `install` | Default runner labels |
| `GRM_LANG` | all | UI language: `en`, `bg`, `de`, `ru`, `zh` |
| `GRM_LANG` | all | UI language: `en`, `bg`, `de`, `ru`, `zh`, `pl` |
| `GRM_LOG_LEVEL` | all | Console log level: `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL` |
+18 -18
View File
@@ -1,6 +1,6 @@
# FAQ
### How do I obtain the Gitea registration token?
## How do I obtain the Gitea registration token?
There are three levels of registration tokens, depending on which repositories the runner should serve:
@@ -10,7 +10,7 @@ There are three levels of registration tokens, depending on which repositories t
Set the token as `GITEA_REGISTRATION_TOKEN` in your `.env` file or pass it via `--token` on the command line.
### What is the CI_GITEA_TOKEN and do I need it?
## What is the CI_GITEA_TOKEN and do I need it?
`CI_GITEA_TOKEN` is a Gitea admin API token used for optional post-install verification. When set, GRM queries the Gitea API after installation to confirm the runner appears in the runner list. This is purely informational — the integration test passes/fails based on the `.runner` file and systemd service, not the API check.
@@ -18,7 +18,7 @@ To generate one: Settings → Applications → Generate New Token, with the `adm
If you skip it, GRM will still verify the runner correctly — it just won't show the extra API confirmation.
### How do I skip the sudo password prompt for automation?
## How do I skip the sudo password prompt for automation?
Configure passwordless sudo on the remote host and pass `--no-ask-become-pass` to the CLI command. This is recommended for CI/CD pipelines.
@@ -34,7 +34,7 @@ Then use:
grm install 192.168.1.10 --user ubuntu --key ~/.ssh/id_ed25519 --name prod-runner --no-ask-become-pass
```
### Can I run multiple runners on the same host?
## Can I run multiple runners on the same host?
Yes. Each runner instance is fully isolated with its own system user (`grm-<name>`), rootless Docker daemon, data directory, and systemd user service. Install additional runners with different `--name` values and manage them independently by name.
@@ -46,7 +46,7 @@ grm list
Runners on the same host never interfere with each other or with the host's Docker installation.
### Why does my runner appear offline after installation?
## Why does my runner appear offline after installation?
Check that `GITEA_URL` and `GITEA_REGISTRATION_TOKEN` are correct, verify the runner service is running with `sudo -u grm-<name> systemctl --user status gitea-runner`, and check the logs for registration errors. You can also confirm the runner appears as **Online** in the Gitea UI under **Actions → Runners**.
@@ -56,15 +56,15 @@ Common causes:
- Rootless Docker daemon not running — check `sudo -u grm-<name> systemctl --user status docker`
- Lingering not enabled — check `loginctl show-user grm-<name> | grep Linger`
### What does the "Event loop is closed" warning mean?
## What does the "Event loop is closed" warning mean?
This is a harmless cleanup traceback from Molecule's Docker driver when the test process is interrupted. It does not indicate a test failure.
### Where are runner connection details stored?
## Where are runner connection details stored?
GRM stores each runner's connection details (host, user, SSH key, Gitea URL, labels) in a local JSON registry at `~/.local/share/grm/runners.json`. After installation, lifecycle commands work by runner name only — you can override any stored value by passing the corresponding flag.
### How do I update the gitea_runner binary?
## How do I update the gitea_runner binary?
Use the `grm update` command:
@@ -80,7 +80,7 @@ grm update 192.168.1.10 --user ubuntu --version 1.0.8
The update command downloads the new binary and replaces the existing one at `/usr/local/bin/gitea_runner`. The runner service is restarted automatically.
### How do I completely remove a runner?
## How do I completely remove a runner?
Use the `grm remove` command:
@@ -96,18 +96,18 @@ If the remote host is already gone or unreachable, use `--force` to skip remote
grm remove prod-runner --force
```
### What is the difference between disable and remove?
## What is the difference between disable and remove?
- **`grm disable <name>`** — Deregisters the runner from Gitea and stops the service, but leaves the user, directories, and service files in place. The runner can be re-enabled later with `grm enable` and re-registered with a new token.
- **`grm remove <name>`** — Completely removes the runner: deregisters from Gitea, stops and disables the service, removes the system user, deletes all directories, and removes the local registry entry. This is irreversible.
### What operating systems are supported?
## What operating systems are supported?
GRM supports Arch Linux (rolling), Ubuntu 22.04/24.04, and Debian 12. All supported OSes are tested in CI via Molecule scenarios on every PR that changes Ansible files.
### How do I change the UI language?
## How do I change the UI language?
Set the `GRM_LANG` environment variable to one of the supported languages: `en` (English, default), `bg` (Bulgarian), `de` (German), `ru` (Russian), `zh` (Chinese).
Set the `GRM_LANG` environment variable to one of the supported languages: `en` (English, default), `bg` (Bulgarian), `de` (German), `ru` (Russian), `zh` (Chinese), `pl` (Polish).
```bash
GRM_LANG=bg grm install 192.168.1.10 --user ubuntu --name prod-runner
@@ -119,7 +119,7 @@ Or set it in your `.env` file:
GRM_LANG=bg
```
### How do I enable debug logging?
## How do I enable debug logging?
Set the `GRM_LOG_LEVEL` environment variable to `DEBUG`:
@@ -129,7 +129,7 @@ GRM_LOG_LEVEL=DEBUG grm install 192.168.1.10 --user ubuntu --name prod-runner
The log file at `~/.local/state/grm/logs/grm.log` always captures DEBUG level regardless of this setting. Ansible execution logs are stored in timestamped files at `~/.local/state/grm/logs/ansible-<timestamp>.log`.
### What runner labels should I use?
## What runner labels should I use?
By default, runners are registered with `docker,ubuntu-latest:docker://runner-images:ubuntu-22.04`. You can override this with `--labels` or the `GITEA_RUNNER_LABELS` environment variable.
@@ -142,7 +142,7 @@ grm install 192.168.1.10 --user ubuntu --name prod-runner \
--labels "docker:docker://gitea/runner-images:ubuntu-latest"
```
### Is GRM secure?
## Is GRM secure?
Yes. GRM is designed with security as a first-class concern:
@@ -151,7 +151,7 @@ Yes. GRM is designed with security as a first-class concern:
- **No shell injection**: The CLI never uses `shell=True` with subprocess.
- **Bandit security scan**: The CI pipeline runs Bandit on every PR.
### Can I install GRM via pip?
## Can I install GRM via pip?
Yes:
@@ -161,7 +161,7 @@ pip install gitea-runner-manager
This installs the `grm` CLI and its Python dependencies. The Ansible playbooks and role are bundled with the package. For development or access to Make targets, clone the repository instead.
### How does GRM handle idempotence?
## How does GRM handle idempotence?
The Ansible role is idempotent — running `grm install` twice produces zero changes on the second run. Each task checks for existing state before making changes. For example:
+3 -3
View File
@@ -98,7 +98,7 @@ CI_GITEA_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
| `GITEA_RUNNER_USER` | No | current login | Default SSH user (overrides `--user`) |
| `GITEA_RUNNER_KEY` | No | — | Default SSH key path (overrides `--key`) |
| `GITEA_RUNNER_LABELS` | No | — | Default runner labels (overrides `--labels`) |
| `GRM_LANG` | No | `en` | UI language: `en`, `bg`, `de`, `ru`, `zh` |
| `GRM_LANG` | No | `en` | UI language: `en`, `bg`, `de`, `ru`, `zh`, `pl` |
| `GRM_LOG_LEVEL` | No | `INFO` | Console log level: `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL` |
## Step 3: Install Your First Runner
@@ -182,7 +182,7 @@ grm disable prod-runner # Disable and deregister the runner
grm remove prod-runner # Remove the runner completely
```
See [CLI Commands](CLI-Commands.-) for the full command reference.
See [CLI Commands](CLI-Commands) for the full command reference.
## View Logs
@@ -232,6 +232,6 @@ Console output is automatically colorised via `click.style`: operation headers i
## Next Steps
- **Install more runners** on the same or different hosts — see [Installation](Installation)
- **Learn all CLI commands** — see [CLI Commands](CLI-Commands.-)
- **Learn all CLI commands** — see [CLI Commands](CLI-Commands)
- **Troubleshoot issues** — see [Troubleshooting](Troubleshooting)
- **Understand the architecture** — see [Architecture](Architecture)
+3 -3
View File
@@ -1,6 +1,6 @@
# Installation
> **Before you start:** Make sure you have cloned the repo and checked out the latest stable release tag. See [Getting Started](Getting-Started.-) for setup instructions. Do not run from `master` — it may contain unreleased changes.
> **Before you start:** Make sure you have cloned the repo and checked out the latest stable release tag. See [Getting Started](Getting-Started) for setup instructions. Do not run from `master` — it may contain unreleased changes.
## Prerequisites
@@ -14,7 +14,7 @@
- **SSH server** — The remote host must be reachable via SSH using the user specified with `--user` and the private key specified with `--key`. GRM uses Ansible under the hood, which connects to the target host over SSH to execute all installation and configuration tasks. Without valid SSH credentials, Ansible cannot establish a connection and the deployment will fail.
- **Sudo access** — GRM requires root privileges on the remote host to create system users, install packages, and configure rootless Docker. By default, you will be prompted interactively for the sudo password. For automation or uninterrupted workflows, configure passwordless sudo on the remote host and pass `--no-ask-become-pass`.
- **Gitea registration token** — You need a runner registration token from your Gitea instance. See [Getting Started](Getting-Started.-) for detailed instructions on obtaining tokens.
- **Gitea registration token** — You need a runner registration token from your Gitea instance. See [Getting Started](Getting-Started) for detailed instructions on obtaining tokens.
- **systemd** — Required for user services and lingering. All supported OSes ship with systemd.
- **Docker** — Installed automatically by the Ansible role (rootless mode). No pre-existing Docker installation is required.
@@ -96,7 +96,7 @@ Required variables:
| `GITEA_URL` | Your Gitea instance URL (e.g., `https://git.example.com`) |
| `GITEA_REGISTRATION_TOKEN` | Runner registration token from Gitea (starts with `GR`) |
See [Getting Started](Getting-Started.-) for detailed token setup instructions.
See [Getting Started](Getting-Started) for detailed token setup instructions.
## Quick Start Install
+2 -2
View File
@@ -34,7 +34,7 @@ ci = [
"build==1.5.0",
"twine==6.2.0",
# Reusable CI/CD and dev tools (auto-merge, pr-review, pre-push checks, etc.)
"devx==0.26.3",
"devx==0.27.2",
]
# Lint and type-checking tools (quality job)
lint = [
@@ -54,7 +54,7 @@ molecule = [
dev = [
"gitea-runner-manager[ci,lint,molecule]",
# Reusable CI/CD and dev tools (pre-push hooks, create-task, create-pr)
"devx==0.26.3",
"devx==0.27.2",
# Non-Python dev dependency: checkmake (Makefile linter)
# Install via: go install github.com/checkmake/checkmake/cmd/checkmake@latest
]
+1 -1
View File
@@ -1,3 +1,3 @@
"""Gitea Runner Manager — lean CLI for managing Gitea Actions runners."""
__version__ = "0.12.2"
__version__ = "0.12.4"