Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb9e8e6c4b | ||
|
|
d8312ff62c | ||
|
|
39a8f20df2 | ||
|
|
240f08fff4 | ||
|
|
d38a64b0e1 | ||
|
|
89bd40c4a8 | ||
|
|
ab2101983f | ||
|
|
12f4aa4c92 | ||
|
|
60ad1ad30d | ||
|
|
0e64353b0d | ||
|
|
5956bb4fac |
+12
-1
@@ -15,7 +15,8 @@ GITEA_REGISTRATION_TOKEN=your-registration-token
|
||||
# If set, API checks are performed as a bonus but do NOT affect pass/fail.
|
||||
# Required scopes: read:user, read:repository, read:admin (or just "admin")
|
||||
# Generate token at: Settings → Applications → Generate New Token
|
||||
# CI_GITEA_TOKEN=your-admin-api-token
|
||||
# CI_GITEA_API_TOKEN=your-admin-api-token
|
||||
# Legacy CI_GITEA_TOKEN is also accepted.
|
||||
|
||||
# Integration test API retries (optional, default: 3).
|
||||
# Number of times to retry API checks waiting for runner to appear.
|
||||
@@ -50,6 +51,16 @@ GITEA_REGISTRATION_TOKEN=your-registration-token
|
||||
# Used by PIP_INSTALL to configure PIP_EXTRA_INDEX_URL
|
||||
CI_GITEA_USERNAME=your-gitea-username
|
||||
|
||||
# Role-based Gitea API tokens (devx 0.38.0+)
|
||||
# DEVELOPER_GITEA_API_TOKEN is used by local `grm trigger-workflow` and `make create-pr`.
|
||||
# CI_GITEA_API_TOKEN is used by CI workflows (and accepted as a fallback for local tools).
|
||||
# REVIEWER_GITEA_API_TOKEN is used by CI to post APPROVE reviews; it must belong to a
|
||||
# different user than the PR author.
|
||||
# Legacy CI_GITEA_TOKEN and REVIEW_GITEA_TOKEN are accepted as fallbacks.
|
||||
# DEVELOPER_GITEA_API_TOKEN=your-developer-token
|
||||
# CI_GITEA_API_TOKEN=your-ci-token
|
||||
# REVIEWER_GITEA_API_TOKEN=your-reviewer-token
|
||||
|
||||
# Vikunja API token (required for `make create-task` dev workflow)
|
||||
# Generate at: Vikunja → Settings → API Tokens
|
||||
# VIKUNJA_TOKEN=your-vikunja-api-token
|
||||
|
||||
+23
-35
@@ -6,7 +6,7 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
CI_GITEA_USERNAME: ${{ vars.CI_GITEA_USERNAME }}
|
||||
|
||||
jobs:
|
||||
@@ -18,7 +18,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up environment
|
||||
env:
|
||||
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
CI_GITEA_USERNAME: ${{ vars.CI_GITEA_USERNAME }}
|
||||
run: make setup-image EXTRAS=ci,lint
|
||||
- name: Lint all
|
||||
@@ -30,30 +30,16 @@ jobs:
|
||||
run: |
|
||||
. .venv/bin/activate 2>/dev/null || true
|
||||
make pytest-cov
|
||||
- name: Documentation lint check
|
||||
env:
|
||||
PYTHONPATH: src
|
||||
run: |
|
||||
. .venv/bin/activate 2>/dev/null || true
|
||||
python3 -m devx.ci.lint_docs --root .
|
||||
- name: Documentation version reference check
|
||||
env:
|
||||
PYTHONPATH: src
|
||||
run: |
|
||||
. .venv/bin/activate 2>/dev/null || true
|
||||
python3 -m devx.tools.check_doc_versions --root . --package grm
|
||||
- name: Vale prose lint check
|
||||
- name: Documentation gate (coverage + stale refs + lint + version refs + prose)
|
||||
env:
|
||||
PYTHONPATH: src
|
||||
DEVX_DOC_COVERAGE_STRICT: "1"
|
||||
DEVX_DOC_VERSIONS_PKG: grm
|
||||
DEVX_VALE_LEVEL: warning
|
||||
run: |
|
||||
. .venv/bin/activate 2>/dev/null || true
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
# Install vale if not present
|
||||
if ! command -v vale >/dev/null 2>&1; then
|
||||
python3 -m devx.tools.install_tools --tool vale
|
||||
fi
|
||||
vale sync
|
||||
vale --minAlertLevel=error docs/ AGENTS.md README.md
|
||||
make devx-docs-check
|
||||
- name: Translation completeness check
|
||||
run: |
|
||||
. .venv/bin/activate 2>/dev/null || true
|
||||
@@ -94,7 +80,7 @@ jobs:
|
||||
fetch-depth: 0
|
||||
- name: Set up environment
|
||||
env:
|
||||
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
CI_GITEA_USERNAME: ${{ vars.CI_GITEA_USERNAME }}
|
||||
run: make setup-image EXTRAS=ci,lint
|
||||
- name: Release dry-run validation
|
||||
@@ -120,7 +106,7 @@ jobs:
|
||||
fetch-depth: 0
|
||||
- name: Set up environment
|
||||
env:
|
||||
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
CI_GITEA_USERNAME: ${{ vars.CI_GITEA_USERNAME }}
|
||||
run: make setup-image EXTRAS=ci
|
||||
- name: Detect changed paths
|
||||
@@ -149,7 +135,7 @@ jobs:
|
||||
run: make setup-image EXTRAS=ci
|
||||
- name: Validate auto-merge preconditions
|
||||
env:
|
||||
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
VIKUNJA_TOKEN: ${{ secrets.VIKUNJA_TOKEN }}
|
||||
DEVX_TASK_PREFIX: GRM
|
||||
DEVX_VIKUNJA_PROJECT_ID: 6
|
||||
@@ -179,13 +165,13 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up environment
|
||||
env:
|
||||
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
CI_GITEA_USERNAME: ${{ vars.CI_GITEA_USERNAME }}
|
||||
run: make setup-image EXTRAS=ci
|
||||
- name: Discover available runners
|
||||
id: discover
|
||||
env:
|
||||
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
MOLECULE_RUNNERS: ${{ vars.MOLECULE_RUNNERS }}
|
||||
PYTHONPATH: src
|
||||
run: |
|
||||
@@ -210,7 +196,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up environment
|
||||
env:
|
||||
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
CI_GITEA_USERNAME: ${{ vars.CI_GITEA_USERNAME }}
|
||||
run: make setup-image EXTRAS=ci,molecule
|
||||
- name: Install Ansible collections
|
||||
@@ -237,12 +223,14 @@ jobs:
|
||||
echo "Docker not available in CI container — skipping molecule tests"
|
||||
exit 0
|
||||
fi
|
||||
echo "$CI_GITEA_TOKEN" | docker login git.oblachno.oblachno.fyi -u "$CI_GITEA_USERNAME" --password-stdin
|
||||
_TOKEN="$CI_GITEA_API_TOKEN"; [ -z "$_TOKEN" ] && _TOKEN="$CI_GITEA_TOKEN"
|
||||
[ -z "$_TOKEN" ] && { echo "Gitea API token not set — skipping Docker login"; exit 0; }
|
||||
echo "$_TOKEN" | docker login git.oblachno.oblachno.fyi -u "$CI_GITEA_USERNAME" --password-stdin
|
||||
# shellcheck disable=SC2086 # intentional word splitting for argument expansion
|
||||
python3 -m devx.molecule.molecule_ci_guard $TEST_PAIRS
|
||||
env:
|
||||
GITEA_URL: ${{ github.server_url }}
|
||||
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
CI_GITEA_USERNAME: ${{ vars.CI_GITEA_USERNAME }}
|
||||
RUN_ID: ${{ github.run_id }}
|
||||
ANSIBLE_INJECT_INVOCATION: "1"
|
||||
@@ -264,12 +252,12 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up environment
|
||||
env:
|
||||
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
CI_GITEA_USERNAME: ${{ vars.CI_GITEA_USERNAME }}
|
||||
run: make setup-image EXTRAS=ci
|
||||
- name: Run automated PR review
|
||||
env:
|
||||
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
PYTHONPATH: src
|
||||
run: |
|
||||
set -euo pipefail
|
||||
@@ -302,15 +290,15 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
token: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
- name: Set up environment
|
||||
env:
|
||||
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
CI_GITEA_USERNAME: ${{ vars.CI_GITEA_USERNAME }}
|
||||
run: make setup-image EXTRAS=ci
|
||||
- name: Post approval review
|
||||
env:
|
||||
CI_GITEA_TOKEN: ${{ secrets.REVIEW_GITEA_TOKEN }}
|
||||
REVIEWER_GITEA_API_TOKEN: ${{ secrets.REVIEWER_GITEA_API_TOKEN }}
|
||||
PR_NUMBER: ${{ github.event.number }}
|
||||
REPOSITORY: ${{ github.repository }}
|
||||
PYTHONPATH: src
|
||||
@@ -325,7 +313,7 @@ jobs:
|
||||
--body "Auto-approved: all CI checks passed (quality, molecule, pr-review, pre-merge-check)."
|
||||
- name: Squash merge with task ID
|
||||
env:
|
||||
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
VIKUNJA_TOKEN: ${{ secrets.VIKUNJA_TOKEN }}
|
||||
PYTHONPATH: src
|
||||
DEVX_TASK_PREFIX: GRM
|
||||
|
||||
@@ -32,7 +32,7 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
CI_GITEA_USERNAME: ${{ vars.CI_GITEA_USERNAME }}
|
||||
|
||||
jobs:
|
||||
@@ -48,7 +48,7 @@ jobs:
|
||||
fetch-depth: 1
|
||||
- name: Set up environment
|
||||
env:
|
||||
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
CI_GITEA_USERNAME: ${{ vars.CI_GITEA_USERNAME }}
|
||||
run: make setup-image EXTRAS=ci
|
||||
- name: Check if this is a release commit
|
||||
@@ -71,7 +71,7 @@ jobs:
|
||||
fetch-depth: 1
|
||||
- name: Set up environment
|
||||
env:
|
||||
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
CI_GITEA_USERNAME: ${{ vars.CI_GITEA_USERNAME }}
|
||||
run: make setup-image EXTRAS=ci
|
||||
- name: Validate latest commit message
|
||||
@@ -96,10 +96,10 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
token: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
- name: Set up environment
|
||||
env:
|
||||
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
CI_GITEA_USERNAME: ${{ vars.CI_GITEA_USERNAME }}
|
||||
run: make setup-image EXTRAS=ci,lint
|
||||
- name: Configure git
|
||||
@@ -120,7 +120,7 @@ jobs:
|
||||
- name: Notify on failure
|
||||
if: failure()
|
||||
env:
|
||||
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
PYTHONPATH: src
|
||||
run: |
|
||||
. .venv/bin/activate 2>/dev/null || true
|
||||
@@ -144,12 +144,12 @@ jobs:
|
||||
ref: ${{ needs.release.outputs.tag }}
|
||||
- name: Set up environment
|
||||
env:
|
||||
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
CI_GITEA_USERNAME: ${{ vars.CI_GITEA_USERNAME }}
|
||||
run: make setup-image EXTRAS=ci,lint
|
||||
- name: Build and publish release
|
||||
env:
|
||||
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
PYTHONPATH: src
|
||||
run: |
|
||||
. .venv/bin/activate 2>/dev/null || true
|
||||
@@ -160,7 +160,7 @@ jobs:
|
||||
- name: Notify on failure
|
||||
if: failure()
|
||||
env:
|
||||
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
PYTHONPATH: src
|
||||
run: |
|
||||
. .venv/bin/activate 2>/dev/null || true
|
||||
@@ -186,20 +186,20 @@ jobs:
|
||||
fetch-depth: 0
|
||||
- name: Set up environment
|
||||
env:
|
||||
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
CI_GITEA_USERNAME: ${{ vars.CI_GITEA_USERNAME }}
|
||||
run: make setup-image EXTRAS=ci
|
||||
- name: Sync documentation to wiki
|
||||
env:
|
||||
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
PYTHONPATH: src
|
||||
run: |
|
||||
. .venv/bin/activate 2>/dev/null || true
|
||||
python3 -m devx.ci.sync_wiki --repo "${{ github.repository }}" --strict
|
||||
python3 -m devx.ci.sync_wiki --repo "${{ github.repository }}" --verify
|
||||
- name: Notify on failure
|
||||
if: failure()
|
||||
env:
|
||||
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
PYTHONPATH: src
|
||||
run: |
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
@@ -220,14 +220,14 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: master
|
||||
token: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
token: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
- name: Fetch latest master
|
||||
run: |
|
||||
git fetch origin master
|
||||
git reset --hard origin/master
|
||||
- name: Set up environment
|
||||
env:
|
||||
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
CI_GITEA_USERNAME: ${{ vars.CI_GITEA_USERNAME }}
|
||||
run: make setup-image EXTRAS=lint
|
||||
- name: Generate and push badges
|
||||
@@ -239,7 +239,7 @@ jobs:
|
||||
- name: Notify on failure
|
||||
if: failure()
|
||||
env:
|
||||
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
PYTHONPATH: src
|
||||
run: |
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
@@ -261,7 +261,7 @@ jobs:
|
||||
fetch-depth: 0
|
||||
- name: Set up environment
|
||||
env:
|
||||
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
CI_GITEA_USERNAME: ${{ vars.CI_GITEA_USERNAME }}
|
||||
run: make setup-image EXTRAS=ci
|
||||
- name: Update Vikunja task
|
||||
@@ -276,7 +276,7 @@ jobs:
|
||||
- name: Notify on failure
|
||||
if: failure()
|
||||
env:
|
||||
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
PYTHONPATH: src
|
||||
run: |
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
@@ -296,12 +296,12 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up environment
|
||||
env:
|
||||
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
CI_GITEA_USERNAME: ${{ vars.CI_GITEA_USERNAME }}
|
||||
run: make setup-image EXTRAS=ci
|
||||
- name: Ensure branch protection and labels
|
||||
env:
|
||||
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
PYTHONPATH: src
|
||||
DEVX_REPO_NAME: grm
|
||||
DEVX_REPO_OWNER: oblachno-oss
|
||||
@@ -312,7 +312,7 @@ jobs:
|
||||
- name: Notify on failure
|
||||
if: failure()
|
||||
env:
|
||||
CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }}
|
||||
PYTHONPATH: src
|
||||
run: |
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
|
||||
@@ -81,11 +81,12 @@ repos:
|
||||
pass_filenames: false
|
||||
stages: [pre-commit]
|
||||
|
||||
- id: lint-docs
|
||||
name: documentation lint check
|
||||
entry: env PYTHONPATH=src .venv/bin/python -m devx.ci.lint_docs --root .
|
||||
- id: docs-check
|
||||
name: documentation gate (coverage + stale refs + lint + version refs + prose)
|
||||
entry: bash -c 'PYTHONPATH=src DEVX_DOC_COVERAGE_STRICT=1 DEVX_DOC_VERSIONS_PKG=grm DEVX_VALE_LEVEL=warning make devx-docs-check'
|
||||
language: system
|
||||
pass_filenames: false
|
||||
always_run: true
|
||||
stages: [pre-commit]
|
||||
|
||||
- id: pytest-cov
|
||||
|
||||
@@ -34,14 +34,17 @@ write-good.E-Prime = NO
|
||||
write-good.So = NO
|
||||
write-good.ThereIs = NO
|
||||
write-good.TooWordy = NO
|
||||
write-good.Passive = NO
|
||||
|
||||
# Vale defaults — spelling catches too many technical terms
|
||||
Vale.Terms = NO
|
||||
Vale.Repetition = NO
|
||||
Vale.Spelling = NO
|
||||
|
||||
# Readability — warnings only, technical docs are naturally complex
|
||||
# Readability — technical docs are naturally complex, downgrade to suggestions
|
||||
Readability.FleschReadingEase = suggestion
|
||||
Readability.FleschKincaid = suggestion
|
||||
Readability.AutomatedReadability = suggestion
|
||||
Readability.ColemanLiau = suggestion
|
||||
Readability.LIX = suggestion
|
||||
Readability.GunningFog = suggestion
|
||||
|
||||
@@ -3,4 +3,4 @@ message: "Unlabeled code block — add a language tag (```bash, ```yaml, etc.)"
|
||||
level: warning
|
||||
scope: raw
|
||||
raw:
|
||||
- '(?s)```\n(?!.*```)'
|
||||
- '(?ms)^\n```\n.*?^```\s*$'
|
||||
|
||||
@@ -2,7 +2,7 @@ Based on [write-good](https://github.com/btford/write-good).
|
||||
|
||||
> Naive linter for English prose for developers who can't write good and wanna learn to do other stuff good too.
|
||||
|
||||
```text
|
||||
```
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Brian Ford
|
||||
|
||||
@@ -166,7 +166,7 @@ it attests that the reviewer has gone through every checklist category.
|
||||
The `--checklist-categories` flag is also **required** — it must list at
|
||||
least 8 of the 13 category numbers, ensuring the reviewer actually
|
||||
checked each category rather than rubber-stamping. The review body must
|
||||
be substantive (> 50 characters) — trivial approvals like "LGTM" are
|
||||
be substantive (> 50 characters) — perfunctory approvals like "LGTM" are
|
||||
rejected.
|
||||
|
||||
Then add the `ready-to-merge` label. The auto-merge workflow will:
|
||||
@@ -244,7 +244,7 @@ Vikunja task updates:
|
||||
- Loops are prevented by `has_unreleased_changes` — after a release commit is tagged, the next run finds no unreleased changes and exits
|
||||
|
||||
3. **sync-wiki** — Syncs documentation to the Gitea wiki. Runs for ALL
|
||||
non-release commits (not just when release succeeds), so docs-only
|
||||
non-release commits (not only when release succeeds), so docs-only
|
||||
changes still update the wiki.
|
||||
|
||||
4. **badges** — Generates and pushes quality badge SVGs to the `badges` branch.
|
||||
@@ -253,7 +253,7 @@ Vikunja task updates:
|
||||
any release commits.
|
||||
|
||||
5. **vikunja** — Marks the corresponding Vikunja task as done. Runs for ALL
|
||||
non-release commits (not just when release succeeds), so infrastructure-only
|
||||
non-release commits (not only when release succeeds), so infrastructure-only
|
||||
changes still update the task tracker.
|
||||
|
||||
6. **publish** — Runs after release succeeds (needs: release). Builds and
|
||||
@@ -486,7 +486,7 @@ main.yml → systemd_check → user_setup → rootless_docker → install_runner
|
||||
- `install_runner.yml` handles: download, config, validate, register, service
|
||||
- `main.yml` handles: prune, integration_test (NOT install_runner — avoids duplicates)
|
||||
- `systemctl --user` tasks must be guarded by `docker_rootless_setup`
|
||||
- Template creation tasks are NOT guarded by `docker_rootless_setup` (they just create files)
|
||||
- Template creation tasks are NOT guarded by `docker_rootless_setup` (they only create files)
|
||||
|
||||
## Molecule Scenarios
|
||||
|
||||
@@ -590,7 +590,7 @@ the user should not need to specify which profile to use.
|
||||
2. **Background by default, foreground when blocking.**
|
||||
3. **Provide full context in the prompt** — subagents don't inherit conversation history.
|
||||
4. **One subagent per concern.** Chain: investigate → fix in main session → review.
|
||||
5. **Don't delegate trivial work** (<30s, <50 lines of context).
|
||||
5. **Don't delegate minor work** (<30s, <50 lines of context).
|
||||
6. **Compact after subagent returns.**
|
||||
7. **Never skip delegation to save time** — it keeps main context small.
|
||||
|
||||
|
||||
@@ -2,6 +2,28 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [0.17.1] - 2026-07-09
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Disable IPv6 in rootless Docker daemon on runners
|
||||
|
||||
## [0.17.0] - 2026-07-08
|
||||
|
||||
### Features
|
||||
|
||||
- Bump devx to 0.38.0 and migrate to role-based Gitea tokens
|
||||
|
||||
## [0.16.0] - 2026-07-07
|
||||
|
||||
### Features
|
||||
|
||||
- Consolidate docs checks into devx-docs-check target
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Replace --strict with --verify for sync_wiki
|
||||
|
||||
## [0.15.0] - 2026-07-06
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
.PHONY: all setup setup-ci setup-quality setup-molecule setup-release setup-image install update lint ansible-lint makefile-lint lint-all lint-ruff lint-format lint-bandit lint-deps typecheck checkmake install-hooks test test-unit pytest-cov molecule molecule-all test-all clean workflow-lint workflow-dryrun workflow-check install-tools check-api-identity-checks
|
||||
.PHONY: configure-gitea-pypi
|
||||
.PHONY: create-task create-pr push-with-pr git-push
|
||||
.PHONY: check-docs docs-check
|
||||
|
||||
PYTHON := python3
|
||||
VENV := .venv
|
||||
@@ -85,7 +86,8 @@ setup-release: $(VENV)/bin/activate .env configure-gitea-pypi
|
||||
# the venv symlink first, then installs the project.
|
||||
setup-image:
|
||||
@if [ -d /opt/venv ]; then ln -sf /opt/venv .venv; . .venv/bin/activate; \
|
||||
if [ -n "$$CI_GITEA_TOKEN" ]; then export PIP_EXTRA_INDEX_URL="https://$$CI_GITEA_USERNAME:$$CI_GITEA_TOKEN@git.oblachno.oblachno.fyi/api/packages/oblachno-oss/pypi/simple/"; fi; \
|
||||
_TOKEN="$$CI_GITEA_API_TOKEN"; [ -z "$$_TOKEN" ] && _TOKEN="$$DEVELOPER_GITEA_API_TOKEN"; [ -z "$$_TOKEN" ] && _TOKEN="$$CI_GITEA_TOKEN"; \
|
||||
if [ -n "$$_TOKEN" ]; then export PIP_EXTRA_INDEX_URL="https://$$CI_GITEA_USERNAME:$${_TOKEN}@git.oblachno.oblachno.fyi/api/packages/oblachno-oss/pypi/simple/"; fi; \
|
||||
pip install -e .$(if $(EXTRAS),[$(EXTRAS)],); \
|
||||
else echo "[setup-image] /opt/venv not found — falling back to setup-ci"; $(MAKE) setup-ci; fi
|
||||
|
||||
@@ -158,10 +160,9 @@ workflow-dryrun: devx-workflow-dryrun
|
||||
workflow-check: devx-workflow-check
|
||||
|
||||
configure-gitea-pypi:
|
||||
@if [ -z "$$CI_GITEA_TOKEN" ]; then . ./.env 2>/dev/null; fi; \
|
||||
CI_GITEA_TOKEN="$$CI_GITEA_TOKEN"; \
|
||||
if [ -z "$$CI_GITEA_TOKEN" ]; then echo "[configure-gitea-pypi] CI_GITEA_TOKEN not set — skipping (devx must be on public PyPI)"; exit 0; fi; \
|
||||
echo "[configure-gitea-pypi] Gitea PyPI registry configured (CI_GITEA_TOKEN present)."
|
||||
_TOKEN="$$CI_GITEA_API_TOKEN"; [ -z "$$_TOKEN" ] && _TOKEN="$$DEVELOPER_GITEA_API_TOKEN"; [ -z "$$_TOKEN" ] && _TOKEN="$$CI_GITEA_TOKEN"; \
|
||||
if [ -z "$$_TOKEN" ]; then echo "[configure-gitea-pypi] Gitea API token not set — skipping (devx must be on public PyPI)"; exit 0; fi; \
|
||||
echo "[configure-gitea-pypi] Gitea PyPI registry configured (token present)."
|
||||
|
||||
ansible-lint:
|
||||
PATH="$(PWD)/$(BIN):$$PATH" $(BIN)/ansible-lint ansible/
|
||||
@@ -202,3 +203,7 @@ create-task: devx-create-task
|
||||
create-pr: devx-create-pr
|
||||
push-with-pr: devx-push-with-pr
|
||||
git-push: devx-push
|
||||
|
||||
# --- Documentation checks (via devx.mak fragment) -----------------------------
|
||||
check-docs: devx-check-docs
|
||||
docs-check: devx-docs-check
|
||||
|
||||
@@ -8,12 +8,12 @@ Each runner runs in an isolated **rootless Docker** environment under a dedicate
|
||||
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/src/branch/master/LICENSE)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/wiki)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/releases)
|
||||
[](https://www.python.org/downloads/)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/wiki)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/releases)
|
||||
[](https://www.python.org/downloads/)
|
||||
|
||||
## Why GRM?
|
||||
|
||||
@@ -147,7 +147,7 @@ GRM provides a single `grm` command with subcommands for the full runner lifecyc
|
||||
| `grm enable <name>` | Enable a runner to start on boot |
|
||||
| `grm disable <name>` | Disable and deregister a runner |
|
||||
| `grm status <name>` | Check the status of a registered runner |
|
||||
| `grm remove <name>` | Remove a runner completely (with remote cleanup) |
|
||||
| `grm remove <name>` | Remove a runner entirely (with remote cleanup) |
|
||||
| `grm remove <name> --force` | Remove only the local registry entry (skip remote cleanup) |
|
||||
| `grm list` | List all registered runners with live status |
|
||||
| `grm list --no-status` | List registered runners without SSH status checks |
|
||||
@@ -187,7 +187,7 @@ GRM reads configuration from a `.env` file in the current directory (loaded auto
|
||||
|
||||
### Sudo Password Handling
|
||||
|
||||
GRM delegates remote operations to Ansible, which uses `sudo` (become) on the target host. There are several ways to provide the sudo password, in priority order:
|
||||
GRM delegates remote operations to Ansible, which uses `sudo` (become) on the target host. There are multiple ways to provide the sudo password, in priority order:
|
||||
|
||||
1. **`--become-password-file <path>`** (CLI flag, global) — Read sudo password from a file. Works for all commands including `grm list`.
|
||||
2. **`GRM_BECOME_PASSWORD_FILE`** (env var) — Same as above, set in `.env` or environment.
|
||||
|
||||
@@ -97,6 +97,39 @@
|
||||
changed_when: true
|
||||
when: docker_rootless_setup
|
||||
|
||||
- name: Ensure Docker config directory exists
|
||||
ansible.builtin.file:
|
||||
path: "{{ gitea_runner_home }}/.config/docker"
|
||||
state: directory
|
||||
mode: "0755"
|
||||
owner: "{{ gitea_runner_service_user }}"
|
||||
group: "{{ gitea_runner_service_user }}"
|
||||
when: docker_rootless_setup
|
||||
|
||||
- name: Configure rootless Docker to disable IPv6
|
||||
ansible.builtin.copy:
|
||||
dest: "{{ gitea_runner_home }}/.config/docker/daemon.json"
|
||||
content: |
|
||||
{
|
||||
"ipv6": false
|
||||
}
|
||||
mode: "0644"
|
||||
owner: "{{ gitea_runner_service_user }}"
|
||||
group: "{{ gitea_runner_service_user }}"
|
||||
register: docker_ipv6_config
|
||||
when: docker_rootless_setup
|
||||
|
||||
- name: Restart rootless Docker if config changed
|
||||
ansible.builtin.command: systemctl --user restart docker
|
||||
become: true
|
||||
become_user: "{{ gitea_runner_service_user }}"
|
||||
environment:
|
||||
XDG_RUNTIME_DIR: "/run/user/{{ gitea_runner_uid }}"
|
||||
changed_when: true
|
||||
when:
|
||||
- docker_rootless_setup
|
||||
- docker_ipv6_config is changed
|
||||
|
||||
- name: Wait for rootless Docker daemon to be ready
|
||||
ansible.builtin.command: docker version
|
||||
become: true
|
||||
|
||||
+6
-6
@@ -8,12 +8,12 @@ Each runner runs in an isolated **rootless Docker** environment under a dedicate
|
||||
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/src/branch/master/LICENSE)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/wiki)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/releases)
|
||||
[](https://www.python.org/downloads/)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/wiki)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/releases)
|
||||
[](https://www.python.org/downloads/)
|
||||
|
||||
## Overview
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ main.yml → systemd_check → user_setup → rootless_docker → install_runner
|
||||
- `install_runner.yml` handles: download, config, validate, register, service
|
||||
- `main.yml` handles: prune, integration_test (NOT install_runner — avoids duplicates)
|
||||
- `systemctl --user` tasks must be guarded by `docker_rootless_setup`
|
||||
- Template creation tasks are NOT guarded by `docker_rootless_setup` (they just create files)
|
||||
- Template creation tasks are NOT guarded by `docker_rootless_setup` (they only create files)
|
||||
|
||||
### Ansible task files
|
||||
|
||||
|
||||
@@ -202,7 +202,7 @@ main.yml → systemd_check → user_setup → rootless_docker → install_runner
|
||||
- `install_runner.yml` handles: download, config, validate, register, service
|
||||
- `main.yml` handles: prune, integration_test (NOT install_runner — avoids duplicates)
|
||||
- `systemctl --user` tasks must be guarded by `docker_rootless_setup`
|
||||
- Template creation tasks are NOT guarded by `docker_rootless_setup` (they just create files)
|
||||
- Template creation tasks are NOT guarded by `docker_rootless_setup` (they only create files)
|
||||
- `apt` tasks use `cache_valid_time: 3600` to avoid unnecessary cache updates
|
||||
- `remove-runner.yml` runs `loginctl disable-linger` and removes subuid/subgid entries
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ Key technical decisions for the GRM project, extracted from `CHANGELOG.md` and `
|
||||
|
||||
**Decision:** Classify changed files into user-facing and workflow-only categories using `devx.ci.classify_changes`. Only user-facing changes trigger a release; workflow-only changes (CI, docs, tests, lint config) do not.
|
||||
|
||||
**Rationale:** Not all changes require a new release. CI workflow updates, documentation improvements, and test additions should not produce a new version tag. The classification is config-driven via `[tool.devx.classify]` in `pyproject.toml`. The strategy is safe-by-default: any file NOT in the explicit workflow-only allowlist is treated as user-facing, preventing new file types from accidentally skipping releases. User-facing paths include `src/grm/**` (except `__init__.py`) and `ansible/**`. Workflow-only paths include `.gitea/**`, `docs/**`, `tests/**`, `scripts/**`, and various config files.
|
||||
**Rationale:** Not all changes require a new release. CI workflow updates, documentation improvements, and test additions should not produce a new version tag. The classification is config-driven via `[tool.devx.classify]` in `pyproject.toml`. The strategy is safe-by-default: any file NOT in the explicit workflow-only allowlist is treated as user-facing, preventing new file types from accidentally skipping releases. User-facing paths include `src/grm/**` (except `__init__.py`) and `ansible/**`. Workflow-only paths include `.gitea/**`, `docs/**`, `tests/**`, `scripts/**`, and other config files.
|
||||
|
||||
**Source:** `AGENTS.md` (Smart CI: User-Facing vs Workflow-Only Changes), `pyproject.toml` (`[tool.devx.classify]`)
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ GRM provides the following CLI commands for managing Gitea Actions runners. The
|
||||
| `grm enable` | `<runner_name>` | Enable a runner to start on boot |
|
||||
| `grm disable` | `<runner_name>` | Disable and deregister a runner |
|
||||
| `grm status` | `<runner_name>` | Check the status of a registered runner |
|
||||
| `grm remove` | `<runner_name>` | Remove a runner completely |
|
||||
| `grm remove` | `<runner_name>` | Remove a runner entirely |
|
||||
| `grm list` | — | List all registered runners with live status |
|
||||
| `grm health` | `[runner_name]` | Run health check (Docker, runner service, disk) on one or all runners |
|
||||
| `grm trigger-workflow` | `<workflow_id>` | Trigger a Gitea Actions workflow via the API |
|
||||
@@ -244,7 +244,7 @@ grm status <runner_name> [options]
|
||||
|
||||
## remove
|
||||
|
||||
Remove a registered Gitea Runner completely.
|
||||
Remove a registered Gitea Runner entirely.
|
||||
|
||||
```bash
|
||||
grm remove <runner_name> [options]
|
||||
|
||||
+13
-13
@@ -1,6 +1,6 @@
|
||||
# FAQ
|
||||
|
||||
## How do I obtain the Gitea registration token?
|
||||
## How to obtain the Gitea registration token
|
||||
|
||||
There are three levels of registration tokens, depending on which repositories the runner should serve:
|
||||
|
||||
@@ -10,15 +10,15 @@ 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 is it needed?
|
||||
|
||||
`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.
|
||||
|
||||
To generate one: Settings → Applications → Generate New Token, with the `admin` scope (or at minimum `read:user`, `read:repository`, `read:admin`).
|
||||
|
||||
If you skip it, GRM will still verify the runner correctly — it just won't show the extra API confirmation.
|
||||
If you skip it, GRM will still verify the runner correctly — it won't show the extra API confirmation.
|
||||
|
||||
## How do I skip the sudo password prompt for automation?
|
||||
## How to 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 multiple runners run 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 a 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**.
|
||||
|
||||
@@ -64,7 +64,7 @@ This is a harmless cleanup traceback from Molecule's Docker driver when the test
|
||||
|
||||
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 to 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 to remove a runner entirely
|
||||
|
||||
Use the `grm remove` command:
|
||||
|
||||
@@ -99,13 +99,13 @@ grm remove prod-runner --force
|
||||
## 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.
|
||||
- **`grm remove <name>`** — Removes the runner entirely: 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?
|
||||
|
||||
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 to 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), `pl` (Polish).
|
||||
|
||||
@@ -119,7 +119,7 @@ Or set it in your `.env` file:
|
||||
GRM_LANG=bg
|
||||
```
|
||||
|
||||
## How do I enable debug logging?
|
||||
## How to 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 be used?
|
||||
|
||||
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.
|
||||
|
||||
@@ -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 GRM be installed via pip?
|
||||
|
||||
Yes:
|
||||
|
||||
|
||||
@@ -223,7 +223,7 @@ make update HOST=192.168.1.10 USER=ubuntu VERSION=1.0.8
|
||||
|
||||
## Removing Runners
|
||||
|
||||
To remove a runner completely (deregisters from Gitea, removes user, directories, and service files):
|
||||
To remove a runner entirely (deregisters from Gitea, removes user, directories, and service files):
|
||||
|
||||
```bash
|
||||
grm remove prod-runner --token <registration-token>
|
||||
|
||||
+7
-2
@@ -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.35.1",
|
||||
"devx==0.38.0",
|
||||
]
|
||||
# Lint and type-checking tools (quality job)
|
||||
lint = [
|
||||
@@ -54,7 +54,7 @@ molecule = [
|
||||
dev = [
|
||||
"grm[ci,lint,molecule]",
|
||||
# Reusable CI/CD and dev tools (pre-push hooks, create-task, create-pr)
|
||||
"devx==0.35.1",
|
||||
"devx==0.38.0",
|
||||
# Non-Python dev dependency: checkmake (Makefile linter)
|
||||
# Install via: go install github.com/checkmake/checkmake/cmd/checkmake@latest
|
||||
]
|
||||
@@ -101,6 +101,11 @@ vikunja_project_id = 6
|
||||
repo_owner = "oblachno-oss"
|
||||
repo_name = "grm"
|
||||
|
||||
# grm doesn't have its own CI scripts — it uses devx's CI modules.
|
||||
# Skip CI script checks (doc_coverage would otherwise look for src/ci/).
|
||||
[tool.devx.doc_coverage]
|
||||
ci_scripts_dir = ""
|
||||
|
||||
# Molecule test weights for LPT scheduling.
|
||||
# GRM has a single role (gitea-runner) with 7 scenarios.
|
||||
# Weights are estimates — recalibrate from CI logs after next run.
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
"""Gitea Runner Manager — lean CLI for managing Gitea Actions runners."""
|
||||
|
||||
__version__ = "0.15.0"
|
||||
__version__ = "0.17.1"
|
||||
|
||||
+6
-4
@@ -125,8 +125,8 @@ def cli(ctx: click.Context, become_password_file: str | None, verbose: bool) ->
|
||||
@click.option(
|
||||
"--admin-token",
|
||||
"-a",
|
||||
default=lambda: os.getenv("CI_GITEA_TOKEN"),
|
||||
help=_("Gitea admin API token for integration test (env: CI_GITEA_TOKEN)"),
|
||||
default=lambda: os.getenv("CI_GITEA_API_TOKEN") or os.getenv("CI_GITEA_TOKEN"),
|
||||
help=_("Gitea admin API token for integration test (env: CI_GITEA_API_TOKEN or CI_GITEA_TOKEN)"),
|
||||
)
|
||||
@click.option(
|
||||
"--integration-retries",
|
||||
@@ -528,8 +528,10 @@ def list_runners(ask_become_pass: bool, no_status: bool) -> None:
|
||||
)
|
||||
@click.option(
|
||||
"--token",
|
||||
default=lambda: os.getenv("CI_GITEA_TOKEN"),
|
||||
help=_("Gitea API token (env: CI_GITEA_TOKEN)"),
|
||||
default=lambda: (
|
||||
os.getenv("DEVELOPER_GITEA_API_TOKEN") or os.getenv("CI_GITEA_API_TOKEN") or os.getenv("CI_GITEA_TOKEN")
|
||||
),
|
||||
help=_("Gitea API token (env: DEVELOPER_GITEA_API_TOKEN, CI_GITEA_API_TOKEN, or CI_GITEA_TOKEN)"),
|
||||
)
|
||||
@click.option(
|
||||
"--list",
|
||||
|
||||
+14
-14
@@ -175,13 +175,13 @@
|
||||
"ru": "URL Gitea (env: GITEA_URL)",
|
||||
"zh": "Gitea URL(环境变量: GITEA_URL)"
|
||||
},
|
||||
"Gitea admin API token for integration test (env: CI_GITEA_TOKEN)": {
|
||||
"bg": "Gitea admin API токен за интеграционен тест (env: CI_GITEA_TOKEN)",
|
||||
"de": "Gitea-Admin-API-Token für Integrationstest (env: CI_GITEA_TOKEN)",
|
||||
"en": "Gitea admin API token for integration test (env: CI_GITEA_TOKEN)",
|
||||
"pl": "Token API administratora Gitea do testów integracyjnych (env: CI_GITEA_TOKEN)",
|
||||
"ru": "Токен админ API Gitea для интеграционного теста (env: CI_GITEA_TOKEN)",
|
||||
"zh": "Gitea 管理员 API 令牌,用于集成测试(环境变量: CI_GITEA_TOKEN)"
|
||||
"Gitea admin API token for integration test (env: CI_GITEA_API_TOKEN or CI_GITEA_TOKEN)": {
|
||||
"bg": "Gitea admin API token for integration test (env: CI_GITEA_API_TOKEN or CI_GITEA_TOKEN)",
|
||||
"de": "Gitea admin API token for integration test (env: CI_GITEA_API_TOKEN or CI_GITEA_TOKEN)",
|
||||
"en": "Gitea admin API token for integration test (env: CI_GITEA_API_TOKEN or CI_GITEA_TOKEN)",
|
||||
"pl": "Gitea admin API token for integration test (env: CI_GITEA_API_TOKEN or CI_GITEA_TOKEN)",
|
||||
"ru": "Gitea admin API token for integration test (env: CI_GITEA_API_TOKEN or CI_GITEA_TOKEN)",
|
||||
"zh": "Gitea admin API token for integration test(环境变量: CI_GITEA_API_TOKEN or CI_GITEA_TOKEN)"
|
||||
},
|
||||
"HEALTHY": {
|
||||
"bg": "ЗДРАВ",
|
||||
@@ -703,13 +703,13 @@
|
||||
"ru": "Git ref для запуска workflow (по умолчанию: master)",
|
||||
"zh": "运行工作流的 Git ref(默认:master)"
|
||||
},
|
||||
"Gitea API token (env: CI_GITEA_TOKEN)": {
|
||||
"bg": "Gitea API токен (env: CI_GITEA_TOKEN)",
|
||||
"de": "Gitea API-Token (env: CI_GITEA_TOKEN)",
|
||||
"en": "Gitea API token (env: CI_GITEA_TOKEN)",
|
||||
"pl": "Token API Gitea (env: CI_GITEA_TOKEN)",
|
||||
"ru": "Токен API Gitea (env: CI_GITEA_TOKEN)",
|
||||
"zh": "Gitea API 令牌(环境变量:CI_GITEA_TOKEN)"
|
||||
"Gitea API token (env: DEVELOPER_GITEA_API_TOKEN, CI_GITEA_API_TOKEN, or CI_GITEA_TOKEN)": {
|
||||
"bg": "Gitea API token (env: DEVELOPER_GITEA_API_TOKEN, CI_GITEA_API_TOKEN, or CI_GITEA_TOKEN)",
|
||||
"de": "Gitea API token (env: DEVELOPER_GITEA_API_TOKEN, CI_GITEA_API_TOKEN, or CI_GITEA_TOKEN)",
|
||||
"en": "Gitea API token (env: DEVELOPER_GITEA_API_TOKEN, CI_GITEA_API_TOKEN, or CI_GITEA_TOKEN)",
|
||||
"pl": "Gitea API token (env: DEVELOPER_GITEA_API_TOKEN, CI_GITEA_API_TOKEN, or CI_GITEA_TOKEN)",
|
||||
"ru": "Gitea API token (env: DEVELOPER_GITEA_API_TOKEN, CI_GITEA_API_TOKEN, or CI_GITEA_TOKEN)",
|
||||
"zh": "Gitea API token(环境变量:DEVELOPER_GITEA_API_TOKEN, CI_GITEA_API_TOKEN, or CI_GITEA_TOKEN)"
|
||||
},
|
||||
"List available workflows instead of triggering one": {
|
||||
"bg": "Списък на наличните работни процеси вместо изпълнение",
|
||||
|
||||
@@ -9,7 +9,12 @@ from click.testing import CliRunner
|
||||
from grm import __version__
|
||||
from grm.cli import cli
|
||||
|
||||
_TEST_ENV = {"GITEA_URL": "https://git.example.com", "CI_GITEA_TOKEN": ""}
|
||||
_TEST_ENV = {
|
||||
"GITEA_URL": "https://git.example.com",
|
||||
"DEVELOPER_GITEA_API_TOKEN": "",
|
||||
"CI_GITEA_API_TOKEN": "",
|
||||
"CI_GITEA_TOKEN": "",
|
||||
}
|
||||
|
||||
|
||||
class TestCLI:
|
||||
|
||||
Reference in New Issue
Block a user