Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a0b03f01ef | ||
|
|
3f5808d6be | ||
|
|
60c94b2b93 | ||
|
|
2ca56ed317 |
@@ -94,6 +94,33 @@ jobs:
|
||||
echo "No user-facing files changed — skipping release dry-run."
|
||||
fi
|
||||
|
||||
validate-merge:
|
||||
if: github.event_name == 'push'
|
||||
runs-on: docker
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 2
|
||||
- name: Validate commit message format
|
||||
run: |
|
||||
set -euo pipefail
|
||||
MSG=$(git log -1 --pretty=%s)
|
||||
echo "Commit message: $MSG"
|
||||
# Allowed formats:
|
||||
# GRM-N <type>: <description> (squash-merge)
|
||||
# release: vX.Y.Z (release commits)
|
||||
# GRM-N <type>: <description> (#M) (squash-merge with PR ref)
|
||||
if echo "$MSG" | grep -qE '^GRM-[0-9]+ [a-z]+: .+'; then
|
||||
echo "OK: GRM-N <conventional> format"
|
||||
elif echo "$MSG" | grep -qE '^release: v[0-9]+\.[0-9]+\.[0-9]+'; then
|
||||
echo "OK: release commit format"
|
||||
else
|
||||
echo "FAIL: commit message does not follow naming convention"
|
||||
echo "Expected: GRM-N <type>: <description> or release: vX.Y.Z"
|
||||
echo "Got: $MSG"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
discover-runners:
|
||||
needs: [detect-changes]
|
||||
if: needs.detect-changes.outputs.ansible-changed == 'true'
|
||||
|
||||
@@ -103,13 +103,19 @@ REPO_TOKEN=<token> python3 scripts/ci/review_pr.py <pr_number> <owner/repo> \
|
||||
```
|
||||
|
||||
Then add the `ready-to-merge` label. The auto-merge workflow will:
|
||||
1. **Validate** PR title format and match against Vikunja task title
|
||||
1. **Validate** PR title format (`GRM-N: <vikunja task title>`) and match against Vikunja task title
|
||||
2. **Check** that at least one APPROVE review exists
|
||||
3. Wait for all CI checks to pass
|
||||
4. Squash-merge with title: `GRM-N <conventional commit message>` (space-separated)
|
||||
4. Squash-merge with title: `GRM-N <conventional commit message>` (space-separated, no colon after GRM-N)
|
||||
5. The post-merge workflow marks the Vikunja task as done
|
||||
6. The release workflow automatically versions, tags, and publishes (see below)
|
||||
|
||||
> **IMPORTANT**: Never manually merge PRs via the API. Always use the auto-merge
|
||||
> workflow by adding the `ready-to-merge` label. Manual merges bypass the
|
||||
> `GRM-N <conventional>` format enforcement, producing incorrectly named commits.
|
||||
> The CI `validate-merge` job checks every push to master and will fail if a
|
||||
> commit message doesn't match `GRM-N <type>: <description>` or `release: vX.Y.Z`.
|
||||
|
||||
### CI Path Filtering
|
||||
|
||||
The CI workflow includes a `detect-changes` job that checks whether any files
|
||||
|
||||
+118
-107
@@ -2,147 +2,158 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [0.4.0] - 2026-06-21
|
||||
## [0.5.0] - 2026-06-21
|
||||
|
||||
### Features
|
||||
|
||||
- Add mandatory PR review step to workflow
|
||||
- Add automated semver versioning, tagging, and releases with git-cliff
|
||||
- Fix 12 critical workflow gaps in release pipeline
|
||||
- Implement documentation-as-code with wiki sync and doc-coverage
|
||||
- Smart CI and release skipping for workflow-only changes
|
||||
- Enforce commit naming conventions and workflow discipline
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Move release commit skip check into release.py
|
||||
- Install git-cliff to user-writable dir and fix archlinux idempotence
|
||||
- Use mktemp for git-cliff extraction to avoid file conflicts
|
||||
- Use full path for git-cliff version check in install step
|
||||
- Handle same-version update in release.py
|
||||
- Skip commit when version file unchanged in release.py
|
||||
- Release push permission and notify_failure label IDs
|
||||
- Strip git-cliff header from CHANGELOG.md updates
|
||||
- Enforce tests pass before tagging a release
|
||||
- Bypass commit-msg hook for release commits
|
||||
- Use correct Gitea 1.26 wiki API endpoints
|
||||
- Set PYTHONPATH=. for release.py to find scripts.ci module (#32)
|
||||
- Use content_base64 for Gitea wiki API, add --verify flag (#33)
|
||||
- Wiki links, add --strict integrity check for wiki sync (#34)
|
||||
|
||||
### Other
|
||||
|
||||
- V0.3.2
|
||||
- Clean up infrastructure-only releases and fix release classification
|
||||
- Rewrite changelog and re-tag releases at user-facing milestones
|
||||
|
||||
### Refactor
|
||||
|
||||
- Split CI scripts, fix release PYTHONPATH, dynamic runner discovery
|
||||
|
||||
## [0.3.2] - 2026-06-21
|
||||
## [0.4.0] - 2026-06-21
|
||||
|
||||
### Bug Fixes
|
||||
### Rootless Docker Support
|
||||
|
||||
- Set PYTHONPATH=. for release.py to find scripts.ci module (#32)
|
||||
- Full rootless Docker installation and configuration via Ansible
|
||||
- `docker_rootless_setup` variable controls whether rootless Docker tasks run
|
||||
- User setup tasks (subuid/subgid, lingering, dockerd-rootless)
|
||||
- Proper gating of all Docker-dependent and `systemctl --user` tasks
|
||||
|
||||
### Other
|
||||
### Runner Labels
|
||||
|
||||
- Smart CI and release skipping for workflow-only changes
|
||||
- Split CI scripts, fix release PYTHONPATH, dynamic runner discovery
|
||||
- `--labels` option on `grm install` — specify runner labels (e.g., `--labels "ubuntu-latest:docker://node:20"`)
|
||||
- Labels passed through to runner config YAML
|
||||
|
||||
## [0.3.1] - 2026-06-21
|
||||
### Security Fix (CWE-214)
|
||||
|
||||
### Bug Fixes
|
||||
- **Critical**: Registration tokens and admin tokens are no longer passed via `--extra-vars` on the command line
|
||||
- Extra-vars are now written to a temporary JSON file with `0600` permissions and passed via `--extra-vars @tempfile`
|
||||
- This prevents secrets from being visible in the process list (`ps aux`)
|
||||
|
||||
- Use correct Gitea 1.26 wiki API endpoints
|
||||
### Configuration via Environment Variables
|
||||
|
||||
- API URLs and repo configuration in `config.py` are now overridable via environment variables:
|
||||
- `GRM_GITEA_API_URL`
|
||||
- `GRM_VIKUNJA_API_URL`
|
||||
- `GRM_REPO_OWNER`
|
||||
- `GRM_REPO_NAME`
|
||||
- `GRM_VIKUNJA_PROJECT_ID`
|
||||
|
||||
### Ansible Role Improvements
|
||||
|
||||
- Dead code cleanup (removed `config.yml`, legacy system-level service, duplicate task includes)
|
||||
- `remove-runner.yml` now disables lingering and removes subuid/subgid entries for complete cleanup
|
||||
- Arch Linux: `gnupg` package name fix, pacman cache handling
|
||||
- Docker APT repository: deb822 format, proper GPG handling, arch mapping
|
||||
- Idempotence fixes for user_setup and download tasks
|
||||
|
||||
## [0.3.0] - 2026-06-21
|
||||
|
||||
### Features
|
||||
### New CLI Options
|
||||
|
||||
- Implement documentation-as-code with wiki sync and doc-coverage
|
||||
- `--force` flag on `grm remove` — remove a runner even when the host is unreachable (skips Ansible playbook, only deregisters via API)
|
||||
- `--url` option — override the Gitea URL for any command (useful for multiple Gitea instances)
|
||||
- `--ask-become-pass` is now the default behavior (no need to pass it explicitly)
|
||||
|
||||
## [0.2.2] - 2026-06-21
|
||||
### Status Detection Fixes
|
||||
|
||||
### Bug Fixes
|
||||
- `grm list` now correctly retrieves runner status (was showing "unknown" for active runners)
|
||||
- Docker mode status detection via `docker inspect`
|
||||
- Host/user context added to status output
|
||||
|
||||
- Enforce tests pass before tagging a release
|
||||
- Bypass commit-msg hook for release commits
|
||||
### Output Improvements
|
||||
|
||||
## [0.2.1] - 2026-06-21
|
||||
- Colorized output for better visual feedback (green/red/yellow)
|
||||
- Translated operation reports for success and failure cases
|
||||
- Dual logging: `click.echo()` for user-facing messages, `logging` for debug
|
||||
- `GRM_LOG_LEVEL` environment variable for controlling verbosity
|
||||
- Full i18n support (all user-facing strings translated)
|
||||
|
||||
### Bug Fixes
|
||||
### Internal Refactoring
|
||||
|
||||
- Strip git-cliff header from CHANGELOG.md updates
|
||||
- Validation moved from CLI layer to business layer
|
||||
- Centralized API clients and HTTP status codes
|
||||
- User-friendly Click errors with i18n
|
||||
|
||||
## [0.2.0] - 2026-06-21
|
||||
|
||||
### New CLI Commands
|
||||
|
||||
- `grm start <host>` — start a runner's systemd service
|
||||
- `grm stop <host>` — stop a runner's systemd service
|
||||
- `grm enable <host>` — enable a runner to start on boot
|
||||
- `grm disable <host>` — disable a runner from starting on boot
|
||||
- `grm status <host>` — check runner service status
|
||||
- `grm remove <host>` — deregister and remove a runner
|
||||
- `grm list-runners` — list all runners from the local registry
|
||||
|
||||
### Runner Registry
|
||||
|
||||
- Runners are tracked in `~/.config/grm/runners.toml` for simplified CLI usage
|
||||
- No need to specify `--url`, `--user`, `--key` for every command — the registry remembers
|
||||
|
||||
### Multi-Instance Support
|
||||
|
||||
- systemd template units (`gitea-runner@.service`) for running multiple runners per host
|
||||
- Per-instance config and data directories
|
||||
|
||||
### Ansible Role Improvements
|
||||
|
||||
- Parameterized all hardcoded configuration values as Ansible variables
|
||||
- Idempotence fixes for repeated runs
|
||||
- Runner config converted from TOML to YAML format
|
||||
- Registration timeout to prevent indefinite hangs
|
||||
- Docker container entrypoint override and working directory fix for `.runner` persistence
|
||||
|
||||
## [0.1.0] - 2026-06-21
|
||||
|
||||
### Initial Release
|
||||
|
||||
The first release of GRM, a lean CLI for managing Gitea Actions runners via SSH.
|
||||
|
||||
### CLI Commands
|
||||
|
||||
- `grm install <host>` — install and register a Gitea Runner on a remote host via SSH
|
||||
- `grm token` — generate a registration token via the Gitea API
|
||||
- `grm list` — list all registered runners
|
||||
- `grm update <host>` — update a runner to the latest version
|
||||
|
||||
### Ansible Role
|
||||
|
||||
- Installs Gitea Runner binary in binary or Docker mode
|
||||
- Registers runner with Gitea instance
|
||||
- Configures systemd service
|
||||
- Supports Arch Linux, Ubuntu, and Debian
|
||||
|
||||
### Features
|
||||
|
||||
- Fix 12 critical workflow gaps in release pipeline
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Release push permission and notify_failure label IDs
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- **Automated semver versioning and releases**: `scripts/release.py` — CI script that uses git-cliff to calculate the next version from conventional commits, update version files, create a release commit, tag, and push.
|
||||
- `cliff.toml` — git-cliff configuration for conventional commit parsing, semver bumping, and changelog generation.
|
||||
- Release workflow (`.gitea/workflows/release.yml`) — triggers on push to master, runs `scripts/release.py` to automatically version and tag releases.
|
||||
- `publish.py` now uses git-cliff to generate release notes for Gitea releases (falls back to generic message if git-cliff is not available).
|
||||
- `pyproject.toml` now uses `dynamic = ["version"]` with setuptools `attr` to source version from `__init__.py` (single source of truth — release script only updates `__init__.py`).
|
||||
- **Mandatory PR review step**: `scripts/review_pr.py` — CLI to post Gitea PR reviews (COMMENT, APPROVE, REQUEST_CHANGES) with inline comments via `--comments-json` or `--comments-stdin`.
|
||||
- `GiteaClient.get_pr_files`, `GiteaClient.get_pr_commits`, `GiteaClient.create_review` — API methods for PR review workflow.
|
||||
- `VikunjaClient.get_task` — fetch a single task by numeric ID.
|
||||
- PR title format: `GRM-N: <vikunja task title>` (colon-separated, human-friendly).
|
||||
- Merge commit format: `GRM-N <conventional commit message>` (space-separated, conventional).
|
||||
- `auto_merge.py` now extracts the conventional commit message from PR commits and constructs the merge title as `GRM-N <conventional commit>`.
|
||||
- `post_merge.py` `extract_conventional_msg` now handles both legacy (`GRM-N: <msg>`) and current (`GRM-N <msg>`) merge commit formats.
|
||||
- Full PR workflow documented in `AGENTS.md` and `README.md` (Vikunja task → branch → implement → commit → PR → review → address comments → approve → merge).
|
||||
|
||||
### Changed
|
||||
|
||||
- Parameterized all hardcoded configuration values as Ansible variables in `defaults/main.yml`:
|
||||
- `gitea_runner_data_dir` — Runtime data directory
|
||||
- `gitea_runner_config_dir` — Config directory
|
||||
- `gitea_runner_binary_path` — Binary install path
|
||||
- `gitea_runner_prune_until` — Prune age filter
|
||||
- `gitea_runner_prune_schedule` — Prune timer schedule
|
||||
- `gitea_runner_prune_label` — Docker label for pruning
|
||||
- `gitea_runner_service_restart_sec` — systemd restart interval
|
||||
- `gitea_runner_service_user` — Service user
|
||||
- `gitea_runner_log_level` — Runner log level
|
||||
- `gitea_runner_container_label` — Container label
|
||||
- `gitea_runner_file` — Runner metadata file
|
||||
- `docker_gpg_key_path` — Docker GPG key path
|
||||
- Added `console_scripts` entry point in `pyproject.toml` (`grm = "gitea_runner_manager.cli:cli"`).
|
||||
- Added shared `molecule/common/prepare.yml` to eliminate duplicated prepare playbooks.
|
||||
- Extracted repeated systemd availability check into `tasks/systemd_check.yml`.
|
||||
- Added idempotence checks to all Molecule scenarios.
|
||||
- Comprehensive README overhaul with Architecture, Configuration, Development, Testing, and Troubleshooting sections.
|
||||
- API URLs and repo configuration in `config.py` are now overridable via environment variables (`GRM_GITEA_API_URL`, `GRM_VIKUNJA_API_URL`, `GRM_REPO_OWNER`, `GRM_REPO_NAME`, `GRM_VIKUNJA_PROJECT_ID`).
|
||||
- `remove-runner.yml` now disables lingering and removes subuid/subgid entries for complete cleanup.
|
||||
|
||||
### Security
|
||||
|
||||
- **Critical fix**: Registration tokens and admin tokens are no longer passed via `--extra-vars` on the command line (CWE-214). Extra-vars are now written to a temporary JSON file with `0600` permissions and passed via `--extra-vars @tempfile`, which is deleted after execution. This prevents secrets from being visible in the process list (`ps aux`).
|
||||
|
||||
### Changed
|
||||
|
||||
- Replaced legacy runner terminology with `gitea_runner` / `gitea-runner` / `Gitea Runner`.
|
||||
- Updated default Docker image from `gitea/gitea_runner` to `gitea/runner`.
|
||||
- `Makefile` now uses the installed `grm` console script instead of `python grm`.
|
||||
- `pyproject.toml` ruff and pyright target versions updated from `py311` to `py312` to match `requires-python = ">=3.12"`.
|
||||
- `BRANCH_PROTECTION_CONFIG` updated with correct Gitea Actions status check contexts (including `(pull_request)` suffix) and `required_approvals: 0` for auto-merge.
|
||||
- `CONVENTIONAL_RE` no longer matches `BREAKING CHANGE` as a commit type (it is a footer, not a type).
|
||||
- `rootless_docker.yml` apt cache update now only runs when the Docker repo file changes (idempotent, but always refreshes on first add).
|
||||
- `service.yml` and `prune.yml` template creation tasks are not guarded by `docker_rootless_setup` (templates just create files, they don't need Docker; molecule tests set `docker_rootless_setup: false` but still verify the service file exists).
|
||||
- `molecule_all.sh` now sources the platform list from `distribute_molecule.py` to avoid duplication.
|
||||
|
||||
### Removed
|
||||
|
||||
- Deleted `setup.py` (redundant with `pyproject.toml`).
|
||||
- Deleted `grm` shell entrypoint script (replaced by `console_scripts`).
|
||||
- Deleted `initial-plan.md` and `tests/integration/test_provision.py` (dead code).
|
||||
- Removed empty `__init__.py` files from `tests/` directories.
|
||||
- Removed unused `runner_validated` fact from `validate.yml`.
|
||||
- Removed duplicate `prune.yml` and `integration_test.yml` includes from `install_runner.yml` (already included from `main.yml`).
|
||||
- Removed dead `tasks/config.yml` (never included by any playbook).
|
||||
- Removed dead `templates/gitea-runner.service.j2` (legacy system-level service, replaced by rootless `gitea-runner-user.service.j2`).
|
||||
- Removed dead "Reload systemd" handler (system-level reload, never notified, wrong scope for user services).
|
||||
- Removed dead `scripts/run_molecule_parallel.py` and its test (replaced by `molecule_ci_guard.py`).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Molecule idempotence failures caused by non-idempotent service restart.
|
||||
- Missing `/etc/docker` directory handling in Molecule tests.
|
||||
- `ansible-lint` formatting warnings (yaml empty lines).
|
||||
- Verify playbooks now explicitly load role defaults so parameterized variables are available during verification.
|
||||
- Duplicate execution of prune and integration test tasks during installation (were included from both `main.yml` and `install_runner.yml`).
|
||||
- apt cache update reporting `changed` on every run due to `cache_valid_time: 0`.
|
||||
- SSH-based remote execution via Ansible
|
||||
- Automatic registration token generation
|
||||
- Docker and binary installation modes
|
||||
- Integration test verification after installation
|
||||
|
||||
+10
-9
@@ -46,19 +46,20 @@ commit_preprocessors = [
|
||||
commit_parsers = [
|
||||
{ message = "^feat", group = "<!-- 0 -->Features" },
|
||||
{ message = "^fix", group = "<!-- 1 -->Bug Fixes" },
|
||||
{ message = "^doc", group = "<!-- 3 -->Documentation" },
|
||||
{ message = "^perf", group = "<!-- 4 -->Performance" },
|
||||
{ message = "^refactor", group = "<!-- 2 -->Refactor" },
|
||||
{ message = "^style", group = "<!-- 5 -->Styling" },
|
||||
{ message = "^test", group = "<!-- 6 -->Testing" },
|
||||
{ message = "^chore\\(release\\): prepare for", skip = true },
|
||||
{ message = "^chore\\(deps.*\\)", skip = true },
|
||||
{ message = "^chore\\(pr\\)", skip = true },
|
||||
{ message = "^chore\\(pull\\)", skip = true },
|
||||
{ message = "^chore|^ci", group = "<!-- 7 -->Miscellaneous Tasks" },
|
||||
# Skip infrastructure-only commits — they don't affect users
|
||||
{ message = "^doc", skip = true },
|
||||
{ message = "^test", skip = true },
|
||||
{ message = "^style", skip = true },
|
||||
{ message = "^chore", skip = true },
|
||||
{ message = "^ci", skip = true },
|
||||
# Skip release commits — they are release artifacts, not features
|
||||
{ message = "^release:", skip = true },
|
||||
{ body = ".*security", group = "<!-- 8 -->Security" },
|
||||
{ message = "^revert", group = "<!-- 9 -->Revert" },
|
||||
{ message = ".*", group = "<!-- 10 -->Other" },
|
||||
# Skip anything that doesn't match above — safe default
|
||||
{ message = ".*", skip = true },
|
||||
]
|
||||
|
||||
[bump]
|
||||
|
||||
+2
-2
@@ -50,7 +50,7 @@ gitea_runner_manager = ["translations.json"]
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests"]
|
||||
pythonpath = ["src", "."]
|
||||
addopts = "--cov=src/gitea_runner_manager --cov=scripts --cov=scripts/ci --cov-report=term-missing --cov-fail-under=100"
|
||||
addopts = "--cov=src/gitea_runner_manager --cov=scripts --cov-report=term-missing --cov-fail-under=100"
|
||||
markers = [
|
||||
"integration: marks tests as integration tests (not counted in coverage)",
|
||||
]
|
||||
@@ -68,6 +68,6 @@ quote-style = "double"
|
||||
indent-style = "space"
|
||||
|
||||
[tool.pyright]
|
||||
include = ["src", "scripts", "scripts/ci"]
|
||||
include = ["src", "scripts"]
|
||||
pythonVersion = "3.12"
|
||||
strict = ["src/gitea_runner_manager"]
|
||||
|
||||
@@ -17,9 +17,8 @@ Classification strategy (safe-by-default):
|
||||
|
||||
Workflow-only paths (infrastructure → no release needed):
|
||||
- .gitea/workflows/** — Gitea Actions workflows
|
||||
- scripts/ci/** — CI/CD automation scripts
|
||||
- scripts/*.sh — Shell scripts (setup, molecule runners)
|
||||
- scripts/__init__.py — Package init for scripts
|
||||
- scripts/** — All scripts (CI/CD, dev tools, setup)
|
||||
- src/gitea_runner_manager/__init__.py — Version file (release artifact)
|
||||
- docs/** — Documentation
|
||||
- tests/** — Test files
|
||||
- hooks/** — Git hooks
|
||||
@@ -38,7 +37,7 @@ Classification strategy (safe-by-default):
|
||||
|
||||
Everything else is user-facing (tool changes → release needed),
|
||||
including but not limited to:
|
||||
- src/gitea_runner_manager/** — Python CLI source
|
||||
- src/gitea_runner_manager/*.py — Python CLI source (except __init__.py)
|
||||
- ansible/** — Ansible role
|
||||
- pyproject.toml — Package metadata
|
||||
- Any new file type not in the allowlist
|
||||
@@ -63,10 +62,12 @@ WORKFLOW_ONLY_PATTERNS = frozenset(
|
||||
[
|
||||
# CI/CD infrastructure
|
||||
".gitea/",
|
||||
"scripts/ci/",
|
||||
"scripts/setup.sh",
|
||||
"scripts/molecule_all.sh",
|
||||
"scripts/__init__.py",
|
||||
# All scripts are infrastructure (CI/CD, dev tools, setup)
|
||||
# User-facing code lives in src/gitea_runner_manager/
|
||||
"scripts/",
|
||||
# Version file — only contains __version__, not user-facing code.
|
||||
# Version bumps are a release artifact, not a feature.
|
||||
"src/gitea_runner_manager/__init__.py",
|
||||
# Documentation
|
||||
"docs/",
|
||||
"AGENTS.md",
|
||||
|
||||
@@ -78,8 +78,19 @@ def main(commit_msg: str, commit_sha: str) -> None:
|
||||
|
||||
task_id = extract_task_id(commit_msg)
|
||||
if not task_id:
|
||||
click.echo(_("No task ID in commit message, skipping Vikunja update. All good — nothing to do here!"))
|
||||
return
|
||||
# Allow release commits without GRM-N prefix
|
||||
first_line = commit_msg.split("\n")[0]
|
||||
if re.match(r"^release: v\d+\.\d+\.\d+", first_line):
|
||||
click.echo(_("Release commit without task ID, skipping Vikunja update."))
|
||||
return
|
||||
# Non-release commits must have GRM-N prefix — fail loudly
|
||||
raise click.ClickException(
|
||||
_(
|
||||
"No task ID (GRM-N) found in commit message: {msg}\n"
|
||||
"All non-release commits on master must follow format: GRM-N <type>: <description>",
|
||||
msg=first_line,
|
||||
)
|
||||
)
|
||||
|
||||
client = VikunjaClient(VIKUNJA_API_URL, token)
|
||||
vikunja_task_id = 0
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
"""Gitea Runner Manager — lean CLI for managing Gitea Actions runners."""
|
||||
|
||||
__version__ = "0.4.0"
|
||||
__version__ = "0.5.0"
|
||||
|
||||
@@ -34,12 +34,12 @@ class TestIsUserFacing:
|
||||
def test_ci_scripts_are_not_user_facing(self) -> None:
|
||||
assert is_user_facing("scripts/ci/release.py") is False
|
||||
|
||||
def test_dev_scripts_are_user_facing(self) -> None:
|
||||
"""Dev scripts (check_test_speed, configure_repo) are NOT in the
|
||||
workflow-only allowlist, so they default to user-facing."""
|
||||
assert is_user_facing("scripts/check_test_speed.py") is True
|
||||
assert is_user_facing("scripts/configure_repo.py") is True
|
||||
assert is_user_facing("scripts/install_checkmake.py") is True
|
||||
def test_dev_scripts_are_not_user_facing(self) -> None:
|
||||
"""All scripts under scripts/ are infrastructure (CI/CD, dev tools).
|
||||
User-facing code lives in src/gitea_runner_manager/."""
|
||||
assert is_user_facing("scripts/check_test_speed.py") is False
|
||||
assert is_user_facing("scripts/configure_repo.py") is False
|
||||
assert is_user_facing("scripts/install_checkmake.py") is False
|
||||
|
||||
def test_shell_scripts_are_not_user_facing(self) -> None:
|
||||
assert is_user_facing("scripts/setup.sh") is False
|
||||
@@ -48,6 +48,11 @@ class TestIsUserFacing:
|
||||
def test_scripts_init_is_not_user_facing(self) -> None:
|
||||
assert is_user_facing("scripts/__init__.py") is False
|
||||
|
||||
def test_version_file_is_not_user_facing(self) -> None:
|
||||
"""__init__.py only contains __version__ — a release artifact,
|
||||
not user-facing code. Version bumps alone should not trigger releases."""
|
||||
assert is_user_facing("src/gitea_runner_manager/__init__.py") is False
|
||||
|
||||
def test_docs_are_not_user_facing(self) -> None:
|
||||
assert is_user_facing("docs/user/getting-started.md") is False
|
||||
|
||||
|
||||
@@ -130,10 +130,20 @@ class TestMain:
|
||||
assert "VIKUNJA_TOKEN" in result.output
|
||||
|
||||
@patch.dict("os.environ", {"VIKUNJA_TOKEN": "tok"})
|
||||
def test_no_task_id_skips(self) -> None:
|
||||
def test_no_task_id_non_release_fails(self) -> None:
|
||||
"""Non-release commits without GRM-N prefix should fail."""
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ["fix: resolve bug"])
|
||||
assert result.exit_code == 1
|
||||
assert "No task ID" in result.output
|
||||
|
||||
@patch.dict("os.environ", {"VIKUNJA_TOKEN": "tok"})
|
||||
def test_release_commit_without_task_id_skips(self) -> None:
|
||||
"""Release commits without GRM-N prefix should skip gracefully."""
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ["release: v0.3.2"])
|
||||
assert result.exit_code == 0
|
||||
assert "Release commit" in result.output
|
||||
assert "skipping" in result.output
|
||||
|
||||
@patch.dict("os.environ", {"VIKUNJA_TOKEN": "tok"})
|
||||
|
||||
Reference in New Issue
Block a user