first commit
This commit is contained in:
217
backend/app/gitea/client.py
Normal file
217
backend/app/gitea/client.py
Normal file
@@ -0,0 +1,217 @@
|
||||
"""Gitea API客户端,用于与Gitea服务器通信"""
|
||||
|
||||
import requests
|
||||
import json
|
||||
import logging
|
||||
from typing import Optional, Dict, Any, List
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GiteaClient:
|
||||
"""Gitea API客户端类"""
|
||||
|
||||
def __init__(self, server_url: str, access_token: str):
|
||||
"""初始化Gitea客户端
|
||||
|
||||
Args:
|
||||
server_url: Gitea服务器URL
|
||||
access_token: Gitea访问令牌
|
||||
"""
|
||||
self.server_url = server_url.rstrip('/')
|
||||
self.access_token = access_token
|
||||
self.api_url = f"{self.server_url}/api/v1"
|
||||
self.headers = {
|
||||
"Authorization": f"token {self.access_token}",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
def _request(self, method: str, endpoint: str, data: Optional[Dict[str, Any]] = None) -> Optional[Dict[str, Any]]:
|
||||
"""发送API请求
|
||||
|
||||
Args:
|
||||
method: HTTP方法(GET, POST, PUT, DELETE)
|
||||
endpoint: API端点
|
||||
data: 请求数据
|
||||
|
||||
Returns:
|
||||
API响应数据
|
||||
"""
|
||||
url = f"{self.api_url}/{endpoint}"
|
||||
|
||||
try:
|
||||
if method == "GET":
|
||||
response = requests.get(url, headers=self.headers, params=data)
|
||||
elif method == "POST":
|
||||
response = requests.post(url, headers=self.headers, json=data)
|
||||
elif method == "PUT":
|
||||
response = requests.put(url, headers=self.headers, json=data)
|
||||
elif method == "PATCH":
|
||||
response = requests.patch(url, headers=self.headers, json=data)
|
||||
elif method == "DELETE":
|
||||
response = requests.delete(url, headers=self.headers)
|
||||
else:
|
||||
raise ValueError(f"Unsupported HTTP method: {method}")
|
||||
|
||||
response.raise_for_status()
|
||||
|
||||
if response.content:
|
||||
return response.json()
|
||||
return None
|
||||
|
||||
except requests.RequestException as e:
|
||||
logger.error(f"Gitea API request failed: {str(e)}")
|
||||
return None
|
||||
|
||||
def create_repository(self, owner: str, name: str, description: str = "", private: bool = False) -> Optional[Dict[str, Any]]:
|
||||
"""创建仓库
|
||||
|
||||
Args:
|
||||
owner: 所有者(用户或组织)
|
||||
name: 仓库名称
|
||||
description: 仓库描述
|
||||
private: 是否私有
|
||||
|
||||
Returns:
|
||||
创建的仓库信息
|
||||
"""
|
||||
data = {
|
||||
"name": name,
|
||||
"description": description,
|
||||
"private": private,
|
||||
"auto_init": True
|
||||
}
|
||||
|
||||
# 优先尝试在指定的 owner(组织)下创建仓库
|
||||
logger.info(f"Attempting to create repository for owner: {owner}")
|
||||
owner_response = self._request("POST", f"org/{owner}/repos", data)
|
||||
if owner_response:
|
||||
logger.info(f"Repository created successfully under owner: {owner}")
|
||||
return owner_response
|
||||
|
||||
# 如果组织创建失败,尝试在用户下创建仓库
|
||||
logger.info(f"Organization creation failed, trying user account")
|
||||
user_response = self._request("POST", f"user/repos", data)
|
||||
if user_response:
|
||||
logger.info(f"Repository created successfully in user account")
|
||||
return user_response
|
||||
|
||||
logger.error(f"Failed to create repository for owner {owner}")
|
||||
return None
|
||||
|
||||
def get_repository(self, owner: str, repo: str) -> Optional[Dict[str, Any]]:
|
||||
"""获取仓库信息
|
||||
|
||||
Args:
|
||||
owner: 所有者(用户或组织)
|
||||
repo: 仓库名称
|
||||
|
||||
Returns:
|
||||
仓库信息
|
||||
"""
|
||||
return self._request("GET", f"repos/{owner}/{repo}")
|
||||
|
||||
def list_repositories(self, owner: str) -> Optional[List[Dict[str, Any]]]:
|
||||
"""列出用户或组织的仓库
|
||||
|
||||
Args:
|
||||
owner: 所有者(用户或组织)
|
||||
|
||||
Returns:
|
||||
仓库列表
|
||||
"""
|
||||
return self._request("GET", f"users/{owner}/repos")
|
||||
|
||||
def delete_repository(self, owner: str, repo: str) -> bool:
|
||||
"""删除仓库
|
||||
|
||||
Args:
|
||||
owner: 所有者(用户或组织)
|
||||
repo: 仓库名称
|
||||
|
||||
Returns:
|
||||
是否删除成功
|
||||
"""
|
||||
response = self._request("DELETE", f"repos/{owner}/{repo}")
|
||||
return response is not None
|
||||
|
||||
def create_file(self, owner: str, repo: str, path: str, content: str, message: str) -> Optional[Dict[str, Any]]:
|
||||
"""创建或更新文件
|
||||
|
||||
Args:
|
||||
owner: 所有者(用户或组织)
|
||||
repo: 仓库名称
|
||||
path: 文件路径
|
||||
content: 文件内容(base64编码)
|
||||
message: 提交消息
|
||||
|
||||
Returns:
|
||||
操作结果
|
||||
"""
|
||||
data = {
|
||||
"content": content,
|
||||
"message": message
|
||||
}
|
||||
|
||||
return self._request("POST", f"repos/{owner}/{repo}/contents/{path}", data)
|
||||
|
||||
def get_file(self, owner: str, repo: str, path: str) -> Optional[Dict[str, Any]]:
|
||||
"""获取文件内容
|
||||
|
||||
Args:
|
||||
owner: 所有者(用户或组织)
|
||||
repo: 仓库名称
|
||||
path: 文件路径
|
||||
|
||||
Returns:
|
||||
文件信息和内容
|
||||
"""
|
||||
return self._request("GET", f"repos/{owner}/{repo}/contents/{path}")
|
||||
|
||||
def get_repository_files(self, owner: str, repo: str, path: str = "") -> Optional[List[Dict[str, Any]]]:
|
||||
"""获取仓库文件列表
|
||||
|
||||
Args:
|
||||
owner: 所有者(用户或组织)
|
||||
repo: 仓库名称
|
||||
path: 目录路径(默认为根目录)
|
||||
|
||||
Returns:
|
||||
文件列表
|
||||
"""
|
||||
result = self._request("GET", f"repos/{owner}/{repo}/contents/{path}")
|
||||
return result if isinstance(result, list) else None
|
||||
|
||||
|
||||
|
||||
def check_connection(self) -> bool:
|
||||
"""检查与Gitea服务器的连接
|
||||
|
||||
Returns:
|
||||
是否连接成功
|
||||
"""
|
||||
response = self._request("GET", "user")
|
||||
return response is not None
|
||||
|
||||
def update_repository(self, owner: str, repo: str, name: Optional[str] = None, description: Optional[str] = None, private: Optional[bool] = None) -> Optional[Dict[str, Any]]:
|
||||
"""更新仓库信息
|
||||
|
||||
Args:
|
||||
owner: 所有者(用户或组织)
|
||||
repo: 仓库名称
|
||||
name: 新的仓库名称(可选)
|
||||
description: 新的仓库描述(可选)
|
||||
private: 是否私有(可选)
|
||||
|
||||
Returns:
|
||||
更新后的仓库信息
|
||||
"""
|
||||
data = {}
|
||||
if name is not None:
|
||||
data["name"] = name
|
||||
if description is not None:
|
||||
data["description"] = description
|
||||
if private is not None:
|
||||
data["private"] = private
|
||||
|
||||
return self._request("PATCH", f"repos/{owner}/{repo}", data)
|
||||
Reference in New Issue
Block a user