Create multiple shadowJars for each flavor of application

I asked a Create multiple shadowJars for each flavor of application on SO but haven’t received any attention there. Even though shadowJar related questions are not precisely a core gradle issue, but I suspect the issue is with the way I’m trying to use gradle rather than the shadowJar plugin. Trying java plugin, for example runs into the same problem.


I’m experimenting with gradle and trying to setup a system that builds different flavors (brands) of an application, which differ by configuration mainly. What I have so far are two versions of the build scripts - both not working.

Version 1
First flavor specific resource folder flavor-res is added to sourcesets, which achieves overwriting some default resources. A task rule defines tasks for each flavor, which should (ideally) trigger build of the whole jar.

This works fine and generates the required jar, for one flavor at a time, like

gradle clean flavorOne 

but the shadowJar task runs only once, if I do

gradle clean flavorOne flavorTwo

Stripped down Script:

sourceSets {
    main {
        ...
        resources {
            srcDirs = ['src/main/resources', "${project.buildDir}/flavor-res/"]
        }
    }
}

shadowJar { classifier = 'SNAPSHOT' }

tasks.addRule("Pattern: flavor<Name>") { String taskName ->
if (taskName.startsWith("flavor")) {

    String flavorName = (taskName - "flavor")
    String flavorOutDir = "${project.buildDir}/${flavorName}"
    
    // Set output folder and jar name 
    task("${taskName}Configure") {
        outputs.dir(flavorOutDir)

        doFirst {
            archivesBaseName = flavorName
            project.buildDir = flavorOutDir
        }
    }

    // Copy res to folder used in sourcesets
    task("${taskName}CopyResources") {
        mustRunAfter = ["${taskName}Configure"]
        outputs.dir("${project.buildDir}/flavor-res")

        doFirst {
            copy {
                from "flavors/${flavorName}/"
                into "${project.buildDir}/flavor-res/"
            }
        }
    }

    shadowJar.mustRunAfter = ["${taskName}Configure", "${taskName}CopyResources"]

    // Define task that depends on shadowJar
    task(taskName, dependsOn: ["${taskName}Configure", "${taskName}CopyResources", 
         shadowJar]) {
        println "Configuring ${taskName}"
    }

}

Sensing that it probably doesnt work because the change detection somehow doesnt work, I tried an alternative approach. Here is a simplified version of script

Version 2

Modified the rule to define a shadowJar dynamic task for each flavor.

/* Removed sourceSets in this version */

shadowJar { classifier = 'SNAPSHOT' }

tasks.addRule("Pattern: flavor<Name>") { String taskName ->
if (taskName.startsWith("flavor")) {

    String flavorName = (taskName - "flavor")
    String flavorOutDir = "${project.buildDir}/${flavorName}"

    // Set resources for main sourceset
    task("${taskName}Configure") {
        outputs.dir(flavorOutDir)

        doFirst {
            archivesBaseName = flavorName
            sourceSets.main.resources.srcDirs = ['src/main/resources', "${flavorOutDir}/flavor-res"]
            project.buildDir = flavorOutDir
        }
    }

    task("${taskName}CopyResources") {
        outputs.dir("${flavorOutDir}/flavor-res")
        dependsOn "${taskName}Configure"

        doFirst {
            copy {
                from "flavors/${flavorName}/"
                into "${project.buildDir}/flavor-res/"
            }
        }
    }
    
    // This should shadowJar for each flavor - but generate jars dont have the required artifacts.
    task ("${taskName}Build", type: ShadowJar) {

        from sourceSets.main.output
        configurations = [ configurations.runtime ] 
        classifier = 'SNAPSHOT'

        dependsOn "${taskName}CopyResources"
    }

    task(taskName, dependsOn: ["${taskName}Build"]) {
    }
}
 }

However, now, the generated jars are malformed. The first flavor just gets the artifacts for main, but no showed jars. The second jar just has the manifest and nothing else.

What would be the correct way of achieving that? I would appreciate if someone could point out why what I’ve done so far behaves the way it does.