added gradle dependencies for jacoco tasks

This commit is contained in:
adamopolous 2019-11-07 13:17:06 -05:00
parent 05ee2c14b9
commit 2de421d3f9
5 changed files with 70 additions and 254 deletions

View file

@ -1,6 +1,6 @@
apply from: "$rootProject.projectDir/gradle/distributableGhidraModule.gradle" apply from: "$rootProject.projectDir/gradle/distributableGhidraModule.gradle"
apply from: "$rootProject.projectDir/gradle/javaProject.gradle" apply from: "$rootProject.projectDir/gradle/javaProject.gradle"
apply from: "$rootProject.projectDir/gradle/jacocoProject.gradle" //apply from: "$rootProject.projectDir/gradle/jacocoProject.gradle"
apply from: "$rootProject.projectDir/gradle/javaTestProject.gradle" apply from: "$rootProject.projectDir/gradle/javaTestProject.gradle"
apply plugin: 'eclipse' apply plugin: 'eclipse'

View file

@ -1,6 +1,5 @@
apply from: "$rootProject.projectDir/gradle/distributableGhidraModule.gradle" apply from: "$rootProject.projectDir/gradle/distributableGhidraModule.gradle"
apply from: "$rootProject.projectDir/gradle/javaProject.gradle" apply from: "$rootProject.projectDir/gradle/javaProject.gradle"
apply from: "$rootProject.projectDir/gradle/jacocoProject.gradle"
apply from: "$rootProject.projectDir/gradle/processorProject.gradle" apply from: "$rootProject.projectDir/gradle/processorProject.gradle"
apply plugin: 'eclipse' apply plugin: 'eclipse'

View file

@ -6,11 +6,18 @@
file: file:
apply from: "$rootProject.projectDir/gradle/jacocoProject.gradle" apply from: "$rootProject.projectDir/gradle/jacocoProject.gradle"
IMPORTANT!!!!! If you include this script in your project, you must have source
sets for both test and test.slow in your project, or jacoco will
fail.
*****************************************************************************************/ *****************************************************************************************/
// Apply jacoco plugin to subprojects. This will create coverage files for each java Test task. // Apply jacoco plugin to subprojects. This will create coverage files for each java Test task.
if (rootProject.ext.jacocoEnabled) { apply plugin:'jacoco'
apply plugin:'jacoco'
dependencies {
jacocoAnt 'org.jacoco:org.jacoco.ant:0.8.2'
jacocoAgent 'org.jacoco:org.jacoco.agent:0.8.2'
} }
// Clean any jacoco files that may have been left behind previously. // Clean any jacoco files that may have been left behind previously.
@ -26,4 +33,3 @@ clean {
file("$rootProject.buildDir/reports/jacoco/").deleteDir() // delete jacocoReport, jacocoBranchReport output file("$rootProject.buildDir/reports/jacoco/").deleteDir() // delete jacocoReport, jacocoBranchReport output
} }
} }

View file

@ -1,245 +1,56 @@
// Used for jacocoBranchReport task. Cmd line param to specify branch origin. Defaults to master.
def jacoco_origin = project.hasProperty('jacoco.origin') ? project.getProperty('jacoco.origin') : "master"
import groovy.io.FileType; import groovy.io.FileType;
// 'jacocoEnabled' will enable jacocoMerge, jacocoBranchReport and jacocoReport if these tasks are
// specified on the cmd line.
// Applying jacoco plugin will create coverage files for each java Test task. This extra analysis
// slows down the overall Test task, so only enable jacoco when specified on the cmd line.
rootProject.ext.jacocoEnabled = (rootProject.gradle.startParameter.taskNames.contains('jacocoMerge') ||
rootProject.gradle.startParameter.taskNames.contains('jacocoBranchReport') ||
rootProject.gradle.startParameter.taskNames.contains('jacocoReport'))
if (project.jacocoEnabled) { apply plugin:'jacoco'
// jacoco plugin needs to be in the root-level to get the jacocoAnt and jacocoAgent dependencies below dependencies {
// and any subproject (via jacocoProject.gradle)
apply plugin:'jacoco'
// set classpath dependency for root-level tasks defined in this file.
dependencies {
jacocoAnt 'org.jacoco:org.jacoco.ant:0.8.2' jacocoAnt 'org.jacoco:org.jacoco.ant:0.8.2'
jacocoAgent 'org.jacoco:org.jacoco.agent:0.8.2' jacocoAgent 'org.jacoco:org.jacoco.agent:0.8.2'
} }
def String jacocoRootExecPath = "$buildDir/jacoco/jacocoMerge.exec" def String jacocoRootExecPath = "$buildDir/jacoco/jacocoMerge.exec"
def numFoundExecutionFiles = 0 // number of jacoco data files found in subprojects
delete new File(jacocoRootExecPath) // If the merged exec file (output from jacocoMerge) exists, delete new File(jacocoRootExecPath) // If the merged exec file (output from jacocoMerge) exists,
// jacocoReport & jacocoBranchReport tasks are skipped and // jacocoReport & jacocoBranchReport tasks are skipped and
// the report is not generated. // the report is not generated.
// So always delete the merged file before the determination // So always delete the merged file before the determination
// to skip a task is made. // to skip a task is made.
List excludesList = generateExcludesList()
/********************************************************************************* /*********************************************************************************
* Task to merge multiple jacoco execution data files into one. * Task to merge multiple jacoco execution data files into one
*********************************************************************************/ *********************************************************************************/
task jacocoMerge(type: JacocoMerge) { task jacocoMerge(type: JacocoMerge) {
description = 'Task to merge multiple jacoco execution data files into one.' description = 'Task to merge multiple jacoco execution data files into one.'
destinationFile = new File(jacocoRootExecPath) destinationFile = new File(jacocoRootExecPath)
dependsOn { subprojects.findAll { p -> p.plugins.hasPlugin('jacoco') }.test }
// Make this collection of execution data files empty during the configuration phase. dependsOn { subprojects.findAll { p -> p.plugins.hasPlugin('jacoco') }.integrationTest }
// There may be new exec files generated during the execution phase executionData fileTree(rootDir) {
// (ex: gradle test jacocoReport). So gather up these files in the execution phase include '**/*.exec'
// via doFirst below.
executionData = project.files([])
// Before Task runs, update executionData by searching for files in each subproject.
doFirst {
logger.debug("jacocoMerge: Searching in " + subprojects.size() + " subproject(s)")
subprojects.each { p ->
logger.debug("jacocoMerge: Searching $p.name subproject in directory: $p.buildDir/jacoco/")
File jacocoExecDir = new File("$p.buildDir/jacoco/")
if (jacocoExecDir.exists()) {
jacocoExecDir.eachFileRecurse (FileType.FILES) { file ->
numFoundExecutionFiles++
logger.debug("jacocoMerge: Adding $p.name: $file")
executionData file
}
}
}
println "jacocoMerge: Added $numFoundExecutionFiles execution data files to $destinationFile"
}
} }
}
/********************************************************************************* /*********************************************************************************
* Task to create a jacoco report based on changes from current branch and origin. * Task to generate an aggregate jacoco report from subprojects with
* Default origin is 'master'. Specify -Pjacoco.origin=value to change the value of origin. * Java sourceSets
*********************************************************************************/ *********************************************************************************/
task jacocoBranchReport(type: JacocoReport, group: 'Coverage reports') { task jacocoReport(type: JacocoReport, group: 'Coverage reports') {
description = 'Generates a Jacoco report based on changes from current branch and origin.'
dependsOn ":jacocoMerge"
executionData new File(jacocoRootExecPath)
// Get current branch name
String[] cmd = ["/bin/bash", "-c", "git rev-parse --abbrev-ref HEAD"]
ProcessBuilder builder = new ProcessBuilder();
builder.command(cmd);
Process process = builder.start();
def branchName = process.in.text
process.waitFor();
branchName = branchName.trim()
logger.debug("jacocoBranchReport: Current branchName is $branchName")
// Find commit in origin before branching. See: https://stackoverflow.com/q/1527234
cmd = ["/bin/bash", "-c", "diff -u <(git rev-list --first-parent $branchName) <(git rev-list --first-parent $jacoco_origin) | sed -ne 's/^ //p' | head -1"]
builder = new ProcessBuilder();
builder.command(cmd);
process = builder.start();
def lastRevision = process.in.text
process.waitFor();
lastRevision = lastRevision.trim()
logger.debug("jacocoBranchReport: last revision before branching from $jacoco_origin is $lastRevision")
// Find the files that were changed in the branch.
builder = new ProcessBuilder();
cmd = ["/bin/bash", "-c", "git diff --name-only $lastRevision"]
builder.command(cmd);
process = builder.start();
def filesChanged = process.in.text
process.waitFor();
logger.debug("jacocoBranchReport: files changed are:" + filesChanged)
List filesToInclude = new ArrayList<String>()
filesChanged.split().each{ fileName ->
// Filter out files not in src/main/java and create an inclusion pattern.
if(fileName.endsWith(".java") && fileName.contains("/src/main/java/")) {
String fqName = fileName.split("/src/main/java/")[1]
fqName = fqName.replace(".java", ".class")
filesToInclude.add(fqName)
}
}
// Turn on html reports, 'doFirst' may disable this later on.
reports {
html.enabled = true
xml.enabled = false
}
doFirst {
// Only report on subprojects with Java sourceSets
// This configuration in doFirst to let all subprojects configuration to evaluate.
def subprojectsWithJava = []
subprojects { p ->
p.plugins.withType(JavaPlugin) {
subprojectsWithJava += p
}
}
sourceDirectories = files(subprojectsWithJava.sourceSets.main.allSource.srcDirs)
classDirectories = files(subprojectsWithJava.sourceSets.main.output)
logger.debug("jacocoBranchReport: Files to include: " + filesToInclude)
// Only include these src/main/java files in the report
if (filesToInclude.size() > 0) {
classDirectories = files(classDirectories.files.collect {
fileTree(dir: it,
include: filesToInclude.toArray(new String[filesToInclude.size()]))
})
}
println "jacocoBranchReport: Found $filesToInclude.size Java files to filter on branch '$branchName' and revision $lastRevision from origin '$jacoco_origin'"
println "jacocoBranchReport: Number of jacoco execution data files found from jacocoMerge: $numFoundExecutionFiles"
// Turn off reports if no files to report or no jacoco data files found. Otherwise the jacoco task will create empty report.
if (filesToInclude.size() == 0 || numFoundExecutionFiles == 0) {
reports {
html.enabled = false
xml.enabled = false
}
println "jacocoBranchReport: Empty filter or no jacoco execution data found. Not writing report."
} else {
println "jacocoBranchReport: Writing report to file://$reports.html.destination/index.html"
}
}
}
/*********************************************************************************
* Task to generate an aggregate jacoco report from subprojects with Java sourceSets.
*********************************************************************************/
task jacocoReport(type: JacocoReport, group: 'Coverage reports') {
description = 'Generates an aggregate Jacoco report from all subprojects' description = 'Generates an aggregate Jacoco report from all subprojects'
dependsOn ":jacocoMerge" dependsOn 'jacocoMerge'
executionData new File(jacocoRootExecPath) executionData new File(jacocoRootExecPath)
// Setting these source/class dirs MUST be done in the configuration phase (we used
// to do it in a doFirst block but that was deprecated in later gradle builds). However,
// we have to delay evaluation of the subprojects (using the '{ }' notation) to wait for
// some project attributes (eg: 'sourceSets') to be made available.
additionalSourceDirs files({ subprojects.findAll { p -> p.plugins.hasPlugin('jacoco') }.sourceSets.main.java.srcDirs })
additionalClassDirs files({ subprojects.findAll { p -> p.plugins.hasPlugin('jacoco') }.sourceSets.main.output })
reports { reports {
html.enabled = true html {
xml.enabled = false enabled true
html.destination = new File(project.ext.reportDir + "/jacocoReport") destination new File(rootDir.absolutePath + "/jacocoReport")
}
doFirst {
// Only report on subprojects with Java sourceSets
// This configuration in doFirst to let all subprojects configuration to evaluate.
def subprojectsWithJava = []
subprojects { p ->
p.plugins.withType(JavaPlugin) {
subprojectsWithJava += p
}
}
sourceDirectories = files(subprojectsWithJava.sourceSets.main.allSource.srcDirs)
classDirectories = files(subprojectsWithJava.sourceSets.main.output)
classDirectories = files(classDirectories.files.collect {
fileTree(dir: it, exclude: excludesList)
})
if (numFoundExecutionFiles == 0) {
println "jacocoReport: No execution data files found."
println "jacocoReport: No report written to $reports.html.destination.absolutePath."
reports {
html.enabled = false
xml.enabled = false
}
} else {
println "jacocoReport: Writing report to $reports.html.destination.absolutePath"
} }
xml {
enabled false
} }
} }
} }
/*********************************************************************************
* Generate the Jacoco excludes list from file (this will strip out comments and
* whitespace).
*
* This uses 'gradle/support/jacoco.excludes.src.txt' to generate list of
* class exclusions for the 'jacocoReport' task.
*
*********************************************************************************/
def String[] generateExcludesList() {
File inputFile = new File(rootProject.projectDir, "gradle/support/jacoco.excludes.src.txt")
def lines = inputFile.readLines()
.findAll({ line ->
!shouldIgnoreLine(line)
})
.collect()
println "Returning ${lines.size()} exclusion line(s) for jacocoReport."
return lines
}
/* An ignorable line is one that is only whitespace or that starts with a comment marker */
def shouldIgnoreLine(line) {
if (line.startsWith('#')){
return true
}
if (line.startsWith("//")) {
return true
}
if (line.trim().isEmpty()) {
return true
}
return false
}