How to: SonarQube Code Coverage in Jenkins with Maven Project
Tags: jenkins, maven, sonarqube
Published: 2023-11-22 09:48:10

Hallo dear everyone whoever read this post. Today I'd love to share my learning journey with Jenkins. In today's post I will be using  [this code](https://dev.to/amalja0/lokomotif-use-case-4-implementing-spring-boot-scheduler-report-1h6l) as my use case and I'll be cooking from scratch which is installing Jenkins until we have the final dish of seeing the code coverage of our maven project in SonarQube. 

## Prerequisite
1. Installed Java version of 17 and have it configured in environment variable
2. Installed Maven version of 3.9.5 and have it configured in environment variable

## Installing Jenkins
1. Since I'm on Windows 10, I downloaded Jenkins lts version (mine is 2.426.1 LTS) from this [official link](https://www.jenkins.io/download/#downloading-jenkins). 
2. Open the installer and click `Next`. 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4ubniz5rkj42fvpg6h3k.png)
3. I'm going to use the default path so I just click `Next`. 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gjvqvlwoxh40tv32hc8l.png)
4. Since I cannot remember my own credential, I choose the `Run service as LocalSystem`. Then, click `Next`. 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g5xks1bd6qoem83czbyg.png)
5. I choose the default port which is 8085. Click Test Port then proceed to `Next`.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9ksgumry5i2cgb7cjawk.png)
6. Choose your java version. Mine is 17. If the path is correct, just click `Next`. 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n9uk777zefrhuhltar3z.png)
7. I don't understand what is happening here, so I assume it is safe to just click `Next`.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ajrlvxuo62hyepfn1l86.png)
8. And now Jenkins is ready to be installed! Don't forget to click the `Install` button. After that you might have to wait for a few times until installation is finish.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i43zu9tvmim2o68nibyg.png)
9. Now that installation is finished already, we can move on by clicking `Finish` button.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7nkg3ebdmv3k8m49q56c.png)

## Installing and Prepare SonarQube
1. I downloaded the latest version of SonarQube from [this official link](https://www.sonarsource.com/products/sonarqube/downloads/). The version is now at Version 10.3.
2. Unzip the file in your dedicated folder. Mine is on `D: drive`.
3. We might cannot start the SonarQube just now because we have to do thing to make sure the configuration is working.
4. To make things easier, open `sonar.properties` in code editor. You can find the file by entering the unzip directory result, go to `conf` directory, and there laying the `sonar.properties`. Now I uncomment few things in that file such as below lines:
    ```
    sonar.web.host=0.0.0.0
    sonar.web.port=9000
    sonar.search.port=0 // For this line you might want to change the port as well. Mine is from `9001` to `0`
    ```
5. Don't forget to save after making those changes.
6. Now let's try to run SonarQube server by going to `bin` directory, it is at the same level as `conf` directory. Choose the directory that match your operating system. For me, I choose `windows-x86-64`.
7. Open `command prompt` from that directory.
8. Run this command:
    ```
    StartSonar.bat
    ```
9. If it's working properly this is what will you see at the bottom of command line:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qh51eyz8g99ey4ejowvt.png)

## Updating POM.xml
You can find the original resource at [here](https://www.baeldung.com/sonarqube-jacoco-code-coverage) for this step. But it wasn't working at the first try since some of the versions are not compatible with my java version. But the final `POM.xml` looks like:
```
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>3.0.0</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.tujuhsembilan</groupId>
	<artifactId>scheduler</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>scheduler</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>17</java.version>
		<jacoco.version>0.8.8</jacoco.version>
		<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>
	<dependencies>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-hateoas</artifactId>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-quartz</artifactId>
		</dependency>

		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<scope>runtime</scope>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-mongodb</artifactId>
		</dependency>

		<dependency>
			<groupId>org.modelmapper</groupId>
			<artifactId>modelmapper</artifactId>
			<version>3.0.0</version>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-rest</artifactId>
		</dependency>

		<dependency>
			<groupId>org.postgresql</groupId>
			<artifactId>postgresql</artifactId>
			<scope>runtime</scope>
		</dependency>
		
		<dependency>
			<groupId>org.telegram</groupId>
			<artifactId>telegrambots-spring-boot-starter</artifactId>
			<version>6.1.0</version>
		</dependency>
		<dependency>
			<groupId>org.telegram</groupId>
			<artifactId>telegrambots-abilities</artifactId>
			<version>6.7.0</version>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>

		<dependency>
			<groupId>org.jacoco</groupId> 
			<artifactId>jacoco-maven-plugin</artifactId>
			<version>0.8.6</version>
		</dependency>

	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
			<plugin>
				<groupId>org.jacoco</groupId>
				<artifactId>jacoco-maven-plugin</artifactId>
				<version>${jacoco.version}</version>
				<executions>
					<execution>
						<id>jacoco-initialize</id>
						<goals>
							<goal>prepare-agent</goal>
						</goals>
					</execution>
					<execution>
						<id>jacoco-site</id>
						<phase>package</phase>
						<goals>
							<goal>report</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
	<repositories>
		<repository>
			<id>spring-releases</id>
			<name>Spring Releases</name>
			<url>https://repo.spring.io/libs-release</url>
		</repository>
	</repositories>
	<pluginRepositories>
		<pluginRepository>
			<id>spring-releases</id>
			<name>Spring Releases</name>
			<url>https://repo.spring.io/libs-release</url>
		</pluginRepository>
	</pluginRepositories>

</project>
```

## Running SonarQube in Local Environment
Now that I have the SonarQube and the project ready, I tried to run it, but some problem happened related to my maven settings. I hope you're not going to have the problem, but this is how I update my maven settings (you can find the settings at MAVEN_HOME/conf):
1. Adding sonarscanner plugin group.
    ```
    <pluginGroup>org.sonarsource.scanner.maven</pluginGroup>
    
    ```
2. Adding sonar profile.
    ```
        <profile>
            <id>sonar</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <!-- Optional URL to server. Default value is http://localhost:9000 -->
                <sonar.host.url>
                  http://localhost:9000
                </sonar.host.url>
            </properties>
        </profile>
    ```

Now, let's try to run SonarQube locally using command prompt

1. Open `command prompt` from the root of the project and run:
    ```
    mvn clean install
    ```
    If the build success you will have this on your command prompt:
    ![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zvr7ct59hzwiwgyniaj0.png)
2. Start the SonarQube server
3. Get back to the project command line and run:
    ```
    mvn sonar:sonar -Dsonar.login=admin -Dsonar.password=admin
    ```
    I did not change any credential, so by default the credential should be as what written above.
    
    ![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zie1wk2e50t8pemtf9q4.png)

4. If the build succeed, you might wanna see some previous line to know where you can open the coverage result. Mine is at `http://localhost:9000/dashboard?id=com.tujuhsembilan%3Ascheduler`. Disclaimer: you might need to login for the first time using the default credentials and have to change your password, but after that you should be good to go.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cy6tj4y4sa4jda8r0xgg.png)

## Creating Jenkins Maven Project and Implementing SonarQube

### Configuring Jenkins for the first time
1. Open `localhost:8085`. Jenkins is automatically start by default. From here, I will use the picture from the [official site](https://www.jenkins.io/doc/book/installing/windows/) since mine is already unlcoked. You will have to unlock jenkins by inputing the password provided in red block. Then click continue.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5ll9dtc6fsld6k4b7i2e.png)
2. You will be asked to install some plugins. I choose the `Install suggested plugins`.
3. Now you will be redirected to creating admin user. Just fill it as you wish and then click `Save and Continue`.
4. After that put `http://localhost:8085/` as Jenkins URL and click `Save and Finish`.
5. You are now supposed to be at the dashboard.

### Configuring SonarQube Scanner Plugin in Jenkins
1. In the Dashboard, click `Manage Jenkins`.
2. Choose `Plugins`.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tq2zmj7mtbe38l9bi33z.png)
3. Choose Available Plugin and search `SonarQube Scanner for Jenkins`. Tick the checkbox and click `Install`.

### Configuring Tools
1. In the Dashboard, click `Manage Jenkins`.
2. Choose `Tools`.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t5dj6gxe2xp5cljr9ni0.png)
3. Add JDK installations and fill it with your `JAVA_HOME`.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/279ugjtt9ehri0efsdkp.png)
4. Add Maven installations and fill it with your `MAVEN_HOME`.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oyynxwl2vyys8a7meb82.png)

### Getting SonarQube Token
1. Make sure that SonarQube server is still running.
2. Go to `http://localhost:9000/`.
3. On the right corner, click on your initial and choose `My Account`
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2c1yoctawpcnfvdq2i38.png)

4. Go to `Security` tab.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/csnnunrz2famjn8nv90i.png)

5. Fill the field and click `Generate`.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dj2s7qqp2kh09xyiij5h.png)
6. Copy the token to somewhere save because we are not able to see it again.

### Configuring System
1. In the Dashboard, click `Manage Jenkins`.
2. Choose `System`.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jiih8ggyyyrh7p6wdhi4.png)
3. Go to `SonarQube servers`. Tick the check box for `Environment variables`.
4. Add `SonarQube installations`.
5. Fill the name and Server URL
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p7v4p8qiazzaxyvy72nt.png)
6. In Server authentication token field, click `Add`.
7. Choose `Jenkins`. 
8. Add `Kind` dropdown, choose `Secret text`.
9. Leave the scope.
10. Enter the SonarQube secret token that you copy before.
11. Fill the `ID` with some name that make it easier to know what credential is that for.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s3x6ht6vqapv100mohwn.png)
12. Click `Add`.
13. Back to `Server authentication token` field, click the dropdown and choose the newly generated credential.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vw3grheedfyser6s3xxl.png)
14. Click `Save`.

### Creating Maven Project
1. In the dashboard, click `New Item`.
2. Enter the project name and choose Maven Project. Then Click `OK`.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2x4aqv6avbbla26qut0j.png)
3. Now we are going to configure build settings.
4. In `Source Code Management` section, choose `Git`. Make sure you alredy push the latest change especially the `POM.xml` change to your repository.
5. Enter your repository URL that you usually use to clone the project.
6. In `credential` fields, click `Add`, choose `Jenkins`.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qvvc381ad6lzk2qimfsr.png)
7. In `Kind` dropdown, choose `Username with password`.
8. Leave the Scope.
9. Enter your github username.
10. Enter your github password.
11. Again, fill the ID with some name that make it easier to know what credential is that for. 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/syvnj46mwcsc3v7tv2kh.png)
12. click `Add`.
13. Back to `credential` field dropdown, choose your github credential.
14. Moving to `Build Environment` section, tick the `Prepare SonarQube Scanner environment`, and again in the dropdown, choose the SonarQube token credential.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cnmkc89lgtnyk34wm791.png)
15. Moving to the  `Build` section you want to add this to the `Goals and options`.
    ```
    clean install $SONAR_MAVEN_GOAL
    ```
    ![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w80ccdo9zvj6ppkhl7cw.png)
16. Click `Save`.

### Building Maven Project
1. From Dashboard, you can see your new project. Click on the project.
2. In the sidebar you can see `Build Now` button. Click that.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/163t1u4mvrkumxdza5mq.png)
3. Wait for the build.
4. When the build is success, you can click `SonarQube` button in sidebar.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t4wjyjdvvzqizze54nco.png)
5. Now you have your code coverage running from Jenkins!
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sajdlhbtduvurjii4zdd.png)


The working repository can be seen [here](https://github.com/amalja0/jenkins-lokomotif-scheduler-report).