Jacoco coverage of unit test code - maven-3

I'm converting an ANT build to Maven. I don't use Sonar.
In Maven, Jacoco doesn't seem to report about coverage of the unit tests themselves, while ANT does. I've been trying to get this for my Maven build as well, but I haven't been able to find anything.
It seems like I should add an <include> to the prepare-agent goal, but I'm not sure what to include. I've tried src/test/java/* and all kinds of variations on that theme, but none works.
How can I configure Jacoco in Maven such that it does report the coverage of unit test code?

Turns out, the only way to do this, is to use the maven-antrun-plugin.
There's no need to add an <include> to the prepare-agent goal, because all information is present in the jacoco.exec file it generates, including the unit test code.
The report goal doesn't include it, though, and it can't be configured to use it either. You would need to specifically set the classfiles and sourcefiles properties, and the Maven Jacoco plugin won't let you do this.
Hence, you need the Maven Antrun plugin, and configure and call it from there.
<plugins>
<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>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<id>default-report</id>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<taskdef name="report" classname="org.jacoco.ant.ReportTask" classpathref="maven.plugin.classpath" />
<report>
<executiondata>
<file file="${project.build.directory}/jacoco.exec" />
</executiondata>
<structure name="Coverage">
<classfiles>
<fileset dir="${project.build.directory}/classes"/>
<fileset dir="${project.build.directory}/test-classes"/>
</classfiles>
<sourcefiles encoding="UTF-8">
<fileset dir="src/main/java"/>
<fileset dir="src/test/java"/>
</sourcefiles>
</structure>
<check failonviolation="true" violationsproperty="violation">
<rule element="BUNDLE">
<limit counter="INSTRUCTION" value="COVEREDRATIO" minimum="0.95" />
</rule>
</check>
<html destdir="${project.build.directory}/jacoco-internal"/>
</report>
</target>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.jacoco</groupId>
<artifactId>org.jacoco.ant</artifactId>
<version>${jacoco.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>

Related

Maven antrun plugin missing target task after combining from multiple profiles

This is quite an interesting problem I have 2 profiles as defined below. I'm using Maven 3.6.3 with the latest Java 11.
<profiles>
<profile>
<id>assembly-unzip</id>
<build>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<unzip src="src1.zip" dest="dest10" />
<copy file="copy1.txt" todir="dest11"/>
</target>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>assembly-get</id>
<build>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<mkdir dir="download" />
<get src="src20" dest="dest"/>
<unzip src="dest/src20}" dest="dest"/>
<get src="src21" dest="dest"/>
<unzip src="dest/src21}" dest="dest"/>
</target>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
When I activate BOTH profiles, I get from (-X) that Maven combines the 2 antrun plugin configurations into a single configuration that looks like this:
<configuration>
<exportAntProperties default-value="false"/>
<failOnError default-value="true"/>
<localRepository>${localRepository}</localRepository>
<mavenProject default-value="${project}"/>
<pluginArtifacts>${plugin.artifacts}</pluginArtifacts>
<session default-value="${session}"/>
<skip default-value="false">${maven.antrun.skip}</skip>
<sourceRoot>${sourceRoot}</sourceRoot>
<target>
<mkdir dir="download"/>
<get src="src20" dest="dest"/>
<unzip src="dest/src20}" dest="dest"/>
<get src="src21" dest="dest"/>
<unzip src="dest/src21}" dest="dest"/>
<copy file="copy1.txt" todir="dest11"/>
</target>
<testSourceRoot>${testSourceRoot}</testSourceRoot>
<versionsPropertyName default-value="maven.project.dependencies.versions"/>
</configuration>
What's missing from the combined configuration is:
<unzip src="src1.zip" dest="dest10" />
I've tried this multiple times in different ways and the long and short of it is that it seems like if the from the 1st profile that Maven processes has an task (for example) then any tasks in the of the 2nd profile will be ignored and NOT part of the combined configuration. Please be aware that i'm just using as an example. I've tried it with other tasks and see the same behavior.
Any thoughts?
You can do two things:
Use an <id> to each of your execution: without it, you get the default, and that's what maven use to determine duplicate configuration items when it merge them.
Use combine.children and so on. I would advise you not to do that, but you may read more on blog.sonatype.com or at maven.apache.org.
You could also directly use the power of ant, create target and invoke it conditionally using condition.

How to have a pom.xml but prevent Maven being used for building?

I have a project for which I have created a pom.xml. However, I'm not using Maven as my build system, I am using something else (e.g. ANT). But I want the pom.xml to exist for the use of other tools, e.g. IDEs. How can I make sure, that if someone downloads my project and tries to build it with Maven, they will get a clear indication that they are doing the wrong thing?
Add the following to pom.xml:
<properties>
<maven.build.not.supported>
Do not use Maven to build this module. Please see README.html for
instructions on how to build it.
</maven.build.not.supported>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>fail-clean-lifecycle</id>
<phase>pre-clean</phase>
<configuration>
<tasks>
<fail message="${maven.build.not.supported}" />
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
<execution>
<id>fail-default-lifecycle</id>
<phase>validate</phase>
<configuration>
<tasks>
<fail message="${maven.build.not.supported}" />
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
<execution>
<id>fail-site-lifecycle</id>
<phase>pre-site</phase>
<configuration>
<tasks>
<fail message="${maven.build.not.supported}" />
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Since we cannot apparently bind a plugin execution to multiple phases, we need to repeat the execution block three times, one for each of the built-in lifecycles (clean, default and site). To avoid duplication of the failure message, we store it in a Maven property and reuse that property in each execution. In each execution we bind to the first phase of the lifecycle to fail it immediately.

Performing specific Ant tasks in pom.xml

I've been trying to find a good way to specify some ant tasks(defined in build.xml) in pom.xml of a Maven project. For example, in my build.xml, I have the following line of code;
<target name="clean">
<delete dir="dist"/>
<delete dir="build"/>
</target>
How can I perform this action in my pom.xml?
The following is the maven-way of doing such things:
<build>
[...]
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>2.5</version>
<configuration>
<filesets>
<fileset>
<directory>${project.basedir}/dist</directory>
<includes>
<include>**/*</include>
</includes>
</fileset>
<fileset>
<directory>${project.basedir}/build</directory>
<includes>
<include>**/*</include>
</includes>
</fileset>
</filesets>
</configuration>
</plugin>
[...]
</build>
Use maven-antrun-plugin.
You can put in the target ANT commands.
Here the example of the maven-antrun-plugin on phase install that execute your commands:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<id>file-exists</id>
<phase>install</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<delete dir="dist"/>
<delete dir="build"/>
</target>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

How can I deploy a zip file created with the maven-antrun-plugin?

I'm using the maven-antrun-plugin to do a bunch of work with Ant, which ultimately results in a zip file. I'd like to deploy the zip file to our maven server (Artifactory). The maven-antrun-portion works as intended and successfully creates the zip file; however deployment fails with the following error message:
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.maven.plugins:maven-deploy-plugin:2.6:deploy (default-deploy) on project projectname: The packaging for this project did not assign a file to the build artifact
My POM file is as follows:
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.company.division</groupId>
<artifactId>projectname</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<parent>
<groupId>com.company.product</groupId>
<artifactId>parentproject</artifactId>
<version>1.0.0</version>
</parent>
<distributionManagement>
<snapshotRepository>
<id>artifactory</id>
<name>artifactory-snapshots</name>
<url>http://localartifactoryserver/artifactory/libs-snapshot-local</url>
<uniqueVersion>false</uniqueVersion>
</snapshotRepository>
</distributionManagement>
<dependencies>
<!-- Some dependencies... -->
</dependencies>
<build>
<plugins>
<!-- Compiler plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<encoding>UTF8</encoding>
<optimize>true</optimize>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<configuration>
<target>
<!-- Do lots of other stuff with Ant. -->
<!-- Create a zip file. -->
<zip basedir="mydir" destfile="${WORKSPACE}/MyZip.zip" />
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.6</version>
<configuration>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<version>${project.version}</version>
<packaging>zip</packaging>
<file>MyZip.zip</file>
<url>${project.distributionManagement.snapshotRepository.url}</url>
</configuration>
</plugin>
</plugins>
</build>
</project>
When I invoke this (from the parent POM) with mvn -U -pl projectname clean deploy I get the aforementioned error during the deploy phase. Does anyone know what I'm doing wrong or how I can fix this?
The solution that worked for me (I'm not sure if it is ideal, it seems rather hackish) was to switch to the deploy:deploy-file goal:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.6</version>
<goals>
<goal>deploy-file</goal>
</goals>
<configuration>
<repositoryId>artifactory</repositoryId>
<packaging>zip</packaging>
<generatePom>true</generatePom>
<url>${project.distributionManagement.snapshotRepository.url}</url>
<artifactId>${project.artifactId}</artifactId>
<groupId>${project.groupId}</groupId>
<version>${project.version}</version>
<file>${WORKSPACE}/MyZip.zip</file>
</configuration>
</plugin>
and invoke it explicitly:
mvn -U -X -pl projectname clean install deploy:deploy-file
The solution worked for me is to add the <attachartifact> tag after zip creation, filled with the same path and zip filename . So something like:
<executions>
<execution>
<id>zip-artifacts</id>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<zip destfile="${project.build.directory}/MyStuff-${project.version}.zip" update="true" comment="This is my comment...">
<fileset dir="${project.build.directory}/MyStuff" />
</zip>
<attachartifact file="${project.build.directory}/MyStuff-${project.version}.zip" type="zip" />
</target>
</configuration>
</execution>
</executions>
Remember that the zip file has to exists, otherwise attachartifact returns "file does not exists" error (consider to use whenempty="create" in tag in order to avoid errors).
While looking for a way to add comment to a zip file I found this question. The deploy worked fine but had troubles with the maven release to post into nexus. The solution below solved my problem, I made an empty zip assembly and then simply replaced it with the zip file from the ant task which allowed me to add the comment to the zip file.
This way the artifact is generated and not transitive.
<?xml version="1.0" encoding="UTF-8"?>
<assembly>
<id>${project.build.finalName}</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.build.directory}/MyStuff/emptydir</directory>
<outputDirectory></outputDirectory>
<useDefaultExcludes>true</useDefaultExcludes>
</fileSet>
</fileSets>
<plugin>
<!-- make an assembly (zip the LxBase) for the distribuition -->
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>docs-assembly</id>
<phase>package</phase>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>src/main/assembly/assemble.xml</descriptor>
</descriptors>
</configuration>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<id>zip-artifacts</id>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<zip destfile="${project.build.directory}/MyStuff-${project.version}.zip" update="true" comment="This is my comment...">
<fileset dir="${project.build.directory}/MyStuff" />
</zip>
</target>
</configuration>
</execution>
</executions>
</plugin>

How to run an ant target from Maven2?

How do i run a specific target with the antrun-plugin from the command line?
mvn antrun:run doesn't make it run.
<project>
...
<build>
<plugins>
...
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>myExecution</id>
<phase>deploy</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<ant target="myTarget" inheritRefs="true">
...
</ant>
</tasks>
</configuration>
</execution>
</executions>
<dependencies>
...
</dependencies>
</plugin>
...
</plugins>
...
</build>
...
</project>
How do i run a specific target with the antrun-plugin from the command line?
To strictly answer this question, you can't, and you don't.
What you can do is either:
1. provide a plugin-level configuration
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<configuration>
....
</configuration>
</plugin>
And this configuration will be used when invoking the plugin (regardless of how the plugin is invoked: from the cli, a part of the lifecycle).
2. provide an execution-level configuration (which is what you did)
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>myExecution</id>
<phase>deploy</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<ant target="myTarget" inheritRefs="true">
...
</ant>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
And then invoke the phase to which the plugin is bound (deploy in this case).
3. provide an execution-level configuration for the special default-cli execution Id
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>default-cli</id>
<configuration>
<tasks>
<ant target="myTarget" inheritRefs="true">
...
</ant>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
As of Maven 2.2.0 (see MNG-3401), goals invoked directly from the command line can be configured in the POM separately from other plugin invocations using a special executionId called default-cli. In other words, the above configuration would be only used when invoking the plugin from the command line.
But in any case, you can't invoke a specific Ant target inside a configuration element. You could maybe mess with profiles to implement something approaching but, if you really want to go this direction, my advice would be to use Ant.
References
Guide to Configuring Default Mojo Executions
You can, by being sneaky.
In pom.xml:
...
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<configuration>
<target>
<ant target="trampoline" />
</target>
</configuration>
</plugin>
...
In build.xml:
...
<target name="trampoline">
<echo message="Executing target '${mvnAntTarget}'"/>
<antcall target="${mvnAntTarget}" />
</target>
<target name="testTarget">
<echo message="Yay, I'm a test target.."/>
</target>
....
And then, by running:
$ mvn antrun:run -DmvnAntTarget=testTarget
The Ant's testTarget will be run.
Refer to the example at : http://docs.codehaus.org/display/MAVENUSER/Antrun+Plugin
Basically write your ant targets in a regular build.xml.
Then define a single <target> under configuration where you dynamically decide what is the buildFile name and targetName and do a
<ant andfile="${buildFile}" target="${targetName}" inheritAll="true" inheritRefs="true"/>
I'm not too sure that's the reason it doesn't work but the syntax you're using is deprecated. You should have something like:
<configuration>
<target name="myTarget">
<!--
Place any Ant task here. You can add anything
you can add between <target> and </target> in a
build.xml.
-->
</target>
<configuration>
More details here:
http://maven.apache.org/plugins/maven-antrun-plugin/usage.html

Resources