Sonar-HLA V. 0.4.1 released

I’m happy to announce that my little open source project Sonar-HLA is now released in version 0.4.1. This is a feature release, so I’d like to introduce those new features and give some examples. For a general introduction into Sonar-HLA you may refer to my previous post or simply visit the official Sonar-HLA homepage at Github.

The new features in version 0.4.1 are:

  1. Aggregate data from many projects into one line of CSV data.
  2. Write generated CSV data to file.
  3. Version of project is now retrieved from Sonar.
  4. API will also provide double and integer values, not only strings.

Now let me explain in more detail what these new features are about:

Aggregate data from many projects into one line of CSV data

An aggregated project is a project which consist of more than one project. These projects may be based on a pattern or simply on all projects available on a SonarQube server. The difference is now, that an aggregated project will only create a single line of CSV data (besides the header, of course) containing either the average or the sum of the measures of the single projects. The single measures are calculated like in this list:

  • HLAMeasure#DUPLINES: sum
  • HLAMeasure#COVERAGE: average
  • HLAMeasure#CMPLX: average
  • HLAMeasure#LOCS: sum
  • HLAMeasure#ISSUES_MINOR: sum
  • HLAMeasure#ISSUES_MAJOR: sum
  • HLAMeasure#ISSUES_INFO: sum
  • HLAMeasure#ISSUES_CRITICAL: sum
  • HLAMeasure#ISSUES_BLOCKER: sum
  • HLAMeasure#ISSUES_ALL: sum

This can be useful if there are a lot of single Sonar builds for a large software project, which quite often is the case. Now, let’s see what the API and the plugin provides now.

There is now a new interface type called IProjectAggregated. It extends from IProject. This type has two more methods, one called getName(), which simply returns the (user defined) name of the project, and another method that looks like this:

    /**
     * Get all the projects which are part of this aggregated project.
     * 
     * @return The list of all project IDs used.
     */
    public List<String> getProjectIDs();

So far this is nothing really exciting. What now comes into play is a new method in interface ISonarExtractor:

    /**
     * Retrieve an aggregated project consisting of a set of real projects.
     * 
     * @param name The name the generated aggregated project will be assigned to.
     * @param projectKeyPattern A pattern matching the desired project names or null. If this value is null, all projects from
     *        SonarQube will be used.
     * @return A new project containing aggregated values from all selected projects.
     */
    public IProjectAggregated getProjectAggregated(String name, String projectKeyPattern);

As you can see, just give an arbitrary name for this project and a pattern to match the project keys. Once you got an aggregated project, you’ll now find some new methods in ISonarConverter. One of them looks like this:

    /**
     * Create CSV data based on the given aggregated project.
     * 
     * @param projectAgg The aggregated project.
     * @param hlaMeasures The measures to be used for output.
     * @param surroundFields If true, every single field of data will be surrounded with quotation marks.
     * @return The string containing the CSV data.
     */
    public String getCSVData(IProjectAggregated projectAgg, List<HLAMeasure> hlaMeasures, boolean surroundFields);

This method takes an aggregated project and generates CSV from it. There are other methods available which return an InputStream or a File object, as they were already available for projects of type IProject. The API now makes it pretty simple to generate such an aggregated project as shown in this example:

IProjectAggregated projectAgg  = null;
ISonarExtractor extractor      = null;
ISonarConverter converter      = null;
String csv                     = null;

extractor = new DefaultSonarExtractor("http://localhost:9000");
projectAgg = extractor.getProjectAggregated("Aggregated Project", ".*:sonar-hla.*");
csv = converter.getCSVData(projectAgg, Arrays.asList(HLAMeasure.values()), false);

// do something with CSV

Using the Maven Plugin for aggregating data

As shown in the previous post for Sonar-HLA, one may of course call the plugin without any Maven project or without any existing POM. Here I will show instead a ready to use POM for the specific use cases. Here we go with an example configuration for aggregating projects:

  <build>
    <plugins>
      <plugin>
        <groupId>com.github.badamowicz</groupId>
        <artifactId>sonar-hla-maven-plugin</artifactId>
        <version>0.4.1</version>
        <configuration>
          <hostUrl>http://localhost:9000</hostUrl>
          <csvFile>projects.csv</csvFile>
          <projectKeyPattern>.*sonar-hla.*</projectKeyPattern>
          <aggregate>true</aggregate>
        </configuration>
        <executions>
          <execution>
            <id>extract</id>
            <goals>
              <goal>extract</goal>
            </goals>
            <phase>compile</phase>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

The only additional thing you have to provide is the projectKey Pattern and then set aggregate to true. Then run any Maven life cycle equal or higher to compile, e.g. mvn clean install. Leaving the proejctKeyPattern empty will simply take all available projects on the given host. The output generated by the plugin may look something like this:

Created aggregated project with pattern '.*sonar-hla.*'.
Generated CSV is based on these projects:
com.github.badamowicz.sonar.hla:sonar-hla-parent
com.github.badamowicz:sonar-hla-parent

**** Here we go with CSV:

Project;Lines of Code;Coverage [%];Complexity;Duplicate Lines;Issues;Blocker;Critical;Major;Minor;Info
Aggregated Project;1540;88.05000000000001;136.5;0;32;0;0;28;4;0


**** End of CSV data. Have a nice day!

As you can see, the plugin will also issue information about the projects used for generating the aggregated data.

Write generated CSV data to a File

Up to now, the generated data was simply written to standard output or – optionally – to an InputStream object. Now you can make Sonar-HLA also write the CSV data to a file. This file will then only contain the raw CSV data, that is, the header and the data – nothing else. This is convenient in many cases. One may then simply double click on the file with any spreadsheet program and it will be opened immediately.

The new methods inside ISonarConverter are called public File getCSVDataAsFile(…) and take various arguments. I’ll show only the simplest method here:

/**
     * Convert the given projects into CSV data and write them to a file object. The fields will not be surrounded with any
     * quotation marks.
     * 
     * @param fileName A relative or absolute file name.
     * @param projects A list of projects.
     * @param hlaMeasure The measures to use.
     * @param cleanValues When set to true, no non-numeric characters will be contained.
     * @return The {@link File} object containing the CSV data.
     */
    public File getCSVDataAsFile(String fileName, List<IProject> projects, List<HLAMeasure> hlaMeasure, boolean cleanValues);

This method may be – of course – called directly. However, there might be some use cases where the CSV data has already been generated as a string, and in addition one may need it as a file. In this case simply use the method writeCSVDataToFile:

/**
     * This is a convenience method and a kind of shortcut to write CSV data which has already been generated to the given file.
     * It might be useful for implementing classes which have already generated the CSV data <b>and</b> also need these data
     * written to a file. Using this method will avoid processing the request to a SonarQube host again.
     * 
     * @param fileName A relative or absolute file name.
     * @param csvData The CSV data to be written to the file. Actually this method will <b>not</b> check if this string really
     *        contains CSV data. It will simply write what is given in the string object.
     */
    public void writeCSVDataToFile(String fileName, String csvData);

Writing data to a File using the Plugin

This is pretty simple. Only give a valid file name for the csvFile parameter. Given the example above which creates aggregated data, your POM might be simply enhanced like this:

 <build>
    <plugins>
      <plugin>
        <groupId>com.github.badamowicz</groupId>
        <artifactId>sonar-hla-maven-plugin</artifactId>
        <version>0.4.1</version>
        <configuration>
          <hostUrl>http://localhost:9000</hostUrl>
          <csvFile>projects.csv</csvFile>
          <projectKeyPattern>.*sonar-hla.*</projectKeyPattern>
          <aggregate>true</aggregate>
          <csvFile>aggregated.csv</csvFile>
        </configuration>
        <executions>
          <execution>
            <id>extract</id>
            <goals>
              <goal>extract</goal>
            </goals>
            <phase>compile</phase>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

Line 12 provides the file name to the plugin. One may use absolute or relative paths. But, in any case, you should provide the file extension csv since the plugin will not handle this. (Neither will the API.)

Version of project is now retrieved from Sonar

This is not a big issue. The IProject interface now provides a new method public String getVersion(). The plugin in turn will output the version along with the project’s name.

API will also provide double and integer values, not only strings

Two new methods inside IProject make it possible to retrieve either an integer or double value of a measure where applicable:

    /**
     * Method will try to retrieve the value for the given measure.
     * 
     * @param measure The {@link HLAMeasure} to be retrieved.
     * @return The {@link Double} value if available or <b>null</b>.
     */
    public Double getMeasureDoubleValue(HLAMeasure measure);

    /**
     * Method will try to retrieve the value for the given measure.
     * 
     * @param measure The {@link HLAMeasure} to be retrieved.
     * @return the {@link Integer} value of this measure if available or <b>null</b>.
     */
    public Integer getMeasureIntValue(HLAMeasure measure);

Beware that a value can only be returned if the appropriate type is available. So one should check for null pointers before trying to use one of the returned values. The plugin is not affected by this change. It will only use the method returning a string object.

finally{}

If you find these features useful, you may want to leave a comment. Also feature requests or criticism is welcome. And maybe you may want to visit the project’s home page at Github here. It provides full documentation as well as access to the source code.

Subscribe to new posts

If you're interested in new posts and updates, just subscribe here.

No comments yet.

Leave a Reply

* Copy This Password *

* Type Or Paste Password Here *