Multi-Modules Apache Maven Sonarqube Scanner

Multi-Modules Apache Maven Sonarqube Scanner

Author : Hamza EL YAAQOUBI

2020, Mar 28    

Introduction

In my current mission, I was faced with a fairly well-known but little documented problem, It’s the aggregation of the overall test coverage of an application built with Apache Maven.

That’s why I thought of writing this article in order to share and help the community ;)

Installations

In this article, I will use Docker to install the LTS version of SonarQube (v8.2.0), so I suppose that you’re familiar with Docker and its commands.

  • Docker

To check if docker is installed on your machine, type the following command :

hamza@hamza-perso:~$ docker -v

The result should be something like this :

If docker is not installed, please refer to the official web site.

  • SonarQube LTS

Firstly, start with search SonarQube docker image

hamza@hamza-perso:~$ docker search sonarqube

Secondly install SonarQube docker image

hamza@hamza-perso:~$ docker pull sonarqube

Finally run SonarQube docker container

hamza@hamza-perso:~$ docker run -d --name sonarqube -p 9000:9000 -p 9092:9092 sonarqube

And visit the local server on http://localhost:9000 :

Project

Architecture

The architecture of the project looks like :

This project contains essentially 3 sub modules. As example, we have a sub domain domain and web and coverage.

The first two modules contain java classes and units tests.

The sub module web depends on sub module domain, that’s mean we have a dependency of domain in web.

The third sub module coverage allows us to generate aggregate coverage report (xml format in my case) needed by SonarQube. It imports all of sub modules on which we want coverage to be imported.

Configuration

In the parent pom.xml file, I will just add jacoco-maven-plugin and maven-surefire-plugin as plugins management because they will be used by all of sub modules.

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>0.8.2</version>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>${maven-surfire.version}</version>
            </plugin>
        </plugins>
    </pluginManagement>
</build>

Then, I will configure a default enabled profile so as to collect coverage data from all of sub modules :

<profiles>
    <profile>
        <id>coverage-init</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.jacoco</groupId>
                    <artifactId>jacoco-maven-plugin</artifactId>
                    <executions>
                        <execution>
                            <id>prepare-agent</id>
                            <goals>
                                <goal>prepare-agent</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
        <properties>
            <sonar.host.url>http://localhost:9000/</sonar.host.url>
            <sonar.login>03a85d7c38de33297e41b57deb50573abe0086b6</sonar.login>
        </properties>
    </profile>
</profiles>

As you can see, I configured two properties sonar.host.url and sonar.login to avoid using them on command line.

In the next step, we will configure pom.xml file of coverage sub module to generate the target report by collecting data from sub modules using report-aggregate goal. This goal will create a file named jacoco.xml located at coverage/target/site/jacoco-aggregate

<build>
    <plugins>
        <plugin>
            <groupId>org.jacoco</groupId>
            <artifactId>jacoco-maven-plugin</artifactId>
            <executions>
                <execution>
                    <id>report</id>
                    <goals>
                        <goal>report-aggregate</goal>
                    </goals>
                    <phase>verify</phase>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Finally, we have to import the generated report in every sub modules on which this coverage should be imported.

According to the official documentation and analysis coverage documentation, the property sonar.jacoco.reportPaths is deprecated since 8.0 version and replaced by sonar.coverage.jacoco.xmlReportPaths

To accomplish this import, we have just to set sonar.coverage.jacoco.xmlReportPaths in every sub modules as follows :

<properties>
    <sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../coverage/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>
</properties>

Results

Once the configuration is done, you can type the following command to generate report and publish the result on Sonarqube server :

hamza@hamza-perso:~$ mvn install sonar:sonar

As you can see, after connecting to the SonarQube (login: admin, password: admin), you can check the result of the coverage :

The all of source code is located here.

That’s all !

Don’t hesitate to send me your feedback :)

Thank you.