Task considered up-to-date even if it (mistakenly) doesn't produce output

Consider the following task:

task foo {
   doLast {
  // Oops: forgot to implement any execution steps

Assume that input.txt exists, and output.txt doesn’t exist. The first time this runs, it isn’t considered up-to-date, so the task executes (although it does nothing). The second time it runs, it is considered up-to-date, and so is skipped.

This is a pain, because if I later notice my mistake and complete the implementation, it still won’t execute. The only workaround I can find is to delete the project cache directory.

Is this a bug, or expected behaviour?

(This behaviour is observed with both Gradle 1.10 and 1.11 (haven’t tried earlier versions).)

The biggest problem here is that the task action isn’t currently recognized as an input. As a consequence, changing the task action doesn’t make the task out-of-date. This is a known limitation.

Perhaps one could also fail if the declared output file isn’t produced. I’m not entirely sure why this isn’t done, and how useful it would be.

You can force the task to rerun with ‘–rerun-tasks’.

Is there a reason not to make the build.gradle file itself an implicit inputs for all tasks? If the build file has changed, then unless you have some positive information, like a finer grained task action as inputs, then I don’t see how gradle can make the assumption that up to date checks are even meaningful and so should always rebuild. I would prefer gradle to be conservative and to err on the side of a correct rebuild with the possible cost of running tasks that were up to date as opposed to taking the chance on skipping a task that really did need to be run.

As a defensive workaround, is there any problem with doing

inputs.file ‘build.gradle’

I’m curious about this as well. It would seem that re-defining a task should cause the task to be considered out of date. Having to remind everyone to re-run tasks that have changed is very error prone.

FWIW – the workaround suggested by Philip does seem to accomplish the general goal (though obviously it can trigger too often since you may make changes that don’t impact the task definition, that’s better than the alternative).