sureshg / gradle-publish-ossrh-sample

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

This project demonstrates how to publish a Gradle project to OSSRH. Refer to build.gradle for a complete working sample.

build.gradle

The following steps discuss how to configure the build.gradle for deploying to OSSRH.

Apply Plugins

The first step is to apply the necessary plugins:

build.gradle
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.

Configure group

We configure the group so it can be used to default the group in the pom:

build.gradle
group = "io.rwinch.sample"

Configure Gradle Publications

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.

build.gradle
publishing {
	publications {
		maven(MavenPublication) {
			from(components.java)
		}
	}
}

OSSRH Requirements

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.

build.gradle
java {
	withJavadocJar()
	withSourcesJar()
}

The following code configures the Signing Plugin to generate the required signatures if the Gradle property signingKey or signingKeyId is found.

build.gradle
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.

build.gradle
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"
			}
		}
	}
}

Configure Gradle Nexus Publishing Plugin

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.

build.gradle
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)
}

Publishing Local

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.

build.gradle
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
		}
	}
}

Gradle Tasks

The configuration we use requires the following Gradle Properties to be set:

  • signingKey the pgp used to sign the artifacts. This project has a test-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 the signingKey. The password for test-private.pgp is password. 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

About