Gradle is a magic box for me. I often don’t get it and always do try and error. I use gradle 8.1 and groovy scripts. I have this small task
import java.time.Instant tasks.register('continuous-build') { dependsOn tasks.compileJava onlyIf { !compileJava.state.upToDate } logger.lifecycle("Job executed at " + Instant.now()) doLast { def file = new File(projectDir, "build/classes/java/main/.reloadTrigger"); file.createNewFile(); file.setLastModified(Instant.now().toEpochMilli()) logger.lifecycle("This message is never seen") } }
I want this task to run with –continuous-build and just touch a file if it’s done compiling.
this is what I do:
Run ./gradlew continuous-build –continuous
$ ./gradlew continuous-build --continuous Reload triggered at 2023-11-10T11:48:50.446501720Z BUILD SUCCESSFUL in 1s 6 actionable tasks: 1 executed, 5 up-to-date Waiting for changes to input files... (ctrl-d to exit)
Make a small change to Main.java which compiles fine
modified: [...]Main.java Change detected, executing build... Reload triggered at 2023-11-10T11:49:02.870526619Z BUILD SUCCESSFUL in 1s 6 actionable tasks: 1 executed, 2 from cache, 3 up-to-date Waiting for changes to input files... (ctrl-d to exit)
After this the file timestamp is changed. That is what I want.
Make a small change to Main.java which compiles with error
modified: [...]Main.java Change detected, executing build... Reload triggered at 2023-11-10T11:49:09.303034432Z > Task :compileJava FAILED [...]Main.java:22: error: <identifier> expected publi static final String ANSWER = "42"; ^ 1 error FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':compileJava'. > Compilation failed; see the compiler error output for details. * Try: > Run with --stacktrace option to get the stack trace. > Run with --info or --debug option to get more log output. > Run with --scan to get full insights. * Get more help at https://help.gradle.org BUILD FAILED in 1s 3 actionable tasks: 2 executed, 1 up-to-date Waiting for changes to input files... (ctrl-d to exit)
After this the file timestamp is NOT changed. That is what I want as it compiled with an error.
Make a small change to Main.java which compiles fine again
modified: [...]Main.java Change detected, executing build... Reload triggered at 2023-11-10T11:49:14.192599979Z BUILD SUCCESSFUL in 1s 6 actionable tasks: 1 executed, 5 up-to-date Waiting for changes to input files... (ctrl-d to exit)
After this the file timestamp is NOT changed anymore even the compilation succeeded. How can I achieve a file touch cmd if compileJava was successful.
And why is the second logging message never seen?
PS I have shortened the output a little bit to make it more readable
The reason why the file timestamp is not changed after the second successful compilation is that Gradle’s upToDate check considers both the inputs and outputs of the task. If the inputs and outputs of a task have not changed since the last successful execution, Gradle considers the task up-to-date and skips its execution.
upToDate
In your case, the compileJava task has not changed (since you’re using --continuous and it’s watching for changes in source files), and its outputs are still valid, so Gradle skips the task execution, and consequently, your continuous-build task is not executed.
compileJava
--continuous
continuous-build
To work around this, you can introduce a custom input property that changes when you want to force the compileJava task to execute. Here’s an updated version of your script:
import java.time.Instant tasks.register('continuous-build') { dependsOn tasks.compileJava onlyIf { !compileJava.state.upToDate } inputs.property("forceCompile", Instant.now().toEpochMilli()) logger.lifecycle("Reload triggered at " + Instant.now()) doLast { def file = new File(projectDir, "build/classes/java/main/.reloadTrigger") file.createNewFile() file.setLastModified(Instant.now().toEpochMilli()) logger.lifecycle("This message is now seen") } }
By introducing the forceCompile input property, you ensure that the continuous-build task is considered out-of-date whenever you want to force the compileJava task to execute. This should address the issue you’re facing.
forceCompile
Regarding the second logging message not being seen, it’s because the doLast block is only executed if the task’s work action executes. In your case, since the task is considered up-to-date, the doLast block is skipped. If you want the message to be seen regardless, you can move it outside the doLast block:
doLast
tasks.register('continuous-build') { dependsOn tasks.compileJava onlyIf { !compileJava.state.upToDate } inputs.property("forceCompile", Instant.now().toEpochMilli()) logger.lifecycle("Reload triggered at " + Instant.now()) } // Move this outside the task definition tasks.register('continuous-build-message') { doLast { logger.lifecycle("This message is now seen") } } // Add a dependency to 'continuous-build-message' in 'continuous-build' tasks.named('continuous-build') { dependsOn 'continuous-build-message' }
Now, the message will be logged even if the continuous-build task is considered up-to-date.