jamesfredley opened a new pull request, #15652:
URL: https://github.com/apache/grails-core/pull/15652
> **Status: DRAFT** - posted as a possible solution / discussion starter for
the BOM-leak class of CI failures we keep absorbing into the Groovy 5 upgrade.
Happy to redirect, narrow, or split further based on feedback before marking
ready.
## Summary
Stop leaking Grails-build-only artefacts (Gradle plugins,
JavaParser-as-build-tool) into the **application** Grails BOMs. Those entries
belong in `grails-gradle-bom` (which manages the Grails build classpath);
republishing them in `grails-bom` / `grails-base-bom` / `grails-hibernate5-bom`
/ `grails-micronaut-bom` adds no value to consumers and creates a class of CI
failures that we keep paying off manually.
## The recurring problem
The `Validate Dependency Versions` job has been catching transitive drift
between Grails BOM constraints and the resolved runtime classpath whenever
Apache Groovy bumps an internal dependency. The most recent instance, on PR
#15557 against `8.0.x`:
```
Dependency version validation failed for project 'grails-async-gpars'.
The following dependencies resolved to versions different from the BOM
(:grails-bom):
com.github.javaparser:javaparser-core - resolved 3.28.1, expected 3.28.0
A transitive dependency is upgrading these versions.
```
The mechanism, every time:
1. `dependencies.gradle` pins a Grails-build-only artefact (e.g.
`javaparser-core: 3.28.0`) inside `gradleBomDependencyVersions` because the
build itself uses it (here: `build-logic`'s `GroovydocEnhancerExtension`).
2. `grails-bom/{base,default,hibernate5,micronaut}/build.gradle` iterates
**all** of `gradleBomDependencies` into `constraints {}`, so the build-only pin
gets republished as a managed-version constraint of the **application** BOM.
3. Apache Groovy ships a patch that bumps the same artefact internally -
e.g. [GROOVY-11989](https://issues.apache.org/jira/browse/GROOVY-11989) bumped
`javaparser-core` 3.28.0 → 3.28.1 on `GROOVY_5_0_X` HEAD - and
`groovy-groovysh` / `groovy-ginq` link against the new version.
4. Any Grails subproject that resolves Groovy gets `javaparser-core` 3.28.1
transitively, which now contradicts the 3.28.0 constraint the Grails BOM is
republishing -> `:validateDependencyVersions` fails on every module.
5. We bump the version in `dependencies.gradle` to match (PR #15557 did
`813b131607`).
6. Groovy ships another patch some weeks later. Goto 1.
These artefacts are not used by user-facing Grails artefacts and have no
business in the consumer BOM. Gradle plugins like `asciidoctor-gradle-jvm` or
`asset-pipeline-gradle` are normally applied via the `plugins {}` block with a
literal version, not via BOM resolution. `javaparser-core` reaches end users
only as a transitive of `groovy-groovysh` (which is the version that should
win, per Apache Groovy's release).
## Proposal
Introduce a `gradleBomBuildOnlyDependencyKeys` set in `dependencies.gradle`:
```groovy
gradleBomBuildOnlyDependencyKeys = [
'asciidoctor-gradle-jvm', // Gradle plugin
'asset-pipeline-gradle', // Gradle plugin
'grails-publish-plugin', // Gradle plugin
'javaparser-core', // build-time GroovydocEnhancer; transitive
via groovy-groovysh for end users
'spring-boot-gradle', // Gradle plugin
] as Set
```
The four application BOM projects
(`grails-bom/{base,default,hibernate5,micronaut}/build.gradle`) skip these keys
when iterating `gradleBomDependencies` into their `constraints {}`.
`grails-gradle-bom` (in `grails-gradle/bom/`) is **unchanged** and continues to
manage the build classpath, so Grails-plugin developers are unaffected.
## What stays in the application BOM
I deliberately left these in `gradleBomDependencies` -> consumer BOM,
because they are or may be used at app runtime / test runtime:
| Entry | Why it stays |
|---|---|
| `ant`, `ant-junit` | Ant runtime artefacts (some Grails apps still use Ant
tasks) |
| `byte-buddy` | Spock 2 / Mockito need this at test runtime |
| `commons-text` | Used by Grails CLI runtime + likely by app code |
| `directory-watcher` | Grails dev-mode file watcher (runtime) |
| `jansi`, `jline`, `jline2`, `jna` | Grails shell/console runtime |
| `jquery` | Webjar (asset runtime) |
| `objenesis` | Spock / Mockito test runtime |
| `asciidoctorj` | Borderline - kept conservatively in case any user docs
pipeline depends on it |
| `spring-boot-cli`, `spring-boot-loader-tools` | Borderline - left in
pending discussion |
Three of those last items (`asciidoctorj`, `spring-boot-cli`,
`spring-boot-loader-tools`) are arguably build-only too. I left them for a
separate decision so the diff stays minimal and focused.
## Verification
Verified locally on `origin/8.0.x` HEAD (`b47917c1fe`) **without** the
manual `javaparser-core` 3.28.0 -> 3.28.1 bump that PR #15557 had to apply:
```
./gradlew validateDependencyVersions
> 184 actionable tasks, BUILD SUCCESSFUL
```
Without this fix, that exact command on the same source tree fails with the
`javaparser-core - resolved 3.28.1, expected 3.28.0` error.
Generated BOM POMs confirm the leak is gone:
```
grails-base-bom / grails-bom / grails-hibernate5-bom / grails-micronaut-bom
POMs:
ABSENT javaparser-core, asciidoctor-gradle-jvm, asset-pipeline-gradle,
grails-publish, spring-boot-gradle-plugin <-- the leak
PRESENT jansi, jline, byte-buddy, commons-text,
directory-watcher, ant-junit <-- legitimate
runtime/test deps
grails-gradle-bom POM:
PRESENT all of the above (this is the build-time BOM, unchanged)
```
## Why a draft
A few open questions worth resolving before this lands:
1. **Scope of "build-only"**: `asciidoctorj`, `spring-boot-cli`,
`spring-boot-loader-tools` are arguably also build-only - I left them in the
application BOM conservatively, but if anyone has clear opinions about whether
end-user apps consume them via the BOM today I am happy to expand the set.
2. **Backwards compatibility**: any Grails 7.x / 8.0.0-M1 app that was
relying on `grails-bom` to manage `javaparser-core` etc. will need to either
pin directly or import `grails-gradle-bom`. I surveyed grails-core and only
`grails-data-graphql/plugin/build.gradle` line 38 directly references
`javaparser-core` (and it pins 3.25.7 explicitly, ignoring the BOM-managed
version anyway), so internally this is a no-op. External consumers may want a
release note.
3. **Whether to also publish `grails-gradle-bom` cross-referenced** from the
application BOM POMs so any consumer that *does* want the Gradle classpath
versions can opt in with one extra `platform(...)`.
## Context
Surfaced while burning down workarounds on PR #15557 (Groovy 5 / Spring Boot
4 upgrade). PR #15557 worked around the same javaparser leak by bumping
`javaparser-core.version` to `3.28.1` (commit `813b131607`); this PR removes
the underlying class of failure rather than playing whack-a-mole each time
Groovy bumps an internal.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]