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]

Reply via email to