Scala Tips #1: Publishing to Sonatype and Maven Central
Flavian
Flavian Scala Developer
Flavian is a Scala engineer with many years of experience and the author of phantom and morpheus.


This tutorial is about publishing to Maven Central, quickly and efficiently, from a Scala based SBT backed project. Before we going any forward we are going to set a few ground rules and assumptions about what you will need to have before getting started.

Prerequisities

- You either own a domain that you want to publish artefacts from or you are hosting your code in a public repository of some sort. This is a requirement, and Sonatype will require you to validate everything properly. For instance, in order for us to publish artefacts as com.outworkers we had to prove that we own the outworkers.com domain as part of the Sonatype OSS initial account setup outlined below. If you are hosting code on GitHub, you will be allowed to publish as com.github.yourusername.

- First, we are going to assume you are using a modern version of SBT, let's assume anything above 0.13.6 for the purposes of this exercise. We are using 0.13.11 to be precise. If you are not sure about the SBT version you are currently using, either type sbtVersion in the SBT prompt of your project, or check the project/build.properties file within your root project folder, and you should hopefully see something like sbt.version=0.13.11

- Next, we are going to assume this is something you are looking to distribute publicly, as there is obviously no way to control access on Maven Central. Everything is published forever, and unlike Bintray for example, there is no way to pull back a version from Maven Central. The process of leveraging SBT to release to a custom repository is actually very very similar and will be outlined in more detail in a future tutorial, explicitly targeting common tools such as Nexus Pro, Bintray Professional or even Artifactory.


1. Sonatype OSS initial account setup

The process is outlined in more detail here, but in effect what you need to do is to create an account with the Sonatype Jira installation available.

Step 1: Register an account with Sonatype Jira. You will later use these same credentials to access http://oss.sonatype.org, where you can control the artefacts you deploy, check your deployments, what stage they are in, investigate any failures during the deployment process, and so on.

Step 2: Create a "New Project" ticket that will need to be manually peer reviewed by a Sonatype representative. This will take 2 business days, so factor this in your deadlines if you are working against any. Once your project is approved, you will need to publish a version of your artefact and the Central syncing will be automatically activated.

Rule #1: You need to own the domain you will want to make a claim on as your groupId. You can only publish artefacts for com.yourcompany if you own yourcompany.com. The specific domain name extension is also important, so for instance if you want to publish under net.yourcompany you need to own yourcompany.net and so on.

Rule #2: Pick a password that you are comfortable sharing with other members of your team or probably company. This will need to probably be distributed to your CI servers in some encrypted form and so on, which means you are better off not using the same thing you have for your personal email.

2. Setting up your GPG encryption key

The essential things you are trying to achieve at this stage are to first generate a key that belongs to you, and is registered to the same email address that you have used for the Sonatype account. This is an important step, so make sure the details you use match. 

The second part of what you are trying to do here is to distribute the public part of your key to known key servers, so any third party can basically identify the key and its owner, essentially allowing the verification of provenance and origin for a given artefact.

If you are using a Mac, there is an automated way to do this using GPG Suite, that will allow you to easily generate a new key and distribute it to known servers for you. If you are not either found of Apple or gone down the Mac route yet for unknown reasons(yes, we are Apple fanboys), you can still obviously do this manually.

First you will need to install the default PGP suite on your operating system of choice. We cannot advise you on how to do this on Windows but an initial Google search there seems to be a GPG4Win software that may point you in the right direction. It probably automates around the same idea of generating a PGP key, storing it someone on disc, and distributing the public part of that key to known key servers.

pgp-cmd gen-key

Input all the relevant details, and for the sake of argument let's assume you wind up with the following two files. 

~/.gpg/pubring.asc
~/.gpg/secring.asc


Wherever the files are located on disk, you will now need to use two utilities for the next stage of this process:

gpg --list-secret-keys

This will produce an output like the following:

sec   1024D/D0FE7AFB 20016-06-24
uid Flavian
uid Flavian
ssb 2048g/E75EAB2B 2016-06-24

The part you care about is the unique ID of the key, as that's what you will need at the next stage. In the above case the sec key ID you are after is D0FE7AFB.

gpg --send-keys


You can also specify the target keyserver by using the --keyserver options, and you can then pick from the list of available standard GPG servers online:

keyserver.pgp.com
keyserver.ubuntu.com
pgp.mit.edu

Ubuntu uses Seahorse underneath to manage keys, which should automatically sync your PGP keys with a default remote server, namely the Ubuntu keyserver from the above list, but just in case this is how to manually achieve the same thing.

gpg --send-keys D0FE7AFB --keyserver keyserver.ubuntu.com


If you are using the GPG Suite, the files will be located in a different location, namely ~/.gnupg/. You don't really need to do anything manual or terminal based here, just fire up the GPG Suite UI and right click "Send public key to Keyserver" if your public key has not yet been uploaded.

~/.gnupg/pubring.gpg
~/.gpg/secring.gpg

The suite is a nicer interface to all this, as it will allow you to do things like updating the password of the key or re-destributing the key automatically from the comfort of a user interface as opposed to the less user friendly command line process. We know there are some of you out there that would ideally enjoy a command line interface to everything in existence such that they should never leave the known comfort of vi or emacs, but for everyone's benefit, use the suite if you can.

It's a Mac only tool unfortunately, but there are probably a wide range of sensible alternatives that give you the same functionality. To recap:

- GPG Suite is the Apple fanboy variant.
- KGpg is the Ubuntu user's friend.
- GPG4Win is the Windows variant, for all those MSFT MVPs and investment banking contractors, our hearts go out to you.


3. Setting up your SBT build for Sonatype publishing

You need a total of 2 plugins to achieve this efficiently.

The first is called the sbt-pgp-plugin and it deals with the PGP encryption we will use to sign our jars. When deploying to Sonatype/Maven Central, this is actually one of the requirements, so fortunately not something we can skip.

The second is sbt-sonatype plugin which can help you publish things more easily and allows you to skip some otherwise manual steps that you would need to undertake.

Add the following two lines to your plugins.sbt.

addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0")
addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "1.1")


4.
Getting the publishSettings right.

A very important part of your build definition is to define the correct settings to be mixed in to all sub modules. There are a number of requirements you need to meet to be allowed to publish to Maven Central, and they will be automatically evaluated every time you try to publish, so you need to make sure you comply with them.

The full list is available here, in essence we are covering all the relevant bits here but make sure you are complying. Don't get confused about pom.xml, SBT ultimately also outputs a pom.xml from your SBT build, you will just use different ways of specifying the exact same settings.

lazy val mavenPublishingSettings: Seq[Def.Setting[_]] = Seq(
    credentials += Credentials(Path.userHome / ".ivy2" / ".credentials"),
    publishMavenStyle := true,
    publishTo <<= version.apply {
      v =>
        val nexus = "https://oss.sonatype.org/"
        if (v.trim.endsWith("SNAPSHOT")) {
          Some("snapshots" at nexus + "content/repositories/snapshots")
        } else {
          Some("releases" at nexus + "service/local/staging/deploy/maven2")
        }
    },
    externalResolvers <<= resolvers map { rs =>
      Resolver.withDefaultResolvers(rs, mavenCentral = true)
    },
    licenses += ("Outworkers License", url("https://github.com/outworkers/phantom/blob/develop/LICENSE.txt")),
    publishArtifact in Test := false,
    pomIncludeRepository := { _ => true },
    pomExtra := {
      <url>https://github.com/outworkers/phantom</url>
      <scm>
        <url>git@github.com:outworkers/phantom.git</url>
        <connection>scm:git:git@github.com:outworkers/phantom.git</connection>
      </scm>
      <developers>
        <developer>
          <id>alexflav</id>
          <name>Flavian</name>
          <url>http://github.com/alexflav23</url>
        </developer>
      </developers>
    }  


6. Publishing your first artefact to Maven Central/Sonatype OSS

Finally, you are now ready to use the setup, and publish your very first artefact to Sonatype OSS/Maven Central. 

// If you haven't specified the pgpPass in your build settings
// You will need to manually input it here in the terminal.
// It will prompt you for the GPG key password you set when creating the key.
sbt publishSigned
sbt sonatypeReleaseAll

It's very easy to cross publish for multiple Scala variants as well:

// If you haven't specified the pgpPass in your build settings
// You will need to manually input it here in the terminal.
// It will prompt you for the GPG key password you set when creating the key. sbt +publishSigned sbt sonatypeReleaseAll


The first command will essentially push the artefacts to Sonatype OSS, simply publishing the JARs together with all the associated information. If your password and GPG key setup are correct, you should be able to see your published artefacts under "Staging repositories", available on the left hand side menu of Sonatype OSS after you log in to the system.

The second command is used to automate the last steps of syncing your artefacts with Maven Central. At this stage, your signature and key will be validated, the information in your SBT build will be evaluated, and a bunch of rules called the Central Sync Requirements will be validated to make sure your build meets the criteria set by Maven Central.

On the Sonatype UI, these are called the Close and the Drop step. Close will trigger the validation of your artefact to make sure it complies with all the sync rules. Drop will remove your artefact from Sonatype and sync it with Maven Central, and it usually takes about 2 hours after dropping an artefact to see it available directly on Maven Central.

7. Ending

It's definitely not the most straightforward process, but hopefully this tutorial has done some good and pointed you in the right direction.

Most of the setup required here is one time only, for all your other projects you don't really need to repeat steps 1 and 2, which are arguably the most laborious. All you need is to add the plugins, settings, and you're done, you can publish any number of projects through the same GPG setup.

And most of the time you can just copy paste the relevant settings and just change URLs, which is all there is to it really.

Related articles