Observed with "org.springframework.boot" Gradle plugin, version 2.6.1
The bootBuildImage
Gradle task is lacking a proper up-to-date check and therefor the (pretty expensive) task is executed on every incremental build. For a working up-to-date check a task needs both inputs
and outputs
to be defined.
At the moment the outputs
property of bootBuildImage
task seems undefined.
As a first iteration towards fixing this, I added outputs.upToDateWhen { true }
to the task definition in my build script (Kotlin DSL), as in:
tasks.named<BootBuildImage>("bootBuildImage") {
outputs.upToDateWhen { true }
imageName = "someDockerImageName"
}
With outputs.upToDateWhen { true }
added, the tasks up-to-date check will only depend on the inputs.
But from this point on the bootBuildImage
Gradle task fails with the error:
Execution failed for task 'bootBuildImage'.
> Input property 'archiveFile' with value '<path to build folder>/libs/sample-0.0.1-SNAPSHOT.jar' cannot be serialized.
I checked the BootBuildImage
class and noticed the archiveFile
and the deprecated jar
@Input
properties being of type org.gradle.api.file.RegularFileProperty
, a type that is not Serializable and is fitted with a note in its Javadoc that the interface is not intended for implementation by build script or plugin authors.
The properties should be changed to a serializable type, to make the input matching functionality of Gradle work properly.
Conclusion:
- without outputs definition, Gradle does not even try to serialize the inputs, it does presume the task not up-to-date and it will always perform the task
- with outputs defined, Gradle fails to serialize the input properties because they are of an non-Serializable type
- instead of outputs.upToDateWhen { true }
the outputs definition should better be some smarter, something like: query the docker daemon and then the task is up -to-date if an image is found with the same name and image digest as the one produced in the last task run. For this, the task should probably keep track of the digest of its produced docker image in a build output file to match it against the queried digest.
Comment From: wilkinsona
The current behaviour is intentional as implementing an up-to-date check for image building is prohibitively complex. In addition to recording the SHA and querying the daemon to see if the image is present, we also have to know if the inputs and, crucially, the things to which they point, are unchanged and would produce the same output. For example, the builder
may be unchanged from a Gradle property perspective but when used would be resolved to a builder image with a different SHA than that which was used in the previous invocation. Furthermore, even if the builder image itself is unchanged, we have no way of knowing how repeatable it may be in terms of its own implementation, the build packs that it uses, etc.
In short, it would be fairly easy to implement up-to-date checks that will occasionally produce a false positive. Implementing them accurately is much harder and, in some cases, may not even be possible given the limited information that we would have available. I think it's unlikely that we'll ever be able to implement a 100% accurate up-to-date check for image building. It may be that we can modify things a bit so that you could opt in somehow, providing extra information to remove some unknowns and, perhaps, also accept some caveats and pitfalls.
I'll flag this for discussion at a team meeting so that we can consider our options.
Comment From: wilkinsona
We've just discussed this and agreed that we cannot provide up-to-date checks out of the box for BootBuildImage
. We also decided that we do not want to encourage users to try to add them themselves as the risk of them shooting themselves in the foot is too high. Thanks anyway for the suggestion.
Comment From: m-koops
Thank you for your extended response and considering the enhancement/fix.
When writing my report I could not imagine that the problem had so much layers. So I've learned another time that no simple problems exist in IT.