How to define the scope for a Java custom rule

versions used (SonarQube, Scanner, language analyzer)

SonarQube : 8.7.0.41497
SonarLint : 4.14.2.28348
Intellij IDEA : 2020.3.3
Scanner : 3.1.1

How can I define the “scope” for my custom java rules?

We are using SonarQube as a main source for our code quality. As we maintain a quite large code base with a main application consisting of several modules, we also try to make sure, that our unit tests are of high quality.

Because of this, I implemented a custom rule for making sure, that @Ignore in JUnit tests is only used according to our coding rules. I implemented this rule just the same way, the other rules I did. But then I found out, the the rule was only appied to the main java source sets (defined in the sonar runner property sonar.sources) and not the test source sets (defined in the property sonar.tests).

Searching for the reason of the behavior, I figured out that the built-in java rules use a json file for defining the rules (rule name, type, status, tags etc.). And within these json configuration of a rule, there is also the property “scope” with the possible values “All”, “Main” and “Tests”. Looking at the issues in our code base I came to the conclusion, that only rules having the scope “All” or “Tests” are applied to the java files in the test source set.

{
  "title": "JUnit5 inner test classes should be annotated with @Nested",
  "type": "BUG",
  "status": "ready",
  "remediation": {
      "func": "Constant\/Issue",
      "constantCost": "2min"
  },
  "tags": [
    "junit",
    "tests"
  ],
  "defaultSeverity": "Critical",
  "ruleSpecification": "RSPEC-5790",
  "sqKey": "S5790",
  "scope": "Tests"
}

Obviously my custom rules are only applied on the “Main” java source set and not on the test source set. And the @Rule Annotation does not offer a property for defining a “scope” of a custom rule:

package org.sonar.check;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface Rule {
    String key() default "";

    String name() default "";

    String description() default "";

    Priority priority() default Priority.MAJOR;

    Cardinality cardinality() default Cardinality.SINGLE;

    String status() default "READY";

    String[] tags() default {};
}

My Question

Is there a way to define the scope of a custom rule so that the rule is applied to the test source set?

Hey Thomas,

Sorry, I didn’t saw your question earlier.

Yes, there is. To do so you just have to register the rule differently in your RulesList class or your CheckRegistrar class, depending on how you implemented it.

If you followed our tutorial, by default all the rules are simply assigned to MAIN code. This makes me think that we should add an example of rules targeting TEST, at least for completeness (SONARJAVA-3818).

Now, the only thing you have to do is to add some new rules to be executed exclusively on TEST code, by modifying the list of rules assigned to each scope.


Now, regarding the scope field that you can see in the metadata json file. Currently, this field has no impact on what domain the (java) rules are going to be executed. As of today, it is even purely and simply ignored by the Java analyzer, and rules are exclusive: they target either MAIN, either TEST sources. Even rules having the ALL scope are currently only executed on MAIN.

This scope was introduced a while ago, while we were exploring the possibility to actually execute much more rules on TEST scope, in a more global wish to push for improved quality of tests… This effort is currently paused on our side, but we might get back to it at some point. You might want to have a look at its umbrella ticket (MMF-1451) or the related feature request expressed in this forum (Allow enabling sonar rules for test sources).

Hope this helps,
Michael

2 Likes

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.