Public Access
Post-merge / detect-type (push) Successful in 9s
Post-merge / validate-commit-msg (push) Successful in 11s
Post-merge / vikunja (push) Successful in 13s
Post-merge / sync-wiki (push) Successful in 17s
Post-merge / configure-repo (push) Successful in 10s
Post-merge / release (push) Successful in 30s
Build Images / detect-type (push) Successful in 48s
Post-merge / badges (push) Successful in 41s
Post-merge / publish (push) Successful in 16s
Build Images / build-and-push (push) Successful in 4m41s
Build Images / cleanup (push) Successful in 2m23s
97 lines
3.3 KiB
Python
97 lines
3.3 KiB
Python
"""Shared configuration constants for devx scripts and API clients.
|
|
|
|
Configuration is read from two sources, in priority order:
|
|
|
|
1. **Environment variables** (``DEVX_`` prefix) — highest priority, used for
|
|
CI secrets and per-run overrides.
|
|
2. **``[tool.devx]`` section in ``pyproject.toml``** — project defaults,
|
|
read from the current working directory.
|
|
|
|
If neither source provides a value, built-in defaults are used.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import re
|
|
import tomllib
|
|
from pathlib import Path
|
|
|
|
|
|
def _load_pyproject_devx() -> dict[str, object]:
|
|
"""Load the ``[tool.devx]`` section from pyproject.toml in the CWD.
|
|
|
|
Returns an empty dict if the file or section is missing.
|
|
"""
|
|
path = Path("pyproject.toml")
|
|
if not path.exists():
|
|
return {}
|
|
try:
|
|
with open(path, "rb") as f: # noqa: PTH123
|
|
data: dict[str, object] = tomllib.load(f)
|
|
except (tomllib.TOMLDecodeError, OSError):
|
|
return {}
|
|
tool_raw: object = data.get("tool", {})
|
|
if not isinstance(tool_raw, dict):
|
|
return {}
|
|
tool: dict[str, object] = tool_raw # type: ignore[assignment]
|
|
devx_raw: object = tool.get("devx", {})
|
|
if not isinstance(devx_raw, dict):
|
|
return {}
|
|
devx: dict[str, object] = devx_raw # type: ignore[assignment]
|
|
return devx
|
|
|
|
|
|
_PYPROJECT = _load_pyproject_devx()
|
|
|
|
|
|
def _get(key: str, env_var: str, default: str) -> str:
|
|
"""Get a config value: env var > pyproject.toml > default."""
|
|
env_val = os.getenv(env_var)
|
|
if env_val is not None:
|
|
return env_val
|
|
pyproject_val = _PYPROJECT.get(key)
|
|
if isinstance(pyproject_val, str):
|
|
return pyproject_val
|
|
return default
|
|
|
|
|
|
def _get_int(key: str, env_var: str, default: int) -> int:
|
|
"""Get an int config value: env var > pyproject.toml > default."""
|
|
env_val = os.getenv(env_var)
|
|
if env_val is not None:
|
|
return int(env_val)
|
|
pyproject_val = _PYPROJECT.get(key)
|
|
if isinstance(pyproject_val, int):
|
|
return pyproject_val
|
|
return default
|
|
|
|
|
|
# API endpoints — override via env vars for different Gitea/Vikunja instances
|
|
GITEA_API_URL = _get("gitea_api_url", "DEVX_GITEA_API_URL", "https://git.oblachno.oblachno.fyi/api/v1")
|
|
VIKUNJA_API_URL = _get("vikunja_api_url", "DEVX_VIKUNJA_API_URL", "https://work.oblachno.oblachno.fyi/api/v1")
|
|
|
|
# Organization defaults — each project MUST set DEVX_REPO_OWNER explicitly.
|
|
# No default: prevents silent 404s when the wrong owner is used.
|
|
REPO_OWNER = _get("repo_owner", "DEVX_REPO_OWNER", "")
|
|
REPO_NAME = _get("repo_name", "DEVX_REPO_NAME", "")
|
|
|
|
# Task prefix for Vikunja task IDs — each project sets its own (GRM, DEVX, INFRA, etc.)
|
|
TASK_PREFIX = _get("task_prefix", "DEVX_TASK_PREFIX", "DEVX")
|
|
TASK_ID_RE = re.compile(rf"{TASK_PREFIX}-\d+")
|
|
|
|
# Vikunja project ID — each project uses a different Vikunja project
|
|
VIKUNJA_PROJECT_ID = _get_int("vikunja_project_id", "DEVX_VIKUNJA_PROJECT_ID", 6)
|
|
|
|
# HTTP client defaults
|
|
DEFAULT_TIMEOUT = 30
|
|
DEFAULT_PER_PAGE = 50
|
|
|
|
# Retry configuration for transient errors (429, 5xx, connection errors)
|
|
MAX_RETRIES = 3
|
|
RETRY_BACKOFF_BASE = 2 # seconds: 2, 4, 8
|
|
RETRY_STATUS_CODES = {429, 500, 502, 503, 504}
|
|
|
|
# Conventional commit regex — used by validate_commit_msg.py
|
|
CONVENTIONAL_RE = re.compile(r"^(feat|fix|chore|docs|style|refactor|perf|test|ci|build|revert)(\(.+\))?: .+")
|