Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

The extension points are listed and documented in the Javadoc. See http://docs.sonarsource.org/latest/apidocs/index.html?org/sonar/api/Extension.html.

Batch lifecycle

A SonarQube analysis follow the following lifecycle:

  1. Bootstrapper (SonarQube Maven Plugin, SonarQube Runner, SonarQube Ant Task) collects a set of properties describing the project to analyze and starts the batch.
  2. ProjectBuilder extensions are called to give a chance for plugins to change project structure (add/remove module, change any property). After this step project structure can't be modified.
  3. For each module (bottom-up):
    1. Initializer extensions are called to give a chance to customize module configuration (add/remove sources, change any property)
    2. SonarQube FileSystem is constructed (ie list of files to analyze). All project files are indexed according to configuration (inclusions/exclusions). After this step the FileSystem can't be modified.
    3. Sensor extensions are called. Usually to add measures/issues on files.
    4. Decorator extensions are called bottom-up on each element of the resource tree (File -> Directory -> Module -> Project). Usually to aggregate measures or compute "level-2" issues (issues based on result of sensors).
    5. All collected data (measures, issues, ...) are persisted. No addition for this module are permitted after this step.
  4. Results of analysis are sent to the server
  5. PostJob extensions are called. A PostJob can access all results of the analysis but not change anything. Used for example to produce various reports (PDF, CSV).

Sensor or Decorator?

There are two extension points that allow plugins to save measures: Sensor and Decorator. A common problem when writing a plugin is to decide which one to use.

...

A Sensor is invoked once during the analysis of a project. The sensor can invoke a maven plugin, parse a flat file, connect to a web server... For example the Cobertura Sensor invokes the Codehaus Cobertura MOJO. Then the generated XML file is parsed is able to parse the cobertura XML report file generated during execution of your tests and used to save the first-level of measures on resources (project, package or class).
A sensor can access and save measures on the whole tree of resources. Sensor are generally used to add measure at the lowest level of the resource tree.

...

Decorators are triggered once all sensors have completed. Their decorate method is called on every resource of a certain level bottom up. Decorators can load (SELECT) read and save (INSERT) measures. The call is contextual, i.e it is only possible to access the resource and its children.
Decorators are generally used to consolidate / aggregate at higher levels, measures that have been added saved by Sensors at the lowest level.

How to Reuse Existing Components

...

Extensions are registered in an IoC container, with constructor injection. To communicate with other extensions or with existing components provided by the API, just declare them in the constructor of your extension. For example to get references on DatabaseSession FileSystem or RulesProfileActiveRules:

Code Block
java
java
public class MySensor extends Sensor {
  private DatabaseSessionFileSystem sessionfs;
  private RulesProfileActiveRules profileactiveRules;

  public MySensor(DatabaseSessionFileSystem sessionfs, RulesProfileActiveRules profileactiveRules) {
    this.sessionfs = sessionfs;
    this.profileactiveRules = profileactiveRules;
  }
}

References will be automatically set at runtime.

...

Warning

You should never directly instantiate classes which implement BatchComponent or ServerComponent , because they should be retrieved as an IoC dependency. Otherwise it leads to issues with backward compatibility.

How to Quickly Start the Plugin

...

As described in the Getting Started page, you can build sources, copy the JAR file to the directory extensions/plugins/ and restart the server. But this approach can quickly become tedious. The following solutions help to edit code without leaving your development environment:

...

Once the server is launched, hit http://localhost:9000. By default, the in-process database (H2, or Derby prior to SonarQube 3.2) is used but you can specify a local MySQL instance instead with the property "-Dsonar.database=mysql". In that case, the sonar schema must exist in the MySQL DB along with the user sonar/sonar (login/password) which must have all rights on the sonar schema.

Code Block
# Note that SonarQube versions greater than or equal 4.0 are not supported yet
mvn install org.codehaus.sonar:sonar-dev-maven-plugin::start -Dsonar.runtimeVersion=3.7.2

...

Code Block
mvn sonar:sonar
Info
titleNote for Mac OS

Add the property -Djava.io.tmpdir=/tmp to the mvn command.

...

How to Use External Libraries?

A plugin benefits from all the dependencies provided by the API. Execute the following command on your plugin to list them:

...

  • Libraries used for GWT compilation must be defined with scope provided
  • The plugin classloader is a child of the Sonar classloader, with a parent-first delegation model. There are two consequences:
    1. Sonar libraries are automatically inherited. Their versions can not be changed.
    2. There are side-effects on some libraries, for example the classloader must be explicitly set for XStream:
    Code Block
    java
    java
    XStream xstream = new XStream();
    xstream.setClassLoader(getClass().getClassLoader());

How to Log

...

SLF4J is used as a simple facade of various logging frameworks (log4j, commons-log, logback, java.util.logging). It's simple to use:

...

Read the SLF4J manual for more details.

How to Get Configuration

...

The component org.sonar.api.config.Settings provides properties for batch extensions (global/project settings, command-line parameters, system properties) and server extensions (global settings, system properties, file $SONAR_HOME/conf/sonar.properties). It replaces Apache Commons Configuration that is deprecated since release 2.12.

...

Persistent properties are also accessible from the Web Service named 'properties'. To exclude some properties from anonymous requests, add the suffix ".secured" to the key (my.property.secured). It can be useful for license keys for example.

Steps to cover a new language

  1. Write the grammar. This is the hardest part.
  2. Write a parser (a parser simply takes a grammar, an input, and will parse it, yielding a parse tree).
  3. Test your grammar, to ensure it is able to parse your real-life language files.
  4. Write a few parse tree visitors. Some visitors will compute metrics, while others will enforce coding rules. A dozen or so visitors is sufficient for an initial release.
  5. Write a SonarQube sensor to launch the visitors. It should query the API to get the list of source files, the list of active coding rules in the quality profile, and the API to save metrics and issues.
See also: SSLR.

Tips and Tricks

  • For generating charts use d3.js, which is packaged with SonarQube since version 4.1.
  • To create "template" rules (rules that can be duplicated by the user) set the rule's cardinality field to MULTIPLE
  • To access a constant from a Java class in a .erb file, use Java::OrgSonarPluginsPlug::MyConfiguration::MY_CONSTANT