Split CLI dependencies from the runtime classpath#15948
Conversation
a7d2537 to
01ddd85
Compare
|
These were resolving locally due to having maven local search on; I need to fix the dependency substitution to fix these resolution issues. |
|
Turns out there's a real build issue separate from this change, micronaut-singleton isn't including our functional test app so it was pulling from upstream instead of testing with the local copy. |
|
The published Gradle Module Metadata still contains capability-style dependencies (org.apache.grails:grails-core + requireCapability('org.apache.grails:grails-core-cli')) — violating the split's design rule that external consumers must see the plain -cli coordinate, never capabilities. When Gradle resolves that from a Maven repo, it selects grails-core's cliRuntimeElements variant, follows its available-at redirect to the standalone grails-core-cli module, and then sees both nodes providing the same capability — a self-conflict. I reproduced it with a one-dependency project against build/local-maven, and it fails with both timestamped and non-unique snapshots, so it's not a snapshot-timestamp issue. There are two distinct leak paths:
I'm still researching possible solutions for this one. |
|
This is now fixed. We have to support cases where the library is a regular library imported by another project that uses the requireCapbility - this is only when the projects are defined in the same build. I've created a dedicated plugin for this scenario. |
🚨 TestLens detected 1 failed test 🚨Here is what you can do:
Test SummaryCI - Groovy Joint Validation Build / build_grails > :grails-test-examples-gsp-sitemesh3:integrationTest
🏷️ Commit: c6739f4 Test FailuresEndToEndSpec > async multiple levels of layouts (:grails-test-examples-gsp-sitemesh3:integrationTest in CI - Groovy Joint Validation Build / build_grails)Muted TestsSelect tests to mute in this pull request:
Reuse successful test results:
Click the checkbox to trigger a rerun:
Learn more about TestLens at testlens.app. |
Description
Grails commands (
ApplicationCommandimplementations) have always shipped inside runtime pluginartifacts, dragging CLI-only dependencies onto application runtime classpaths. This causes real
failures:
grails-shell-clileaks a conflicting Groovy onto the app classpath (see thelong-standing exclusion + TODO in
grails-data-hibernate{5,7}/dbmigration/build.gradle), and aCLI-only Spring Boot
WebApplicationInitializerbreaks classic WAR deployment with an NPE(#15377) unless users hand-filter the
bootWarclasspath.(no classifiers or capability syntax for consumers), fully consumable by Maven as well as Gradle.
Framework changes
grails-core-cli: the command contract moves fromgrails.dev.commands.*toorg.apache.grails.core.cli.*. Command registrations move fromMETA-INF/grails.factoriesto adedicated
META-INF/grails-cli.factories, written by a newCommandFactoriesTransformationthat ships in the cli artifact (so it is active exactly when a command can compile). The default
grails-corejar contains no command code and no command contract.Automatic-Module-Name: dbmigration (h5/h7, 29dbm-*commands each), the hibernate plugins(
schema-export), scaffolding (9generate-*commands), web-url-mappings(
url-mappings-report), spring-security, and spring-security-oauth2.grails-shell-cliis gonefrom every runtime dependency graph.
Build/tooling changes
org.apache.grails.gradle.grails-cliplugin (applied automatically by the Grailsapplication/plugin plugins): registers the
grailsCliconfiguration — compile-visible forgrails-app/commandssources and on the command-runner and test classpaths, but never on themain
runtimeClasspath, so commands and their CLI-only dependencies are excluded frombootRun/bootJar/bootWar. It auto-provisionsgrails-core-cli+grails-console, anddiscovers plugin companions automatically: a command-bearing plugin advertises its companion
through a
Grails-Cli-Artifactmanifest attribute on its runtime jar, and the plugin walks theresolved dependency graph (including transitive plugins) and adds each advertised companion to
grailsCli. Per-command Gradle tasks (dbmUpdate, …) register from the discovered companions —no
buildscript { classpath }entry needed. Opt out withgrails { cliAutoProvision = false }.The
console/shelltasks draw from the same provisioned tier, so generated apps no longerdeclare
console "org.apache.grails:grails-console".org.apache.grails.gradle.grails-plugin-cliplugin for plugin authors (dogfooded by theframework's own modules): one
applysets up the cli source set as a feature variant, thecommand contract on its compile classpath, the manifest advertisement, and the companion
publication.
Support additional source sets and custom publishing grails-gradle-publish#34 (requires
grails-publish≥1.0.0-SNAPSHOT; the version isbumped in
dependencies.gradle).Consumer impact
Most applications upgrade with no build changes: declaring a command-bearing plugin is enough,
and its commands (and Gradle tasks) follow automatically. Application commands in
grails-app/commandsonly need the import rename (grails.dev.commands.*→8.0.x— breaking changes are part of the major release).Code Quality
suites, dbmigration integration tests, the config-report end-to-end integration test
exercising the full discovery → factories → runner chain, forge feature specs, and
grails-gradle plugin tests).
./gradlew build --rerun-tasks.aggregateViolationsreports zeroCheckstyle/CodeNarc/PMD/SpotBugs findings).
beyond the approved scope.
Licensing and Attribution
Documentation
Gradle plugins catalog,
create-commandreference).-cliartifacts, automatic discovery, and the new plugins.grails-cli.factoriesclean break, the
grailsCliconfiguration, and the third-party plugin migration path.