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')
}
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.