Skip to content
Merged
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
4 changes: 3 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,6 @@ repos:
hooks:
- id: bandit
args: ["-c", "pyproject.toml"]
additional_dependencies: ["bandit[toml]"]
additional_dependencies:
- "bandit[toml]"
- "pbr"
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -513,6 +514,12 @@ art.artifacts.delete("<ARTIFACT_PATH_IN_ARTIFACTORY>")
build_list: BuildListResponse = art.builds.list()
```

#### Get a list of build runs

```python
build_runs: BuildRuns = art.builds.get_build_runs("<build_name>")
```

#### Get the information about a build

```python
Expand Down
4 changes: 2 additions & 2 deletions pyartifactory/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
BuildPromotionRequest,
BuildPromotionResult,
BuildProperties,
BuildRun,
BuildRuns,
Run,
SimpleBuild,
)
Expand Down Expand Up @@ -92,7 +92,7 @@
"SimpleBuild",
"BuildListResponse",
"Run",
"BuildRun",
"BuildRuns",
"BuildArtifact",
"BuildModules",
"BuildAgent",
Expand Down
4 changes: 2 additions & 2 deletions pyartifactory/models/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@ class Run(BaseModel):
started: str


class BuildRun(BaseModel):
class BuildRuns(BaseModel):
"""Models artifactory build runs."""

uri: str
buildsNumber: Optional[List[Run]] = None
buildsNumbers: Optional[List[Run]] = None


class BuildArtifact(BaseModel):
Expand Down
17 changes: 17 additions & 0 deletions pyartifactory/objects/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
BuildPromotionRequest,
BuildPromotionResult,
BuildProperties,
BuildRuns,
)
from pyartifactory.objects.object import ArtifactoryObject

Expand All @@ -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,
Expand Down
40 changes: 40 additions & 0 deletions tests/test_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"}])
Expand All @@ -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(
Expand Down
Loading