Search code examples
filegradleorder-of-execution

How do I check the current contents of a file in Gradle


First and formost... I'm new to Gradle. Having said that, I love it. Unfortunatly, I've hit a snag. I have a series of tasks that are part of a deploy process. One (buildProject) Calls a shell script, that as part of it's process updates a REVISION file with the new "version". After that the deployToRemote task is called to deploy the latest version to the server. It calls getCurrentVersion to read the latest version from the REVISION file. All of these tasks are outlined below. The problem is that it appears that getLatestVersion is called first in spite of proper mustRunAfter statements, as it always reads in the "PRE" buildProject version listed in the REVISION file. How can I make sure that getLatestVersion reads the file after buildProject runs?

Here are the tasks:

buildProject:

task buildProject(type:Exec) {
  def command = ['./make-release', '-f']
  if (deployEnvironment != 'stage') {
    command = ['./make-release', "-e ${deployEnvironment}"]
  }

  commandLine command
}

deployToRemote

task deployToRemote(dependsOn: 'getCurrentVersion') {
  doLast {
    def version = tasks.getCurrentVersion.hash()
    println "Using version ${version}"
    println "Using user ${webhostUser}"
    println "Using host ${webhostUrl}"
    ssh.run {
      session(remotes.webhost) {
        put from: "dist/project-${version}.tar.gz", into: '/srv/staging/'
        execute "cd /srv/staging; ./manual_install.sh ${version}"
      }
    }
  }
}

getCurrentVersion

task getCurrentVersion {
  def line
  new File("REVISION").withReader { line = it.readLine() }
  ext.hash = {
    line
  }
}

My build.gradle file has this at the end:

deployToRemote.mustRunAfter buildProject
getCurrentVersion.mustRunAfter buildProject

The REVISION file looks like this;

1196.dev10
919b642fd5ca5037a437dac28e2cfac0ea18ceed
dev

Solution

  • Gradle build has three phases: Initialization, Configuration and Execution.

    The problem you faced is that code in getCurrentVersion is executed in the configuration phase. In the configuration phase the code in tasks is executed in the order of their definition and dependencies are not taken into account.

    Consider this example:

    task second(dependsOn: 'first') {
        println 'second: this is executed during the configuration phase.'
        doLast {
          println 'second: This is executed during the execution phase.'
        }
    }
    
    task first {
        println 'first: this is executed during the configuration phase.'
        doLast {
          println 'first: This is executed during the execution phase.'
        }
    }
    
    second.mustRunAfter first
    

    If you execute gradle -q second you'll get:

    second: this is executed during the configuration phase.
    first: this is executed during the configuration phase.
    first: This is executed during the execution phase.
    second: This is executed during the execution phase.
    

    To fix your script you need to put the code into doLast like this:

    task getCurrentVersion {
      doLast {
         def line
         new File("REVISION").withReader { line = it.readLine() }
         ext.hash = {
           line
         }
      }
    }