I totally agree with plugin upgrades being a sore spot and should be
avoided to a great degree.

However, adding an opt-in for supporting un-upgraded plugins is a very good
compromise if it lets us evolve the framework without drawbacks for
unaffected users.

As for M4, as a milestone is not a release candidate, but just a marker of
the current development state that is not a moving target, I think it would
be wasteful to pull the release.

Den tis 21 juli 2026 23:11James Fredley <[email protected]> skrev:

> Plugin support for newer version is a real sore spot for Grails.  What is
> the argument for non-default, opt-in support for Grails 7 plugins in Grails
> 8 apps?
>
> https://github.com/apache/grails-core/pull/15947 ended up as on opt-in
> for the breaking changes
>
> James
>
> On 2026/07/21 20:44:12 Søren Berg Glasius wrote:
> > Hi all,
> >
> > +1 with James D.
> >
> > Making legacy support an explicit opt-in (legacyCommandSupport = true)
> with
> > loud detection makes total sense. It avoids dragging legacy debt into
> every
> > Grails 8 build by default while providing an easy, well-documented path
> for
> > those who need it.
> >
> > Let's move forward with this approach and the proposed testing gates.
> >
> > Den tirs. 21. jul. 2026 kl. 22.22 skrev James Daugherty <
> > [email protected]>:
> >
> > > Do we plan to revert every breaking API change then?  Deprecations have
> > > already broken multiple plugins (I recently fixed the grails web
> console in
> > > one example). Why is changing a single flag to enable compatibility not
> > > acceptable while removing an entire API is? This inconsistently does
> not
> > > make sense to me.
> > >
> > > On 2026/07/21 19:52:25 James Fredley wrote:
> > > > I am taking another spin through
> > > https://github.com/apache/grails-core/pull/16011 in an attempt to get
> > > this closer to a compromise.
> > > >
> > > > But I am strongly of the opinion that existing, already published
> Grails
> > > 7 plugins should work in Grails 8, by default with warnings.  And I
> think
> > > we should keep the compatibility shims for an extended period of time.
> > > >
> > > > If we do not have to break end apps, I would like to keep them
> working,
> > > while still doing the split and letting teams move to the modern plugin
> > > approach, at their own pace.
> > > >
> > > > On the 1 of 4, it seems like the other 3 could also have similar
> > > classpath issues, based on what they import.
> > > >
> > > > James
> > > >
> > > > On 2026/07/21 16:52:21 James Daugherty wrote:
> > > > > Hi all,
> > > > >
> > > > > Following James Fredley's -1 on the CLI split, I want to lay out
> where
> > > > > we actually agree, correct a couple of points in the record, and
> > > > > propose a concrete path so we can settle this on the list rather
> than
> > > > > in PR or voting threads.
> > > > >
> > > > > Where we agree
> > > > >
> > > > > Nobody is proposing that users wait on plugin re-releases. We all
> > > > > agree on the goal: an application upgrading to Grails 8 must be
> able
> > > > > to keep using commands from already-published, unchanged Grails 7
> > > > > plugins. #16011 provides a mechanism for that, and after the review
> > > > > iterations its core design is right: the deprecated
> > > > > grails.dev.commands.* contract lives in a separate, execution-only
> > > > > grails-core-cli-legacy artifact, off every compile classpath,
> > > > > discovered through a neutral SPI, so grails-core-cli carries zero
> > > > > legacy references and retiring the window later means dropping one
> > > > > artifact. I support that design and want it to land.
> > > > >
> > > > > Correcting the record
> > > > >
> > > > > 1. "We only addressed 1 of 4 paths that provide commands." #16011's
> > > > > own audit table reaches the opposite conclusion: of the four
> > > > > mechanisms (application commands, codegen scripts, YAML commands,
> > > > > ServiceLoader/profile commands), only application commands were
> broken
> > > > > by the split. Codegen scripts, YAML, and ServiceLoader commands
> were
> > > > > verified unaffected. The hyphenated-script issue is a separate
> Groovy
> > > > > 5 regression that exists independently of #15948 and is fixed in
> > > > > #16011. So the compatibility gap is one mechanism, not four — and
> it's
> > > > > the one both PRs are focused on.
> > > > >
> > > > > 2. "#15948 was merged before a path was identified." It was merged
> > > > > into a milestone, explicitly with the note that the design would
> > > > > iterate before an RC. Milestones exist precisely so breaking
> changes
> > > > > can land and the compatibility story can be worked out before
> anything
> > > > > users depend on ships. Nothing has GA'd; no user is currently
> > > > > stranded. Framing a milestone merge as the final word — and a -1 as
> > > > > the response — escalates a design discussion we were already
> having.
> > > > >
> > > > > The actual open disagreement: default-on vs. explicit opt-in
> > > > >
> > > > > I am firmly for shipping the compatibility layer, and firmly
> against
> > > > > provisioning it by default. My proposal keeps the upgrade
> > > > > zero-confusion without committing the framework to zero-touch
> support
> > > > > of a deprecated ABI:
> > > > >
> > > > > - Detection always-on, provisioning opt-in. When the build or
> registry
> > > > > sees a grails.dev.commands.ApplicationCommand entry on the
> classpath
> > > > > and grails { legacyCommandSupport = true } is not set, it fails
> loudly
> > > > > with exact remediation: "Plugin X ships Grails 7 commands; set
> grails
> > > > > { legacyCommandSupport = true } or upgrade the plugin." Nothing is
> > > > > silent. The discoverability concern behind default-on is fully
> > > > > answered. The user flips one documented switch during an upgrade
> they
> > > > > are already performing.
> > > > >
> > > > > - Precedent. This is how we've handled every comparable transition:
> > > > > indy, and the BOM-handling change in this very release, shipped
> behind
> > > > > explicit settings. The wider ecosystem does the same: Spring Boot
> did
> > > > > not keep Jackson 2 on the classpath by default next to Jackson 3;
> you
> > > > > add it explicitly if you need it. I know of no precedent for
> > > > > default-provisioning a deprecated contract onto every build, test
> > > > > runtime included.
> > > > >
> > > > > - Costs of default-on fall on people who don't need it. Every
> Grails 8
> > > > > application would carry grails-core-cli-legacy and the
> > > > > dual-classloader factories scan on its command and test-runtime
> > > > > classpaths for the lifetime of the window.
> > > > >
> > > > > - Convergence. Default-on removes the only pressure that makes the
> > > > > deprecation window converge. A one-time runtime warning doesn't
> reach
> > > > > plugin authors — they never see their users' logs. And when the
> > > > > artifact is eventually dropped, plugins that never migrated break
> at
> > > > > that point with no action ever having been asked of anyone — a
> silent
> > > > > break outside the visible opt-in contract. A visible switch is the
> > > > > signal, to users and authors both, that migration is actually
> > > > > expected.
> > > > >
> > > > > What must be true before we advertise the compat contract
> (regardless
> > > > > of the default)
> > > > >
> > > > > These are in my review of #16011 and I consider them merge/RC
> gates,
> > > > > not follow-ups:
> > > > >
> > > > > 1. Prove the headline claim. The current fixture recompiles legacy
> > > > > sources with Groovy 5, which answers a different question than
> whether
> > > > > a genuine Grails 7/Groovy 4 trait-consumer binary links against the
> > > > > restored traits. The repo's existing composite-build pattern
> > > > > (includeBuild) gives us a pinned grails-core:7.1.1 fixture without
> any
> > > > > toolchain fight. Until that two-app test is green, "unchanged
> plugins
> > > > > keep working without a re-release" is a hope, not a contract — and
> > > > > it's the exact claim the -1 rests on.
> > > > >
> > > > > 2. No nondeterministic task graphs. The legacy per-command task
> > > > > discovery resolves runtimeClasspath eagerly in afterEvaluate under
> > > > > catch (Throwable), making the task set scheduling-dependent. Either
> > > > > drop the legacy per-command tasks (the generic runCommand
> -Pargs=...
> > > > > already works) or source names from the lenient withDependencies
> > > > > mechanism the companion discovery uses. We spent Grails 7 removing
> > > > > exactly this pattern.
> > > > >
> > > > > 3. Loud linkage failures. A LinkageError loading a legacy command
> is
> > > > > the compat layer failing its contract, not a faulty plugin; it must
> > > > > log at error level with clear framework-bug wording, distinct from
> > > > > ordinary per-command isolation.
> > > > >
> > > > > Proposal
> > > > >
> > > > > Land #16011 with: the separate-artifact design as-is;
> > > > > detection-always-on + legacyCommandSupport opt-in; the precompiled
> > > > > 7.1.1 fixture via composite build; legacy per-command tasks
> dropped in
> > > > > favor of runCommand; the LinkageError split. Document the switch in
> > > > > the upgrade notes as a one-line step.
> > > > >
> > > > > To be clear, I'm not asking James to carry these items alone — I'm
> > > > > offering to do the heavy lifting on them. Specifically, I'll take
> the
> > > > > precompiled 7.1.1 fixture (the composite-build wiring is the
> pattern I
> > > > > set up for grails-gradle and build-logic, so it's fastest for me to
> > > > > stand up), and I'm happy to do the opt-in gating and detection
> wiring
> > > > > in the Gradle plugin as well, either as commits into #16011 or as a
> > > > > stacked PR on top of it, whichever James prefers. The LinkageError
> > > > > split is a few lines either of us can do. None of this needs to
> slow
> > > > > the PR down.
> > > > >
> > > > > If the community consensus after discussion is genuinely
> default-on,
> > > > > I'll accept that outcome — but let's decide it here, deliberately,
> > > > > with the trade-offs on the table. With the gates above shared
> between
> > > > > us, I think we can have this landed well before the RC either way.
> > > > >
> > > >
> > >
> >
>

Reply via email to