206 lines
6.5 KiB
Python
206 lines
6.5 KiB
Python
"""
|
|
项目Git仓库管理 API
|
|
"""
|
|
from fastapi import APIRouter, Depends, HTTPException, Request
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlalchemy import select, update, func
|
|
|
|
from app.core.database import get_db
|
|
from app.core.deps import get_current_user
|
|
from app.models.user import User
|
|
from app.models.git_repo import ProjectGitRepo
|
|
from app.schemas.git_repo import GitRepoCreate, GitRepoUpdate, GitRepoResponse, GitRepoTestRequest
|
|
from app.services.git_service import git_service
|
|
from app.schemas.response import success_response
|
|
from app.services.log_service import log_service
|
|
from app.services.project_service import require_project_read_access, require_project_roles
|
|
from app.core.enums import OperationType
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
def _repo_response(repo: ProjectGitRepo) -> dict:
|
|
data = GitRepoResponse.from_orm(repo).dict()
|
|
data["token"] = None
|
|
data["has_token"] = bool(repo.token)
|
|
return data
|
|
|
|
|
|
@router.get("/projects/{project_id}/git-repos", response_model=dict)
|
|
async def get_project_git_repos(
|
|
project_id: int,
|
|
current_user: User = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db)
|
|
):
|
|
"""获取项目的Git仓库列表"""
|
|
await require_project_read_access(db, project_id, current_user)
|
|
|
|
result = await db.execute(
|
|
select(ProjectGitRepo).where(ProjectGitRepo.project_id == project_id).order_by(ProjectGitRepo.created_at)
|
|
)
|
|
repos = result.scalars().all()
|
|
|
|
# 隐藏 token
|
|
data = []
|
|
for repo in repos:
|
|
data.append(_repo_response(repo))
|
|
|
|
return success_response(data=data)
|
|
|
|
|
|
@router.post("/projects/{project_id}/git-repos", response_model=dict)
|
|
async def create_git_repo(
|
|
project_id: int,
|
|
repo_in: GitRepoCreate,
|
|
request: Request,
|
|
current_user: User = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db)
|
|
):
|
|
"""添加Git仓库"""
|
|
await require_project_roles(
|
|
db,
|
|
project_id,
|
|
current_user,
|
|
allowed_roles=["admin", "editor"],
|
|
)
|
|
|
|
# 如果是设为默认,先取消其他默认
|
|
if repo_in.is_default:
|
|
await db.execute(
|
|
update(ProjectGitRepo)
|
|
.where(ProjectGitRepo.project_id == project_id)
|
|
.values(is_default=0)
|
|
)
|
|
|
|
# 检查是否是第一个仓库,如果是,强制设为默认
|
|
result = await db.execute(select(func.count()).select_from(ProjectGitRepo).where(ProjectGitRepo.project_id == project_id))
|
|
count = result.scalar()
|
|
is_default = repo_in.is_default
|
|
if count == 0:
|
|
is_default = 1
|
|
|
|
db_repo = ProjectGitRepo(
|
|
project_id=project_id,
|
|
name=repo_in.name,
|
|
repo_url=repo_in.repo_url,
|
|
branch=repo_in.branch,
|
|
username=repo_in.username,
|
|
token=repo_in.token,
|
|
is_default=is_default,
|
|
sync_path=""
|
|
)
|
|
db.add(db_repo)
|
|
await db.commit()
|
|
await db.refresh(db_repo)
|
|
|
|
return success_response(data=_repo_response(db_repo), message="Git仓库添加成功")
|
|
|
|
|
|
@router.post("/projects/{project_id}/git-repos/test-connection", response_model=dict)
|
|
async def test_git_repo_connection(
|
|
project_id: int,
|
|
repo_in: GitRepoTestRequest,
|
|
current_user: User = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""Test remote repository access without saving configuration or changing project files."""
|
|
await require_project_roles(
|
|
db,
|
|
project_id,
|
|
current_user,
|
|
allowed_roles=["admin", "editor"],
|
|
)
|
|
|
|
saved_repo = None
|
|
if repo_in.repo_id:
|
|
result = await db.execute(
|
|
select(ProjectGitRepo).where(
|
|
ProjectGitRepo.id == repo_in.repo_id,
|
|
ProjectGitRepo.project_id == project_id,
|
|
)
|
|
)
|
|
saved_repo = result.scalar_one_or_none()
|
|
if not saved_repo:
|
|
raise HTTPException(status_code=404, detail="仓库不存在")
|
|
|
|
repo_url = repo_in.repo_url or (saved_repo.repo_url if saved_repo else None)
|
|
branch = repo_in.branch or (saved_repo.branch if saved_repo else "main")
|
|
username = repo_in.username if repo_in.username is not None else (saved_repo.username if saved_repo else None)
|
|
token = repo_in.token or (saved_repo.token if saved_repo else None)
|
|
|
|
success, message = await git_service.test_connection(repo_url, branch, username, token)
|
|
if not success:
|
|
raise HTTPException(status_code=400, detail=f"远端仓库认证失败:{message}")
|
|
return success_response(message="远端仓库认证成功")
|
|
|
|
|
|
@router.put("/projects/{project_id}/git-repos/{repo_id}", response_model=dict)
|
|
async def update_git_repo(
|
|
project_id: int,
|
|
repo_id: int,
|
|
repo_in: GitRepoUpdate,
|
|
request: Request,
|
|
current_user: User = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db)
|
|
):
|
|
"""更新Git仓库"""
|
|
await require_project_roles(
|
|
db,
|
|
project_id,
|
|
current_user,
|
|
allowed_roles=["admin", "editor"],
|
|
)
|
|
|
|
result = await db.execute(select(ProjectGitRepo).where(ProjectGitRepo.id == repo_id, ProjectGitRepo.project_id == project_id))
|
|
repo = result.scalar_one_or_none()
|
|
|
|
if not repo:
|
|
raise HTTPException(status_code=404, detail="仓库不存在")
|
|
|
|
# 如果设为默认,取消其他默认
|
|
if repo_in.is_default == 1:
|
|
await db.execute(
|
|
update(ProjectGitRepo)
|
|
.where(ProjectGitRepo.project_id == project_id)
|
|
.values(is_default=0)
|
|
)
|
|
|
|
update_data = repo_in.dict(exclude_unset=True)
|
|
# token 不回显;编辑时留空表示继续使用已保存凭据。
|
|
if not update_data.get("token"):
|
|
update_data.pop("token", None)
|
|
for field, value in update_data.items():
|
|
setattr(repo, field, value)
|
|
|
|
await db.commit()
|
|
await db.refresh(repo)
|
|
|
|
return success_response(data=_repo_response(repo), message="更新成功")
|
|
|
|
|
|
@router.delete("/projects/{project_id}/git-repos/{repo_id}", response_model=dict)
|
|
async def delete_git_repo(
|
|
project_id: int,
|
|
repo_id: int,
|
|
current_user: User = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db)
|
|
):
|
|
"""删除Git仓库"""
|
|
await require_project_roles(
|
|
db,
|
|
project_id,
|
|
current_user,
|
|
allowed_roles=["admin", "editor"],
|
|
)
|
|
|
|
result = await db.execute(select(ProjectGitRepo).where(ProjectGitRepo.id == repo_id, ProjectGitRepo.project_id == project_id))
|
|
repo = result.scalar_one_or_none()
|
|
|
|
if not repo:
|
|
raise HTTPException(status_code=404, detail="仓库不存在")
|
|
|
|
await db.delete(repo)
|
|
await db.commit()
|
|
|
|
return success_response(message="删除成功")
|