How to remove duplication in Gradle tasks?

Viewed 66

I have two tasks that launch a Java program. They are very similar. How do I remove the duplication between them, especially since I will almost certainly add more launchers to the project?

task(exportBallsThrownDetails, dependsOn: 'classes', type: JavaExec) {
    // https://github.com/gradle/gradle/issues/14363
    javaLauncher = javaToolchains.launcherFor {
        languageVersion = JavaLanguageVersion.of(17)
    }

    mainClass = 'ca.jbrains.wcbt.ExportBallsThrownDetails'
    classpath = sourceSets.main.runtimeClasspath
    workingDir = rootProject.projectDir
    args ''
}

task(exportGameSummaries, dependsOn: 'classes', type: JavaExec) {
    // https://github.com/gradle/gradle/issues/14363
    javaLauncher = javaToolchains.launcherFor {
        languageVersion = JavaLanguageVersion.of(17)
    }

    mainClass = 'ca.jbrains.wcbt.ExportGameSummaries'
    classpath = sourceSets.main.runtimeClasspath
    workingDir = rootProject.projectDir
    args ''
}
1 Answers

I learned that there is a newer way to declare tasks (I'm using Gradle 7.x) and that made it more obvious how to extract the duplicate code using my very rudimentary knowledge of Groovy.

The basic idea involves extracting a function that mutates the state of a Gradle Task object. This part is plain Groovy with knowledge of the Task interface.

/*
 * I am grateful to https://twitter.com/Neppord for suggesting this approach.
 * I used the guide at https://docs.gradle.org/current/userguide/more_about_tasks.html
 * and my rudimentary knowledge of Groovy, obtained in the early 2010s by spending
 * a few days working with Energized Work, thanks to https://www.linkedin.com/in/energizr
 */

def configureTaskToLaunchTheEntryPointInJava17UsingTheProjectRootAsItsWorkingDirectory(Task task, String entryPointClassName) {
    task.dependsOn tasks.classes

    // https://github.com/gradle/gradle/issues/14363
    task.javaLauncher = javaToolchains.launcherFor {
        languageVersion = JavaLanguageVersion.of(17)
    }

    task.mainClass = entryPointClassName
    task.classpath = sourceSets.main.runtimeClasspath
    task.workingDir = rootProject.projectDir
    task.args ''
}

tasks.register('exportBallsThrownDetails', JavaExec) {
    configureTaskToLaunchTheEntryPointInJava17UsingTheProjectRootAsItsWorkingDirectory(it, 'ca.jbrains.wcbt.ExportBallsThrownDetails')
}

tasks.register('exportGameSummaries', JavaExec) {
    configureTaskToLaunchTheEntryPointInJava17UsingTheProjectRootAsItsWorkingDirectory(it, 'ca.jbrains.wcbt.ExportGameSummaries')
}

I imagine that more refactoring is possible, but this sufficed for my purposes.

Related