I have a break in my build after migration to gradle 9, i.e. the current setup worked ok in gradle 8.14.3
The setup is
a configurable object is exposed to the build, it has various Propertyfields
it is used as an @Input to multiple tasks (which are marked as @Nested)
one property is @Optionaland the typical value is a value that is fetched from an external service
since it’s some work that requires external service calls, this is done via a task so we have a task that takes a @Nested as input and tries to mutate it
as mentioned, in gradle 8.14.3, this is fine but in gradle 9 it breaks because it appears that all inputs are finalised ahead of task execution
The alternatives I can think of are:
serialise that object to a file and then read that back in every other task that needs it (or perhaps create a different object to write to which is only referenced by tasks that I know run later)
shift this “task” to project.gradle.taskGraph.whenReady which does still allow the value to be mutated
Is there any other alternative way to mutate shared state (configuration) at task execution time?
I’d say your option one are the two options to use.
If the task result is to be reused across multiple build runs, write it to a file.
If it is only for the current build execution, use a shared build service as data store.
OK thanks, hadn’t thought of a build service for this.
Unfortunately it seems that neither option works in this specific because of another related problem
namely one such value is a version string so Provider<String> gets transformed to group:artifact:version which gets added to a configuration as a dependency. This configuration is used as an @InputFiles to another task and it seems that this configuration is also resolved early, before the taskGraph is even ready which means there’s no apparent way to obtain such a value beyond the configuration phase.
Any suggested workarounds to this other than having to do the lookup during configuration?
Maybe not really a clean solution, but what you observed is just partly correct.
If you enable configuration cache, then yes, dependency resolution and Provider evaluation is done at the end of the configuration phase and the result stored to the CC entry so that the work does not need to be done when the entry is reused.
But there is one exception, if the file collection or provider has a task dependency, then that means that the value depends on the task being executed first, so those are evaluated at execution time instead after the dependency task was executed.
So you can trick the mechanism by having a provider that is derived from a task provider. That task does not need to do anything, it is just important that the task dependency is there to delay the evaluation to the execution phase.
Whether there is maybe a cleaner solution I’m not sure without analyzing the situation in more detail.
I see what you mean now, I was using addLater anyway (had been surprised that was a separate API to add) with the provider being property based. This approach is still not configuration cache friendly though?