Gradle 4 upgrade complex task.execute() replacement

216 Views Asked by At

I am currently upgrading from gradle4.5 to 6.5, the project i am working on has a stage.gradle with 200+ custom tasks called with .execute which has since been removed. I have seen many writeups on how to replace a .execute() with dependsOn/finalizedBy etc however this cant work for my usecase.

I have written code example of my tasks as follows

List listFromDB = []
task getListFromServer() {
    doLast{
        listFromDB << dataFromDB
    }
}

task generateConfig() {
    doLast{
        listFromDB.each { item -> 
        
            // code block 1
            
            def javaTask = task "taskName${item.name}"(type TaskJavaFile) {
                param1 = paramTemp1
                param2 = paramTemp2
            }
            javaTask.execute()
            
            // code block 2
            
            def task2 = task "taskName2${item.name}"() {

            // code block 3
            
            } task2.execute()
                    
            // code block 4
        }
    }
}

I have tried to replace this code by separating the code before and after each task.execute into its own tasks. However the way i have done this has added multiple repetition of listFromDB loops and i am unable to figure out how to call code within the generateConfig2Executor or generateConfig4Executor since the tasks are created at runtime but depondsOn must be used before task start (outside of doLast block).

List listFromDB = []

def TasksRunInOrder(Task... tasks) {
    for(int i =0; i < tasks.length-1; ++i) {
        tasks[i+1].mustRunAfter(tasks[i])
    }
}

task getListFromServer() {
    doLast{
        listFromDB << dataFromDB
    }
}

task generateConfig() {
    def listOfTasks = []
    listOfTasks << getListFromServer
    listOfTasks << generateConfig1
    listOfTasks << generateConfig2
    listOfTasks << generateConfig2Executor
    listOfTasks << generateConfig3
    listOfTasks << generateConfig4
    listOfTasks << generateConfig4Executor
    listOfTasks << generateConfig5
    dependsOn(TasksRunInOrder(*listOfTasks))
}
task generateConfig1() {
    doLast{
        listFromDB.each { item -> 
            // code block 1
        }
    }
}
task generateConfig2() {
    doLast{
        listFromDB.each { item -> 
            task.register("taskName${item.name}",TaskJavaFile) {
                param1 = paramTemp1
                param2 = paramTemp2
            }
        }
    }
}
task generateConfig2Executor() {
    doLast{
        def listOfTasks =[]
         listFromDB.each { item -> 
            listOfTasks << tasks.named("taskName${item.name}").get()
         }
         dependsOn(TasksRunInOrder(*listOfTasks))
    }
}
task generateConfig3() {
    doLast{
        listFromDB.each { item -> 
            // code block 2
        }
    }
}

task generateConfig4() {
    doLast{
        listFromDB.each { item -> 
            task.register("taskName2${item.name}") {
                // codeBlock 3
            }
        }
    }
}

task generateConfig4Executor() {
    doLast{
        def listOfTasks =[]
        listFromDB.each { item -> 
            listOfTasks << tasks.named("taskName2${item.name}").get()
        }
        dependsOn(TasksRunInOrder(*listOfTasks))
    }
}

task generateConfig5() {
    doLast{
        listFromDB.each { item -> 
            // code block 4
        }
    }
}
1

There are 1 best solutions below

0
On

It feels like Gradle might not be the ideal tool for your needs … Anyway, here’s a possible approach: we use Gradle to generate another Gradle build based on the items from the DB. The generated build is run right afterwards.

build.gradle

task getListFromServer() {
    ext.genBuildScript = new File(buildDir, 'myGeneratedBuild/build.gradle')
    doLast{
        // dummy items only to demonstrate:
        List listFromDB = [[name: 'Foo'], [name: 'Bar'], [name: 'Baz']]

        mkdir genBuildScript.parentFile
        genBuildScript.text = '''\
            task runAll() {}
            '''.stripIndent()

        listFromDB.each { item ->
            genBuildScript << """\
                task 'codeBlock1For${item.name}'() {
                    doLast{
                        // code block 1

                        // only to demonstrate:
                        println("\$delegate.name: $item.name")
                    }
                }

                // task type and config only commented for the demo:
                task 'taskName${item.name}'(/*type: TaskJavaFile */) {
                    dependsOn 'codeBlock1For${item.name}'

                    /* param1 = paramTemp1
                    param2 = paramTemp2 */

                    // only to demonstrate:
                    doLast{
                        println("\$delegate.name: $item.name")
                    }
                }

                task 'codeBlock2For${item.name}'() {
                    dependsOn 'taskName${item.name}'

                    doLast{
                        // code block 2

                        // only to demonstrate:
                        println("\$delegate.name: $item.name")
                    }
                }

                task 'taskWithCodeBlock3For${item.name}'() {
                    dependsOn 'codeBlock2For${item.name}'

                    doLast{
                        // code block 3

                        // only to demonstrate:
                        println("\$delegate.name: $item.name")
                    }
                }

                task 'codeBlock4For${item.name}'() {
                    dependsOn 'taskWithCodeBlock3For${item.name}'

                    doLast{
                        // code block 4

                        // only to demonstrate:
                        println("\$delegate.name: $item.name")
                    }
                }

                runAll.dependsOn 'codeBlock4For${item.name}'
                """.stripIndent()
        }

        // only needed if the running order of the tasks generated for the DB
        // items is relevant:
        for (int i = 1; i < listFromDB.size(); i++) {
            def prevItem = listFromDB[i - 1]
            def item = listFromDB[i]
            genBuildScript << """\
                tasks.'codeBlock4For${item.name}'.mustRunAfter(
                    'codeBlock4For${prevItem.name}')
                """.stripIndent()
        }
    }
}

task generateConfig(type: GradleBuild) {
    dependsOn getListFromServer
    dir =  getListFromServer.genBuildScript.parentFile
    buildFile = getListFromServer.genBuildScript
    tasks = ['runAll']
}

When Run

When the above build is run with ./gradlew --console=verbose generateConfig, it prints the following to the console:

> Task :getListFromServer

> Task :myGeneratedBuild:codeBlock1ForFoo
codeBlock1ForFoo: Foo

> Task :myGeneratedBuild:taskNameFoo
taskNameFoo: Foo

> Task :myGeneratedBuild:codeBlock2ForFoo
codeBlock2ForFoo: Foo

> Task :myGeneratedBuild:taskWithCodeBlock3ForFoo
taskWithCodeBlock3ForFoo: Foo

> Task :myGeneratedBuild:codeBlock4ForFoo
codeBlock4ForFoo: Foo

> Task :myGeneratedBuild:codeBlock1ForBar
codeBlock1ForBar: Bar

> Task :myGeneratedBuild:taskNameBar
taskNameBar: Bar

> Task :myGeneratedBuild:codeBlock2ForBar
codeBlock2ForBar: Bar

> Task :myGeneratedBuild:taskWithCodeBlock3ForBar
taskWithCodeBlock3ForBar: Bar

> Task :myGeneratedBuild:codeBlock4ForBar
codeBlock4ForBar: Bar

> Task :myGeneratedBuild:codeBlock1ForBaz
codeBlock1ForBaz: Baz

> Task :myGeneratedBuild:taskNameBaz
taskNameBaz: Baz

> Task :myGeneratedBuild:codeBlock2ForBaz
codeBlock2ForBaz: Baz

> Task :myGeneratedBuild:taskWithCodeBlock3ForBaz
taskWithCodeBlock3ForBaz: Baz

> Task :myGeneratedBuild:codeBlock4ForBaz
codeBlock4ForBaz: Baz

> Task :myGeneratedBuild:runAll
> Task :generateConfig

BUILD SUCCESSFUL in 984ms
2 actionable tasks: 2 executed