No source for Zip task

I would like to create a dynamic Zip task taking the distributions of 2 subprojects in order to merge them

Here is an extract of the code I use

TaskProvider createDistribution(String proj) {
    // *** Distribution task ***
    String distribTaskName = "distribute${proj}";
    def u = tasks.register (distribTaskName, Zip) {
        doFirst {
            println "task for ${proj}"

            //Get archive from project
            def projFile = tasks.getByPath(":${proj}:distZip").outputs.files.singleFile
            def projTree = zipTree(projFile)

            //Get application archive
            def appliFile = tasks.getByPath(":application:distZip").outputs.files.singleFile
            def appliTree = zipTree(appliFile)

            from projTree.files
            from appliTree.files

            include '**/*.jar'
            archiveName "${distTask.baseName}.zip"
            duplicatesStrategy 'exclude'
        doLast{ println "Merging ${projFile.absolutePath} & ${appliFile.absolutePath} into ${archivePath}" }
    return u

def program = ["proj1", "proj2", "proj3"]
distributedProjects.each {
   TaskProvider dis = createDistribution (it)
     dis.configure {
        dependsOn tasks.getByPath(":application:distZip")
        dependsOn tasks.getByPath(":$proj:distZip")

proj1, proj2 and proj3 are subprojects of my main project where I defined this above code.

My issue is, as written above, task does not run as no source is identified.

Skipping task ‘:distributeproj1’ as it has no source files and no previous output files.

If I remove the doFirst block in createDistributionFunction, configuration fails as the distributionZip is not already created.

Could not create task ‘:distributeproj1’.
Cannot expand ZIP ‘[proj1 zip path]’ as it does not exist.

How can I handle this issue ? I’m trying to force the task to get over the “no source” but I don’t find any tips on forum.

Hi Pierre,

the reason why your task is not having any sources is since all the configuration happens during execution in the doFirst block. The configuration should happen at configuration time.
So you need to move out the configuration from the doFirst block (i.e. things like from, include, archiveName, etc.). When doing so, make sure you don’t actually do the work during configuration time by wrapping the arguments to the from in closures, so that they are evaluated lazily.

You can find an example of such lazy configuration of the copy task in the user guide here:


Hi Stefan,

My issue is based on what you call “the lazy configuration”.
I don’t understand how I can reference a directory or a file produced by a task executed before.


  • task1 depends on task2 and
  • Task2 produces a directory “$buildDir/dir1”

How should I reference dir1 in task1 ?
Because, if I write from { zipTree("$buildDir/dir1") }, the configuration fails as this directory not already exist.

So, as you said, you need to make sure that task1 depends on task2. I think you are already adding the task dependency.

Then you can reference the output directory of the other task in from in a closure. For example you can do:

task task1(type: Copy) {
    dependsOn task1
    from {

Referencing the path should work as well. I guess the problem in your example is that you want to reference the buildDir in the other sub-project, not the one in the current sub-project.

Thank you very much Stefan ! It works.

It seems to have a different behaviour according from content is written into a closure or not.