Files
headquarter/apps/api/src/services/git/files.py
T
Developer cccf4379d8 refactor: extract CSS modules for session/settings and delete styles.css (Task 2.3)
- Create InstanceList.module.css, AppShell.module.css, SettingsTabLayout.module.css
- Create CommitPanel.module.css, FileViewer.module.css
- Create page CSS files: sessions, repo-workspace, dashboard, projects,
  git-history, ssh-keys, settings
- Update components to import and use CSS modules
- Delete monolithic styles.css (2,255 lines)
- Update main.tsx to import page CSS and new modules

Quality gates: tsc (pass), eslint (pass), build (pass)
Refs: repo-restructure Task 2.3
2026-06-02 21:09:57 +00:00

151 lines
4.4 KiB
Python

"""Git file operations with repo validation."""
import logging
import uuid
from fastapi import HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession
from src.models.git_repository import GitRepository
from src.models.user import User
from src.schemas.git_repository import (
FileContentResponse,
FileListResponse,
FileUpdateRequest,
FileUpdateResponse,
)
from src.services.git.repository import ensure_repo_on_disk, get_repo_and_validate
from src.utils.git_files import (
commit_file,
get_file_content,
list_branches,
list_tree,
)
logger = logging.getLogger(__name__)
async def list_files(
session: AsyncSession,
project_id: uuid.UUID,
repo_id: uuid.UUID,
branch: str = "main",
path: str = "",
) -> FileListResponse:
repo = await get_repo_and_validate(session, repo_id, project_id)
ensure_repo_on_disk(repo)
try:
entries = list_tree(repo.path, branch=branch, path=path)
return FileListResponse(
path=path,
branch=branch,
entries=[
{
"name": e.name,
"type": e.type,
"path": e.path,
"size": e.size,
"mode": e.mode,
"last_commit": e.last_commit,
}
for e in entries
],
)
except RuntimeError as e:
logger.error(
"Failed to list files for repo %s (path=%s, branch=%s): %s",
repo_id,
path,
branch,
str(e),
exc_info=True,
)
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
async def get_file(
session: AsyncSession,
project_id: uuid.UUID,
repo_id: uuid.UUID,
branch: str,
path: str,
) -> FileContentResponse:
repo = await get_repo_and_validate(session, repo_id, project_id)
ensure_repo_on_disk(repo)
try:
file_content = get_file_content(repo.path, branch=branch, path=path)
return FileContentResponse(
path=file_content.path,
branch=file_content.branch,
content=file_content.content,
size=file_content.size,
encoding=file_content.encoding,
language=file_content.language,
is_binary=file_content.is_binary,
last_commit=file_content.last_commit,
)
except FileNotFoundError:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="file not found")
except RuntimeError as e:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
async def update_file(
session: AsyncSession,
project_id: uuid.UUID,
repo_id: uuid.UUID,
data: FileUpdateRequest,
user: User,
) -> FileUpdateResponse:
repo = await get_repo_and_validate(session, repo_id, project_id)
ensure_repo_on_disk(repo)
author_name = user.name or "Unknown"
author_email = user.email or "unknown@example.com"
try:
commit_hash = commit_file(
repo_path=repo.path,
branch=data.branch,
path=data.path,
content=data.content,
commit_message=data.commit_message,
author_name=author_name,
author_email=author_email,
)
return FileUpdateResponse(
commit_hash=commit_hash,
message=data.commit_message,
branch=data.branch,
)
except RuntimeError as e:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
async def list_branches_with_validation(
session: AsyncSession,
project_id: uuid.UUID,
repo_id: uuid.UUID,
) -> dict:
repo = await get_repo_and_validate(session, repo_id, project_id)
ensure_repo_on_disk(repo)
try:
branches, default_branch = list_branches(repo.path)
return {
"branches": [
{
"name": b.name,
"is_default": b.is_default,
"last_commit": b.last_commit,
}
for b in branches
],
"default_branch": default_branch,
}
except RuntimeError as e:
logger.error(
"Failed to list branches for repo %s: %s",
repo_id,
str(e),
exc_info=True,
)
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))