Publish to Maven Central via Sonatype with SBT

Publish to Maven Central via Sonatype with SBT

First, create an account on the Sonatype JIRA, unless you have one. For the new group ID, create a ticket using the form under this URI. Once requested, wait for the ticket to go into Resolved state. When this happens, you can publish your project to Sonatype.

To do so, configure your SBT project. Add the following lines to your project/plugins.sbt:

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

Configure Sonatype credentials for sbt-sonatype, create the ~/.sbt/0.13/sonatype.sbt file with the contents like:

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

Add the following to your build.sbt:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
organization := "uk.co.appministry" // set to whatever you requested as an organization in the form
publishMavenStyle := true
pomIncludeRepository := { _ => false }
pomExtra := (
  <url>https://github.com/AppMinistry/scathon</url>
    <licenses>
      <license>
        <name>Apache 2</name>
        <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
      </license>
    </licenses>
    <scm>
      <connection>scm:git:git://github.com/AppMinistry/scathon.git</connection>
      <developerConnection>scm:git:git://github.com/AppMinistry/scathon.git</developerConnection>
      <url>https://github.com/AppMinistry/scathon/tree/master</url>
    </scm>
    <developers>
      <developer>
        <id>radekg</id>
        <name>Radoslaw Gruchalski</name>
        <url>http://gruchalski.com</url>
      </developer>
    </developers>
  )

Obviously, make sure you provide the details correct to your project: URL, license details, SCM details, developers data and so on. For the comprehensive explanation, look here.

In order to publish to Sonatype, we need gnupg installed. This is for macOS:

$ brew install gnupg gnupg2

Generate a key pair, use the defaults, set the expiry to some same value - the recommended value is less than 2 years. Also, consider setting a passphrase!

$ gpg --gen-key

Check the keyid of the newly generated key:

$ gpg --list-keys
/Users/rad/.gnupg/pubring.gpg
-----------------------------
pub   2048R/6664767F 2017-01-26 [expires: 2019-01-26]
uid       [ultimate] Radoslaw Gruchalski <radek@gruchalski.com>
sub   2048R/C0C1DF05 2017-01-26 [expires: 2019-01-26]

The keyid in the output above is 6664767F. Send this key to the key server used by Sonatype:

$ gpg --keyserver hkp://pgp.mit.edu --send-keys 6664767F

Give it a few minutes to propagate your key across different machines. It’ll get a little bit confusing otherwise…

Finally, deploy the artifacts to the staging repository:

$ sbt publishSigned

A valid output should be look like this:

[rad] scathon (master) $ sbt publishSigned
[info] Loading global plugins from /Users/rad/.sbt/0.13/plugins
[info] Updating {file:/Users/rad/.sbt/0.13/plugins/}global-plugins...
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[info] Done updating.
[info] Loading project definition from /Users/rad/dev/my/scathon/project
[info] Set current project to scathon (in build file:/Users/rad/dev/my/scathon/)
[info] Packaging /Users/rad/dev/my/scathon/scathon-client/target/scala-2.11/scathon-client_2.11-0.2.1-sources.jar ...
[info] Packaging /Users/rad/dev/my/scathon/scathon-models/target/scala-2.11/scathon-models_2.11-0.2.1-sources.jar ...
[info] Packaging /Users/rad/dev/my/scathon/scathon-testServer/target/scala-2.11/scathon-testserver_2.11-0.2.1-sources.jar ...
[info] Done packaging.
[info] Done packaging.
[info] Done packaging.
[info] Wrote /Users/rad/dev/my/scathon/scathon-models/target/scala-2.11/scathon-models_2.11-0.2.1.pom
[info] :: delivering :: uk.co.appministry#scathon_2.11;0.2.1 :: 0.2.1 :: release :: Mon Jan 30 23:34:00 GMT 2017
[info]  delivering ivy file to /Users/rad/dev/my/scathon/target/scala-2.11/ivy-0.2.1.xml
[info] :: delivering :: uk.co.appministry#scathon-models_2.11;0.2.1 :: 0.2.1 :: release :: Mon Jan 30 23:34:00 GMT 2017
[info]  delivering ivy file to /Users/rad/dev/my/scathon/scathon-models/target/scala-2.11/ivy-0.2.1.xml
[info] Wrote /Users/rad/dev/my/scathon/scathon-testServer/target/scala-2.11/scathon-testserver_2.11-0.2.1.pom
[info] Wrote /Users/rad/dev/my/scathon/scathon-client/target/scala-2.11/scathon-client_2.11-0.2.1.pom
[info] Main Scala API documentation to /Users/rad/dev/my/scathon/scathon-models/target/scala-2.11/api...
[info] :: delivering :: uk.co.appministry#scathon-testserver_2.11;0.2.1 :: 0.2.1 :: release :: Mon Jan 30 23:34:00 GMT 2017
[info]  delivering ivy file to /Users/rad/dev/my/scathon/scathon-testServer/target/scala-2.11/ivy-0.2.1.xml
[info] :: delivering :: uk.co.appministry#scathon-client_2.11;0.2.1 :: 0.2.1 :: release :: Mon Jan 30 23:34:00 GMT 2017
[info]  delivering ivy file to /Users/rad/dev/my/scathon/scathon-client/target/scala-2.11/ivy-0.2.1.xml
[info] Main Scala API documentation to /Users/rad/dev/my/scathon/scathon-testServer/target/scala-2.11/api...
[info] Packaging /Users/rad/dev/my/scathon/scathon-models/target/scala-2.11/scathon-models_2.11-0.2.1.jar ...
[info] Done packaging.
[info] Packaging /Users/rad/dev/my/scathon/scathon-testServer/target/scala-2.11/scathon-testserver_2.11-0.2.1.jar ...
[info] Main Scala API documentation to /Users/rad/dev/my/scathon/scathon-client/target/scala-2.11/api...
[info] Done packaging.
[info] Packaging /Users/rad/dev/my/scathon/scathon-client/target/scala-2.11/scathon-client_2.11-0.2.1.jar ...
[info] Done packaging.
model contains 16 documentable templates
[warn] there was one feature warning; re-run with -feature for details
model contains 17 documentable templates
[info] Main Scala API documentation successful.
[info] Packaging /Users/rad/dev/my/scathon/scathon-client/target/scala-2.11/scathon-client_2.11-0.2.1-javadoc.jar ...
[info] Done packaging.
Please enter PGP passphrase (or ENTER to abort): ***************************
[warn] there was one feature warning; re-run with -feature for details
[warn] one warning found
[info] Main Scala API documentation successful.
[info] Packaging /Users/rad/dev/my/scathon/scathon-testServer/target/scala-2.11/scathon-testserver_2.11-0.2.1-javadoc.jar ...
[info] Done packaging.
model contains 157 documentable templates
[warn] one warning found
[info] Main Scala API documentation successful.
[info] Packaging /Users/rad/dev/my/scathon/scathon-models/target/scala-2.11/scathon-models_2.11-0.2.1-javadoc.jar ...
[info] Done packaging.
[info]  published scathon-client_2.11 to https://oss.sonatype.org/service/local/staging/deploy/maven2/uk/co/appministry/scathon-client_2.11/0.2.1/scathon-client_2.11-0.2.1-javadoc.jar
[info]  published scathon-client_2.11 to https://oss.sonatype.org/service/local/staging/deploy/maven2/uk/co/appministry/scathon-client_2.11/0.2.1/scathon-client_2.11-0.2.1-sources.jar.asc
[info]  published scathon-client_2.11 to https://oss.sonatype.org/service/local/staging/deploy/maven2/uk/co/appministry/scathon-client_2.11/0.2.1/scathon-client_2.11-0.2.1.jar.asc
[info]  published scathon-client_2.11 to https://oss.sonatype.org/service/local/staging/deploy/maven2/uk/co/appministry/scathon-client_2.11/0.2.1/scathon-client_2.11-0.2.1-javadoc.jar.asc
[info]  published scathon-client_2.11 to https://oss.sonatype.org/service/local/staging/deploy/maven2/uk/co/appministry/scathon-client_2.11/0.2.1/scathon-client_2.11-0.2.1-sources.jar
[info]  published scathon-client_2.11 to https://oss.sonatype.org/service/local/staging/deploy/maven2/uk/co/appministry/scathon-client_2.11/0.2.1/scathon-client_2.11-0.2.1.pom
[info]  published scathon-client_2.11 to https://oss.sonatype.org/service/local/staging/deploy/maven2/uk/co/appministry/scathon-client_2.11/0.2.1/scathon-client_2.11-0.2.1.pom.asc
[info]  published scathon-client_2.11 to https://oss.sonatype.org/service/local/staging/deploy/maven2/uk/co/appministry/scathon-client_2.11/0.2.1/scathon-client_2.11-0.2.1.jar
[info]  published scathon-models_2.11 to https://oss.sonatype.org/service/local/staging/deploy/maven2/uk/co/appministry/scathon-models_2.11/0.2.1/scathon-models_2.11-0.2.1.pom.asc
[info]  published scathon-models_2.11 to https://oss.sonatype.org/service/local/staging/deploy/maven2/uk/co/appministry/scathon-models_2.11/0.2.1/scathon-models_2.11-0.2.1-sources.jar.asc
[info]  published scathon-models_2.11 to https://oss.sonatype.org/service/local/staging/deploy/maven2/uk/co/appministry/scathon-models_2.11/0.2.1/scathon-models_2.11-0.2.1-javadoc.jar.asc
[info]  published scathon-models_2.11 to https://oss.sonatype.org/service/local/staging/deploy/maven2/uk/co/appministry/scathon-models_2.11/0.2.1/scathon-models_2.11-0.2.1.jar.asc
[info]  published scathon-models_2.11 to https://oss.sonatype.org/service/local/staging/deploy/maven2/uk/co/appministry/scathon-models_2.11/0.2.1/scathon-models_2.11-0.2.1-javadoc.jar
[info]  published scathon-models_2.11 to https://oss.sonatype.org/service/local/staging/deploy/maven2/uk/co/appministry/scathon-models_2.11/0.2.1/scathon-models_2.11-0.2.1.jar
[info]  published scathon-models_2.11 to https://oss.sonatype.org/service/local/staging/deploy/maven2/uk/co/appministry/scathon-models_2.11/0.2.1/scathon-models_2.11-0.2.1.pom
[info]  published scathon-models_2.11 to https://oss.sonatype.org/service/local/staging/deploy/maven2/uk/co/appministry/scathon-models_2.11/0.2.1/scathon-models_2.11-0.2.1-sources.jar
[info]  published scathon-testserver_2.11 to https://oss.sonatype.org/service/local/staging/deploy/maven2/uk/co/appministry/scathon-testserver_2.11/0.2.1/scathon-testserver_2.11-0.2.1-javadoc.jar
[info]  published scathon-testserver_2.11 to https://oss.sonatype.org/service/local/staging/deploy/maven2/uk/co/appministry/scathon-testserver_2.11/0.2.1/scathon-testserver_2.11-0.2.1-sources.jar
[info]  published scathon-testserver_2.11 to https://oss.sonatype.org/service/local/staging/deploy/maven2/uk/co/appministry/scathon-testserver_2.11/0.2.1/scathon-testserver_2.11-0.2.1.pom
[info]  published scathon-testserver_2.11 to https://oss.sonatype.org/service/local/staging/deploy/maven2/uk/co/appministry/scathon-testserver_2.11/0.2.1/scathon-testserver_2.11-0.2.1.jar
[info]  published scathon-testserver_2.11 to https://oss.sonatype.org/service/local/staging/deploy/maven2/uk/co/appministry/scathon-testserver_2.11/0.2.1/scathon-testserver_2.11-0.2.1-sources.jar.asc
[info]  published scathon-testserver_2.11 to https://oss.sonatype.org/service/local/staging/deploy/maven2/uk/co/appministry/scathon-testserver_2.11/0.2.1/scathon-testserver_2.11-0.2.1.jar.asc
[info]  published scathon-testserver_2.11 to https://oss.sonatype.org/service/local/staging/deploy/maven2/uk/co/appministry/scathon-testserver_2.11/0.2.1/scathon-testserver_2.11-0.2.1.pom.asc
[info]  published scathon-testserver_2.11 to https://oss.sonatype.org/service/local/staging/deploy/maven2/uk/co/appministry/scathon-testserver_2.11/0.2.1/scathon-testserver_2.11-0.2.1-javadoc.jar.asc
[success] Total time: 35 s, completed Jan 30, 2017 11:34:35 PM

If I was to publish this project for Scala 2.12, I’d do the following:

SCALA_VERSION=2.12.1
$ sbt ++$SCALA_VERSION -Dscala.version=$SCALA_VERSION publishSigned

And release:

$ sbt sonatypeRelease

The output should look like:

$ sbt sonatypeRelease
[info] Loading global plugins from /Users/rad/.sbt/0.13/plugins
[info] Loading project definition from /Users/rad/dev/my/scathon/project
[info] Set current project to scathon (in build file:/Users/rad/dev/my/scathon/)
[info] Nexus repository URL: https://oss.sonatype.org/service/local
[info] sonatypeProfileName = uk.co.appministry
[info] Reading staging repository profiles...
[info] Reading staging profiles...
[info] Closing staging repository [ukcoappministry-1008] status:open, profile:uk.co.appministry(439d1bb6b3d35e) description: Implicitly created (auto staging).
[info] Activity open started:2017-01-30T23:34:14.860Z, stopped:2017-01-30T23:34:18.364Z
[info] repositoryCreated: id:ukcoappministry-1008, user:radekg, ip:92.79.39.101
[info] Activity close started:2017-01-30T23:38:12.624Z, stopped:
[info]   Evaluate: id:5e9e8e6f8d20a3, rule:sources-staging
[info]   Evaluate: checksum-staging
[info]     Passed: checksum-staging
[info]   Evaluate: signature-staging
[info]     Passed: signature-staging
[info]   Evaluate: sources-staging
[info]     Passed: sources-staging
[info]   Evaluate: javadoc-staging
[info]     Passed: javadoc-staging
[info]   Evaluate: pom-staging
[info]     Passed: pom-staging
[info]     Passed: id:5e9e8e6f8d20a3
[info]      email: to:radek@gruchalski.com
[info] repositoryClosed: id:ukcoappministry-1008
[info] Closed successfully
[info] Promoting staging repository [ukcoappministry-1008] status:closed, profile:uk.co.appministry(439d1bb6b3d35e) description: Implicitly created (auto staging).
[info] Activity release started:2017-01-30T23:38:26.336Z, stopped:
[info]   Evaluate: id:5e9e8e6f8d20a3, rule:sources-staging
[info]   Evaluate: sources-staging
[info]     Passed: sources-staging
[info]   Evaluate: javadoc-staging
[info]     Passed: javadoc-staging
[info]   Evaluate: signature-staging
[info]     Passed: signature-staging
[info]   Evaluate: pom-staging
[info]     Passed: pom-staging
[info]   Evaluate: checksum-staging
[info]     Passed: checksum-staging
[info]     Passed: id:5e9e8e6f8d20a3
[info]   Evaluate: id:nx-internal-ruleset, rule:RepositoryWritePolicy
[info]   Evaluate: RepositoryWritePolicy
[info]     Passed: RepositoryWritePolicy
[info]     Passed: id:nx-internal-ruleset
[info]  copyItems: source:ukcoappministry-1008, target:releases
[info]      email: to:radek@gruchalski.com
[info] repositoryReleased: id:ukcoappministry-1008, target:releases
[info] Promoted successfully
[info] Dropping staging repository [ukcoappministry-1008] status:released, profile:uk.co.appministry(439d1bb6b3d35e) description: Implicitly created (auto staging).
[info] Dropped successfully: ukcoappministry-1008
[info] Set current project to scathon (in build file:/Users/rad/dev/my/scathon/)

If this was a first release with a given organization, go back to your Sonatype JIRA ticket and let them know you’ve released your first version. The Maven Central sync will be enabled for your organization. It might take a couple of hours before you see your changes in Central.

That’s about it.

Some interesting links: