Publishing SBT projects to Nexus

Specs2 Spring is available on Sonatype OSS and Maven Central! But how did we get there and what should you do to get the hosting, synchronisation to Maven Central and how do you automate the deployment process? Let’s tackle one thing at a time:

Sonatype OSS support

The first thing to is to open an issue in Sonatype’s JIRA, asking them to set up the Nexus repository for you. Once that’s done, you will be able to publish your snapshots and releases to Sonatype; the releases are then synchronised to Maven Central. The first few pages of Sonatype OSS Maven Repository Usage Guide will show you how to get started.

Building and publishing

Now, this is the interesting bit. We are using SBT to build the project and we’d like to be able to run sbt publish to compile, package and publish the project to Sonatype automatically. Before we can do that, we need to configure GPG and SBT plugin that uses GPG to sign the artefacts. The plugin is xsbt-gpg-plugin, which will use GPG to sign the artefacts–properly signed artefacts are the requirement for Maven Central synchronisation. So, with the plugin, your project/plugins.sbt file should contain:

...
resolvers += Resolver.url("scalasbt", /* no new line */
  new URL("http://scalasbt.artifactoryonline.com/scalasbt/sbt-plugin-releases")) /* no new line */
  (Resolver.ivyStylePatterns)

addSbtPlugin("com.jsuereth" % "xsbt-gpg-plugin" % "0.5")
...

If you do not have GPG, you must also install & configure it for your platform; if you do not have your keys, you must also generate key pair and then publish your public key. I cannot quite show you how to do this on Windows (sorry, get a Mac!). On OS X, you can use GPG Tools. Download and install it; the first thing GPG Tools will prompt you to do is to generate your key, protected by a passphrase. (I recommend that you keep the passphrase very long, as XKCD points out in Figure 1!)

Figure 1. Key strengths

Before I can release the artefacts in Sonatype OSS releases and in Maven Central, I need to publish my public keys (so that others can verify that the artefacts are intact and that it was I who has produced them). To do that, you can use the GPG Keychain Access (see Figure 2) tool or use the gpg command-line program.

Figure 2. GPG Keychain Access

We are programmers, so let’s turn to the command line: we need to export a key, but to do that, we need to know its identifier:

$ gpg --list-secret-keys
/Users/janmachacek/.gnupg/secring.gpg
-------------------------------------
sec   2048R/90A468A9 2012-01-30 [expires: 2016-01-30]
uid                  Jan Machacek <jan.machacek@gmail.com>
ssb   2048R/A9ED23D0 2012-01-30

$ gpg --send-keys 90A468A9

Your public key is now uploaded to the default key server (specified in ~/.gnupg/gpg.conf) and it will be distributed to other key servers over the next few minutes. Once that happens, you’ll be ready to release your artefacts to Maven Central.

Releasing

Before we’ll configure the JAR signing, we must deal with the publish process. We set the publishTo (and several other settings) in build.sbt to use the Sonatype repository like so:


publishTo <<= version { v: String =>
  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")
}

Before we can publish our SBT-based project, we must ensure that its generated Maven POMs match the strict requirements of Sonatype and Maven Central. So, we must include the following code in your build.sbt:

organization := "org.specs2"

publishMavenStyle := true

publishArtifact in Test := false

pomIncludeRepository := { x => false }

pomExtra := (
  <url>http://www.cakesolutions.org/specs2-spring.html</url>
  <licenses>
    <license>
      <name>BSD-style</name>
      <url>http://www.opensource.org/licenses/bsd-license.php</url>
      <distribution>repo</distribution>
    </license>
  </licenses>
  <scm>
    <url>git@github.com:janm399/specs2-spring.git</url>
    <connection>scm:git:git@github.com:janm399/specs2-spring.git</connection>
  </scm>
  <developers>
    <developer>
      <id>janmachacek</id>
      <name>Jan Machacek</name>
      <url>http://cakesolutions.org</url>
    </developer>
  </developers>
)

Now, before we even attempt to run sbt publish, we need to specify the credentials for the Sonatype repository. But we don’t want to do that in the files we push to the VCS! Instead, we’ll create file sonatype.sbt, which sets the credentials setting to the Sonatype ones. If you are using SBT version prior to 0.11.x, save this file in ~./sbt; if you are using later version (in my case, 0.11.2 and 0.12.0-M1), put the file in ~./sbt/sbt-version, for example ~./sbt/0.11.2. (Thanks to @channingwalton for the reminder to update!)

credentials += Credentials("Sonatype Nexus Repository Manager", 
                           "oss.sonatype.org", 
                           "your-sonatype-username", 
                           "your-sonatype-password")

The work is done! We’ve modified

  • ~/.sbt/sbt-version/sonatype.sbt with the Sonatype OSS credentials
  • project/plugins.sbt with the xsbt-gpg-plugin plugin to sign the artefacts
  • build.sbt to include the release settings

Now we can run sbt publish, supply our key phrase go GPG and push the artefacts to Sonatype. If you are publishing snapshot release, then your work is done. If you are publishing a “real” release, keep reading.

Promoting

Once you’ve published your non-snapshot release, you will need to go to the Sonatype Nexus, login, select the staging repository and close it. (Again, follow the Sonatype Nexus guide for details.) Closing will verify that the Maven POMs are well formed, that the artefacts’ signatures are valid. If all is well, your repository will end up in Maven Central within a few hours’ time!

Summary

Publishing SBT-based projects to Sonatype and then Maven Central is easy–once you’ve dealt with the details of the Maven POMs. For complete views of the build.sbt and project/plugins.sbt files, take a look at Specs2 Spring’s sources at https://www.github.com/janm399/specs2-spring.

Josh Suereth (http://jsuereth.com/), the maintainer of the xsbt-gpg-plugin SBT plugin maintains a page where he outlines the latest details of the SBT deployment process. Clicky-here to see Josh’s instructions.

This entry was posted in Jan's Blog and tagged , , , . Bookmark the permalink.

13 Responses to Publishing SBT projects to Nexus

  1. Josh Suereth says:

    HI! Good blog! You may not have seen this, but we have instructions for publishing to sonatype on the scala-sbt.org website. Here’s the source file:

    https://github.com/sbt/sbt.github.com/blob/gen-master/src/jekyll/using_sonatype.md

    And the website is live here:

    http://scala-sbt.org/using_sonatype.html

    The formatting is pretty atrocious, which I hope to fix shortly. I’d love if you could (1) update the instructions with anything we might have missed based on your blog, and (2) Point to those instructions so that, in case things become easier or any changes need to be made, users can always find up-to-date instructions!

    Great blog by the way. I’ve read through most of it.

  2. Jan Machacek says:

    Cheers! I’ll help out tomorrow. I have a longer post in mind that will cover automatic tagging and branching in Git when publishing, too.

    Thanks for your kind comment and, of course, the GPG SBT plugin.

    Jan

  3. Pingback: This week in #Scala (03/02/2012) | Cake Solutions Team Blog

  4. Pingback: Sonatype Blog » Scala Artifacts Now on Central

  5. Evan Chan says:

    By the way, don’t forget to mention that you need to set the organization setting, to the groupId which you registered with at Sonatype, or else the publish step won’t work.

  6. Hi,
    I ran into a frustrating issue regarding the location of the sonatype.sbt file. For reasons I don’t understand my .sbt directory started out life where I could put the sonatype.sbt file in ~/.sbt.

    But since using sbt 0.11.2 and above, subdirectories named after the sbt version are created in ~/.sbt and I didn’t notice. This meant that sbt was looking for sonatype.sbt in those directories.

    Anyway, you might need to move ~/.sbt/sonatype.sbt to ~/.sbt/0.11.x/sonatype.sbt to publish successfully.

    Channing

  7. Jan Machacek says:

    Thanks for the reminder–I’ve updated the post. (I’m now using 0.11.2 and 0.12.0-M1.)

  8. Channing Walton says:

    Hi, actually I am wrong about the global location. I have been using sbt-extras which changes the default.

  9. Jan Machacek says:

    Ha! I fel into the same trap of treating sbt-extras as sbt itself. What do you think–is there anyone who’s seriously into SBT (i.e. publishing artefacts and all) and NOT using sbt-extras?

  10. It took me 3 long infuriating evenings to get the credentials correct. In the end I did the following:

    In build.sbt:


    credentials += Credentials(Path.userHome / ".sbt" / "sonatype.credentials")

    In ~/.sbt/sonatype.credentials:

    realm=Sonatype Nexus Repository Manager
    host=oss.sonatype.org
    user=my-user-name
    password=my-password

    Furthermore, I had resolvers that pointed to sonatype. This messed up the URL that was used for the upload. I changed:

    resolvers ++= Seq(
    "Local Maven Repository" at "file://"+Path.userHome.absolutePath+"/.m2/repository",
    "snapshots" at "http://oss.sonatype.org/content/repositories/snapshots",
    "releases" at "http://oss.sonatype.org/content/repositories/releases",
    "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/"
    )

    to:

    resolvers ++= Seq(
    "Local Maven Repository" at "file://"+Path.userHome.absolutePath+"/.m2/repository",
    "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/"
    )

    I am using SBT 0.11.3-2 and xsbt-gpg-plugin 0.6.

  11. Patrick Wendell says:

    Thanks for posting this! Helped me out with a similar issue.

  12. Thank you for sharing your thoughts. I truly appreciate your efforts and I will be waiting for
    your further post thanks once again.

  13. Nicholas Ren says:

    ‘sbt publish’ dosen’t work for me, but sbt ‘publish-signed’ dose

Leave a Reply