From 1465c74cf6532d8ac4325cb1c43dacb0559224df Mon Sep 17 00:00:00 2001 From: Alec Grieser Date: Fri, 31 Oct 2025 15:55:49 +0000 Subject: [PATCH 1/4] Update the release plugin to use the central publishing API directly Following the recommendation of the central publishing portal, this updates our publishing plugin from Nexus to jReleaser. See: https://central.sonatype.org/publish/publish-portal-gradle/ The way that this works is that now, the "publish" command will publish artifacts locally to a staging repository that is in the build directory. At the conclusion of the build, the `jreleaserDeploy` task will take those artifacts and send them up to maven central. It will sign them before it does so, which is why this also removes the manual signing configuration that we'd previously had in our `publishing.gradle` configuration. I've tested this out by applying these changes to a parallel repo I had. I was even able to validate that it could deploy to maven central, but I had configured that other repo to only uplaod artifacts. This is supposed to both upload and then publish the artifacts in the "deploy" step. I have not been able to actually validate that that worked, for obvious reasons. I can see locally that when I call `publish`, it publishes to a staging folder in the build directory. This resolves #3709. --- .github/workflows/release.yml | 11 ++++++----- build.gradle | 34 +++++++++++++++++++++++++++------- gradle/libs.versions.toml | 2 +- gradle/publishing.gradle | 11 ++++------- 4 files changed, 38 insertions(+), 20 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b6de4deefe..6ae1a26525 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -185,12 +185,13 @@ jobs: - name: Publish Artifacts uses: ./actions/run-gradle with: - gradle_command: publish closeAndReleaseStagingRepositories -PreleaseBuild=true -PpublishBuild=true -PgithubPublish=true -PcentralPublish=true + gradle_command: publish jreleaserDeploy -PreleaseBuild=true -PpublishBuild=true -PgithubPublish=true -PcentralPublish=true env: - ORG_GRADLE_PROJECT_signingKey: ${{ secrets.GPG_PRIVATE_KEY }} - ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.GPG_PASSPHRASE }} - ORG_GRADLE_PROJECT_sonatypeUsername: ${{ secrets.SONATYPE_USERNAME }} - ORG_GRADLE_PROJECT_sonatypePassword: ${{ secrets.SONATYPE_PASSWORD }} + JRELEASER_GPG_PUBLIC_KEY: ${{ secrets.GPG_PUBLIC_KEY }} + JRELEASER_GPG_SECRET_KEY: ${{ secrets.GPG_PRIVATE_KEY }} + JRELEASER_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} + JRELEASER_MAVENCENTRAL_USERNAME: ${{ secrets.SONATYPE_USERNAME }} + JRELEASER_MAVENCENTRAL_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Post release: Update various files which reference version diff --git a/build.gradle b/build.gradle index d4dc5c72ea..fa888f5b0a 100644 --- a/build.gradle +++ b/build.gradle @@ -41,7 +41,7 @@ plugins { alias(libs.plugins.protobuf) alias(libs.plugins.versions) alias(libs.plugins.spotbugs) - alias(libs.plugins.nexus) + alias(libs.plugins.jreleaser) alias(libs.plugins.download) } @@ -310,13 +310,33 @@ subprojects { // Configure publishing for maven central. This is done in the top-level build.gradle, and then // all of the subprojects configure the artifacts they want published by applying // ${rootDir}/gradle/publishing.gradle in the project gradle. By default, we publish a library -// from each package, but this can be configured by adjusting the publishLibrary variable +// from each package, but this can be configured by adjusting the publishLibrary variable. +// Each subproject will place its artifacts into the central staging repository, +// which will then be picked up by the release configuration if (Boolean.parseBoolean(centralPublish)) { - nexusPublishing { - repositories { - sonatype { - // Update the URL now that the OSSRH service has been sunset: https://central.sonatype.org/news/20250326_ossrh_sunset/ - nexusUrl.set(uri("https://ossrh-staging-api.central.sonatype.com/service/local/")) + jreleaser { + project { + authors = ['FoundationDB'] + license = 'The Apache License, Version 2.0' + licenseUrl = 'https://www.apache.org/licenses/LICENSE-2.0' + links { + homepage = 'https://foundationdb.github.io/fdb-record-layer/' + } + inceptionYear = '2021' + } + + deploy { + maven { + mavenCentral { + sonatype { + active = 'ALWAYS' + url = 'https://central.sonatype.com/api/v1/publisher' + applyMavenCentralRules = true + stage = 'FULL' + + stagingRepository("${rootDir}/.out/staging-repo") + } + } } } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c4e6482b97..6bc4859419 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -153,7 +153,7 @@ test-compileOnly = [ "autoService", "jsr305" ] download = { id = "de.undercouch.download", version = "5.6.0" } gitversion = { id = "com.palantir.git-version", version = "3.1.0" } jmh = { id = "me.champeau.jmh", version = "0.7.2" } -nexus = { id = "io.github.gradle-nexus.publish-plugin", version = "2.0.0" } +jreleaser = { id = "org.jreleaser", version = "1.21.0" } protobuf = { id = "com.google.protobuf", version = "0.9.4" } serviceloader = { id = "com.github.harbby.gradle.serviceloader", version = "1.1.8" } shadow = { id = "com.gradleup.shadow", version = "8.3.5" } diff --git a/gradle/publishing.gradle b/gradle/publishing.gradle index 79e4d82ef9..2d076796bd 100644 --- a/gradle/publishing.gradle +++ b/gradle/publishing.gradle @@ -18,8 +18,6 @@ * limitations under the License. */ -apply plugin: 'signing' - // Add various details to the pom file to allow for publishing def addPublishingInfo(publication) { publication.pom { @@ -88,11 +86,6 @@ if (ext.publishLibrary) { } } } - if (Boolean.parseBoolean(centralPublish)) { - signing { - sign publishing.publications.library - } - } } ext { @@ -103,6 +96,10 @@ ext { publishing { if (Boolean.parseBoolean(publishBuild)) { repositories { + maven { + url = "${rootProject.rootDir}/.out/staging-repo" + } + if (Boolean.parseBoolean(githubPublish)) { maven { name = "GitHubPackages" From f84f0e560ff58f1cc4bdb0ef1390f54ecfb38169 Mon Sep 17 00:00:00 2001 From: Alec Grieser Date: Mon, 3 Nov 2025 18:29:37 +0000 Subject: [PATCH 2/4] update inception year and explicitly opt in to signing --- build.gradle | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index fa888f5b0a..c3ef5fc9f3 100644 --- a/build.gradle +++ b/build.gradle @@ -322,7 +322,12 @@ if (Boolean.parseBoolean(centralPublish)) { links { homepage = 'https://foundationdb.github.io/fdb-record-layer/' } - inceptionYear = '2021' + inceptionYear = '2015' + } + + signing { + active = 'ALWAYS' + armored = true } deploy { From 092922c2453440ec6bc2e3a26b5e6e0fea6c212c Mon Sep 17 00:00:00 2001 From: Alec Grieser Date: Mon, 3 Nov 2025 19:07:21 +0000 Subject: [PATCH 3/4] remove additional signing ; use layout instead of string interpolation ; add input --- build.gradle | 20 ++++++++----------- .../fdb-record-layer-core-shaded.gradle | 6 ------ gradle/publishing.gradle | 2 +- 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/build.gradle b/build.gradle index c3ef5fc9f3..8e5d279015 100644 --- a/build.gradle +++ b/build.gradle @@ -18,9 +18,8 @@ * limitations under the License. */ -import org.yaml.snakeyaml.Yaml - import org.apache.tools.ant.taskdefs.condition.Os +import org.yaml.snakeyaml.Yaml buildscript { repositories { @@ -60,7 +59,6 @@ allprojects { apply plugin: 'base' apply plugin: 'java-library' apply plugin: 'maven-publish' - apply plugin: 'signing' apply plugin: 'project-reports' apply plugin: 'com.github.ben-manes.versions' apply plugin: 'de.undercouch.download' @@ -165,14 +163,6 @@ allprojects { dependsOn tasks.jar, tasks.package } - signing { - def signingKey = findProperty("signingKey") - def signingPassword = findProperty("signingPassword") - if (signingKey != null && signingPassword != null) { - useInMemoryPgpKeys(signingKey, signingPassword) - } - } - repositories { if (System.getenv("ARTIFACT_VERSION") != null) { version = "${System.getenv('ARTIFACT_VERSION')}" @@ -314,6 +304,8 @@ subprojects { // Each subproject will place its artifacts into the central staging repository, // which will then be picked up by the release configuration if (Boolean.parseBoolean(centralPublish)) { + var stagingRepo = layout.buildDirectory.dir('staging-repo').get() + jreleaser { project { authors = ['FoundationDB'] @@ -339,12 +331,16 @@ if (Boolean.parseBoolean(centralPublish)) { applyMavenCentralRules = true stage = 'FULL' - stagingRepository("${rootDir}/.out/staging-repo") + stagingRepository(stagingRepo.asFile.path) } } } } + + dependsOnAssemble = true } + + tasks.jreleaserDeploy.inputs.dir(stagingRepo) } // Script for upgrading gradle. To upgrade the gradle version, set the property to the version diff --git a/fdb-record-layer-core-shaded/fdb-record-layer-core-shaded.gradle b/fdb-record-layer-core-shaded/fdb-record-layer-core-shaded.gradle index c3f46d943c..c0d3837c0a 100644 --- a/fdb-record-layer-core-shaded/fdb-record-layer-core-shaded.gradle +++ b/fdb-record-layer-core-shaded/fdb-record-layer-core-shaded.gradle @@ -120,9 +120,3 @@ publishing { } } - -if (Boolean.parseBoolean(centralPublish)) { - signing { - sign publishing.publications.shadow - } -} diff --git a/gradle/publishing.gradle b/gradle/publishing.gradle index 2d076796bd..1be6b269a3 100644 --- a/gradle/publishing.gradle +++ b/gradle/publishing.gradle @@ -97,7 +97,7 @@ publishing { if (Boolean.parseBoolean(publishBuild)) { repositories { maven { - url = "${rootProject.rootDir}/.out/staging-repo" + url = rootProject.layout.buildDirectory.dir('staging-repo') } if (Boolean.parseBoolean(githubPublish)) { From 70c22aad8ecfb34a073229787e59bb142e7efa46 Mon Sep 17 00:00:00 2001 From: Alec Grieser Date: Mon, 3 Nov 2025 19:23:16 +0000 Subject: [PATCH 4/4] add dependency between jreleaserDeploy and artifact staging --- build.gradle | 6 +++--- gradle/publishing.gradle | 14 ++++++++++++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index 8e5d279015..b082d0999d 100644 --- a/build.gradle +++ b/build.gradle @@ -303,8 +303,8 @@ subprojects { // from each package, but this can be configured by adjusting the publishLibrary variable. // Each subproject will place its artifacts into the central staging repository, // which will then be picked up by the release configuration -if (Boolean.parseBoolean(centralPublish)) { - var stagingRepo = layout.buildDirectory.dir('staging-repo').get() +if (Boolean.parseBoolean(publishBuild) && Boolean.parseBoolean(centralPublish)) { + var stagingRepo = layout.buildDirectory.dir('staging-repo') jreleaser { project { @@ -331,7 +331,7 @@ if (Boolean.parseBoolean(centralPublish)) { applyMavenCentralRules = true stage = 'FULL' - stagingRepository(stagingRepo.asFile.path) + stagingRepository(stagingRepo.get().asFile.path) } } } diff --git a/gradle/publishing.gradle b/gradle/publishing.gradle index 1be6b269a3..6bb05393a6 100644 --- a/gradle/publishing.gradle +++ b/gradle/publishing.gradle @@ -95,9 +95,19 @@ ext { publishing { if (Boolean.parseBoolean(publishBuild)) { + repositories { - maven { - url = rootProject.layout.buildDirectory.dir('staging-repo') + if (Boolean.parseBoolean(centralPublish)) { + // For JReleaser to deploy artifacts, they must have been staged to the local staging repo. + // Mark that directory as an output and declare a dependency between publishing the + // project and deploying artifacts. + var stagingDir = rootProject.layout.buildDirectory.dir('staging-repo') + tasks.publish.outputs.dir(stagingDir) + rootProject.tasks.findByName('jreleaserDeploy').dependsOn(tasks.publish) + + maven { + url = stagingDir + } } if (Boolean.parseBoolean(githubPublish)) {