This project demonstrates how to publish a Gradle project to OSSRH. Refer to build.gradle for a complete working sample.
The following steps discuss how to configure the build.gradle
for deploying to OSSRH.
The first step is to apply the necessary plugins:
plugins {
id "java"
id "signing"
id "maven-publish"
id "io.github.gradle-nexus.publish-plugin" version "1.0.0"
}
-
We apply the Java Plugin to use Gradle’s standard Java conventions. This is applied to every project that is deployed.
-
We apply the Signing Plugin to sign the Maven artifacts. This is applied to every project that is deployed.
-
We apply the maven-publish adds the ability to publish our artifacts. This is applied to every project that is deployed.
-
We apply the io.github.gradle-nexus.publish-plugin to manage the staging repository in OSSRH. This is applied only to the root project.
We configure the group
so it can be used to default the group in the pom:
group = "io.rwinch.sample"
Here we configure the Gradle Publications (i.e. what will be published to the repository).
In our example, we configure a publication named maven
that contains all of the java
compoonents.
This is applied to every project that is deployed.
publishing {
publications {
maven(MavenPublication) {
from(components.java)
}
}
}
Next we must ensure that all of the OSSRH requirements are met. This is applied to every project that is deployed.
The following code generates the required Javadoc and Sources using Gradle’s Java extension.
java {
withJavadocJar()
withSourcesJar()
}
The following code configures the Signing Plugin to generate the required signatures if the Gradle property signingKey
or signingKeyId
is found.
def hasSigningKey = project.hasProperty("signingKeyId") || project.hasProperty("signingKey")
if(hasSigningKey) {
sign(project)
}
void sign(Project project) {
project.signing {
required { project.gradle.taskGraph.hasTask("required") }
def signingKeyId = project.findProperty("signingKeyId")
def signingKey = project.findProperty("signingKey")
def signingPassword = project.findProperty("signingPassword")
if (signingKeyId) {
useInMemoryPgpKeys(signingKeyId, signingKey, signingPassword)
} else if (signingKey) {
useInMemoryPgpKeys(signingKey, signingPassword)
}
sign publishing.publications.maven
}
}
Next we need to ensure that Gradle is configured to customize the pom in order to ensure the required metadata is present in the Maven pom.
The groupId
, artifactId
, and vession
of the pom are defaulted by the maven-publish
plugin.
project.plugins.withType(MavenPublishPlugin).all {
PublishingExtension publishing = project.extensions.getByType(PublishingExtension)
publishing.publications.withType(MavenPublication).all { mavenPublication ->
mavenPublication.pom {
name = "${project.group}:${project.name}"
description = name
url = "https://github.com/rwinch/gradle-publish-ossrh-sample"
licenses {
license {
name = "The Apache License, Version 2.0"
url = "https://www.apache.org/licenses/LICENSE-2.0"
}
}
developers {
developer {
id = "rwinch"
name = "Rob Winch"
email = "rwinch@noreply.github.com"
}
}
scm {
connection = "scm:git:https://github.com/rwinch/gradle-publish-ossrh-sample"
developerConnection = "scm:git:ssh://github.com/rwinch/gradle-publish-ossrh-sample.git"
url = "https://github.com/rwinch/gradle-publish-ossrh-sample"
}
}
}
}
We configure the Gradle Nexus Publishing Plugin.
By default it uses credentials configured as the project properties sonatypeUsername
and sonatypePassword
.
This is only configured on the root project.
If you registered with Sonatype after 24 February 2021 to publish to Maven Central, then you must set your nexusUrl
and snapshotRepositoryUrl
manually. See https://central.sonatype.org/news/20210223_new-users-on-s01/ for more information.
nexusPublishing {
repositories {
sonatype() //sonatypeUsername and sonatypePassword properties are used automatically
// OR, if you registered with Sonatype after 24 February 2021
// sonatype {
// nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/"))
// snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/"))
// }
}
// these are not strictly required. The default timeouts are set to 1 minute. But Sonatype can be really slow.
// If you get the error "java.net.SocketTimeoutException: timeout", these lines will help.
connectTimeout = Duration.ofMinutes(3)
clientTimeout = Duration.ofMinutes(3)
}
Finally, we set up a repository on our local file system in the build directory, so that we can easily test publishing independant of OSSRH. This is not required, but it makes troubleshooting easier. This is applied to every project that is deployed.
publishing {
repositories {
maven {
name = "local"
// change URLs to point to your repos, e.g. http://my.org/repo
def releasesRepoUrl = "$buildDir/repos/releases"
def snapshotsRepoUrl = "$buildDir/repos/snapshots"
url = version.endsWith("SNAPSHOT") ? snapshotsRepoUrl : releasesRepoUrl
}
}
}
The configuration we use requires the following Gradle Properties to be set:
-
signingKey
the pgp used to sign the artifacts. This project has atest-private.pgp
key in it that you can use to try things out. Do not use it for your own artifacts because anyone could use it to impersonate you. -
signingPassword
the password for thesigningKey
. The password fortest-private.pgp
ispassword
. Again, do not use this for real deployments. -
sonatypeUsername
the username from sonatype used to publish artifacts. This is the token username, not the one used for logging into the UI. -
sonatypePassword
the password from sonatype used to publish artifacts. This is the token password, not the one used for logging into the UI.
The following will provide all the Gradle Properties necessary for the commands below using environment variables.
export ORG_GRADLE_PROJECT_signingKey=`cat test-private.pgp`
export ORG_GRADLE_PROJECT_signingPassword=password
export ORG_GRADLE_PROJECT_sonatypeUsername=<replace-with-your-token-username>
export ORG_GRADLE_PROJECT_sonatypePassword=<replace-with-your-token-password>
When you first set up the code or need to troubleshoot signing process, you can run the signMavenPublication
task.
$ ./gradlew signMavenPublication $ tree build/libs build/libs ├── publish-ossrh-sample-1.0.0.jar ├── publish-ossrh-sample-1.0.0.jar.asc ├── publish-ossrh-sample-1.0.0-javadoc.jar ├── publish-ossrh-sample-1.0.0-javadoc.jar.asc ├── publish-ossrh-sample-1.0.0-sources.jar └── publish-ossrh-sample-1.0.0-sources.jar.asc
You can also test what is going to be published using the local publication to publish to a directory on your local machine. You will notice, if we have defined the signing properties, that all of our artifacts (jars, javadoc, pom, etc) are also signed.
$ ./gradlew publishMavenPublicationToLocalRepository $ tree build/repos/releases/ build/repos/releases/ └── io └── rwinch └── sample └── publish-ossrh-sample ├── 1.0.0 │ ├── publish-ossrh-sample-1.0.0.jar │ ├── publish-ossrh-sample-1.0.0.jar.asc │ ├── publish-ossrh-sample-1.0.0.jar.asc.md5 │ ├── publish-ossrh-sample-1.0.0.jar.asc.sha1 │ ├── publish-ossrh-sample-1.0.0.jar.asc.sha256 │ ├── publish-ossrh-sample-1.0.0.jar.asc.sha512 │ ├── publish-ossrh-sample-1.0.0.jar.md5 │ ├── publish-ossrh-sample-1.0.0.jar.sha1 │ ├── publish-ossrh-sample-1.0.0.jar.sha256 │ ├── publish-ossrh-sample-1.0.0.jar.sha512 │ ├── publish-ossrh-sample-1.0.0-javadoc.jar │ ├── publish-ossrh-sample-1.0.0-javadoc.jar.asc ...
If you publish to OSSRH it will automatically create a staging repository if the version looks like a release:
$ ./gradlew publishToSonatype
Now visit https://oss.sonatype.org/#stagingRepositories and you can view the staged repository using the Sonatype username and password (the UI one not the token).
We can publish and close the repository all at once:
$ ./gradlew publishToSonatype closeSonatypeStagingRepository
If you want to release the staged repository as well, then you can perform:
$ ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository
Note
|
If you want to perform some additional checks before you release the repository, you can create a task that mustRunAfter the closeSonatypeStagingRepository task and ensure that the releaseSonatypeStagingRepository task depends on it. The staging repository can be accessed at https://oss.sonatype.org/service/local/repositories/{staging-id}/content
|