Skip to content

Commit

Permalink
feat: deploy properties along with artifacts
Browse files Browse the repository at this point in the history
  • Loading branch information
anancarv authored Sep 20, 2024
2 parents e3fb56d + 71f63e3 commit 55675c4
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 9 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ This library enables you to manage Artifactory resources such as users, groups,
* [Artifacts](#artifacts)
+ [Get the information about a file or folder](#get-the-information-about-a-file-or-folder)
+ [Deploy an artifact](#deploy-an-artifact)
+ [Deploy an artifact with properties](#deploy-an-artifact-with-properties)
+ [Deploy an artifact with checksums](#deploy-an-artifact-with-checksums)
+ [Download an artifact](#download-an-artifact)
+ [Retrieve artifact list](#retrieve-artifact-list)
Expand Down Expand Up @@ -411,6 +412,13 @@ artifact = art.artifacts.deploy("<LOCAL_FILE_LOCATION>", "<ARTIFACT_PATH_IN_ARTI
# artifact = art.artifacts.deploy("Desktop/myNewFile.txt", "my-repository/my/new/artifact/directory/file.txt")
```

#### Deploy an artifact with properties

```python
artifact = art.artifacts.deploy("<LOCAL_FILE_LOCATION>", "<ARTIFACT_PATH_IN_ARTIFACTORY>", "<PROPERTIES>")
# artifact = art.artifacts.deploy("Desktop/myNewFile.txt", "my-repository/my/new/artifact/directory/file.txt", {"retention": ["30"]})
```

#### Deploy an artifact with checksums

```python
Expand Down
21 changes: 15 additions & 6 deletions pyartifactory/objects/artifact.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ def deploy(
self,
local_file_location: Union[Path, str],
artifact_path: Union[Path, str],
properties: Optional[Dict[str, List[str]]] = None,
checksum_enabled: bool = False,
) -> ArtifactInfoResponse:
"""
Expand All @@ -95,7 +96,7 @@ def deploy(
for root, _, files in os.walk(local_file.as_posix()):
new_root = f"{artifact_folder}/{root[len(local_file.as_posix()):]}"
for file in files:
self.deploy(Path(f"{root}/{file}"), Path(f"{new_root}/{file}"), checksum_enabled)
self.deploy(Path(f"{root}/{file}"), Path(f"{new_root}/{file}"), properties, checksum_enabled)
else:
if checksum_enabled:
artifact_check_sums = Checksums.generate(local_file)
Expand All @@ -120,7 +121,11 @@ def deploy(
raise ArtifactoryError from error
else:
with local_file.open("rb") as stream:
self._put(route=artifact_folder.as_posix(), data=stream)
properties_param_str = ""
if properties is not None:
properties_param_str = self._format_properties(properties)
route = ";".join(s for s in [artifact_folder.as_posix(), properties_param_str] if s)
self._put(route, data=stream)

logger.debug("Artifact %s successfully deployed", local_file)
return self.info(artifact_folder)
Expand Down Expand Up @@ -216,6 +221,13 @@ def list(
raise ArtifactNotFoundError(f"Artifact {artifact_path} does not exist")
raise ArtifactoryError from error

def _format_properties(self, properties: Dict[str, List[str]]):
properties_param_str = ""
for k, v in properties.items():
values_str = ",".join(v)
properties_param_str += f"{k}={values_str};"
return properties_param_str.rstrip(";")

def properties(self, artifact_path: str, properties: Optional[List[str]] = None) -> ArtifactPropertiesResponse:
"""
:param artifact_path: Path to file in Artifactory
Expand Down Expand Up @@ -253,10 +265,7 @@ def set_properties(
if properties is None:
properties = {}
artifact_path = artifact_path.lstrip("/")
properties_param_str = ""
for k, v in properties.items():
values_str = ",".join(v)
properties_param_str += f"{k}={values_str};"
properties_param_str = self._format_properties(properties)
try:
self._put(
f"api/storage/{artifact_path}",
Expand Down
74 changes: 71 additions & 3 deletions tests/test_artifacts.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ def test_set_property_success():
properties_param_str += urllib.parse.quote_plus(f"{k}={values_str};")
responses.add(
responses.PUT,
f"{URL}/api/storage/{ARTIFACT_PATH}?recursive=1&properties={properties_param_str}",
f"{URL}/api/storage/{ARTIFACT_PATH}?recursive=1&properties={properties_param_str.rstrip('%3B')}",
status=200,
)
responses.add(
Expand All @@ -424,6 +424,74 @@ def test_set_property_success():
assert set_properties_response == ARTIFACT_MULTIPLE_PROPERTIES


@responses.activate
def test_deploy_artifact_with_properties_success():
properties_param_str = ""
for k, v in ARTIFACT_ONE_PROPERTY.properties.items():
values_str = ",".join(v)
properties_param_str += f"{k}={values_str};"
responses.add(
responses.PUT,
f"{URL}/{ARTIFACT_PATH};{properties_param_str.rstrip(';')}",
status=200,
)
responses.add(
responses.GET,
f"{URL}/api/storage/{ARTIFACT_PATH}",
json=FILE_INFO_RESPONSE,
status=200,
)
responses.add(
responses.GET,
f"{URL}/api/storage/{ARTIFACT_PATH}?properties=prop1",
json=ARTIFACT_ONE_PROPERTY.model_dump(),
status=200,
)
artifactory = ArtifactoryArtifact(AuthModel(url=URL, auth=AUTH))
artifactory.deploy(
Path(LOCAL_FILE_LOCATION),
Path(ARTIFACT_PATH),
properties=ARTIFACT_ONE_PROPERTY.properties,
checksum_enabled=False,
)
artifact_properties = artifactory.properties(ARTIFACT_PATH, ["prop1"])
assert artifact_properties.model_dump() == ARTIFACT_ONE_PROPERTY.model_dump()


@responses.activate
def test_deploy_artifact_with_multiple_properties_success():
properties_param_str = ""
for k, v in ARTIFACT_MULTIPLE_PROPERTIES.properties.items():
values_str = ",".join(list(map(urllib.parse.quote, v)))
properties_param_str += f"{k}={values_str};"
responses.add(
responses.PUT,
f"{URL}/{ARTIFACT_PATH};{properties_param_str.rstrip(';')}",
status=200,
)
responses.add(
responses.GET,
f"{URL}/api/storage/{ARTIFACT_PATH}",
json=FILE_INFO_RESPONSE,
status=200,
)
responses.add(
responses.GET,
f"{URL}/api/storage/{ARTIFACT_PATH}?properties=prop1,prop2",
json=ARTIFACT_MULTIPLE_PROPERTIES.model_dump(),
status=200,
)
artifactory = ArtifactoryArtifact(AuthModel(url=URL, auth=AUTH))
artifactory.deploy(
Path(LOCAL_FILE_LOCATION),
Path(ARTIFACT_PATH),
properties=ARTIFACT_MULTIPLE_PROPERTIES.properties,
checksum_enabled=False,
)
artifact_properties = artifactory.properties(ARTIFACT_PATH, ["prop1", "prop2"])
assert artifact_properties.model_dump() == ARTIFACT_MULTIPLE_PROPERTIES.model_dump()


@responses.activate
def test_set_property_fail_artifact_not_found():
properties_param_str = ""
Expand All @@ -432,7 +500,7 @@ def test_set_property_fail_artifact_not_found():
properties_param_str += urllib.parse.quote_plus(f"{k}={values_str};")
responses.add(
responses.PUT,
f"{URL}/api/storage/{NX_ARTIFACT_PATH}?recursive=1&properties={properties_param_str}",
f"{URL}/api/storage/{NX_ARTIFACT_PATH}?recursive=1&properties={properties_param_str.rstrip('%3B')}",
status=404,
)
artifactory = ArtifactoryArtifact(AuthModel(url=URL, auth=AUTH))
Expand All @@ -443,7 +511,7 @@ def test_set_property_fail_artifact_not_found():

@responses.activate
def test_set_property_fail_bad_value():
properties_param_str = urllib.parse.quote_plus(f"{BAD_PROPERTY_NAME}={BAD_PROPERTY_VALUE};")
properties_param_str = urllib.parse.quote_plus(f"{BAD_PROPERTY_NAME}={BAD_PROPERTY_VALUE}")
responses.add(
responses.PUT,
f"{URL}/api/storage/{ARTIFACT_PATH}?recursive=1&properties={properties_param_str}",
Expand Down

0 comments on commit 55675c4

Please sign in to comment.