I am using maven with the jacoco plugin to generate code coverage metrics. I am having some difficulty in configuring the surefire plugin with the java options required by the jacoco plugin. I've seen some answers about this already on Stack Overflow but something is not working for me.
I have a multi-module project, and one of my modules configures the surefire plugin as follows:
foo/pom.xml:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-XX:MaxPermSize=512m</argLine>
</configuration>
</plugin>
</plugins>
This works as expected.
Now I want to incorporate jacoco to get code coverage metrics, so I added a CodeCoverage profile that handles all the jacoco configuration:
parent/pom.xml:
<profile>
<id>CodeCoverage</id>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<executions>
<execution>
<id>jacoco-initialize</id>
<goals><goal>prepare-agent</goal></goals>
<configuration>
<propertyName>surefire.argLine</propertyName>
</configuration>
...
</execution>
<executions>
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>
It is seen here that if the CodeCoverage profile is specified, then the jacoco plugin is configured to use the surefire.argLine property, and that property is used to configure the argLine for the surefire plugin.
I then updated the pom.xml file for the foo module to use the surefire.argLine property generated by the jacoco plugin:
foo/pom.xml:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>${surefire.argLine} -XX:MaxPermSize=512m</argLine>
</configuration>
</plugin>
</plugins>
This approach is specified in the jacoco plugin documentation (see [1]).
When I build the foo module with the CodeCoverage profile, I see the following:
[foo] $ mvn clean install -X -PCodeCoverage
...
[INFO] --- jacoco-maven-plugin:0.7.0.201403182114:prepare-agent (jacoco-initialize) # foo ---
[INFO] surefire.argLine set to -javaagent:...\\org.jacoco.agent\\0.7.0.201403182114\\org.jacoco.agent-0.7.0.201403182114-runtime.jar=destfile=...\foo\\\target\\coverage-reports\\jacoco-ut.exec
...
[DEBUG] Configuring mojo 'org.apache.maven.plugins:maven-surefire-plugin:2.13:test' with basic configurator -->
[DEBUG] (s) argLine = -javaagent:...\\org.jacoco.agent\\0.7.0.201403182114\\org.jacoco.agent-0.7.0.201403182114-runtime.jar=destfile=...\\foo\\target\\coverage-reports\\jacoco-ut.exec -XX:MaxPermSize=512m
...
[INFO] --- jacoco-maven-plugin:0.7.0.201403182114:report (jacoco-site) # foo ---
[INFO] Analyzed bundle 'Foo' with 59 classes`
So the jacoco plugin is executed, a surefire.argLine property is created, the argLine for the surefire plugin uses the surefire.argLine property and the local MaxPermSize argument, and a target\code-coverage\jacoc-ut-exec file is generated, as expected.
However, if I do not use the CodeCoverage profile, then I get an error, because the ${surefire.argLine} property (used in foo/pom.xml) is not created by the jacoco plugin, and is not defined anywhere:
[foo] $ mvn clean install -X
...
[DEBUG] Configuring mojo 'org.apache.maven.plugins:maven-surefire-plugin:2.13:test' with basic configurator -->
[DEBUG] (s) argLine = ${surefire.argLine} -XX:MaxPermSize=512m
...
Error: Could not find or load main class ${surefire.argLine}`
Sinec the jacoco plugin was not invoked, there's no surefire.argLine property created, hence the error.
So, I go back to the parent/pom.xml and create this property, with no initial value:
parent/pom.xml:
<properties>
<surefire.argLine></surefire.argLine>
</properties>
Now when I build the foo module without using the CodeCoverage profile, I get no errors:
[foo] $ mvn clean install -X
...
[DEBUG] Configuring mojo 'org.apache.maven.plugins:maven-surefire-plugin:2.13:test' with basic configurator -->
[DEBUG] (s) argLine = -XX:MaxPermSize=512m
...
[INFO] BUILD SUCCESS`
The surefire argline is now correct (using the empty surefire.argLine property) and there is no target\code-coverage directory, as expected.
So now I go back to generating code metrics, using the CodeCoverage profile:
[foo] $ mvn clean install -X -PCodeCoverage
...
[INFO] --- jacoco-maven-plugin:0.7.0.201403182114:prepare-agent (jacoco-initialize) # foo ---
[INFO] surefire.argLine set to -javaagent:...\\org.jacoco.agent\\0.7.0.201403182114\\org.jacoco.agent-0.7.0.201403182114-runtime.jar=destfile=...\\foo\\target\\coverage-reports\\jacoco-ut.exec
...
[DEBUG] Configuring mojo 'org.apache.maven.plugins:maven-surefire-plugin:2.13:test' with basic configurator -->
[DEBUG] (s) argLine = -XX:MaxPermSize=512m
...
[INFO] --- jacoco-maven-plugin:0.7.0.201403182114:report (jacoco-site) # foo ---
[INFO] Skipping JaCoCo execution due to missing execution data file:...\foo\target\coverage-reports\jacoco-ut.exec
It can be observed here that the jacoco plugin is invoked and sets the surefire.argLine property, but the surefire.argLine property with the empty value defined in the parent/pom.xml file is actually used to create the argline for the surefire plugin.
As a result, there is no jacoco-ut.exec file, and no target\code-coverage directory, when I use the CodeCoverage profile.
I'm not sure what I am doing wrong here. I'm declaring an argLine property as suggested by the jacoco documentation, and using it whenever a surefire plugin needs to specify additional argument. Other answers on Stack Overflow suggest creating a property with the same name as the jacoco argLine property to handle the case when jacoco is not invoked.
Any suggestions?
edit
Maybe one solution is to explicitly declare the surefire.argLine property in the CodeCoverage profile, and forget about using the argLine of the jacoco plugin:
<profile>
<id>CodeCoverage</id>
<properties>
<surefire.argLine>-javaagent:${jacoco.agent.jar}=destfile=${jacoco.report.path}</surefire.argLine>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<executions>
<execution>
<id>jacoco-initialize</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<!-- no longer specifying 'argLine' for jacoco plugin ... -->
</execution>
<executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!-- ... instead the arg line is configured explicitly for surefire plugin. -->
<argLine>${surefire.argLine}</argLine>
</configuration>
</plugin>
</plugins>
</plugin>
</build>
This will create the surefire.argLine property to use the java agent required by the jacoco plugin, and configure the surefire plugin to use that property for its JVM args. The jacoco plugin will now create a argLine property, but this will be ignored. It's not an elegant solution (since I'm making assumptions about how the jacoco plugin works, and this may change in a future version).
edit
The jacoco.agent.jar property must also be set, by pointing to its location in the local repository (not sure if this is robust) or by using the dependency plugin to copy the jacoco agent jar to the local build directory:
<profile>
<id>CodeCoverage</id>
<properties>
<jacoco.agent.jar>${project.build.directory}/jacoco-agent.jar</jacoco.agent.jar>
...
</project>
<build>
...
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>download-jacoco-agent</id>
<phase>process-test-resources</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.jacoco</groupId>
<artifactId>org.jacoco.agent</artifactId>
<version>${jacoco.version}</version>
<classifier>runtime</classifier>
<outputDirectory>${project.build.directory}</outputDirectory>
<destFileName>jacoco-agent.jar</destFileName>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
edit
Not sure if using the dependency plugin is the right approach, or pointing to the jacoco agent artifact in the local repository:
<profile>
<id>CodeCoverage</id>
<properties>
<jacoco.agent.jar>${settings.localRepository}/org/jacoco/org.jacoco.agent/${jacoco.version}/org.jacoco.agent-${jacoco.version}-runtime.jar</jacoco.agent.jar>
</properties>
...
</profile>
This is simpler, and does not require copying an artifact to the local build directory, but is fragile: changes in the repository layout will break this.
[1] http://www.eclemma.org/jacoco/trunk/doc/prepare-agent-mojo.html
Try using
#{argLine}
instead of
${argLine}
(or surefire.argLine in your case)
It allows surefire to read a property as modified by other plugins instead of reading the one substituted by Maven itself. Then you can set the argLine param to empty in Maven properties:
<properties>
<argLine></argLine>
</properties>
Which now will not cause any problems. More here: How do I use properties set by other plugins in argLine?
Since the jacoco-maven-plugin:prepare-agent goal executes before the maven-surefire-plugin, try adding the ${argLine} variable into the argLine value set by the maven-surefire-plugin.
Example:
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.1</version>
<configuration>
<argLine>-server -ea -XX:MaxPermSize=256m -Xmx4g -XX:-UseSplitVerifier ${argLine}</argLine>
</configuration>
</plugin>
I had the same problem and this solution worked for me, without any need to reconfigure other sections of the POM.
If your project already uses the argLine to configure the surefire-maven-plugin, be sure that argLine defined as a property, rather than as part of the plugin configuration. For example:
<properties>
<argLine>-your -extra -arguments</argLine>
</properties>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!-- Do not define argLine here! -->
</configuration>
</plugin>
Resulting coverage information is collected during execution and by default written to a file when the process terminates.
Worked for me. See: http://www.eclemma.org/jacoco/trunk/doc/prepare-agent-mojo.html
Try adding the argLine property in the properties section (as shown in the code below) instead of adding it in the configuration section of maven-sure-fire plugin. Jacoco maven plugin will just append to this and things will work as expected.
<properties>
<argLine>-XX:MaxPermSize=512m</argLine>
</properties>
See https://docs.sonarqube.org/display/PLUG/Usage+of+JaCoCo+with+Java+Plugin
My solution is to use multiple profiles.
The first profile sets a blank value for the surefire.argLine and the failsafe.argLine and is active by default.
<profile>
<id>not-sonar</id>
<properties>
<surefire.argLine/>
<failsafe.argLine/>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
The second profile has the jacoco plugin configuration and is inactive by default.
<profile>
<id>sonar</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco-maven-plugin-version}</version>
<executions>
<execution>
<id>default-prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<propertyName>surefire.argLine</propertyName>
</configuration>
</execution>
<execution>
<id>default-prepare-agent-integration</id>
<goals>
<goal>prepare-agent-integration</goal>
</goals>
<configuration>
<propertyName>failsafe.argLine</propertyName>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
When you activate the sonar profile the not-sonar profile will automatically be turned off.
This should be a little more elegant than using other plugins to do the work for you. You can now use the ${surefire.argLine} variable in your argLine and it will always exists and be set when you run your build.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>${surefire.argLine} -XX:MaxPermSize=512m</argLine>
</configuration>
</plugin>
If you still have problems because the ${surefire.argLine} does not have a value you can also set a dummy property like so:
<profile>
<id>not-sonar</id>
<properties>
<surefire.argLine>-DdummyProperty=notUsed</surefire.argLine>
<failsafe.argLine>-DdummyProperty=notUsed</failsafe.argLine>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
I recently ran into the same issue and even took implicitly the same steps as you described with the same result. No clean solution I found worked for me.
So I ran several steps in debug mode and it seems that Maven replaces properties twice. That is not just in a lazy manner, as I thought, but in both eager and lazy manner:
eagerly (before any goal is run) are replaced static properties (defined in properties section of POM and probably also settings.xml),
lazily (before each execution) are replaced dynamic properties.
This is where our step with setting a blank property as a default failed. Maven just went:
eager replace of default value (blank)
JaCoCo sets dynamic value
lazy replace of dynamic values (nothing to replace now, already used the blank value)
Finally the solution is to set the default value dynamically. This can be done with GMaven plugin like this:
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>set-default-values</id>
<phase>initialize</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>
project.properties.'surefire.argLine' = ''
</source>
</configuration>
</execution>
</executions>
</plugin>
So now Maven goes:
eager replace of static properties
GMaven dynamically sets default value (if profile is active)
JaCoCo sets dynamic value
Surefire runs with correctly set argLine
With active profile the exec file is generated, with non-active profile the blank default value is used and build succeeds.
My solution to use argLine in the maven-surefire-plugin safely.
<plugin>
<groupId>org.codehaus.groovy.maven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>2.0</version>
<executions>
<execution>
<id>set-custom-arg-line</id>
<phase>validate</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>
def argLine = project.properties['argLine'];
if (argLine == null) {
argLine = "";
}
project.properties.argLine = argLine;
</source>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<argLine>-Xmx1024m ${argLine}</argLine>
</configuration>
</plugin>
For me upgrading the version from 0.7.7.201606060606 to 0.7.9 also fixed this.
I had to explicitly add the version to the commandline (not just to the pom) because the build server kept using the old verison. This can be done as follows:
org.jacoco:jacoco-maven-plugin:0.7.9:prepare-agent
instead of
org.jacoco:jacoco-maven-plugin:prepare-agent
The jacoco plugin site (for sonar) states that argline must be added as a property. For me it also worken when using the #{argLine} in the surefire plugin settings.
Update the POM.xml as
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.7.201606060606</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.1</version>
<configuration>
<argLine>${argLine} -XX:PermSize=256m -XX:MaxPermSize=1048m</argLine>
</configuration>
</plugin>
and then the most important thing is to run the Maven project with goals:
mvn jacoco:prepare-agent clean test jacoco:report
I have added a Maven/Java project with 1 domain class with the following features:
Unit or Integration testing with the plugins Surefire and Failsafe.
Findbugs.
Test coverage via Jacoco.
I kept the project as simple as possible. The project puts many suggestions from these and other posts together in an example project. Thank you, contributors!
The readme file gives a brief explanation. It explains how you can run either a user or an integration test with Jacoco.
Enjoy!
Related
I have the pom.xml below.
I'd like to pass a tag property to my build, using this command:
mvn clean package -Dtag=test
It should split this property into two others, my.group an my.version, and then use it in a URI to build an XLDeploy package, using the xldeploy-maven-plugin (https://docs.xebialabs.com/xldeploy-maven-plugin/6.0.x/).
My problem is that the regex-properties goal is actually doing the job, as I can see thanks to the maven-antrun-plugin:
[INFO] --- maven-antrun-plugin:1.1:run (default) # myArtifactId ---
[INFO] Executing tasks
[echo] Displaying value of 'my.group' property
[echo] [my.group] group/test
[echo] Displaying value of 'my.version' property
[echo] [my.version] test
But the command grep fileUri target\deployit-working-dir\deployit-manifest.xml show that the vars in Uri does not get replaced:
grep fileUri target\deployit-working-dir\deployit-manifest.xml
<fileUri>http://mynexus.ur/service/local/repositories/my-repo/content/${my.group}/anArtefact/${my.version}/anArtefact-1.0.zip</fileUri>
The POM is the following file:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>myGroupId</groupId>
<artifactId>myArtifactId</artifactId>
<version>1.0</version>
<packaging>dar</packaging>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>regex-properties</id>
<goals>
<goal>regex-properties</goal>
</goals>
<configuration>
<regexPropertySettings>
<regexPropertySetting>
<name>my.group</name>
<value>group/${tag}</value>
<regex>(asm-[0-9]+)-([0-9]+.[0-9]+)-([0-9]+)$</regex>
<replacement>$1</replacement>
<failIfNoMatch>false</failIfNoMatch>
</regexPropertySetting>
<regexPropertySetting>
<name>my.version</name>
<value>${tag}</value>
<regex>(asm-[0-9]+)-([0-9]+.[0-9]+)-([0-9]+)$</regex>
<replacement>$1-SNAPSHOT</replacement>
<failIfNoMatch>false</failIfNoMatch>
</regexPropertySetting>
</regexPropertySettings>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<echo>Displaying value of 'my.group' property</echo>
<echo>[my.group] ${my.group}</echo>
<echo>Displaying value of 'my.version' property</echo>
<echo>[my.version] ${my.version}</echo>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.xebialabs.xldeploy</groupId>
<artifactId>xldeploy-maven-plugin</artifactId>
<version>6.0.0</version>
<extensions>true</extensions>
<configuration>
<deployables>
<file.Folder name="file">
<scanPlaceholders>false</scanPlaceholders>
<fileUri>http://mynexus.ur/service/local/repositories/my-repo/content/${my.group}/anArtefact/${my.version}/anArtefact-${project.version}.zip</fileUri>
</file.Folder>
</deployables>
</configuration>
</plugin>
</plugins>
</build>
</project>
I'm not quite sure if the build-helper-maven-plugin wrong, or anywhere else in my POM, or if it's simply lack of replacing properties in the xldeploy-maven-plugin...
Thanks for the help ;)
I checked the source of xldeploy-maven-plugin-6.0.1, and it seems it is the limitation of the current implementation.
The problem is that GenerateDeploymentPackageMojo does not rely on maven to do the substitution of the properties. Instead, it uses a custom AbstractConfigurationConverter named DeployitCIConverter (which delegates to MavenDeployableConverter) to convert the <deployables> node to a list of MavenDeployable)
This boils down to:
you have the access to effective POM
you don't have access to properties defined dynamically via build helper plugin
Of course the properties defined dynamically can be acessed in any mojo:
if you use a parameter
if you evaluate them manually via expression evaluator (check: get mojo parameters in maven plugin)
For the antrun plugin, it uses ExpressionEvaluator explicitely in the echo task.
Informative article:
Properties resolution in Maven and its implications on Antrun plugin
Ideas to fix the problem:
do your group and version parsing in external script and pass the values to mvn command.
create a cutom mojo extending GenerateDeploymentPackageMojo and preprocess deployables in the execute method (not that hard as it sounds).
so we have a Spring Boot maven based project, which we split into multi modules which all works perfectly fine in unit tests and Jenkins, but coverage is not showing up in Sonar at all.
This is the structure of our application:
ApplicationRoot
-SharedCommonModule
--main
---java
-----com...(SomeModule.java)
--test
----com....(SomeModuleTest.java)
-ApplicationModule
--main
---java
-----com...(Application.java)
--test
----com....(ApplicationTest.java)
Parent pom file config:
<properties>
<!-- Sonar -->
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
<sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
<sonar.jacoco.reportPath>${project.basedir}/../target/jacoco.exec</sonar.jacoco.reportPath>
<sonar.language>java</sonar.language>
<jacoco.destFile>${sonar.jacoco.reportPath}</jacoco.destFile>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.5.201505241946</version>
<configuration>
<destFile>${sonar.jacoco.reportPath}</destFile>
<append>true</append>
</configuration>
<executions>
<execution>
<id>agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
SharedCommonModule pom:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
Main ApplicationModule pom file:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.org.Application</mainClass>
</configuration>
</plugin>
</plugins>
</build>
Jenkins SonarQube plugin configuration:
sonar.projectKey=com.Application
sonar.projectName=ApplicationModule
sonar.projectVersion=1.0.0.${BUILD_NUMBER}
sonar.sources=src/main
sonar.tests=src/test
sonar.java.binaries=target/classes
sonar.jacoco.reportPaths=target/jacoco.exec
sonar.modules=ApplicationModule,SharedCommonModule
ApplicationModule.sonar.projectName=ApplicationModule
SharedCommonModule.sonar.projectName=SharedCommonModule
We have researched and tried to hack it together from multiple examples, but nothing seems to work - closest we've got, is for Sonar to show some coverage, while some classes would show 0% coverage even though we know for sure we have UTs that used those classes (tested via IntelliJ).
So, without without the added properties and build xml sections above, we get partial coverage, only for ApplicaitonModule, I think all reported uncovered classes, belong to SharedCommonModule
EDIT: I want to clarify, the combined jacoco.exec file does show coverage for classes when loaded in IntelliJ Coverage tool, but Sonar does not show coverage for the very same classes in its report (which is generated only when I remove the build and properties xml elements in the parent pom).
Please help :)
You have Maven projects, so you should start using Sonar Scanner for Maven.
It is smart enough to generate all parameters for you.
If you remove:
<sonar.jacoco.reportPath>${project.basedir}/../target/jacoco.exec</sonar.jacoco.reportPath>
<jacoco.destFile>${sonar.jacoco.reportPath}</jacoco.destFile>
<destFile>${sonar.jacoco.reportPath}</destFile>
Jenkins SonarQube plugin configuration
add to parent pom file:
<name>ApplicationModule</name>
<properties>
<sonar.sources>src/main</sonar.sources>
<sonar.tests>src/test</sonar.tests>
<sonar.projectKey>com.Application</sonar.projectKey>
</properties>
add to SharedCommonModule pom file:
<name>SharedCommonModule</name>
add to ApplicationModule.pom file:
<name>ApplicationModule</name>
and finally execute:
mvn sonar:sonar -Dsonar.projectVersion="1.0.0.${BUILD_NUMBER}"
After that you should see missing coverage data.
Btw. it is not recomended to set sonar.projectKey for Maven projects. I set it to the same value, so your project will be accessible under the same link.
Provided you have the following defined in your POM.xml:
<project>
<!-- ... -->
<build>
<plugins>
<plugin>
<artifactId>plugin-X</artifactId>
<!-- plugin config -->
</plugin>
<plugins>
</build>
<profiles>
<profile>
<id>foo</id>
<build>
<plugins>
<plugin>
<artifactId>plugin-X</artifactId>
<!-- plugin config -->
</plugin>
<plugins>
</build>
<profile>
</profiles>
</project>
If the plugin config for plugin-X is exactly the same for profile foo as it is for a build without a selected profile, do you have to redeclare the plugin at all on the profile level? If so, do you also have to redeclare all config settings for it?
If you declared plugin-Y in project.profile.build.plugins instead of plugin-X (but left it declared on the project level), which plugins would be run when you run mvn -P foo? Only plugin-Y, or also plugin-X?
More generally speaking, are profiles additive to what is declared on the project level, or do they override it? (If they are additive, how do you "remove" entities that were declared on a project level when you run a build profile and don't want them for that specific profile?)
I know profile configuration gets inherited from parent pom files ("from either the build/plugins or pluginManagement sections of the parent") with options "merge", "append", and "override". I think what I really want to know is: how does maven behave when the same/similar information is defined on the project and profile levels in the same pom file...
This isn't a full answer, but another piece of the puzzle - in addition to my earlier comments, and maven's Guide to Configuring Plug-ins.
Given the following pom.xml file:
</profiles>
<properties>
<foo>main</foo>
<bar>main</bar>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>validate</phase>
<configuration>
<target>
<echo>${foo}</echo>
<echo>${bar}</echo>
<echo>${baz}</echo>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>p</id>
<properties>
<bar>prof</bar>
<baz>prof</baz>
</properties>
</profile>
</profiles>
</project>
When I run mvn validate, I get the following output:
[echo] main
[echo] main
[echo] ${baz}
Running mvn validate -P p however yields:
[echo] main
[echo] prof
[echo] prof
That means that properties at least are merged, appending new items and replacing those that are redefined.
Also, if I add another plugin to the profile (such as surefire), it will execute when running the profile with mvn <phase> -P p, so the profile inherits antrun and adds surefire. Plugin re-definitions however replace the original; adding
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>validate</phase>
<configuration>
<target>
<echo>Tada!</echo>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
only prints Tada!, but no longer the original antrun output (even when changing the new addition's phase to initialize. Adding <inherited>true</inherited> to any of the two plugin definitions doesn't make a difference. The behaviour might be plugin-specific, though.
I am having issues with sonar picking up the jacoco analysis report. Jenkins however is able to pick up the report and display the results.
My project is a maven build, built by Jenkins. The jacoco report is generated by maven (configured in the pom). Sonar is executed by using the Jenkins plugin.
This is what I see on SonarQube:
This is the report i can see of the project in jenkins.
The maven plugin config:
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.6.4.201312101107</version>
<executions>
<execution>
<id>default-prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>default-report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>default-check</id>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
Jenkins Sonar Plugin config
You were missing a few important sonar properties, Here is a sample from one of my builds:
sonar.jdbc.dialect=mssql
sonar.projectKey=projectname
sonar.projectName=Project Name
sonar.projectVersion=1.0
sonar.sources=src
sonar.language=java
sonar.binaries=build/classes
sonar.tests=junit
sonar.dynamicAnalysis=reuseReports
sonar.junit.reportsPath=build/test-reports
sonar.java.coveragePlugin=jacoco
sonar.jacoco.reportPath=build/test-reports/jacoco.exec
The error in Jenkins console output can be pretty useful for getting code coverage to work.
Project coverage is set to 0% since there is no directories with classes. Indicates that you have not set the Sonar.Binaries property correctly
No information about coverage per test Indicates you have not set the Sonar.Tests property properly
Coverage information was not collected. Perhaps you forget to include debug information into compiled classes? Indicates that the sonar.binaries property was set correctly, but those files were not compiled in debug mode, and they need to be
Based on https://github.com/SonarSource/sonar-examples/blob/master/projects/tycho/pom.xml, the following POM works for me:
<properties>
<sonar.core.codeCoveragePlugin>jacoco</sonar.core.codeCoveragePlugin>
<sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
<sonar.jacoco.reportPath>${project.basedir}/../target/jacoco.exec</sonar.jacoco.reportPath>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.0.201403182114</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
</executions>
<configuration>
<destFile>${sonar.jacoco.reportPath}</destFile>
</configuration>
</plugin>
</plugins>
</build>
Setting the destination file to the report path ensures that Sonar reads exactly the file JaCoCo generates.
The report path should be outside the projects' directories to take cross-project coverage into account (e.g. in case of Tycho where the convention is to have separate projects for tests).
The reuseReports setting prevents the deletion of the JaCoCo report file before it is read! (Since 4.3, this is the default and is deprecated.)
Then I just run
mvn clean install
mvn sonar:sonar
I had the similar issue, 0.0% coverage & no unit tests count on Sonar dashboard with SonarQube 6.7.2:
Maven : 3.5.2,
Java : 1.8,
Jacoco : Worked with 7.0/7.9/8.0,
OS : Windows
After a lot of struggle finding for correct solution on maven multi-module project,not like single module project here we need to say to pick jacoco reports from individual modules & merge to one report,So resolved issue with this configuration as my parent pom looks like:
<properties>
<!--Sonar -->
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
<sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
<sonar.jacoco.reportPath>${project.basedir}/../target/jacoco.exec</sonar.jacoco.reportPath>
<sonar.language>java</sonar.language>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>3.4.0.905</version>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.9</version>
<configuration>
<destFile>${sonar.jacoco.reportPath}</destFile>
<append>true</append>
</configuration>
<executions>
<execution>
<id>agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
I've tried few other options like jacoco-aggregate & even creating a sub-module by including that in parent pom but nothing really worked & this is simple. I see in logs <sonar.jacoco.reportPath> is deprecated,but still works as is and seems like auto replaced on execution or can be manually updated to <sonar.jacoco.reportPaths> or latest. Once after doing setup in cmd start with mvn clean install then mvn org.jacoco:jacoco-maven-plugin:prepare-agent install (Check on project's target folder whether jacoco.exec is created) & then do mvn sonar:sonar , this is what I've tried please let me know if some other best possible solution available.Hope this helps!! If not please post your question..
Jenkins does not show coverage results as it is a problem of version compatibilities between jenkins jacoco plugin and maven jacoco plugin.
On my side I have fixed it by using a more recent version of maven jacoco plugin
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.9</version>
</plugin>
<plugins>
<pluginManagement>
<build>
I was facing the same problem and the challenge in my case was to configure Jacoco correctly and to configure the right parameters for Sonar. I will briefly explain, how I finally got SonarQube to display the test results and test coverage correctly.
In your project you need the Jacoco plugin in your pom or parent pom (you already got this). Moreover, you need the maven-surefire-plugin, which is used to display test results. All test reports are automatically generated when you run the maven build. The tricky part is to find the right parameters for Sonar. Not all parameters seem to work with regular expressions and you have to use a comma separated list for those (documentation is not really good in my opinion). Here is the list of parameters I have used (I used them from Bamboo, you might omit the "-D" if you use a sonar.properties file):
-Dsonar.branch.target=master (in newer version of SQ I had to remove this, so that master branch is analyzed correctly; I used auto branch checkbox in bamboo instead)
-Dsonar.working.directory=./target/sonar
-Dsonar.java.binaries=**/target/classes
-Dsonar.sources=./service-a/src,./service-b/src,./service-c/src,[..]
-Dsonar.exclusions=**/data/dto/**
-Dsonar.tests=.
-Dsonar.test.inclusions=**/*Test.java [-> all your tests have to end with "Test"]
-Dsonar.junit.reportPaths=./service-a/target/surefire-reports,./service-b/target/surefire-reports,
./service-c/target/surefire-reports,[..]
-Dsonar.jacoco.reportPaths=./service-a/target/jacoco.exec,./service-b/target/jacoco.exec,
./service-c/target/jacoco.exec,[..]
-Dsonar.projectVersion=${bamboo.buildNumber}
-Dsonar.coverage.exclusions=**/src/test/**,**/common/**
-Dsonar.cpd.exclusions=**/*Dto.java,**/*Entity.java,**/common/**
If you are using Lombok in your project, than you also need a lombok.config file to get the correct code coverage. The lombok.config file is located in the root directory of your project with the following content:
config.stopBubbling = true
lombok.addLombokGeneratedAnnotation = true
Include the sunfire and jacoco plugins in the pom.xml and
Run the maven command as given below.
mvn jacoco:prepare-agent jacoco:report sonar:sonar
<properties>
<surefire.version>2.17</surefire.version>
<jacoco.version>0.7.2.201409121644</jacoco.version>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire.version}</version>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
<executions>
<execution>
<id>default-prepare-agent</id>
<goals><goal>prepare-agent</goal></goals>
</execution>
<execution>
<id>default-report</id>
<phase>prepare-package</phase>
<goals><goal>report</goal></goals>
</execution>
</executions>
</plugin>
</plugins>
The presence of argLine configurations in either of surefire and jacoco plugins stops the jacoco report generation. The argLine should be defined in properties
<properties>
<argLine>your jvm options here</argLine>
</properties>
For me percentage coverage was not appearing in the sonarqube dashboard. I have added below property in our pom.xml to work.
<sonar.binaries>${project.basedir}/../target/classes</sonar.binaries>
Make sure that Sonarqube can find your test coverage file.
As somebody already mentioned the Sonarqube output should really be helpful here.
e.g.
WARN: No coverage information will be saved because LCOV file cannot be found.
I have a need to only run a specific jUnit when the mvn release:prepare is executed. I don't want this to run under mvn install or any other goal as this jUnit is designed to see if the developer has executed a database activity first.
Is there any way to either have the junit know, by parameter(?), that the process under execution is release:prepare?
Or, is there a way to define within the pom.xml that this jUnit only runs on that goal?
I've been doing some searching on this and I cannot seem to find a solution as I'm not that good at maven as of yet. Any help is appreciated!
I haven't done exactly what you want but the key is to use the <executions> section under the SureFire :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
... exclude the test from normal execution ...
</configuration>
<executions>
<execution>
<id>release-phase</id>
<phase>release-prepare</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
... fill this in to include the tests you want ...
</configuration>
</execution>
</executions>
<plugin>
You will also want to exclude that test in the normal <configuration> section.
There is some related information HERE
Others are close... but no cigar.
When Maven runs a release, there are no special phases for the release process. What you want to do is add a profile that is configured to include the test you want, e.g.
<profiles>
<profile>
<id>release-preflight-checks</id>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<id>release-preflight-checks</id>
<goals>
<goal>test</goal>
</goals>
<configuration>
.. include your test here
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
Then you need to configure surefire by default to not execute your preflight check
<build>
<plugins>
...
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
.. exclude your test here
</configuration>
</plugin>
...
</plugins>
</build>
And then finally, you need to tell Maven that this profile should be active only during release:prepare's forked execution
<build>
<plugins>
...
<plugin>
<artifactId>maven-release-plugin</artifactId>
<configuration>
...
<preparationGoals>clean verify -P+release-preflight-checks</preparationGoals>
...
</configuration>
</plugin>
...
</plugins>
</build>
Note: it is vitally important to have the + in front of the profile name so that you are adding the profile to the list of active profiles otherwise your release:prepare step will not be validating that the build works with the release profile active and you can have a subsequent release:perform fail.
Note: A less complex route would be to just put the surefire configuration into the release profile that you are using (by default that has the id of release but that is more error prone as you could change that via the parent pom - e.g. if you decide to push your project to central, the sonatype-oss-parent changes the release profile to sonatype-release - and then you won't see the build being failed as the test would not be executed until you change your pom to match new the release profile's id... using the -P+release-preflight-checks ensures that the profile is always active for release:prepare and additionally has the benefit of meeting the requesters original requirement completely - i.e. only runs for release:prepare and doesn't run for release:perform which would be the case if the execution was added to the release profile)