Sunday, July 12, 2015

Sonatype Nexus: Delete artifacts based on a selection

Sonatype Nexus provides several mechanisms to remove artifacts from the repository. You can schedule a job to keep only specified number of the latest releases (see here). You can also specifically remove a single artifact or an entire group using the API (see here). Suppose you want to make a selection though. I only want to delete artifacts from before a certain date with a specified groupid. In this article I have provided a Python 2.7 script which allows you to do just that.

The script has been created for my specific sample situation. Yours might differ. For example, I have only used the Releases repository and no snapshot versions. First check if the artifacts are the ones you expect to be selected based on your criteria before actually performing the artifact deletion. If they differ, it is easy to alter the script to suit your particular needs.

You can download the NetBeans 8.0.2 project containing the code of the script here. I've used the NetBeans Python plugin you can find here. Also I have not used any third party Python libraries so a default installation should suffice.

Script to delete artifacts

Configuration

The script starts with some configuration. First the connection information for Nexus followed by artifact selection criteria. Only the group is required. All other criteria can be left empty (None). If empty, any test related to the selection criteria passes. Thus for example setting the ARTIFACTVERSIONMIN to None means all previous versions could become part of the selection.

#how to access Nexus. used to build the URL in get_nexus_artifact_version_listing and get_nexus_artifact_names
NEXUSHOST = "localhost"
NEXUSPORT = "8081"
NEXUSREPOSITORY = "releases"
NEXUSBASEURL = "/nexus/service/local/repositories/"
NEXUSUSERNAME = 'admin'
NEXUSPASSWORD = 'admin123'

#what to delete
ARTIFACTGROUP = "nl.amis.smeetsm.application" #required
ARTIFACTNAME = None #"testproject" #can be an artifact name or None. None first searches for artifacts in the group
ARTIFACTVERSIONMIN = "1.1" #can be None or a version like 1.1
ARTIFACTVERSIONMAX = "1.2" #can be None or a version like 1.2
ARTIFACTMAXLASTMODIFIED = datetime.datetime.strptime("2014-10-29 12:00:00","%Y-%m-%d %H:%M:%S") #can be None or datetime in format like 2014-10-29 12:00:00
ARTIFACTMINLASTMODIFIED = datetime.datetime.strptime("2014-10-28 12:00:00","%Y-%m-%d %H:%M:%S") #can be None or datetime in format like 2014-10-28 12:00:00

What does the script do?

The script uses the Nexus API (see for example my previous post). If the artifact name is specified, that is used. Else the API is used to query for artifacts which are part of the specified group. When the artifacts are determined, artifact versions are looked at.

For example, a group nl.amis.smeetsm.application is specified and an artifact name of testproject is specified. This translates to an URL like;

http://localhost:8081/nexus/service/local/repositories/releases/content/nl/amis/smeetsm/application/testproject/

When I go to this URL in a browser, an XML is returned containing directory content which among others contain the artifact versions and several properties of these versions such as lastModified date. This I can then use in the selection.

If an artifact version is determined to be part of the provided selection, it is removed. Interesting about the actual removing of the artifact using the Nexus API is the Python usage of HTTP Basic Authentication. See for the sample I have used this as inspiration.

Seeing it work

My test situation looks at follows. testproject is my artifact name. I have 4 versions. 1.0, 1.2, 1.3, 1.4. 1.0 is the oldest one with a lastModifiedDate of 2014-10-28. I want to remove it.


I have used the following selection (delete testproject releases before 2014-10-29 12:00:00)

ARTIFACTGROUP = "nl.amis.smeetsm.application"
ARTIFACTNAME = "testproject"
ARTIFACTVERSIONMIN = None
ARTIFACTVERSIONMAX = None
ARTIFACTMAXLASTMODIFIED = datetime.datetime.strptime("2014-10-29 12:00:00","%Y-%m-%d %H:%M:%S")
ARTIFACTMINLASTMODIFIED = None

The output of the script is as follows;

Processing artifact: testproject
URL to determine artifact
versions:http://localhost:8081/nexus/service/local/repositories/releases/content/nl/amis/smeetsm/application/testproject/
Item datetime: 2015-07-11 14:43:32.0 UTC
Item version: 1.3
Item datetime: 2015-07-11 14:43:57.0 UTC
Item version: 1.4
Item datetime: 2014-10-28 18:20:49.0 UTC
Item version: 1.0
Artifact to be removed nl.amis.smeetsm.application: testproject: 1.0
Sending HTTP DELETE request to
http://localhost:8081/nexus/service/local/repositories/releases/content/nl/amis/smeetsm/application/testproject/1.0
Response:  204 No Content
Item datetime: 2014-11-03 13:36:43.0 UTC
Item version: 1.2

As you can see, all versions are evaluated and only one is selected and removed. The HTTP 204 indicates the action has been successful.

References

NetBeans Python plugin
http://plugins.netbeans.org/plugin/56795/python4netbeans802

Can I delete releases from Nexus after they have been published?
https://support.sonatype.com/entries/20871791-Can-I-delete-releases-from-Nexus-after-they-have-been-published-

curl : safely delete artifacts from Nexus
https://parkerwy.wordpress.com/2011/07/10/curl-safely-delete-artifacts-from-nexus/

Python: HTTP Basic authentication with httplib
http://mozgovipc.blogspot.nl/2012/06/python-http-basic-authentication-with.html

Retrieve Artifacts from Nexus Using the REST API or Apache Ivy
http://www.sonatype.org/nexus/2015/02/18/retrieve-artifacts-from-nexus-using-the-rest-api-or-apache-ivy/