59 lines
1.5 KiB
Python
59 lines
1.5 KiB
Python
"""Workspace-independent authority/network/Gitea ref sentinel."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from pathlib import Path
|
|
import subprocess
|
|
from typing import Callable, Mapping
|
|
|
|
|
|
class SentinelError(RuntimeError):
|
|
pass
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class SentinelInputs:
|
|
authority_git_dir: Path
|
|
gitea_remote: str
|
|
gitea_api: str
|
|
ref: str
|
|
expected_oid: str
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class SentinelResult:
|
|
authority_oid: str | None
|
|
network_oid: str | None
|
|
gitea_oid: str | None
|
|
equal: bool
|
|
error: str | None = None
|
|
|
|
|
|
def authority_oid(inputs: SentinelInputs) -> str:
|
|
result = subprocess.run(
|
|
["git", "--git-dir", str(inputs.authority_git_dir), "rev-parse", inputs.ref],
|
|
text=True,
|
|
capture_output=True,
|
|
check=False,
|
|
)
|
|
if result.returncode != 0:
|
|
raise SentinelError("AUTHORITY_REF_UNAVAILABLE")
|
|
return result.stdout.strip()
|
|
|
|
|
|
def evaluate(
|
|
inputs: SentinelInputs,
|
|
*,
|
|
network_reader: Callable[[str, str], str | None],
|
|
gitea_reader: Callable[[str, str], str | None],
|
|
) -> SentinelResult:
|
|
try:
|
|
local = authority_oid(inputs)
|
|
network = network_reader(inputs.gitea_remote, inputs.ref)
|
|
gitea = gitea_reader(inputs.gitea_api, inputs.ref)
|
|
equal = local == network == gitea == inputs.expected_oid
|
|
return SentinelResult(local, network, gitea, equal, None if equal else "OID_MISMATCH")
|
|
except SentinelError as exc:
|
|
return SentinelResult(None, None, None, False, str(exc))
|