Use Maven snapshots - CodeArtifact

Use Maven snapshots

A Maven snapshot is a special version of a Maven package that refers to the latest production branch code. It is a development version that precedes the final release version. You can identify a snapshot version of a Maven package by the suffix SNAPSHOT that's appended to the package version. For example, the snapshot of version 1.1 is 1.1-SNAPSHOT. For more information, see What is a SNAPSHOT version? on the Apache Maven Project website.

AWS CodeArtifact supports publishing and consuming Maven snapshots. Unique snapshots that use a time-based version number are the only snapshots that are supported. CodeArtifact doesn't support non-unique snapshots that are generated by Maven 2 clients. You can publish a supported Maven snapshot to any CodeArtifact repository.

Snapshot publishing in CodeArtifact

AWS CodeArtifact supports the request patterns that clients, such as mvn, use when publishing snapshots. Because of this, you can follow the documentation for your build tool or package manager without having a detailed understanding of how Maven snapshots are published. If you’re doing something more complex, this section describes in detail how CodeArtifact handles snapshots.

When a Maven snapshot is published to a CodeArtifact repository, its previous version is preserved in a new version called a build. Each time a Maven snapshot is published, a new build version is created. All previous versions of a snapshot are maintained in its build versions. When a Maven snapshot is published, its package version status is set to Published and the status of the build that contains the previous version is set to Unlisted. This behavior applies only to Maven package versions where the package version has -SNAPSHOT as a suffix.

For example, snapshot versions of a maven package called com.mycompany.myapp:pkg-1 are uploaded to a CodeArtifact repository called my-maven-repo. The snapshot version is 1.0-SNAPSHOT. So far, no versions of com.mycompany.myapp:pkg-1 have been published. First, the assets of the initial build are published at these paths:

PUT maven/my-maven-repo/com/mycompany/myapp/pkg-1/1.0-SNAPSHOT/pkg-1-1.0-20210728.194552-1.jar PUT maven/my-maven-repo/com/mycompany/myapp/pkg-1/1.0-SNAPSHOT/pkg-1-1.0-20210728.194552-1.pom

Note that the timestamp 20210728.194552-1 is generated by the client publishing the snapshot builds.

After the .pom and .jar files are uploaded, the only version of com.mycompany.myapp:pkg-1 that exists in the repository is 1.0-20210728.194552-1. This happens even though the version specified in the preceding path is 1.0-SNAPSHOT. The package version status at this point is Unfinished.

aws codeartifact list-package-versions --domain my-domain --repository \ my-maven-repo --package pkg-1 --namespace com.mycompany.myapp --format maven { "versions": [ { "version": "1.0-20210728.194552-1", "revision": "GipMW+599JmwTcTLaXo9YvDsVQ2bcrrk/02rWJhoKUU=", "status": "Unfinished" } ], "defaultDisplayVersion": null, "format": "maven", "package": "pkg-1", "namespace": "com.mycompany.myapp" }

Next, the client uploads the maven-metadata.xml file for the package version:

PUT my-maven-repo/com/mycompany/myapp/pkg-1/1.0-SNAPSHOT/maven-metadata.xml

When the maven-metadata.xml file is uploaded successfully, CodeArtifact creates the 1.0-SNAPSHOT package version and sets the 1.0-20210728.194552-1 version to Unlisted.

aws codeartifact list-package-versions --domain my-domain --repository \ my-maven-repo --package pkg-1 --namespace com.mycompany.myapp --format maven { "versions": [ { "version": "1.0-20210728.194552-1", "revision": "GipMW+599JmwTcTLaXo9YvDsVQ2bcrrk/02rWJhoKUU=", "status": "Unlisted" }, { "version": "1.0-SNAPSHOT", "revision": "tWu8n3IX5HR82vzVZQAxlwcvvA4U/+S80edWNAkil24=", "status": "Published" } ], "defaultDisplayVersion": "1.0-SNAPSHOT", "format": "maven", "package": "pkg-1", "namespace": "com.mycompany.myapp" }

At this point, the snapshot version 1.0-SNAPSHOT can be consumed in a build. While there are two versions of com.mycompany.myapp:pkg-1 in the repository my-maven-repo, they both contain the same assets.

aws codeartifact list-package-version-assets --domain my-domain --repository \ my-maven-repo --format maven --namespace com.mycompany.myapp \ --package pkg-1 --package-version 1.0-SNAPSHOT--query 'assets[*].name' [ "pkg-1-1.0-20210728.194552-1.jar", "pkg-1-1.0-20210728.194552-1.pom" ]

Running the same list-package-version-assets command as shown previously with the --package-version parameter changed to 1.0-20210728.194552-1 results in an identical output.

As additional builds of 1.0-SNAPSHOT are added to the repository, a new Unlisted package version is created for each new build. The assets of the version 1.0-SNAPSHOT are updated each time so that the version always refers to the latest build for that version. Updating the 1.0-SNAPSHOT with the latest assets is initiated by uploading the maven-metadata.xml file for the new build.

Consuming snapshot versions

If you request a snapshot, the version with the status Published is returned. This is always the most recent version of the Maven snapshot. You can also request a particular build of a snapshot using the build version number (for example, 1.0-20210728.194552-1) instead of the snapshot version (for example, 1.0-SNAPSHOT) in the URL path. To see the build versions of a Maven snapshot, use the ListPackageVersions API in the CodeArtifact API Guide and set the status parameter to Unlisted.

Deleting snapshot versions

To delete all build versions of a Maven snapshot, use the DeletePackageVersions API, specifying the versions that you want to delete.

Snapshot publishing with curl

If you have existing snapshot versions stored in Amazon Simple Storage Service (Amazon S3) or another artifact repository product, you may want to republish them to AWS CodeArtifact. Because of how CodeArtifact supports Maven snapshots (see Snapshot publishing in CodeArtifact), publishing snapshots with a generic HTTP client such as curl is more complex than publishing Maven release versions as described in Publishing with curl. Note that this section isn’t relevant if you’re building and deploying snapshot versions with a Maven client such as mvn or gradle. You need to follow the documentation for that client.

Publishing a snapshot version involves publishing one or more builds of a snapshot version. In CodeArtifact, if there are n builds of a snapshot version, there will be n + 1 CodeArtifact versions: n build versions all with a status of Unlisted, and one snapshot version (the latest published build) with a status of Published. The snapshot version (that is, the version with a version string that contains “-SNAPSHOT”) contains an identical set of assets to the latest published build. The simplest way to create this structure using curl is as follows:

  1. Publish all assets of all builds using curl.

  2. Publish the maven-metadata.xml file of the last build (that is, the build with the most-recent date-time stamp) with curl. This will create a version with “-SNAPSHOT” in the version string and with the correct set of assets.

  3. Use the UpdatePackageVersionsStatus API to set the status of all the non-latest build versions to Unlisted.

Use the following curl commands to publish snapshot assets (such as .jar and .pom files) for the snapshot version 1.0-SNAPSHOT of a package com.mycompany.app:pkg-1:

curl --user "aws:$CODEARTIFACT_AUTH_TOKEN" -H "Content-Type: application/octet-stream" \ -X PUT https://my_domain-111122223333.d.codeartifact.us-west-2.amazonaws.com/maven/my_maven_repo/com/mycompany/app/pkg-1/1.0-SNAPSHOT/pkg-1-1.0-20210729.171330-2.jar \ --data-binary @pkg-1-1.0-20210728.194552-1.jar
curl --user "aws:$CODEARTIFACT_AUTH_TOKEN" -H "Content-Type: application/octet-stream" \ -X PUT https://my_domain-111122223333.d.codeartifact.us-west-2.amazonaws.com/maven/my_maven_repo/com/mycompany/app/pkg-1/1.0-SNAPSHOT/pkg-1-1.0-20210729.171330-2.pom \ --data-binary @pkg-1-1.0-20210728.194552-1.pom

When using these examples:

  • Replace my_domain with your CodeArtifact domain name.

  • Replace 111122223333 with the AWS account ID of the owner of your CodeArtifact domain.

  • Replace us-west-2 with the AWS Region in which your CodeArtifact domain is located.

  • Replace my_maven_repo with your CodeArtifact repository name.

Important

You must prefix the value of the --data-binary parameter with the @ character. When putting the value in quotation marks, the @ must be included inside the quotation marks.

You may have more than two assets to upload for each build. For example, there might be Javadoc and source JAR files in addition to the main JAR and pom.xml. It is not necessary to publish checksum files for the package version assets because CodeArtifact automatically generates checksums for each uploaded asset. To verify the assets were uploaded correctly, fetch the generated checksums using the list-package-version-assets command and compare those to the original checksums. For more information about how CodeArtifact handles Maven checksums, see Use Maven checksums.

Use the following curl command to publish the maven-metadata.xml file for the latest build version:

curl --user "aws:$CODEARTIFACT_AUTH_TOKEN" -H "Content-Type: application/octet-stream" \ -X PUT https://my_domain-111122223333.d.codeartifact.us-west-2.amazonaws.com/maven/my_maven_repo/com/mycompany/app/pkg-1/1.0-SNAPSHOT/maven-metadata.xml \ --data-binary @maven-metadata.xml

The maven-metadata.xml file must reference at least one of the assets in the latest build version in the <snapshotVersions> element. In addition, the <timestamp> value must be present and must match the timestamp in the asset file names. For example, for the 20210729.171330-2 build published previously, the contents of maven-metadata.xml would be:

<?xml version="1.0" encoding="UTF-8"?> <metadata> <groupId>com.mycompany.app</groupId> <artifactId>pkg-1</artifactId> <version>1.0-SNAPSHOT</version> <versioning> <snapshot> <timestamp>20210729.171330</timestamp> <buildNumber>2</buildNumber> </snapshot> <lastUpdated>20210729171330</lastUpdated> <snapshotVersions> <snapshotVersion> <extension>jar</extension> <value>1.0-20210729.171330-2</value> <updated>20210729171330</updated> </snapshotVersion> <snapshotVersion> <extension>pom</extension> <value>1.0-20210729.171330-2</value> <updated>20210729171330</updated> </snapshotVersion> </snapshotVersions> </versioning> </metadata>

After maven-metadata.xml has been published, the last step is to set all the other build versions (that is, all the build versions apart from the latest build) to have a package version status of Unlisted. For example, if the 1.0-SNAPSHOT version has two builds, with the first build being 20210728.194552-1, the command to set that build to Unlisted is:

aws codeartifact update-package-versions-status --domain my-domain --domain-owner 111122223333 \ --repository my-maven-repo --format maven --namespace com.mycompany.app --package pkg-1 \ --versions 1.0-20210728.194552-1 --target-status Unlisted

Snapshots and external connections

Maven snapshots cannot be fetched from a Maven public repository through an external connection. AWS CodeArtifact only supports importing Maven release versions.

Snapshots and upstream repositories

In general, Maven snapshots work in the same way as Maven release versions when used with upstream repositories, but there is a limitation if you plan on publishing snapshots of the same package version to two repositories which have an upstream relationship. For example, say that there are two repositories in an AWS CodeArtifact domain, R and U, where U is an upstream of R. If you publish a new build in R, when a Maven client requests the latest build of that snapshot version, CodeArtifact returns the latest version from U. This can be unexpected since the latest version is now in R, not U. There are two ways to avoid this:

  1. Don't publish builds of a snapshot version such as 1.0-SNAPSHOT in R, if 1.0-SNAPSHOT exists in U.

  2. Use CodeArtifact package origin controls to disable upstreams on that package in R. The latter will allow you to publish builds of1.0-SNAPSHOT in R, but it will also prevent R from getting any other versions of that package from U that aren't already retained.