Unexpected UP-TO-DATE task while output file is missing

I stumbled upon a situation where the outputs.file defined in a task is missing but the task is still flagged as UP-TO-DATE.

The test case is here: https://gist.github.com/jandsu/978bd8a995c9c3b06de5

If you run it, you will see that it runs properly and as expected.

Now change the Java code and set

boolean skip = true;
gradle clean generate

==> the ‘generate’ task is run as expected

Again

gradle clean generate

==> the ‘generate’ task is not run. It says:

:generate UP-TO-DATE

This seems odd, because the ./build folder was completely removed. I understand that the task should have generated the output file. However, since it did not (obviously the real code is more complex and it seems that the file was not generated because of an error that was not properly detected).

This is unfortunate because in that case, there is no file I can remove anywhere to force the re-build (except the project .gradle or using --rerun-tasks).

Shouldn’t a defined but missing output file be triggering the execution of a task, just as for tasks that have no outputs definition?

I think this is by design.

For many tasks the outputs are not explicit, so for each task that runs, Gradle records the outputs files in the provided dirs or file paths to scan. If none exist, and the tasks was successful, then the set of outputs for the task is null.

In your case when you re-run the task, the inputs are the same, so Gradle correctly skips the task. There were no outputs missing the 2nd time, because the the first time it ran it did not create any output.

If you want to fix this, I would suggest you update the task to either;

  • return a non-zero exit code from the java class if the outputs are not created correctly, OR * manually add a check for the output files in the Gradle task, and throw and exception if they are not found’, OR * set the ‘upToDateWhen’ closure to ‘false’ for the task so it always runs.

Thanks for your reply! This is what I was scared of… that it was by design… My humble belief is that this is going to bite more often than it’s going to help… so that it is a bit of a questionable design choice. Especially since once your build has produced this state, entirely deleting the ‘build’ folder will not allow triggering the task again. I am scared that some people might lose confidence in the incremental builds…

To solve my issue, since I have no control on the Java code and I want to benefit from the great incremental build feature of Gradle, I only had the second option left.

Here is the corresponding excerpt… if it can help future readers of this post.

doFirst {
        generatedWsdlDir.mkdirs()
        wsdlFile.write ''
    }
    doLast {
        if (wsdlFile.text == '') {
            throw new TaskExecutionException(project.tasks[name], new Exception("WSDL generation failure: ${logFile.text}") )
        }
    }
2 Likes