Files
grm/src/gitea_runner_manager/registry.py
T
Emil SimeonovandDevin <158243242+devin-ai-integration[bot]@users.noreply.github.com> 55c2746569
CI / quality (pull_request) Failing after 1m4s
CI / molecule-tests (0) (pull_request) Has been skipped
CI / molecule-tests (1) (pull_request) Has been skipped
CI / molecule-tests (2) (pull_request) Has been skipped
refactor: rootless Docker, fix auto-merge, molecule platform matrix
Three major improvements:

1. Rootless Docker refactor: Removes docker/binary modes, unifies to
   rootless Docker with per-runner system users. Each runner gets its
   own rootless Docker daemon, systemd user service, and isolated
   environment. Simplifies CLI (removes --mode option), Ansible role
   (single code path), and molecule scenarios (removes binary scenario).

2. Auto-merge fix: Fixes status check context mismatch in branch
   protection (was requiring "lint", "unit-tests", "molecule-tests" but
   actual contexts are "CI / quality", "CI / molecule-tests*"). Adds
   retry/wait logic to auto_merge.py that polls commit statuses for up
   to 15 minutes before attempting merge, eliminating the chicken-and-egg
   problem where auto-merge would fail because CI hadn't completed yet.

3. Molecule platform matrix: Adds OS platform matrix to CI — all 6
   scenarios now run on all 4 supported OSes (ubuntu-2204, ubuntu-2404,
   debian-12, archlinux) = 24 test pairs distributed across 3 parallel
   runners. Updates distribute_molecule.py to distribute (scenario,
   platform) pairs. Updates Makefile with molecule-all target for
   local multi-platform testing.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-06-20 21:02:52 +02:00

84 lines
2.6 KiB
Python

"""Local JSON registry for installed Gitea Runners.
Stores connection metadata (host, user, key, labels) on the local machine
so that subsequent lifecycle commands only need the runner name.
"""
from __future__ import annotations
import json
from datetime import UTC, datetime
from pathlib import Path
from typing import Any, cast
from .exceptions import GRMError
from .i18n import _
class RunnerRegistry:
"""Manages a local JSON file mapping runner names to connection metadata."""
def __init__(self, path: Path | None = None) -> None:
self._path = path or Path.home() / ".local" / "share" / "grm" / "runners.json"
self._data: dict[str, dict[str, Any]] = self._load()
def _load(self) -> dict[str, dict[str, Any]]:
if self._path.exists():
try:
with open(self._path) as f:
data: Any = json.load(f)
if isinstance(data, dict):
return cast(dict[str, dict[str, Any]], data)
except (json.JSONDecodeError, OSError):
pass
return {}
def _save(self) -> None:
self._path.parent.mkdir(parents=True, exist_ok=True)
with open(self._path, "w") as f:
json.dump(self._data, f, indent=2)
def add(
self,
name: str,
host: str,
user: str,
key: str | None = None,
gitea_url: str = "",
labels: str | None = None,
) -> None:
"""Register a runner in the local database."""
self._data[name] = {
"host": host,
"user": user,
"key": key,
"gitea_url": gitea_url,
"labels": labels,
"created_at": datetime.now(UTC).isoformat(),
}
self._save()
def get(self, name: str) -> dict[str, Any] | None:
"""Retrieve runner metadata by name."""
info = self._data.get(name)
if info:
return dict(info)
return None
def remove(self, name: str) -> None:
"""Remove a runner from the local database."""
if name in self._data:
del self._data[name]
self._save()
def list(self) -> dict[str, dict[str, Any]]:
"""Return a copy of all registered runners."""
return {name: dict(info) for name, info in self._data.items()}
def update(self, name: str, **kwargs: str | None) -> None:
"""Update fields for an existing runner entry."""
if name not in self._data:
raise GRMError(_("Runner '{name}' not found in registry.", name=name))
self._data[name].update({k: v for k, v in kwargs.items() if v is not None})
self._save()