SonarQube is an open-source platform for continuous inspection of code quality. It’s one of ‘must have’ tools in every software development company. This tutorial helps you to integrate any Java based application (in this case Oracle ADF) with Sonar using one of Gradle plugins.
Objectives
In this tutorial you will learn how to:
- create fully functional SonarQube container using docker-compose.
- perform static code analysis of Oracle ADF using Gradle.
Before you start
I. Creating SonarQube container
Current version of SonarQube requires database to store analysis data. The creation of two separate containers and their synchronization can be somewhat cumbersome. We can use Docker Compose to make it easier. It is is a tool for defining and running multi-container applications.
Docker Compose installation
At first, make sure you have docker installed correctly (here you can find how to properly install docker on linux OS). Install docker-compose tool by running command:
sudo apt-get install docker-compose #Debian based distributions yum install docker-compose #RedHat based distributions
Creating docker-compose.yml file
Docker Compose requires docker-compose.yml file with is a definition of multi-container environment. More about the file structure you can find on the project website. For the purposes of this tutorial I used official SonarSource docker-compose recipe.
Create an empty directory with docker-compose.yml file like below:
#https://github.com/SonarSource/docker-sonarqube/blob/master/recipes.md #Please make sure that you use latest version. version: "2" services: sonarqube: image: sonarqube ports: - "9000:9000" networks: - sonarnet environment: - SONARQUBE_JDBC_URL=jdbc:postgresql://db:5432/sonar volumes: - sonarqube_conf:/opt/sonarqube/conf - sonarqube_data:/opt/sonarqube/data - sonarqube_extensions:/opt/sonarqube/extensions - sonarqube_bundled-plugins:/opt/sonarqube/lib/bundled-plugins db: image: postgres networks: - sonarnet environment: - POSTGRES_USER=sonar - POSTGRES_PASSWORD=sonar volumes: - postgresql:/var/lib/postgresql # This needs explicit mapping due to https://github.com/docker-library/postgres/blob/4e48e3228a30763913ece952c611e5e9b95c8759/Dockerfile.template#L52 - postgresql_data:/var/lib/postgresql/data networks: sonarnet: driver: bridge volumes: sonarqube_conf: sonarqube_data: sonarqube_extensions: sonarqube_bundled-plugins: postgresql: postgresql_data:
The environment described in the recipe consists of two containers (PostgreSQL database and SonarQube) connected to internal sonarnet network. SonarQube is exposed on port 9000 .
Starting/Stopping environment
Familiarize yourself with the following commands:
docker-compose up #create and start the environment; use -d switch to run as daemon docker-compose down #stop the environment and remove containers docker-compose start #start the environment; use -d switch to run as daemon docker-compose stop #stop the environment
Go to the directory where you created docker-compose.yml file and run:
docker-compose up
After successful run you can stop environment by pressing Ctrl+c .
Logging in to SonarQube
Run environment as daemon by adding -d switch:
docker-compose up -d
Wait a few seconds and open http://localhost:9000 .
Now you can Log in. Default SonarQube username/password is admin/admin.
II. Create Oracle ADF application
You can use your own application or just download sample application. If you use your own application remember to integrate it with Gradle as I showed you in this post.
The sample application contains standard ADF Model/ViewController application and it is integrated with Gradle. The ViewController project contains SampleBean class which will be analysed by SonarQube.
. ├── ADFGradle │ ├── adf-gradle │ │ └── build.gradle │ ├── ADFGradleSonar.jws │ ├── Model │ ├── src │ └── ViewController │ ├── src │ └── com │ └── bettercoding │ └── docker │ └── view │ └── bean │ └── SampleBean.java └── gradle-wrapper
III. Configure Gradle project
Now it’s time to integrate SonaQube with Gradle project. In this tutorial I’ll use org.sonarqube plugin. More about the plugin you can find at the official site.
Go to adf-gradle directory and edit build.gradle file. Add plugin repository and classpath dependency to sonarqube-gradle-plugin at the beginning of the file (lines:1-14). After that just apply org.sonarqube plugin before group property (line 17).
buildscript { repositories { maven { url "https://plugins.gradle.org/m2/" } } dependencies { classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.6.2" } } plugins { id "org.sonarqube" version "2.6.2" } apply plugin: "org.sonarqube" group 'com.bettercoding' version '1.0-SNAPSHOT' ...
Sonar configuration
After added org.sonarqube plugin we have to provide some sonar properties:
- sonar.host
- sonar.projectKey
- sonar.projectVersion
- sonar.language – you can specify only one language (i.e. xml, java). Leave it empty for multi-language project
- sonar.projectBaseDir – all analysed sources have to be inside projectBaseDir
- sonar.binaries – coma separated paths to generated artefacts
- sonar.sources – coma separated paths to the sources of application
- more you can find at the official SonarQube website.
... ext { middlewareHome = project.hasProperty("middlewareHome") ? project.property("middlewareHome") : null ojDeployExec = middlewareHome + "/Oracle_Home/jdeveloper/jdev/bin/ojdeploy" adfWorkspace = ".." adfWorkspaceDeployDir = "${adfWorkspace}/deploy" gradleTargetDir = "./build" ojDeployBuildfile = "./ojdeploy-buildfile.xml" ojDeployAppWorkspaceDir = new File(adfWorkspace).getAbsolutePath() } sonarqube { //More: https://docs.sonarqube.org/display/SONAR/Analysis+Parameters properties { properties["sonar.host"] = "http://localhost:9000" properties["sonar.projectKey"] = "${project.group}:${project.name}" properties["sonar.projectVersion"] = "${project.version}" properties["sonar.language"] = "java" properties["sonar.projectBaseDir"] = "${adfWorkspace}" properties["sonar.binaries"] = "${project.ext.adfWorkspaceDeployDir}" properties["sonar.sources"] = "ViewController/,Model/,src" } } task checkAdfEnvironment { ...
Task order
You can also add task order dependency (line 2). This will ensure the right order of task execution. If you want to enforce assemble before sonarqube task you can add line 3.
... tasks.sonarqube.mustRunAfter assemble tasks.sonarqube.dependsOn assemble
After all modifications your build.gradle file should look like below:
buildscript { repositories { maven { url "https://plugins.gradle.org/m2/" } } dependencies { classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.6.2" } } plugins { id "org.sonarqube" version "2.6.2" } apply plugin: "org.sonarqube" group 'com.bettercoding' version '1.0-SNAPSHOT' ext { middlewareHome = project.hasProperty("middlewareHome") ? project.property("middlewareHome") : null ojDeployExec = middlewareHome + "/Oracle_Home/jdeveloper/jdev/bin/ojdeploy" adfWorkspace = ".." adfWorkspaceDeployDir = "${adfWorkspace}/deploy" gradleTargetDir = "./build" ojDeployBuildfile = "./ojdeploy-buildfile.xml" ojDeployAppWorkspaceDir = new File(adfWorkspace).getAbsolutePath() } sonarqube { //More: https://docs.sonarqube.org/display/SONAR/Analysis+Parameters properties { properties["sonar.host"] = "http://localhost:9000" properties["sonar.projectKey"] = "${project.group}:${project.name}" properties["sonar.projectVersion"] = "${project.version}" properties["sonar.language"] = "java" properties["sonar.projectBaseDir"] = "${adfWorkspace}" properties["sonar.binaries"] = "${project.ext.adfWorkspaceDeployDir}" properties["sonar.sources"] = "ViewController/,Model/,src" } } task checkAdfEnvironment { group "oracle-adf" description "Check if ADF environment configured correctly" doLast { if (project.ext.middlewareHome == null ) { throw new GradleException("Missing project property [middlewareHome]. " + "Add -PmiddlewareHome=<MIDDLEWARE_HOME> switch to gradle invomation") } } } task clean { group "oracle-adf" description "Clean ADF workspace" mustRunAfter checkAdfEnvironment dependsOn checkAdfEnvironment doLast { println "Cleaning project ${project.name}" println "Deleting ${project.ext.adfWorkspaceDeployDir}" delete fileTree(project.ext.adfWorkspaceDeployDir) println "Deleting ${project.ext.gradleTargetDir}" delete fileTree(project.ext.gradleTargetDir) } } task assemble { group "oracle-adf" description "Build ADF artficats" mustRunAfter clean, checkAdfEnvironment dependsOn clean, checkAdfEnvironment doLast { println "Building using OJDeploy:" //Build exec { commandLine project.ext.ojDeployExec, '-buildfile', project.ext.ojDeployBuildfile, '-define', "app.workspace.dir=${project.ext.ojDeployAppWorkspaceDir}" } } } tasks.sonarqube.mustRunAfter assemble
Performing Sonar analysis
Make sure that you have SonarQube service started. Run gradlew tasks command. As you can see new task appeared.
Oracle-adf tasks ---------------- assemble - Build ADF artficats checkAdfEnvironment - Check if ADF environment configured correctly clean - Clean ADF workspace Other tasks ----------- sonarqube - Analyzes root project 'adf-gradle' and its subprojects with SonarQube. To see all tasks and more detail, run gradlew tasks --all To see more detail about a task, run gradlew help --task <task> BUILD SUCCESSFUL
To perform clean, build and SonarQube analysis run:
./gradlew clean assemble sonarqube -PmiddlewareHome=<MIDDLEWARE_HOME>
You may also run ./gradlew sonarqube to perform only sonar analysis without project assembling. After few seconds you will see BUILD SUCCESSFUL message like below:
better-coding@bc-vbox:~/bc-workspace$ ./gradlew sonarqube :sonarqube ... Bytecode of dependencies was not provided for analysis of source files, you might end up with less precise results. Bytecode can be provided using sonar.java.libraries property Missing blame information for the following files: * ViewController/src/com/bettercoding/docker/view/bean/SampleBean.java This may lead to missing/broken features in SonarQube BUILD SUCCESSFUL Total time: 5.568 secs
Go to http://localhost:9000/ and watch the results.
You can download the final version of application from here.
If you think this tutorial is valuable, please leave me +1 or share it. This action will allow me to reach a wider audience.
Thank you.
Great job!
Nice post!
[…] Oracle ADF and Gradle integration – part#2: SonarQube […]