""" Gitea Webhook 数据模型 """ from typing import List, Optional from pydantic import BaseModel, Field from datetime import datetime class User(BaseModel): """Gitea 用户模型""" id: int login: str full_name: Optional[str] = None email: Optional[str] = None username: Optional[str] = None class Commit(BaseModel): """Git 提交模型""" id: str message: str url: str author: User timestamp: Optional[datetime] = None class Repository(BaseModel): """Git 仓库模型""" id: int name: str owner: User full_name: str private: bool = False clone_url: str ssh_url: Optional[str] = None html_url: str default_branch: str = "main" class GiteaWebhook(BaseModel): """Gitea Webhook 模型""" secret: Optional[str] = None ref: str before: str after: str compare_url: Optional[str] = None commits: List[Commit] = Field(default_factory=list) repository: Repository pusher: User def get_branch_name(self) -> str: """从 ref 中提取分支名""" prefix = "refs/heads/" if self.ref.startswith(prefix): return self.ref[len(prefix):] return self.ref def get_event_id(self) -> str: """生成唯一的事件 ID""" return f"{self.repository.full_name}-{self.after}" def get_commit_hash(self) -> str: """获取提交哈希""" return self.after def get_deduplication_key(self) -> str: """生成防抖键值""" branch = self.get_branch_name() return f"{self.after}:{branch}" def is_push_event(self) -> bool: """判断是否为推送事件""" return self.ref.startswith("refs/heads/") def is_tag_event(self) -> bool: """判断是否为标签事件""" return self.ref.startswith("refs/tags/") def get_commit_message(self) -> str: """获取提交信息""" if self.commits: return self.commits[0].message return "" def get_author_info(self) -> dict: """获取作者信息""" if self.commits: author = self.commits[0].author return { "name": author.full_name or author.login, "email": author.email, "username": author.login } return { "name": self.pusher.full_name or self.pusher.login, "email": self.pusher.email, "username": self.pusher.login } class WebhookEvent(BaseModel): """Webhook 事件模型""" id: str repository: str branch: str commit_hash: str event_type: str timestamp: datetime payload: dict class Config: json_encoders = { datetime: lambda v: v.isoformat() } class WebhookResponse(BaseModel): """Webhook 响应模型""" success: bool message: str event_id: Optional[str] = None job_name: Optional[str] = None environment: Optional[str] = None timestamp: datetime = Field(default_factory=datetime.utcnow) class Config: json_encoders = { datetime: lambda v: v.isoformat() }