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. For example, say that there are two repositories in an AWS CodeArtifact domain, R and U, where U is an upstream of R. In this situation, you can freely publish snapshot builds of a given package (such as 1.0-SNAPSHOT of com.mycompany.app:pkg-1) to both R and U. However, there are some important behaviors to understand when consuming snapshot builds from R (the downstream repository).

  1. If 1.0-SNAPSHOT is present in R, then only the assets of 1.0-SNAPSHOT in R can be retrieved with a package manager configured to fetch packages from R. You cannot retrieve an asset of 1.0-SNAPSHOT in U through R. This is because the snapshot version in U is shadowed by the version in R. This behavior is identical to Maven release versions and the behavior of other package formats. In the diagram, a GET of /maven/R/com/mycompany/myapp/pkg-1/1.0-SNAPSHOT/pkg-1-1.0-20221231.002230-3.jar will return a 200 (OK) HTTP response code, but a GET of /maven/R/com/mycompany/myapp/pkg-1/1.0-SNAPSHOT/pkg-1-1.0-20221220.150959-1.jar will return a 404 (Not Found) HTTP response code.

  2. If 1.0-SNAPSHOT is present in U but not in R, you can pull assets of 1.0-SNAPSHOT from R. This will cause 1.0-SNAPSHOT to be retained in R, the same as with a release version.

  3. After 1.0-SNAPSHOT is retained in R, you can publish additional builds of 1.0-SNAPSHOT in U. However, these will not be accessible from R because of the behavior described in point (1). This means the standard rationale for using snapshot versions, that is, consuming the latest build of a dependency through a specific snapshot version, doesn’t work as expected across an upstream relationship. Even though new builds of 1.0-SNAPSHOT are published to U, consumers cannot access the latest build of 1.0-SNAPSHOT from R. To work around this, either periodically delete version 1.0-SNAPSHOT in R or configure the client to pull versions of 1.0-SNAPSHOT from U.

  4. The Unlisted snapshot build versions are accessible from the downstream repository. In the diagram, a GET of /maven/R/com/mycompany/myapp/pkg-1/1.0-20221220.150959-1/pkg-1-1.0-20221220.150959-1.jar will return a 200 (OK) response code. Even though this requests an asset present in the upstream repository, because the version is addressed using the build version string (1.0-20221220.150959-1), the asset can be fetched through the downstream repository. This GET will also cause version 1.0-20221220.150959-1 to be retained in R, with a package version status of Unlisted.