Using Gradle Cargo plugin to deploy to multiple environments

Deb Dey picture Deb Dey · Feb 12, 2014 · Viewed 7.6k times · Source

I am trying to have multiple Gradle tasks in my build.gradle file to deploy a war to different environments. I want to be able to have a deployToLocal task along with deployToQA and deployToDev, after a war file has been generated.

Of course, this means that I want to stop the Tomcat service, delete existing war files and expanded wars in the Tomcat webapps directory, copy the war, and restart Tomcat again to deploy the service.

My question is twofold:

  1. I have specified the location of the war that I will be copying along with all the hostname, port and username/ password information. My question is: how do I specify which location in the remote environments (directory structure) the war should be copied into?
  2. For the end I am trying to achieve, is this the correct way to move forward?

My code so far:

task deleteDirLocalhost(type: Delete){
    //delete fileTree(dir: local_Tomcat_webapps_dir)
    delete fileTree(dir: 'C:\\Tomcat7.0\\webapps')
}

task deployToLocal{
    dependsOn war, tomcatStop, deleteDirLocalhost
    println "Starting Cargo"
    println "Using war from: $warLocation"              // warLocation is a variable defined in gradle.properties file

    cargo {
        containerId = 'tomcat7x'
        port = TomcatPortLocalhost as Integer
        local {
            homeDir = file(local_Tomcat_webapps_dir)    // local_Tomcat_webapps_dir is a variable defined in gradle.properties file
        }

        deployable {
            file = file(warLocation)            // This is where I specify where the war file is to be copied from. In the 'local' section, I have specified 'homeDir' as the location where I want this file to be copied to. Is that correct usage?
            context = 'web-application'
        }
    }
    tomcatRunWar
}

task deployToQA{
    dependsOn war, tomcatStop, deleteDirQA
    println "Starting Cargo"
    println "Using war from: $warLocation"

    cargo {
        containerId = 'tomcat7x'
        port = TomcatPortQA as Integer
        remote {
            hostname = server_address_qa        // all these are variables defined in the gradle.properties file
            username = username_qa
            password = password_qa
        }

        deployable {
            file = file(warLocation)           // This is where I specify the location of the war file. How do I specify in the 'remote' section in which directory in the server this file should be copied to?
            context = 'web-application'
        }
    }
    tomcatRunWar
}

task deployToDev{
    dependsOn war, tomcatStop, deleteDirDev
    println "Starting Cargo"
    println "Using war from: $warLocation"

    cargo {
        containerId = 'tomcat7x'
        port = TomcatPortDev as Integer
        remote {
            hostname = RT3_webapp_address_dev
            username = username_dev
            password = password_dev
        }

        deployable {
            file = file(warLocation)
            context = 'web-application'
        }
    }
    tomcatRunWar
}

I want to call task gradle deployToLocal and expect the behavior that local Tomcat instance is stopped, the war is copied to my Tomcat\webapps folder (with any previously existing files or folders in the same folder having been deleted), and then the Tomcat service is started again and the war is deployed.

This doesn't work, and obviously I am missing something. I also scoured the web for a solid fully-worked-out example of an implementation of the gradle cargo/ tomcat plugin without much luck. Could someone please point me in the right direction?

Thank you in advance for any help!

Answer

Benjamin Muschko picture Benjamin Muschko · Feb 15, 2014

The Tomcat and the Cargo plugins are two distinct plugins and do not work with one another in the way your tried to solve your problem. The Tomcat plugin only provides an in-memory, embedded container for Tomcat (meaning you don't have to have a local installation) whereas Cargo requires you to either point to a local container installation or a remote URL. For your purposes, I'd exclusively go with the Cargo plugin.

All the code you define in your tasks is executed during the configuration phase. Using the DSL of the Cargo plugin in multiple tasks will override the previous declaration. For a better understanding on execution vs. configuration phase, I'd recommend checking the Gradle online user guide. Keep in mind that Cargo in general does not provide management functionality for remote containers (starting/stopping). This was also mentioned in the README file of the plugin. If you want to do something like that, you'd have to write tasks that run remote SSH commands.

Apart from not being able to start/stop containers with the plugin, your actual problem can be solved in multiple ways. Either you use the Cargo plugin DSL and assign the remote hostname, port, username, password dynamically or you create multiple tasks. It seems like you still want to create multiple tasks for each environment. For that apply the cargo-base plugin and create two tasks of type CargoDeployRemote, one for your dev and one for your QA environment. In that scenario you are not using the DSL exposed by the plugin. Of course you'd create another task for your local Tomcat installation as well with the appropriate task type.

apply plugin: 'cargo-base'

import com.bmuschko.gradle.cargo.convention.Deployable
import com.bmuschko.gradle.cargo.tasks.remote.CargoDeployRemote

task deployToQA(type: CargoDeployRemote) {
    containerId = 'tomcat7x'
    hostname = server_address_qa
    port = TomcatPortQA as Integer
    username = username_qa
    password = password_qa
    deployables = [new Deployable(file: file(warLocation), context: 'web-application')]
}