155 lines
5.2 KiB
Python
155 lines
5.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Shared Gitea configuration helpers for issue scripts."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import re
|
|
import shlex
|
|
import subprocess
|
|
from pathlib import Path
|
|
from urllib.parse import urlparse
|
|
|
|
|
|
DEFAULT_ENV_FILE = Path("~/.config/gitea/gitea.env").expanduser()
|
|
SECRETS_ENV_FILE = Path("~/.config/secrets/gitea.env").expanduser()
|
|
LEGACY_ENV_FILE = Path("~/.config/gitea/data-analysis-agent.env").expanduser()
|
|
REQUIRED_ENV = ("GITEA_BASE_URL", "GITEA_OWNER", "GITEA_REPO", "GITEA_TOKEN")
|
|
|
|
|
|
def load_env_file(path: Path) -> dict[str, str]:
|
|
values: dict[str, str] = {}
|
|
if not path.exists():
|
|
return values
|
|
|
|
for raw_line in path.read_text(encoding="utf-8").splitlines():
|
|
line = raw_line.strip()
|
|
if not line or line.startswith("#"):
|
|
continue
|
|
if line.startswith("export "):
|
|
line = line[len("export ") :]
|
|
if "=" not in line:
|
|
continue
|
|
key, raw_value = line.split("=", 1)
|
|
key = key.strip()
|
|
try:
|
|
parsed = shlex.split(raw_value.strip(), comments=False, posix=True)
|
|
except ValueError as exc:
|
|
raise SystemExit(f"Could not parse {path}: {exc}") from exc
|
|
values[key] = parsed[0] if parsed else ""
|
|
return values
|
|
|
|
|
|
def discover_origin_config() -> dict[str, str]:
|
|
try:
|
|
remote = subprocess.run(
|
|
["git", "remote", "get-url", "origin"],
|
|
capture_output=True,
|
|
text=True,
|
|
check=True,
|
|
).stdout.strip()
|
|
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
return {}
|
|
|
|
if not remote:
|
|
return {}
|
|
|
|
parsed = urlparse(remote)
|
|
host = ""
|
|
path = ""
|
|
if parsed.scheme in {"http", "https", "ssh"} and parsed.netloc:
|
|
host = parsed.hostname or parsed.netloc.split("@")[-1].split(":")[0]
|
|
path = parsed.path.lstrip("/")
|
|
else:
|
|
match = re.match(r"(?:(?P<user>[^@]+)@)?(?P<host>[^:]+):(?P<path>.+)$", remote)
|
|
if match:
|
|
host = match.group("host")
|
|
path = match.group("path")
|
|
|
|
if not host or not path:
|
|
return {}
|
|
|
|
if path.endswith(".git"):
|
|
path = path[:-4]
|
|
parts = [part for part in path.split("/") if part]
|
|
if len(parts) < 2:
|
|
return {}
|
|
|
|
return {
|
|
"GITEA_BASE_URL": f"https://{host}",
|
|
"GITEA_OWNER": parts[-2],
|
|
"GITEA_REPO": parts[-1],
|
|
}
|
|
|
|
|
|
def config(env_file: Path | None = None) -> dict[str, str]:
|
|
env_path = (env_file or DEFAULT_ENV_FILE).expanduser()
|
|
file_values = load_env_file(env_path)
|
|
if env_path == DEFAULT_ENV_FILE:
|
|
secrets_values = load_env_file(SECRETS_ENV_FILE)
|
|
legacy_values = load_env_file(LEGACY_ENV_FILE)
|
|
file_values = {**legacy_values, **secrets_values, **file_values}
|
|
|
|
origin_values = discover_origin_config()
|
|
base_url = (
|
|
os.environ.get("GITEA_BASE_URL")
|
|
or os.environ.get("GITEA_URL")
|
|
or origin_values.get("GITEA_BASE_URL")
|
|
or file_values.get("GITEA_BASE_URL")
|
|
or file_values.get("GITEA_URL", "")
|
|
)
|
|
values = {
|
|
"GITEA_BASE_URL": base_url,
|
|
"GITEA_OWNER": os.environ.get("GITEA_OWNER")
|
|
or origin_values.get("GITEA_OWNER")
|
|
or file_values.get("GITEA_OWNER", ""),
|
|
"GITEA_REPO": os.environ.get("GITEA_REPO")
|
|
or origin_values.get("GITEA_REPO")
|
|
or file_values.get("GITEA_REPO", ""),
|
|
"GITEA_TOKEN": os.environ.get("GITEA_TOKEN") or file_values.get("GITEA_TOKEN", ""),
|
|
}
|
|
missing = [key for key, value in values.items() if not value]
|
|
if missing:
|
|
raise SystemExit(
|
|
"Missing required Gitea configuration: "
|
|
+ ", ".join(missing)
|
|
+ f"\nSet them in the shell, {env_path}, {SECRETS_ENV_FILE}, "
|
|
+ "or run from a git repo with a Gitea origin."
|
|
)
|
|
return values
|
|
|
|
|
|
def auth_config(env_file: Path | None = None) -> dict[str, str]:
|
|
"""Return Gitea API auth config without requiring a repository context."""
|
|
env_path = (env_file or DEFAULT_ENV_FILE).expanduser()
|
|
file_values = load_env_file(env_path)
|
|
if env_path == DEFAULT_ENV_FILE:
|
|
secrets_values = load_env_file(SECRETS_ENV_FILE)
|
|
legacy_values = load_env_file(LEGACY_ENV_FILE)
|
|
file_values = {**legacy_values, **secrets_values, **file_values}
|
|
|
|
origin_values = discover_origin_config()
|
|
base_url = (
|
|
os.environ.get("GITEA_BASE_URL")
|
|
or os.environ.get("GITEA_URL")
|
|
or origin_values.get("GITEA_BASE_URL")
|
|
or file_values.get("GITEA_BASE_URL")
|
|
or file_values.get("GITEA_URL", "")
|
|
)
|
|
values = {
|
|
"GITEA_BASE_URL": base_url,
|
|
"GITEA_OWNER": os.environ.get("GITEA_OWNER")
|
|
or origin_values.get("GITEA_OWNER")
|
|
or file_values.get("GITEA_OWNER", ""),
|
|
"GITEA_TOKEN": os.environ.get("GITEA_TOKEN") or file_values.get("GITEA_TOKEN", ""),
|
|
}
|
|
missing = [key for key in ("GITEA_BASE_URL", "GITEA_TOKEN") if not values[key]]
|
|
if missing:
|
|
raise SystemExit(
|
|
"Missing required Gitea configuration: "
|
|
+ ", ".join(missing)
|
|
+ f"\nSet them in the shell, {env_path}, {SECRETS_ENV_FILE}, "
|
|
+ "or run from a git repo with a Gitea origin."
|
|
)
|
|
return values
|