You have developed some crafty Java library or Maven plugin and now you want to distribute it to other users through Maven Central repository? Using Sonatype Open Source Software Repository Hosting Service is a nice way for open source projects to achieve that and there’s two options to get your artifacts in it: 1. Release with Sonatype’s process or 2. Use Bintray’s process. In short, both options end up with the same results, your project’s artifacts are in Maven Central repository, but using Sonatype’s process and Maven release plugin makes it easy to release new version after you have set it up.
Using Sonatype’s service for pushing artifacts to Maven Central
Sonatype Open Source Software Repository Hosting Service (OSSRH) provides Maven repository hosting service for open source projects. You can deploy snapshots, stage releases, and promote your releases so they will be synced to Maven Central.
The process with Sonatype has a bit more steps than Bintray but if you follow the user guide, quite easy. And now as they have made some changes to their release process it’s
easier more or less the same than using Bintray. All you need to do is to sign up a Sonatype JIRA account, create a JIRA ticket and make some POM/settings configuration and then use Maven release plugin to perform release. The procedure is described in Sonatype OSS Maven Repository Usage Guide but here is a short recap.
Performing release deployment with the Maven release plugin
Using Maven to perform release deployment to OSSRH is described in Sonatype’s guide which tells you how to do it manually or through the Maven release plugin which I find convenient.
First start with Initial Setup and create your JIRA account and new project ticket. The new project ticket triggers creation of your repositories. While your repositories are taken care of you should review the requirements for components in Central.
The artifacts need to be GPG signed so if you yet haven’t got a GPG key follow this guide to create one. Then you need to have your GPG key in a keyserver so start by sending your GPG key to keyserver:
gpg --keyserver pool.sks-keyservers.net --send-keys <your KEYID>
If you have more than one GPG key in your keychain then it’s useful to set a default key to be used for signing. Edit your ~/.gnupg/gpg.conf and uncomment the “default-key KEYID” line and add your KEYID.
Your Maven project settings
Configure your Maven settings.xml to have Sonatype OSSRH credentials (in .m2/settings.xml).
<settings> ... <servers> <server> <id>ossrh</id> <username>your-jira-id</username> <password>your-jira-pwd</password> </server> </servers> ... </settings>
Edit your’project’s pom.xml for Maven release
Add the distributionManagement section to point to OSSRH.
<distributionManagement> <snapshotRepository> <id>ossrh</id> <url>https://oss.sonatype.org/content/repositories/snapshots</url> </snapshotRepository> <repository> <id>ossrh</id> <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url> </repository> </distributionManagement>
The configuration for the Maven release plugin should include disabling the release profile that is part of the Maven Super POM, since we are using our own profile, and specify the deploy goal together with the activation of our release profile
<pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-release-plugin</artifactId> <version>2.5</version> <configuration> <useReleaseProfile>false</useReleaseProfile> <releaseProfiles>release</releaseProfiles> <goals>deploy</goals> </configuration> </plugin> </plugins> </pluginManagement>
Add the nexus-staging plugin to define where’s Nexus and if we release it right after closing.
<plugin> <groupId>org.sonatype.plugins</groupId> <artifactId>nexus-staging-maven-plugin</artifactId> <version>1.6.3</version> <extensions>true</extensions> <configuration> <serverId>ossrh</serverId> <nexusUrl>https://oss.sonatype.org/</nexusUrl> <autoReleaseAfterClose>true</autoReleaseAfterClose> </configuration> </plugin>
Add the release profile for signing with GPG & Javadoc and Sources Attachments
<profile> <id>release</id> <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> <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> </profile>
You can see the full pom.xml e.g from my markdown-page-generator-plugin’s pom.xml.
Snapshot deployment are performed when your version ends in -SNAPSHOT. You do not need to fulfil the requirements when performing snapshot deployments and can simply run
$ mvn clean deploy
Successfully deployed SNAPSHOT versions will be found in Snapshot repository. If you need to delete your artifacts, you can log in to Sonatype’s Nexus using the same credentials you use to access to the Sonatype JIRA.
Performing a Release Deployment
The Maven Release Plugin can be used to automate the changes to the Maven POM files, sanity checks, the SCM operations required, the actual deployment execution and you can perform a release deployment to OSSRH with the following steps.
Prepare the release by answering the prompts for versions and tags
$ mvn release:clean release:prepare
If prepare fails use
$ mvn release:rollback $ mvn release:clean
The prepare will create a new tag in SCM, even in GitHub, automatically checking in on your behalf. For it to work you need to have working public key in GitHub for git-push.
Perform the release. The perform process will ask for your gpg.passphrase if you don’t give it with passphrase argument.
$ mvn release:perform
For some reason I can’t provide the GPG passphrase when Maven GPG plugin asks it and I have to use the -Dgpg.passphrase argument.
$ mvn -Darguments="-Dgpg.passphrase=<your GPG key passphrase> release:perform
If release:perform fails to error “gpg: signing failed: No pinentry” then on macOS you need to restart gpg-agent and define pinentry-program. gnupg21 comes with pineentry as dependency. Or see Gist about commit signing with GPG on macOS.
$ killall gpg-agent && gpg-agent --daemon --use-standard-socket --pinentry-program /usr/local/bin/pinentry
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.
Now your artifacts are in the Releases repository. The updates to The Central Repository search can take up to two hours. Once your artifacts are released you will not be allowed to update or delete them.
The first time you promote a release, you need to comment on the OSSRH JIRA ticket you created so OSSRH can know you are ready to be synced.
Manually Releasing the Deployment to the Central Repository
If you don’t want to release artifacts automatically you can also do it manually. Set the autoReleaseAfterClose set to false so you can inspect and potentially release the deployed artifacts manually. Then to release your artifacts is done through Nexus as described in the guide.
Using Bintray for pushing artifacts to Maven Central
“Bintray offers developers the fastest way to publish and consume OSS software releases. Whether you are distributing software packages or downloading ones”. In short it provides i.a. an alternative way to release artifacts to Maven Central and to Sonatype Open Source Software Repository.
I found out about Bintray after I had already used the Sonatype’s way to release artifacts so I haven’t tested this myself. Bintray’s process is more or less similar than Sonatype’s but if I hadn’t read the blog post about how to do it I wouldn’t have know where to start. In short the process is the following.
- Register to Bintray and set up auto-signing: Generate yourself a keypair, if you don’t have one. Add it to your profile, and setup your default Maven repo (or a new one) for signing with your GPG key: Bintray can then sign your jars automatically.
- Add your Sonatype account under “accounts”. If you don’t have one, follow this procedure
- Create and link your package: Import from a GitHub repo or create a new package for your Maven project.
- You can link your package to JCenter by clicking “Add to JCenter”.
- Set up Maven up to deploy to Bintray by copy-pasting the pom.xml snippets from “Set me up!” guide.
Then for each release:
- Deploy: Deploy files by running your build tool.
- Publish: Review the build artifacts and publish the version files if satisfied.
- Sync: On the version page go to the Maven Central tab, enter your Sonatype password and click “Sync” and you’re done!
- Your package is now in https://oss.sonatype.org/content/repositories/releases and will be synced to Maven Central (usually takes time). In case of a sync problem, Bintray will automatically take care of any needed cleanup.
For distributing your open source projects’ artifacts through Maven Central repository and OSSRH you have two options: 1. Release with Sonatype’s process or 2. Use Bintray’s process. Both options end up with the same results: your project’s artifacts are in Maven Central repository. In my opinion if you’re using Maven then it doesn’t really matter which option you choose.
Before Sonatype simplified their process for making releases to OSSRH the Bintray’s process was the only almost pain-free gateway to Maven Central. But with the new Sonatype way the two alternative ways are more or less the same and I could say that Sonatype’s new process feels a bit easier when using the Maven release plugin. In practice there’s not much differences, e.g. both supports SNAPSHOTs, Sonatype in OSSRH and Bintray in oss.jfrog.org. Bintray is more flexible especially if not using Maven so if you’re using other tools like Gradle then it’s the easier way to go.