Automatic deployment of opensource projects to Maven Central

In this blog post I will describe how we set up automatic deployment of our rabbitmq-client library to Sonatype’s Nexus Repository Manager.

For a refresher on what Sonatype Nexus Repository Manager is, check out this excellent post.

Some recommended reading

First and foremost, Alex Nedelcu’s excellent post Automatic Releases to Maven Central with Travis and SBT which was the source for most of the information described in this post.

I also found these two Sonatype articles very helpful:
OSSRH Guide
Releasing the Deployment

Overview of our CI pipeline to Sonatype Nexus

We use Travis-ci to power the continuous delivery pipeline of the rabbitmq-client repo.

A .travis.yml file, located in the root folder of the project, describes a sequence of build steps that comprise this project’s pipeline. For example code instrumentation, static-analysis, and code coverage report generation.

The final line of the .travis.yml file reads as follows:

after_success:
- ./project/publish

The file ./project/publish is a ruby script which I copied from the Monix/shade project.

When this script is called from within sbt, the newly-built jar file is signed and uploaded to Sonatype.

It took much trial and error before I successfully completed this step; read on to learn more.

The 30,000 foot view of deploying to Sonatype Nexus

This section is a brief overview. The following section will discuss each step in more detail.

To deploy artifacts to Sonatype, you will need:

  • a Sonatype account (see the following section)
  • a maven groupId for your project.

Your maven groupId must be requested by creating a new Jira issue.

Travis-ci will use the above information to publish newly built artifacts on your behalf.

Sonatype Nexus requires that new artifacts are cryptographically signed.

To fulfil this requirement a new public/private key pair must be created. Your new public/private key pair will be stored in your github project. The private key will be encrypted.

The build.sbt file must be updated with values that sbt will use to successfully deploy the jar file to Sonatype.

Finally, the Sonatype username, Sonatype password, and PGP passphrase of the private key will be stored in Travis-ci as environment variables.

The details of deploying to Sonatype Nexus

Creating a Sonatype Account

A Sonatype Account is created when you first sign up with Sonatype’s Jira page. You may then log into Sonatype’s Nexus Respository Manager console using the same username and password as your Jira account.

Request a repository groupId for your project

Navigate to https://issues.sonatype.org and create a new user account which you will use to request a new maven groupId for your project.

Open a new Jira issue requesting a new groupId for your project. As an example, this is the Jira issue we opened to request a groupId for the rabbitmq-client project.

Create a public/private key pair

As already mentioned, Sonatype Nexus requires that artifacts are cryptographically signed. To fulfil this requirement a new public/private key pair must be created.

I happen to use an Apple MacBook so I chose to use an OSX application called “GPG Keychain” to generate a new public/private key pair.

The new key is visible from within the terminal:

$ gpg --list-secret-keys

/Users/xxxxx/.gnupg/pubring.kbx
-----------------------------------
sec rsa4096 2017-11-08 [SC]
4BEF11849D8638711107EB75B76CCB046AAA0BF2
uid [ unknown] PaddyPowerBetfair (Used to sign artifacts which are uploaded to central.sonartype.org)
ssb rsa4096 2017-11-08 [E]

The public and private keys must be exported to separate keyrings and then stored in the github project.

$ gpg -a --export 4BEF11849D8638711107EB75B76CCB046AAA0BF2 > my-key.asc

$ gpg --no-default-keyring --primary-keyring pubring.gpg --keyring pubring.gpg --fingerprint --import ./my-key.asc

$ gpg --export-secret-keys > secring.gpg

$ cd /path/to/github/project/.gnupg
$ cp pubring.gpg /path/to/github/project/.gnupg/
$ cp secring.gpg /path/to/github/project/.gnupg/

Update build.sbt

Update your build.sbt file with the following:

useGpg := false
usePgpKeyHex("4BEF11849D8638711107EB75B76CCB046AAA0BF2")
pgpPublicRing := baseDirectory.value / "project" / ".gnupg" / "pubring.gpg"
pgpSecretRing := baseDirectory.value / "project" / ".gnupg" / "secring.gpg"
pgpPassphrase := sys.env.get("PGP_PASSWORD").map(_.toArray)

credentials += Credentials(
"Sonatype Nexus Repository Manager",
"oss.sonatype.org",
sys.env.getOrElse("SONATYPE_USER", ""),
sys.env.getOrElse("SONATYPE_PASSWORD", "")
)

isSnapshot := version.value endsWith "SNAPSHOT"

publishTo := Some(
if (isSnapshot.value)
Opts.resolver.sonatypeSnapshots
else
Opts.resolver.sonatypeStaging
)

Add the following to project/plugins.sbt:

addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.1.0")
addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "2.0")

Add environment variables to your Travis-ci project settings.
Log into Travis CI, navigate to your project’s home page and click “More Options | Settings”.

Scroll down to environment variables and add the following variable names and their corresponding values: SONATYPE_USERNAME, SONATYPE_PASSWORD and PGP_PASSWORD.

And you’re done …

At this point all the machinery is in place for you to test automatic deployment of your project to Sonatype Nexus.

Let’s test it

The scripts we have added in the preceding steps, work as follows:

Publishing snapshots

If the git branch is called “snapshot” and the value of version in the build.sbt file ends with “SNAPSHOT” (e.g. 1.0.1-SNAPSHOT) then the following command, when executed in a local terminal, should publish your library to the snapshot repository in Sonatype Nexus.

$ PGP_PASS="" sbt publishSigned

You may confirm this by navigating to your equivalent of this url: https://oss.sonatype.org/content/repositories/snapshots/com/paddypowerbetfair/rabbitmq-client_2.12/.

Publishing releases

If the git branch is called something like “v1.0.1” and the value of version in the build.sbt file is 1.0.1 then the artifact will be uploaded to the equivalent of https://oss.sonatype.org/content/repositories/releases/com/paddypowerbetfair/rabbitmq-client_2.12/1.0.1.

According to the OSSRH Guide it may take two hours before your library is searchable in the Central Repository or mvnrepository.com.

Conclusion

With this pipeline in place, new releases of our open source libaries are a trivial matter. It only requires that the git branch is correctly named (e.g. v1.0.2 or SNAPSHOT).

I would strongly recommend reading the articles that are linked above in the Recommended Reading section. Without them I would not have known where to begin.

Automatic deployment of opensource projects to Maven Central

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s