Publishing to the Central Repo

Note

The recipe section of the documentation focuses on the objectives with minimal explanations.

See also Sonatype's Publish guides for general concepts around publishing to the Central Portal.

Objective

I want to publish my project to the Central Repository.

Steps

Preliminary 1: Central Portal registration

Create a Central Portal account, following Sonatype's Publish guides.

  • If you had an OSSRH account, use Forgot password flow to convert the account to the new Central Portal, which lets you keep the previous namespace associations.
  • If you authenticate via GitHub, io.github.<user_name> will automatically be associated with the account.

Follow the steps described in register a namespace guide to associate a domain name with your account.

Preliminary 2: PGP key pair

Follow the Sonatype's GPG guide to generate a PGP key pair.

Install GnuPG, and verify the version:

$ gpg --version
gpg (GnuPG/MacGPG2) 2.2.8
libgcrypt 1.8.3
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>

Next generate a key:

$ gpg --gen-key

List the keys:

$ gpg --list-keys

/home/foo/.gnupg/pubring.gpg
------------------------------

pub   rsa4096 2018-08-22 [SC]
      1234517530FB96F147C6A146A326F592D39AAAAA
uid           [ultimate] your name <[email protected]>
sub   rsa4096 2018-08-22 [E]

Distribute the key:

$ gpg --keyserver keyserver.ubuntu.com --send-keys 1234517530FB96F147C6A146A326F592D39AAAAA

Step 1: sbt-pgp

The sbt-pgp plugin can sign the published artifacts with GPG/PGP. (Optionally sbt-ci-release can automate the publishing process.)

Add the following line to your project/plugins.sbt file to enable it for your build:

addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.3.1")

Note

Make sure that the gpg command is in PATH available to the sbt.

Step 2: Credentials

Generate a user token from the portal to be used for the credentials. The token must be stored somewhere safe (NOT in the repository).

sbt 2.x can also reads from the environment variables SONATYPE_USERNAME and SONATYPE_PASSWORD and appends a credential for central.sonatype.com out-of-box, which might be useful for automatic publishing from the CI environment, such as GitHub Actions.

- run: sbt ci-release
  env:
    PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }}
    PGP_SECRET: ${{ secrets.PGP_SECRET }}
    SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
    SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}

On a local machine, a common convention is a $HOME/.sbt/2/credentials.sbt file, with the following:

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

Next create a file $HOME/.sbt/sonatype_central_credentials:

host=central.sonatype.com
user=<your username>
password=<your password>

Step 3: Configure build.sbt

To publish to a Maven repository, you'll need to configure a few settings so that the correct metadata is generated.

Note: To publish to the Central Portal, publishTo must be set to the localStaging repository:

// new setting for the Central Portal
publishTo := {
  val centralSnapshots = "https://central.sonatype.com/repository/maven-snapshots/"
  if version.value.endsWith("-SNAPSHOT") then Some("central-snapshots" at centralSnapshots)
  else localStaging.value
}

Add these settings at the end of build.sbt or a separate publish.sbt:

organization := "com.example.project2"
organizationName := "example"
organizationHomepage := Some(url("http://example.com/"))

scmInfo := Some(
  ScmInfo(
    url("https://github.com/your-account/your-project"),
    "scm:[email protected]:your-account/your-project.git"
  )
)
developers := List(
  Developer(
    id = "Your identifier",
    name = "Your Name",
    email = "your@email",
    url = url("http://your.url")
  )
)

description := "Some description about your project."
licenses := List(License.Apache2)
homepage := Some(url("https://github.com/example/project"))

// Remove all additional repository other than Maven Central from POM
pomIncludeRepository := { _ => false }
publishMavenStyle := true

// new setting for the Central Portal
publishTo := {
  val centralSnapshots = "https://central.sonatype.com/repository/maven-snapshots/"
  if version.value.endsWith("-SNAPSHOT") then Some("central-snapshots" at centralSnapshots)
  else localStaging.value
}

The full format of a pom.xml (an end product of the project configuration used by Maven) file is outlined in POM Reference. You can add more data to it with the pomExtra option in build.sbt.

Step 4: Stage the artifacts

From sbt shell run:

> publishSigned

Step 5: Upload or release the bundle

From sbt shell run:

> sonaUpload

This will upload the bundle to the Central Portal. Hit the "Publish" button to publish to the Central Repository.

If you want to automate the publishing, run:

> sonaRelease

It might take 10 minutes to a few hours for the published artifacts to be visible on the Central Repository https://repo1.maven.org/maven2/.