From f2681c36b7002820ae576e535f05ee507526034b Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jun 2025 12:24:41 +0100 Subject: [PATCH 1/7] Next development version (v0.0.24-SNAPSHOT) --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 399d82c..c7df331 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=0.0.23-SNAPSHOT +version=0.0.24-SNAPSHOT From d81ba939efa25b20a2013ac783ff3edc6c4bc176 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 26 Jun 2025 09:12:23 +0100 Subject: [PATCH 2/7] Enable CodeQL Analysis of GitHub Actions workflows --- .github/workflows/build-and-deploy-snapshot.yml | 2 ++ .github/workflows/release.yml | 2 ++ .github/workflows/run-codeql-analysis.yml | 15 +++++++++++++++ .github/workflows/validate-gradle-wrapper.yml | 3 ++- 4 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/run-codeql-analysis.yml diff --git a/.github/workflows/build-and-deploy-snapshot.yml b/.github/workflows/build-and-deploy-snapshot.yml index 7dacedd..14ae518 100644 --- a/.github/workflows/build-and-deploy-snapshot.yml +++ b/.github/workflows/build-and-deploy-snapshot.yml @@ -3,6 +3,8 @@ on: push: branches: - main +permissions: + contents: read concurrency: group: ${{ github.workflow }}-${{ github.ref }} jobs: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8024ee7..606d6f5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,6 +3,8 @@ on: push: tags: - v[0-9]+.[0-9]+.[0-9]+ +permissions: + contents: read concurrency: group: ${{ github.workflow }}-${{ github.ref }} jobs: diff --git a/.github/workflows/run-codeql-analysis.yml b/.github/workflows/run-codeql-analysis.yml new file mode 100644 index 0000000..377918a --- /dev/null +++ b/.github/workflows/run-codeql-analysis.yml @@ -0,0 +1,15 @@ +name: "Run CodeQL Analysis" +on: + push: + pull_request: + workflow_dispatch: + schedule: + - cron: '45 0 * * 1' +permissions: read-all +jobs: + run-analysis: + permissions: + actions: read + contents: read + security-events: write + uses: spring-io/github-actions/.github/workflows/codeql-analysis.yml@6e66995f7d29de1e4ff76e4f0def7a10163fe910 diff --git a/.github/workflows/validate-gradle-wrapper.yml b/.github/workflows/validate-gradle-wrapper.yml index aecafd2..d8c184a 100644 --- a/.github/workflows/validate-gradle-wrapper.yml +++ b/.github/workflows/validate-gradle-wrapper.yml @@ -1,6 +1,7 @@ name: "Validate Gradle Wrapper" on: [push, pull_request] - +permissions: + contents: read jobs: validate-gradle-wrapper: name: Validate Gradle wrapper From f00d365a8a9516d2eba597d01f1fe585190033d0 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 18 Jul 2025 10:45:38 +0100 Subject: [PATCH 3/7] Detect toolchainVersion when it is set in gradle.properties Closes gh-100 --- README.md | 2 +- .../gradle/DevelocityConventionsPlugin.java | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 6ac9651..fd95add 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ The build scans will be customized to: - Add tags: - `JDK-`. When using Maven, `` is the specification version of the JDK running the build. - When using Gradle, `` is the value of the `toolchainVersion` project property or, when not set, it's the specification version of the JDK running the build. + When using Gradle, `` is the value of the `toolchainVersion` property or, when not set, it's the specification version of the JDK running the build. - `CI` or `Local` depending on where the build is executing. - `dirty` if the git working copy is dirty. - Name of the git branch being built. diff --git a/develocity-conventions-gradle-plugin/src/main/java/io/spring/develocity/conventions/gradle/DevelocityConventionsPlugin.java b/develocity-conventions-gradle-plugin/src/main/java/io/spring/develocity/conventions/gradle/DevelocityConventionsPlugin.java index f813b8b..519c67e 100644 --- a/develocity-conventions-gradle-plugin/src/main/java/io/spring/develocity/conventions/gradle/DevelocityConventionsPlugin.java +++ b/develocity-conventions-gradle-plugin/src/main/java/io/spring/develocity/conventions/gradle/DevelocityConventionsPlugin.java @@ -34,6 +34,7 @@ import org.gradle.api.Plugin; import org.gradle.api.initialization.Settings; import org.gradle.api.internal.ProcessOperations; +import org.gradle.api.provider.Provider; /** * {@link Plugin plugin} for configuring the use of Develocity hosted at @@ -60,8 +61,7 @@ public void apply(Settings settings) { return; } if (isBuildScanEnabled(settings)) { - configureBuildScanConventions(extension, extension.getBuildScan(), settings.getStartParameter(), - settings.getRootDir()); + configureBuildScanConventions(extension, extension.getBuildScan(), settings); } if (settings.getStartParameter().isBuildCacheEnabled()) { settings.buildCache((buildCacheConfiguration) -> new BuildCacheConventions() @@ -99,16 +99,16 @@ private boolean containsPropertiesTask(StartParameter startParameter) { } private void configureBuildScanConventions(DevelocityConfiguration develocity, BuildScanConfiguration buildScan, - StartParameter startParameter, File rootDir) { + Settings settings) { + Provider toolchainVersion = settings.getProviders().gradleProperty("toolchainVersion"); ProcessOperationsProcessRunner processRunner = new ProcessOperationsProcessRunner( - new WorkingDirectoryProcessOperations(this.processOperations, rootDir)); - if (startParameter.isBuildScan()) { + new WorkingDirectoryProcessOperations(this.processOperations, settings.getRootDir())); + if (settings.getStartParameter().isBuildScan()) { new AnonymousPublicationBuildScanConventions(processRunner) { @Override protected String getJdkVersion() { - String toolchainVersion = startParameter.getProjectProperties().get("toolchainVersion"); - return (toolchainVersion != null) ? toolchainVersion : super.getJdkVersion(); + return toolchainVersion.getOrElse(super.getJdkVersion()); } }.execute(new GradleConfigurableDevelocity(develocity), new GradleConfigurableBuildScan(buildScan)); @@ -118,8 +118,7 @@ protected String getJdkVersion() { @Override protected String getJdkVersion() { - String toolchainVersion = startParameter.getProjectProperties().get("toolchainVersion"); - return (toolchainVersion != null) ? toolchainVersion : super.getJdkVersion(); + return toolchainVersion.getOrElse(super.getJdkVersion()); } }.execute(new GradleConfigurableDevelocity(develocity), new GradleConfigurableBuildScan(buildScan)); From c1272425b4691d2fc037017ee2829e977348cb38 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 18 Jul 2025 11:33:55 +0100 Subject: [PATCH 4/7] Upgrade to Develocity Plugin 4.0.2 Closes gh-101 --- README.md | 1 + .../build.gradle | 2 +- .../gradle/DevelocityConventionsPlugin.java | 18 +++++ ...cityConventionsPluginIntegrationTests.java | 65 ++++++++++++------- .../gradle/TestDevelocityConfiguration.java | 8 ++- 5 files changed, 69 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index fd95add..3223825 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ To work around this, an environment variable named `BRANCH` can be set on the ta ### Anonymous publication When using Gradle, build scans can be published anonymously to scans.gradle.com by running the build with `--scan`. +This requires Gradle 8.8 or later. ## Authentication diff --git a/develocity-conventions-gradle-plugin/build.gradle b/develocity-conventions-gradle-plugin/build.gradle index 31e7e37..cd9b20b 100644 --- a/develocity-conventions-gradle-plugin/build.gradle +++ b/develocity-conventions-gradle-plugin/build.gradle @@ -13,7 +13,7 @@ repositories { dependencies { implementation(project(":develocity-conventions-core")) - implementation("com.gradle:develocity-gradle-plugin:3.19.2") + implementation("com.gradle:develocity-gradle-plugin:4.0.2") testImplementation("org.assertj:assertj-core:3.27.2") testImplementation("org.junit.jupiter:junit-jupiter:5.13.0") diff --git a/develocity-conventions-gradle-plugin/src/main/java/io/spring/develocity/conventions/gradle/DevelocityConventionsPlugin.java b/develocity-conventions-gradle-plugin/src/main/java/io/spring/develocity/conventions/gradle/DevelocityConventionsPlugin.java index 519c67e..338ec4c 100644 --- a/develocity-conventions-gradle-plugin/src/main/java/io/spring/develocity/conventions/gradle/DevelocityConventionsPlugin.java +++ b/develocity-conventions-gradle-plugin/src/main/java/io/spring/develocity/conventions/gradle/DevelocityConventionsPlugin.java @@ -35,6 +35,9 @@ import org.gradle.api.initialization.Settings; import org.gradle.api.internal.ProcessOperations; import org.gradle.api.provider.Provider; +import org.gradle.util.GradleVersion; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * {@link Plugin plugin} for configuring the use of Develocity hosted at @@ -44,6 +47,8 @@ */ public class DevelocityConventionsPlugin implements Plugin { + private final Logger log = LoggerFactory.getLogger(DevelocityConventionsPlugin.class); + private final ProcessOperations processOperations; @Inject @@ -53,6 +58,11 @@ public DevelocityConventionsPlugin(ProcessOperations processOperations) { @Override public void apply(Settings settings) { + if (buildScanRequested(settings) && gradleVersionIsLessThanEightEight()) { + this.log.warn("Develocity conventions disabled. Using --scan requires Gradle 8.8 or later. " + + "Current Gradle version is " + GradleVersion.current().getVersion()); + return; + } settings.getPlugins().apply(DevelocityPlugin.class); DevelocityConfiguration extension = settings.getExtensions().getByType(DevelocityConfiguration.class); if (!isOssBuild(settings)) { @@ -69,6 +79,14 @@ public void apply(Settings settings) { } } + private boolean buildScanRequested(Settings settings) { + return settings.getStartParameter().isBuildScan(); + } + + private boolean gradleVersionIsLessThanEightEight() { + return GradleVersion.version("8.8").compareTo(GradleVersion.current()) > 0; + } + private boolean isOssBuild(Settings settings) { Properties properties = new Properties(); File propertiesFile = new File(settings.getRootDir(), "gradle.properties"); diff --git a/develocity-conventions-gradle-plugin/src/test/java/io/spring/develocity/conventions/gradle/DevelocityConventionsPluginIntegrationTests.java b/develocity-conventions-gradle-plugin/src/test/java/io/spring/develocity/conventions/gradle/DevelocityConventionsPluginIntegrationTests.java index bbd86f9..8c93004 100644 --- a/develocity-conventions-gradle-plugin/src/test/java/io/spring/develocity/conventions/gradle/DevelocityConventionsPluginIntegrationTests.java +++ b/develocity-conventions-gradle-plugin/src/test/java/io/spring/develocity/conventions/gradle/DevelocityConventionsPluginIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2024 the original author or authors. + * Copyright 2020-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -48,8 +48,8 @@ class DevelocityConventionsPluginIntegrationTests { void whenThePluginIsAppliedThenBuildScanConventionsAreApplied(@TempDir File projectDir) { prepareProject(projectDir); BuildResult result = build(projectDir, "verifyBuildScanConfig"); - assertThat(result.getOutput()).contains("Build scan server: https://ge.spring.io"); - assertThat(result.getOutput()).contains("Capture task input files: true"); + assertThat(result.getOutput()).contains("Develocity server: https://ge.spring.io"); + assertThat(result.getOutput()).contains("Capture file fingerprints: true"); } @Test @@ -63,8 +63,8 @@ void whenThePluginIsAppliedThenBuildCacheConventionsAreApplied(@TempDir File pro void whenThePluginIsAppliedAndBuildScansAreDisabledThenBuildScanConventionsAreNotApplied(@TempDir File projectDir) { prepareProject(projectDir); BuildResult result = build(projectDir, "verifyBuildScanConfig", "--no-scan"); - assertThat(result.getOutput()).contains("Build scan server: null"); - assertThat(result.getOutput()).contains("Capture task input files: false"); + assertThat(result.getOutput()).contains("Develocity server: null"); + assertThat(result.getOutput()).contains("Capture file fingerprints: false"); } @Test @@ -73,8 +73,8 @@ void whenThePluginIsAppliedAndTheSpringBuildTypeIsNotOssThenBuildScanConventions prepareProject(projectDir); write(new File(projectDir, "gradle.properties"), (writer) -> writer.println("spring.build-type=other")); BuildResult result = build(projectDir, "verifyBuildScanConfig"); - assertThat(result.getOutput()).contains("Build scan server: null"); - assertThat(result.getOutput()).contains("Capture task input files: false"); + assertThat(result.getOutput()).contains("Develocity server: null"); + assertThat(result.getOutput()).contains("Capture file fingerprints: false"); } @Test @@ -82,8 +82,8 @@ void whenThePluginIsAppliedAndTheSpringBuildTypeIsOssThenBuildScanConventionsAre prepareProject(projectDir); write(new File(projectDir, "gradle.properties"), (writer) -> writer.println("spring.build-type=oss")); BuildResult result = build(projectDir, "verifyBuildScanConfig"); - assertThat(result.getOutput()).contains("Build scan server: https://ge.spring.io"); - assertThat(result.getOutput()).contains("Capture task input files: true"); + assertThat(result.getOutput()).contains("Develocity server: https://ge.spring.io"); + assertThat(result.getOutput()).contains("Capture file fingerprints: true"); } @Test @@ -91,8 +91,8 @@ void whenThePluginIsAppliedAndPropertiesTaskIsExecutedThenBuildScanConventionsAr @TempDir File projectDir) { prepareProject(projectDir); BuildResult result = build(projectDir, "properties", "verifyBuildScanConfig", "--no-scan"); - assertThat(result.getOutput()).contains("Build scan server: null"); - assertThat(result.getOutput()).contains("Capture task input files: false"); + assertThat(result.getOutput()).contains("Develocity server: null"); + assertThat(result.getOutput()).contains("Capture file fingerprints: false"); } @Test @@ -100,16 +100,26 @@ void givenMultiProjectBuildWhenThePluginIsAppliedAndPropertiesTaskIsExecutedThen @TempDir File projectDir) { prepareMultiModuleProject(projectDir); BuildResult result = build(projectDir, "sub:properties", "sub:verifyBuildScanConfig", "--no-scan"); - assertThat(result.getOutput()).contains("Build scan server: null"); - assertThat(result.getOutput()).contains("Capture task input files: false"); + assertThat(result.getOutput()).contains("Develocity server: null"); + assertThat(result.getOutput()).contains("Capture file fingerprints: false"); } @Test - void whenThePluginIsAppliedAndScanIsSpecifiedThenServerIsNotCustomized(@TempDir File projectDir) { + void whenThePluginIsAppliedAndScanIsSpecifiedItBacksOff(@TempDir File projectDir) { prepareProject(projectDir); - BuildResult result = build(projectDir, "verifyBuildScanConfig", "--scan"); - assertThat(result.getOutput()).contains("Build scan server: null"); - assertThat(result.getOutput()).contains("Capture task input files: true"); + BuildResult result = build(projectDir, "--scan"); + assertThat(result.getOutput()) + .contains("Develocity conventions disabled. Using --scan requires Gradle 8.8 or later. " + + "Current Gradle version is 7.4.2"); + } + + @Test + void whenThePluginIsAppliedAndScanIsSpecifiedWithGradleEightEightServerIsNotCustomized(@TempDir File projectDir) { + prepareProject(projectDir); + BuildResult result = build( + prepareBuild(projectDir, "verifyBuildScanConfig", "--scan").withGradleVersion("8.8")); + assertThat(result.getOutput()).contains("Develocity server: null"); + assertThat(result.getOutput()).contains("Capture file fingerprints: true"); } @Test @@ -147,8 +157,9 @@ private void prepareProject(File projectDir) { write(new File(projectDir, "build.gradle"), (writer) -> { writer.println("task verifyBuildScanConfig {"); writer.println(" doFirst {"); - writer.println(" println \"Build scan server: ${buildScan.server}\""); - writer.println(" println \"Capture task input files: ${buildScan.captureTaskInputFiles}\""); + writer.println(" println \"Develocity server: ${develocity.server.getOrElse(null)}\""); + writer.println(" def fileFingerprints = develocity.buildScan.capture.fileFingerprints"); + writer.println(" println \"Capture file fingerprints: ${fileFingerprints.getOrElse(false)}\""); writer.println(" }"); writer.println("}"); writer.println("task verifyBuildCacheConfig {"); @@ -172,8 +183,9 @@ private void prepareMultiModuleProject(File projectDir) { write(new File(new File(projectDir, "sub"), "build.gradle"), (writer) -> { writer.println("task verifyBuildScanConfig {"); writer.println(" doFirst {"); - writer.println(" println \"Build scan server: ${buildScan.server}\""); - writer.println(" println \"Capture task input files: ${buildScan.captureTaskInputFiles}\""); + writer.println(" println \"Develocity server: ${develocity.server.getOrElse(null)}\""); + writer.println(" def fileFingerprints = develocity.buildScan.capture.fileFingerprints"); + writer.println(" println \"Capture file fingerprints: ${fileFingerprints.getOrElse(false)}\""); writer.println(" }"); writer.println("}"); writer.println("task verifyBuildCacheConfig {"); @@ -207,6 +219,10 @@ private String version() { } private BuildResult build(File projectDir, String... arguments) { + return build(prepareBuild(projectDir, arguments)); + } + + private GradleRunner prepareBuild(File projectDir, String... arguments) { List classpath = Arrays.asList(new File("bin/main"), new File("build/classes/java/main"), new File("build/resources/main"), new File(DevelocityPlugin.class.getProtectionDomain().getCodeSource().getLocation().getFile()), @@ -216,8 +232,11 @@ private BuildResult build(File projectDir, String... arguments) { return GradleRunner.create() .withProjectDir(projectDir) .withPluginClasspath(classpath) - .withArguments(augmentedArguments) - .build(); + .withArguments(augmentedArguments); + } + + private BuildResult build(GradleRunner runner) { + return runner.build(); } } diff --git a/develocity-conventions-gradle-plugin/src/test/java/io/spring/develocity/conventions/gradle/TestDevelocityConfiguration.java b/develocity-conventions-gradle-plugin/src/test/java/io/spring/develocity/conventions/gradle/TestDevelocityConfiguration.java index f025d15..12f495e 100644 --- a/develocity-conventions-gradle-plugin/src/test/java/io/spring/develocity/conventions/gradle/TestDevelocityConfiguration.java +++ b/develocity-conventions-gradle-plugin/src/test/java/io/spring/develocity/conventions/gradle/TestDevelocityConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2024 the original author or authors. + * Copyright 2020-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ import com.gradle.develocity.agent.gradle.DevelocityConfiguration; import com.gradle.develocity.agent.gradle.buildcache.DevelocityBuildCache; +import com.gradle.develocity.agent.gradle.integration.DevelocityIntegrationConfiguration; import com.gradle.develocity.agent.gradle.scan.BuildScanConfiguration; import org.gradle.api.Action; import org.gradle.api.provider.Property; @@ -72,4 +73,9 @@ public Property getEdgeDiscovery() { throw new UnsupportedOperationException(); } + @Override + public DevelocityIntegrationConfiguration getIntegration() { + throw new UnsupportedOperationException(); + } + } From 93d9b3410fc5200d22eef06141b0a5fee8f2c19d Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 21 Jul 2025 09:29:23 +0100 Subject: [PATCH 5/7] Upgrade to Develocity Maven Extension 2.0.1 Closes gh-102 --- develocity-conventions-maven-extension/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/develocity-conventions-maven-extension/build.gradle b/develocity-conventions-maven-extension/build.gradle index 1ee2161..dec6efd 100644 --- a/develocity-conventions-maven-extension/build.gradle +++ b/develocity-conventions-maven-extension/build.gradle @@ -14,7 +14,7 @@ dependencies { compileOnly("org.apache.maven:maven-core:3.6.3") compileOnly("org.codehaus.plexus:plexus-component-annotations:1.7.1") - implementation("com.gradle:develocity-maven-extension:1.23.2") + implementation("com.gradle:develocity-maven-extension:2.0.1") implementation(project(":develocity-conventions-core")) testImplementation("org.assertj:assertj-core:3.27.2") From 0cdd91dfeb8b1c44bb5965b8c426406ed16ccd3e Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 21 Jul 2025 09:47:06 +0100 Subject: [PATCH 6/7] Use new portal to publish to Maven Central Closes gh-103 --- .github/workflows/release.yml | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 606d6f5..812f80d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -70,16 +70,10 @@ jobs: - name: Download release artifacts run: jf rt download --spec .github/release-artifacts.spec --spec-vars 'buildName=${{ format('develocity-conventions-{0}', needs.get-version.outputs.version) }};buildNumber=${{ github.run_number }}' - name: Sync - uses: spring-io/nexus-sync-action@42477a2230a2f694f9eaa4643fa9e76b99b7ab84 # v0.0.1 + uses: spring-io/central-publish-action@0cdd90d12e6876341e82860d951e1bcddc1e51b6 # v0.2.0 with: - username: ${{ secrets.OSSRH_S01_TOKEN_USERNAME }} - password: ${{ secrets.OSSRH_S01_TOKEN_PASSWORD }} - staging-profile-name: ${{ secrets.OSSRH_S01_STAGING_PROFILE_NAME }} - create: true - upload: true - close: true - release: true - generate-checksums: true + token: ${{ secrets.CENTRAL_TOKEN_PASSWORD }} + token-name: ${{ secrets.CENTRAL_TOKEN_USERNAME }} - name: Await shell: bash run: | From 8e0654469d30ba03d9339147a9254a748c990136 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 21 Jul 2025 09:38:31 +0100 Subject: [PATCH 7/7] Release v0.0.24 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index c7df331..d1bbaca 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=0.0.24-SNAPSHOT +version=0.0.24