Upgrade to Gradle 9.4.1 and Micronaut 4#15365
Conversation
- Update Gradle wrapper to 9.3.1 across grails-core, grails-gradle, build-logic, and profiles - Migrate Groovy dependencies from org.codehaus.groovy to org.apache.groovy (Groovy 4+) - Update Spock version for grails-gradle tests to 2.3-groovy-4.0 - Add explicit groovy.ant.AntBuilder import (moved in Groovy 4) - Make task classes abstract for Gradle 9 compatibility (JavaExec, AbstractCompile) - Add @Inject annotation to task constructors where required - Fix documentation configuration attributes for groovydoc tasks - Update IOUtilsSpec test expectation for Groovy 4 Spock jar name Note: grails-forge remains on Gradle 8.x pending Micronaut 4 upgrade
- Upgrade Micronaut from 3.10.4 to 4.10.7 - Upgrade Groovy from 3.x to 4.0.30 - Upgrade Spock from 2.1-groovy-3.0 to 2.3-groovy-4.0 - Migrate javax.* to jakarta.* validation annotations - Update dependency coordinates from org.codehaus.groovy to org.apache.groovy - Update micronaut-bom to micronaut-platform - Add micronaut-validation-processor for annotation processing - Add micronaut-jackson-databind runtime dependency - Fix deprecated Gradle APIs (conventions -> extensions) - Add ByteBuddy for Spock mocking on Java 17+ - Add JUnit Platform launcher for Gradle 9 test execution - Remove shadow plugin (now provided by micronaut-application plugin)
|
@jamesfredley did Gradle 9 not remove the testClassDir as they said they would? It was my understanding the integration plugin + TCK had to be rewritten similar to the grails-publish project to work. |
|
Replace artifacts { archives ... } with direct task dependencies on
assemble task as recommended by Gradle 9 deprecation warnings.
The remaining StartParameter.isConfigurationCacheRequested deprecation
is from the Asciidoctor Gradle plugin (grolifant library) and cannot
be fixed in this project.
There was a problem hiding this comment.
Pull request overview
Upgrades the build/tooling stack to Gradle 9.3.1 and updates the grails-forge module family to Micronaut 4 / Groovy 4 / Spock 2.3, including related Gradle API migrations and test-runtime adjustments.
Changes:
- Bump Gradle wrapper/tooling versions to 9.3.1 across the repo and update Gradle plugin/task implementations for Gradle 9 APIs.
- Upgrade
grails-forgeto Micronaut 4 (Groovy 4, Spock 2.3) and migratejavax.*validation/transaction usage tojakarta.*. - Update test infrastructure for Gradle 9 / Java 17+ (JUnit Platform launcher, Byte Buddy, and JVM
--add-opens).
Reviewed changes
Copilot reviewed 55 out of 55 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| grails-profiles/profile/skeleton/gradle/wrapper/gradle-wrapper.properties | Update profile skeleton Gradle wrapper to 9.3.1 |
| grails-profiles/base/skeleton/gradle/wrapper/gradle-wrapper.properties | Update base skeleton Gradle wrapper to 9.3.1 |
| grails-gradle/plugins/src/main/groovy/org/grails/gradle/plugin/views/markup/MarkupViewCompilerTask.groovy | Make task type abstract for Gradle 9 task instantiation model |
| grails-gradle/plugins/src/main/groovy/org/grails/gradle/plugin/views/json/GsonViewCompilerTask.groovy | Make task type abstract for Gradle 9 task instantiation model |
| grails-gradle/plugins/src/main/groovy/org/grails/gradle/plugin/run/GrailsRunTask.groovy | Make task type abstract for Gradle 9 task instantiation model |
| grails-gradle/plugins/src/main/groovy/org/grails/gradle/plugin/profiles/tasks/ProfileCompilerTask.groovy | Make task type abstract for Gradle 9 task instantiation model |
| grails-gradle/plugins/src/main/groovy/org/grails/gradle/plugin/commands/ApplicationContextScriptTask.groovy | Make task abstract and add @Inject constructor for Gradle services |
| grails-gradle/plugins/src/main/groovy/org/grails/gradle/plugin/commands/ApplicationContextCommandTask.groovy | Make task abstract and add @Inject constructor for Gradle services |
| grails-gradle/plugins/build.gradle | Switch Groovy dependency coordinates to org.apache.groovy |
| grails-gradle/model/src/test/groovy/grails/io/IOUtilsSpec.groovy | Update test expectation for Spock Groovy 4 artifact name |
| grails-gradle/model/build.gradle | Switch Groovy deps to org.apache.groovy coordinates (including tests) |
| grails-gradle/gradle/wrapper/gradle-wrapper.properties | Update Gradle wrapper to 9.3.1 |
| grails-gradle/common/build.gradle | Switch Groovy deps to org.apache.groovy coordinates (including tests) |
| grails-gradle/bom/build.gradle | Use Gradle-embedded Groovy BOM via org.apache.groovy:groovy-bom |
| grails-forge/test-core/build.gradle | Switch Groovy dependency coordinates to org.apache.groovy |
| grails-forge/grails-forge-web-netty/build.gradle | Remove explicit Shadow plugin; add Micronaut Jackson databind runtime dep |
| grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/GitHubUtil.java | Migrate validation annotations to jakarta.validation |
| grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/templates/gradleWrapperProperties.rocker.raw | Update generated wrapper template to Gradle 9.3.1 |
| grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/oauth/AccessToken.java | Migrate validation annotations to jakarta.validation |
| grails-forge/grails-forge-core/build.gradle | Switch to Micronaut platform BOM; update Groovy coords; add validation/Jackson APIs |
| grails-forge/grails-forge-cli/build.gradle | Switch to Micronaut platform BOM; update Groovy coords and resolution strategy |
| grails-forge/grails-forge-api/src/test/groovy/org/grails/forge/api/DiffClient.groovy | Migrate validation annotations to jakarta.validation |
| grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/diff/DiffOperations.java | Migrate validation annotations to jakarta.validation |
| grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/diff/DiffController.java | Migrate validation annotations to jakarta.validation |
| grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/zip/ZipCreateOperation.java | Migrate validation annotations to jakarta.validation |
| grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/zip/ZipCreateController.java | Add @Validated; migrate validation annotations to jakarta.validation |
| grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubRedirectService.java | Migrate validation annotations to jakarta.validation |
| grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubCreateService.java | Migrate validation annotations to jakarta.validation |
| grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubCreateOperation.java | Migrate validation annotations to jakarta.validation |
| grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubCreateController.java | Migrate validation annotations to jakarta.validation |
| grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/AbstractCreateController.java | Migrate validation annotations to jakarta.validation |
| grails-forge/grails-forge-api/build.gradle | Switch to Micronaut platform BOM; add validation processor; jakarta inject; Jackson runtime |
| grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/Application.java | Migrate validation annotations to jakarta.validation |
| grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/AnalyticsController.java | Migrate transactions to jakarta.transaction |
| grails-forge/grails-forge-analytics-postgres/build.gradle | Remove explicit Shadow plugin; add Micronaut Jackson databind runtime dep |
| grails-forge/gradle/wrapper/gradle-wrapper.properties | Update Gradle wrapper to 9.3.1 |
| grails-forge/gradle/test-config.gradle | Add Gradle 9 test runtime deps + JVM args for Java 17+ |
| grails-forge/gradle/micronaut-openapi-config.gradle | Replace deprecated WriteProperties.outputFile with destinationFile |
| grails-forge/gradle/doc-config.gradle | Switch Groovy documentation deps to org.apache.groovy |
| grails-forge/gradle.properties | Bump Micronaut/Groovy/Spock versions; add Byte Buddy version; update Jakarta inject version |
| grails-forge/buildSrc/src/main/java/org/grails/forge/rocker/plugin/RockerSourceSetProperty.java | Replace deprecated Gradle configure util; add DSL delegation helpers |
| grails-forge/buildSrc/src/main/java/org/grails/forge/rocker/plugin/RockerPlugin.java | Replace deprecated convention/DSL object usage with JavaPluginExtension + ExtensionAware |
| grails-data-neo4j/docs/build.gradle | Update docs configuration attributes + switch Groovy coords to org.apache.groovy |
| grails-data-mongodb/docs/build.gradle | Update docs configuration attributes for Gradle 9 variant-aware resolution |
| grails-data-hibernate5/docs/build.gradle | Update docs configuration attributes for Gradle 9 variant-aware resolution |
| gradle/wrapper/gradle-wrapper.properties | Update root Gradle wrapper to 9.3.1 |
| gradle.properties | Bump gradleToolingApiVersion to 9.3.1 |
| dependencies.gradle | Bump gradle-spock BOM version to Groovy 4 compatible variant |
| build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/SbomPlugin.groovy | Add license mapping for Coherence BOM 25.03.2 |
| build-logic/gradle/wrapper/gradle-wrapper.properties | Update build-logic Gradle wrapper to 9.3.1 |
| build-logic/docs-core/src/main/groovy/grails/doc/ant/DocPublisherTask.groovy | Add missing AntBuilder import for Groovy/Gradle compatibility |
| build-logic/docs-core/build.gradle | Switch Groovy coords to org.apache.groovy and update Groovy test artifact |
| .sdkmanrc | Update SDKMAN Gradle version to 9.3.1 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Update asciidoctor plugin version for consistency across modules. Note: The StartParameter.isConfigurationCacheRequested deprecation warning remains as it's caused by the grolifant library used by asciidoctor-gradle-plugin. This will be fixed in version 5.0.0 (currently in alpha) which upgrades to Grolifant 5.
|
|
I did not touch SBOM in this PR. Grails BOM Dependencies still generates during grails-doc build. |
Fix CodeNarc violations by removing unused Gradle API imports that were left over from refactoring.
|
asciidoctor still results in a deprecation warning, which will be resolved in 5 https://github.com/asciidoctor/asciidoctor-gradle-plugin/releases |
Add explicit dependency on groovydoc task from dist task to satisfy Gradle 9's stricter validation of implicit task dependencies. The dist task uses outputDir (build/docs) which includes the output from the groovydoc task (build/docs/groovydoc), so an explicit dependency is required.
|
All the BOM and build-logic plugins are working correctly:
|
|
The reports in those other tickets claim that they execute but the wrong datasets are returned with gradle 9. I would suggest diffing the output of those files and clearing any local cache before calling this a victory. |
|
grails-bom and /ref/Versions/Grails%20BOM.html have the correct dependencies and versions. |
- Update com.gradle.develocity from 4.1.1 to 4.3.2 (latest compatible with Develocity 2025.4.2) - Update com.gradle.common-custom-user-data-gradle-plugin from 2.3 to 2.4.0 - Migrate grails-data-neo4j and grails-data-graphql from deprecated gradle-enterprise plugin to develocity - Add reproducible build configuration to grails-data-neo4j and grails-data-graphql settings - Add comment documenting known Asciidoctor plugin deprecation (StartParameter.isConfigurationCacheRequested)
Fix deprecated Task.project access at execution time (scheduled for removal in Gradle 10) by capturing project properties at configuration time. Changes: - SbomPlugin: Capture projectName, projectPath, and buildDate at configuration time; refactor pickLicense() to accept these values instead of task reference - PublishPlugin: Capture PublishingExtension at configuration time before doLast block - GrailsGradlePlugin: Capture buildDir at configuration time for buildProperties task; capture antBuilder at configuration time for native2ascii task - GrailsProfileGradlePlugin: Replace project.sync in doLast with Sync task type Tested output before/after changes: - cyclonedxBom: Identical (except expected timestamp/UUID differences) - savePublishedArtifacts: Identical - processProfileResources: Identical - buildProperties: Functionally identical (minor formatting: one less blank line) - grails-doc docs: Identical (verified Grails BOM.html)
3d4c6ea to
480ad17
Compare
Replace deprecated leftShift operator (<<) with modern tasks.register and doLast syntax for Gradle 9+ compatibility.
Update gradle-wrapper.jar, gradlew, and gradlew.bat across all locations: - Main project (gradle/) - build-logic/ - grails-gradle/ - grails-forge/ - grails-forge/grails-forge-core/src/main/resources/gradle/ (template) - grails-profiles/base/skeleton/ (template) - grails-profiles/profile/skeleton/ (template) - grails-shell-cli/src/test/resources/gradle-sample/
|
Companion PR for the Gradle 9.4.1 upgrade in |
…ublish plugin bump Review feedback from #15365: * OpenTelemetry version (replace BOM import with explicit constraints): Selenium 4.41+ needs OpenTelemetry 1.59+, which is newer than the 1.55.x that Spring Boot 4.0.5 manages. The previous fix relied on importing the opentelemetry-bom AFTER the spring-boot-bom so ordering would favour the newer version, but BOM import order is not guaranteed by Gradle or Maven resolution (same class of issue as the hibernate PR). Replace the BOM import with an explicit list of opentelemetry module constraints in the grails-bom constraints block; explicit constraints always win over any imported BOM's transitively-managed version, regardless of ordering. * grails-publish 0.0.4 -> 1.0.0-SNAPSHOT: adopt the Gradle 9 / Java 21 compatible build of the publish plugin. Add the apache snapshots repo to root, grails-gradle, and grails-gradle/buildSrc pluginManagement blocks so the composite build classpath resolves the snapshot before the org.apache.grails.buildsrc.repo settings plugin itself is available. * grails-forge: bump groovyVersion 4.0.30 -> 4.0.31 to match grails-core; drop ':$micronautVersion' suffix from micronaut-inject-groovy references in grails-forge-api, grails-forge-cli, grails-forge-core, grails-forge- web-netty, grails-forge-analytics-postgres, and test-core so the micronaut-platform BOM (already applied in each file) manages the version. Apply the micronaut-platform BOM in test-core which was using direct versions only. * grails-forge-web-netty: runtimeOnly io.micronaut:micronaut-jackson- databind -> io.micronaut.serde:micronaut-serde-jackson. The forge stack is a Micronaut 4 serde-jackson application; the legacy jackson-databind runtime was a copy-paste from an earlier generator template. * grails-test-examples-micronaut: import the micronaut-platform BOM and drop the per-artifact micronautHttpClientVersion / micronautSerde- JacksonVersion references. Delete the now-unused properties from the root gradle.properties. * grails-bom/build.gradle: drop the java-platform plugin guard on the extractConstraints task. The task is only consumed internally, so the external-use guard no longer needs to exist. * grails-doc/build.gradle: disable the per-project groovydoc' task instead of adding a dependency from dist'. grails-doc has no real source to document - the groovy plugin is only applied for version resolution, so the default groovydoc output is empty/unused. The user- facing groovydoc is produced by the aggregateGroovydoc task, which is already wired into the docs task. * Drop grails-doc/src/en/ref/Configuration/Application Properties.adoc. This 866-line new documentation file is unrelated to the Gradle 9 / Micronaut 4 upgrade and will be submitted separately. Assisted-by: claude-code:claude-opus-4-7
# Conflicts: # dependencies.gradle
|
Related #15597 |
Round of review feedback addressedTelemetry override (your top-level comment): swapped the
Inline review threads (all 20 resolved): see individual replies on each thread. Every prior unresolved item is now either confirmed already in place or fixed in the new commit:
Latest 8.0.x merged in: picked up the Jansi/JLine upgrade (#15367), forge GraalVM image fixes (#15579, #15580), pull request template, and 7.1.0 release. One conflict in Locally verified |
… reference Two follow-up CI issues from the previous review-feedback commit: * Add the apache snapshots repo to the pluginManagement blocks in buildSrc/settings.gradle, grails-forge/settings.gradle, and grails- forge/buildSrc/settings.gradle. Same chicken-and-egg pattern as the root and grails-gradle settings - the org.apache.grails.buildsrc.repo plugin cannot register the snapshot repo until its own classpath (which transitively pulls grails-publish:1.0.0-SNAPSHOT) has been resolved. * grails-gradle/plugins/build.gradle: org.codehaus.groovy:groovy-test- junit5 -> org.apache.groovy:groovy-test-junit5. The codehaus reference was inherited from the 8.0.x merge (toolchain test rewrite commit fec38f4) and resolves to an empty version because no BOM declares the codehaus coordinates. Verified ./gradlew :grails-bom:extractConstraints :grails-test-examples- scaffolding:validateDependencyVersions still passes locally. Assisted-by: claude-code:claude-opus-4-7
| repositories { | ||
| mavenCentral() | ||
| gradlePluginPortal() | ||
| // Needed to resolve grails-publish snapshots that the build-logic composite |
There was a problem hiding this comment.
We should take #15597 instead of these changes.
There was a problem hiding this comment.
Done in fe527d1. Merged matrei's gradle-plugin-bootstrap branch from #15597 (preserving authorship through the merge commit) and removed the inline pluginManagement.repositories { ... } block I had here. All seven settings files (root, build-logic, buildSrc, grails-forge, grails-forge/buildSrc, grails-gradle, grails-gradle/buildSrc) now route plugin repos through the shared gradle/plugin-repositories.gradle script.
| 'rxjava2.version' : '2.2.21', | ||
| 'rxjava3.version' : '3.1.12', | ||
| 'selenium.version' : '4.38.0', | ||
| 'selenium.version' : '4.41.0', |
There was a problem hiding this comment.
We had pinned selenium to .38 due to the geb issues. Do we know if these are resolved?
There was a problem hiding this comment.
Investigated; resolved in ccafe2b.
Spring Boot 4.0.5's BOM declares selenium 4.37.0 (spring-boot-dependencies 4.0.5). I rolled selenium back from 4.41.0 to 4.37.0 to track Spring Boot's choice. The OpenTelemetry 1.59.0 override and the 24-module constraint list that the 4.41 bump previously required are no longer needed - Spring Boot's managed 1.55.x line is sufficient for selenium 4.37.
Verified:
gradle validateDependencyVersionspasses across all 157 reporting tasks (no resolved-vs-BOM mismatches).gradle :grails-test-examples-{geb,geb-context-path,geb-gebconfig}:compileTestGroovysucceeds.- The geb test apps now resolve
org.seleniumhq.selenium:selenium-bom:4.37.0with no transitive opentelemetry conflict.
Net diff: dependencies.gradle shrinks by 40 lines.
| 'jquery.version' : '3.7.1', | ||
| 'liquibase-hibernate5.version': '4.27.0', | ||
| 'mongodb.version' : '5.6.4', | ||
| // Selenium 4.41+ requires OpenTelemetry 1.59+, which is newer than the |
There was a problem hiding this comment.
Is this upgrade just to prevent conflicts with forge's version of micronaut?
There was a problem hiding this comment.
The opentelemetry pin existed only because selenium 4.41+ pulled in opentelemetry-* modules newer than the 1.55.x line that Spring Boot 4.0.5 manages, which the dependency-version validator flagged. Not related to forge / micronaut.
Now that ccafe2b rolls selenium back to 4.37.0 (Spring Boot's managed version), there is no more transitive conflict and the entire opentelemetry block - the opentelemetry.version constant plus all 24 opentelemetry-* constraints - is gone.
| gradleChecksumPluginVersion=1.4.0 | ||
| # note: the cyclonedx 3 requires Gradle 9 | ||
| gradleCycloneDxPluginVersion=2.4.1 | ||
| # CycloneDX Gradle plugin version |
| it.inputs.dir(src) | ||
| it.outputs.dir(dest) | ||
|
|
||
| // Capture ant builder at configuration time to avoid Task.project access at execution time |
There was a problem hiding this comment.
Let's remove the comment, it's obvious once we're on Gradle 9 why we did this.
There was a problem hiding this comment.
Done in 5d21fc3 (also dropped the second // See: ... doc-link line).
|
|
||
| TaskProvider<Task> processProfileResourcesTask = project.tasks.register('processProfileResources') | ||
| processProfileResourcesTask.configure { Task task -> | ||
| // Use Sync task type instead of project.sync in doLast to avoid Task.project access at execution time |
There was a problem hiding this comment.
Let's remove the comment, it's unnecessary
There was a problem hiding this comment.
Done in 5d21fc3 (also dropped the second // See: ... doc-link line).
| import org.gradle.api.initialization.resolve.RepositoriesMode | ||
|
|
||
| pluginManagement { | ||
| repositories { |
There was a problem hiding this comment.
Done in fe527d1. Merged matrei's gradle-plugin-bootstrap branch from #15597 (preserving authorship through the merge commit) and removed the inline pluginManagement.repositories { ... } block I had here. All seven settings files (root, build-logic, buildSrc, grails-forge, grails-forge/buildSrc, grails-gradle, grails-gradle/buildSrc) now route plugin repos through the shared gradle/plugin-repositories.gradle script.
| // Re-run whenever either compile step emits new metadata; the task mutates files | ||
| // inside the compile output directories so we cannot rely on standard up-to-date | ||
| // tracking. The work is cheap (two small JSON files) so always running is acceptable. | ||
| outputs.upToDateWhen { false } |
There was a problem hiding this comment.
This is the incorrect way to do this. we should be able to cache these merges, otherwise it will always run this in our build.
There was a problem hiding this comment.
Refactored properly in d9a2181.
The merge task now:
- Writes to a new
build/merged-spring-configuration-metadata/directory instead of mutating compile outputs. - Declares
inputs.files(provider { ... })filtered to existing files at execution time, plus anoutputs.file(...)andoutputs.cacheIf { true }so Gradle can cache it. dependsOn compileJava, compileGroovyso the compile output dirs always populate before the merge runs.- The
jartask uses aneachFilefilter to drop the per-compiler copies but keep the merged copy (a globalexcludewould have discarded the merged document too).
Verified:
- A second
gradle :grails-test-examples-plugins-issue-11767:jarinvocation reportscompileJava,compileGroovy,mergeMicronautConfigMetadataandjarall UP-TO-DATE - the always-rerun behavior is gone. - The produced jar contains exactly one
META-INF/spring-configuration-metadata.jsonwith bothPluginJavaMicronautBeanandPluginGroovyMicronautBeanentries merged (groups + properties). - Consumer app (
:grails-test-examples-issue-11767:compileGroovy) still compiles cleanly.
Also dropped the long block comment - the inline 7-line summary above the task is enough.
| import org.gradle.api.initialization.resolve.RepositoriesMode | ||
|
|
||
| pluginManagement { | ||
| repositories { |
There was a problem hiding this comment.
Done in fe527d1. Merged matrei's gradle-plugin-bootstrap branch from #15597 (preserving authorship through the merge commit) and removed the inline pluginManagement.repositories { ... } block I had here. All seven settings files (root, build-logic, buildSrc, grails-forge, grails-forge/buildSrc, grails-gradle, grails-gradle/buildSrc) now route plugin repos through the shared gradle/plugin-repositories.gradle script.
…nt repos Adopt the shared gradle/plugin-repositories.gradle bootstrap script introduced in #15597 (matrei) and remove the inline repositories blocks previously added to settings.gradle, buildSrc/settings.gradle, grails-forge/settings.gradle, grails-forge/buildSrc/settings.gradle, grails-gradle/settings.gradle, and grails-gradle/buildSrc/settings.gradle. All seven settings files now resolve plugin repositories through the same configurePluginRepositories closure, eliminating the copy-paste drift flagged in PR #15365 review (jdaugherty) and gaining the additional repos PR #15365's inline blocks did not cover (mavenLocal env hook, sonatype snapshots for cloud.wondrify.*, ASF staging for grails-publish releases and org.apache.groovy:groovy.*). PR #15597 targets 7.0.x; this merge brings the same fix to 8.0.x while preserving the original commit (Mattias Reichel) so the bootstrap fix is attributed correctly across both branches. Closes gh-15596 Assisted-by: claude-code:claude-opus-4-7
Remove the four comments jdaugherty flagged as restating obvious build mechanics: * gradle.properties: '# CycloneDX Gradle plugin version' above gradleCycloneDxPluginVersion - the property name already states this. * grails-bom/build.gradle (extractConstraints task): comment about capturing services at configuration time - the captureProjectServices call is self-explanatory once the team is on Gradle 9. * GrailsGradlePlugin.createNative2AsciiTask: 'Capture ant builder at configuration time to avoid Task.project access at execution time' plus its config-cache doc URL - obvious once Gradle 9 is the baseline. * GrailsProfileGradlePlugin.processProfileResources: 'Use Sync task type instead of project.sync in doLast to avoid Task.project access at execution time' plus its config-cache doc URL - same rationale. No behavior change. Assisted-by: claude-code:claude-opus-4-7
…anage it
Removes the explicit ':2.0.1' coordinate from the jakarta-inject declarations
in grails-forge-api/build.gradle (api) and grails-forge-cli/build.gradle
(implementation) and deletes jakartaInjectVersion=2.0.1 from
grails-forge/gradle.properties.
Both modules already import the micronaut-platform 4.10.10 BOM via
'platform("io.micronaut.platform:micronaut-platform:$micronautVersion")',
which manages jakarta.inject:jakarta.inject-api transitively through
io.micronaut:micronaut-core:4.10.18 (verified with gradle :grails-forge-api:
dependencies --configuration compileClasspath -> resolves to 2.0.1, matching
the previously hard-coded value).
Letting the BOM drive the version eliminates the version-mismatch concern
jdaugherty raised in PR #15365 review: future Micronaut platform bumps will
keep jakarta-inject in sync automatically rather than requiring a separate
property update here.
Compilation verified: ./gradlew :grails-forge-api:compileJava
:grails-forge-cli:compileJava (exit 0).
Assisted-by: claude-code:claude-opus-4-7
Removes the explicit ':$groovyVersion' coordinate from every forge build
script and deletes groovyVersion=4.0.31 from grails-forge/gradle.properties.
Also drops the eachDependency { details.useVersion(groovyVersion) }
resolutionStrategy override in grails-forge-api, grails-forge-cli, and
grails-forge-core (the spock-core override is preserved - that one is still
needed because the micronaut-platform BOM's spock version differs from ours).
Files touched:
* grails-forge/gradle.properties
* grails-forge/gradle/doc-config.gradle (4 documentation entries)
* grails-forge/test-core/build.gradle
* grails-forge/grails-forge-api/build.gradle
* grails-forge/grails-forge-cli/build.gradle
* grails-forge/grails-forge-core/build.gradle
The forge composite build already imports the micronaut-platform 4.10.10
BOM in every consumer module, which transitively manages org.apache.groovy
artifacts via groovy-bom. With the override removed, Gradle's conflict
resolution lets the BOM-managed version win for forge:
org.apache.groovy:groovy-bom -> 4.0.28
org.apache.groovy:groovy -> 4.0.28
org.apache.groovy:groovy-test-> 4.0.28
(Verified with gradle :grails-forge-api:dependencies --configuration
testRuntimeClasspath.) Forge now tracks the Groovy version Micronaut
4.10.10 was built against (4.0.28) instead of the artificially-pinned
4.0.31 that was being forced. grails-core itself stays on 4.0.31 - the
two builds are independent composite projects with their own platform
choices, exactly as jdaugherty noted in the PR #15365 review thread on
test-core/build.gradle line 62.
Verified: gradle :grails-forge-api:compileTestGroovy
:grails-forge-cli:compileTestGroovy :grails-forge-core:compileTestGroovy
:test-core:compileTestGroovy succeeds (exit 0).
Assisted-by: claude-code:claude-opus-4-7
Replaces the hard-coded '4.0.31' literal in dependencies.gradle with GroovySystem.version, the static accessor for the Groovy version currently loaded by the running Gradle JVM. This 'gradle-groovy.version' entry feeds the grails-gradle-bom (the BOM consumed by Grails Gradle plugin authors), where it controls which groovy-bom platform is imported. Gradle plugin code is compiled against and runs in Gradle's Groovy classpath, so pinning this to a value other than what Gradle ships only adds drift risk - exactly the concern jdaugherty raised in the PR #15365 review thread on dependencies.gradle line 32. With Gradle 9.4.1 the published gradle-groovy.version becomes 4.0.29 (matching gradle -v output), verified in grails-gradle/bom/build/publications/maven/pom-default.xml after running gradle :grails-gradle-bom:generatePomFileForMavenPublication. The application-side groovy.version (4.0.31, used by grails-bom for runtime Groovy) is unchanged. Future Gradle wrapper bumps will flow through automatically without a parallel constants update here. Assisted-by: claude-code:claude-opus-4-7
Replaces the previous outputs.upToDateWhen { false } / mutate-in-place
implementation flagged by jdaugherty in PR #15365 review with a
properly-declared incremental task that Gradle can mark UP-TO-DATE
between builds.
Changes:
* Merge writes to a new build/merged-spring-configuration-metadata/
directory instead of mutating build/classes/{java,groovy}/main.
* Inputs are declared as a lazy FileCollection that filters to existing
files at execution time, so Gradle no longer fails the validation
when one or both compilers are NO-SOURCE.
* outputs.cacheIf { true } enables Gradle build-cache reuse.
* The task explicitly dependsOn compileJava and compileGroovy so the
compile output dirs always populate before the merge runs.
* The jar task uses an eachFile filter to drop the per-compiler copies
but keep the merged copy, instead of a global exclude that would have
also discarded the merged document.
* Removed the long block comment - the inline 7-line summary above the
task is enough context for future readers.
Verified:
* gradle :grails-test-examples-plugins-issue-11767:clean :...:jar
produces build/libs/...jar containing exactly one
META-INF/spring-configuration-metadata.json with both
PluginJavaMicronautBean (groups + properties) and
PluginGroovyMicronautBean entries merged.
* A second jar invocation reports compileJava, compileGroovy,
mergeMicronautConfigMetadata, and jar all UP-TO-DATE - the previous
always-rerun behavior is gone.
* The downstream consumer (:grails-test-examples-issue-11767) compiles
cleanly, confirming the merged metadata still satisfies its
@ConfigurationProperties('my') consumer code.
Assisted-by: claude-code:claude-opus-4-7
…ride Roll selenium back from 4.41.0 to 4.37.0 - the same version managed by Spring Boot 4.0.5's spring-boot-dependencies BOM - and remove the explicit OpenTelemetry 1.59.0 pin plus the 24-module constraint list that the 4.41 bump previously required. Background (jdaugherty review thread on dependencies.gradle line 95): * selenium had been pinned at 4.38 in main due to a geb compatibility concern. The PR #15365 bump to 4.41 forced OpenTelemetry to 1.59+ because Selenium 4.41+ depends on opentelemetry-* modules newer than the 1.55.x that Spring Boot 4.0.5 manages, which the dependency-version validator flagged. * Spring Boot 4.0.5 BOM declares selenium 4.37 (verified via spring-boot-dependencies 4.0.5 dependencyManagement). Adopting the same version makes the OpenTelemetry override unnecessary because Selenium 4.37 still works with the 1.55.x line that Spring Boot manages. Verified: * gradle :grails-test-examples-scaffolding:validateDependencyVersions succeeds (resolved versions match BOM-declared versions across every project in the build). * gradle validateDependencyVersions (whole-project) succeeds for all 157 reporting tasks. * gradle :grails-test-examples-geb:compileTestGroovy :grails-test-examples-geb-context-path:compileTestGroovy :grails-test-examples-geb-gebconfig:compileTestGroovy succeeds. * The geb test apps now resolve org.seleniumhq.selenium:selenium-bom:4.37.0 with no transitive opentelemetry conflict. Net diff: -40 lines from dependencies.gradle. The selenium-version constant moves to 4.37.0; the opentelemetry.version constant and the 24 opentelemetry-* module entries that propped up the 4.41 path go away. Reviewer note: This is option (a) from the four selenium options explored in the review thread. The 4.41 path is preserved on main if a later bump is needed, but tracking Spring Boot's choice keeps the override surface zero, which is what the validator wants. Assisted-by: claude-code:claude-opus-4-7
Review feedback addressed (commits ccafe2b .. fe527d1)Pushed 8 atomic commits resolving every line comment from the latest review. Net effect vs prior PR head: +153 / -241 across 20 files. All commits are independently revertable. Commit ledger
Verification matrix
Resolves all open review threads
Ready for re-review @jdaugherty @matrei. Assisted-by: claude-code:claude-opus-4-7 |
Reverts cc2f85f. `GroovySystem.version` returns Gradle's bundled Groovy, which can lag the version grails-gradle code resolves transitively via grails-core. The `validateDependencyVersions` task in CI failed because the BOM advertised Gradle's bundled version while the modules actually resolved grails-core's: org.apache.groovy:groovy - resolved <core>, expected <gradle-bundled> org.apache.groovy:groovy-ant - resolved <core>, expected <gradle-bundled> org.apache.groovy:groovy-groovydoc - resolved <core>, expected <gradle-bundled> org.apache.groovy:groovy-templates - resolved <core>, expected <gradle-bundled> ... etc Going back to the hard-coded literal so the BOM matches what we actually publish. Added an inline comment explaining why `GroovySystem.version` is not viable here (without specific version numbers, since those drift every Gradle/Groovy bump). Verified: `./gradlew :grails-gradle-plugins:validateDependencyVersions :grails-gradle-tasks:validateDependencyVersions` and `./gradlew validateDependencyVersions` (whole project, 157 tasks) both pass. See #15365 (comment) for the discussion thread. Assisted-by: claude-code:claude-opus-4-7
Fixes the `Build Grails Forge` CI jobs that 0143553 broke. The `documentation` configuration is registered by the buildsrc.groovydoc plugin and is independent of compileClasspath / testRuntimeClasspath, so the micronaut-platform BOM applied in each forge module's main `dependencies { }` block does not reach it. After 0143553 dropped the explicit `:$groovyVersion` from the documentation entries, the groovy-* artifacts had no version source and groovydoc failed with `Could not find org.apache.groovy:groovy-templates:.` Apply the same BOM to the documentation configuration here so the unversioned coordinates resolve through groovy-bom, matching the approach used in the other forge configurations. Verified: `./gradlew :grails-forge-cli:groovydoc :grails-forge-api:groovydoc :grails-forge-core:groovydoc` succeeds. Assisted-by: claude-code:claude-opus-4-7
CI fixes (commits 735ce32, 0314d5f)Pushed two follow-up commits resolving the CI failures introduced by the previous batch. Failures and fixes
Verification
Note on
|
|
So we did say we would pick the newer versions, and since we have a mismatch the change makes sense. I will review the PR next |
jdaugherty
left a comment
There was a problem hiding this comment.
Looks so much better, lets fix the jackson variable usage (use the bom instead) and then merge
…latform manage it Removes the explicit `:$jacksonDatabindVersion` coordinate flagged by jdaugherty in PR #15365 review on grails-forge-core/build.gradle:51. The micronaut-platform 4.10.10 BOM (already imported as a platform on the line above) imports jackson-bom transitively, which manages jackson-databind. Verified with `gradle :grails-forge-core:dependencies --configuration compileClasspath` -> `com.fasterxml.jackson.core: jackson-databind -> 2.19.2` (one minor newer than the previously hard-coded 2.18.3). The `jacksonDatabindVersion` property is left in grails-forge/gradle.properties because grails-forge/buildSrc/build.gradle still references it on its own gradle-plugin compile classpath, where no BOM is imported. Verified: `gradle :grails-forge-core:compileJava :grails-forge-core:compileTestGroovy` passes. Assisted-by: claude-code:claude-opus-4-7
…ntime After PR #15647 + #15648 fixed dockerBuildNative + Cloud Run startup for the analytics service, both Forge deploy workflows finally finished green and pushed `next.grails.org` (8.0.0-M1 hotfix branch) and `prev-snapshot.grails.org` (8.0.x) revisions live. start.grails.org still does not list 8.0.0-M1 / 8.0-SNAPSHOT in the Grails Version selector, though, because both backends return: $ curl -i -H 'Origin: https://start.grails.org' https://next.grails.org/versions HTTP/1.1 500 Internal Server Error Content-Type: application/json ... {"_embedded":{"errors":[{"message":"Internal Server Error: Error encoding object [org.grails.forge.api.VersionDTO@..] to JSON: No serializable introspection present for type VersionDTO. Consider adding Serdeable.Serializable annotate to type VersionDTO."}]}, "message":"Internal Server Error"} Reproduced locally (`docker run grails-forge-local:web-netty` against the GraalVM Community 21.0.2-ol9 native image with CORS_ALLOWED_ORIGIN set, then `curl -H 'Origin: https://start.grails.org' /versions`) - identical 500. Root cause: PR #15365 review feedback (commit e1f3013, "Address PR review feedback: telemetry override, forge BOM adoption, publish plugin bump") swapped grails-forge-web-netty's runtime JSON dependency: - runtimeOnly 'io.micronaut:micronaut-jackson-databind' + runtimeOnly 'io.micronaut.serde:micronaut-serde-jackson' with the rationale that "the forge stack is a Micronaut 4 serde- jackson application; the legacy jackson-databind runtime was a copy-paste from an earlier generator template". That is not yet true: every DTO returned by the Forge controllers (VersionDTO, ApplicationTypeDTO, FeatureDTO, FeatureList, SelectOptionsDTO, GormImplDTO, JdkVersionDTO, LanguageDTO, ServletImplDTO, DevelopmentReloadingDTO, GitHubCreateDTO, PreviewDTO, ApplicationTypeList, LinkDTO, the abstract Linkable parent, ...) carries `@Introspected` only - none of them are `@Serdeable` or registered via `@SerdeImport`. Micronaut Serde correctly rejects @Introspected-only classes at runtime, while Micronaut Jackson Databind serialises them via Jackson + bean introspection. The mismatch turns every JSON endpoint behind next.grails.org and prev-snapshot.grails.org into a 500, which is why Forge UI's `versions` fetch is empty for those backends and 8.0.0-M1 is missing from the start.grails.org Grails Version selector. The other Forge modules (forge-api tests, forge-core, analytics- postgres) all still use micronaut-jackson-databind; web-netty was the only inconsistency. Restore web-netty to micronaut-jackson-databind so the runtime matches the rest of the forge stack and the existing @introspected DTOs serialise. A proper end-to-end Serde migration belongs in a separate PR that also annotates every Forge DTO with @Serdeable / @SerdeImport. Verified locally on Docker 29.3.0 with the same Java 21 GraalVM Community 21.0.2-ol9 native-image container the deploy workflows use: $ curl -i -H 'Origin: https://start.grails.org' http://localhost:18080/versions HTTP/1.1 200 OK Access-Control-Allow-Origin: https://start.grails.org Vary: Origin Access-Control-Allow-Credentials: true content-type: application/json ... {"_links":{"self":{"href":"http://.../versions","templated":false}}, "versions":{...,"grails.version":"8.0.0-M1",...}} $ curl -i -H 'Origin: https://start.grails.org' http://localhost:18080/select-options HTTP/1.1 200 OK Access-Control-Allow-Origin: https://start.grails.org ... Endpoints serve JSON cleanly; CORS allow-origin header is present; the start.grails.org Grails Version selector will pick up 8.0.0-M1 once next.grails.org is redeployed from this commit. Assisted-by: claude-code:claude-4.7-opus
…ntime After PR #15647 + #15648 fixed dockerBuildNative + Cloud Run startup for the analytics service, both Forge deploy workflows finally finished green and pushed `next.grails.org` (8.0.0-M1 hotfix branch) and `prev-snapshot.grails.org` (8.0.x) revisions live. start.grails.org still does not list 8.0.0-M1 / 8.0-SNAPSHOT in the Grails Version selector, though, because both backends return: $ curl -i -H 'Origin: https://start.grails.org' https://next.grails.org/versions HTTP/1.1 500 Internal Server Error Content-Type: application/json ... {"_embedded":{"errors":[{"message":"Internal Server Error: Error encoding object [org.grails.forge.api.VersionDTO@..] to JSON: No serializable introspection present for type VersionDTO. Consider adding Serdeable.Serializable annotate to type VersionDTO."}]}, "message":"Internal Server Error"} Reproduced locally (`docker run grails-forge-local:web-netty` against the GraalVM Community 21.0.2-ol9 native image with CORS_ALLOWED_ORIGIN set, then `curl -H 'Origin: https://start.grails.org' /versions`) - identical 500. Root cause: PR #15365 review feedback (commit e1f3013, "Address PR review feedback: telemetry override, forge BOM adoption, publish plugin bump") swapped grails-forge-web-netty's runtime JSON dependency: - runtimeOnly 'io.micronaut:micronaut-jackson-databind' + runtimeOnly 'io.micronaut.serde:micronaut-serde-jackson' with the rationale that "the forge stack is a Micronaut 4 serde- jackson application; the legacy jackson-databind runtime was a copy-paste from an earlier generator template". That is not yet true: every DTO returned by the Forge controllers (VersionDTO, ApplicationTypeDTO, FeatureDTO, FeatureList, SelectOptionsDTO, GormImplDTO, JdkVersionDTO, LanguageDTO, ServletImplDTO, DevelopmentReloadingDTO, GitHubCreateDTO, PreviewDTO, ApplicationTypeList, LinkDTO, the abstract Linkable parent, ...) carries `@Introspected` only - none of them are `@Serdeable` or registered via `@SerdeImport`. Micronaut Serde correctly rejects @Introspected-only classes at runtime, while Micronaut Jackson Databind serialises them via Jackson + bean introspection. The mismatch turns every JSON endpoint behind next.grails.org and prev-snapshot.grails.org into a 500, which is why Forge UI's `versions` fetch is empty for those backends and 8.0.0-M1 is missing from the start.grails.org Grails Version selector. The other Forge modules (forge-api tests, forge-core, analytics- postgres) all still use micronaut-jackson-databind; web-netty was the only inconsistency. Restore web-netty to micronaut-jackson-databind so the runtime matches the rest of the forge stack and the existing @introspected DTOs serialise. A proper end-to-end Serde migration belongs in a separate PR that also annotates every Forge DTO with @Serdeable / @SerdeImport. Verified locally on Docker 29.3.0 with the same Java 21 GraalVM Community 21.0.2-ol9 native-image container the deploy workflows use: $ curl -i -H 'Origin: https://start.grails.org' http://localhost:18080/versions HTTP/1.1 200 OK Access-Control-Allow-Origin: https://start.grails.org Vary: Origin Access-Control-Allow-Credentials: true content-type: application/json ... {"_links":{"self":{"href":"http://.../versions","templated":false}}, "versions":{...,"grails.version":"8.0.0-M1",...}} $ curl -i -H 'Origin: https://start.grails.org' http://localhost:18080/select-options HTTP/1.1 200 OK Access-Control-Allow-Origin: https://start.grails.org ... Endpoints serve JSON cleanly; CORS allow-origin header is present; the start.grails.org Grails Version selector will pick up 8.0.0-M1 once next.grails.org is redeployed from this commit. Assisted-by: claude-code:claude-4.7-opus
Summary
This PR upgrades the Grails build infrastructure to use Gradle 9.4.1 and upgrades the grails-forge module to Micronaut 4. It also bumps the root project's Micronaut Platform BOM and related library versions to the latest 4.10.x releases.
Issue: #14738
Changes
Gradle 9.4.1 Upgrade
conventionwithextensionsAPIConfigureUtilwithClosureBackedActionJavaPluginConventionwithJavaPluginExtensionoutputFilewithdestinationFileinWriteProperties@DisableCachingByDefaulttoApplicationContextCommandTask,ApplicationContextScriptTask, andGrailsRunTaskto satisfy Gradle 9's requirement that all task types declare their caching intent.sdkmanrcto reference Gradle 9.4.1gradle-wrapper.properties(7),.sdkmanrcconventionto extensionsConfigureUtiltoClosureBackedActionJavaPluginConventiontoJavaPluginExtensionoutputFiletodestinationFile@DisableCachingByDefaultspring-configuration-metadata.jsonconflict in issue-11767 test plugin (both Java and Groovy annotation processors generate this file)grails-test-examples/plugins/issue-11767/build.gradleDevelocity Plugin Update
com.gradle.develocityfrom 4.1.1 to 4.3.2 (latest compatible with Develocity 2025.4.2)com.gradle.common-custom-user-data-gradle-pluginfrom 2.3 to 2.4.0grails-data-neo4jandgrails-data-graphqlfrom deprecatedgradle-enterpriseplugin todevelocitygrails-data-neo4jandgrails-data-graphqlsettingsTask.project Deprecation Fixes
Fix deprecated
Task.projectaccess at execution time (scheduled for removal in Gradle 10) by capturing project properties at configuration time:projectName,projectPath, andbuildDateat configuration time; refactorpickLicense()to accept these values instead of task referencePublishingExtensionat configuration time beforedoLastblockbuildDirat configuration time forbuildPropertiestask; captureantBuilderat configuration time fornative2asciitaskproject.syncindoLastwith properSynctask typeMicronaut 4 Upgrade (grails-forge)
javax.*tojakarta.*validation annotations:javax.validation.constraints.*->jakarta.validation.constraints.*javax.transaction.*->jakarta.transaction.*org.codehaus.groovy->org.apache.groovyio.micronaut:micronaut-bom->io.micronaut.platform:micronaut-platformjavax.inject:javax.inject->jakarta.inject:jakarta.inject-apimicronaut-validation-processorfor annotation processingmicronaut-jackson-databindruntime dependency@Validatedannotation to controllers using validationgradle.properties, all forgebuild.gradlefilesgradle.propertiesjavaxtojakarta(grails-forge)javax.validation.*tojakarta.validation.*;javax.transaction.*tojakarta.transaction.*org.codehaus.groovytoorg.apache.groovy;io.micronaut:micronaut-bomtoio.micronaut.platform:micronaut-platformMicronaut Platform Upgrade (root project)
The Micronaut Platform 4.10.10 BOM aligns with Spring Boot 3.5.10 and Spring Framework 6.2.16, which are compatible with the Grails 8.0.x target stack.
Test Infrastructure Updates
--add-opens java.base/java.lang=ALL-UNNAMEDJVM arg for test executionTesting
Application Testing
Plugin Output Verification
Verified output before/after Task.project deprecation fixes:
cyclonedxBomsavePublishedArtifactsprocessProfileResourcesbuildPropertiesdocsref/Versions/Grails BOM.htmlverified)Workarounds
None - all changes in this PR are proper fixes, not workarounds.
Known Deprecation Warnings
The following deprecation warning remains (scheduled for Gradle 10, not blocking):
StartParameter.isConfigurationCacheRequestedorg.asciidoctor.jvm.convertplugin 4.0.5Open Decisions
Breaking Changes
None expected for end users. This is an internal build infrastructure upgrade.
Related Issues