From 7481cd0460abef73f63dbfdbe157f629b0d3bce3 Mon Sep 17 00:00:00 2001 From: Robert Stupp Date: Tue, 25 Mar 2025 14:46:32 +0100 Subject: [PATCH] Build/Release: Add a "generate digest" task and use for source tarball and Quarkus distributables * Ensure that digest and signature are generated for both Polaris-Server and admin tar/zip distribution * Move "generate digest" functionality to a Gradle task --- .../publishing/PublishingHelperExtension.kt | 6 -- .../src/main/kotlin/publishing/digest-task.kt | 66 +++++++++++++++++++ .../src/main/kotlin/publishing/rootProject.kt | 31 ++++----- .../src/main/kotlin/publishing/util.kt | 21 ------ quarkus/admin/build.gradle.kts | 28 ++++++++ quarkus/server/build.gradle.kts | 28 ++++++++ 6 files changed, 138 insertions(+), 42 deletions(-) create mode 100644 build-logic/src/main/kotlin/publishing/digest-task.kt diff --git a/build-logic/src/main/kotlin/publishing/PublishingHelperExtension.kt b/build-logic/src/main/kotlin/publishing/PublishingHelperExtension.kt index 419f6afbaf..26c879a116 100644 --- a/build-logic/src/main/kotlin/publishing/PublishingHelperExtension.kt +++ b/build-logic/src/main/kotlin/publishing/PublishingHelperExtension.kt @@ -49,12 +49,6 @@ constructor(objectFactory: ObjectFactory, project: Project) { objectFactory .fileProperty() .convention(project.provider { distributionDir.get().file("${baseName.get()}.tar.gz") }) - val sourceTarballDigest = - objectFactory - .fileProperty() - .convention( - project.provider { distributionDir.get().file("${baseName.get()}.tar.gz.sha512") } - ) val mailingLists = objectFactory.listProperty(String::class.java).convention(emptyList()) diff --git a/build-logic/src/main/kotlin/publishing/digest-task.kt b/build-logic/src/main/kotlin/publishing/digest-task.kt new file mode 100644 index 0000000000..b0b62a5900 --- /dev/null +++ b/build-logic/src/main/kotlin/publishing/digest-task.kt @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package publishing + +import java.security.MessageDigest +import javax.inject.Inject +import org.gradle.api.DefaultTask +import org.gradle.api.model.ObjectFactory +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputFile +import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.TaskAction +import org.gradle.work.DisableCachingByDefault + +@DisableCachingByDefault +abstract class GenerateDigest @Inject constructor(objectFactory: ObjectFactory) : DefaultTask() { + + @get:InputFile val file = objectFactory.fileProperty() + @get:Input val algorithm = objectFactory.property(String::class.java).convention("SHA-512") + @get:OutputFile + val outputFile = + objectFactory.fileProperty().convention { + val input = file.get().asFile + val algo = algorithm.get() + input.parentFile.resolve("${input.name}-${algo.replace("-", "").lowercase()}") + } + + @TaskAction + fun generate() { + val input = file.get().asFile + val digestFile = outputFile.get().asFile + val md = MessageDigest.getInstance(algorithm.get()) + input.inputStream().use { + val buffered = it.buffered(8192) + val buf = ByteArray(8192) + var rd: Int + while (true) { + rd = buffered.read(buf) + if (rd == -1) break + md.update(buf, 0, rd) + } + + digestFile.writeText( + md.digest().joinToString(separator = "") { eachByte -> "%02x".format(eachByte) } + + " ${input.name}" + ) + } + } +} diff --git a/build-logic/src/main/kotlin/publishing/rootProject.kt b/build-logic/src/main/kotlin/publishing/rootProject.kt index f8a637f546..ebfc3a5e99 100644 --- a/build-logic/src/main/kotlin/publishing/rootProject.kt +++ b/build-logic/src/main/kotlin/publishing/rootProject.kt @@ -61,27 +61,28 @@ internal fun configureOnRootProject(project: Project) = workingDir(project.projectDir) } - val digestSourceTarball = tasks.register("digestSourceTarball") - digestSourceTarball.configure { - mustRunAfter(sourceTarball) - - doFirst { - val e = project.extensions.getByType(PublishingHelperExtension::class.java) - generateDigest(e.sourceTarball.get().asFile, e.sourceTarballDigest.get().asFile, "SHA-512") + val digestSourceTarball = + tasks.register("digestSourceTarball") { + description = "Generate the source tarball digest" + mustRunAfter(sourceTarball) + file.set { + val e = project.extensions.getByType(PublishingHelperExtension::class.java) + e.sourceTarball.get().asFile + } } - } sourceTarball.configure { finalizedBy(digestSourceTarball) } if (isSigning) { - val signSourceTarball = tasks.register("signSourceTarball") - signSourceTarball.configure { - mustRunAfter(sourceTarball) - doFirst { - val e = project.extensions.getByType(PublishingHelperExtension::class.java) - sign(e.sourceTarball.get().asFile) + val signSourceTarball = + tasks.register("signSourceTarball") { + description = "Sign the source tarball" + mustRunAfter(sourceTarball) + doFirst { + val e = project.extensions.getByType(PublishingHelperExtension::class.java) + sign(e.sourceTarball.get().asFile) + } } - } sourceTarball.configure { finalizedBy(signSourceTarball) } } diff --git a/build-logic/src/main/kotlin/publishing/util.kt b/build-logic/src/main/kotlin/publishing/util.kt index 1d05a90cea..93c14abae6 100644 --- a/build-logic/src/main/kotlin/publishing/util.kt +++ b/build-logic/src/main/kotlin/publishing/util.kt @@ -23,10 +23,8 @@ import groovy.json.JsonException import groovy.json.JsonSlurper import groovy.util.Node import groovy.util.NodeList -import java.io.File import java.io.FileNotFoundException import java.net.URI -import java.security.MessageDigest import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.component.ModuleComponentSelector import org.gradle.api.artifacts.result.DependencyResult @@ -58,25 +56,6 @@ internal fun xmlNode(node: Node?, child: String): Node? { return null } -internal fun generateDigest(input: File, output: File, algorithm: String) { - val md = MessageDigest.getInstance(algorithm) - input.inputStream().use { - val buffered = it.buffered(8192) - val buf = ByteArray(8192) - var rd: Int - while (true) { - rd = buffered.read(buf) - if (rd == -1) break - md.update(buf, 0, rd) - } - - output.writeText( - md.digest().joinToString(separator = "") { eachByte -> "%02x".format(eachByte) } + - " ${input.name}" - ) - } -} - internal fun unsafeCast(o: Any?): T { @Suppress("UNCHECKED_CAST") return o as T diff --git a/quarkus/admin/build.gradle.kts b/quarkus/admin/build.gradle.kts index cbad25e107..474814925e 100644 --- a/quarkus/admin/build.gradle.kts +++ b/quarkus/admin/build.gradle.kts @@ -18,6 +18,7 @@ */ import io.quarkus.gradle.tasks.QuarkusBuild +import publishing.GenerateDigest plugins { alias(libs.plugins.quarkus) @@ -110,11 +111,38 @@ val distZip = inputs.files(runScript) } +val digestDistTar = + tasks.register("digestDistTar") { + description = "Generate the distribution tar digest" + mustRunAfter(distTar) + file.set { distTar.get().archiveFile.get().asFile } + } + +val digestDistZip = + tasks.register("digestDistZip") { + description = "Generate the distribution zip digest" + mustRunAfter(distZip) + file.set { distZip.get().archiveFile.get().asFile } + } + +distTar.configure { finalizedBy(digestDistTar) } + +distZip.configure { finalizedBy(digestDistZip) } + +if (project.hasProperty("release") || project.hasProperty("signArtifacts")) { + signing { + sign(distTar.get()) + sign(distZip.get()) + } +} + // Expose runnable jar via quarkusRunner configuration for integration-tests that require the // server. artifacts { add(distributionTar.name, provider { distTar.get().archiveFile }) { builtBy(distTar) } + add(distributionTar.name, provider { digestDistTar.get().outputFile }) { builtBy(digestDistTar) } add(distributionZip.name, provider { distZip.get().archiveFile }) { builtBy(distZip) } + add(distributionZip.name, provider { digestDistZip.get().outputFile }) { builtBy(digestDistZip) } } afterEvaluate { diff --git a/quarkus/server/build.gradle.kts b/quarkus/server/build.gradle.kts index 04b7030c96..7e8cddf3f9 100644 --- a/quarkus/server/build.gradle.kts +++ b/quarkus/server/build.gradle.kts @@ -19,6 +19,7 @@ import io.quarkus.gradle.tasks.QuarkusBuild import io.quarkus.gradle.tasks.QuarkusRun +import publishing.GenerateDigest plugins { alias(libs.plugins.quarkus) @@ -109,6 +110,31 @@ val distZip = inputs.files(runScript) } +val digestDistTar = + tasks.register("digestDistTar") { + description = "Generate the distribution tar digest" + mustRunAfter(distTar) + file.set { distTar.get().archiveFile.get().asFile } + } + +val digestDistZip = + tasks.register("digestDistZip") { + description = "Generate the distribution zip digest" + mustRunAfter(distZip) + file.set { distZip.get().archiveFile.get().asFile } + } + +distTar.configure { finalizedBy(digestDistTar) } + +distZip.configure { finalizedBy(digestDistZip) } + +if (project.hasProperty("release") || project.hasProperty("signArtifacts")) { + signing { + sign(distTar.get()) + sign(distZip.get()) + } +} + // Expose runnable jar via quarkusRunner configuration for integration-tests that require the // server. artifacts { @@ -116,7 +142,9 @@ artifacts { builtBy(quarkusBuild) } add(distributionTar.name, provider { distTar.get().archiveFile }) { builtBy(distTar) } + add(distributionTar.name, provider { digestDistTar.get().outputFile }) { builtBy(digestDistTar) } add(distributionZip.name, provider { distZip.get().archiveFile }) { builtBy(distZip) } + add(distributionZip.name, provider { digestDistZip.get().outputFile }) { builtBy(digestDistZip) } } afterEvaluate {