matrei opened a new issue, #16517:
URL: https://github.com/apache/grails-core/issues/16517
### Summary
With the Gradle configuration cache enabled, `configReport` and the other
tasks that run against the application fail in Grails 8.0.0:
```
Execution failed for task ':configReport'.
> Could not find method requireMainClass() for arguments [fixed(class
java.lang.String, pingcrm.Application), configReport]
on task ':configReport' of type
org.grails.gradle.plugin.commands.ApplicationContextCommandTask.
```
It fails both when Gradle stores a new configuration cache entry and when it
reuses one. The same task works with `--no-configuration-cache`, and it works
with the configuration cache in 8.0.0-RC2.
### Steps to reproduce
1. In a Grails 8.0.0 application, enable the configuration cache in
`gradle.properties`:
```properties
org.gradle.configuration-cache=true
```
2. Run `./gradlew configReport`.
Seen with Gradle 9.8.0 and Java 21.
### Cause
#16433 (Explain the missing application class in tasks that need one)
changed the `doFirst` actions in `GrailsCliGradlePlugin` from reading the main
class provider:
```groovy
it.doFirst {
args << appClassProvider.get()
```
to calling a static helper on the plugin class:
```groovy
it.doFirst {
args << requireMainClass(appClassProvider, it.name)
```
These closures are created in `@CompileDynamic` methods, so the unqualified
`requireMainClass(…)` is resolved at run time through the closure's owner, the
plugin. With the configuration cache, Gradle serializes task actions without
keeping the closure's owner. The call then falls through to the delegate, the
task, which has no such method. The previous code only called `get()` on a
captured provider, which works after serialization.
All five calls are in `doFirst` actions, so with the configuration cache
this affects:
- every application command task, such as `configReport`
- `runCommand`
- `runScript`
- `console`
- `shell`
`MainClassRequiredSpec` does not run the tasks with the configuration cache,
so it did not catch this. The `8.0.x` and `8.1.x` branches still have the
unqualified calls.
### Minimal reproduction of the mechanism
A `buildSrc` plugin shaped like `GrailsCliGradlePlugin`:
```groovy
@CompileStatic
class DemoPlugin implements Plugin<Project> {
@PackageScope
static String requireMainClass(Provider<String> mainClass, String
taskName) {
"${mainClass.get()} for $taskName"
}
void apply(Project project) {
registerTasks(project)
}
@CompileDynamic
void registerTasks(Project project) {
def provider = project.provider { 'demo.Application' }
project.tasks.register('unqualified') {
it.doFirst { println(requireMainClass(provider, it.name)) }
}
project.tasks.register('qualified') {
it.doFirst { println(DemoPlugin.requireMainClass(provider,
it.name)) }
}
}
}
```
| Task | `--no-configuration-cache` | `--configuration-cache` |
|---|---|---|
| `unqualified` | works | `Could not find method requireMainClass() … on
task ':unqualified'` |
| `qualified` | works | works |
### Suggested fix
Qualify the calls with the class name,
`GrailsCliGradlePlugin.requireMainClass(…)`, as the `qualified` task above
does, and run `MainClassRequiredSpec` (or a new spec) with
`--configuration-cache` so the tasks are covered with the configuration cache
enabled.
### Workaround
Run the task without the configuration cache:
```
./gradlew configReport --no-configuration-cache
```
--
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]