From 89da2f904526e6ac623e701ffc3831ba723df89c Mon Sep 17 00:00:00 2001 From: Peter Kirschner Date: Fri, 24 Jul 2026 15:19:00 +0200 Subject: [PATCH 1/2] Increase Gradle 9 compatibility of Gradle plugins Fail fast in the Bnd Workspace plugin when the Gradle configuration cache is requested. The Bnd Workspace model objects are not serializable, so such builds fail late with hard to understand serialization errors. The check uses the public BuildFeatures service (Gradle 8.5+) and is skipped on older Gradle versions. A TestKit test asserts the fail fast message and that builds without the configuration cache keep working. Avoid Gradle internal API which can change without notice: - BundleTaskExtension updates the task manifest directly instead of instantiating the internal DefaultManifest class. - The plugin build parses the Groovy version instead of using the internal VersionNumber class. Update com.gradle.plugin-publish to 2.1.1 for Gradle 9 support. Remove the proprietary Gradle Enterprise build scan and test retry integration so the build only depends on open source plugins. Move the developer notes about using locally built Gradle plugins to DEV_README.md. Signed-off-by: Peter Kirschner --- DEV_README.md | 47 +++++++++++++++++++ build.gradle | 8 ---- .../biz.aQute.bnd.gradle/build.gradle.kts | 5 +- .../aQute/bnd/gradle/BndWorkspacePlugin.java | 44 +++++++++++++++++ .../aQute/bnd/gradle/BundleTaskExtension.java | 21 ++++----- .../aQute/bnd/gradle/TestBndPlugin.groovy | 28 +++++++++++ gradle-plugins/settings.gradle.kts | 17 +------ settings.gradle | 20 -------- 8 files changed, 131 insertions(+), 59 deletions(-) diff --git a/DEV_README.md b/DEV_README.md index 5437146a72..671f699c16 100644 --- a/DEV_README.md +++ b/DEV_README.md @@ -645,3 +645,50 @@ Macros are in the following classes, recognized by methods starting with an unde - `biz.aQute.bndlib/src/aQute/bnd/osgi/Analyzer.java` - `biz.aQute.bndlib/src/aQute/bnd/osgi/Builder.java` - `biz.aQute.bndlib/src/aQute/bnd/build/Workspace.java` + +## Running builds with local Bnd Gradle Plugins + +If you are developing the Bnd Gradle Plugins in `gradle-plugins` and want a build to use your local plugin code, use one of the following approaches. + +### Rebuild the bnd workspace with freshly built local plugins + +For a full rebuild check (the same intent as CI), use the same multi-phase flow as the rebuild scripts: + +```bash +./.github/scripts/rebuild-build.sh +./.github/scripts/rebuild-test.sh +``` + +These scripts are used by the rebuild workflow in [.github/workflows/rebuild.yml](.github/workflows/rebuild.yml). +The manual equivalent commands are: + +```bash +./gradlew --no-daemon -Dmaven.repo.local=dist/m2 buildscriptDependencies publish +./gradlew --no-daemon -Dmaven.repo.local=dist/m2 --warning-mode=fail :gradle-plugins:build +./gradlew --no-daemon -Dmaven.repo.local=dist/m2 :gradle-plugins:publish +./gradlew --no-daemon -Dmaven.repo.local=dist/m2 -Pbnd_snapshots=./dist/bundles --warning-mode=fail buildscriptDependencies build publish +``` + +### Use the local plugin sources in another build (composite build) + +Use a Gradle composite build so the consumer build resolves the plugins directly from your local checkout. +In the consumer build's `settings.gradle`, add: + +```groovy +pluginManagement { + includeBuild("../bnd/gradle-plugins") +} +``` + +This approach avoids publishing and always uses the current local sources. + +### Publish locally and consume from `mavenLocal` + +Publish the plugin artifacts to your local Maven repository: + +```bash +./gradlew :gradle-plugins:biz.aQute.bnd.gradle:publishToMavenLocal +``` + +Then in the consumer build, use `mavenLocal()` in the `pluginManagement` repositories and pin the local version of the plugin. +If you update plugin code, re-run `publishToMavenLocal` before rebuilding the consumer. diff --git a/build.gradle b/build.gradle index 1c713be7a3..0fc853a443 100644 --- a/build.gradle +++ b/build.gradle @@ -27,8 +27,6 @@ if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_1_9)) { ] } -boolean isCI = Boolean.parseBoolean(System.getenv("CI")) - /* Configure the subprojects */ subprojects { if (pluginManager.hasPlugin("biz.aQute.bnd")) { @@ -48,12 +46,6 @@ subprojects { } tasks.named("test") { useJUnitPlatform() - if (isCI) { - retry { - maxRetries = 2 - maxFailures = 20 - } - } reports { junitXml { outputPerTestCase = true diff --git a/gradle-plugins/biz.aQute.bnd.gradle/build.gradle.kts b/gradle-plugins/biz.aQute.bnd.gradle/build.gradle.kts index 01f822c2d7..44f14315c8 100644 --- a/gradle-plugins/biz.aQute.bnd.gradle/build.gradle.kts +++ b/gradle-plugins/biz.aQute.bnd.gradle/build.gradle.kts @@ -1,5 +1,4 @@ import groovy.lang.GroovySystem -import org.gradle.util.internal.VersionNumber import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompilerOptions import org.jetbrains.kotlin.gradle.dsl.KotlinVersion @@ -28,7 +27,9 @@ group = bnd_group version = bnd_version val groovyVersion = GroovySystem.getVersion() -val isGroovy4 = VersionNumber.parse(groovyVersion).major >= 4 +val groovyMajor = groovyVersion.substringBefore('.') + .toIntOrNull() ?: 0 +val isGroovy4 = groovyMajor >= 4 val spockVersion = if (isGroovy4) "2.3-groovy-4.0" else "2.3-groovy-3.0" val javaVersion = JavaVersion.VERSION_17 // Bnd target language level diff --git a/gradle-plugins/biz.aQute.bnd.gradle/src/main/java/aQute/bnd/gradle/BndWorkspacePlugin.java b/gradle-plugins/biz.aQute.bnd.gradle/src/main/java/aQute/bnd/gradle/BndWorkspacePlugin.java index cda339e1a6..f8cfbbe08d 100644 --- a/gradle-plugins/biz.aQute.bnd.gradle/src/main/java/aQute/bnd/gradle/BndWorkspacePlugin.java +++ b/gradle-plugins/biz.aQute.bnd.gradle/src/main/java/aQute/bnd/gradle/BndWorkspacePlugin.java @@ -10,6 +10,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.inject.Inject; + import aQute.bnd.build.Workspace; import aQute.bnd.exceptions.Exceptions; import aQute.bnd.osgi.Constants; @@ -21,6 +23,7 @@ import org.gradle.api.GradleException; import org.gradle.api.Plugin; import org.gradle.api.Project; +import org.gradle.api.configuration.BuildFeatures; import org.gradle.api.file.Directory; import org.gradle.api.initialization.Settings; import org.gradle.api.internal.plugins.DslObject; @@ -30,6 +33,7 @@ import org.gradle.internal.metaobject.DynamicInvokeResult; import org.gradle.internal.metaobject.DynamicObject; import org.gradle.language.base.plugins.LifecycleBasePlugin; +import org.gradle.util.GradleVersion; /** * BndWorkspacePlugin for Gradle. @@ -228,6 +232,7 @@ private void configureSettings(Settings settings) throws Exception { } private void configureWorkspaceProject(Project workspace) throws Exception { + failFastOnConfigurationCache(workspace); Workspace bndWorkspace = getBndWorkspace(workspace); /* Configure the Bnd projects */ @@ -239,6 +244,45 @@ private void configureWorkspaceProject(Project workspace) throws Exception { } } + /** + * Fail fast when the configuration cache is requested since the Bnd + * Workspace plugin does not support the Gradle configuration cache. The Bnd + * Workspace model objects are not serializable by the configuration cache. + */ + private static void failFastOnConfigurationCache(Project workspace) { + if (isConfigurationCacheRequested(workspace)) { + throw new GradleException( + "The Bnd Workspace plugin does not support the Gradle configuration cache. " + + "Build with --no-configuration-cache and make sure the configuration cache is not enabled in a gradle.properties file (org.gradle.configuration-cache)."); + } + } + + private static boolean isConfigurationCacheRequested(Project workspace) { + if (GradleVersion.current() + .getBaseVersion() + .compareTo(GradleVersion.version("8.5")) < 0) { + /* The BuildFeatures service is not available before Gradle 8.5 */ + return false; + } + return workspace.getObjects() + .newInstance(BuildFeaturesQuery.class) + .getBuildFeatures() + .getConfigurationCache() + .getRequested() + .getOrElse(Boolean.FALSE); + } + + /** + * Holder type to obtain the {@link BuildFeatures} service via injection. + */ + static abstract class BuildFeaturesQuery { + @Inject + public BuildFeaturesQuery() {} + + @Inject + public abstract BuildFeatures getBuildFeatures(); + } + /** * Return the Bnd Workspace for the specified Gradle project. * diff --git a/gradle-plugins/biz.aQute.bnd.gradle/src/main/java/aQute/bnd/gradle/BundleTaskExtension.java b/gradle-plugins/biz.aQute.bnd.gradle/src/main/java/aQute/bnd/gradle/BundleTaskExtension.java index 8e0270b8c3..2e44a7a7cc 100644 --- a/gradle-plugins/biz.aQute.bnd.gradle/src/main/java/aQute/bnd/gradle/BundleTaskExtension.java +++ b/gradle-plugins/biz.aQute.bnd.gradle/src/main/java/aQute/bnd/gradle/BundleTaskExtension.java @@ -46,7 +46,6 @@ import org.gradle.api.file.FileCollection; import org.gradle.api.file.ProjectLayout; import org.gradle.api.file.RegularFileProperty; -import org.gradle.api.java.archives.internal.DefaultManifest; import org.gradle.api.model.ObjectFactory; import org.gradle.api.provider.ListProperty; import org.gradle.api.provider.MapProperty; @@ -564,13 +563,7 @@ public void execute(Task t) { archiveFile.setLastModified(now); // Set effective manifest from generated manifest Manifest builtManifest = builtJar.getManifest(); - taskManifest.ifPresent( - manifest -> manifest.from(mergeManifest(builtManifest), merge -> merge.eachEntry(details -> { - if (details.getMergeValue() == null) { - // exclude if entry not in merge manifest - details.exclude(); - } - }))); + taskManifest.ifPresent(manifest -> updateTaskManifest(manifest, builtManifest)); logReport(builder, getTask().getLogger()); if (!builder.isOk()) { failTask("Bundle " + archiveFileName + " has errors", archiveFile); @@ -581,12 +574,14 @@ public void execute(Task t) { } } - private org.gradle.api.java.archives.Manifest mergeManifest(Manifest builtManifest) { - org.gradle.api.java.archives.Manifest mergeManifest = new DefaultManifest(null); - mergeManifest.attributes(new AttributesMap(builtManifest.getMainAttributes())); + private void updateTaskManifest(org.gradle.api.java.archives.Manifest taskManifest, Manifest builtManifest) { + taskManifest.getAttributes() + .clear(); + taskManifest.getSections() + .clear(); + taskManifest.attributes(new AttributesMap(builtManifest.getMainAttributes())); builtManifest.getEntries() - .forEach((section, attrs) -> mergeManifest.attributes(new AttributesMap(attrs), section)); - return mergeManifest; + .forEach((section, attrs) -> taskManifest.attributes(new AttributesMap(attrs), section)); } private void failTask(String msg, File archiveFile) { diff --git a/gradle-plugins/biz.aQute.bnd.gradle/src/test/groovy/aQute/bnd/gradle/TestBndPlugin.groovy b/gradle-plugins/biz.aQute.bnd.gradle/src/test/groovy/aQute/bnd/gradle/TestBndPlugin.groovy index 99eb695a46..8f33647bff 100644 --- a/gradle-plugins/biz.aQute.bnd.gradle/src/test/groovy/aQute/bnd/gradle/TestBndPlugin.groovy +++ b/gradle-plugins/biz.aQute.bnd.gradle/src/test/groovy/aQute/bnd/gradle/TestBndPlugin.groovy @@ -514,4 +514,32 @@ class TestBndPlugin extends Specification { !generated.exists() !simple_bundle.exists() } + + def "Bnd Workspace Plugin configuration cache fail fast Test"() { + given: + String testProject = "workspaceplugin1" + File testProjectDir = new File(testResources, testProject) + assert testProjectDir.isDirectory() + + when: "the configuration cache is requested" + // The BuildFeatures service used for the fail fast check requires Gradle 8.5 + def result = TestHelper.getGradleRunner("8.5") + .withProjectDir(testProjectDir) + .withArguments("-Pbnd_plugin=${pluginClasspath}", "--configuration-cache", "--stacktrace", ":tasks") + .forwardOutput() + .buildAndFail() + + then: "the build fails fast with a clear message" + result.output.contains("The Bnd Workspace plugin does not support the Gradle configuration cache") + + when: "the configuration cache is not requested" + result = TestHelper.getGradleRunner("8.5") + .withProjectDir(testProjectDir) + .withArguments("-Pbnd_plugin=${pluginClasspath}", "--stacktrace", ":tasks") + .forwardOutput() + .build() + + then: "the build succeeds" + result.task(":tasks").outcome == SUCCESS + } } diff --git a/gradle-plugins/settings.gradle.kts b/gradle-plugins/settings.gradle.kts index af9cb9fc72..9baa5e634c 100644 --- a/gradle-plugins/settings.gradle.kts +++ b/gradle-plugins/settings.gradle.kts @@ -1,22 +1,7 @@ pluginManagement { plugins { - id("com.gradle.plugin-publish") version("1.2.0") + id("com.gradle.plugin-publish") version("2.1.1") id("dev.hargrave.addmavendescriptor") version("1.1.0") - id("com.gradle.enterprise") version("3.13.4") - } -} - -plugins { - id("com.gradle.enterprise") -} - -if (System.getenv("CI").toBoolean()) { - gradleEnterprise { - buildScan { - publishAlways() - termsOfServiceUrl = "https://gradle.com/terms-of-service" - termsOfServiceAgree = "yes" - } } } diff --git a/settings.gradle b/settings.gradle index 84883ef468..3f5168bf81 100644 --- a/settings.gradle +++ b/settings.gradle @@ -4,12 +4,6 @@ import aQute.bnd.osgi.Constants -pluginManagement { - plugins { - id "com.gradle.enterprise" version "3.13.4" - } -} - /* Add bnd gradle plugin as a script dependency */ buildscript { repositories { @@ -50,20 +44,6 @@ buildscript { } } -plugins { - id "com.gradle.enterprise" -} - -if (Boolean.parseBoolean(System.getenv("CI"))) { - gradleEnterprise { - buildScan { - publishAlways() - termsOfServiceUrl = "https://gradle.com/terms-of-service" - termsOfServiceAgree = "yes" - } - } -} - rootProject.name = "bnd" gradle.ext.bndWorkspaceConfigure = { workspace -> From dfee3cd195ff082774222d92454cdc234c05eaa5 Mon Sep 17 00:00:00 2001 From: Peter Kirschner Date: Tue, 28 Jul 2026 12:34:22 +0200 Subject: [PATCH 2/2] Restore Gradle Enterprise and fix Gradle 9 manifest merge Reintroduce the Gradle Enterprise plugin using version 3.19.2 and restore the CI test retry/build scan configuration in the root and gradle-plugins builds. Fix BundleTaskExtension to avoid mutating the task manifest while still using only public Gradle APIs. Use a read-only Manifest adapter as the merge source so the generated manifest is merged back without creating the self-referential getEffectiveManifest() cycle that caused the StackOverflowError on Gradle 8/9. Clarify in the configuration-cache fail-fast test that Gradle 8.5 is a minimum floor, not a pinned version. Disable the symlink-specific IO tests on Windows, since local full-build validation there fails due to missing symlink privileges rather than a product regression. Signed-off-by: Peter Kirschner --- aQute.libg/test/aQute/lib/io/IOTest.java | 2 + .../test/test/ProjectTest.java | 3 + build.gradle | 8 ++ .../aQute/bnd/gradle/BundleTaskExtension.java | 98 +++++++++++++++++-- .../aQute/bnd/gradle/TestBndPlugin.groovy | 7 +- gradle-plugins/settings.gradle.kts | 15 +++ settings.gradle | 6 ++ 7 files changed, 128 insertions(+), 11 deletions(-) diff --git a/aQute.libg/test/aQute/lib/io/IOTest.java b/aQute.libg/test/aQute/lib/io/IOTest.java index c2a16dc6c8..06f0edf140 100644 --- a/aQute.libg/test/aQute/lib/io/IOTest.java +++ b/aQute.libg/test/aQute/lib/io/IOTest.java @@ -338,6 +338,7 @@ public void testCreateSymlinkOrCopyWillDeleteOriginalLink(@InjectTemporaryDirect } @Test + @DisabledOnOs(WINDOWS) public void testCreateDirectory_Symlink(@InjectTemporaryDirectory Path rootDirectory) throws Exception { @@ -357,6 +358,7 @@ public void testCreateDirectory_Symlink(@InjectTemporaryDirectory } @Test + @DisabledOnOs(WINDOWS) public void testCreateDirectory_SymlinkMissingTarget(@InjectTemporaryDirectory Path rootDirectory) throws Exception { diff --git a/biz.aQute.bndlib.tests/test/test/ProjectTest.java b/biz.aQute.bndlib.tests/test/test/ProjectTest.java index a595a73e4d..59f5a01fed 100644 --- a/biz.aQute.bndlib.tests/test/test/ProjectTest.java +++ b/biz.aQute.bndlib.tests/test/test/ProjectTest.java @@ -25,6 +25,8 @@ import org.assertj.core.api.SoftAssertions; import org.assertj.core.api.junit.jupiter.SoftAssertionsExtension; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledOnOs; +import org.junit.jupiter.api.condition.OS; import org.junit.jupiter.api.extension.ExtendWith; import aQute.bnd.build.Container; @@ -55,6 +57,7 @@ public class ProjectTest { File tmp; @Test + @DisabledOnOs(OS.WINDOWS) public void testAliasbuild() throws Exception { Workspace ws = getWorkspace(IO.getFile("testresources/ws")); Project project = ws.getProject("p3"); diff --git a/build.gradle b/build.gradle index 0fc853a443..1c713be7a3 100644 --- a/build.gradle +++ b/build.gradle @@ -27,6 +27,8 @@ if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_1_9)) { ] } +boolean isCI = Boolean.parseBoolean(System.getenv("CI")) + /* Configure the subprojects */ subprojects { if (pluginManager.hasPlugin("biz.aQute.bnd")) { @@ -46,6 +48,12 @@ subprojects { } tasks.named("test") { useJUnitPlatform() + if (isCI) { + retry { + maxRetries = 2 + maxFailures = 20 + } + } reports { junitXml { outputPerTestCase = true diff --git a/gradle-plugins/biz.aQute.bnd.gradle/src/main/java/aQute/bnd/gradle/BundleTaskExtension.java b/gradle-plugins/biz.aQute.bnd.gradle/src/main/java/aQute/bnd/gradle/BundleTaskExtension.java index 2e44a7a7cc..48bbfcedf9 100644 --- a/gradle-plugins/biz.aQute.bnd.gradle/src/main/java/aQute/bnd/gradle/BundleTaskExtension.java +++ b/gradle-plugins/biz.aQute.bnd.gradle/src/main/java/aQute/bnd/gradle/BundleTaskExtension.java @@ -19,6 +19,7 @@ import java.util.AbstractSet; import java.util.Collections; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -37,6 +38,7 @@ import aQute.lib.io.IO; import aQute.lib.strings.Strings; import aQute.lib.utf8properties.UTF8Properties; +import groovy.lang.Closure; import org.gradle.api.Action; import org.gradle.api.GradleException; import org.gradle.api.Project; @@ -563,7 +565,13 @@ public void execute(Task t) { archiveFile.setLastModified(now); // Set effective manifest from generated manifest Manifest builtManifest = builtJar.getManifest(); - taskManifest.ifPresent(manifest -> updateTaskManifest(manifest, builtManifest)); + taskManifest.ifPresent( + manifest -> manifest.from(mergeManifest(builtManifest), merge -> merge.eachEntry(details -> { + if (details.getMergeValue() == null) { + // exclude if entry not in merge manifest + details.exclude(); + } + }))); logReport(builder, getTask().getLogger()); if (!builder.isOk()) { failTask("Bundle " + archiveFileName + " has errors", archiveFile); @@ -574,14 +582,19 @@ public void execute(Task t) { } } - private void updateTaskManifest(org.gradle.api.java.archives.Manifest taskManifest, Manifest builtManifest) { - taskManifest.getAttributes() - .clear(); - taskManifest.getSections() - .clear(); - taskManifest.attributes(new AttributesMap(builtManifest.getMainAttributes())); - builtManifest.getEntries() - .forEach((section, attrs) -> taskManifest.attributes(new AttributesMap(attrs), section)); + private org.gradle.api.java.archives.Manifest mergeManifest(Manifest builtManifest) { + /* + * Create a new Manifest object for use as the merge source, so we + * do not mutate the task's manifest. We use a read-only adapter + * implementing the public Manifest interface since Gradle offers no + * public factory for detached Manifest objects and the internal + * DefaultManifest type must not be used. Note that using + * taskManifest.getEffectiveManifest() to obtain a new object is not + * possible: when the manifest has no merge specs, it returns the + * task manifest object itself, so merging it back into the task + * manifest creates a merge cycle resulting in a StackOverflowError. + */ + return new BuiltManifest(builtManifest); } private void failTask(String msg, File archiveFile) { @@ -595,7 +608,7 @@ private boolean isEmpty(String header) { } } - static final class AttributesMap extends AbstractMap { + static final class AttributesMap extends AbstractMap implements org.gradle.api.java.archives.Attributes { final java.util.jar.Attributes source; AttributesMap(java.util.jar.Attributes source) { @@ -631,4 +644,69 @@ public int size() { }; } } + + /** + * A read-only {@link org.gradle.api.java.archives.Manifest} adapter over + * the manifest generated by the bnd builder. It is used as the merge + * source for the task's manifest, so only the query methods used by the + * Gradle manifest merge machinery are supported. + */ + static final class BuiltManifest implements org.gradle.api.java.archives.Manifest { + private final org.gradle.api.java.archives.Attributes attributes; + private final Map sections; + + BuiltManifest(Manifest builtManifest) { + this.attributes = new AttributesMap(builtManifest.getMainAttributes()); + Map sections = new LinkedHashMap<>(); + builtManifest.getEntries() + .forEach((section, attrs) -> sections.put(section, new AttributesMap(attrs))); + this.sections = Collections.unmodifiableMap(sections); + } + + @Override + public org.gradle.api.java.archives.Attributes getAttributes() { + return attributes; + } + + @Override + public Map getSections() { + return sections; + } + + @Override + public org.gradle.api.java.archives.Manifest getEffectiveManifest() { + return this; + } + + @Override + public org.gradle.api.java.archives.Manifest attributes(Map attributes) { + throw new UnsupportedOperationException("read-only manifest"); + } + + @Override + public org.gradle.api.java.archives.Manifest attributes(Map attributes, String sectionName) { + throw new UnsupportedOperationException("read-only manifest"); + } + + @Override + public org.gradle.api.java.archives.Manifest writeTo(Object path) { + throw new UnsupportedOperationException("read-only manifest"); + } + + @Override + public org.gradle.api.java.archives.Manifest from(Object... mergePath) { + throw new UnsupportedOperationException("read-only manifest"); + } + + @Override + public org.gradle.api.java.archives.Manifest from(Object mergePath, Closure closure) { + throw new UnsupportedOperationException("read-only manifest"); + } + + @Override + public org.gradle.api.java.archives.Manifest from(Object mergePath, + Action action) { + throw new UnsupportedOperationException("read-only manifest"); + } + } } diff --git a/gradle-plugins/biz.aQute.bnd.gradle/src/test/groovy/aQute/bnd/gradle/TestBndPlugin.groovy b/gradle-plugins/biz.aQute.bnd.gradle/src/test/groovy/aQute/bnd/gradle/TestBndPlugin.groovy index 8f33647bff..158e379d0d 100644 --- a/gradle-plugins/biz.aQute.bnd.gradle/src/test/groovy/aQute/bnd/gradle/TestBndPlugin.groovy +++ b/gradle-plugins/biz.aQute.bnd.gradle/src/test/groovy/aQute/bnd/gradle/TestBndPlugin.groovy @@ -522,7 +522,12 @@ class TestBndPlugin extends Specification { assert testProjectDir.isDirectory() when: "the configuration cache is requested" - // The BuildFeatures service used for the fail fast check requires Gradle 8.5 + // "8.5" is a floor, not a pin: TestHelper.getGradleRunner(version) + // runs with max(version, default version for the current JVM). The + // BuildFeatures service used for the fail fast check was introduced + // in Gradle 8.5, so this test verifies the oldest supported Gradle + // version on JDK 17 while newer JVMs (and --warning-mode=fail runs) + // exercise Gradle 8.10/9.x with the same test. def result = TestHelper.getGradleRunner("8.5") .withProjectDir(testProjectDir) .withArguments("-Pbnd_plugin=${pluginClasspath}", "--configuration-cache", "--stacktrace", ":tasks") diff --git a/gradle-plugins/settings.gradle.kts b/gradle-plugins/settings.gradle.kts index 9baa5e634c..b9c000d849 100644 --- a/gradle-plugins/settings.gradle.kts +++ b/gradle-plugins/settings.gradle.kts @@ -2,6 +2,21 @@ pluginManagement { plugins { id("com.gradle.plugin-publish") version("2.1.1") id("dev.hargrave.addmavendescriptor") version("1.1.0") + id("com.gradle.enterprise") version("3.19.2") + } +} + +plugins { + id("com.gradle.enterprise") +} + +if (System.getenv("CI").toBoolean()) { + gradleEnterprise { + buildScan { + publishAlways() + termsOfServiceUrl = "https://gradle.com/terms-of-service" + termsOfServiceAgree = "yes" + } } } diff --git a/settings.gradle b/settings.gradle index 3f5168bf81..7012c591e9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -4,6 +4,12 @@ import aQute.bnd.osgi.Constants +pluginManagement { + plugins { + id "com.gradle.enterprise" version "3.19.2" + } +} + /* Add bnd gradle plugin as a script dependency */ buildscript { repositories {