From 3a0cbb22e521071502fd61d9154d74bc93063af7 Mon Sep 17 00:00:00 2001 From: Eero Aaltonen Date: Wed, 10 Sep 2025 17:34:37 +0300 Subject: [PATCH 1/3] Rename get_build_runs reply object to BuildRuns --- pyartifactory/models/__init__.py | 4 ++-- pyartifactory/models/build.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pyartifactory/models/__init__.py b/pyartifactory/models/__init__.py index 9d2bca85..68a070ca 100644 --- a/pyartifactory/models/__init__.py +++ b/pyartifactory/models/__init__.py @@ -28,7 +28,7 @@ BuildPromotionRequest, BuildPromotionResult, BuildProperties, - BuildRun, + BuildRuns, Run, SimpleBuild, ) @@ -92,7 +92,7 @@ "SimpleBuild", "BuildListResponse", "Run", - "BuildRun", + "BuildRuns", "BuildArtifact", "BuildModules", "BuildAgent", diff --git a/pyartifactory/models/build.py b/pyartifactory/models/build.py index 67bd7736..31bcab87 100644 --- a/pyartifactory/models/build.py +++ b/pyartifactory/models/build.py @@ -44,7 +44,7 @@ class Run(BaseModel): started: str -class BuildRun(BaseModel): +class BuildRuns(BaseModel): """Models artifactory build runs.""" uri: str From 4deafb41aa88fd20d86924927d7169cf08640ed8 Mon Sep 17 00:00:00 2001 From: Eero Aaltonen Date: Wed, 10 Sep 2025 17:37:47 +0300 Subject: [PATCH 2/3] feat: add method to get build runs of build name --- README.md | 7 ++++++ pyartifactory/models/build.py | 2 +- pyartifactory/objects/build.py | 17 +++++++++++++++ tests/test_build.py | 40 ++++++++++++++++++++++++++++++++++ 4 files changed, 65 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0534111f..289c5014 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,7 @@ This library enables you to manage Artifactory resources such as users, groups, + [Delete an artifact](#delete-an-artifact) * [Builds](#builds) + [Get a list of all builds](#get-a-list-of-all-builds) + + [Get a list of build runs](#get-a-list-of-build-runs) + [Get the information about a build](#get-the-information-about-a-build) + [Create build](#create-build) + [Promote a build](#promote-a-build) @@ -513,6 +514,12 @@ art.artifacts.delete("") build_list: BuildListResponse = art.builds.list() ``` +#### Get a list of build runs + +```python +build_runs: BuildRuns = art.builds.get_build_runs("") +``` + #### Get the information about a build ```python diff --git a/pyartifactory/models/build.py b/pyartifactory/models/build.py index 31bcab87..896cc2a8 100644 --- a/pyartifactory/models/build.py +++ b/pyartifactory/models/build.py @@ -48,7 +48,7 @@ class BuildRuns(BaseModel): """Models artifactory build runs.""" uri: str - buildsNumber: Optional[List[Run]] = None + buildsNumbers: Optional[List[Run]] = None class BuildArtifact(BaseModel): diff --git a/pyartifactory/objects/build.py b/pyartifactory/objects/build.py index 55bacdbb..a6fc6192 100644 --- a/pyartifactory/objects/build.py +++ b/pyartifactory/objects/build.py @@ -17,6 +17,7 @@ BuildPromotionRequest, BuildPromotionResult, BuildProperties, + BuildRuns, ) from pyartifactory.objects.object import ArtifactoryObject @@ -28,6 +29,22 @@ class ArtifactoryBuild(ArtifactoryObject): _uri = "build" + def get_build_runs(self, build_name: str) -> BuildRuns: + """Provides information about the build runs for the given build name. + + :param build_name: Build name to be retrieved + :return: BuildRuns model object containing server response + """ + try: + response = self._get( + f"api/{self._uri}/{build_name}", + ) + logger.debug("Build Runs successfully retrieved") + except requests.exceptions.HTTPError as error: + self._raise_exception(error) + + return BuildRuns(**response.json()) + def get_build_info( self, build_name: str, diff --git a/tests/test_build.py b/tests/test_build.py index e2c9e25b..55c649f8 100644 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -18,11 +18,20 @@ BuildPromotionRequest, BuildPromotionResult, BuildProperties, + BuildRuns, + Run, ) URL = "http://localhost:8080/artifactory" AUTH = ("user", "password_or_apiKey") +BUILD_RUNS = BuildRuns( + uri=f"{URL}/api/build/build_name", + buildsNumbers=[ + Run(uri="/number", started="2025-09-05T19:55:09.593+0000"), + Run(uri="/other", started="2025-09-05T19:55:28.040+0000"), + ], +) BUILD_INFO = BuildInfo(uri=f"{URL}/api/build/build_name/number") BUILD_LIST_RESPONSE = BuildListResponse(uri=f"{URL}/api/build") BUILD_NOT_FOUND_ERROR = BuildError(errors=[{"status": 404, "message": "Not found"}]) @@ -44,6 +53,37 @@ NOT_FOUND_EXCEPTION_BODY = requests.exceptions.HTTPError(response=NOT_FOUND_HTTP_RESPONSE) +@responses.activate +def test_get_build_numbers_success(mocker): + responses.add( + responses.GET, + f"{URL}/api/build/build_name", + json=BUILD_RUNS.model_dump(), + status=200, + ) + + artifactory_build = ArtifactoryBuild(AuthModel(url=URL, auth=AUTH)) + mocker.spy(artifactory_build, "get_build_runs") + get_build_runs = artifactory_build.get_build_runs("build_name") + + assert isinstance(get_build_runs, BuildRuns) + assert get_build_runs == BUILD_RUNS + + +@responses.activate +def test_get_build_numbers_error(mocker): + responses.add( + responses.GET, + f"{URL}/api/build/non_build", + body=NOT_FOUND_EXCEPTION_BODY, + status=404, + ) + artifactory_build = ArtifactoryBuild(AuthModel(url=URL, auth=AUTH)) + mocker.spy(artifactory_build, "get_build_runs") + with pytest.raises(BuildNotFoundError): + artifactory_build.get_build_runs("non_build") + + @responses.activate def test_get_build_info_success(mocker): responses.add( From dd45a7dd6cc018dc720955d24c022035ca4a3ea9 Mon Sep 17 00:00:00 2001 From: Eero Aaltonen Date: Wed, 10 Sep 2025 17:41:20 +0300 Subject: [PATCH 3/3] Fix bandit pre-commit --- .pre-commit-config.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index df371c58..ec95a267 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -50,4 +50,6 @@ repos: hooks: - id: bandit args: ["-c", "pyproject.toml"] - additional_dependencies: ["bandit[toml]"] + additional_dependencies: + - "bandit[toml]" + - "pbr"