Maven
Deploying to OSSRH with Apache Maven⚓︎
Apache Maven started the Central Repository by publishing all its components and required dependencies into the Central Repository - back then known as Maven Central. Maven is pre-configured to connect to and download everything it needs including your project dependencies from the Central Repository.
We recommend using stable versions of Maven 3 since all previous versions of Apache Maven have reached their end of life and are no longer supported by the project maintainers. There are known issues regarding signing components with a number of older Maven releases.
A Maven build configuration can be set up to fulfill all the requirements in various ways and we will discuss all applicable details below.
Note that while these instructions are considered best practice by Sonatype, opinions differ and you can find links to other documentation in the Additional Information section below.
Other Prerequisites⚓︎
Besides an Apache Maven installation, you must have a GPG client installed and on your command line path as required by the Maven GPG plugin. For more information, please refer to http://www.gnupg.org/ as well as the plugin documentation and below.
Distribution Management and Authentication⚓︎
In order for Maven to deploy to the OSSRH Nexus Repository Manager with the Nexus Staging Maven plugin you must have the following configuration:
<distributionManagement>
<snapshotRepository>
<id>ossrh</id>
<url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
</distributionManagement>
<build>
<plugins>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.7</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://s01.oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
</configuration>
</plugin>
...
</plugins>
</build>
Since OSSRH is always running the latest available version of Sonatype Nexus Repository Manager 2, it is best to use the latest version of the Nexus Staging Maven plugin.
Alternatively if you are using the Maven deploy plugin, which is the default
behavior, you need to add a full distributionManagement
section:
<distributionManagement>
<snapshotRepository>
<id>ossrh</id>
<url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
<repository>
<id>ossrh</id>
<url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
The above configurations will get the user account details to deploy to OSSRH
from your Maven settings.xml
file, usually placed in ~/.m2
. A minimal
setup with authentication is:
<settings>
<servers>
<server>
<id>ossrh</id>
<username>token-username</username>
<password>token-password</password>
</server>
</servers>
</settings>
Do not use your login username and password in settings.xml
Please do not use your UI login username and password in settings.xml
.
Use the token that was previously generated.
Note that the id
element in the server element in settings.xml
are identical to
the id
elements in the snapshotRepository
and repository
element as well as
the serverId
configuration of the Nexus Staging Maven plugin.
Javadoc and Sources Attachments⚓︎
To get Javadoc and Source jar files generated, you have to configure the Javadoc and source Maven plugins:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
GPG Signed Components⚓︎
The Maven GPG plugin is used to sign the components with the following configuration:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
This relies on the GPG
command being installed and the GPG credentials being
available e.g. from settings.xml
. For more information please consult the
Maven GPG Plugin documentation:
<settings>
<profiles>
<profile>
<id>ossrh</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<gpg.executable>gpg2</gpg.executable>
<gpg.passphrase>the_pass_phrase</gpg.passphrase>
</properties>
</profile>
</profiles>
</settings>
In case you have multiple keys, the local gpg
will use the first listed
signature key (gpg --list-signatures
), if you need to use a specific key you
could add the details of the gpg key inside a <configuration>
section and use
local settings.xml
to discover the passphrase via the signature keyname:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
<configuration>
<keyname>${gpg.keyname}</keyname>
<passphraseServerId>${gpg.keyname}</passphraseServerId>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Are you being prompted for a passphrase or getting a gpg: signing failed: No such file or directory
error?
This may be happening to you because you are using gpg
version 2.1 or later. If running gpg --version
shows that
you are running version 2.1 or later, you must modify the configuration of the Maven GPG plugin to add additional
gpgArguments
. Building on the example above:
<configuration>
<keyname>${gpg.keyname}</keyname>
<passphraseServerId>${gpg.keyname}</passphraseServerId>
<gpgArguments>
<arg>--pinentry-mode</arg>
<arg>loopback</arg>
</gpgArguments>
</configuration>
Hint
In the example below you may need to use the last 8 characters of the
signature keyid in hexadecimal format, you can find them using this command
gpg --list-signatures --keyid-format 0xshort
:
$ gpg --list-signatures --keyid-format 0xshort
/home/mylocaluser/.gnupg/pubring.kbx
---------------------------------
pub rsa3072/0x3ABDEC12 2021-01-27 [SC] [expires: 2023-01-27]
74524542545300A398653AB5242798823ABDEC12
uid [ultimate] Other Name <otheremail@example.com>
sig 3 0x3ABDEC12 2021-01-27 Other Name <alarconj@gmail.com>
sub rsa3072 2021-01-27 [E] [expires: 2023-01-27]
sig 0x3ABDEC12 2021-01-27 Julian Alarcon <alarconj@gmail.com>
pub rsa3072/0x0ABA0F98 2021-06-23 [SC] [expires: 2022-03-21]
CA925CD6C9E8D064FF05B4728190C4130ABA0F98
uid [ultimate] Central Repo Test <central@example.com>
sig 3 0x0ABA0F98 2021-06-24 Central Repo Test <central@example.com>
sub rsa3072/0x7C17C93B 2021-06-23 [E] [expires: 2023-06-23]
sig 0x0ABA0F98 2021-06-23 Central Repo Test <central@example.com>
You will find in the line that starts with sig 3 that
0x3ABDEC12
is the signature short keyid in hexadecimal format that you
will need to pass as ${gpg.keyname}
.
If you need more help setting up and configuring GPG, please read our detailed instructions.
Nexus Staging Maven Plugin for Deployment and Release⚓︎
The Nexus Staging Maven Plugin is the recommended way to deploy your components
to OSSRH and release them to the Central Repository. To configure it simply add
the plugin to your Maven pom.xml
:
<build>
<plugins>
...
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.7</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://s01.oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
</configuration>
</plugin>
If your version is a release version (does not end in -SNAPSHOT
) with this setup
in place you can run a deployment to OSSRH, and an automated release to the Central
Repository with:
mvn clean deploy
With the property autoReleaseAfterClose
set to false
you can manually inspect the staging
repository in the Nexus Repository Manager and trigger a release of the staging repository later with:
mvn nexus-staging:release
If you find something went wrong you can drop the staging repository with:
mvn nexus-staging:drop
Please read Staging Releases in the Repository Manager 2 documentation for more information about the Nexus Staging Maven Plugin.
Deprecated oss-parent⚓︎
In the past all the plugin configuration and other setup was managed by a Maven parent POM with the
coordinates org.sonatype.oss:oss-parent:9
. This project leaked SCM, URL, and other details and its usage is
discouraged. Maintenance of the project has stopped and it no longer works with latest tooling.
If desired, please manage your own organization-level POM in a similar manner.
Using a Profile⚓︎
Since the generation of the javadoc
and source
jars as well as signing
components with GPG is a fairly time consuming process, these executions are
typically isolated from the normal build configuration and moved into a profile.
When a deployment is performed we active the profile:
<profiles>
<profile>
<id>release</id>
<build>
...
javadoc, source and gpg plugin from above
...
</build>
</profile>
</profiles>
Performing a Snapshot Deployment⚓︎
Snapshot deployments are performed when your version ends in -SNAPSHOT
. You do
not need to fulfill the usual requirements when performing snapshot deployments and can simply run:
mvn clean deploy
SNAPSHOT versions are not synchronized to the Central Repository. If you wish
your users to consume your SNAPSHOT versions, they would need to add the
snapshot repository to their Nexus Repository Manager, settings.xml
, or pom.xml
. Successfully
deployed SNAPSHOT versions will be found in
https://s01.oss.sonatype.org/content/repositories/snapshots/.
Performing a Release Deployment⚓︎
In order to perform a release deployment you have to edit your version
in all
your POM files to use release versions. This means that they cannot end in -SNAPSHOT
.
Note that plugin and dependency declarations cannot use snapshot
versions. This ensures that you only depend on released components.
Ideally they are all available in the Central Repository. This ensures that your
users can retrieve your components as well as your transitive dependencies from
the Central Repository.
Changing versions for your project, and the parent references in a multi-module setup, can be performed manually or with the help of the Maven versions plugin:
mvn versions:set -DnewVersion=1.2.3
Once you have updated all the versions and ensured that your build passes
without deployment you can perform the deployment by using the release
profile:
mvn clean deploy -P release
This process is completely independent from your workflow with your SCM system. If you want to ensure that a specific version in the Central Repository corresponds to a specific revision in your SCM system, which is a good practice, you can either perform the commits manually in a flow similar to:
- Develop, develop, develop
- Commit any outstanding changes
- Verify build passes
- Update versions to release version
- Commit release version
- Run deployment
- Update versions to next snapshot version
- Commit new snapshot version
- Develop, develop, develop, rinse and repeat
You can automate it with a script including configuration running on a CI server, or you can use the Maven release plugin as documented below.
Performing a Release Deployment with the Maven Release Plugin⚓︎
The Maven Release Plugin can be used to automate the changes to the Maven POM files, sanity checks, required SCM operations, and the actual deployment execution.
Since we are using our own profile the Maven release plugin configuration should disable the
release profile that is part of the Maven Super POM and specify the deploy goal together with
the activation of the release
profile:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.3</version>
<configuration>
<autoVersionSubmodules>true</autoVersionSubmodules>
<useReleaseProfile>false</useReleaseProfile>
<releaseProfiles>release</releaseProfiles>
<goals>deploy</goals>
</configuration>
</plugin>
With the SCM connection configured correctly you can perform a release deployment to OSSRH with:
mvn release:clean release:prepare
Answer the prompts for versions and tags, and followed with:
mvn release:perform
This execution will deploy to OSSRH and release to the Central Repository in one go
thanks to the usage of the Nexus Staging Maven Plugin with autoReleaseAfterClose
set to true
.
Manually Releasing the Deployment to the Central Repository⚓︎
If you are using autoReleaseAfterClose
set to false
or you are using the
default Maven deploy plugin, you can
inspect and potentially release the deployed artifacts manually.
Alternatively if you have deployed with the Nexus Staging Maven Plugin, and the deployment succeeded, you can release the repository directly on the command line. Immediately after the deployment a properties file is created in the target directory which contains all the information required and you can simply release the staging repository with:
mvn nexus-staging:release
If you have been running the deployment as part of a release done with the
Maven release plugin, the deployment was done from the tag in your version
control system checked out into target/checkout
so you have to run the
Nexus Staging plugin from there:
mvn release:perform
...
cd target/checkout
mvn nexus-staging:release
You can configure this goal to be run automatically as part of your release deployment with the release plugin by adding it as a goal execution after deploy:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<configuration>
<goals>deploy nexus-staging:release</goals>
...
Additional Information⚓︎
- Using a local repo manager and OSSRH. An approach to using OSSRH for the occasional deployment of a component.
- Example project
- Blog post with example project with documentation and video showcasing deployment with Bitbucket Pipelines