jamesfredley opened a new issue, #16544:
URL: https://github.com/apache/grails-core/issues/16544

   ## Why this issue exists
   
   The Gradle build is the single biggest drag on this project. Across the last 
two and a half years we have spent thousands of volunteer hours on it, and that 
time did not go into Grails. In other projects Gradle is close to invisible: 
you upgrade it, you run it, it works. In grails-core it is a standing 
maintenance burden that breaks on its own schedule. These are the problems we 
keep hitting.
   
   - **Every Gradle upgrade breaks the build.** Each upgrade touches 25 to 35 
files and is followed by fixes to our own plugin code. We do this every few 
weeks.
   - **Memory is hand-tuned forever.** We raise a heap, an OOM moves somewhere 
else, and we raise another heap. Each round is a new PR, a new review cycle, 
and a new magic number.
   - **CI hammers the dependency repositories until they push back.** Maven 
Central and repo.grails.org rate-limit or block us because every CI run 
re-downloads and re-checks dependencies from scratch.
   - **We pay for caching, then throw it away.** We keep fixing tasks so they 
can be cached, then force CI to rerun everything anyway.
   - **CI is slow and fragile.** We have stacked timeouts, hang sentinels and 
"accept the known hang" scripts on top of the build instead of removing the 
reasons it hangs.
   - **Contributors can't reason about it.** It is spread over 6 separate 
Gradle builds, 12 test-config script variants, about 9,000 lines of custom 
Gradle plugin code, and roughly 20 `-P` switches.
   
   Most of this is not anyone's fault. It is legacy structure plus a lot of 
reasonable-looking local fixes that each added one more moving part. The 
cumulative result is a build that needs constant attention. **The goal of this 
issue is simplification:**
   
   - fewer moving parts
   - fewer files to edit per change
   - fewer breakages when Gradle or a dependency moves
   - stock Gradle behavior wherever possible
   
   ### What the git history shows
   
   Since 2025-01-01, **3,506 of 8,938 non-merge commits (39%)** touched a 
Gradle build file, a build-logic class, `gradle.properties`, or a CI workflow. 
1,233 of them touched the core build machinery (`build-logic`, root 
`build.gradle`/`settings.gradle`, `dependencies.gradle`, the test config 
scripts, or `gradle.yml`). Two caveats: the history includes repositories that 
were merged into the monorepo, and some of those commits are ordinary 
dependency edits. Even so, the patterns below are unambiguous.
   
   **1. Nine Gradle upgrades in nine months, each followed by repair work**
   
   | Date | Commit | What happened |
   |---|---|---|
   | 2026-01-23 | b7c9ed4dcf | Upgrade to Gradle 8.14.4 |
   | 2026-01-30 | 9fb682661f | Upgrade to Gradle 9.3.1 |
   | 2026-01-31 | 7ce8d2b62a | Fix `Task.project` invocation at execution time 
deprecations |
   | 2026-03-20 | 66f6229306 | Upgrade to Gradle 9.4.1 |
   | 2026-03-25 | 90c408651d | Fix overlapping task outputs preventing build 
cache usage |
   | 2026-05-13 | f4082aa7ee | Revert abstract compile changes |
   | 2026-05-20 | 7e4c48e799 | Upgrade to Gradle 9.5.1: **35 files** (6 copies 
of the wrapper, 2 profile skeletons, Forge templates) |
   | 2026-06-24 | 8af52a37ef, 3d55d78174 | Gradle 9.6.0 and 8.14.5 the same day 
|
   | 2026-07-22 | f8d8601adc | Gradle 9.6.1 |
   | 2026-07-31 | 4fdb88b163 | Defer compile-classpath probes out of 
GroovyCompile task configuration |
   | 2026-08-07 | 56a8dc4da4, 79504824fd | Gradle 9.7.0 (28 files), and the 
same day the Groovy compiler config script had to move into its own task |
   | 2026-08-20 | e718a7ba79 | Gradle 9.7.1 |
   | 2026-09-25 | ec6ec08873, 6c54b95fcd | Gradle 9.8.0 (25 files), and the 
same day a fix for a now no-op `Configuration.visible` call |
   | 2026-09-28 | 0c2f05ed06 | Build with a **SNAPSHOT** of our own 
`grails-publish` plugin just to support Gradle 9.8.0 |
   
   Earlier, e272f5614f (2025-05-19) had to add a whole new Gradle task "since 
newer versions of Gradle isolate classpaths of Gradle tasks". Almost every 
break lands in our custom plugin and task code, not in module build files. The 
more custom Gradle code we carry, the more every upgrade costs.
   
   **2. Memory whack-a-mole**
   
   - 816a20735b (2024-03) Increase MaxMetaspaceSize. Then d5bade295c, 
36b44429ba, 7d8ef50b07 (2025-06) remove the metaspace settings again.
   - acdc46ec8e and e5b0471936 (2025-02) increase Gradle memory and set 
`--max-workers=2`.
   - 6cce089473 (2026-01) increase the build runner root reserve to 6 GB.
   - 629e94ad6f, 61818f00f7, 3a0fe5fc89 (2026-04) "increase CI test memory", 
"fixed OOM", "analysis of OOM".
   - 13c964143f (2026-08-16) stop test forks oversubscribing the machine. 
cc7e0c3353 (2026-08-18) bound concurrent JVMs on the macOS runner.
   - 1b2cab5ffd, 900dff8160 (2026-09-15) release Groovydoc memory between 
documentation tasks, then serialize Groovydoc. 93f00bbed6 (2026-09-22) run 
Groovydoc and the user guide outside the Gradle daemon, followed by three 
review-round commits (5d347efc38, 725d807fee, dfede9d49d) and eb0b0bcf76 
"record the measured basis for the 3G daemon heap".
   - f921b366b3, 79d34939e2, 9ad51a9b5c (2026-09-26 to 28) test fork heap 
budget, condensed, then documented.
   - 626c81dca3 (2026-10-01) keep the dependency-analysis plugin inside the 3G 
daemon.
   - #16534 (2026-10-05) Hibernate 7 tests OOM after an `8.1.x` merge. 
`gradle/hibernate7-test-config.gradle` never applied the shared test config, so 
`forkEvery` silently stayed 0 and one JVM ran every test class until the heap 
filled.
   
   **3. Making tasks cacheable while forcing CI to rerun everything**
   
   We keep doing careful work to make tasks cacheable:
   
   - ffbf8adb73 make the SBOM timestamp reproducible to prevent cascading cache 
misses
   - 90c408651d fix overlapping outputs preventing build cache usage
   - fc7c9a4885 normalize `APP_BASE_DIR` for relocatability
   - bb884fff83 force `base.dir` into the Groovy compiler cache key
   - e5f942e93c keep scaffolded pages built on one platform out of another's 
build cache
   - 5a10bbab5b (2026-10-03) hash dependency cache keys from fixed-depth paths
   
   At the same time, CI is told to ignore the cache:
   
   - a78c022505 (2025-06-03) "always rerun tasks in CI to ensure tests are run"
   - cca2abfd77 (2025-06-16) "rerun tasks so all tests always run"
   - e6f28c3718 (2026-01-25) "Disable Groovy compilation cache in CI"
   - ddf492abe2 (2026-01-27) "use --rerun-tasks flag"
   - 5103ee38bc (2026-04-25) add the ability to rerun tests without rerunning 
all tasks
   - 7bb015970e (2026-08-08) separate rerun build work from its test shards
   
   **4. Repository flip-flops and rate limiting**
   
   - 24d23af351 (2025-03) remove `--refresh-dependencies` "to avoid Premature 
end of Content-Length delimited message body"
   - 395d9a64ba (2025-04-30) use Maven Central and Apache snapshots instead of 
repo.grails.org
   - c15f2f21a6 (2025-05-01) simplify back to a single Maven repository
   - 2fdcd2a12a (2025-05-02) add repo.grails.org for the Gradle tooling API 
dependency
   - 9767a171ec (2025-05-07) add repo.grails.org to grails-gradle
   - bf38aa59c2 (2025-05-08) use repo.spring.io/milestone instead of 
repo.grails.org/core
   - 42626fd036 (2025-05-15) use repo.grails.org/grails/restricted
   - 967690d86d and 314317b9f0 (2025-06-28) reorder the Maven Central 
repositories, and "add IP checks for debugging timeout issues"
   - 55c86cc25b (2025-07-06) remove a duplicate repository definition
   - 95cafe5ee2 (2025-10) centralize repository configuration
   - 5f903f078a (2026-01) rework repository definitions into a settings plugin
   - 11a4fc8e85 (2026-04-29) "add check for rate limit for debugging"
   
   Repository lists are still declared in three places today.
   
   **5. CI hangs papered over instead of removed** (most of this in two days, 
2026-08-17 and 18)
   
   - f5e7a91157 cap functional jobs at 70 minutes and disable the Gradle daemon
   - 699f8c6dd1 give the slower Groovy 6 functional shard 90 minutes
   - 403f43d2b4 finish functional shard 1 after Gradle worker teardown hangs 
(new init script)
   - f6c942b35f write a "functional hang sentinel" when the task graph empties
   - 2ef2a57df3 "accept the known functional hang after a green end-of-suite" 
(new Python script)
   - 9051523827 time out test jobs well before GitHub's six-hour default
   - a1bd43ddfc give the Validate Actions job 10 minutes "for a cold Gradle 
run". Validating YAML takes a cold Gradle run.
   
   **6. Tooling added, reverted, re-added**
   
   - Code analysis: 6aa1d893f1 (2026-03-29) consolidated violation reporting. 
29a24649f1 (2026-05-28) adds a code-analysis convention plugin, then 33412eebc7 
(same day) reverts the code-analysis and JaCoCo infrastructure. b08441587d 
(2026-06-01) restores the code style config to the 8.0.x baseline. adbe27cde5 
(2026-07-20) automates repository conventions and staged analysis. 51367bbe7e 
(2026-09-25) runs the report writers only through their aggregate tasks.
   - Develocity: 324e880510 then 2f09493f25 (2025-04-14) upgrade the Develocity 
plugin to v4, then revert to v3 the same day. 2bb982f3f9 goes back to a prior 
Develocity version to work around a retry issue. e5dfb507d6 adds the test-retry 
plugin "required after updating to develocity 4.0". bf78a4cbae removes 
Develocity test retries, and 7180d65c13 removes Test Distribution.
   
   ## How the build is shaped today (9.0.x at c3b2ea8fcf)
   
   - **Separate Gradle builds:** 6 (root, `build-logic`, root `buildSrc`, 
`grails-gradle`, `grails-forge`, `end-to-end`), plus `gradle-bootstrap`, whose 
only job is copying the wrapper.
     - Develocity is already at different versions in different builds (4.5.0 
in 
[settings.gradle](https://github.com/apache/grails-core/blob/c3b2ea8fcf3d6104643787d70e00eb3c261e8ad1/settings.gradle#L36)
 vs 4.3.2 in 
[grails-gradle/settings.gradle](https://github.com/apache/grails-core/blob/c3b2ea8fcf3d6104643787d70e00eb3c261e8ad1/grails-gradle/settings.gradle#L33)).
   - **Root subprojects:** about 280, of which 120 are sample apps under 
`grails-test-examples`.
   - **Test config scripts:** 12 variants. 258 build files `apply from:` one of 
them.
   - **Main CI workflow:** about 60 jobs and 63 Gradle invocations per PR, 
counted from the 
[gradle.yml](https://github.com/apache/grails-core/blob/c3b2ea8fcf3d6104643787d70e00eb3c261e8ad1/.github/workflows/gradle.yml)
 matrix. Most of them pass `--rerun-tasks`, and there is also a separate "rerun 
everything" lane 
([L262-L339](https://github.com/apache/grails-core/blob/c3b2ea8fcf3d6104643787d70e00eb3c261e8ad1/.github/workflows/gradle.yml#L262-L339)).
   - **Cache settings that defeat themselves:**
     - [gradle/test-config.gradle 
L52-L61](https://github.com/apache/grails-core/blob/c3b2ea8fcf3d6104643787d70e00eb3c261e8ad1/gradle/test-config.gradle#L52-L61)
 turns off caching for `GroovyCompile` and `Test` on CI.
     - [settings.gradle 
L69-L75](https://github.com/apache/grails-core/blob/c3b2ea8fcf3d6104643787d70e00eb3c261e8ad1/settings.gradle#L69-L75)
 turns off the local build cache on CI but still pushes to the remote cache.
   - **Zero-hour dependency cache on CI:** [build.gradle 
L170-L176](https://github.com/apache/grails-core/blob/c3b2ea8fcf3d6104643787d70e00eb3c261e8ad1/build.gradle#L170-L176)
 sets the dynamic and changing (snapshot) dependency cache time to 0 hours on 
CI. Every invocation on every runner re-checks every snapshot over the network.
   - **Unfiltered fallback repository:** [GrailsRepoSettingsPlugin 
L84-L89](https://github.com/apache/grails-core/blob/c3b2ea8fcf3d6104643787d70e00eb3c261e8ad1/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsRepoSettingsPlugin.groovy#L84-L89)
 lists repo.grails.org/grails/restricted with no content filter, so every 
Central miss is retried there.
   
   ## Principles for this work
   
   - **Delete before adding.** The fix for a problem should usually remove 
code, not add a new switch.
   - **Stock Gradle first.** Prefer behavior Gradle ships and keeps stable over 
custom plugins and tasks. Our own plugin code is where upgrades break.
   - **No fashion-driven migrations.** Configuration cache, isolated projects, 
version catalogs, Kotlin DSL, Test Distribution and predictive test selection 
are out of scope. They add migration work without removing the problems above. 
Some may become free later once the build is simpler, but they are not goals.
   - **Define once.** A setting that matters (heap, forks, cache, repositories, 
wrapper version) should live in exactly one place.
   - **Measure, don't guess.** Each phase records before and after numbers. 
Suggested metrics: PR CI wall clock, Gradle invocations per PR, dependency 
downloads per run, configuration time for `:grails-core:test`, and files 
touched by a Gradle version bump.
   
   ## Phase 1: stop discarding work and stop hammering repositories
   
   These are small, independent changes. Each is one PR.
   
   ### 1.1 Stop forcing reruns on CI
   
   Remove routine `--rerun-tasks`, remove `outputs.cacheIf { !isCiBuild }` for 
`Test`, and enable the local build cache on CI.
   
   - **Benefits:**
     - The largest single CI time saving. Unchanged modules stop rebuilding and 
retesting on every job.
     - Far less memory pressure and fewer OOMs, because far fewer JVMs start.
     - The remote cache we already push to finally gets used.
     - Deletes the separate rerun lane and its sharding.
   - **Downsides:**
     - A test whose inputs did not change is not re-executed. That is correct 
Gradle behavior, but it means a flaky test or a test with an undeclared input 
can hide behind a cache hit.
     - Mitigation: keep one scheduled, fully uncached run (nightly) that runs 
everything.
     - Release builds keep running without the cache.
   - **Done when:** PR jobs no longer pass `--rerun-tasks`, a nightly uncached 
run exists, and the before and after CI times are recorded.
   
   ### 1.2 Re-enable the build cache for Groovy compilation, after proving it 
is safe
   
   `GroovyCompile` was taken out of the CI cache (e6f28c3718) out of concern 
that a changed AST transform might not invalidate a cached compile.
   
   - **Benefits:** Compilation is the other big repeated cost on CI. Cached 
compiles also make every downstream task cheaper.
   - **Downsides:**
     - If an AST transform's classes are not part of the compile task's inputs, 
we would get stale bytecode. That is the exact bug the current setting guards 
against.
     - This item therefore depends on proving the inputs are modeled correctly, 
and it may uncover input-modeling work first.
   - **Gate:** add a test that changes an AST transform, recompiles a module 
that uses it with the build cache enabled, and asserts a cache miss and the new 
behavior. Only remove `cacheIf { !isCiBuild }` from `GroovyCompile` once that 
test passes.
   
   ### 1.3 Restore normal dependency cache times on CI
   
   Remove the 0-hour `cacheDynamicVersionsFor` and `cacheChangingModulesFor` 
override on CI ([build.gradle 
L170-L176](https://github.com/apache/grails-core/blob/c3b2ea8fcf3d6104643787d70e00eb3c261e8ad1/build.gradle#L170-L176),
 and the same pattern in `grails-forge/build.gradle`).
   
   - **Benefits:** This is the most direct cause of hammering the repositories. 
Every Gradle invocation on every runner currently re-checks every snapshot and 
dynamic version over the network.
   - **Downsides:**
     - Snapshots of our own libraries (asset-pipeline, SiteMesh, 
grails-publish) can be up to the cache window old on CI.
     - Mitigation: use a short window (a few hours) rather than 24, and keep 0 
for release and reproducible builds.
   
   ### 1.4 Put a content filter on repo.grails.org
   
   - **Benefits:**
     - Every lookup Central does not answer currently falls through to 
repo.grails.org/grails/restricted.
     - A filter limited to the coordinates we really need from there stops the 
fallback traffic and makes resolution predictable.
     - Repository lists are declared in three places today 
(`gradle/plugin-repositories.gradle`, `GrailsRepoSettingsPlugin`, 
`build-logic/settings.gradle`). This item collapses them into one.
   - **Downsides:**
     - We have to find out which coordinates actually come from 
repo.grails.org, for example with a resolution run against Central only.
     - If the filter is too narrow, resolution fails loudly. That is better 
than silent fallback, but it can briefly break a branch.
   
   ### 1.5 Give the Gradle cache on CI one owner
   
   Let `gradle/actions/setup-gradle` manage the Gradle user home cache, write 
it only from default branches, and delete the hand-rolled `actions/cache` 
restore and save steps in `gradle.yml`.
   
   - **Benefits:**
     - Today unrelated jobs race to save the same key, and the key only hashes 
`dependencies.gradle`, so most changes produce a stale or useless cache.
     - One owner means a warm dependency cache on every job, fewer downloads, 
and a lot less workflow YAML.
   - **Downsides:**
     - Less fine-grained control over cache keys.
     - GitHub's per-repository cache size limit means we need to watch cache 
churn after the switch.
   
   ### 1.6 Build Groovydoc only in the docs and publish jobs
   
   Groovydoc currently runs in every main build matrix leg ([gradle.yml 
L175-L199](https://github.com/apache/grails-core/blob/c3b2ea8fcf3d6104643787d70e00eb3c261e8ad1/.github/workflows/gradle.yml#L175-L199)).
 All 123 Groovydoc tasks run one at a time in forked JVMs.
   
   - **Benefits:** Removes one of the slowest and most memory-hungry steps from 
every PR leg, and most of the recent memory tuning was about Groovydoc.
   - **Downsides:** A Groovydoc-only breakage on one OS or JDK is caught later, 
in the docs job instead of every matrix leg.
   
   ### 1.7 Collect coverage from the existing test jobs
   
   The coverage workflow schedules the tests again 
([coverage.yml](https://github.com/apache/grails-core/blob/c3b2ea8fcf3d6104643787d70e00eb3c261e8ad1/.github/workflows/coverage.yml)).
   
   - **Benefits:** Coverage stops costing a second full test run.
   - **Downsides:**
     - The test jobs must upload their JaCoCo execution data, and a small 
aggregation job merges it.
     - Coverage then depends on the test jobs succeeding.
   
   ### 1.8 Run the Groovy snapshot canary on a schedule
   
   Change 
[groovy-snapshot-canary.yml](https://github.com/apache/grails-core/blob/c3b2ea8fcf3d6104643787d70e00eb3c261e8ad1/.github/workflows/groovy-snapshot-canary.yml#L21)
 from every PR to a nightly schedule plus manual dispatch.
   
   - **Benefits:** Every PR stops rebuilding upstream Groovy and downloading 
its dependencies.
   - **Downsides:** A Groovy snapshot regression is noticed up to a day later 
and is no longer tied to the PR that hit it.
   - **Alerting:** failures are still emailed. 
[.asf.yaml](https://github.com/apache/grails-core/blob/c3b2ea8fcf3d6104643787d70e00eb3c261e8ad1/.asf.yaml#L86)
 sets `jobs: [email protected]`, which sends an email whenever a 
workflow run fails, including scheduled runs, and again when it recovers.
   
   ## Phase 2: one definition of a module
   
   ### 2.1 Explore: move the sample apps out of the default project set
   
   This is an investigation, not a commitment. The output is a measured 
recommendation.
   
   - **Today:**
     - The 120 apps in `grails-test-examples` are root subprojects.
     - Each applies 
[functional-test-config.gradle](https://github.com/apache/grails-core/blob/c3b2ea8fcf3d6104643787d70e00eb3c261e8ad1/gradle/functional-test-config.gradle#L20-L38),
 which calls `evaluationDependsOn` on every other subproject.
     - It then hand-builds a substitution table so `org.apache.grails:*` 
coordinates resolve to local projects.
     - As a result, even `:grails-core:test` configures all of about 280 
projects.
   - **Idea:** give `grails-test-examples` its own `settings.gradle` with 
`includeBuild('..')`. Gradle's built-in composite substitution then maps those 
coordinates to the root projects, so the custom substitution code goes away.
   - **Benefits if it pans out:**
     - Framework work configures about 160 projects instead of about 280.
     - Fewer cross-project hooks.
     - The sample apps consume Grails the way a real application does, through 
stock Gradle behavior.
   - **Downsides:**
     - The examples become a separate entry point (`cd grails-test-examples && 
../gradlew ...`).
     - IDE import becomes a composite of two builds.
     - CI functional jobs need new commands.
   - **Deliverable:** a spike branch that records configuration time for 
`:grails-core:test --dry-run` before and after, notes IDE import behavior, and 
states a go or no-go recommendation.
   
   ### 2.2 Do: one `grails-library` convention plugin and one test configuration
   
   - **Today:**
     - A typical module, for example 
[grails-common/build.gradle](https://github.com/apache/grails-core/blob/c3b2ea8fcf3d6104643787d70e00eb3c261e8ad1/grails-common/build.gradle#L18-L72),
 lists 11 plugin ids and then `apply from:` the docs and test config scripts.
     - That block is pasted, with small variations, into most module build 
files.
     - Test settings are split across 12 script variants that are free to 
drift. #16534 is the latest example of that drift.
   - **Change:**
     - Modules apply a single `id 'org.apache.grails.buildsrc.library'`.
     - That plugin applies the common plugins, the docs config, and one test 
configuration.
     - The test-config variants collapse into one, with a few explicit, named 
settings where a module genuinely differs (for example a heap size or a forked 
database).
     - The memory policy lives here too, in one place: fork count, heap per 
fork, `forkEvery`, and a worker cap sized to the runner.
   - **Benefits:**
     - A fix to test, cache, or memory settings lands in every module at once.
     - New modules get correct settings by default.
     - Module build files shrink to what is actually unique about them.
     - The class of bug behind #16534 goes away.
   - **Downsides:**
     - A mechanical edit across many build files, which is a large diff to 
review.
     - Risk of silently changing a module's effective settings.
     - Mitigation: before and after, dump the effective settings of every 
`Test` and `GroovyCompile` task (heap, forks, `forkEvery`, JVM args, 
cacheability) and diff them in the PR.
   
   ## Phase 3: collapse the build sprawl from 7 builds to 3
   
   Not everything can be one build. The root build applies the Grails Gradle 
plugins (every sample app uses `org.apache.grails.gradle.grails-web` or 
`grails-plugin`). Gradle only allows a build to apply plugins it produces 
through an included build. So `grails-gradle` and `build-logic` stay as 
included builds, and the rest goes.
   
   | Build | Today | After |
   |---|---|---|
   | root | main build | main build, with Forge folded in via #16337 |
   | `grails-gradle` | own wrapper, own `buildSrc`, duplicated settings, built 
standalone in CI | included build only; no wrapper, no `buildSrc`, no 
duplicated settings; built from root |
   | `build-logic` | own wrapper; included by root, root `buildSrc` and 
`grails-gradle` | the single home for build plugins |
   | root `buildSrc` | [no source 
code](https://github.com/apache/grails-core/blob/c3b2ea8fcf3d6104643787d70e00eb3c261e8ad1/buildSrc/build.gradle#L27-L36),
 only puts 8 third-party plugins on the classpath | deleted; dependencies move 
to `build-logic` or versioned `plugins {}` blocks |
   | `grails-gradle/buildSrc`, `grails-forge/buildSrc` | classpath-only shims | 
deleted |
   | `gradle-bootstrap` | copies the wrapper into the other builds | deleted |
   | `end-to-end` | consumes published artifacts | stays separate, which is its 
purpose |
   
   The settings boilerplate (Develocity, build cache, repositories, the 
`DirectoryScanner` workaround) moves into the existing 
`org.apache.grails.buildsrc.repo` settings plugin. The property-sharing code 
(`SharedPropertyPlugin`, plus the root lookup that walks up to `.asf.yaml`) 
shrinks to one small helper. Included builds genuinely cannot read the root 
`gradle.properties`, so a little of this has to stay.
   
   - **Benefits:**
     - A Gradle version bump touches one build wrapper instead of six. The 
user-facing templates (profile skeletons, Forge templates) still need it, as 
they should.
     - One settings plugin instead of copy-pasted blocks that drift.
     - Much less "which build am I in" code, which is exactly the custom code 
that breaks on upgrades.
   - **Downsides:**
     - `grails-gradle` can no longer be built standalone with its own 
`./gradlew build`. Its CI job runs from the root instead.
     - Contributors who work only on the Gradle plugins lose that small, fast 
entry point.
     - Moving the `buildSrc` dependencies requires care with plugin classpath 
ordering.
   
   ## Explicitly not doing
   
   - **Configuration cache or isolated projects migration:** blocked by 
cross-project wiring today; revisit only if it comes cheaply after Phases 2 and 
3.
   - **Version catalog or Kotlin DSL migration:** moves strings around without 
removing any of the problems above.
   - **More shards, Develocity Test Distribution, or another cache or mirror 
tier:** we already tried and removed Test Distribution (7180d65c13). Use the 
cache we already pay for first.
   - **More `-P` switches or larger heaps as a fix:** they move the OOM rather 
than removing it.
   


-- 
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]

Reply via email to