[Originally posted on G+ on the 17th of January 2012]

I finally completed the integration of #Sonar (http://www.sonarsource.org) in our PDEBuild (http://eclipse.org/pde/pde-build/) based build system.

Requirements

I was looking for an integration approach that would allow us to run the analysis on our OSGi bundles and to globally define default values for as many configuration parameters as possible (to avoid copy/pasting the same Sonar configuration values in every project build script), but I also wanted to provide project owners with convenient means of tweaking the configuration parameters of their projects and overriding default values when appropriate.

PDEBuild customBuildCallbacks.xml

After playing a bit with the many customisation hooks that #PDEBuild offers (see http://help.eclipse.org/galileo/topic/org.eclipse.pde.doc.user/tasks/pde_customization.htm) I believe that the best option is to use per project custom build call backs
(http://help.eclipse.org/indigo/index.jsp?topic=/org.eclipse.pde.doc.user/tasks/pde_custom_callbacks.htm).
These callbacks consist in a Ant script containing a number of predefined targets (a template is included in the #PDEBuild bundle) that, if declared in the project's build.properties file, will be invoked by #PDEBuild during many steps of each bundle's build process.

Some implementation details

I want Sonar analysis to take place if and only if the source code compiles successfully, therefore I believe the most appropriate callback is the post.name target (which becomes post.@dot for those bundles that are deployed as JARs and post.<jarname.jar> for those bundles that are deployed as folders (in Eclipse the latter usually feature the BundleShape: dir header attribute in their MANIFEST.MF file).

Being PDEBuild an Ant based build process, my first try consisted in using the Sonar Ant task (http://docs.codehaus.org/display/SONAR/Analyse+with+Ant+Task) but that failed because such Ant task plays some tricks with the classloader to run Sonar that are not OSGi friendly and does not work within the Eclipse Ant Runner (and therefore within PDEBuild ), even if you package the Sonar Ant task as a bundle that contributes to the Eclipse Ant runner.

Luckily enough, Sonar provides also a standalone Java application for performing the analysis called SonarRunner (http://docs.codehaus.org/display/SONAR/Analyse+with+a+simple+Java+Runner), which can be successfully executed by PDEBuild . It's basically a shell script that starts a JVM to run the Sonar analyser. SonarRunner requires a global configuration file ($SONAR_RUNNER_HOME/conf/sonar-runner.properties) where you can set database connection parameters, server URL as well as the default source and binary folder (project relative path).

Given that by convention most of our bundles have a single source folder named src/ and that the vast majority of our bundles are deployed as JARs (in which case PDEBuild automatically names the binary folder @dot during compilation), the global file was a very good location for defining good defaults for most projects.

The remaining mandatory configuration parameters will be set on a per-project basis in the PDE custom build callback, by creating a dedicated properties file in the project root folder for SonarRunner just before executing it, as documented in the SonarRunner page.

Eventually, my SonarRunner global configuration looked like this:



#----- Default Sonar server
sonar.host.url=http://localhost:9000

#----- MySQL
sonar.jdbc.url=jdbc:mysql://localhost:3306/sonar?useUnicode=true&characterEncoding=utf8
sonar.jdbc.driver=com.mysql.jdbc.Driver

#----- Global database settings
sonar.jdbc.username=<user>
sonar.jdbc.password=<password>

#----- Default directory layout
sources=src/
tests=test/
binaries=@dot/

sonar.sourceEncoding=UTF-8

and a project specific callback to perform the analysis looked like this:



<target name="post.@dot">
<antcall target="sonar"/>
</target>

<target name="sonar" if="run.sonar">

<propertyfile file="${plugin.destination}/sonar-project.properties">
<!-- ==== Common properties, should not be changed ====-->
<entry key="sonar.projectKey" value="studio:${bundleId}"/>
<entry key="sonar.projectName" value="${bundleId}"/>
<entry key="sonar.projectVersion"
value="${sonar.projectVersion}"/>

<!-- ==== Project specific properties -->
<!-- <entry key="sources" value="${plugin.destination}/src"/> -->
<!-- <entry key="binaries" value="${plugin.destination}/@dot"/>-->

<!-- == Additional Sonar properties. Add project specific properties here == -->
<!-- <entry key="sonar.exclusions" value="com/mycompany/*/.java,**/*Dummy.java"/> -->
<!-- <entry key="sonar.profile" value="MyProfile"/> -->
</propertyfile>

<exec spawn="false" command="${sonar.runner}" failonerror="true" />
</target>
where the property run.sonar is set globally somewhere earlier in the main build script, to make sure that the analysis (which can be very time consuming if you enable a lot of rules) is perfomed only if the build flavour is nightly or when explicitly requested by the build master.

Final comments
Congrats to the Sonar team for writing such a great piece of software! I am really looking forward for the next release which, according to the roadmap http://www.sonarsource.org/roadmap/, should be out in January 2012 and may provide the ability to use #Sonar as a generic code review tool, as opposed to current version 2.12 which supports code review limited only to the violations reported by Sonar.