How to properly expose files generated by a task?


Could you advise what is the right way to expose files generated by a task? I tried an approach below (kotlin DSL) and it didn’t work:

abstract class Producer : DefaultTask() {
    abstract val targetFiles: ListProperty<File>

    fun printMessage() {
        val files = listOf(
        project.logger.lifecycle("exposing ${files.size} files: ${files.joinToString { it.canonicalPath }}")

abstract class Consumer : DefaultTask() {

    abstract val inputFiles: ListProperty<File>

    fun processFiles() {
        val files = inputFiles.get()
        project.logger.lifecycle("consuming ${files.size} files: ${files.joinToString { it.canonicalPath }}")


tasks.register<Consumer>("consumer") {
    inputFiles = (tasks.getByName("producer") as Producer).targetFiles.get()


./gradlew producer

> Task :producer FAILED
exposing 2 files: /Users/denis/Downloads/tmp/build/file1, /Users/denis/Downloads/tmp/build/file2

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':producer'.
> The value for task ':producer' property 'targetFiles' is final and cannot be changed any further.

It seems that such task output property is assumed to be configured by script author in build script and then its value should be used by the task itself. However, my goal is to expose files created by the task and use them as another task’s input.

Declaring the outputs at task execution is too late.
Gradle needs to know the inputs and outputs before the task is executed and even if the task is not executed, to find out whether the task maybe is up-to-date and does not even need to be executed.

If you can only know at task execution time which files will be generated, use an @OutputDirectory DirectoryProperty instead as output and accordingly as input.

thanks, Björn! Does it also mean that there is no way to ‘dynamically’ expose files generated by task? (not via configurations, artifacts, etc)

If you have an output directory into which you generate the files in question, that is the dynamic expose you ask for, isn’t it?

If the task cannot say up-front which exact files it is going to generate, I don’t think there is another sane way to do it.