SonarQube can be configured to use many database system. Here I have used MySQL. If you want to use another database system such as Oracle you can follow the same procedure.
First you need to install MySQL. Installation instructions can be found on http://dev.mysql.com/doc/refman/5.5/en/installing.html
Log on to mysql
mysql -u root -p
Enter password if there is a one, if you didn't set up a password during the installation just press enter.
You may need to delete the empty user first if you haven't done so yet.
DELETE FROM mysql.user WHERE User='';
Create a database to be used for Sonar. You can use any suitable name. I have used the name "SONARDB" here.
CREATE DATABASE SONARDB CHARACTER SET utf8 COLLATE utf8_general_ci;
Create a new database user SONARDB with password PASSWORD and grant all the privileges. Again you can choose any valid user name.
grant all privileges on SONARDB.* to 'SONARDB'@'%' identified by 'PASSWORD';
flush privileges;
You can download SonarQube using the following link. For commercial applications it will be better to use a LTS version. The version I have used here is 3.5.1 ( http://dist.sonar.codehaus.org/sonar-3.5.1.zip). But this procedure should work for newer version also (At least up to 3.7, I haven't tested for later versions).
http://www.sonarqube.org/downloads/
Go to conf folder and open sonar.properties file. Only thing we need to configure here is the database connection information.
Set sonar database username and password properties.
sonar.jdbc.username: SONARDB
sonar.jdbc.password: PASSWORD
Uncomment the following line and change the db name form sonar to SONARDB
sonar.jdbc.url: jdbc:mysql://localhost:3306/SONARDB?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true
Go to bin folder. You can see several folders with several platform names. Select the one most suitable for your platform. ( For CentOS 6.4 64bit, Linux 32 bit Sonar worked without a problem )
Start Sonar using following command.
sh sonar.sh start
When the project is complex with several modules, it is easier to define sonar related configuration in separate files. Anyway for small projects you can define all the properties in the same build.xml.
First create a file named sonar-main.xml. This file will be the root of all sonar related configuration files.
Download sonar-ant-task jar file using the following link and put it into the lib folder in your ant installation. sonar-ant-task-2.1.jar
Download jacoco-ant-task jar file using the following link and put it into the lib folder in your ant installation. http://www.eclemma.org/jacoco/
sonar-main.xml
<?xml version="1.0" encoding="US-ASCII"?>
<project name="sonar" default="sonar" xmlns:sonar="antlib:org.sonar.ant" >
<property name="sonar.project.key" value="org.myproject"/>
<property name="sonar.project.name" value="My Project"/>
<property name="sonar.project.java.version" value="1.6"/>
<property name="sonar.dir" value="${basedir}/target/sonar"/>
<property name="sonar.host.url" value="http://localhost:9000"/>
<property name="sonar.jdbc.url" value="jdbc:mysql://localhost:3306/SONARDB?useUnicode=true&characterEncoding=utf8"/>
<property name="sonar.jdbc.driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="sonar.jdbc.username" value="SONARDB"/>
<property name="sonar.jdbc.password" value="PASSWORD"/>
<target name="sonar" >
<taskdef uri="antlib:org.sonar.ant" resource="org/jacoco/ant/antlib.xml">
<!--<!– Update the following line, or put the "jacocoant.jar" file in your "$HOME/.ant/lib" folder –>-->
<classpath path="path/to/sonar/ant/task/lib/sonar-ant-task.jar" />
</taskdef>
<taskdef uri="antlib:org.jacoco.ant" resource="org/jacoco/ant/antlib.xml">
<!--<!– Update the following line, or put the "jacocoant.jar" file in your "$HOME/.ant/lib" folder –>-->
<classpath path="path/to/jacoco/ant/task/lib/jacocoant.jar" />
</taskdef>
<property name="sonar.modules"
value="sdk/oranges/sonar-oranges.xml,sdk/apples/sonar-apples.xml"/>
<!-- The workDir directory is used by Sonar to store temporary files -->
<sonar:sonar key="${sonar.project.key}" version="${target.version}" xmlns:sonar="antlib:org.sonar.ant">
<!-- SERVER ON A REMOTE HOST -->
<property key="sonar.host.url" value="${sonar.host.url}"/>
<property key="sonar.jdbc.url" value="${sonar.jdbc.url}"/>
<property key="sonar.jdbc.driverClassName" value="${sonar.jdbc.driverClassName}"/>
<property key="sonar.jdbc.username" value="${sonar.jdbc.username}"/>
<property key="sonar.jdbc.password" value="${sonar.jdbc.password}"/>
<property key="sonar.java.source" value="${sonar.project.java.version}"/>
<property key="sonar.java.target" value="${sonar.project.java.version}"/>
<property key="sonar.build-stability.url" value="${sonar.host.url}"/>
<property key="sonar.projectName" value="${sonar.project.name}"/>
<property key="sonar.core.codeCoveragePlugin" value="jacoco" />
<property key="sonar.jacoco.reportPath" value="target/jacoco.exec" />
<property key="sonar.dynamicAnalysis" value="reuseReports"/>
</sonar:sonar>
</target>
</project>
In each module, a xml file should be created with details about module name, locations of sources, binaries, test reports and other required properties.
File name : sonar-oranges.xml
Path : sdk/oranges/sonar-oranges.xml
<?xml version="1.0" encoding="US-ASCII"?>
<project name="Oranges" default="all" basedir=".">
<property name="sonar.java.source" value="1.6"/>
<property name="sonar.java.target" value="1.6"/>
<property name="sonar.projectKey" value="org.myproject"/>
<property name="sonar.projectName" value="Oranges"/>
<property name="sonar.sources" value="src/share"/>
<property name="sonar.binaries" value="target/layout/WEB-INF/classes"/>
<property name="sonar.tests" value="src/test"/>
<property name="sonar.surefire.reportsPath" value="target/test/report" />
<path id="lib.path">
<fileset dir="../../target/layout/core/lib">
<include name="**/*.jar"/>
</fileset>
<fileset dir="../../target/layout/tomcat/lib">
<include name="**/*.jar"/>
</fileset>
</path>
<pathconvert property="sonar.libraries" pathsep="," refid="lib.path" targetos="unix"/>
</project>
sonar.sources property should point to the directory where source files belonging to the module located.
sonar.binaries should point to the directory where .class files belonging to the module located.
sonar.tests should point to the directory where Junit test files located.
sonar.surefire.reportsPath property should point to the directory where Junit xml test reports are created after executing the test cases. Sonar uses these reports to display details of test execution in the dashboard.
A target should be defined in the main build.xml file pointing to sonar-main.xml file.
<target name="run-sonar" depends="sonar-clean">
<ant antfile="sonar-main.xml" target="sonar"/>
</target>
To analyse code coverage with Jacoco, it is required to run Unit tests with Jacoco agent. There are two methods to add Jacoco agent to the unit tests.
Method 1:
If you plan to run Jacoco agent every time units tests are run, this method can be used.
<!-- Run your unit tests, adding the JaCoCo agent -->
<jacoco:coverage destfile="target/jacoco.exec" xmlns:jacoco="antlib:org.jacoco.ant">
<junit fork="yes" dir="${basedir}" failureProperty="test.failed">
<classpath location="${classes.dir}" />
<classpath refid="classpath" />
<formatter type="xml" />
<batchtest todir="${reports.junit.xml.dir}">
<fileset dir="${test.dir}">
<include name="**/*Test.java" />
</fileset>
</batchtest>
</junit>
</jacoco:coverage>
Method 2:
If you do not want to run Jacoco agent every time the tests are running, you can use this method. This method will be more useful than the earlier method, because running Jacoco agent will increase the running time of test cases.
First you use the value of run-coverage property to decide whether or not to pass Jacoco agent as a JVM argument.
<if>
<equals arg1="${run-coverage}" arg2="true"/>
<then>
<jacoco:agent property="agentvmparam" destfile="target/jacoco.exec"
xmlns:jacoco="antlib:org.jacoco.ant"/>
</then>
<else>
<property name="agentvmparam" value=""/>
</else>
</if>
If the run-coverage property is set to true, Jacoco agent will be passed as a JVM argument. Otherwise it will pass a empty value for agentvmparam.
<junit fork="yes" dir="${basedir}" failureProperty="test.failed">
<!-- Run unit tests, adding the JaCoCo agent -->
<jvmarg line="${agentvmparam}"/>
<classpath location="${classes.dir}" />
<classpath refid="classpath" />
<formatter type="xml" />
<batchtest todir="${reports.junit.xml.dir}">
<fileset dir="${test.dir}">
<include name="**/*Test.java" />
</fileset>
</batchtest>
</junit>
You can set the parameter value only when running test cases to collect coverage data by using "antcall".
<target name="run-coverage">
<antcall target="test">
<param name="run-coverage" value="true"/>
</antcall>
</target>



