Up-To-Date Checking with Output FileTrees

When using a file tree to declare outputs, the up-to-date checker will consistently fail on the second run and succeed on the third run, if following a clean. After debugging into the source, it looks like the issue is with how previousExecution is set when history is loaded before execution.

In org/gradle/api/internal/changedetection/state/CacheBackedTaskHistoryRepository.java:findPreviousExection it looks like the previousExecution for history is selected based on the intersection of our currently declared outputs and those from previous runs. These outputFiles are resolved before the task is run to compare against those resolved before the previous run. However, after a clean the fileTree (unlike file/dir outputs) resolves to 0 files and that history entry will have the correct outputFilesSnapshot (set post execution) but the wrong outputFiles set.

When we run the second time, our outputFiles resolved before execution contains the appropriate files, which does not match the outputFiles from the first run, causing the previous execution (or in the example below since I nuked the history before the run, no execution) to be selected for comparison. The third time, we do have correct outputFiles in history, so the correct history is selected and up-to-date checking works as expected.

This becomes more obvious with output that is independent of input, as any clean/delete type behavior which correctly forces an execution will incur this second run penalty. I am currently working around this with directory outputs.

I have seen this behavior in both gradle 2.4 and 2.5 (did not test other versions).
See below output:

bash-4.3$ ls -a
.               ..              build.gradle
bash-4.3$ gradle --version

------------------------------------------------------------
Gradle 2.4
------------------------------------------------------------

Build time:   2015-05-05 08:09:24 UTC
Build number: none
Revision:     5c9c3bc20ca1c281ac7972643f1e2d190f2c943c

Groovy:       2.3.10
Ant:          Apache Ant(TM) version 1.9.4 compiled on April 29 2014
JVM:          1.7.0_76 (Oracle Corporation 24.76-b04)
OS:           Mac OS X 10.9.5 x86_64

bash-4.3$ cat build.gradle
task clean(type: Delete) {
    delete buildDir
}

task testTheory {
    def outFile = file("$buildDir/test.txt")
    outputs.files(fileTree(dir: buildDir, include: "*.txt"))

    doLast {
        if(!outFile.exists()) {
            outFile.parentFile.mkdirs()
        }
        outFile.withWriter("UTF-8") { writer ->
            writer << new Date() << System.lineSeparator()
        }
    }
}
bash-4.3$ gradle clean testTheory
:clean UP-TO-DATE
:testTheory

BUILD SUCCESSFUL

Total time: 1.936 secs

This build could be faster, please consider using the Gradle Daemon: http://gradle.org/docs/2.4/userguide/gradle_daemon.html
bash-4.3$ gradle testTheory --info
Starting Build
Settings evaluated using settings file '/master/settings.gradle'.
Projects loaded. Root project using build file '/Users/asteinfeld/other/testGradleBug/build.gradle'.
Included projects: [root project 'testGradleBug']
Evaluating root project 'testGradleBug' using build file '/Users/asteinfeld/other/testGradleBug/build.gradle'.
All projects evaluated.
Selected primary task 'testTheory' from project :
Tasks to be executed: [task ':testTheory']
:testTheory (Thread[main,5,main]) started.
:testTheory
Executing task ':testTheory' (up-to-date check took 0.045 secs) due to:
  No history is available.
:testTheory (Thread[main,5,main]) completed. Took 0.09 secs.

BUILD SUCCESSFUL

Total time: 1.942 secs

This build could be faster, please consider using the Gradle Daemon: http://gradle.org/docs/2.4/userguide/gradle_daemon.html
bash-4.3$ gradle testTheory
:testTheory UP-TO-DATE

BUILD SUCCESSFUL

Total time: 1.884 secs