diff --git a/docs/gl_objects/pipelines_and_jobs.rst b/docs/gl_objects/pipelines_and_jobs.rst index 0a3ddb1ec..627af1c06 100644 --- a/docs/gl_objects/pipelines_and_jobs.rst +++ b/docs/gl_objects/pipelines_and_jobs.rst @@ -326,3 +326,26 @@ Examples List bridges for the pipeline:: bridges = pipeline.bridges.list() + +Pipeline test report +==================== + +Get a pipeline's complete test report. + +Reference +--------- + +* v4 API + + + :class:`gitlab.v4.objects.ProjectPipelineTestReport` + + :class:`gitlab.v4.objects.ProjectPipelineTestReportManager` + + :attr:`gitlab.v4.objects.ProjectPipeline.test_report` + +* GitLab API: https://docs.gitlab.com/ee/api/pipelines.html#get-a-pipelines-test-report + +Examples +-------- + +Get the test report for a pipeline:: + + test_report = pipeline.test_report.get() diff --git a/gitlab/v4/objects/pipelines.py b/gitlab/v4/objects/pipelines.py index 644df7dcd..01f29b880 100644 --- a/gitlab/v4/objects/pipelines.py +++ b/gitlab/v4/objects/pipelines.py @@ -5,6 +5,7 @@ CreateMixin, CRUDMixin, DeleteMixin, + GetWithoutIdMixin, ListMixin, ObjectDeleteMixin, RefreshMixin, @@ -26,6 +27,8 @@ "ProjectPipelineScheduleVariableManager", "ProjectPipelineSchedule", "ProjectPipelineScheduleManager", + "ProjectPipelineTestReport", + "ProjectPipelineTestReportManager", ] @@ -34,6 +37,7 @@ class ProjectPipeline(RefreshMixin, ObjectDeleteMixin, RESTObject): ("jobs", "ProjectPipelineJobManager"), ("bridges", "ProjectPipelineBridgeManager"), ("variables", "ProjectPipelineVariableManager"), + ("test_report", "ProjectPipelineTestReportManager"), ) @cli.register_custom_action("ProjectPipeline") @@ -201,3 +205,13 @@ class ProjectPipelineScheduleManager(CRUDMixin, RESTManager): _update_attrs = RequiredOptional( optional=("description", "ref", "cron", "cron_timezone", "active"), ) + + +class ProjectPipelineTestReport(RESTObject): + _id_attr = None + + +class ProjectPipelineTestReportManager(GetWithoutIdMixin, RESTManager): + _path = "/projects/%(project_id)s/pipelines/%(pipeline_id)s/test_report" + _obj_cls = ProjectPipelineTestReport + _from_parent_attrs = {"project_id": "project_id", "pipeline_id": "id"} diff --git a/tests/unit/objects/test_pipelines.py b/tests/unit/objects/test_pipelines.py index d47429636..c0b87f225 100644 --- a/tests/unit/objects/test_pipelines.py +++ b/tests/unit/objects/test_pipelines.py @@ -4,7 +4,7 @@ import pytest import responses -from gitlab.v4.objects import ProjectPipeline +from gitlab.v4.objects import ProjectPipeline, ProjectPipelineTestReport pipeline_content = { "id": 46, @@ -35,6 +35,37 @@ } +test_report_content = { + "total_time": 5, + "total_count": 1, + "success_count": 1, + "failed_count": 0, + "skipped_count": 0, + "error_count": 0, + "test_suites": [ + { + "name": "Secure", + "total_time": 5, + "total_count": 1, + "success_count": 1, + "failed_count": 0, + "skipped_count": 0, + "error_count": 0, + "test_cases": [ + { + "status": "success", + "name": "Security Reports can create an auto-remediation MR", + "classname": "vulnerability_management_spec", + "execution_time": 5, + "system_output": None, + "stack_trace": None, + } + ], + } + ], +} + + @pytest.fixture def resp_get_pipeline(): with responses.RequestsMock() as rsps: @@ -74,6 +105,19 @@ def resp_retry_pipeline(): yield rsps +@pytest.fixture +def resp_get_pipeline_test_report(): + with responses.RequestsMock() as rsps: + rsps.add( + method=responses.GET, + url="http://localhost/api/v4/projects/1/pipelines/1/test_report", + json=test_report_content, + content_type="application/json", + status=200, + ) + yield rsps + + def test_get_project_pipeline(project, resp_get_pipeline): pipeline = project.pipelines.get(1) assert isinstance(pipeline, ProjectPipeline) @@ -92,3 +136,11 @@ def test_retry_project_pipeline(project, resp_retry_pipeline): output = pipeline.retry() assert output["ref"] == "master" + + +def test_get_project_pipeline_test_report(project, resp_get_pipeline_test_report): + pipeline = project.pipelines.get(1, lazy=True) + test_report = pipeline.test_report.get() + assert isinstance(test_report, ProjectPipelineTestReport) + assert test_report.total_time == 5 + assert test_report.test_suites[0]["name"] == "Secure"