First MVP

This commit is contained in:
Space-Banane
2026-05-22 19:25:57 +02:00
parent 673f70b32a
commit 860ccb731d
40 changed files with 2336 additions and 0 deletions

View File

@@ -0,0 +1,97 @@
from __future__ import annotations
from dataclasses import dataclass
from typing import Any
from urllib.parse import quote
import httpx
from gitea_codex_bot.config import Settings
@dataclass(slots=True)
class PullRequestContext:
repo: str
pr_number: int
base_ref: str
base_sha: str
head_ref: str
head_sha: str
clone_url: str
html_url: str
is_fork: bool
class GiteaClient:
def __init__(self, settings: Settings) -> None:
self.settings = settings
self.base_url = settings.gitea_base_url
self.headers = {
"Authorization": f"token {settings.gitea_token.get_secret_value()}",
"Accept": "application/json",
"Content-Type": "application/json",
}
def _request(self, method: str, path: str, *, json_body: dict[str, Any] | None = None) -> Any:
with httpx.Client(timeout=20.0) as client:
response = client.request(
method,
f"{self.base_url}{path}",
headers=self.headers,
json=json_body,
)
response.raise_for_status()
if response.status_code == 204:
return None
return response.json()
@staticmethod
def split_repo(repo: str) -> tuple[str, str]:
owner, name = repo.split("/", 1)
return owner, name
def get_pull_request(self, repo: str, pr_number: int) -> PullRequestContext:
owner, name = self.split_repo(repo)
encoded_owner = quote(owner, safe="")
encoded_name = quote(name, safe="")
payload = self._request("GET", f"/api/v1/repos/{encoded_owner}/{encoded_name}/pulls/{pr_number}")
return PullRequestContext(
repo=repo,
pr_number=pr_number,
base_ref=payload["base"]["ref"],
base_sha=payload["base"]["sha"],
head_ref=payload["head"]["ref"],
head_sha=payload["head"]["sha"],
clone_url=payload["head"]["repo"]["clone_url"],
html_url=payload["html_url"],
is_fork=bool(payload["head"]["repo"]["full_name"] != payload["base"]["repo"]["full_name"]),
)
def post_issue_comment(self, repo: str, pr_number: int, body: str) -> int:
owner, name = self.split_repo(repo)
encoded_owner = quote(owner, safe="")
encoded_name = quote(name, safe="")
payload = self._request(
"POST",
f"/api/v1/repos/{encoded_owner}/{encoded_name}/issues/{pr_number}/comments",
json_body={"body": body},
)
return int(payload["id"])
def edit_issue_comment(self, repo: str, comment_id: int, body: str) -> int:
owner, name = self.split_repo(repo)
encoded_owner = quote(owner, safe="")
encoded_name = quote(name, safe="")
payload = self._request(
"PATCH",
f"/api/v1/repos/{encoded_owner}/{encoded_name}/issues/comments/{comment_id}",
json_body={"body": body},
)
return int(payload["id"])
def list_issue_comments(self, repo: str, pr_number: int) -> list[dict[str, Any]]:
owner, name = self.split_repo(repo)
encoded_owner = quote(owner, safe="")
encoded_name = quote(name, safe="")
payload = self._request("GET", f"/api/v1/repos/{encoded_owner}/{encoded_name}/issues/{pr_number}/comments")
return list(payload)