Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions git0/api/deps.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,19 @@ async def get_organization_service(


async def get_repository_service(
db: Annotated[AsyncSession, Depends(get_db)]
db: Annotated[AsyncSession, Depends(get_db)],
s3_storage: Annotated[S3Storage, Depends(get_s3_storage)], # Added S3Storage dependency
) -> RepositoryService:
"""Get a repository service instance.

Args:
db: The database session
s3_storage: The S3 storage instance

Returns:
RepositoryService: The repository service
"""
return RepositoryService(db)
return RepositoryService(db, s3_storage) # Pass s3_storage to constructor


async def get_issue_service(
Expand All @@ -94,17 +96,19 @@ async def get_issue_service(


async def get_pull_request_service(
db: Annotated[AsyncSession, Depends(get_db)]
db: Annotated[AsyncSession, Depends(get_db)],
s3_storage: Annotated[S3Storage, Depends(get_s3_storage)], # Added S3Storage dependency
) -> PullRequestService:
"""Get a pull request service.

Args:
db: The database session
s3_storage: The S3 storage instance

Returns:
PullRequestService: The pull request service
"""
return PullRequestService(db)
return PullRequestService(db, s3_storage) # Pass s3_storage to constructor


async def get_commit_service(
Expand Down
166 changes: 166 additions & 0 deletions git0/api/v1/branches.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
"""Branches API router for Git0."""

from fastapi import APIRouter, Depends, HTTPException, status, Response

from git0.api.deps import get_repository_service
from git0.core.exceptions import NotFoundError, ConflictError
from git0.models.branch import BranchRead, BranchCreate # Added BranchCreate
from git0.services.repository import RepositoryService

router = APIRouter(prefix="/orgs/{org_name}/repos/{repo_name}/branches", tags=["branches"])


@router.get(
"",
response_model=list[BranchRead],
summary="List Repository Branches",
responses={
status.HTTP_404_NOT_FOUND: {"description": "Organization or repository not found."},
status.HTTP_500_INTERNAL_SERVER_ERROR: {"description": "An unexpected error occurred while listing branches."},
},
)
async def list_repository_branches(
org_name: str,
repo_name: str,
service: RepositoryService = Depends(get_repository_service),
) -> list[BranchRead]:
"""
Retrieve a list of all branches in the specified repository.

Each branch object in the list includes its name and the SHA of its head commit.
"""
try:
return await service.list_branches(
organization_name=org_name, repository_name=repo_name
)
except Exception as e:
# Log the exception e
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"An unexpected error occurred while listing branches: {str(e)}",
)


@router.get(
"/{branch_name:path}",
response_model=BranchRead,
summary="Get a Specific Branch",
responses={
status.HTTP_404_NOT_FOUND: {"description": "Organization, repository, or branch not found."},
status.HTTP_409_CONFLICT: {"description": "Error retrieving branch details (e.g., invalid SHA content)."},
status.HTTP_500_INTERNAL_SERVER_ERROR: {"description": "An unexpected error occurred while getting the branch."},
},
)
async def get_repository_branch(
org_name: str,
repo_name: str,
branch_name: str, # Path parameter allows slashes, e.g., "feature/new-ux"
service: RepositoryService = Depends(get_repository_service),
) -> BranchRead:
"""
Retrieve details for a specific branch within a repository.

The `branch_name` can include slashes if it's a hierarchical branch (e.g., `feature/login`).
Returns the branch name and the SHA of its head commit.
"""
try:
return await service.get_branch(
organization_name=org_name,
repository_name=repo_name,
branch_name=branch_name,
)
except NotFoundError as e:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))
except ConflictError as e: # If get_branch raises ConflictError for other issues
raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail=str(e))
except Exception as e:
# Log the exception e
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"An unexpected error occurred while getting branch '{branch_name}': {str(e)}",
)


@router.post(
"",
response_model=BranchRead,
status_code=status.HTTP_201_CREATED,
summary="Create a New Branch",
responses={
status.HTTP_404_NOT_FOUND: {"description": "Organization, repository, or source commit SHA not found."},
status.HTTP_409_CONFLICT: {"description": "Branch already exists or other conflict during creation."},
status.HTTP_422_UNPROCESSABLE_ENTITY: {"description": "Validation error, e.g., invalid branch name format or invalid source SHA format."},
status.HTTP_500_INTERNAL_SERVER_ERROR: {"description": "An unexpected error occurred while creating the branch."},
},
)
async def create_new_branch(
org_name: str,
repo_name: str,
branch_create: BranchCreate,
service: RepositoryService = Depends(get_repository_service),
) -> BranchRead:
"""
Create a new branch in the specified repository.

The new branch will point to the commit specified by `source_sha`.
Branch names must adhere to Git reference naming conventions.
"""
try:
return await service.create_branch(
organization_name=org_name,
repository_name=repo_name,
branch_create=branch_create,
)
except NotFoundError as e:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))
except ConflictError as e:
raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail=str(e))
except ValueError as e: # Catch Pydantic validation errors for branch name or SHA
raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(e))
except Exception as e:
# Log the exception e
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"An unexpected error occurred while creating branch '{branch_create.name}': {str(e)}",
)


@router.delete(
"/{branch_name:path}",
status_code=status.HTTP_204_NO_CONTENT,
summary="Delete a Branch",
responses={
status.HTTP_404_NOT_FOUND: {"description": "Organization, repository, or branch not found."},
status.HTTP_409_CONFLICT: {"description": "Error during deletion process (e.g., could not verify branch for deletion)."},
status.HTTP_500_INTERNAL_SERVER_ERROR: {"description": "An unexpected error occurred while deleting the branch."},
},
)
async def delete_repository_branch(
org_name: str,
repo_name: str,
branch_name: str, # Path parameter allows slashes
service: RepositoryService = Depends(get_repository_service),
) -> Response:
"""
Delete a specific branch from the repository.

The `branch_name` can include slashes if it's a hierarchical branch.
This operation is permanent and cannot be undone through the API.
"""
try:
await service.delete_branch(
organization_name=org_name,
repository_name=repo_name,
branch_name=branch_name,
)
return Response(status_code=status.HTTP_204_NO_CONTENT)
except NotFoundError as e:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))
except ConflictError as e: # If delete_branch raises ConflictError for other issues
raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail=str(e))
except Exception as e:
# Log the exception e
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"An unexpected error occurred while deleting branch '{branch_name}': {str(e)}",
)
2 changes: 1 addition & 1 deletion git0/api/v1/git_http.py
Original file line number Diff line number Diff line change
Expand Up @@ -679,7 +679,7 @@ async def notify_push(
return {"ref_updates": response_ref_updates}


@router.post("/orgs/{org_name}/repos/{repo_name}.git/git-remote-config")
@router.get("/orgs/{org_name}/repos/{repo_name}/git-remote-config")
async def get_git_remote_config(
org_name: Annotated[str, Path(description="Organization name.")],
repo_name: Annotated[str, Path(description="Repository name.")],
Expand Down
Loading