Gradle: Force Custom Task to always run (no cache)

25,016

You can achieve this by setting outputs.upToDateWhen { false } on the task.

This can be performed in your build.gradle file:

handleManagementArchive.outputs.upToDateWhen { false }

It can also be done in the constructor of your custom task.

ResolveProjectArchiveDependency() {
    outputs.upToDateWhen { false }
}
Share:
25,016
Jonathan Deon
Author by

Jonathan Deon

Professional Software Developer based in Boston, MA, USA. Professional experience with Scala, Spark, Java technologies, SQL/Databases, Javascript, front-end technologies (HTML/CSS), various web services.

Updated on June 13, 2020

Comments

  • Jonathan Deon
    Jonathan Deon almost 4 years

    I wrote up a custom Gradle task to handle some dependency resolution on the file system where the paths are configurable. I want tasks of this type to always run. It seems though they only run once, I'm guessing because the inputs never seem to change.

    I am aware of using configurations { resolutionStrategy.cacheChangingModulesFor 0, 'seconds' } to effectively disable the cache, but I only want it to apply to very specific tasks. Also am aware of --rerun-tasks command line prompt, which is also similar. Neither feel like the best solution, there must be a way to set this up properly in the custom task definition.

    Follows is my current implementation. I also had a version prior where the first 3 def String statements were instead @Input annotated String declarations.

    class ResolveProjectArchiveDependency extends DefaultTask {
        def String archiveFilename = ""
        def String relativeArchivePath = ""
        def String dependencyScope = ""
    
        @OutputFile
        File outputFile
    
        @TaskAction
        void resolveArtifact() {
            def arcFile = project.file("dependencies/"+dependencyScope+"/"+archiveFilename)
            def newArcFile = ""
    
            if(project.hasProperty('environmentSeparated') && project.hasProperty('separatedDependencyRoot')){
                println "Properties set denoting the prerelease environment is separated"
                newArcFile = project.file(project.ext.separatedDependencyRoot+relativeArchivePath+archiveFilename)
            }   else {
                newArcFile = project.file('../../'+relativeArchivePath+archiveFilename)
            }
    
            if(!newArcFile.isFile()){
                println "Warn: Could not find the latest copy of " + archiveFilename + ".."
    
                if(!arcFile.isFile()) {
                    println "Error: No version of " + archiveFilename + " can be found"
                    throw new StopExecutionException(archiveFilename +" missing")
                }
            }
    
            if(!arcFile.isFile()) {
                println archiveFilename + " jar not in dependencies, pulling from archives"
            } else {
                println archiveFilename + " jar in dependencies. Checking for staleness"
    
                def oldHash = generateMD5(new File(arcFile.path))
                def newHash = generateMD5(new File(newArcFile.path))
    
                if(newHash.equals(oldHash)) {
                    println "Hashes for the jars match. Not pulling in a copy"
                    return
                }
            }
    
            //Copy the archive
            project.copy {
                println "Copying " + archiveFilename
                from newArcFile
                into "dependencies/"+dependencyScope
            }
        }
    
        def generateMD5(final file) {
           MessageDigest digest = MessageDigest.getInstance("MD5")
           file.withInputStream(){is->
           byte[] buffer = new byte[8192]
           int read = 0
              while( (read = is.read(buffer)) > 0) {
                     digest.update(buffer, 0, read);
                 }
             }
           byte[] md5sum = digest.digest()
           BigInteger bigInt = new BigInteger(1, md5sum)
           return bigInt.toString(16)
        }
    }
    

    Here's an example of usage of the task:

    task handleManagementArchive (type: com.moremagic.ResolveProjectArchiveDependency) {
        archiveFilename = 'management.jar'
        relativeArchivePath = 'management/dist/'
        dependencyScope = 'compile/archive'
        outputFile = file('dependencies/'+dependencyScope+'/'+archiveFilename)
    }
    
  • Steinar
    Steinar over 5 years
    @Nick Thanks for the link to this interesting blog entry. As pointed out there, this is not the proper mechanism for rerunning tests. The question here though was about getting a custom task to always run. If the task uses other results from the build cache, those tasks will not be executed, but as far as I understand, this task will.
  • Ali Hidim
    Ali Hidim over 5 years
    Good point, if you're sure the task itself isn't cached then it should be okay. I'm never sure what tasks the cache will cover so I like to use something that works everywhere!