From ccec32180c54f45b9fbff621738fba7d735718a3 Mon Sep 17 00:00:00 2001 From: Frank Niessink Date: Fri, 15 Nov 2024 18:28:17 +0100 Subject: [PATCH] Add a result type parameter to the 'jobs within time period' metric. Add a result type parameter to the 'jobs within time period' metric for the sources: - Azure DevOps - GitLab (todo) - Jenkins (todo) Closes #9926. --- .../src/source_collectors/azure_devops/base.py | 3 ++- .../azure_devops/job_runs_within_time_period.py | 3 ++- .../tests/source_collectors/azure_devops/base.py | 2 ++ .../test_job_runs_within_time_period.py | 15 +++++++++++++++ .../src/shared_data_model/parameters.py | 9 +++++++++ .../src/shared_data_model/sources/azure_devops.py | 7 ++++++- docs/src/changelog.md | 1 + 7 files changed, 37 insertions(+), 3 deletions(-) diff --git a/components/collector/src/source_collectors/azure_devops/base.py b/components/collector/src/source_collectors/azure_devops/base.py index 29b58892a3..de6d1e3ade 100644 --- a/components/collector/src/source_collectors/azure_devops/base.py +++ b/components/collector/src/source_collectors/azure_devops/base.py @@ -107,8 +107,8 @@ async def _api_url(self) -> URL: async def _api_pipelines_url(self, pipeline_id: int | None = None) -> URL: """Add the pipelines API, or runs API path if needed.""" extra_path = "" if not pipeline_id else f"/{pipeline_id}/runs" - # currently the pipelines api is not available in any version which is not a -preview version api_url = await SourceCollector._api_url(self) # noqa: SLF001 + # Use the oldest API version in which the endpoint is available: return URL(f"{api_url}/_apis/pipelines{extra_path}?api-version=6.0-preview.1") async def _active_pipelines(self) -> list[int]: @@ -148,6 +148,7 @@ async def _parse_pipeline_entities(pipeline_response: Response) -> Entities: pipeline=pipeline_name, url=pipeline_run["_links"]["web"]["href"], build_date=str(parse_datetime(pipeline_run["finishedDate"])), + build_result=pipeline_run.get("result", "unknown"), build_status=pipeline_run["state"], ), ) diff --git a/components/collector/src/source_collectors/azure_devops/job_runs_within_time_period.py b/components/collector/src/source_collectors/azure_devops/job_runs_within_time_period.py index 65d228d355..a76a9993d4 100644 --- a/components/collector/src/source_collectors/azure_devops/job_runs_within_time_period.py +++ b/components/collector/src/source_collectors/azure_devops/job_runs_within_time_period.py @@ -17,4 +17,5 @@ def _include_entity(self, entity: Entity) -> bool: return False build_age = days_ago(parse_datetime(entity["build_date"])) max_build_age = int(cast(str, self._parameter("lookback_days_pipeline_runs"))) - return build_age <= max_build_age + result_types = cast(list[str], self._parameter("result_type")) + return build_age <= max_build_age and entity["build_result"] in result_types diff --git a/components/collector/tests/source_collectors/azure_devops/base.py b/components/collector/tests/source_collectors/azure_devops/base.py index af3ce87a2a..3c0a2c2b08 100644 --- a/components/collector/tests/source_collectors/azure_devops/base.py +++ b/components/collector/tests/source_collectors/azure_devops/base.py @@ -130,6 +130,7 @@ def setUp(self): "key": f"{self.test_pipeline['id']}-20191015_1", # safe_entity_key "url": f"{self.url}/_build/results?buildId=1", "build_date": "2019-10-15 12:24:10.190586+00:00", + "build_result": "succeeded", "build_status": "completed", }, { @@ -138,6 +139,7 @@ def setUp(self): "key": f"{self.test_pipeline['id']}-20191015_2", # safe_entity_key "url": f"{self.url}/_build/results?buildId=2", "build_date": "2019-10-15 12:34:10.190586+00:00", + "build_result": "succeeded", "build_status": "completed", }, ] diff --git a/components/collector/tests/source_collectors/azure_devops/test_job_runs_within_time_period.py b/components/collector/tests/source_collectors/azure_devops/test_job_runs_within_time_period.py index 75fbfbbf73..05a13d0271 100644 --- a/components/collector/tests/source_collectors/azure_devops/test_job_runs_within_time_period.py +++ b/components/collector/tests/source_collectors/azure_devops/test_job_runs_within_time_period.py @@ -33,6 +33,20 @@ async def test_pipeline_runs_jobs_exclude(self): self.assert_measurement(response, value="0", entities=[]) + async def test_pipeline_runs_jobs_exclude_by_result_type(self): + """Test that the pipeline runs are filtered by result type.""" + self.set_source_parameter("lookback_days_pipeline_runs", "424242") + self.set_source_parameter("result_type", ["succeeded"]) + + response = await self.collect( + get_request_json_return_value=self.pipeline_runs, + get_request_json_side_effect=[self.pipelines, self.pipeline_runs], + ) + + expected_entities = [entity for entity in self.expected_entities if entity.get("build_result") == "succeeded"] + self.assert_measurement(response, value=str(len(expected_entities)), entities=expected_entities) + + async def test_pipeline_runs_jobs_empty_include(self): """Test that counting pipeline runs filtered by a not-matching name include, works.""" self.set_source_parameter("lookback_days_pipeline_runs", "424242") @@ -92,6 +106,7 @@ async def test_pipeline_runs_lookback_days(self): "key": f"{self.test_pipeline['id']}-{build_date_str}_1", # safe_entity_key "url": f"{self.url}/_build/results?buildId=6", "build_date": str(now_dt), + "build_result": "succeeded", "build_status": "completed", }, ] diff --git a/components/shared_code/src/shared_data_model/parameters.py b/components/shared_code/src/shared_data_model/parameters.py index d185618956..f0574af462 100644 --- a/components/shared_code/src/shared_data_model/parameters.py +++ b/components/shared_code/src/shared_data_model/parameters.py @@ -196,6 +196,15 @@ class FailureType(MultipleChoiceParameter): metrics: list[str] = ["failed_jobs"] +class ResultType(MultipleChoiceParameter): + """Job or pipeline result type parameter.""" + + name: str = "Result types" + help: str = "Limit which result types to include." + placeholder: str = "all result types" + metrics: list[str] = ["job_runs_within_time_period"] + + def access_parameters( metrics: list[str], include: dict[str, bool] | None = None, diff --git a/components/shared_code/src/shared_data_model/sources/azure_devops.py b/components/shared_code/src/shared_data_model/sources/azure_devops.py index 6da9e7fac3..9e5bc8edbb 100644 --- a/components/shared_code/src/shared_data_model/sources/azure_devops.py +++ b/components/shared_code/src/shared_data_model/sources/azure_devops.py @@ -14,6 +14,7 @@ MultipleChoiceParameter, MultipleChoiceWithAdditionParameter, PrivateToken, + ResultType, StringParameter, TargetBranchesToInclude, TestResult, @@ -46,11 +47,14 @@ EntityAttribute( name="Status of most recent build", key="build_status", + ), + EntityAttribute( + name="Result of most recent build", + key="build_result", color={ "succeeded": Color.POSITIVE, "failed": Color.NEGATIVE, "canceled": Color.ACTIVE, - "partiallySucceeded": Color.WARNING, }, ), EntityAttribute(name="Date of most recent build", key="build_date", type=EntityAttributeType.DATE), @@ -193,6 +197,7 @@ values=["canceled", "failed", "no result", "partially succeeded"], api_values={"no result": "none", "partially succeeded": "partiallySucceeded"}, ), + "result_type": ResultType(values=["canceled", "failed", "succeeded", "unknown"]), "merge_request_state": MergeRequestState( values=["abandoned", "active", "completed", "not set"], api_values={"not set": "notSet"}, diff --git a/docs/src/changelog.md b/docs/src/changelog.md index dbe7882858..68440990a2 100644 --- a/docs/src/changelog.md +++ b/docs/src/changelog.md @@ -17,6 +17,7 @@ If your currently installed *Quality-time* version is not the latest version, pl ### Added - Allow for measuring the time since the last analysis date of a Bill-of-Materials (BOM) in Dependency-Track using the new 'project event type' parameter of the 'source up-to-dateness' metric. Closes [#9764](https://github.com/ICTU/quality-time/issues/9764). +- Add a result type parameter to the 'jobs within time period' metric. Closes [#9926](https://github.com/ICTU/quality-time/issues/9926). - Allow for using Visual Studio test reports (.trx) as source for the metrics 'tests', 'test cases', and 'source up-to-dateness'. Closes [#10009](https://github.com/ICTU/quality-time/issues/10009). ## v5.18.0 - 2024-11-06