Exclude packages from Jacoco report using Sonarrunner and Gradle - gradle

Is there a way to exclude packages from SonarQube(instrumented by gradle + sonar-runner) coverage reports(generated by jacoco) without excluding them completely from the project ?
Below is what i tried so far:
Version information
SonarQube 4.5.1
Gradle 2.2.
Jacoco configuration
// JaCoCo test coverage configuration
tasks.withType(Test) { task ->
jacoco {
append = false
// excluded classes from coverage defined in above configuration
excludes = excludedClasses()
}
jacocoTestReport {
doFirst {
classDirectories = fileTree(dir: "${buildDir}/classes/main/").exclude(excludedClasses())
}
}
}
Sonarrunner configuration
Property setting to exclude package from Sonar analysis. Adding this to my configuration lead to the situation that the packages do not show-up at all in Sonar.
property 'sonar.exclusions', excludedClasses().join(',')
Property setting to exclude packages from jacoco. Setting this leads to the situation that packages are excluded from coverage analysis however show up having 0% which accumulates to bad total scores.
property 'sonar.jacoco.exclusions', excludedClasses().join(',')

I have managed to exclude particular packages from coverage reports by using sonar.coverage.exclusions property in sonar-project.properties. Property is described in official documentation

To combine #Mikalai's answer and #pavel's comment into something that's a bit easier to copy and paste:
To exclude a package or class from all Sonar checks (coverage, code smells, bugs etc), add the following to build.gradle:
sonarqube {
properties {
property 'sonar.exclusions', "**/com/some/package/**"
}
}
To exclude a package or class from only Sonar code coverage checks, add the following to build.gradle:
sonarqube {
properties {
property 'sonar.coverage.exclusions', "**/com/some/package/**"
}
}

To exclude res, assets, custom packages and auto generated classes from sonar code coverage for android project.
Create Exclusion list like below
exclusionList = [
//Res and Assets
"src/main/res/**/*.*",
"src/main/assets/**/*.*",
//Auto-Generated
'**/R.class',
'**/R$*.class',
'**/BuildConfig.*',
'**/*Manifest.*',
'android/**/*.*',
'androidx/**/*.*',
// excluded packages
**/com/<your-package-path>/**/*]
Provide the exclusion list to sonar coverage property
property 'sonar.coverage.exclusions', exclusionList
NOTE:
Keep the full path to exclude the full directory
**/* includes all the files and sub directories under the parent directory Refer Here
*Bean includes all the class names contains "Bean".
**/ starting with it covers the parent directories for the particular package.
Run Jacoco command and check sonar portal's coverage section after doing above changes.

If you are using Gradle 5+ with Kotlin DSL, you can exclude the files from coverage like this:
// configure the SonarQube plugin
sonarqube {
val exclusions = listOf(
"**/com/some/package/**",
"**/all/files/under/package/*",
"**/com/some/package/OneClass.kt"
)
// exclude the directories only from coverage (but not from other analysis)
// https://docs.sonarqube.org/latest/analysis/scan/sonarscanner-for-gradle/
properties {
property("sonar.coverage.exclusions", exclusions)
}
}

exclude multiple module or class from Sonarqube. add below code to
build.gradle:
example :
package name= com.student.result.detail , com.customer.order ,com.student
sonarqube {
properties {
property 'sonar.exclusions', "**/com/student/result/details/**",
"**/com/customer/order/**",
"**/com/student/**";
}
}

This worked for me with gradle 6, sonarqube plugin 2.8
property "sonar.coverage.exclusions" , "**/com/some/package/entity/**/*," + "**/com/some/package/config/**/*,**/com/some/package/dto/**/*,**/com/some/package/dao/**/*"
NOTE: packages are comma separated but in a single string

Most of the answer I have seen here didn't work for me, resulting on the following error:
Execution failed for task ':sonarqube'.
> Could not find method property() for arguments [sonar.coverage.exclusions, **/package/path/Class1**, **/package/path/Class2**, **/package/path/Class3**, **/package/path/Class4**] on object of type org.sonarqube.gradle.SonarQubeProperties.
The reason is that sonar is asking for a string instead of several comma-separated strings as property value. So instead of:
sonarqube {
properties {
property 'sonar.exclusions', "**/com/student/result/details/**",
"**/com/customer/order/**",
"**/com/student/**";
}
}
The solution for me was:
sonarqube {
properties {
property 'sonar.exclusions', "**/com/student/result/details/**,"+
"**/com/customer/order/**,"+
"**/com/student/**";
}
}

Related

How to prevent gradle checkstyle of monitoring the build folder

i have an avro generated tool that create some jave class, thier in turn ships to the build folder.
the problem is that their structure not match with my checkstyle rukes so i want to ignore them
the files under:
C:\src\temp\myproj\build\generated-main-avro-java\
my gradle checkstyle configuration is:
task checkstyle(type: Checkstyle) {
source 'src'
// include '**/*.java'
// exclude '**/gen/**'
// exclude '**/R.java'
// exclude '**/BuildConfig.java'
exclude 'src/main/avro/**'
exclude 'build/**/'
}
tasks.withType(Checkstyle) {
reports {
xml.enabled false
html.enabled true
html.stylesheet resources.text.fromFile('/config/checkstyle/checkstyle-custom.xsl')
}
but i still get:
[ant:checkstyle] [WARN] C:\src\temp\myproj\build\generated-main-avro-java\.....
can you assist of how can i exclude this folder?
(in this example i tried to exclude all the build folder)
can u assist?

how to let jacoco know sources/classes are outside the module

Module A is a separate module having all the integration tests. Maven-Jacoco-Sonar works fine, if sources and tests are located at one module.
Since module A is a different module altogether, we couldn't be able to generate the jacoco reports easily. Because, jacoco is unable to find the sources within module A to measure the coverage for report. Source files are all residing at different modules. jacoco needs to have the class files and source files available in order to generate a report. We need to link up them to module A accordingly while generating the jacoco report so that, jacoco-it.exec can be easily pulled to Sonar to display the coverage analysis.
Currently in this case,
Classes triggered according to the jacoco agent but no source/class files available
Please help me if anyone has as solution how to achieve the above functionality. It would be so helpful to me.
try adding the following as your main src
def debugTree = [fileTree(dir: "${buildDir}/intermediates/classes/debug", excludes: fileFilter),
fileTree(dir: "${project(":your_module_name").projectDir}/build/intermediates/classes/debug", excludes: fileFilter)]
def mainsrc = [fileTree(dir:"${project(":your_module_name").projectDir}/src/main/java"),
fileTree(dir:"${project.projectDir}/src/main/java")]
sourceDirectories = files(mainsrc)
classDirectories = files(debugTree)
This will include your external sub module files to be used while creating the jacoco report.
Try setting sourcesets variable.
jacocoTestReport {
sourceSets project(':module_name').sourceSets.main
reports {
xml.enabled true
// enable html report for debugging in local env
// html.enabled true
// html.destination = file("${buildDir}/jacocoHtml")
}
}

Project with both java and javascript in sonarqube using gradle

We have a pretty standard web project using Java, which contains also some javascript code in the standard src/main/webapp folder. We are using Gradle 2.14 as our build tool.
We have just installed a brand new Sonarqube 6.0.1 on a fresh server, checked that both the Java and Javascript plugins are installed, and modified the build.gradle file as recommended on the Sonarqube documentation:
plugins {
id 'org.sonarqube' version '2.0.1'
}
sonarqube {
properties {
property 'sonar.projectName', 'Our-Project'
property 'sonar.projectKey', 'com.ourcompany:our-project'
}
}
This doesn't work as expected: the java code is analyzed correctly and we can browse the results on sonar, but the javascript code isn't analyzed.
What are we doing wrong? Thanks.
I have managed to fix our issues by adding this property inside the sonarqube block:
property 'sonar.sources', 'src/main'
Are you sure the sonar.sources is including the js files in the analysis? Can you add the module's gradle config? The file above looks like the app level gradle file. You should have at least one module for your app that also has a gradle file.
Android Studio Project Structure
You need to add the sources to the module's gradle file. Here's an example:
project(":app") {
sonarqube {
properties {
property "sonar.analysis.mode", "publish"
property "sonar.sources", "src/main/java"
property "sonar.java.binaries",
"build/intermediates/classes/debug"
property "sonar.junit.reportsPath",
"build/test-results/developDebug"
property "sonar.android.lint.report",
"build/outputs/lint-results-developDebug.xml"
property "sonar.test", "src/test/java"
}
}
}

What parameters can I pass to `gradle dependencies`

When I run gradle dependencies, I can show the dependency tree of a gradle project. Is there any parameter I can pass?
I know just one --configuration compile from somewhere, but can't find any documentation
gradle dependencies is a DependencyReportTask task. Checking Gradle source code for this task it looks like the configuration is the only option for this task (the only one decorated with the #Option annotation), i.e:
#Option(option = "configuration", description = "The configuration to generate the report for.")
public void setConfiguration(String configurationName) {
this.configurations = Collections.singleton(getProject().getConfigurations().getByName(configurationName));
}

jacoco+gradle taskdef A class needed by class org.jacoco.ant.InstrumentTask canno t be found

I'm trying to get jacoco+gradle work together. Looking at this forum it seems some people have successfully done that. But when I tried I got a strange exception.
What I did:
1.Downloaded gradle 2.2.1 and configured env variables, etc.
2.Downloaded jacoco 0.7.1 from http://www.eclemma.org/jacoco/
3.added:
apply plugin: 'jacoco'
and
buildTypes {
debug
{
testCoverageEnabled true
...
in the build.gradle
4.run gradle build
5.I got an error saying the jacoco agent jar cannot be found, etc. Error message showed it tried to search files under C:\Program Files (x86)\Android\android-sdk\extras\android\m2repository... etc.
6.I manually unzipped the jacoco jar files and put them in the place where the error message mentioned and the error message disappeared.
7.Then I ran gradle build. I got the following new error when running the built-in instrumentDebug task:
Caused by: : taskdef A class needed by class org.jacoco.ant.InstrumentTask cannot be found: org/jacoco/core/runtime/IExecutionDataAccessorGenerator using the classloader AntClassLoader[C:\Program Files (x86)\Android\android-sdk\extras\android\m2repository\org\jacoco\org.jacoco.ant\0.7.1.201405082137\org.jacoco.ant-0.7.1.201405082137.jar]
at org.apache.tools.ant.taskdefs.Definer.addDefinition(Definer.java:612)
at org.apache.tools.ant.taskdefs.Definer.execute(Definer.java:237)
at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:292)
at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
at org.gradle.api.internal.project.ant.BasicAntBuilder.nodeCompleted(BasicAntBuilder.java:77)
at org.gradle.api.internal.project.ant.BasicAntBuilder.doInvokeMethod(BasicAntBuilder.java:92)
at com.android.build.gradle.internal.coverage.JacocoInstrumentTask.instrument(JacocoInstrumentask.groovy:51)
at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:63)
at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.doExecute(AnnotationProcessingTaskFactory.java:218)
at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:211)
Caused by: java.lang.ClassNotFoundException:
at org.jacoco.core.runtime.IExecutionDataAccessorGenerator
at org.apache.tools.ant.AntClassLoader.findClassInComponents(AntClassLoader.java:1366)
at org.apache.tools.ant.AntClassLoader.findClass(AntClassLoader.java:1315)
at org.apache.tools.ant.AntClassLoader.loadClass(AntClassLoader.java:1068)...
When I used process monitor (My dev machine is Win 7), I saw there was no access to org.jacoco.core-0.7.1.201405082137.jar,which the org.jacoco.ant.InstrumentTask class resides in. So I think the gradle did not pass the file path to org.apache.tools.ant.AntClassLoader correctly.
I have tried below ways but none of them worked:
Add all jacoco jar files to CLASSPATH environment variable.
Add the jacoco jar files to ant libs, gradle libs,gradle libs/plugins, folder.
Look at source code of gradle 2.2.1. Clueless at this moment...
Does anyone know how to resolve this problem?
Thanks in advance!
Edit:
The main purpose is to:
1. Let jacoco build an instrumented apk file
2. Manually test the apk file (Not auto test)
3. Let jacoco generate coverage report
Update:
I just found when executing InstrumentDebug task, the gradle starts a new process with below command:
"C:\Program Files\Java\jdk1.8.0_25\bin\java.exe" -XX:MaxPermSize=512m -Xmx2048m -Dfile.encoding=UTF-8 -Duser.country=CN -Duser.language=zh -Duser.variant -cp D:\gradle-2.2.1\gradle-2.2.1\lib\gradle-launcher-2.2.1.jar org.gradle.launcher.daemon.bootstrap.GradleDaemon 2.2.1 D:\gradle-2.2.1\gradle-2.2.1\daemon 120000 744501ac-32c1-4930-82bd-59e0a9e2b92d -XX:MaxPermSize=512m -Xmx2048m -Dfile.encoding=UTF-8 -Duser.country=CN -Duser.language=zh -Duser.variant
As you can see the class path is hard coded, which overwrites what defined in environment variable. So the required core lib of jacoco could not be found and thus caused this problem. I'm now trying to see where this process is started and whether there is a way to change the -cp option.
Update2:
I finally found this process is started by gradle-launcher-2.2.1.jar. See below code. I'm now trying to see whether it's possible to change DefaultModuleRegistry and make registry.getGradleHome() == null. In the meantime could anyone who has successfully used jacoco+gradle tell me which version of gradle are you using?
public DaemonStartupInfo startDaemon()
{
DefaultModuleRegistry registry = new DefaultModuleRegistry();
Set<File> bootstrapClasspath = new LinkedHashSet();
bootstrapClasspath.addAll(registry.getModule("gradle-launcher").getImplementationClasspath().getAsFiles());
if (registry.getGradleHome() == null)
{
bootstrapClasspath.addAll(registry.getFullClasspath());
}
if (bootstrapClasspath.isEmpty()) {
throw new IllegalStateException("Unable to construct a bootstrap classpath when starting the daemon");
}
new JvmVersionValidator().validate(this.daemonParameters);
List<String> daemonArgs = new ArrayList();
daemonArgs.add(this.daemonParameters.getEffectiveJavaExecutable());
List<String> daemonOpts = this.daemonParameters.getEffectiveJvmArgs();
LOGGER.debug("Using daemon opts: {}", daemonOpts);
daemonArgs.addAll(daemonOpts);
daemonArgs.add("-cp");
daemonArgs.add(CollectionUtils.join(File.pathSeparator, bootstrapClasspath));
daemonArgs.add(GradleDaemon.class.getName());
daemonArgs.add(GradleVersion.current().getVersion());
daemonArgs.add(this.daemonDir.getBaseDir().getAbsolutePath());
daemonArgs.add(String.valueOf(this.daemonParameters.getIdleTimeout()));
daemonArgs.add(this.daemonParameters.getUid());
...
}
See if this helps.
I'm not using Gradle 2.2.1 but this is what I have in my Global Gradle file (i.e. a file in $GRADLE_HOME/init.d level file). File name can be anything with .gradle extension.
allprojects {
apply plugin: 'java'
apply plugin: 'pmd'
apply plugin: 'findbugs'
apply plugin: 'checkstyle'
apply plugin: 'jacoco'
//NOTE1: The following soureSet section is NOT required, if your folder structure follows what Gradle says where your main source should reside, where test (Unit tests) should reside, and where other like integrationTest (integration tests code reside). If your project structure doesn't follow the Gradle defined structure, then you can define that as my source code is not under src/main/java but is under src/java. The use of "sourceSet" section in this global file is only helping to use some conventional values in this global level file for ex: see integrationTest task and jacocoTestReport task below (you can't use those values if sourceSet is NOT defined in this file and if your project doesn't following the Gradle defined structure).
//NOTE2: Here in the global level Gradle file, I'm using values for sources for main, test, integrationTest etc as "dont_change_me" as I don't know what all projects (which will use this Gradle's global level file), will have what source code structure. The main / actual values of the sources for main, test and integrationTest task MUST be defined in the PROJECT's build.gradle file in sourceSets { main { java { srcDir 'src/java' } } } way.
sourceSets {
main {
java {
srcDir 'dont_change_me'
}
resources {
srcDir 'dont_change_me'
}
}
test {
java {
srcDir 'dont_change_me'
}
resources {
srcDir 'dont_change_me'
}
}
integrationTest {
java {
srcDir 'dont_change_me'
}
resources {
srcDir 'dont_change_me'
}
}
acceptanceTest {
java {
srcDir 'dont_change_me'
}
resources {
srcDir 'dont_change_me'
}
}
}
//...more code here
//...more code here
// The following is necessary to get code coverage info out. Compile with debug mode.
tasks.withType(Compile) {
options.debug = true
options.compilerArgs = ["-g"]
}
jacoco {
//toolVersion = "0.6.2.201302030002"
//toolVersion = "0.7.0.201403182114"
//toolVersion = "0.7.1.201404171759"
//This is latest than above, you may find later versions in online Maven repository.
toolVersion = "0.7.2.201409121644"
//OK I don't need the following folder to be created as I'll define my own.
// reportsDir = file("$buildDir/customJacocoReportDir")
}
//The following section is for UNIT tests (as build task in Gradle calls test task for free)
test {
maxParallelForks = 5
forkEvery = 50
ignoreFailures = true
// I want my reports (html) files to be created in a user defined folder UT(Unit test in build/reports/UT folder) and xml files (in user defined folder UT folder) under build/test-results/UT folder.
testReportDir = file("$buildDir/reports/tests/UT")
testResultsDir = file("$buildDir/test-results/UT")
//Following jacoco session will RUN in GRADLE's JVM session (during build / test time). This is different JVM than what many think of a runtime/Tomcat JVM session where we run a .war/.ear/etc file of an app to run that app and if you want to get code coverage of your main source code using non-unit tests from a Tomcat JVM, then see next task (integrationTest) as the following jacoco section in this "test" task is just for UNIT tests running in Gradle JVM session on a machine.
jacoco {
//NOTE: The following vars works ONLY with Gradle <= 1.6 version
// Create jacoco .exec file for Unit test in a user defined location
destPath = file("$buildDir/jacoco/UT/jacocoUT.exec")
//The following line is not that usesful acc. to my experience so commented it.
//classDumpPath = file("$buildDir/jacoco/UT/classpathdumps")
//NOTE: Following vars works only with versions >= 1.7 version of Gradle
//destinationFile = file("$buildDir/jacoco/UT/jacocoUT.exec")
// classDumpFile = file("$buildDir/jacoco/UT/classpathdumps")
}
}
task integrationTest( type: Test) {
//Always run tests
outputs.upToDateWhen { false }
//Ignore the failures if any during tests and don't mark the Gradle task as failed.
//You can comment this line if you want your gradle task to fail as soon as it finds any failing tests.
ignoreFailures = true
//This is telling Gradle that where it'll find class files from integration tests source code
testClassesDir = sourceSets.integrationTest.output.classesDir
//What path to use in classpath for integration tests
classpath = sourceSets.integrationTest.runtimeClasspath
//My custom location where I want my html reports files and xml result times of integration tests
testReportDir = file("$buildDir/reports/tests/IT")
testResultsDir = file("$buildDir/test-results/IT")
//Jacoco section in IT tests is NOT required here. Why as it'll never generage a coverage report this way as this way of using jacoco section in integrationTest task is telling Gradle to use jacoco in Gradle JVM and for getting code coverage you have to run jacoco/jacocoagent.jar in Target JVM (which is Tomcat or similar) by introducing jacocoagent.jar and other parameters for jacoco to Tomcat using one of Tomcat's -Dxxx option (see Jacoco help on how to do this). As the following is not required, I'm commenting the following jacoco code(otherwise if used, it'll always give you 0% coverage).
//jacoco {
//This works with 1.6
// destPath = file("$buildDir/jacoco/IT/jacocoIT.exec")
// classDumpPath = file("$buildDir/jacoco/IT/classpathdumps")
//Following works only with versions >= 1.7 version of Gradle
//destinationFile = file("$buildDir/jacoco/IT/jacocoIT.exec")
// classDumpFile = file("$buildDir/jacoco/IT/classpathdumps")
//}
}
jacocoTestReport {
group = "Reporting"
description = "Generate Jacoco coverage reports after running tests."
ignoreFailures = true
//Use any .exec file found before generating coverage report i.e. it'll give you combined coverage report if you have both jacocoUT.exec and jacocoIT.exec or other .exec files in build/jacoco/xx folders.
executionData = fileTree(dir: 'build/jacoco', include: '**/*.exec')
//executionData = files('build/jacoco/UT/jacocoUT.exec', 'build/jacoco/IT/jacocoIT.exec')
//executionData = files(['build/jacoco/UT/jacocoUT.exec', 'build/jacoco/IT/jacocoIT.exec'])
reports {
xml{
enabled true
//Following value is a file
destination "${buildDir}/reports/jacoco/xml/jacoco.xml"
}
csv.enabled false
html{
enabled true
//Following value is a folder
destination "${buildDir}/reports/jacoco/html"
}
}
//The following is an example of using Gradle conventional way of saying where is my main source code directory
//sourceDirectories = files(sourceSets.main.allJava.srcDirs)
sourceDirectories = files(['src/java', 'src/groovy'])
classDirectories = files('build/classes/main')
}
}
In Project's build.gradle, you define sourceSets section (with actual values) if your project structure if different than what Gradle says it should be. You define dependencies (i.e. for compile you need this .jar, for test or integrationTest, you need this .jar or .class from main/test etc).
Then, if you run gradle clean build, you'll get jacoco code coverage data for UT(Unit tests) under build/jacoco/UT folder in the form of an .exec file. Under build/reports/... html folder, you'll find jacoco main index.html which will show you the code coverage report.
If you want code coverage report from non-Unit tests (i.e. Integration tests etc), then attach the following parameter to the target JVM. I use Tomcat, so I'm attaching this, where testType is a variable which I use to find/tell whether I'm running IT(Integration Tests), AT (Acceptance Tests) or ST (Selenium GUI tests).
export PROJ_EXTRA_JVM_OPTS="-javaagent:tomcat/jacocoagent.jar=destfile=build/jacoco/${testType}/jacoco${testType}.exec,append=false"
and in startTomcat.sh script which I use, you'll notice I'm using the above variable and passing it to Tomcat's JVM as that's the JVM which is running my project's main .war/.ear file which has the main source code class files against which I want my code covreage data using Integration/Acceptance/other non-UNIT type tests:
## Tomcat command - JDK 1.6/Tomcat 6.0
TOMCAT_CMD="$JAVA_HOME/bin/java $TOMCAT_JVM_ARGS \
$OPTIT_JVM_ARGS \
$JPROF_JVM_ARGS \
$PROJ_EXTRA_JVM_OPTS \
org.apache.catalina.startup.Bootstrap $TOMCAT_CFG_FILE_ARGS start"
The above variable needs to be there in the Tomcat start script i.e. when Tomcat starts, it should get the above variable in its JVM session. Once this is done, you have to run "gradle integrationTest" then stop your Tomcat session(only then it'll flush the code coverage data to jacocoIT.exec file) and then if you run "gradle jacocoTestReport", it'll read the jacocoIT.exec file and genreate jacoco code coverage report for your main source code which your Integration/Acceptance/Selenium Tests tried to cover.

Resources