user991710 user991710 - 1 month ago 20
Groovy Question

Gradle: Mark a plugin subtask as non-runnable depending on environment or other property

I just tested out

Flyway
for DB Migration, and was pleasantly surprised at its capabilities and workflow.

However, there was one issue:
Flyway
can also perform a
clean
task which effectively drops all tables and procedures from the schema you are accessing.

This subtask should for example be runnable in a development environment, but not in a production environment: it is possible that someone misunderstands its meaning and kills the production DB by mistake.

Is it possible to disable (or simply remove) the plugin's subtask? I can do something like:

flywayClean {
enabled = project.hasProperty('devenv')
if(!enabled) {
throw new StopExecutionException("Disabled on production servers.")
}
}


But unfortunately this stops the build from completing. Ideally, I want to throw such an exception only when the task is specifically run, either from another task or from the command line.

Can I do this with Gradle?




EDIT:

Shortly after posting the question I noticed that the
flyway
configuration options also included a
cleanDisabled
option which can do exactly what I wished. So as to not have to delete the question though: is this possible in general, if the plugin itself does not have such an option?

Answer

Yes, each task in Gradle has a list of closures to be executed when the task is run. You can add any closure to the head of that list by adding a 'doFirst' closure.

Do not use the enabled variable but check directly on the property. Or else you will get

Cannot call Task.setEnabled(boolean) on task ':flywayClean' after task has started execution.

And throw a regular Exception if you want the complete run to fail, StopExecutionException will only stop the current task from executing the rest of the task closures with no error message.

flywayClean {
    doFirst{
        if(!project.hasProperty('devenv')) {
            throw new Exception("Disabled on production ervers.")
        }
    }
}

Alternative:

Another way to do this is to skip the task based on condition. Here you can change the enabled variable since we have not started the task execution. Remember to print a reason to the user so he understands why the task is skipped.

gradle.taskGraph.whenReady { taskGraph ->
    if (!project.hasProperty('devenv')){
        taskGraph.allTasks.find {it.name == 'flywayClean'}.each{
            println 'Disabling flywayClean due to missing property "devenv"'
            it.enabled = false
        }
    }
}