91 lines
2.6 KiB
Python
91 lines
2.6 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass, field
|
|
from datetime import datetime, timezone
|
|
from enum import Enum
|
|
from typing import Any, Mapping
|
|
|
|
|
|
class GovernanceState(str, Enum):
|
|
HUMAN_OWNER_APPROVAL_PENDING = "HUMAN_OWNER_APPROVAL_PENDING"
|
|
OWNER_APPROVAL_VERIFIED = "OWNER_APPROVAL_VERIFIED"
|
|
MACHINE_GATES_VERIFIED = "MACHINE_GATES_VERIFIED"
|
|
AUTO_MERGE_READY = "AUTO_MERGE_READY"
|
|
OWNER_APPROVED_EXECUTION_READY = "OWNER_APPROVED_EXECUTION_READY"
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class Review:
|
|
reviewer: str
|
|
reviewer_id: int
|
|
state: str
|
|
head_oid: str
|
|
reviewed_at: datetime
|
|
stale: bool = False
|
|
dismissed: bool = False
|
|
|
|
def __post_init__(self) -> None:
|
|
if self.reviewed_at.tzinfo is None:
|
|
raise ValueError("reviewed_at must be timezone-aware")
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class MachineGate:
|
|
context: str
|
|
state: str
|
|
head_oid: str
|
|
observed_at: datetime
|
|
|
|
def __post_init__(self) -> None:
|
|
if self.observed_at.tzinfo is None:
|
|
raise ValueError("observed_at must be timezone-aware")
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class ApprovalContext:
|
|
current_head_oid: str
|
|
requester: str
|
|
executor: str
|
|
owner: str
|
|
owner_id: int
|
|
reviews: tuple[Review, ...]
|
|
machine_gates: tuple[MachineGate, ...]
|
|
required_machine_contexts: tuple[str, ...]
|
|
expires_at: datetime
|
|
wip: bool
|
|
now: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
|
|
|
|
def __post_init__(self) -> None:
|
|
if self.expires_at.tzinfo is None or self.now.tzinfo is None:
|
|
raise ValueError("approval timestamps must be timezone-aware")
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class ProtectionSnapshot:
|
|
branch: str
|
|
required_approvals: int
|
|
approval_whitelist: tuple[str, ...]
|
|
merge_whitelist: tuple[str, ...]
|
|
dismiss_stale_approvals: bool
|
|
require_status_checks: bool
|
|
status_contexts: tuple[str, ...]
|
|
direct_push: bool
|
|
force_push: bool
|
|
branch_deletion: bool
|
|
version: int
|
|
|
|
def as_dict(self) -> Mapping[str, Any]:
|
|
return {
|
|
"branch": self.branch,
|
|
"required_approvals": self.required_approvals,
|
|
"approval_whitelist": list(self.approval_whitelist),
|
|
"merge_whitelist": list(self.merge_whitelist),
|
|
"dismiss_stale_approvals": self.dismiss_stale_approvals,
|
|
"require_status_checks": self.require_status_checks,
|
|
"status_contexts": list(self.status_contexts),
|
|
"direct_push": self.direct_push,
|
|
"force_push": self.force_push,
|
|
"branch_deletion": self.branch_deletion,
|
|
"version": self.version,
|
|
}
|