Search code examples
gradlegradle-kotlin-dsl

How to hide gradle task?


I have defined few custom build tasks, which set few configuration properties and generate builds for different environments. Tasks are below:

val buildStage by tasks.registering {
    doFirst {
        val profile = "stage"
        println("spring.profiles.active = $profile")
        System.setProperty("spring.profiles.active", profile)
        buildDir = File("${rootDir}/build/${profile}")
        tasks.withType<ProcessResources> {
            exclude("**/*.properties")
        }
    }
    finalizedBy(tasks.getByName("build"))
}

val buildProd by tasks.registering {
    doFirst {
        val profile = "prod"
        println("spring.profiles.active = $profile")
        System.setProperty("spring.profiles.active", profile)
        buildDir = File("${rootDir}/build/${profile}")
        tasks.withType<ProcessResources> {
            exclude("**/*.properties")
        }
    }

    finalizedBy(tasks.getByName("build"))
}

How can I ensure that gradle build command is not directly invokable?

Is it possible to do something like:

tasks.getByName("build") {
    doFirst {
        if (System.getProperty("spring.profiles.active").isNullOrBlank()) {
            println("task not allowed")
            exitProcess(1)
        }
    }
}

Solution

  • The problem with your current approach is that the doFirst closure of your build task will still execute after the tasks build depends on (e.g. assemble, test, jar ...), causing Gradle to fail when all the actual work is already done.

    You may check whether the task build was called from the command line using the example below, but all these approaches to disable a task are just ugly hacks.

    if (gradle.startParameter.taskNames.contains("build") {
        throw new GradleException("Task 'build' must not be called directly");
    }
    

    Instead, you should analyze your project and check which tasks actually require the configuration properties that belong to the different profiles. Afterwards setup your tasks and connect them using dependsOn / finalizedBy / mustRunAfter in a way that the build only fails when it needs to (because properties are not defined) and operates as expected otherwise.

    The task build is the default task for the majority of Gradle projects. Your approach may confuse other developers interacting with your project, as calling ./gradlew build is probably the very first thing to do on a new project.