Last active
March 11, 2019 11:33
-
-
Save WarrenFaith/bfd4de61977d653bb56b9939bcd6f397 to your computer and use it in GitHub Desktop.
Basic script setup to add tasks like "testDebugUnitTestCoverage" (when you have no flavors defined) or "testFlavorNameDebugUnitTestCoverage" (replace FlavorName with your flavor name). Limitation: Does not work with flavor dimensions!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// in your root gradle file: | |
buildscript { | |
repositories { | |
jcenter() | |
google() | |
mavenCentral() | |
} | |
dependencies { | |
classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.6.1" | |
} | |
} | |
// project gradle: | |
apply from: '../gradle/jacoco-devflavor-module.gradle' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
apply from: '../gradle/jacoco.gradle' | |
sonarqube { | |
androidVariant 'devDebug' | |
properties { | |
property "sonar.jacoco.reportPaths", "${project.buildDir}/jacoco/testDevDebugUnitTest.exec" | |
property "sonar.java.binaries", "build/intermediates/classes/dev/debug" | |
property "sonar.java.test.binaries", "build/intermediates/classes/test/dev/debug" | |
} | |
} | |
project.tasks["sonarqube"].dependsOn "testDevDebugUnitTest" | |
project.afterEvaluate { | |
testDevDebugUnitTestCoverage.doLast { | |
def report = file("${jacoco.reportsDir}/testDevDebugUnitTestCoverage/testDevDebugUnitTestCoverage.xml") | |
logger.lifecycle("Checking coverage results: ${report}") | |
def parser = new XmlParser() | |
parser.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false) | |
parser.setFeature("http://apache.org/xml/features/disallow-doctype-decl", false) | |
def results = parser.parse(report) | |
def percentage = { | |
def covered = it.'@covered' as Double | |
def missed = it.'@missed' as Double | |
((covered / (covered + missed)) * 100).round(2) | |
} | |
def counters = results.counter | |
def metrics = [:] | |
metrics << [ | |
'instruction': percentage(counters.find { it.'@type'.equals('INSTRUCTION') }), | |
'branch' : percentage(counters.find { it.'@type'.equals('BRANCH') }), | |
'line' : percentage(counters.find { it.'@type'.equals('LINE') }), | |
'complexity' : percentage(counters.find { it.'@type'.equals('COMPLEXITY') }), | |
'method' : percentage(counters.find { it.'@type'.equals('METHOD') }), | |
'class' : percentage(counters.find { it.'@type'.equals('CLASS') }) | |
] | |
def failures = [] | |
def canIncrease = [] | |
metrics.each { | |
def limit = limits[it.key] | |
if (it.value < limit) { | |
failures.add("- ${it.key} coverage rate is: ${it.value}%, minimum is ${limit}%") | |
} | |
if (it.value > limit + 1) { | |
canIncrease.add("- ${it.key} coverage rate is: ${it.value}%, minimum is ${limit}%") | |
} | |
} | |
def log = printResult(logger, failures, "Code Coverage Failed") | |
log += printResult(logger, canIncrease, "Code Coverage Status!") | |
logger.log(LogLevel.INFO, log) | |
// use this here again if we really want to fail on our limits | |
// if (failures) { | |
// throw new GradleException(log) | |
// } | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
apply from: '../gradle/jacoco.gradle' | |
sonarqube { | |
androidVariant 'debug' | |
properties { | |
property "sonar.jacoco.reportPaths", "${project.buildDir}/jacoco/testDebugUnitTest.exec" | |
property "sonar.java.binaries", "build/intermediates/classes/debug" | |
property "sonar.java.test.binaries", "build/intermediates/classes/test/debug" | |
} | |
} | |
project.tasks["sonarqube"].dependsOn "testDebugUnitTest" | |
project.afterEvaluate { | |
testDebugUnitTestCoverage.doLast { | |
def report = file("${jacoco.reportsDir}/testDebugUnitTestCoverage/testDebugUnitTestCoverage.xml") | |
logger.lifecycle("Checking coverage results: ${report}") | |
def parser = new XmlParser() | |
parser.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); | |
parser.setFeature("http://apache.org/xml/features/disallow-doctype-decl", false) | |
def results = parser.parse(report) | |
def percentage = { | |
def covered = it.'@covered' as Double | |
def missed = it.'@missed' as Double | |
((covered / (covered + missed)) * 100).round(2) | |
} | |
def counters = results.counter | |
def metrics = [:] | |
metrics << [ | |
'instruction': percentage(counters.find { it.'@type'.equals('INSTRUCTION') }), | |
'branch' : percentage(counters.find { it.'@type'.equals('BRANCH') }), | |
'line' : percentage(counters.find { it.'@type'.equals('LINE') }), | |
'complexity' : percentage(counters.find { it.'@type'.equals('COMPLEXITY') }), | |
'method' : percentage(counters.find { it.'@type'.equals('METHOD') }), | |
'class' : percentage(counters.find { it.'@type'.equals('CLASS') }) | |
] | |
def failures = [] | |
def canIncrease = [] | |
metrics.each { | |
def limit = limits[it.key] | |
if (it.value < limit) { | |
failures.add("- ${it.key} coverage rate is: ${it.value}%, minimum is ${limit}%") | |
} | |
if (it.value > limit + 1) { | |
canIncrease.add("- ${it.key} coverage rate is: ${it.value}%, minimum is ${limit}%") | |
} | |
} | |
def log = printResult(logger, failures, "Code Coverage Failed") | |
log += printResult(logger, canIncrease, "Code Coverage Status!") | |
logger.log(LogLevel.INFO, log) | |
// use this here again if we really want to fail on our limits | |
// if (failures) { | |
// throw new GradleException(log) | |
// } | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
apply plugin: 'jacoco' | |
apply plugin: "org.sonarqube" | |
jacoco { | |
toolVersion = "0.7.9" | |
} | |
ext { | |
limits = [ | |
'instruction': 90, | |
'branch' : 90, | |
'line' : 90, | |
'complexity' : 90, | |
'method' : 90, | |
'class' : 90 | |
] | |
} | |
sonarqube { | |
properties { | |
property "sonar.host.url", "https://sonarqube.example.net" | |
property "sonar.sources", "src/main/java" | |
property "sonar.tests", "src/test/java" | |
property "sonar.sourceEncoding", "UTF-8" | |
property "sonar.projectVersion", "${versionName}" | |
} | |
} | |
project.afterEvaluate { | |
// Grab all build types and product flavors | |
def buildTypes = android.buildTypes.collect { type -> type.name } | |
def productFlavors = android.productFlavors.collect { flavor -> flavor.name } | |
// When no product flavors defined, use empty | |
if (!productFlavors) productFlavors.add('') | |
productFlavors.each { productFlavorName -> | |
buildTypes.each { buildTypeName -> | |
def sourceName, sourcePath | |
if (!productFlavorName) { | |
sourceName = sourcePath = "${buildTypeName}" | |
} else { | |
sourceName = "${productFlavorName}${buildTypeName.capitalize()}" | |
sourcePath = "${productFlavorName}/${buildTypeName}" | |
} | |
def testTaskName = "test${sourceName.capitalize()}UnitTest" | |
// Create coverage task of form 'testFlavorTypeCoverage' depending on 'testFlavorTypeUnitTest' | |
task "${testTaskName}Coverage"(type: JacocoReport, dependsOn: "$testTaskName") { | |
group = "Reporting" | |
description = "Generate Jacoco coverage reports on the ${sourceName.capitalize()} build." | |
classDirectories = fileTree( | |
dir: "${project.buildDir}/intermediates/classes/${sourcePath}", | |
excludes: ['**/R.class', // android internal | |
'**/R$*.class', // android internal | |
'**/*$ViewInjector*.*', | |
'**/*$ViewBinder*.*', | |
'**/MemberInjectorRegistry.*', // toothpick | |
'**/FactoryRegistry.*', // toothpick | |
'**/BR.*', // android module "placeholder" | |
'**/BuildConfig.*', // android internal | |
'**/com/android/databinding/**', // android databinding | |
'**/android/databinding/layouts/**', // android databinding | |
'**/Manifest*.*', // android internal | |
] | |
) | |
def coverageSourceDirs = [ | |
"src/main/java", | |
"src/$productFlavorName/java", | |
"src/$buildTypeName/java" | |
] | |
additionalSourceDirs = files(coverageSourceDirs) | |
sourceDirectories = files(coverageSourceDirs) | |
executionData = files("${project.buildDir}/jacoco/${testTaskName}.exec") | |
reports { | |
xml.enabled = true | |
html.enabled = true | |
} | |
} | |
} | |
} | |
} | |
ext.printResult = { logger, result, title -> | |
def log = "" | |
if (result) { | |
log = "------------------ " + title + " -----------------------\n" | |
result.each { | |
log += it + "\n" | |
} | |
logger.quiet(log) | |
} | |
return log | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment