Oracle ADF and Gradle integration – part#2: SonarQube

Oracle ADF and Gradle integration – part#2: SonarQube

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

For a better understanding of this guide, I recommend you read my previous post:

 

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.

3
Leave a Reply

avatar
2 Comment threads
1 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
2 Comment authors
Oracle ADF and Gradle integration – part#3: Dependency Management – Better-CodingSudheerArthur Recent comment authors
  Subscribe  
newest oldest most voted
Notify of
Arthur
Guest
Arthur

Great job!

Sudheer
Guest
Sudheer

Nice post!

trackback

[…] Oracle ADF and Gradle integration – part#2: SonarQube […]

Close Menu