Ports dirigent's gitea scripts into a self-contained reliquary plugin. Scripts run via uv with PEP 723 inline deps — no project venv needed. Gitea connection inferred from `git remote get-url origin` with env-var overrides; only GITEA_TOKEN is mandatory. Workpad path and tickets directory are parameterized so the plugin works in any project. Label set externalized to labels.default.json with project-level override via .gitea-labels.json. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
118 lines
3.7 KiB
Python
118 lines
3.7 KiB
Python
"""Configuration for Gitea API access.
|
|
|
|
Resolution order:
|
|
1. Parse `git remote get-url origin` for base_url/owner/repo.
|
|
2. Env vars (GITEA_URL, GITEA_OWNER, GITEA_REPO) override inferred values.
|
|
3. GITEA_TOKEN is always required from env.
|
|
|
|
`.env` in CWD (or any parent) is loaded via python-dotenv.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
from dataclasses import dataclass
|
|
from typing import Optional, Tuple
|
|
|
|
from dotenv import find_dotenv, load_dotenv
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class GiteaConfig:
|
|
base_url: str
|
|
token: str
|
|
owner: str
|
|
repo: str
|
|
|
|
@property
|
|
def api_url(self) -> str:
|
|
return f"{self.base_url.rstrip('/')}/api/v1"
|
|
|
|
|
|
_HTTPS_RE = re.compile(r"^(https?)://(?:[^@/]+@)?([^/:]+)(?::\d+)?/([^/]+)/(.+?)(?:\.git)?/?$")
|
|
_SSH_URL_RE = re.compile(r"^ssh://(?:[\w.-]+@)?([^:/]+)(?::\d+)?/([^/]+)/(.+?)(?:\.git)?/?$")
|
|
_SCP_RE = re.compile(r"^(?:[\w.-]+@)?([^:/]+):([^/]+)/(.+?)(?:\.git)?/?$")
|
|
|
|
|
|
def parse_remote_url(url: str) -> Optional[Tuple[str, str, str]]:
|
|
"""Parse a git remote URL into (base_url, owner, repo).
|
|
|
|
Handles:
|
|
git@host:owner/repo.git (SCP-like)
|
|
ssh://git@host[:port]/owner/repo.git (SSH URL)
|
|
https://[user@]host[:port]/owner/repo(.git)
|
|
"""
|
|
url = url.strip()
|
|
if not url:
|
|
return None
|
|
|
|
m = _HTTPS_RE.match(url)
|
|
if m:
|
|
scheme, host, owner, repo = m.group(1), m.group(2), m.group(3), m.group(4)
|
|
return f"{scheme}://{host}", owner, repo
|
|
|
|
m = _SSH_URL_RE.match(url)
|
|
if m:
|
|
host, owner, repo = m.group(1), m.group(2), m.group(3)
|
|
return f"https://{host}", owner, repo
|
|
|
|
m = _SCP_RE.match(url)
|
|
if m:
|
|
host, owner, repo = m.group(1), m.group(2), m.group(3)
|
|
return f"https://{host}", owner, repo
|
|
|
|
return None
|
|
|
|
|
|
def git_remote_origin() -> Optional[Tuple[str, str, str]]:
|
|
"""Return (base_url, owner, repo) parsed from `git remote get-url origin`, or None."""
|
|
try:
|
|
result = subprocess.run(
|
|
["git", "remote", "get-url", "origin"],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=5,
|
|
)
|
|
except (FileNotFoundError, subprocess.TimeoutExpired):
|
|
return None
|
|
if result.returncode != 0:
|
|
return None
|
|
return parse_remote_url(result.stdout.strip())
|
|
|
|
|
|
def load_config() -> GiteaConfig:
|
|
"""Load configuration: git remote inference + env-var overrides.
|
|
|
|
GITEA_TOKEN is always required. The other fields can come from either
|
|
the git remote of the current working directory, or be overridden via
|
|
GITEA_URL, GITEA_OWNER, GITEA_REPO in env or .env file.
|
|
"""
|
|
load_dotenv(find_dotenv(usecwd=True))
|
|
|
|
inferred = git_remote_origin()
|
|
base_url = os.environ.get("GITEA_URL") or (inferred[0] if inferred else None)
|
|
owner = os.environ.get("GITEA_OWNER") or (inferred[1] if inferred else None)
|
|
repo = os.environ.get("GITEA_REPO") or (inferred[2] if inferred else None)
|
|
token = os.environ.get("GITEA_TOKEN")
|
|
|
|
missing = []
|
|
if not token:
|
|
missing.append("GITEA_TOKEN")
|
|
if not base_url:
|
|
missing.append("GITEA_URL (or a git origin remote)")
|
|
if not owner:
|
|
missing.append("GITEA_OWNER (or a git origin remote)")
|
|
if not repo:
|
|
missing.append("GITEA_REPO (or a git origin remote)")
|
|
|
|
if missing:
|
|
print(f"Error: missing required configuration: {', '.join(missing)}", file=sys.stderr)
|
|
print("Set GITEA_TOKEN in your environment or .env file.", file=sys.stderr)
|
|
print("URL/owner/repo are inferred from `git remote get-url origin` when available.", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
return GiteaConfig(base_url=base_url, token=token, owner=owner, repo=repo)
|