jamesfredley opened a new issue, #16035:
URL: https://github.com/apache/grails-core/issues/16035
## Summary
PR #15948 successfully isolates `ApplicationCommand` implementations and
their CLI-only dependencies in companion `-cli` artifacts, but the older plugin
script-command channel still packages CLI-only command resources in each
plugin's normal runtime JAR.
`GrailsPluginGradlePlugin.configurePluginResources` copies everything under
`src/main/scripts` into the main `processResources` output at
`META-INF/commands`. That main plugin JAR is then placed on the application's
`runtimeClasspath` and inside deployed `bootJar`/`bootWar` artifacts.
This affects both command resource formats resolved from that directory:
- `*.groovy`, compiled at command execution time by
`GroovyScriptCommandFactory`
- `*.yml` / `*.json`, parsed by `YamlCommandFactory` into multi-step commands
The CLI implementation dependencies themselves remain correctly isolated.
The remaining problem is command-only code/resources in the deployed runtime
plugin artifact.
Related: #15377 and #15948.
## Current behavior
The plugin convention still performs this main-source-set copy:
```groovy
TaskProvider<Copy> copyCommands = project.tasks.register('copyCommands',
Copy) {
from("${project.projectDir}/src/main/scripts")
into("${processResources.destinationDir}/META-INF/commands")
}
processResources.dependsOn(copyCommands, copyTemplates)
```
`ClasspathCommandResourceResolver` later scans
`classpath*:META-INF/commands/*.<extension>` from the command runner's context
classloader. `runCommand` intentionally combines the application runtime
classpath with `grailsCliClasspath`, so discovery currently depends on the
command resources remaining in runtime plugin JARs.
## Reproduction
The existing legacy-command fixture contains:
```text
grails-test-examples/legacy-commands-plugin/src/main/scripts/hello-legacy-script.groovy
```
Build and inspect the plugin and deployable application archives:
```bash
./gradlew :grails-test-examples-legacy-commands:bootJar
jar tf
grails-test-examples/legacy-commands-plugin/build/libs/grails-test-examples-legacy-commands-plugin-0.0.1.jar
jar tf
grails-test-examples/legacy-commands/build/libs/grails-test-examples-legacy-commands-0.1.war
```
The plugin JAR contains:
```text
META-INF/commands/hello-legacy-script.groovy
```
The deployable WAR contains that plugin JAR:
```text
WEB-INF/lib/grails-test-examples-legacy-commands-plugin-0.0.1.jar
```
The same copy task accepts YAML and JSON files without filtering, and
`YamlCommandFactory` resolves those formats from the same `META-INF/commands`
location.
Control checks confirm that PR #15948's dependency isolation is working:
```bash
./gradlew :grails-test-examples-legacy-commands:dependencyInsight \
--dependency grails-shell-cli --configuration runtimeClasspath
./gradlew :grails-test-examples-legacy-commands:dependencyInsight \
--dependency grails-core-cli --configuration runtimeClasspath
```
Both report no matching runtime dependency. The deployable WAR also contains
no `grails-shell-cli`, `grails-core-cli`, `grails-core-cli-legacy`, or
`grails-profiles-*` JAR.
## Expected behavior
When a plugin publishes a companion CLI artifact, command resources from
`src/main/scripts` should be placed in that companion artifact and excluded
from the normal runtime plugin JAR. The companion remains available through
`grailsCliClasspath`, preserving command discovery and execution without
shipping command-only resources in deployed applications.
## Suggested coverage
Add a functional fixture containing both:
```text
src/main/scripts/example-script.groovy
src/main/scripts/example-multi-step.yml
```
Verify that:
1. The normal plugin JAR and consuming `bootJar`/`bootWar` do not contain
either command resource.
2. The companion `-cli` JAR contains both resources under
`META-INF/commands`.
3. `grails <command>` and `runCommand` still discover and execute both
commands through `grailsCliClasspath`.
4. `grails-shell-cli`, profile artifacts, and companion CLI dependencies
remain absent from `runtimeClasspath` and the deployed archive.
## Out of scope / verified isolated
- YAML commands packaged inside profile JARs under
`META-INF/grails-profile/commands` are resolved by the CLI profile repository
and were absent from the deployed application archive.
- `ServiceCommandFactory`, its `META-INF/services` registrations, and
built-in profile command implementations remain in `grails-shell-cli`; that
artifact was absent from the application's runtime classpath and deployed WAR.
--
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]