Merge 8.1.x into 9.0.x - #16319
Conversation
org.gradle.jvmargs sizes the Gradle daemon only. Test forks are separate child JVMs that take their heap from maxHeapSize in gradle/test-config.gradle, so a job's configured heap is the daemon -Xmx plus the concurrent test forks times the per-fork heap. Those two numbers live in different files and have never been reasoned about together. The concurrent fork count is not maxParallelForks. With org.gradle.parallel=true several Test tasks run at once, so the live JVM count is bounded by Gradle's global worker pool, which defaults to the CPU count. On the 4-CPU, ~16 GB Linux and Windows runners that floor is 5G + 4x768m = 8G and fits. On the 3-CPU, ~7 GB macOS runner it is 5G + 3x768m = 7.25G and does not. Cap --max-workers on the macOS leg, since that is what actually limits concurrent test and compiler JVMs, and keep maxTestParallel alongside it so no single task exceeds the same cap. Both are passed through a new runner_arguments matrix key that is undefined, and therefore empty, for every other entry. The daemon stays at 5 GB: groovydoc is what needs it, and shrinking it would trade a memory problem for a slower build. Document the arithmetic next to org.gradle.jvmargs as a simplified configured-heap floor, explicitly excluding metaspace, native memory and the forked compiler workers that CompilePlugin gives their own -Xmx2G, so it is not mistaken for a true peak. This changes concurrency only. No test is added, removed, skipped or weakened. Assisted-by: claude-code:claude-opus-5
Groovy 5 defaults indy on. Only modules that apply the Grails Gradle plugin inherited grails.indy=false, so published framework artifacts were mixed. Centralize indy=false in CompilePlugin and apply gradle/groovy-indy.gradle from the grails-core, grails-gradle, and grails-forge builds. CI can still opt in with -PgrailsIndy=true. See #15293 Assisted-by: Sisyphus:grok-4.6
With indy off, log.debug inside GormStaticApi.count()'s session callback was dispatched as Domain.debug(...). Capture the @slf4j logger in a local first. Also trim -PgrailsIndy the same way as CompilePlugin and apply the shared groovy-indy script from build-logic. Assisted-by: Sisyphus:grok-4.6
Class.newInstance(Map) is not selected under @CompileStatic when invokedynamic is disabled. Use InvokerHelper.invokeConstructorOf with an explicit Object[] so nested Map-constructor types still bind. Also avoid `null as boolean` in the Map-constructor test fixture, which Groovy 5 throws on without indy after unbindable properties are filtered from constructor arguments. Assisted-by: Sisyphus:grok-4.6
Honor review: drop groovy-indy.gradle and subprojects applies. Unpublished build-logic uses Gradle's Groovy default.
Hibernate 7 publishes jboss-logging as a runtime-only transitive. Groovydoc Class.forName's referenced types, so :grails-data-hibernate7-dbmigration-core:groovydoc failed in CI (Forge/e2e publish) with NoClassDefFoundError: org/jboss/logging/Logger.
build(ci): bound concurrent JVMs on the macOS runner
build: disable Groovy invokedynamic for the Grails 8 compile
There was a problem hiding this comment.
🔵 Needs a closer look
This is a cross-branch release-line merge touching build logic and CI behavior, which warrants final human review despite the changes appearing internally consistent.
Pull request overview
Release-line merge bringing the 8.1.x line’s pending build/runtime fixes into 9.0.x, primarily around Groovy invokedynamic (indy) defaults, databinding Map-constructor behavior under @CompileStatic when indy is disabled, and build/docs/CI stability improvements.
Changes:
- Fix Map-constructor instantiation for nested databinding under
@CompileStaticby bypassingClass.newInstance(Map)and invoking the Map constructor reliably. - Prevent
@Slf4jlogger calls inside a session callback from being mis-dispatched (when indy is off) by capturing the logger before entering the closure; add regression coverage. - Improve build robustness: centralize indy default in
CompilePluginwith whitespace-tolerant parsing, extend Groovydoc classpath to include runtime deps, and reduce macOS CI memory pressure via--max-workers.
File summaries
| File | Description |
|---|---|
grails-web-databinding/src/main/groovy/grails/web/databinding/GrailsWebDataBinder.groovy |
Uses the new Map-constructor instantiation helper to keep nested binding working under indy-off + @CompileStatic. |
grails-test-suite-persistence/src/test/groovy/grails/web/databinding/GrailsWebDataBinderSpec.groovy |
Avoids null as boolean failure under indy-off in a Map-constructor test fixture. |
grails-datamapping-core/src/test/groovy/org/grails/datastore/gorm/GormStaticApiSpec.groovy |
Adds regression test ensuring count() doesn’t fail due to logger dispatch issues under indy-off. |
grails-datamapping-core/src/main/groovy/org/grails/datastore/gorm/GormStaticApi.groovy |
Captures the SLF4J logger before entering the callback closure to avoid methodMissing/dynamic-finder dispatch. |
grails-databinding-core/src/main/groovy/grails/databinding/SimpleDataBinder.groovy |
Introduces newInstanceFromMapArguments(...) using InvokerHelper to reliably invoke Map constructors under @CompileStatic. |
gradle/grails-extension-gradle-config.gradle |
Makes -PgrailsIndy=... parsing whitespace-tolerant and documents alignment with CompilePlugin. |
gradle.properties |
Adds detailed daemon/test-fork heap budgeting commentary to clarify CI sizing constraints. |
build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/GroovydocEnhancerPluginSpec.groovy |
New test ensuring Groovydoc classpath includes runtime-only jars required for Class.forName resolution. |
build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/CompilePluginSpec.groovy |
Adds TestKit coverage for default indy=false and -PgrailsIndy opt-in (including whitespace trimming). |
build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GroovydocEnhancerPlugin.groovy |
Extends Groovydoc classpath with runtimeClasspath to prevent NoClassDefFoundError during doc generation. |
build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/CompilePlugin.groovy |
Sets GroovyCompile indy default via lookupProperty(...) and documents the Grails 8/9 intent. |
.github/workflows/gradle.yml |
Caps macOS runner concurrency (--max-workers=2) to reduce memory pressure while keeping groovydoc viable. |
Review details
- Files reviewed: 12/12 changed files
- Comments generated: 0
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## 9.0.x #16319 +/- ##
=============================================
Coverage 30.1177% 30.1177%
Complexity 519 519
=============================================
Files 83 83
Lines 4758 4758
Branches 815 815
=============================================
Hits 1433 1433
Misses 3082 3082
Partials 243 243 🚀 New features to boost your workflow:
|
✅ All tests passed ✅🏷️ Commit: 92e2c82 Learn more about TestLens at testlens.app/docs. |
Description
Merge the pending
8.0.x->8.1.xline (#16318) into9.0.xso Grails 9 receives #16178 (CompilePlugininvokedynamic default) and the related 8.0 groovydoc/CI heap work.This is a release-line merge, not a squash. Stacked on #16318 (
merge/8.0.x-into-8.1.x). One conflict ingradle.propertieswas resolved by keeping 9.0.xprojectVersion=9.0.0-SNAPSHOTand the Spock Groovy 6 version-check JVM arg, and carrying the 8.0 daemon-heap comments.CompilePluginauto-merged: Grails 8 indy-off default plus 9.0.x SpockdisableGroovyVersionCheckfork args. #16165 will flip that CompilePlugin default to indy-on for Grails 9.Contributor Checklist
Issue and Scope
7.0.x): Bug fixes only. No new features or API changes.7.1.x): New features are welcome, but breaking existing APIs must be avoided.8.0.x): Reserved for major changes. Breaking API changes are permitted.Code Quality
./gradlew build --rerun-tasks../gradlew codeStyleand resolved any violations. See Code Style for details.Licensing and Attribution
Documentation
Generative AI (Cursor Grok 4.6) was used to complete the merge and resolve the gradle.properties conflict.