-
Couldn't load subscription status.
- Fork 81
Create a plugin with custom rules
WARNING: the documentation below uses the latest API version. If you want the documentation for older releases, please go to:
The easiest way to extend the Z PL/SQL Analyzer plugin with custom coding rules is to grab the template project from there and import in your favorite IDE: https://github.com/felipebz/zpa/tree/master/plsql-custom-rules
Before diving into code, you probably want to customize some properties in the pom.xml file.
Properties such as groupId, artifactId, version, name and description can be freely modified.
The sonar-plugin-api dependency represents the minimum version of SonarQube your plugin will support. You also need a dependency on the sonar-plsql-open-plugin and, optionally, a dependency on plsql-checks-testkit for easier testing.
It is important to note that the sonar-packaging-maven-plugin is required and it contains the entry point of the plugin, as provided in the property pluginClass. If you refactor the code or rename the class extending org.sonar.api.SonarPlugin, you will have to change this configuration.
SonarQube groups the rules in repositories, so we need to declare a repository first. You can just change the repository key and name in the PlSqlCustomRulesDefinition class.
To create a check, you can create a subclass of org.sonar.plugins.plsqlopen.api.checks.PlSqlCheck. You can use the org.sonar.check.Rule and org.sonar.plugins.plsqlopen.api.annnotations.ConstantRemediation annotations to configure the check metadata (name, description, key...).
Very often you'll need to override just two methods:
-
init(): subscribe to the desired grammar rules -
visitNode(AstNode): analyze the nodes that match the subscribed grammar rules
Suppose you want to write a rule that check for DMLs targeting the USER table. First of all, we need to check the AST to plan how to write the check. The AST can be verified with the zpa-toolkit project:

Let's start subscribing the DML_TABLE_EXPRESSION_CLAUSE rule:
public void init() {
subscribeTo(DmlGrammar.DML_TABLE_EXPRESSION_CLAUSE);
}So, every instance of the DML_TABLE_EXPRESSION_CLAUSE rule will trigger the visitNode method. Then we can check if it is a TABLE_REFERENCE to the table named USERS and create a violation indicating the table usage:
public void visitNode(AstNode node) {
AstNode table = node.getFirstChild(DmlGrammar.TABLE_REFERENCE);
if (table != null && table.getTokenOriginalValue().equalsIgnoreCase("user")) {
addIssue(table, "Replace this query by a function of the USER_WRAPPER package.");
}
}After create the rule, you need to add it to the check list.
To test your check, you only need two files. A class to execute the tests:
public class ForbiddenDmlCheckTest {
@Test
public void test() {
PlSqlCheckVerifier.verify("src/test/resources/forbidden-dml.sql", new ForbiddenDmlCheck());
}
}And the corresponding sql file:
select *
from user u; -- Noncompliant {{Replace this query by a function of the USER_WRAPPER package.}}
-- ^^^^The -- Noncompliant comment is required to indicate that you are expecting an issue in this line. The double braces contain the message that you expect to see in the SonarQube UI.
Optionally, you can indicate the precise location of the issue using carets (like this example, with carets pointing to the "user" word).
Just build the plugin with a standard maven command (mvn package) and copy the .jar file created in the target directory to the SonarQube server ($SONARQUBE_HOME/extensions/plugins).
If you developed a custom plugin targeting an older version, the pom.xml file probably defines:
<dependency>
<groupId>org.sonar.plsqlopen</groupId>
<artifactId>sonar-plsql-open-plugin</artifactId>
<type>sonar-plugin</type>
<version>???</version>
<scope>provided</scope>
</dependency>
<plugin>
<groupId>org.sonarsource.sonar-packaging-maven-plugin</groupId>
<artifactId>sonar-packaging-maven-plugin</artifactId>
<version>1.18.0.372</version>
<extensions>true</extensions>
<configuration>
<pluginClass>com.company.plsql.PlSqlCustomRulesPlugin</pluginClass>
<basePlugin>plsqlopen</basePlugin>
<pluginKey>my-rules</pluginKey>
</configuration>
</plugin>You need to:
- Remove the line
<type>sonar-plugin</type>from the sonar-plsql-open-plugin dependency - Remove the line
<basePlugin>plsqlopen</basePlugin>from sonar-packaging-maven-plugin configuration - Declare explicitly every other dependency you need in your pom.xml file. Example: if you need Guava declare a dependency on it, don't use the version packaged in
sonar-plsql-open-plugin.
In your classes, you will need to reimport many classes that are now located in the org.sonar.plugins.plsqlopen.api.* package.
The checks also need to be migrated from the old getPlSqlContext().createViolation() API to the newer addIssue/addLineIssue/addFileIssue (see example in "Writing a check").