The Fine-Line Between Tasks, Groovy Method and Shell Scripts?

Hello :slightly_smiling:

I did some research, but I couldn’t find a clear answer to my question. Most examples I saw are not very Task oriented, but rather use the build-in Gradle tasks. I’m not very clear where the fine-line between Gradle and things like Shell-scripts passes. Here is some detailed background to explain the though process, and hopefully you will bear with me the long post :blush:

Our Test environment require some manual tweaks like direct modifications to the database, merging of couple of files, running some shell/cmd commands and so on. I start by implementing each atomic action as a task. This worked pretty well, but I didn’t like the extensive usage I’m doing with the Exec build in task, not to mention I have to use a switch case in every task as every cmd command required ‘cmd /c’ as prefix while the linux shell command do not. So this is how the original task looked like:

task installGems(type: Exec) {

    switch (operationSystem) {
        case 'windows':
            commandLine  'cmd', 'c', 'bundler install'
            break

        case 'linux':
            commandLine 'bundler install'
            break
    }
}

This was getting repeated over and over, so I created a Groovy method that builds the command line, like so:

def buildCommandLine(command) {
    switch (operationSystem) {
        case 'windows':
            'cmd /c ' + command
            break

        case 'linux':
            // Do nothing
            break
    }
}

That way I could avoid the switch case in each task and just use:

commandLine(buildCommandLine('bundler install'))

This seems to be like a decent solution, but after a while - our build.gradle file got too big to handle and we decided to split it into two files. I figured I can’t share a groovy method across .gradle files, and after some research I moved this method into the BuildSrc directory. But because moving code to BuildSrc was so easy, I asked myself why not do the same for other Tasks? At the current design I have many tasks that I do not wish to expose with Gradle as they are a bit too low-level. I figured I can technically encapsulate all those ‘help methods’ in a groovy code, and have my primary tasks call those when needed.

This cause some other design issues . For example, I can’t use the ‘Exec’ task in a groovy code, so if I want to execute a command line I need to use Groovy code:

Runtime.getRuntime().exec

But then, why no implement a single Groovy method that runs command line based on the OS and just call it from my Gradle tasks instead of using the ‘Exec’ pre-defined task? Or maybe I’m doing it all wrong and I should just put everything on a big CMD or Shell script and call those from my tasks? But then I was under the impression Gradle was here to stop using those OS specific shell scripts. This all feels… unnatural.

So I figured I’m probably doing something conceptually wrong here and came here to share my thoughts.

Hopefully, someone can share some Gradle wisdom with me. Thanks for reading!