Gradle continuous build behaves odd

190 views Asked by At

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

1

There are 1 answers

3
Anish B. On BEST ANSWER

Few points to mention:

  • doLast is an action to a task. It runs at the end of the task.

  • Your gradle task continuous-build depends on the compileJava task via this line dependsOn tasks.compileJava which means that if compileJava task fails, i.e, compilation of Java classes fail then doLast task action will not be executed from your continuous-build task. So, that's why the file is not created/updated.

  • This line onlyIf { !compileJava.state.upToDate } from the continuous-build gradle task tells that any task action will be executed only if the compileJava task state is changed. In simple words, if you do a code change in your Java classes, then doLast action will be executed from your continuous-build task, otherwise it will be skipped from the execution.

So, your doLast action depends on these two lines dependsOn tasks.compileJava and onlyIf { !compileJava.state.upToDate } completely.

To demonstrate, I have updated your gradle task a little bit to explain.

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");
        def created = file.createNewFile();
        logger.lifecycle("File created status :" + created);
        file.setLastModified(Instant.now().toEpochMilli())
        logger.lifecycle("Last modified timestamp of the file: " + file.lastModified());
        logger.lifecycle("This message is never seen")
    }
} 

First time Execution:

enter image description here

enter image description here

Second time Execution (with no change in Java classes):

doLast task action will not be executed as explained in the point (because of this line onlyIf { !compileJava.state.upToDate }).

enter image description here

Third Time Execution (with the modification in a Java class):

The doLast task action will be executed and this will trigger the file to be updated instead of creation although the timestamp will be changed this time.

enter image description here

Fourth Time Execution (with the modification in a Java class with an error):

The doLast task action will not be executed due to the compilation error in one of the Java classes detected by the compileJava task and the continuous-build task depends on compileJava.

enter image description here

Fifth time Execution (with no error, i.e, reverted the changes): In this case, the third time execution scenario is repeated again.

enter image description here