I recently started to play with Sonarqube to reduce “technical debt” and hopefully improve code quality (see my previous post). I’d like to report on my experiences about using Sonarqube to analyze Xtend code.
Xtend compiles into Java source code, so it looks like it is trivial to analyze it with Sonarqube; of course, Sonarqube will analyze the generated Java code, but it’s rather easy to refer to the original Xtend code, since Xtend generates clean Java code 🙂
However, we Sonarqube 4.4 it looks like it’s harder than I thought due to some facts:
- Xtend automatically adds @SuppressWarnings(“all”) annotations to all generated Java classes.
- Sonarqube ignores every violation raised on classes with such annotations (http://jira.codehaus.org/browse/SONAR-1760)
- There’s currently now way of disabling the generation of such annotations in the Xtend compiler (https://bugs.eclipse.org/bugs/show_bug.cgi?id=363685)
- Inserting a custom @SuppressWarning annotation in the original Xtend class does not prevent such generation (https://www.eclipse.org/forums/index.php/t/821222/)
My starting point was another issue: test results did not show in the Sonarqube 4.4 web interface, and that was because test detection has changed in version 4 (http://sonarqube.15.x6.nabble.com/quot-Unit-test-success-quot-in-Sonarqube-4-4-td5028019.html).
I created an example to reproduce the problem and propose a solution: https://github.com/LorenzoBettini/tycho-xtend-sonar.
In the parent project we specify the actual project with sources to be analyzed, and the project containing tests (in this example I also use jacoco for code coverage, but that’s not crucial for this example):
1 2 3 4 5 6 7 8 9 10 |
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <!-- Sonar --> <sonar.language>java</sonar.language> <sonar.core.codeCoveragePlugin>jacoco</sonar.core.codeCoveragePlugin> <sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis> <sonar.jacoco.reportPath>${project.basedir}/../target/jacoco.exec</sonar.jacoco.reportPath> </properties> |
And we enable all the Maven plug-ins for
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
<plugin> <groupId>org.eclipse.tycho</groupId> <artifactId>tycho-maven-plugin</artifactId> <version>0.21.0</version> <extensions>true</extensions> </plugin> <plugin> <groupId>org.eclipse.xtend</groupId> <artifactId>xtend-maven-plugin</artifactId> <version>2.7.2</version> <executions> <execution> <phase>generate-sources</phase> <goals> <goal>compile</goal> </goals> </execution> </executions> <configuration> <outputDirectory>${basedir}/xtend-gen</outputDirectory> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-clean-plugin</artifactId> <version>2.5</version> <configuration> <filesets> <fileset> <directory>${basedir}/xtend-gen</directory> </fileset> </filesets> </configuration> </plugin> |
The plugin and the plugin.tests projects intentionally contain Xtend and Java files with some Findbugs issues, e.g.,
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class XtendGreeting { def greeting() { "Hello, world." } def useEquals() { // 2 findbugs issues: // findbugs:DM_NUMBER_CTOR // findbugs:EC_UNRELATED_TYPES new Integer(0).equals("foo"); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
package example import org.junit.Test import org.junit.Assert class XtendGreetingTest { @Test def void testGreeting() { val greeting = new XtendGreeting().greeting println(greeting) Assert.assertEquals("Hello, world.", greeting) } def useEquals2() { // 2 findbugs issues: // findbugs:DM_NUMBER_CTOR // findbugs:EC_UNRELATED_TYPES new Integer(0).equals("foo"); } } |
Now, assuming you have Sonarqube 4.4 running on your machine, you can run the typical maven commands to analyze your code (make sure you set the MaxPermSize in the MAVEN_OPTS otherwise the Xtend compiler will run out of memory):
1 2 3 |
export MAVEN_OPTS="-Xmx512m -XX:MaxPermSize=256m" mvn clean install mvn sonar:sonar |
If you go to Sonarqube web interface you see
So you see that Sonarqube correctly detected Findbugs issues in all the Java files, but for the Java code generated by Xtend, it only detected the issues in the plugin.tests project, not on the plugin project (as explained here http://sonarqube.15.x6.nabble.com/sonarqube-findbugs-and-generated-sources-td5028237.html, Sonarqube does “not take into consideration this suppress warnings annotation in test files”).
To deal with this problem, I created an ant file which basically removes all the @SuppressWarnings(“all”) annotations in all the generated Java files in the xtend-gen folder:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<?xml version="1.0"?> <project name="project"> <target name="process-xtend-gen" depends="dir.check" if="dir.exists"> <echo message="" /> <echo message="Replacing in ${project.basedir}/xtend-gen" /> <echo message="" /> <replace dir="${project.basedir}/xtend-gen" token='@SuppressWarnings("all")' value=""> <include name="**/*.java" /> </replace> </target> <target name="dir.check"> <echo message="" /> <echo message="Checking ${project.basedir}/xtend-gen" /> <echo message="" /> <condition property="dir.exists"> <available file="${project.basedir}/xtend-gen" type="dir" /> </condition> </target> </project> |
and I created a Maven profile in the parent pom that, when activated, invokes the ant target, in the process-sources phase (recall that this phase is executed after generate-sources phase, when the Xtend files are compiled into Java code)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
<profiles> <profile> <id>process-xtend-code</id> <activation> <activeByDefault>false</activeByDefault> </activation> <build> <plugins> <plugin> <artifactId>maven-antrun-plugin</artifactId> <version>1.7</version> <executions> <execution> <id>process-xtend-gen</id> <phase>process-sources</phase> <configuration> <skip>!${process-xtend-gen}</skip> <target> <property name="project.basedir" value="${project.basedir}" /> <ant antfile="${basedir}/../plugin.parent/process-xtend-gen.ant"> <target name="process-xtend-gen" /> </ant> </target> </configuration> <goals> <goal>run</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </profile> </profiles> |
Now, let’s invoke the two maven commands, but this time, the first one activates the above profile
1 2 3 |
export MAVEN_OPTS="-Xmx512m -XX:MaxPermSize=256m" mvn clean install -Pprocess-xtend-code mvn sonar:sonar |
OK, let’s go to the “Issues Drilldown” in the Sonarqube web interface and this time the issues are detected also in the plugin project:
You may want to select “Since previous analysis” in the combo box, to make sure that this analysis detected these new issues:
Hope this helps! 🙂
The source code can be found here: https://github.com/LorenzoBettini/tycho-xtend-sonar.