Please note the “Update” section below.
I haven’t had much success with finding useful deployment strategies and/or scripts for Grails anywhere. The extent of the documentation I’ve been able locate for deployment simply tells you to create a WAR and upload it to the servlet container.
Not terribly helpful if you want to run a formal process.
So, for my Grails webapps, I came up with this. I create a file in the “gradle” directory named “deploy.gradle” containing the following:
buildscript { repositories { jcenter() } dependencies { classpath 'org.hidetake:gradle-ssh-plugin:2.9.0' } } apply plugin: 'org.hidetake.ssh' // the below is in it's own ext block because it can potentially be // overridden by .deployrc.gradle in the user's home directory, and the scmUser // might be required in the following ext block (where the repository is // set up) ext { scmUser = project.hasProperty('user') ? project.getProperty('user') : System.properties['user.name'] } // please note that the file must end in ".gradle" or Gradle won't know how // to process it, and you'll get a "String index out of bounds: 0" error def rcFile = new File("${System.properties['user.home']}/.deployrc.gradle") if (rcFile.exists()) { apply from: rcFile.absolutePath } ext { timeNow = new Date().format('yyyyMMddHHmmss') // TODO: the below should use a repository directly associated with the individual user scmRepository = "${project.scmUser}@my.site:/var/repos/${project.name}.git" runEnvironment = project.hasProperty('env') ? project.getProperty('env') : 'production' scmBranch = project.hasProperty('branch') ? project.getProperty('branch') : 'master' tmpDir = System.getProperty('java.io.tmpdir') + "${project.name}/${timeNow}" } apply from: "${project.projectDir}/gradle/deploy/${project.runEnvironment}.gradle" task deploy { group 'Remote Deployment' description 'Deploys a branch from your SCM to a target environment on a remote server' doLast { println "Deploying from branch ${project.scmBranch} to environment ${project.runEnvironment}" ssh.run { session(remotes.role('webserver')) { // upload the WAR to the target server(s) println 'Uploading WAR file' put from: "${project.buildDir}/libs/mercury.war", into: "mercury/mercury-${timeNow}.war" // stop Tomcat so we can get this party started println 'Stopping Tomcat' execute 'sudo service tomcat8 stop' // if a pre-existing link exists to "current", remove it println 'Symlinking' execute 'if [ -f mercury/mercury-current.war ]; then rm mercury/mercury-current.war; fi' // link our new WAR to the name "current" execute "cd mercury; ln -s mercury-${timeNow}.war mercury-current.war" // Tomcat doesn't clean up extracted WAR file directories, so we must flush out the /var/lib/tomcat8/webapps directory execute 'if [ -d /var/lib/tomcat8/mercury ]; then sudo rm -rf /var/lib/tomcat8/mercury; fi' // Fire tomcat back up println 'Starting Tomcat' execute 'sudo service tomcat8 start' } } } } task deployBuild << { println "Building WAR for ${project.runEnvironment} environment" exec { workingDir project.tmpDir environment 'TERM', 'dumb' // this prevents grails+gradle for displaying a second progress bar during the following invocation commandLine 'grails', "-Dgrails.env=${project.runEnvironment}", 'war', 'mercury.war' } } task deployCheckout << { println "Cloning ${project.scmRepository}#${project.scmBranch} for user ${project.scmUser} into ${project.tmpDir}" exec { commandLine 'git', 'clone', '-b', project.scmBranch, project.scmRepository, project.tmpDir } } task deployCleanup << { println "Removing temporary directory ${project.tmpDir}" exec { commandLine 'rm', '-rf', project.tmpDir } } deployBuild.dependsOn deployCheckout deploy.dependsOn deployBuild deploy.finalizedBy deployCleanup
Also in the “gradle” directory is a subdirectory named “deploy” where I have the files specific to the environments to which I can deploy, such as “staging.gradle”:
remotes { web { role 'webserver' host = 'my.site' user = 'webapps' identity = file("${System.properties['user.home']}/.ssh/webapps") } }
Now, you will need to make some modifications to your main “build.gradle” script. First, add in the SSH plugin dependency, immediately after the “buildscript” section:
plugins { id 'org.hidetake.ssh' version '2.10.1' }
And then in the area where you have all the “apply” instructions:
apply from: "${project.projectDir}/gradle/deploy.gradle"
Using the script above, I can deploy a particular branch from within my git repository to a specific environment thus:
gradle -Penv=staging -Pbranch=hotfix/1.2.3.001 deploy
It’s probably not perfect, but since I’m new to Gradle and Grails, I think it’s a pretty good start!
Update!
Alas the “org.hidetake.ssh” plugin has not kept up to date with the latest updates to SSH, and as such the above scripts no longer work, and I have abandoned any attempts to use Gradle to effect deployments. Instead, I have switched over to using Ansible to deal with all of this.