Files
cleveragents-core/tools/controller/master/forgejo_cfg.py
T
drew 0bc734c020 style: ruff format the controller-state-machine branch (288 files)
Applies `ruff format` to the accumulated formatting debt on this branch.
Formatting-only — no behavioral changes. Required for CI/lint's format
gate (`nox -s format -- --check`), which the branch was failing on 288
tracked files that drifted from ruff's canonical style.

In-progress WIP files are intentionally excluded so this commit stays a
clean formatting-only diff.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 00:09:17 -04:00

94 lines
3.2 KiB
Python

"""Controller-owned ForgejoConfig dataclass.
Phase 1k+ refinement (item 16): previously ``__main__.py`` reached up
into ``tools/_mcp_common.ForgejoCfg`` via sys.path injection and
mutated ``cfg.owner`` / ``cfg.repo`` after construction. That:
- inverts the dependency direction (the controller is supposed to be
the new system; it shouldn't reach into sibling pipeline modules);
- mutates a frozen-ish config object after construction;
- ties controller deployments to whatever the legacy ForgejoCfg
schema happens to be.
This module ships a ``ControllerForgejoConfig`` dataclass owning
exactly the fields ``tools/_claim_runtime`` reads from a cfg:
``token``, ``request_timeout_s``, ``api_retries``,
``claim_ttl_seconds``. Plus the controller's own ``owner`` / ``repo``.
URL handling lives in ``_claim_runtime`` itself (reads
``FORGEJO_API_BASE`` env at request time), so it stays out of this
config.
"""
from __future__ import annotations
import os
from dataclasses import dataclass
@dataclass
class ControllerForgejoConfig:
"""Configuration the controller passes to the ``_claim_runtime``
HTTP helpers (which read .token / .request_timeout_s / .api_retries
/ .claim_ttl_seconds) and to the Forgejo callback factory (which
reads .owner / .repo)."""
owner: str
repo: str
token: str
request_timeout_s: int = 30
api_retries: int = 3
claim_ttl_seconds: int = 600
def _env_int(name: str, default: int) -> int:
"""Read an int from env; empty/whitespace value falls back to
``default`` (so an operator who unsets-via-blank doesn't crash
master startup with a non-actionable ``int('')`` ValueError).
A non-numeric value still raises — that's an operator
misconfiguration worth surfacing loudly."""
raw = os.environ.get(name, "")
if not raw.strip():
return default
try:
return int(raw)
except ValueError as exc:
raise ValueError(
f"env {name}={raw!r} is not a valid integer; expected an int"
) from exc
def from_environment(owner: str, repo: str) -> ControllerForgejoConfig:
"""Build a ControllerForgejoConfig from env vars + the
deployment-specified owner/repo. Mirrors the env-driven
construction the legacy ForgejoCfg used (FORGEJO_TOKEN +
standard CONTROLLER_FORGEJO_* tunables) so operators don't have
to relearn anything.
Empty/whitespace env values for the tunables fall back to the
documented defaults rather than crashing startup with
``int('')`` ValueError — operators who clear a var
(e.g., ``unset CONTROLLER_FORGEJO_REQUEST_TIMEOUT_S`` after
sourcing /etc/cleveragents/master.env) get the default behaviour
silently.
"""
token = (
os.environ.get("FORGEJO_TOKEN")
or os.environ.get("CONTROLLER_FORGEJO_TOKEN")
or ""
)
return ControllerForgejoConfig(
owner=owner,
repo=repo,
token=token,
request_timeout_s=_env_int(
"CONTROLLER_FORGEJO_REQUEST_TIMEOUT_S",
30,
),
api_retries=_env_int("CONTROLLER_FORGEJO_API_RETRIES", 3),
claim_ttl_seconds=_env_int("CONTROLLER_FORGEJO_CLAIM_TTL_S", 600),
)
__all__ = ["ControllerForgejoConfig", "from_environment"]