From d8821b4d1d50d16691592a014be2816520519fe3 Mon Sep 17 00:00:00 2001 From: Robert Stupp Date: Wed, 8 Jul 2026 12:25:34 +0200 Subject: [PATCH 1/9] Make test build configuration-cache compatible --- build.gradle.kts | 2 -- conformance/build.gradle.kts | 2 -- core/build.gradle.kts | 2 -- gradle/libs.versions.toml | 2 -- jackson/build.gradle.kts | 2 -- jackson3/build.gradle.kts | 2 -- settings.gradle.kts | 31 ++++++++++++++++++++++--------- tools/build.gradle.kts | 2 -- 8 files changed, 22 insertions(+), 23 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 3b350254..58eff768 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -20,8 +20,6 @@ import org.jetbrains.gradle.ext.taskTriggers plugins { signing - alias(libs.plugins.testsummary) - alias(libs.plugins.testrerun) alias(libs.plugins.nmcp) `cel-conventions` } diff --git a/conformance/build.gradle.kts b/conformance/build.gradle.kts index 6aea2891..7c83dc57 100644 --- a/conformance/build.gradle.kts +++ b/conformance/build.gradle.kts @@ -20,8 +20,6 @@ import com.google.protobuf.gradle.ProtobufPlugin plugins { `java-library` id("com.gradleup.shadow") - id("org.caffinitas.gradle.testsummary") - id("org.caffinitas.gradle.testrerun") `cel-conventions` } diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 021a83ad..d0a15251 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -20,8 +20,6 @@ plugins { `maven-publish` id("com.diffplug.spotless") alias(libs.plugins.jmh) - alias(libs.plugins.testsummary) - alias(libs.plugins.testrerun) `cel-conventions` `java-test-fixtures` } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c7662b3a..2df1e75a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -72,5 +72,3 @@ nmcp = { id = "com.gradleup.nmcp.aggregation", version = "1.6.1" } protobuf = { id = "com.google.protobuf", version.ref = "protobufPlugin" } shadow = { id = "com.gradleup.shadow", version.ref = "shadowPlugin" } spotless = { id = "com.diffplug.spotless", version.ref = "spotlessPlugin" } -testrerun = { id = "org.caffinitas.gradle.testrerun", version = "0.1" } -testsummary = { id = "org.caffinitas.gradle.testsummary", version = "0.1.1" } diff --git a/jackson/build.gradle.kts b/jackson/build.gradle.kts index 03289299..70eec72c 100644 --- a/jackson/build.gradle.kts +++ b/jackson/build.gradle.kts @@ -18,8 +18,6 @@ plugins { `java-library` `maven-publish` signing - id("org.caffinitas.gradle.testsummary") - id("org.caffinitas.gradle.testrerun") `cel-conventions` } diff --git a/jackson3/build.gradle.kts b/jackson3/build.gradle.kts index d49d0907..f74ad9f7 100644 --- a/jackson3/build.gradle.kts +++ b/jackson3/build.gradle.kts @@ -18,8 +18,6 @@ plugins { `java-library` `maven-publish` signing - id("org.caffinitas.gradle.testsummary") - id("org.caffinitas.gradle.testrerun") `cel-conventions` } diff --git a/settings.gradle.kts b/settings.gradle.kts index 8a3a9b6f..b28be9d0 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -14,17 +14,23 @@ * limitations under the License. */ +import com.gradle.develocity.agent.gradle.scan.BuildScanPublishingConfiguration +import org.gradle.api.specs.Spec + if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_17)) { throw GradleException("Build requires Java 17") } -val baseVersion = file("version.txt").readText().trim() +val baseVersion = + providers.fileContents(layout.settingsDirectory.file("version.txt")).asText.map { it.trim() } +val isCI = providers.environmentVariable("CI").isPresent +val isBuildScanRequested = gradle.startParameter.isBuildScan pluginManagement { repositories { mavenCentral() // prefer Maven Central, in case Gradle's repo has issues gradlePluginPortal() - if (System.getProperty("withMavenLocal").toBoolean()) { + if (providers.systemProperty("withMavenLocal").map(String::toBoolean).getOrElse(false)) { mavenLocal() } } @@ -33,10 +39,11 @@ pluginManagement { plugins { id("com.gradle.develocity") version ("4.5.0") } develocity { - if (System.getenv("CI") != null) { + if (isCI) { buildScan { termsOfUseUrl = "https://gradle.com/terms-of-service" termsOfUseAgree = "yes" + publishing.onlyIf(RequestedBuildScanPublishingSpec(true)) // Add some potentially interesting information from the environment listOf( "GITHUB_ACTION_REPOSITORY", @@ -52,29 +59,35 @@ develocity { "GITHUB_WORKFLOW", ) .forEach { e -> - val v = System.getenv(e) + val v = providers.environmentVariable(e).orNull if (v != null) { value(e, v) } } - val ghUrl = System.getenv("GITHUB_SERVER_URL") + val ghUrl = providers.environmentVariable("GITHUB_SERVER_URL").orNull if (ghUrl != null) { - val ghRepo = System.getenv("GITHUB_REPOSITORY") - val ghRunId = System.getenv("GITHUB_RUN_ID") + val ghRepo = providers.environmentVariable("GITHUB_REPOSITORY").orNull + val ghRunId = providers.environmentVariable("GITHUB_RUN_ID").orNull link("Summary", "$ghUrl/$ghRepo/actions/runs/$ghRunId") link("PRs", "$ghUrl/$ghRepo/pulls") } } } else { - buildScan { publishing { onlyIf { gradle.startParameter.isBuildScan } } } + buildScan { publishing.onlyIf(RequestedBuildScanPublishingSpec(isBuildScanRequested)) } } } +class RequestedBuildScanPublishingSpec(private val enabled: Boolean) : + Spec { + override fun isSatisfiedBy(context: BuildScanPublishingConfiguration.PublishingContext): Boolean = + enabled +} + rootProject.name = "cel-parent" gradle.beforeProject { group = "org.projectnessie.cel" - version = baseVersion + version = baseVersion.get() description = when (name) { "cel" -> "Common-Expression-Language - Java implementation" diff --git a/tools/build.gradle.kts b/tools/build.gradle.kts index 1bac71e5..4ff9f502 100644 --- a/tools/build.gradle.kts +++ b/tools/build.gradle.kts @@ -21,8 +21,6 @@ plugins { `java-library` `maven-publish` signing - id("org.caffinitas.gradle.testsummary") - id("org.caffinitas.gradle.testrerun") `cel-conventions` } From 77616af608ed1ca682a48da0fd992067705fa5e9 Mon Sep 17 00:00:00 2001 From: Robert Stupp Date: Wed, 8 Jul 2026 12:43:04 +0200 Subject: [PATCH 2/9] Adopt NMCP and migrate to included build-logic --- bom/build.gradle.kts | 2 +- {buildSrc => build-logic}/build.gradle.kts | 0 {buildSrc => build-logic}/settings.gradle.kts | 0 .../src/main/kotlin/CodeCoverage.kt | 0 .../src/main/kotlin/Ide.kt | 0 .../src/main/kotlin/Java.kt | 0 .../src/main/kotlin/ProtobufHelperPlugin.kt | 0 .../main/kotlin/PublishingHelperExtension.kt | 0 .../src/main/kotlin/PublishingHelperPlugin.kt | 0 .../src/main/kotlin/Spotless.kt | 8 +++--- .../src/main/kotlin/Testing.kt | 0 .../src/main/kotlin/Utilities.kt | 0 .../main/kotlin/cel-conventions.gradle.kts | 0 build.gradle.kts | 25 +---------------- conformance/build.gradle.kts | 2 +- core/build.gradle.kts | 2 +- generated-antlr/build.gradle.kts | 2 +- generated-pb/build.gradle.kts | 2 +- generated-pb3/build.gradle.kts | 2 +- gradle/libs.versions.toml | 1 - jackson/build.gradle.kts | 2 +- jackson3/build.gradle.kts | 2 +- settings.gradle.kts | 28 ++++++++++++++++++- standalone/build.gradle.kts | 2 +- tools/build.gradle.kts | 2 +- 25 files changed, 42 insertions(+), 40 deletions(-) rename {buildSrc => build-logic}/build.gradle.kts (100%) rename {buildSrc => build-logic}/settings.gradle.kts (100%) rename {buildSrc => build-logic}/src/main/kotlin/CodeCoverage.kt (100%) rename {buildSrc => build-logic}/src/main/kotlin/Ide.kt (100%) rename {buildSrc => build-logic}/src/main/kotlin/Java.kt (100%) rename {buildSrc => build-logic}/src/main/kotlin/ProtobufHelperPlugin.kt (100%) rename {buildSrc => build-logic}/src/main/kotlin/PublishingHelperExtension.kt (100%) rename {buildSrc => build-logic}/src/main/kotlin/PublishingHelperPlugin.kt (100%) rename {buildSrc => build-logic}/src/main/kotlin/Spotless.kt (93%) rename {buildSrc => build-logic}/src/main/kotlin/Testing.kt (100%) rename {buildSrc => build-logic}/src/main/kotlin/Utilities.kt (100%) rename {buildSrc => build-logic}/src/main/kotlin/cel-conventions.gradle.kts (100%) diff --git a/bom/build.gradle.kts b/bom/build.gradle.kts index 1c660122..6bb4ce70 100644 --- a/bom/build.gradle.kts +++ b/bom/build.gradle.kts @@ -18,7 +18,7 @@ plugins { `java-platform` `maven-publish` signing - `cel-conventions` + id("cel-conventions") } dependencies { diff --git a/buildSrc/build.gradle.kts b/build-logic/build.gradle.kts similarity index 100% rename from buildSrc/build.gradle.kts rename to build-logic/build.gradle.kts diff --git a/buildSrc/settings.gradle.kts b/build-logic/settings.gradle.kts similarity index 100% rename from buildSrc/settings.gradle.kts rename to build-logic/settings.gradle.kts diff --git a/buildSrc/src/main/kotlin/CodeCoverage.kt b/build-logic/src/main/kotlin/CodeCoverage.kt similarity index 100% rename from buildSrc/src/main/kotlin/CodeCoverage.kt rename to build-logic/src/main/kotlin/CodeCoverage.kt diff --git a/buildSrc/src/main/kotlin/Ide.kt b/build-logic/src/main/kotlin/Ide.kt similarity index 100% rename from buildSrc/src/main/kotlin/Ide.kt rename to build-logic/src/main/kotlin/Ide.kt diff --git a/buildSrc/src/main/kotlin/Java.kt b/build-logic/src/main/kotlin/Java.kt similarity index 100% rename from buildSrc/src/main/kotlin/Java.kt rename to build-logic/src/main/kotlin/Java.kt diff --git a/buildSrc/src/main/kotlin/ProtobufHelperPlugin.kt b/build-logic/src/main/kotlin/ProtobufHelperPlugin.kt similarity index 100% rename from buildSrc/src/main/kotlin/ProtobufHelperPlugin.kt rename to build-logic/src/main/kotlin/ProtobufHelperPlugin.kt diff --git a/buildSrc/src/main/kotlin/PublishingHelperExtension.kt b/build-logic/src/main/kotlin/PublishingHelperExtension.kt similarity index 100% rename from buildSrc/src/main/kotlin/PublishingHelperExtension.kt rename to build-logic/src/main/kotlin/PublishingHelperExtension.kt diff --git a/buildSrc/src/main/kotlin/PublishingHelperPlugin.kt b/build-logic/src/main/kotlin/PublishingHelperPlugin.kt similarity index 100% rename from buildSrc/src/main/kotlin/PublishingHelperPlugin.kt rename to build-logic/src/main/kotlin/PublishingHelperPlugin.kt diff --git a/buildSrc/src/main/kotlin/Spotless.kt b/build-logic/src/main/kotlin/Spotless.kt similarity index 93% rename from buildSrc/src/main/kotlin/Spotless.kt rename to build-logic/src/main/kotlin/Spotless.kt index bf945d80..7c3c3717 100644 --- a/buildSrc/src/main/kotlin/Spotless.kt +++ b/build-logic/src/main/kotlin/Spotless.kt @@ -36,15 +36,15 @@ fun Project.nessieConfigureSpotless() { ktfmt().googleStyle() licenseHeaderFile(rootProject.file("codestyle/copyright-header-java.txt"), "$") if (project == rootProject) { - target("*.gradle.kts", "buildSrc/*.gradle.kts") + target("*.gradle.kts", "build-logic/*.gradle.kts") } } if (project == rootProject) { kotlin { ktfmt().googleStyle() licenseHeaderFile(rootProject.file("codestyle/copyright-header-java.txt"), "$") - target("buildSrc/src/**/kotlin/**") - targetExclude("buildSrc/build/**") + target("build-logic/src/**/kotlin/**") + targetExclude("build-logic/build/**") } } @@ -83,7 +83,7 @@ fun Project.nessieConfigureSpotless() { "^(package|import) .*$", ) target("src/**/scala/**") - targetExclude("buildSrc/build/**") + targetExclude("build-logic/build/**") } } if (sourceLangs.contains("kotlin")) { diff --git a/buildSrc/src/main/kotlin/Testing.kt b/build-logic/src/main/kotlin/Testing.kt similarity index 100% rename from buildSrc/src/main/kotlin/Testing.kt rename to build-logic/src/main/kotlin/Testing.kt diff --git a/buildSrc/src/main/kotlin/Utilities.kt b/build-logic/src/main/kotlin/Utilities.kt similarity index 100% rename from buildSrc/src/main/kotlin/Utilities.kt rename to build-logic/src/main/kotlin/Utilities.kt diff --git a/buildSrc/src/main/kotlin/cel-conventions.gradle.kts b/build-logic/src/main/kotlin/cel-conventions.gradle.kts similarity index 100% rename from buildSrc/src/main/kotlin/cel-conventions.gradle.kts rename to build-logic/src/main/kotlin/cel-conventions.gradle.kts diff --git a/build.gradle.kts b/build.gradle.kts index 58eff768..e8236c15 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -14,14 +14,12 @@ * limitations under the License. */ -import java.time.Duration import org.jetbrains.gradle.ext.settings import org.jetbrains.gradle.ext.taskTriggers plugins { signing - alias(libs.plugins.nmcp) - `cel-conventions` + id("cel-conventions") } mapOf("versionJacoco" to libs.versions.jacoco.get(), "versionJandex" to libs.versions.jandex.get()) @@ -29,27 +27,6 @@ mapOf("versionJacoco" to libs.versions.jacoco.get(), "versionJandex" to libs.ver tasks.named("wrapper") { distributionType = Wrapper.DistributionType.ALL } -// Pass environment variables: -// ORG_GRADLE_PROJECT_sonatypeUsername -// ORG_GRADLE_PROJECT_sonatypePassword -// Gradle targets: -// publishAggregationToCentralPortal -// publishAggregationToCentralPortalSnapshots -// (zipAggregateMavenCentralDeployment to just generate the single, aggregated deployment zip) -// Ref: Maven Central Publisher API: -// https://central.sonatype.org/publish/publish-portal-api/#uploading-a-deployment-bundle -nmcpAggregation { - centralPortal { - username.value(provider { System.getenv("ORG_GRADLE_PROJECT_sonatypeUsername") }) - password.value(provider { System.getenv("ORG_GRADLE_PROJECT_sonatypePassword") }) - publishingType = if (System.getenv("CI") != null) "AUTOMATIC" else "USER_MANAGED" - publishingTimeout = Duration.ofMinutes(120) - validationTimeout = Duration.ofMinutes(120) - publicationName = "${project.name}-$version" - } - publishAllProjectsProbablyBreakingProjectIsolation() -} - val buildToolIntegrationGradle by tasks.registering(Exec::class) { group = "Verification" diff --git a/conformance/build.gradle.kts b/conformance/build.gradle.kts index 7c83dc57..f4d0cb94 100644 --- a/conformance/build.gradle.kts +++ b/conformance/build.gradle.kts @@ -20,7 +20,7 @@ import com.google.protobuf.gradle.ProtobufPlugin plugins { `java-library` id("com.gradleup.shadow") - `cel-conventions` + id("cel-conventions") } apply() diff --git a/core/build.gradle.kts b/core/build.gradle.kts index d0a15251..3fc666f2 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -20,7 +20,7 @@ plugins { `maven-publish` id("com.diffplug.spotless") alias(libs.plugins.jmh) - `cel-conventions` + id("cel-conventions") `java-test-fixtures` } diff --git a/generated-antlr/build.gradle.kts b/generated-antlr/build.gradle.kts index ce86a457..ceafa33e 100644 --- a/generated-antlr/build.gradle.kts +++ b/generated-antlr/build.gradle.kts @@ -22,7 +22,7 @@ plugins { `maven-publish` signing id("com.gradleup.shadow") - `cel-conventions` + id("cel-conventions") } dependencies { diff --git a/generated-pb/build.gradle.kts b/generated-pb/build.gradle.kts index 1cf5e341..da63daed 100644 --- a/generated-pb/build.gradle.kts +++ b/generated-pb/build.gradle.kts @@ -21,7 +21,7 @@ plugins { `java-library` `maven-publish` signing - `cel-conventions` + id("cel-conventions") `java-test-fixtures` } diff --git a/generated-pb3/build.gradle.kts b/generated-pb3/build.gradle.kts index de2c819e..de6169d9 100644 --- a/generated-pb3/build.gradle.kts +++ b/generated-pb3/build.gradle.kts @@ -21,7 +21,7 @@ plugins { `java-library` `maven-publish` signing - `cel-conventions` + id("cel-conventions") `java-test-fixtures` } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2df1e75a..b84b0406 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -68,7 +68,6 @@ tomcat-annotations-api = { module = "org.apache.tomcat:annotations-api", version idea-ext = { id = "org.jetbrains.gradle.plugin.idea-ext", version = "1.4.1" } jandex = { id = "com.github.vlsi.jandex", version.ref = "jandexPlugin" } jmh = { id = "me.champeau.jmh", version = "0.7.3" } -nmcp = { id = "com.gradleup.nmcp.aggregation", version = "1.6.1" } protobuf = { id = "com.google.protobuf", version.ref = "protobufPlugin" } shadow = { id = "com.gradleup.shadow", version.ref = "shadowPlugin" } spotless = { id = "com.diffplug.spotless", version.ref = "spotlessPlugin" } diff --git a/jackson/build.gradle.kts b/jackson/build.gradle.kts index 70eec72c..69ef1224 100644 --- a/jackson/build.gradle.kts +++ b/jackson/build.gradle.kts @@ -18,7 +18,7 @@ plugins { `java-library` `maven-publish` signing - `cel-conventions` + id("cel-conventions") } description = "CEL Jackson 2 support" diff --git a/jackson3/build.gradle.kts b/jackson3/build.gradle.kts index f74ad9f7..3338184e 100644 --- a/jackson3/build.gradle.kts +++ b/jackson3/build.gradle.kts @@ -18,7 +18,7 @@ plugins { `java-library` `maven-publish` signing - `cel-conventions` + id("cel-conventions") } description = "CEL Jackson 3 support" diff --git a/settings.gradle.kts b/settings.gradle.kts index b28be9d0..7f7c88d2 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -15,6 +15,7 @@ */ import com.gradle.develocity.agent.gradle.scan.BuildScanPublishingConfiguration +import java.time.Duration import org.gradle.api.specs.Spec if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_17)) { @@ -27,6 +28,8 @@ val isCI = providers.environmentVariable("CI").isPresent val isBuildScanRequested = gradle.startParameter.isBuildScan pluginManagement { + includeBuild("build-logic") { name = "cel-java-build-logic" } + repositories { mavenCentral() // prefer Maven Central, in case Gradle's repo has issues gradlePluginPortal() @@ -36,7 +39,10 @@ pluginManagement { } } -plugins { id("com.gradle.develocity") version ("4.5.0") } +plugins { + id("com.gradle.develocity") version ("4.5.0") + id("com.gradleup.nmcp.settings") version ("1.6.1") +} develocity { if (isCI) { @@ -85,6 +91,26 @@ class RequestedBuildScanPublishingSpec(private val enabled: Boolean) : rootProject.name = "cel-parent" +// Pass environment variables: +// ORG_GRADLE_PROJECT_sonatypeUsername +// ORG_GRADLE_PROJECT_sonatypePassword +// Gradle targets: +// publishAggregationToCentralPortal +// publishAggregationToCentralPortalSnapshots +// (nmcpZipAggregation to just generate the single, aggregated deployment zip) +// Ref: Maven Central Publisher API: +// https://central.sonatype.org/publish/publish-portal-api/#uploading-a-deployment-bundle +nmcpSettings { + centralPortal { + providers.environmentVariable("ORG_GRADLE_PROJECT_sonatypeUsername").orNull?.let(username::set) + providers.environmentVariable("ORG_GRADLE_PROJECT_sonatypePassword").orNull?.let(password::set) + publishingType.set(if (isCI) "AUTOMATIC" else "USER_MANAGED") + publishingTimeout.set(Duration.ofMinutes(120)) + validationTimeout.set(Duration.ofMinutes(120)) + publicationName.set("cel-parent-${baseVersion.get()}") + } +} + gradle.beforeProject { group = "org.projectnessie.cel" version = baseVersion.get() diff --git a/standalone/build.gradle.kts b/standalone/build.gradle.kts index 25e490e1..4def8ece 100644 --- a/standalone/build.gradle.kts +++ b/standalone/build.gradle.kts @@ -21,7 +21,7 @@ plugins { `maven-publish` signing id("com.gradleup.shadow") - `cel-conventions` + id("cel-conventions") } dependencies { diff --git a/tools/build.gradle.kts b/tools/build.gradle.kts index 4ff9f502..1e8ae29c 100644 --- a/tools/build.gradle.kts +++ b/tools/build.gradle.kts @@ -21,7 +21,7 @@ plugins { `java-library` `maven-publish` signing - `cel-conventions` + id("cel-conventions") } apply() From dd8eb14665e43fa38300bd0ae467cc1390dc978e Mon Sep 17 00:00:00 2001 From: Robert Stupp Date: Wed, 8 Jul 2026 12:52:47 +0200 Subject: [PATCH 3/9] Misc config-cache compatibiltiy changes --- build-logic/src/main/kotlin/Ide.kt | 20 +++++++++------ build-logic/src/main/kotlin/Java.kt | 2 +- .../src/main/kotlin/PublishingHelperPlugin.kt | 20 +++++++++------ build-logic/src/main/kotlin/Spotless.kt | 25 +++++++++++-------- .../main/kotlin/cel-conventions.gradle.kts | 2 +- 5 files changed, 41 insertions(+), 28 deletions(-) diff --git a/build-logic/src/main/kotlin/Ide.kt b/build-logic/src/main/kotlin/Ide.kt index 05f0bb52..a0635780 100644 --- a/build-logic/src/main/kotlin/Ide.kt +++ b/build-logic/src/main/kotlin/Ide.kt @@ -31,11 +31,10 @@ import org.jetbrains.gradle.ext.settings fun Project.nessieIde() { apply() - if (this == rootProject) { + if (path == ":") { - val projectName = rootProject.file("ide-name.txt").readText().trim() - val ideName = - "$projectName ${rootProject.version.toString().replace(Regex("^([0-9.]+).*"), "$1")}" + val projectName = layout.settingsDirectory.file("ide-name.txt").asFile.readText().trim() + val ideName = "$projectName ${version.toString().replace(Regex("^([0-9.]+).*"), "$1")}" apply() configure { @@ -51,7 +50,11 @@ fun Project.nessieIde() { profiles.create("Nessie-ASF") { // strip trailing LF val copyrightText = - rootProject.file("codestyle/copyright-header.txt").readLines().joinToString("\n") + layout.settingsDirectory + .file("codestyle/copyright-header.txt") + .asFile + .readLines() + .joinToString("\n") notice = copyrightText } } @@ -63,8 +66,9 @@ fun Project.nessieIde() { defaults = true jvmArgs = - rootProject.projectDir - .resolve("gradle.properties") + layout.settingsDirectory + .file("gradle.properties") + .asFile .reader() .use { val rules = java.util.Properties() @@ -81,7 +85,7 @@ fun Project.nessieIde() { // There's no proper way to set the name of the IDEA project (when "just importing" or syncing // the Gradle project) - val ideaDir = projectDir.resolve(".idea") + val ideaDir = layout.projectDirectory.dir(".idea").asFile if (ideaDir.isDirectory) { ideaDir.resolve(".name").writeText(ideName) diff --git a/build-logic/src/main/kotlin/Java.kt b/build-logic/src/main/kotlin/Java.kt index d9da69bb..9a0e1196 100644 --- a/build-logic/src/main/kotlin/Java.kt +++ b/build-logic/src/main/kotlin/Java.kt @@ -65,7 +65,7 @@ fun Project.nessieConfigureJava() { } } - if (project != rootProject) { + if (path != ":") { tasks.withType().configureEach { duplicatesStrategy = DuplicatesStrategy.WARN } } } diff --git a/build-logic/src/main/kotlin/PublishingHelperPlugin.kt b/build-logic/src/main/kotlin/PublishingHelperPlugin.kt index 141549d6..244522db 100644 --- a/build-logic/src/main/kotlin/PublishingHelperPlugin.kt +++ b/build-logic/src/main/kotlin/PublishingHelperPlugin.kt @@ -105,14 +105,14 @@ constructor(private val softwareComponentFactory: SoftwareComponentFactory) : Pl } ) description.set(project.description) - if (project != rootProject) { + if (path != ":") { withXml { val projectNode = asNode() val parentNode = projectNode.appendNode("parent") - parentNode.appendNode("groupId", parent!!.group) - parentNode.appendNode("artifactId", parent!!.name) - parentNode.appendNode("version", parent!!.version) + parentNode.appendNode("groupId", group) + parentNode.appendNode("artifactId", "cel-parent") + parentNode.appendNode("version", version) addMissingMandatoryDependencyVersions(projectNode) } @@ -120,10 +120,10 @@ constructor(private val softwareComponentFactory: SoftwareComponentFactory) : Pl val nessieRepoName = e.nessieRepoName.get() inputs - .file(rootProject.file("gradle/developers.csv")) + .file(layout.settingsDirectory.file("gradle/developers.csv")) .withPathSensitivity(PathSensitivity.RELATIVE) inputs - .file(rootProject.file("gradle/contributors.csv")) + .file(layout.settingsDirectory.file("gradle/contributors.csv")) .withPathSensitivity(PathSensitivity.RELATIVE) doFirst { inceptionYear.set(e.inceptionYear.get()) @@ -160,7 +160,9 @@ constructor(private val softwareComponentFactory: SoftwareComponentFactory) : Pl url.set("https://github.com/projectnessie/$nessieRepoName/issues") } developers { - file(rootProject.file("gradle/developers.csv")) + layout.settingsDirectory + .file("gradle/developers.csv") + .asFile .readLines() .map { line -> line.trim() } .filter { line -> line.isNotEmpty() && !line.startsWith("#") } @@ -179,7 +181,9 @@ constructor(private val softwareComponentFactory: SoftwareComponentFactory) : Pl } } contributors { - file(rootProject.file("gradle/contributors.csv")) + layout.settingsDirectory + .file("gradle/contributors.csv") + .asFile .readLines() .map { line -> line.trim() } .filter { line -> line.isNotEmpty() && !line.startsWith("#") } diff --git a/build-logic/src/main/kotlin/Spotless.kt b/build-logic/src/main/kotlin/Spotless.kt index 7c3c3717..8ae48cc9 100644 --- a/build-logic/src/main/kotlin/Spotless.kt +++ b/build-logic/src/main/kotlin/Spotless.kt @@ -25,30 +25,35 @@ fun Project.nessieConfigureSpotless() { apply() if (!java.lang.Boolean.getBoolean("idea.sync.active")) { + val copyrightHeader = layout.settingsDirectory.file("codestyle/copyright-header-java.txt") + val rootProjectOnly = path == ":" + plugins.withType().configureEach { configure { format("xml") { target("src/**/*.xml", "src/**/*.xsd") eclipseWtp(com.diffplug.spotless.extra.wtp.EclipseWtpFormatterStep.XML) - .configFile(rootProject.projectDir.resolve("codestyle/org.eclipse.wst.xml.core.prefs")) + .configFile( + layout.settingsDirectory.file("codestyle/org.eclipse.wst.xml.core.prefs").asFile + ) } kotlinGradle { ktfmt().googleStyle() - licenseHeaderFile(rootProject.file("codestyle/copyright-header-java.txt"), "$") - if (project == rootProject) { + licenseHeaderFile(copyrightHeader.asFile, "$") + if (rootProjectOnly) { target("*.gradle.kts", "build-logic/*.gradle.kts") } } - if (project == rootProject) { + if (rootProjectOnly) { kotlin { ktfmt().googleStyle() - licenseHeaderFile(rootProject.file("codestyle/copyright-header-java.txt"), "$") + licenseHeaderFile(copyrightHeader.asFile, "$") target("build-logic/src/**/kotlin/**") targetExclude("build-logic/build/**") } } - val dirsInSrc = projectDir.resolve("src").listFiles() + val dirsInSrc = layout.projectDirectory.dir("src").asFile.listFiles() val sourceLangs = if (dirsInSrc != null) dirsInSrc @@ -62,7 +67,7 @@ fun Project.nessieConfigureSpotless() { if (sourceLangs.contains("antlr4")) { antlr4 { - licenseHeaderFile(rootProject.file("codestyle/copyright-header-java.txt")) + licenseHeaderFile(copyrightHeader.asFile) target("src/**/antlr4/**") targetExclude("build/**") } @@ -70,7 +75,7 @@ fun Project.nessieConfigureSpotless() { if (sourceLangs.contains("java")) { java { googleJavaFormat(libsRequiredVersion("googleJavaFormat")) - licenseHeaderFile(rootProject.file("codestyle/copyright-header-java.txt")) + licenseHeaderFile(copyrightHeader.asFile) target("src/**/java/**") targetExclude("build/**") } @@ -79,7 +84,7 @@ fun Project.nessieConfigureSpotless() { scala { scalafmt() licenseHeaderFile( - rootProject.file("codestyle/copyright-header-java.txt"), + copyrightHeader.asFile, "^(package|import) .*$", ) target("src/**/scala/**") @@ -89,7 +94,7 @@ fun Project.nessieConfigureSpotless() { if (sourceLangs.contains("kotlin")) { kotlin { ktfmt().googleStyle() - licenseHeaderFile(rootProject.file("codestyle/copyright-header-java.txt"), "$") + licenseHeaderFile(copyrightHeader.asFile, "$") target("src/**/kotlin/**") targetExclude("build/**") } diff --git a/build-logic/src/main/kotlin/cel-conventions.gradle.kts b/build-logic/src/main/kotlin/cel-conventions.gradle.kts index 97e3465a..d7ce2b6c 100644 --- a/build-logic/src/main/kotlin/cel-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/cel-conventions.gradle.kts @@ -26,7 +26,7 @@ nessieIde() apply() -if (projectDir.resolve("src/test/java").exists()) { +if (layout.projectDirectory.dir("src/test/java").asFile.exists()) { nessieConfigureTestTasks() } From af49438be41b1b5cab01798a818704990bc38376 Mon Sep 17 00:00:00 2001 From: Robert Stupp Date: Wed, 8 Jul 2026 12:59:39 +0200 Subject: [PATCH 4/9] Fix config-cache reuse issue --- tools/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/build.gradle.kts b/tools/build.gradle.kts index 1e8ae29c..fd12d9e9 100644 --- a/tools/build.gradle.kts +++ b/tools/build.gradle.kts @@ -41,4 +41,5 @@ configure { // Download from repositories artifact = "com.google.protobuf:protoc:${libs.versions.protobuf.get()}" } + generateProtoTasks { ofSourceSet("main").configureEach { enabled = false } } } From f46e62cba153d451371a3f171334ced0625872b8 Mon Sep 17 00:00:00 2001 From: Robert Stupp Date: Wed, 8 Jul 2026 13:13:58 +0200 Subject: [PATCH 5/9] Make publishing config-cache safe --- .../src/main/kotlin/PublishingHelperPlugin.kt | 382 +++++++++--------- .../main/kotlin/cel-conventions.gradle.kts | 8 +- 2 files changed, 187 insertions(+), 203 deletions(-) diff --git a/build-logic/src/main/kotlin/PublishingHelperPlugin.kt b/build-logic/src/main/kotlin/PublishingHelperPlugin.kt index 244522db..e67351a2 100644 --- a/build-logic/src/main/kotlin/PublishingHelperPlugin.kt +++ b/build-logic/src/main/kotlin/PublishingHelperPlugin.kt @@ -21,11 +21,8 @@ import javax.inject.Inject import org.gradle.api.GradleException import org.gradle.api.Plugin import org.gradle.api.Project -import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.ConfigurationVariant import org.gradle.api.artifacts.ProjectDependency -import org.gradle.api.artifacts.component.ModuleComponentSelector -import org.gradle.api.artifacts.result.DependencyResult import org.gradle.api.attributes.Bundling import org.gradle.api.attributes.Category import org.gradle.api.attributes.LibraryElements @@ -35,12 +32,13 @@ import org.gradle.api.component.SoftwareComponentFactory import org.gradle.api.plugins.JavaBasePlugin import org.gradle.api.publish.PublishingExtension import org.gradle.api.publish.maven.MavenPublication +import org.gradle.api.publish.maven.tasks.GenerateMavenPom import org.gradle.api.publish.tasks.GenerateModuleMetadata import org.gradle.api.tasks.PathSensitivity import org.gradle.kotlin.dsl.apply import org.gradle.kotlin.dsl.configure import org.gradle.kotlin.dsl.extra -import org.gradle.kotlin.dsl.provideDelegate +import org.gradle.kotlin.dsl.getByType import org.gradle.kotlin.dsl.register import org.gradle.kotlin.dsl.withType import org.gradle.plugins.signing.SigningExtension @@ -57,155 +55,58 @@ constructor(private val softwareComponentFactory: SoftwareComponentFactory) : Pl apply(plugin = "maven-publish") apply(plugin = "signing") - plugins.withId("publishing") { - configure { - publications { - register("maven") { - val mavenPublication = this - afterEvaluate { - // This MUST happen in an 'afterEvaluate' to ensure that the Shadow*Plugin has - // been applied. - if (project.plugins.hasPlugin(ShadowPlugin::class.java)) { - configureShadowPublishing(project, mavenPublication, softwareComponentFactory) - } else { - val component = components.firstOrNull { c -> - c.name == "javaPlatform" || c.name == "java" - } - if (component is AdhocComponentWithVariants) { - listOf("testFixturesApiElements", "testFixturesRuntimeElements").forEach { cfg -> - configurations.findByName(cfg)?.apply { - component.addVariantsFromConfiguration(this) { skip() } - } - } - } - from(component) - } - suppressPomMetadataWarningsFor("testApiElements") - suppressPomMetadataWarningsFor("testJavadocElements") - suppressPomMetadataWarningsFor("testRuntimeElements") - suppressPomMetadataWarningsFor("testSourcesElements") - suppressPomMetadataWarningsFor("testFixturesApiElements") - suppressPomMetadataWarningsFor("testFixturesRuntimeElements") - } - - groupId = "$group" - version = project.version.toString() - - tasks.named("generatePomFileForMavenPublication") { - val e = project.extensions.getByType(PublishingHelperExtension::class.java) + plugins.withId("maven-publish") { + val publication = + extensions.getByType().publications.register( + "maven" + ) { + val parentGroupId = project.group.toString() + val parentVersion = project.version.toString() - pom { - name.set( - project.provider { - if (project.extra.has("maven.name")) { - project.extra["maven.name"].toString() - } else { - project.name - } - } - ) - description.set(project.description) - if (path != ":") { - withXml { - val projectNode = asNode() + groupId = "$group" + version = parentVersion - val parentNode = projectNode.appendNode("parent") - parentNode.appendNode("groupId", group) - parentNode.appendNode("artifactId", "cel-parent") - parentNode.appendNode("version", version) + configurePom(project) - addMissingMandatoryDependencyVersions(projectNode) - } - } else { - val nessieRepoName = e.nessieRepoName.get() + if (path != ":") { + pom.withXml { + val projectNode = asNode() - inputs - .file(layout.settingsDirectory.file("gradle/developers.csv")) - .withPathSensitivity(PathSensitivity.RELATIVE) - inputs - .file(layout.settingsDirectory.file("gradle/contributors.csv")) - .withPathSensitivity(PathSensitivity.RELATIVE) - doFirst { - inceptionYear.set(e.inceptionYear.get()) - url.set("https://github.com/projectnessie/$nessieRepoName") - organization { - name.set("Project Nessie") - url.set("https://projectnessie.org") - } - licenses { - license { - name.set("The Apache License, Version 2.0") - url.set("https://www.apache.org/licenses/LICENSE-2.0.txt") - } - } - mailingLists { - mailingList { - name.set("Project Nessie List") - subscribe.set("projectnessie-subscribe@googlegroups.com") - unsubscribe.set("projectnessie-unsubscribe@googlegroups.com") - post.set("projectnessie@googlegroups.com") - archive.set("https://groups.google.com/g/projectnessie") - } - } - scm { - connection.set("scm:git:https://github.com/projectnessie/$nessieRepoName") - developerConnection.set( - "scm:git:https://github.com/projectnessie/$nessieRepoName" - ) - url.set("https://github.com/projectnessie/$nessieRepoName/tree/main") - tag.set("main") - } - issueManagement { - system.set("Github") - url.set("https://github.com/projectnessie/$nessieRepoName/issues") - } - developers { - layout.settingsDirectory - .file("gradle/developers.csv") - .asFile - .readLines() - .map { line -> line.trim() } - .filter { line -> line.isNotEmpty() && !line.startsWith("#") } - .forEach { line -> - val args = line.split(",") - if (args.size < 3) { - throw GradleException( - "gradle/developers.csv contains invalid line '${line}'" - ) - } - developer { - id.set(args[0]) - name.set(args[1]) - url.set(args[2]) - } - } - } - contributors { - layout.settingsDirectory - .file("gradle/contributors.csv") - .asFile - .readLines() - .map { line -> line.trim() } - .filter { line -> line.isNotEmpty() && !line.startsWith("#") } - .forEach { line -> - val args = line.split(",") - if (args.size > 2) { - throw GradleException( - "gradle/contributors.csv contains invalid line '${line}'" - ) - } - contributor { - name.set(args[0]) - url.set(args[1]) - } - } - } - } - } - } + val parentNode = projectNode.appendNode("parent") + parentNode.appendNode("groupId", parentGroupId) + parentNode.appendNode("artifactId", "cel-parent") + parentNode.appendNode("version", parentVersion) } } + + suppressPomMetadataWarningsFor("testApiElements") + suppressPomMetadataWarningsFor("testJavadocElements") + suppressPomMetadataWarningsFor("testRuntimeElements") + suppressPomMetadataWarningsFor("testSourcesElements") + suppressPomMetadataWarningsFor("testFixturesApiElements") + suppressPomMetadataWarningsFor("testFixturesRuntimeElements") + } + + if (project.plugins.hasPlugin(ShadowPlugin::class.java)) { + publication.configure { configureShadowPublishing(project, this, softwareComponentFactory) } + } else { + plugins.withId("java-platform") { + publication.configure { from(components.getByName("javaPlatform")) } } + plugins.withId("java") { publication.configure { project.configureJavaPublishing(this) } } + } + + configureSigning(publication.get()) + } + + tasks.named("generatePomFileForMavenPublication", GenerateMavenPom::class.java) { + if (path == ":") { + inputs + .file(layout.settingsDirectory.file("gradle/developers.csv")) + .withPathSensitivity(PathSensitivity.RELATIVE) + inputs + .file(layout.settingsDirectory.file("gradle/contributors.csv")) + .withPathSensitivity(PathSensitivity.RELATIVE) } } @@ -215,68 +116,143 @@ constructor(private val softwareComponentFactory: SoftwareComponentFactory) : Pl tasks.withType().configureEach { suppressedValidationErrors.add("enforced-platform") } + } - if (project.hasProperty("release")) { - plugins.withType().configureEach { - configure { - val signingKey: String? by project - val signingPassword: String? by project - useInMemoryPgpKeys(signingKey, signingPassword) - val publishing = project.extensions.getByType(PublishingExtension::class.java) - afterEvaluate { sign(publishing.publications.getByName("maven")) } - - if (project.hasProperty("useGpgAgent")) { - useGpgCmd() - } + private fun Project.configureJavaPublishing(mavenPublication: MavenPublication) { + val component = components.findByName("java") ?: return + if (component is AdhocComponentWithVariants) { + listOf("testFixturesApiElements", "testFixturesRuntimeElements").forEach { cfg -> + configurations.findByName(cfg)?.apply { + component.addVariantsFromConfiguration(this) { skip() } } } } + mavenPublication.from(component) } - /** - * Scans the generated pom.xml for `` in `` that do not have a - * `` and adds one, if possible. Maven kinda requires `` tags there, even if the - * `` without a `` is a bom and that bom's version is available transitively. - */ - private fun Project.addMissingMandatoryDependencyVersions(projectNode: Node) { - xmlNode(xmlNode(projectNode, "dependencyManagement"), "dependencies")?.children()?.forEach { - val dependency = it as Node - if (xmlNode(dependency, "version") == null) { - val depGroup = xmlNode(dependency, "groupId")!!.text() - val depName = xmlNode(dependency, "artifactId")!!.text() + private fun MavenPublication.configurePom(project: Project) = project.run { + val e = extensions.getByType() + val pomName = + if (extra.has("maven.name")) { + extra["maven.name"].toString() + } else { + project.name + } + val pomDescription = project.description + val developersFile = layout.settingsDirectory.file("gradle/developers.csv") + val contributorsFile = layout.settingsDirectory.file("gradle/contributors.csv") - var depResult = - findDependency(configurations.findByName("runtimeClasspath"), depGroup, depName) - if (depResult == null) { - depResult = - findDependency(configurations.findByName("testRuntimeClasspath"), depGroup, depName) - } + pom { + name.set(pomName) + description.set(pomDescription) + + if (path == ":") { + val repoUrl = e.nessieRepoName.map { "https://github.com/projectnessie/$it" } + val scmUrl = repoUrl.map { "scm:git:$it" } + val developers = + parsePeopleFile( + providers.fileContents(developersFile).asText.get(), + "gradle/developers.csv", + minColumns = 3, + maxColumns = 3, + ) + val contributors = + parsePeopleFile( + providers.fileContents(contributorsFile).asText.get(), + "gradle/contributors.csv", + minColumns = 2, + maxColumns = 2, + ) - if (depResult != null) { - val req = depResult.requested as ModuleComponentSelector - dependency.appendNode("version", req.version) + inceptionYear.set(e.inceptionYear) + url.set(repoUrl) + organization { + name.set("Project Nessie") + url.set("https://projectnessie.org") + } + licenses { + license { + name.set("The Apache License, Version 2.0") + url.set("https://www.apache.org/licenses/LICENSE-2.0.txt") + } + } + mailingLists { + mailingList { + name.set("Project Nessie List") + subscribe.set("projectnessie-subscribe@googlegroups.com") + unsubscribe.set("projectnessie-unsubscribe@googlegroups.com") + post.set("projectnessie@googlegroups.com") + archive.set("https://groups.google.com/g/projectnessie") + } + } + scm { + connection.set(scmUrl) + developerConnection.set(scmUrl) + url.set(repoUrl.map { "$it/tree/main" }) + tag.set("main") + } + issueManagement { + system.set("Github") + url.set(repoUrl.map { "$it/issues" }) + } + developers { + developers.forEach { person -> + developer { + id.set(person[0]) + name.set(person[1]) + url.set(person[2]) + } + } + } + contributors { + contributors.forEach { person -> + contributor { + name.set(person[0]) + url.set(person[1]) + } + } } } } } - private fun findDependency( - config: Configuration?, - depGroup: String, - depName: String, - ): DependencyResult? { - if (config != null) { - val depResult = - config.incoming.resolutionResult.allDependencies.find { depResult -> - val req = depResult.requested - if (req is ModuleComponentSelector) req.group == depGroup && req.module == depName - else false + private fun Project.configureSigning(mavenPublication: MavenPublication) { + if (providers.gradleProperty("release").isPresent) { + plugins.withType().configureEach { + configure { + useInMemoryPgpKeys( + providers.gradleProperty("signingKey").orNull, + providers.gradleProperty("signingPassword").orNull, + ) + sign(mavenPublication) + + if (providers.gradleProperty("useGpgAgent").isPresent) { + useGpgCmd() + } } - return depResult + } } - return null } + private fun parsePeopleFile( + text: String, + path: String, + minColumns: Int, + maxColumns: Int, + ): List> = + text + .lineSequence() + .map { line -> line.trim() } + .filter { line -> line.isNotEmpty() && !line.startsWith("#") } + .map { line -> + val args = line.split(",") + if (args.size < minColumns || args.size > maxColumns) { + throw GradleException("$path contains invalid line '${line}'") + } + args + } + .toList() + private fun xmlNode(node: Node?, child: String): Node? { val found = node?.get(child) if (found is NodeList) { @@ -303,6 +279,14 @@ internal fun configureShadowPublishing( } val shadowJar = project.tasks.named("shadowJar") + val shadowProjectDependencies = + project.configurations + .getByName("shadow") + .allDependencies + .withType(ProjectDependency::class.java) + .map { + PomDependency(it.group, it.name, it.version) + } val shadowApiElements = project.configurations.create("shadowApiElements") { @@ -360,15 +344,15 @@ internal fun configureShadowPublishing( val dependenciesNode = if ((depNode as NodeList).isNotEmpty()) depNode[0] as Node else node.appendNode("dependencies") - project.configurations.getByName("shadow").allDependencies.forEach { - if (it is ProjectDependency) { - val dependencyNode = dependenciesNode.appendNode("dependency") - dependencyNode.appendNode("groupId", it.group) - dependencyNode.appendNode("artifactId", it.name) - dependencyNode.appendNode("version", it.version) - dependencyNode.appendNode("scope", "runtime") - } + shadowProjectDependencies.forEach { + val dependencyNode = dependenciesNode.appendNode("dependency") + dependencyNode.appendNode("groupId", it.groupId) + dependencyNode.appendNode("artifactId", it.artifactId) + dependencyNode.appendNode("version", it.version) + dependencyNode.appendNode("scope", "runtime") } } } } + +private data class PomDependency(val groupId: String?, val artifactId: String, val version: String?) diff --git a/build-logic/src/main/kotlin/cel-conventions.gradle.kts b/build-logic/src/main/kotlin/cel-conventions.gradle.kts index d7ce2b6c..a2324019 100644 --- a/build-logic/src/main/kotlin/cel-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/cel-conventions.gradle.kts @@ -14,14 +14,14 @@ * limitations under the License. */ -if (project.name != "conformance" && project.name != "jacoco") { - apply() -} - nessieConfigureSpotless() nessieConfigureJava() +if (project.name != "conformance" && project.name != "jacoco") { + apply() +} + nessieIde() apply() From ddaf95309074ba394ee80f7d694217462ca990ef Mon Sep 17 00:00:00 2001 From: Robert Stupp Date: Wed, 8 Jul 2026 13:18:02 +0200 Subject: [PATCH 6/9] Remove Gradle wrapper jar from source tree --- .gitignore | 6 +++ build.gradle.kts | 1 + gradle/gradlew-include.sh | 64 ++++++++++++++++++++++++++++++ gradle/wrapper/gradle-wrapper.jar | Bin 46175 -> 0 bytes gradlew | 3 ++ 5 files changed, 74 insertions(+) create mode 100644 gradle/gradlew-include.sh delete mode 100644 gradle/wrapper/gradle-wrapper.jar diff --git a/.gitignore b/.gitignore index 116162cd..c7ab86eb 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,10 @@ build/ .gradle/ buildSrc/.kotlin/ +# Ignore Gradle wrapper jar file +gradle/wrapper/gradle-wrapper.jar +gradle/wrapper/gradle-wrapper-*.sha256 + # Maven **/.mvn/wrapper/maven-wrapper.jar target/ @@ -13,3 +17,5 @@ target/ out/ conformance/conformance-server.pid + +/.env diff --git a/build.gradle.kts b/build.gradle.kts index e8236c15..df717101 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -79,6 +79,7 @@ tasks.named("wrapper") { val insertAtLine = scriptLines.indexOf("# Use the maximum available, or set MAX_FD != -1 to use that value.") scriptLines.add(insertAtLine, "") + scriptLines.add(insertAtLine, $$"[ -f \"${APP_HOME}/.env\" ] && . \"${APP_HOME}/.env\"") scriptLines.add(insertAtLine, $$". \"${APP_HOME}/gradle/gradlew-include.sh\"") scriptFile.writeText(scriptLines.joinToString("\n")) diff --git a/gradle/gradlew-include.sh b/gradle/gradlew-include.sh new file mode 100644 index 00000000..8ec9a2f6 --- /dev/null +++ b/gradle/gradlew-include.sh @@ -0,0 +1,64 @@ +# +# Copyright (C) 2024 Dremio +# +# Licensed 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. +# + +# Downloads the gradle-wrapper.jar if necessary and verifies its integrity. +# Included from /.gradlew + +# Extract the Gradle version from gradle-wrapper.properties. +GRADLE_DIST_VERSION="$(grep distributionUrl= "$APP_HOME/gradle/wrapper/gradle-wrapper.properties" | sed 's/^.*gradle-\([0-9.]*\)-[a-z]*.zip$/\1/')" +GRADLE_WRAPPER_SHA256="$APP_HOME/gradle/wrapper/gradle-wrapper-${GRADLE_DIST_VERSION}.jar.sha256" +GRADLE_WRAPPER_JAR="$APP_HOME/gradle/wrapper/gradle-wrapper.jar" +if [ -x "$(command -v sha256sum)" ] ; then + SHASUM="sha256sum" +else + if [ -x "$(command -v shasum)" ] ; then + SHASUM="shasum -a 256" + else + echo "Neither sha256sum nor shasum are available, install either." > /dev/stderr + exit 1 + fi +fi +if [ ! -e "${GRADLE_WRAPPER_SHA256}" ]; then + # Delete the wrapper jar, if the checksum file does not exist. + rm -f "${GRADLE_WRAPPER_JAR}" +fi +if [ -e "${GRADLE_WRAPPER_JAR}" ]; then + # Verify the wrapper jar, if it exists, delete wrapper jar and checksum file, if the checksums + # do not match. + JAR_CHECKSUM="$(${SHASUM} "${GRADLE_WRAPPER_JAR}" | cut -d\ -f1)" + EXPECTED="$(cat "${GRADLE_WRAPPER_SHA256}")" + if [ "${JAR_CHECKSUM}" != "${EXPECTED}" ]; then + rm -f "${GRADLE_WRAPPER_JAR}" "${GRADLE_WRAPPER_SHA256}" + fi +fi +if [ ! -e "${GRADLE_WRAPPER_SHA256}" ]; then + curl --location --output "${GRADLE_WRAPPER_SHA256}" https://services.gradle.org/distributions/gradle-${GRADLE_DIST_VERSION}-wrapper.jar.sha256 || exit 1 +fi +if [ ! -e "${GRADLE_WRAPPER_JAR}" ]; then + # The Gradle version extracted from the `distributionUrl` property does not contain ".0" patch + # versions. Need to append a ".0" in that case to download the wrapper jar. + GRADLE_VERSION="$(echo "$GRADLE_DIST_VERSION" | sed 's/^\([0-9]*[.][0-9]*\)$/\1.0/')" + curl --location --output "${GRADLE_WRAPPER_JAR}" https://raw.githubusercontent.com/gradle/gradle/v${GRADLE_VERSION}/gradle/wrapper/gradle-wrapper.jar || exit 1 + JAR_CHECKSUM="$(${SHASUM} "${GRADLE_WRAPPER_JAR}" | cut -d\ -f1)" + EXPECTED="$(cat "${GRADLE_WRAPPER_SHA256}")" + if [ "${JAR_CHECKSUM}" != "${EXPECTED}" ]; then + # If the (just downloaded) checksum and the downloaded wrapper jar do not match, something + # really bad is going on. + echo "Expected sha256 of the downloaded gradle-wrapper.jar does not match the downloaded sha256!" > /dev/stderr + exit 1 + fi +fi + diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 61285a659d17295f1de7c53e24fdf13ad755c379..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 46175 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

pVX@HRij*jw$g4?}Pn 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 diff --git a/gradlew b/gradlew index adff685a..10fe486d 100755 --- a/gradlew +++ b/gradlew @@ -88,6 +88,9 @@ APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit +[ -f "${APP_HOME}/.env" ] && . "${APP_HOME}/.env" +. "${APP_HOME}/gradle/gradlew-include.sh" + # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum From c36e2f06d898854e655fff23fd237384b7893de8 Mon Sep 17 00:00:00 2001 From: Robert Stupp Date: Wed, 8 Jul 2026 13:22:09 +0200 Subject: [PATCH 7/9] Add safeguard for config-cache in CI --- settings.gradle.kts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/settings.gradle.kts b/settings.gradle.kts index 7f7c88d2..0d114d64 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -17,6 +17,7 @@ import com.gradle.develocity.agent.gradle.scan.BuildScanPublishingConfiguration import java.time.Duration import org.gradle.api.specs.Spec +import org.gradle.kotlin.dsl.support.serviceOf if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_17)) { throw GradleException("Build requires Java 17") @@ -26,6 +27,14 @@ val baseVersion = providers.fileContents(layout.settingsDirectory.file("version.txt")).asText.map { it.trim() } val isCI = providers.environmentVariable("CI").isPresent val isBuildScanRequested = gradle.startParameter.isBuildScan +val configurationCacheRequested = + gradle.serviceOf().configurationCache.requested.getOrElse(false) + +if (isCI && configurationCacheRequested) { + throw GradleException( + "Gradle configuration cache must not be enabled in CI because it can persist build configuration state to disk." + ) +} pluginManagement { includeBuild("build-logic") { name = "cel-java-build-logic" } From b9fdaa0e22b50d3dff03028c0b7a4e0ba92734f6 Mon Sep 17 00:00:00 2001 From: Robert Stupp Date: Wed, 8 Jul 2026 13:20:56 +0200 Subject: [PATCH 8/9] Fix some Gradle deprecations --- build.gradle.kts | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index df717101..a7c18240 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -27,8 +27,8 @@ mapOf("versionJacoco" to libs.versions.jacoco.get(), "versionJandex" to libs.ver tasks.named("wrapper") { distributionType = Wrapper.DistributionType.ALL } -val buildToolIntegrationGradle by - tasks.registering(Exec::class) { +val buildToolIntegrationGradle = + tasks.register("buildToolIntegrationGradle") { group = "Verification" description = "Checks whether bom works fine with Gradle, requires preceding publishToMavenLocal in a separate Gradle invocation" @@ -37,8 +37,8 @@ val buildToolIntegrationGradle by commandLine("./gradlew", "jar", "-Dcel.version=${project.version}") } -val buildToolIntegrationMaven by - tasks.registering(Exec::class) { +val buildToolIntegrationMaven = + tasks.register("buildToolIntegrationMaven") { group = "Verification" description = "Checks whether bom works fine with Maven, requires preceding publishToMavenLocal in a separate Gradle invocation" @@ -47,14 +47,15 @@ val buildToolIntegrationMaven by commandLine("./mvnw", "clean", "package", "-Dcel.version=${project.version}") } -val buildToolIntegrations by tasks.registering { - group = "Verification" - description = - "Checks whether bom works fine with build tools, requires preceding publishToMavenLocal in a separate Gradle invocation" +val buildToolIntegrations = + tasks.register("buildToolIntegrations") { + group = "Verification" + description = + "Checks whether bom works fine with build tools, requires preceding publishToMavenLocal in a separate Gradle invocation" - dependsOn(buildToolIntegrationGradle) - dependsOn(buildToolIntegrationMaven) -} + dependsOn(buildToolIntegrationGradle) + dependsOn(buildToolIntegrationMaven) + } publishingHelper { nessieRepoName.set("cel-java") From 2db2d1be14fb267f4b0731da87c4a72a2718f39f Mon Sep 17 00:00:00 2001 From: Robert Stupp Date: Wed, 8 Jul 2026 14:07:00 +0200 Subject: [PATCH 9/9] Prevent/fix `Calculating task graph as configuration cache cannot be reused because an input to unknown location has changed.` --- build-logic/src/main/kotlin/Ide.kt | 7 +- build-logic/src/main/kotlin/Spotless.kt | 6 +- conformance/build.gradle.kts | 54 ++++++++++++- generated-pb/build.gradle.kts | 75 ++++++++++++++++++- .../src/main/proto/google/api/expr/v1alpha1 | 1 - generated-pb/src/main/proto/google/rpc | 1 - .../testFixtures/proto/proto/test/v1/proto2 | 1 - .../testFixtures/proto/proto/test/v1/proto3 | 1 - generated-pb3/build.gradle.kts | 75 ++++++++++++++++++- generated-pb3/src | 1 - 10 files changed, 206 insertions(+), 16 deletions(-) delete mode 120000 generated-pb/src/main/proto/google/api/expr/v1alpha1 delete mode 120000 generated-pb/src/main/proto/google/rpc delete mode 120000 generated-pb/src/testFixtures/proto/proto/test/v1/proto2 delete mode 120000 generated-pb/src/testFixtures/proto/proto/test/v1/proto3 delete mode 120000 generated-pb3/src diff --git a/build-logic/src/main/kotlin/Ide.kt b/build-logic/src/main/kotlin/Ide.kt index a0635780..4b8ebb5b 100644 --- a/build-logic/src/main/kotlin/Ide.kt +++ b/build-logic/src/main/kotlin/Ide.kt @@ -87,8 +87,11 @@ fun Project.nessieIde() { // the Gradle project) val ideaDir = layout.projectDirectory.dir(".idea").asFile - if (ideaDir.isDirectory) { - ideaDir.resolve(".name").writeText(ideName) + if (java.lang.Boolean.getBoolean("idea.sync.active") && ideaDir.isDirectory) { + val ideaNameFile = ideaDir.resolve(".name") + if (!ideaNameFile.isFile || ideaNameFile.readText() != ideName) { + ideaNameFile.writeText(ideName) + } } configure { project { name = ideName } } diff --git a/build-logic/src/main/kotlin/Spotless.kt b/build-logic/src/main/kotlin/Spotless.kt index 8ae48cc9..c476bb22 100644 --- a/build-logic/src/main/kotlin/Spotless.kt +++ b/build-logic/src/main/kotlin/Spotless.kt @@ -16,13 +16,13 @@ import com.diffplug.gradle.spotless.SpotlessExtension import com.diffplug.gradle.spotless.SpotlessPlugin +import com.diffplug.spotless.LineEnding import org.gradle.api.Project import org.gradle.kotlin.dsl.apply import org.gradle.kotlin.dsl.configure import org.gradle.kotlin.dsl.withType fun Project.nessieConfigureSpotless() { - apply() if (!java.lang.Boolean.getBoolean("idea.sync.active")) { val copyrightHeader = layout.settingsDirectory.file("codestyle/copyright-header-java.txt") @@ -30,6 +30,8 @@ fun Project.nessieConfigureSpotless() { plugins.withType().configureEach { configure { + lineEndings = LineEnding.UNIX + format("xml") { target("src/**/*.xml", "src/**/*.xsd") eclipseWtp(com.diffplug.spotless.extra.wtp.EclipseWtpFormatterStep.XML) @@ -76,7 +78,7 @@ fun Project.nessieConfigureSpotless() { java { googleJavaFormat(libsRequiredVersion("googleJavaFormat")) licenseHeaderFile(copyrightHeader.asFile) - target("src/**/java/**") + target("src/**/*.java") targetExclude("build/**") } } diff --git a/conformance/build.gradle.kts b/conformance/build.gradle.kts index f4d0cb94..0b3978cd 100644 --- a/conformance/build.gradle.kts +++ b/conformance/build.gradle.kts @@ -16,6 +16,9 @@ import com.google.protobuf.gradle.ProtobufExtension import com.google.protobuf.gradle.ProtobufPlugin +import org.gradle.api.file.SourceDirectorySet +import org.gradle.api.tasks.Sync +import org.gradle.api.tasks.compile.JavaCompile plugins { `java-library` @@ -25,9 +28,39 @@ plugins { apply() +val syncedMainProtoDir = layout.buildDirectory.dir("pb-src/proto") +val mainProtoResourcesDir = layout.buildDirectory.dir("generated/proto-resources/main") +val syncMainProtoSources = + tasks.register("syncMainProtoSources") { + into(syncedMainProtoDir) + from(layout.settingsDirectory.dir("submodules/googleapis/google/rpc")) { into("google/rpc") } + from(layout.settingsDirectory.dir("submodules/googleapis/google/api/expr/conformance")) { + into("google/api/expr/conformance") + } + } + +val emptyTestProtoDir = layout.buildDirectory.dir("pb-src/test/proto") + sourceSets.main { - java.srcDir(layout.buildDirectory.dir("generated/source/proto/main/java")) - java.srcDir(layout.buildDirectory.dir("generated/source/proto/main/grpc")) + java.setSrcDirs( + listOf( + layout.projectDirectory.dir("src/main/java"), + layout.buildDirectory.dir("generated/sources/proto/main/java"), + layout.buildDirectory.dir("generated/sources/proto/main/grpc"), + ) + ) + resources.setSrcDirs(listOf(mainProtoResourcesDir)) + extensions.configure("proto") { + setSrcDirs(listOf(syncedMainProtoDir)) + } +} + +sourceSets.test { + java.setSrcDirs(listOf(layout.projectDirectory.dir("src/test/java"))) + resources.setSrcDirs(emptyList()) + extensions.configure("proto") { + setSrcDirs(listOf(emptyTestProtoDir)) + } } configurations.all { exclude(group = "org.projectnessie.cel", module = "cel-generated-pb") } @@ -67,5 +100,20 @@ configure { generateProtoTasks { all().configureEach { this.plugins.create("grpc") {} } } } +tasks.named("generateProto") { dependsOn(syncMainProtoSources) } + +tasks.named("compileJava") { dependsOn(tasks.named("generateProto")) } + +tasks.named("processProtoResources") { dependsOn(syncMainProtoSources) } + +tasks.named("processResources") { dependsOn(tasks.named("processProtoResources")) } + +tasks.named("generateTestProto") { enabled = false } + +tasks.named("processTestProtoResources") { enabled = false } + // The protobuf-plugin should ideally do this -tasks.named("sourcesJar") { dependsOn(tasks.named("generateProto")) } +tasks.named("sourcesJar") { + dependsOn(tasks.named("generateProto")) + dependsOn(tasks.named("processProtoResources")) +} diff --git a/generated-pb/build.gradle.kts b/generated-pb/build.gradle.kts index da63daed..bd743f3b 100644 --- a/generated-pb/build.gradle.kts +++ b/generated-pb/build.gradle.kts @@ -16,6 +16,9 @@ import com.google.protobuf.gradle.ProtobufExtension import com.google.protobuf.gradle.ProtobufPlugin +import org.gradle.api.file.SourceDirectorySet +import org.gradle.api.tasks.Sync +import org.gradle.api.tasks.compile.JavaCompile plugins { `java-library` @@ -27,14 +30,57 @@ plugins { apply() +val syncedMainProtoDir = layout.buildDirectory.dir("pb-src/proto") +val mainProtoResourcesDir = layout.buildDirectory.dir("generated/proto-resources/main") +val syncMainProtoSources = + tasks.register("syncMainProtoSources") { + into(syncedMainProtoDir) + from(layout.settingsDirectory.dir("submodules/googleapis/google/rpc")) { into("google/rpc") } + from(layout.settingsDirectory.dir("submodules/googleapis/google/api/expr/v1alpha1")) { + into("google/api/expr/v1alpha1") + } + } + +val emptyTestProtoDir = layout.buildDirectory.dir("pb-src/test/proto") +val syncedTestFixturesProtoDir = layout.buildDirectory.dir("pb-src/testFixtures/proto") +val testFixturesProtoResourcesDir = + layout.buildDirectory.dir("generated/proto-resources/testFixtures") +val syncTestFixturesProtoSources = + tasks.register("syncTestFixturesProtoSources") { + into(syncedTestFixturesProtoDir) + from(layout.projectDirectory.dir("src/testFixtures/proto")) { include("*.proto") } + from(layout.settingsDirectory.dir("submodules/cel-spec/proto/test/v1/proto2")) { + into("proto/test/v1/proto2") + } + from(layout.settingsDirectory.dir("submodules/cel-spec/proto/test/v1/proto3")) { + into("proto/test/v1/proto3") + } + } + sourceSets.main { - java.srcDir(layout.buildDirectory.dir("generated/source/proto/main/java")) + java.setSrcDirs(listOf(layout.buildDirectory.dir("generated/sources/proto/main/java"))) java.destinationDirectory.set(layout.buildDirectory.dir("classes/java/generated")) + resources.setSrcDirs(listOf(mainProtoResourcesDir)) + extensions.configure("proto") { + setSrcDirs(listOf(syncedMainProtoDir)) + } } sourceSets.test { - java.srcDir(layout.buildDirectory.dir("generated/source/proto/test/java")) + java.setSrcDirs(listOf(layout.buildDirectory.dir("generated/sources/proto/test/java"))) java.destinationDirectory.set(layout.buildDirectory.dir("classes/java/generatedTest")) + resources.setSrcDirs(emptyList()) + extensions.configure("proto") { + setSrcDirs(listOf(emptyTestProtoDir)) + } +} + +sourceSets.testFixtures { + java.setSrcDirs(listOf(layout.buildDirectory.dir("generated/sources/proto/testFixtures/java"))) + resources.setSrcDirs(listOf(testFixturesProtoResourcesDir)) + extensions.configure("proto") { + setSrcDirs(listOf(syncedTestFixturesProtoDir)) + } } dependencies { @@ -56,3 +102,28 @@ configure { artifact = "com.google.protobuf:protoc:${libs.versions.protobuf.get()}" } } + +tasks.named("generateProto") { dependsOn(syncMainProtoSources) } + +tasks.named("compileJava") { dependsOn(tasks.named("generateProto")) } + +tasks.named("processProtoResources") { dependsOn(syncMainProtoSources) } + +tasks.named("processResources") { dependsOn(tasks.named("processProtoResources")) } + +tasks.named("sourcesJar") { + dependsOn(tasks.named("generateProto")) + dependsOn(tasks.named("processProtoResources")) +} + +tasks.named("generateTestFixturesProto") { dependsOn(syncTestFixturesProtoSources) } + +tasks.named("compileTestFixturesJava") { + dependsOn(tasks.named("generateTestFixturesProto")) +} + +tasks.named("processTestFixturesProtoResources") { dependsOn(syncTestFixturesProtoSources) } + +tasks.named("processTestFixturesResources") { + dependsOn(tasks.named("processTestFixturesProtoResources")) +} diff --git a/generated-pb/src/main/proto/google/api/expr/v1alpha1 b/generated-pb/src/main/proto/google/api/expr/v1alpha1 deleted file mode 120000 index 3ca742d0..00000000 --- a/generated-pb/src/main/proto/google/api/expr/v1alpha1 +++ /dev/null @@ -1 +0,0 @@ -../../../../../../../submodules/googleapis/google/api/expr/v1alpha1 \ No newline at end of file diff --git a/generated-pb/src/main/proto/google/rpc b/generated-pb/src/main/proto/google/rpc deleted file mode 120000 index b915345f..00000000 --- a/generated-pb/src/main/proto/google/rpc +++ /dev/null @@ -1 +0,0 @@ -../../../../../submodules/googleapis/google/rpc \ No newline at end of file diff --git a/generated-pb/src/testFixtures/proto/proto/test/v1/proto2 b/generated-pb/src/testFixtures/proto/proto/test/v1/proto2 deleted file mode 120000 index c7628e00..00000000 --- a/generated-pb/src/testFixtures/proto/proto/test/v1/proto2 +++ /dev/null @@ -1 +0,0 @@ -../../../../../../../submodules/cel-spec/proto/test/v1/proto2 \ No newline at end of file diff --git a/generated-pb/src/testFixtures/proto/proto/test/v1/proto3 b/generated-pb/src/testFixtures/proto/proto/test/v1/proto3 deleted file mode 120000 index a6b27aac..00000000 --- a/generated-pb/src/testFixtures/proto/proto/test/v1/proto3 +++ /dev/null @@ -1 +0,0 @@ -../../../../../../../submodules/cel-spec/proto/test/v1/proto3 \ No newline at end of file diff --git a/generated-pb3/build.gradle.kts b/generated-pb3/build.gradle.kts index de6169d9..54ecee51 100644 --- a/generated-pb3/build.gradle.kts +++ b/generated-pb3/build.gradle.kts @@ -16,6 +16,9 @@ import com.google.protobuf.gradle.ProtobufExtension import com.google.protobuf.gradle.ProtobufPlugin +import org.gradle.api.file.SourceDirectorySet +import org.gradle.api.tasks.Sync +import org.gradle.api.tasks.compile.JavaCompile plugins { `java-library` @@ -27,14 +30,57 @@ plugins { apply() +val syncedMainProtoDir = layout.buildDirectory.dir("pb-src/proto") +val mainProtoResourcesDir = layout.buildDirectory.dir("generated/proto-resources/main") +val syncMainProtoSources = + tasks.register("syncMainProtoSources") { + into(syncedMainProtoDir) + from(layout.settingsDirectory.dir("submodules/googleapis/google/rpc")) { into("google/rpc") } + from(layout.settingsDirectory.dir("submodules/googleapis/google/api/expr/v1alpha1")) { + into("google/api/expr/v1alpha1") + } + } + +val emptyTestProtoDir = layout.buildDirectory.dir("pb-src/test/proto") +val syncedTestFixturesProtoDir = layout.buildDirectory.dir("pb-src/testFixtures/proto") +val testFixturesProtoResourcesDir = + layout.buildDirectory.dir("generated/proto-resources/testFixtures") +val syncTestFixturesProtoSources = + tasks.register("syncTestFixturesProtoSources") { + into(syncedTestFixturesProtoDir) + from(layout.settingsDirectory.dir("generated-pb/src/testFixtures/proto")) { include("*.proto") } + from(layout.settingsDirectory.dir("submodules/cel-spec/proto/test/v1/proto2")) { + into("proto/test/v1/proto2") + } + from(layout.settingsDirectory.dir("submodules/cel-spec/proto/test/v1/proto3")) { + into("proto/test/v1/proto3") + } + } + sourceSets.main { - java.srcDir(layout.buildDirectory.dir("generated/source/proto/main/java")) + java.setSrcDirs(listOf(layout.buildDirectory.dir("generated/sources/proto/main/java"))) java.destinationDirectory.set(layout.buildDirectory.dir("classes/java/generated")) + resources.setSrcDirs(listOf(mainProtoResourcesDir)) + extensions.configure("proto") { + setSrcDirs(listOf(syncedMainProtoDir)) + } } sourceSets.test { - java.srcDir(layout.buildDirectory.dir("generated/source/proto/test/java")) + java.setSrcDirs(listOf(layout.buildDirectory.dir("generated/sources/proto/test/java"))) java.destinationDirectory.set(layout.buildDirectory.dir("classes/java/generatedTest")) + resources.setSrcDirs(emptyList()) + extensions.configure("proto") { + setSrcDirs(listOf(emptyTestProtoDir)) + } +} + +sourceSets.testFixtures { + java.setSrcDirs(listOf(layout.buildDirectory.dir("generated/sources/proto/testFixtures/java"))) + resources.setSrcDirs(listOf(testFixturesProtoResourcesDir)) + extensions.configure("proto") { + setSrcDirs(listOf(syncedTestFixturesProtoDir)) + } } dependencies { @@ -56,3 +102,28 @@ configure { artifact = "com.google.protobuf:protoc:${libs.versions.protobuf3.get()}" } } + +tasks.named("generateProto") { dependsOn(syncMainProtoSources) } + +tasks.named("compileJava") { dependsOn(tasks.named("generateProto")) } + +tasks.named("processProtoResources") { dependsOn(syncMainProtoSources) } + +tasks.named("processResources") { dependsOn(tasks.named("processProtoResources")) } + +tasks.named("sourcesJar") { + dependsOn(tasks.named("generateProto")) + dependsOn(tasks.named("processProtoResources")) +} + +tasks.named("generateTestFixturesProto") { dependsOn(syncTestFixturesProtoSources) } + +tasks.named("compileTestFixturesJava") { + dependsOn(tasks.named("generateTestFixturesProto")) +} + +tasks.named("processTestFixturesProtoResources") { dependsOn(syncTestFixturesProtoSources) } + +tasks.named("processTestFixturesResources") { + dependsOn(tasks.named("processTestFixturesProtoResources")) +} diff --git a/generated-pb3/src b/generated-pb3/src deleted file mode 120000 index 454c0e97..00000000 --- a/generated-pb3/src +++ /dev/null @@ -1 +0,0 @@ -../generated-pb/src \ No newline at end of file