Task cache enabled with findbugs causes the build to fail

I have a project where we’ve enabled the task cache, and attempting to configure the findbugs plugin so that is also cached. This is a multi-project build. We’re using findbugs version 3.0.1 and Gradle version 3.5

$ ./gradlew :annotations:findbugsMain
Parallel execution is an incubating feature.
Build cache is an incubating feature.
Using directory (/Users/tjoneslo/.gradle/caches/build-cache-1) as local build cache, push is enabled.
:annotations:findbugsMain FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':annotations:findbugsMain'.
> No classes configured for FindBugs analysis.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 3.667 secs

If I make the findbugs tasks explicitly dependent on the project assemble task, I can see the :annotations:compileJava FROM-CACHE process, but it still fails with the same error. If I run it a second time from here, this now passes with :annotations:findbugsMain FROM-CACHE as I would expect.

Could you share your build script? If you don’t want it public, you can email me at sterling@gradle.com

For those of you playing along at home. The issue here seems to be that our build has some generated files (protopuf, META-INF) in the output directory. These files cause FindBugs to fail.

For example, if you have seen a similar error to this one in your build.

Done with analysis
The following errors occurred during analysis:
  Cannot open codebase filesystem: <Our repo>/<project>/.out/classes/main/META-INF/services/GeneratedFile.txt
    java.io.IOException: Wrong magic bytes of 636f6d2e for zip file <our repo>/<project>/.out/classes/main/META-INF/services/GeneratedFile.txt of 121 bytes

The google machine recommends adding the following to your build script:

tasks.withType(FindBugs) { task ->
   task.doFirst {
        def  ft = task.classes
        if (task.classes == null) {
            return
        }
        ft.exclude '**/generated/**'
        ft.exclude '**/META-INF/services/*'
        task.classes = files(ft.files)
    }
}

The problem, as explained to me, is the last line task.classes = files(ft.files) ends up loosing the dependency information the TaskCache needs to correctly process this task. The open question now is how do we get these to play nice together.

I think the issue you are seeing is not related to the task cache. You can find a different report here: https://github.com/gradle/gradle/issues/1094.

My problem is broader than the issue raised you raised. In addition to the zip file warning, which is annoying, we also have protobuf generated files in our output directory. We don’t want these generated class files checked by findbugs, they will never pass. So how do we exclude the generated files, which will cause findbugs to fail, from being processed by findbugs without loosing the dependency information?

I think the next Gradle release will fix the annoying non-fatal error message: https://github.com/gradle/gradle/pull/2102

The easiest way to exclude files will be to use FindBugs excludeFilter. I think you should be able to exclude the classes either by package (if the generated files are in the same packages) or by source location (if they’re all generated into an obvious “generated” directory).

NOTE: Unfortunately the following doesn’t work. Findbugs will still fail for every module of my project, the first time I try to clean build. I.e. having 3 module it will file one time per module and only the 4th time I run it I will have a SUCCESS. Going back to comment findbugs out from my build file.

I cannot upgrade to gradle 4.0 as some of the plugins I am using let the build fail. I solved the problem using ./gradlew --build-cache clean build

I forgot to mention that I am excluding some classes:

def fM = findbugsMain.classes
fM.exclude '/*.txt’
fM.exclude '
/*.json’
findbugsMain.classes = files(fM.files)

def fM = findbugsMain.classes
fM.exclude '*/.txt'
fM.exclude '*/.json'
findbugsMain.classes = files(fM.files)

This causes problems with your build with or without the build cache because fM.files builds the list of classes at configuration time. I think what you’ll see is…

  1. After a clean build (gradle clean && gradle findBugsMain), findBugsMain is skipped.
  2. If you run assemble, then remove a class and run FindBugs, findBugsMain will want to analyze the removed class file.
  3. If you run assemble, add a new class and run FindBugs, findBugsMain won’t analyze the new class until the next build.

With 4.0, you shouldn’t need to exclude files like that now.

Hi Sterling,

Thanks for your answer.

I have two problems.

  1. Can’t use gradle 4 yet. The build depends on some plugin that need to be updated(setTestingDir is now setTestingDirs or something like this).

  2. If I don’t use the exclude thing I am getting the zip error as shown in this post: https://github.com/gradle/gradle/issues/1094

So the exclude part will fix this first problem. Then I can see that once per project’s sub-module I get: " submodule-findbugs: No classes found". So it looks like is what you described in number 3. Because if the first time it fails on sub-module1, second time will perform analysis on sub-module1 and fail on sub-module2 and so on, till I have a success build with findbugs executed for all the sub-modules. As soon as I change a file in my changelist, it will start failing again from sub-module1, that’s why I thought the --build-cache thing would have fixed the problem.