diff --git a/app/api/v1/endpoints/pipelines.py b/app/api/v1/endpoints/pipelines.py index 6560617..01c5411 100644 --- a/app/api/v1/endpoints/pipelines.py +++ b/app/api/v1/endpoints/pipelines.py @@ -152,3 +152,33 @@ async def list_executions( raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Access denied") return await pipeline_service.list_pipeline_executions(db, pipeline_id=pipeline_id) + + +@router.get("/{pipeline_id}/executions/{execution_id}", response_model=PipelineExecutionResponse) +async def get_execution( + pipeline_id: int, + execution_id: int, + db: AsyncSession = Depends(deps.get_db), + current_user: User = Depends(deps.get_current_active_user), +) -> Any: + """Get specific pipeline execution details.""" + # Verify pipeline exists and user has access + pipeline = await pipeline_service.get_pipeline(db, pipeline_id=pipeline_id) + if not pipeline: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Pipeline not found") + + project = await project_service.get_project(db, project_id=pipeline.project_id) + role = await team_service.get_user_role_in_team(db, team_id=project.team_id, user_id=current_user.id) + if not role and not current_user.is_superuser: + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Access denied") + + # Get execution details + execution = await pipeline_service.get_pipeline_execution(db, execution_id=execution_id) + if not execution: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Execution not found") + + # Verify execution belongs to the specified pipeline + if execution.pipeline_id != pipeline_id: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Execution not found for this pipeline") + + return execution diff --git a/app/services/pipeline.py b/app/services/pipeline.py index d880cfe..02d02d2 100644 --- a/app/services/pipeline.py +++ b/app/services/pipeline.py @@ -6,6 +6,9 @@ from app.models.base import Pipeline, PipelineExecution from app.schemas.pipeline import PipelineCreate, PipelineUpdate from app.services.events import events +import logging + +logger = logging.getLogger(__name__) async def create_pipeline(db: AsyncSession, pipeline_in: PipelineCreate) -> Pipeline: diff --git a/tests/unit/test_pipeline_service.py b/tests/unit/test_pipeline_service.py index 711025e..be12e89 100644 --- a/tests/unit/test_pipeline_service.py +++ b/tests/unit/test_pipeline_service.py @@ -84,3 +84,31 @@ async def test_list_pipeline_executions_unit(): assert len(executions) == 1 assert executions[0].status == "success" +@pytest.mark.asyncio +async def test_get_pipeline_execution_unit(): + """Test getting a specific pipeline execution.""" + mock_db = AsyncMock() + mock_result = MagicMock() + mock_execution = PipelineExecution(id=1, pipeline_id=1, status="completed") + mock_result.scalars.return_value.first.return_value = mock_execution + mock_db.execute.return_value = mock_result + + execution = await pipeline_service.get_pipeline_execution(mock_db, execution_id=1) + + assert execution is not None + assert execution.id == 1 + assert execution.status == "completed" + assert execution.pipeline_id == 1 + +@pytest.mark.asyncio +async def test_get_pipeline_execution_not_found_unit(): + """Test getting a non-existent pipeline execution.""" + mock_db = AsyncMock() + mock_result = MagicMock() + mock_result.scalars.return_value.first.return_value = None + mock_db.execute.return_value = mock_result + + execution = await pipeline_service.get_pipeline_execution(mock_db, execution_id=999) + + assert execution is None +