diff --git a/README.md b/README.md index d97eddf9..5282b7e2 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ This library enables you to manage Artifactory resources such as users, groups, + [Retrieve artifact properties](#retrieve-artifact-properties) + [Set artifact properties](#set-artifact-properties) + [Update artifact properties](#update-artifact-properties) + + [Delete all artifact properties](#delete-all-artifact-properties) + [Retrieve artifact stats](#retrieve-artifact-stats) + [Copy artifact to a new location](#copy-artifact-to-a-new-location) + [Move artifact to a new location](#move-artifact-to-a-new-location) @@ -425,6 +426,11 @@ artifact_properties = art.artifacts.update_properties("", {"prop1": ["value"], "prop2": ["value1", "value2", "etc"}, False) # disable recursive mode ``` +#### Delete all artifact properties +```python +artifact_properties = art.artifacts.delete_properties("") +``` + #### Retrieve artifact stats ```python artifact_stats = art.artifacts.stats("") diff --git a/pyartifactory/objects/artifact.py b/pyartifactory/objects/artifact.py index 66f18c5d..e3a816f7 100644 --- a/pyartifactory/objects/artifact.py +++ b/pyartifactory/objects/artifact.py @@ -247,6 +247,26 @@ def set_properties( raise BadPropertiesError("A property value includes forbidden special characters") raise ArtifactoryError from error + def delete_properties( + self, + artifact_path: str, + ) -> ArtifactPropertiesResponse: + """ + Deletes ALL properties of an artifact + :param artifact_path: Path to file or folder in Artifactory + :return: None + """ + artifact_path = artifact_path.lstrip("/") + try: + self._delete(f"api/metadata/{artifact_path}") + logger.debug("Artifact Properties successfully deleted") + return ArtifactPropertiesResponse(uri=artifact_path, properties={}) + except requests.exceptions.HTTPError as error: + http_response: Union[Response, None] = error.response + if isinstance(http_response, Response) and http_response.status_code == 404: + raise PropertyNotFoundError(f"No properties could be found on artifact {artifact_path}") + raise ArtifactoryError from error + def update_properties( self, artifact_path: str, diff --git a/tests/test_artifacts.py b/tests/test_artifacts.py index 1c0e9d00..37d8e054 100644 --- a/tests/test_artifacts.py +++ b/tests/test_artifacts.py @@ -501,3 +501,36 @@ def test_update_property_fail_bad_value(): {BAD_PROPERTY_NAME: [BAD_PROPERTY_VALUE]}, ) assert update_properties_response is None + + +@responses.activate +def test_delete_property_success(): + properties_param_str = "" + for k, v in ARTIFACT_MULTIPLE_PROPERTIES.properties.items(): + values_str = ",".join(v) + 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}", + status=200, + ) + responses.add( + responses.GET, + f"{URL}/api/storage/{ARTIFACT_PATH}?properties=", + json=ARTIFACT_MULTIPLE_PROPERTIES.model_dump(), + status=200, + ) + artifactory = ArtifactoryArtifact(AuthModel(url=URL, auth=AUTH)) + set_properties_response = artifactory.set_properties(ARTIFACT_PATH, ARTIFACT_MULTIPLE_PROPERTIES.properties) + assert set_properties_response == ARTIFACT_MULTIPLE_PROPERTIES + + ARTIFACT_MULTIPLE_PROPERTIES.properties = {} + + responses.add( + responses.DELETE, + f"{URL}/api/metadata/{ARTIFACT_PATH}", + status=204, + ) + + delete_props_response = artifactory.delete_properties(ARTIFACT_PATH).properties + assert delete_props_response == {}