Files
ITWorx_MCP_Hub-Public/connectors/gitea/lifecycle.py
T

60 lines
2.0 KiB
Python

"""Bounded helpers for destructive Gitea pull-request lifecycle cleanup."""
from __future__ import annotations
import re
from typing import Any, Protocol
from packages.connector_kit import GiteaError, RegisteredRepository
_VIRTUAL_PULL_HEAD = re.compile(r"refs/pull/[1-9][0-9]*/head")
class PullRequestReader(Protocol):
def pull_requests(
self, repository: RegisteredRepository, page: int, limit: int
) -> list[dict[str, Any]]: ...
def cleanup_basis(
client: PullRequestReader,
repository: RegisteredRepository,
branch: str,
expected_head_sha: str,
) -> tuple[dict[str, Any] | None, dict[str, Any] | None]:
"""Return the merged/closed PR proving one exact branch is cleanup-eligible."""
related: list[dict[str, Any]] = []
for page_number in range(1, 11):
pulls = client.pull_requests(repository, page_number, 100)
for item in pulls:
head = item.get("head") or {}
head_ref = str(head.get("ref", ""))
head_sha = str(head.get("sha", ""))
if head_ref == branch or (
head_sha == expected_head_sha and _VIRTUAL_PULL_HEAD.fullmatch(head_ref)
):
related.append(item)
if len(pulls) < 100:
break
if any(str(item.get("state", "")) == "open" for item in related):
raise GiteaError(
"GITEA_TARGET_INVALID",
"branch is still referenced by an open pull request; close or merge it first",
)
merged = next((item for item in related if bool(item.get("merged", False))), None)
closed = next(
(
item
for item in related
if str(item.get("state", "")) == "closed" and not bool(item.get("merged", False))
),
None,
)
if merged is None and closed is None:
raise GiteaError(
"GITEA_TARGET_INVALID",
"only a change branch from a merged or closed pull request can be deleted",
)
return merged, closed