The Most Condensed Guide to Publish to Maven Central with Gradle
Accounting
Create a Jira account
Head over to https://issues.sonatype.org and sign up.
Create a Jira ticket
Create a ticket on the OSSRH project. Example ticket.
Optional: Create a TXT record for your domain.
This is only required if you want to publish your artifacts with a groupId other than io.github.username, io.gitlab.username, io.gitee.username, io.bitbucket.username, io.sourceforge.username.
# Check the TXT records for ioki.com
dig -t txt ioki.com
# Output
# ...more
;; ANSWER SECTION:
ioki.com. 3600 IN TXT "OSSRH-96900"
# ...more
Reopen the Jira ticket
Required to start the automated process of checking the TXT record.
Signing
Create a key pair
Install GPG and create a new key pair
gpg --gen-key
You will be asked for an E-Mail address and a password.
Optional: Delete the signing subkey
Some tools will create a signing subkey. We have to delete them. Only the main private key should sign the artifacts.
# This will list all your public keys
gpg --list-keys
# Search for the just created public key and edit it
gpg --edit-key [KeyId]
# Search for the subkey (if available)
# that has `usage: S` and select them
key [KeyIndex]
# Delete the key
delkey
# Save the key deletion
save
The first two commands are mandatory to find out if there is a signing subkey. If there is none, you don’t need to do the other steps and can just quit
the editing.
Optional but recommended: Change the expire date
It is not required if you want to extend the expiration date every two years — which is the default expiration time.
# Edit the key again
gpg --edit-key [KeyId]
# Go into the expire tooling window
expire
# Enter 0 (zero) for "key never expires"
0
# Save the new key expire date
save
Publish the key to an keyserver
As time of writing, keyserver.ubuntu.com, pgp.mit.edu, and keys.openpgp.org are supported.
# Publish they key to the ubuntu keyserver
gpg --keyserver keyserver.ubuntu.com --send-keys [KeyId]
The steps above are one-time steps.
The steps below are required for each project you want to publish to Maven Central and may vary slightly depending on the type of project you have.
Continues Delivery
Create an ASCII armor formatted private key
To sign the artifacts later we have to put the private key to our CD server
# Export the secret key in ASCII armor and save it in key.asc
gpg --export-secret-keys --armor [KeyId] > key.asc
Put the content of the key.asc into your CD as an environment variable
Give it a proper name so you can recognize it later in your scripts. What about GPG_SIGNING_KEY
?
Put the key password into your CD as an environment variable
What about GPG_SIGNING_PASSWORD
?
Put the Jira account name and password into your CD as environment variables
What about SONATYPE_USER
and SONATYPE_PASSWORD
?
Coding
Setup publishing to publish sources and javadocs
It is required to publish Jar files with the -sources
and -javadoc
classifiers. However, these Jar files can also be empty or just contain your README file.
val dokkaJar = tasks.register<Jar>("dokkaJar") {
dependsOn(tasks.dokkaHtml)
from(tasks.dokkaHtml.flatMap { it.outputDirectory })
archiveClassifier.set("javadoc")
}
publishing {
publications {
publications.withType<MavenPublication> {
artifact(dokkaJar)
// ...more
}
}
}
This will put the output of the dokkaHtml
tasks into a Jar
file named as something-javadoc.jar
and add this file to any publication of the type MavenPublication
. Example pull request.
Note: Kotlin Multiplatform will automatically add the sources Jar to the publication. This may not be the case for pure Kotlin, Java, or Android projects. You will need to set up a task similar to your build script and add it to the publication.
Format the POM file according to the requirements
You have to provide at least name
, description
, url
, licenses.license.name
, licenses.license.url
, developers.developer.name
, developers.developer.email
, scm.url,
scm.connection
, scm.developerConnection
in the POM file. Example pull request.
Add the sonatype repositories to publishing
There are two different repositories to push to. One is for -SNAPSHOT
releases, and the other one is a staging repository where you have to push real releases and later promote (close and release) them to the release repository that is automatically synchronized with Maven Central.
publishing {
// ...more
repositories {
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") {
name = "SonatypeSnapshot"
credentials {
username = System.getenv("SONATYPE_USER")
password = System.getenv("SONATYPE_PASSWORD")
}
}
maven("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/") {
name = "SonatypeStaging"
credentials {
username = System.getenv("SONATYPE_USER")
password = System.getenv("SONATYPE_PASSWORD")
}
}
}
}
Publish to the staging repository
At this point you should be able to publish your project to both the snapshot and staging repositories. Example GitHub Action.
# Publish all publications to the snapshot repository
./gradlew publishAllPublicationsToSonatypeSnapshotRepository
# Publish all publications to the staging repository
./gradlew publishAllPublicationsToSonatypeStagingRepository
Promote (close and release) to the release repository
This can be done either manually or via HTTP API calls
Manually promote (close and release)
Go to https://s01.oss.sonatype.org/ and log using your Jira credentials. Click on Staging Repositories, locate your deployment and click on Close. After the staging release closes, you can click on Release. This starts the process of synchronizing to the project with Maven Central.
You can then safely Drop the staging repository.
Automatic promote (close and release) with HTTP API calls
First, you need to find out the staging profile id and the staging repositoy id
# Replace userName and password with your Jira credentials
curl --user userName:password https://s01.oss.sonatype.org/service/local/staging/profile_repositories
This will return something like
<stagingRepositories>
<data>
<stagingProfileRepository>
<profileId>5f2071504368e</profileId>
<profileName>com.ioki</profileName>
<profileType>repository</profileType>
<repositoryId>comioki-1000</repositoryId>
<!-- More -->
</stagingProfileRepository>
</data>
</stagingRepositories>
Use the profileId
and repositoryId
properties to Close the repository
# Replace userName and password with your Jira credentials
# as well as the profileId (here 5f2071504368e)
# and the repositoryId (here comioki-1000)
curl -X POST -H 'Content-Type: application/json' --user userName:password https://s01.oss.sonatype.org/service/local/staging/profiles/5f2071504368e/finish -d '{"data": {"stagedRepositoryId":"comioki-1000","targetRepositoryId":"release"}}'
You can then Release the content of the staging repository to the release repository which automatically synchronizes them with Maven Central
# Replace userName and password with your Jira credentials
# as well as the profileId (here 5f2071504368e)
# and the repositoryId (here comioki-1000)
curl -X POST -H 'Content-Type: application/json' --user userName:password https://s01.oss.sonatype.org/service/local/staging/profiles/5f2071504368e/promote -d '{"data": {"stagedRepositoryId":"comioki-1000","targetRepositoryId":"release"}}'
Finally, you can safely Drop the staging repo
# Replace userName and password with your Jira credentials
# as well as the profileId (here 5f2071504368e)
# and the repositoryId (here comioki-1000)
curl -X POST -H 'Content-Type: application/json' --user userName:password https://s01.oss.sonatype.org/service/local/staging/profiles/5f2071504368e/drop -d '{"data": {"stagedRepositoryId":"comioki-1000"}}'
Resources I found (useful) in my research and implementation:
- Offical Central Repository documentation
- Offical Central Repository documentation — Jira account
- Offical Central Repository documentation — POM file
- Offical Central Repository documentation — GPG
- Offical Central Repository documentation — GroupId/Coordinates
- Offical Central Repository documentation — Releasing
- Nexus Staging Plugin REST API documentation
- Some implementation details of the
vanniktech/radle-maven-publish-plugin
- Some implementation details of the
gradle-nexus/publish-plugin
- Tutorial of how to sign messages by DigitalOcean
- Gradle documentation — The Signing Plugin
- Gradle documentation —Maven Publish Plugin
Stackademic
Thank you for reading until the end. Before you go:
- Please consider clapping and following the writer! 👏
- Follow us on Twitter(X), LinkedIn, and YouTube.
- Visit Stackademic.com to find out more about how we are democratizing free programming education around the world.