Search code examples
javascriptgradlesaga

How to invoke arbitrary method from gradle?


Was trying to call out to the Saga Javascript code coverage from Gradle. After a long time playing with it, I was finally able to get it working. However, I am new to gradle and don't know if the way I did it makes the most sense or not! It seems like there might be quite a few ways to do this, so I thought I would post what I did here in the hopes that I might learn if this way was okay or if there was a better way.

After downloading the saga-core from maven central, it turns out that there is no Java "main". So I didn't think I could easily use JavaExec. It looked to me that I needed to create a Java object, set some params, and call the "run" method provided.

Here is the final build.gradle I ended up with:

apply plugin: 'groovy'

buildscript {    
    repositories {
        mavenCentral()
    }

    dependencies {
        // add the jar file withe the code you want to execute to gradle's classpath
        classpath 'com.github.timurstrekalov:saga-core:1.1.2'
    }
}

configurations {
    compile
    codeCoverageTask
}

dependencies {
    groovy localGroovy()
    codeCoverageTask 'com.github.timurstrekalov:saga-core:1.1.2'
}

// I thought this was simple and made sense to be co-located here rather than
// another file...
// getting the imports to compile requires adding the "buildscript" section above
import java.io.File
import com.github.timurstrekalov.saga.core.CoverageGenerator

class SagaCoverageTask extends DefaultTask {
    def outputDirectory
    def baseDirectory
    def includes = 'my_includesPattern_here'
    def excludes = 'my_excludesPattern_here'
    def noInstrumentPatterns = [ 'my_noIntrumentPatterns_here' ]

    @TaskAction
    def runCoverage() {
        // check these were set correctly!
        println outputDirectory
        println 'baseDir' + baseDirectory

        // create an instance of the object
        CoverageGenerator generator = new CoverageGenerator(baseDirectory, includes, excludes, outputDirectory)   
        generator.noInstrumentPatterns = noInstrumentPatterns
        // there are params, but they would be handled in the same way if needed
        generator.run()   // invoke the arbitrary method
    }
}

task genCodeCoverage(type: SagaCoverageTask)  {
    // needed the values of task properties, so these are set here
    outputDirectory = new File('' + reportsDir + '/coverage')
    baseDirectory = new File('' + projectDir + '/src')   
}

Solution

  • Looks like a decent start. File objects should generally be created with the project.file() method because it handles relative paths better than new File() (although it's not a problem in this particular case). For example: file("$reportsDir/coverage").

    If the task class grows bigger or you want to reuse it across projects/builds, you should move it somewhere else (e.g. into buildSrc) and add some test coverage.

    By annotating the task class properties with @InputDirectory, @OutputDirectory, etc. you can make it so that the task will only run if some input has changed or previously generated output isn't available anymore. This can speed up the build.