Sonar并不是简单地把不同的代码检查工具结果(例如 FindBugs,PMD 等)直接显示在 Web 页面上,而是通过不同的插件对这些结果进行再加工处理,通过量化的方式度量代码质量的变化,从而可以方便地对不同规模和种类的工程进行代码质量管理。
sonarqubue默认的对java的检测规则不一定适合我们,可以自己去自定义rules。
禁用rules
Rules-Quality Profile- Sonar way Java
查看激活的规则,可以禁用,或者更改严重级别(Severity)
自定义rules
sonar提供XPath或Java方式的扩展,有的语言支持XPath,有的只能支持Java,比如Java语言只支持Java方式的扩展。具体详见Support of Custom Rules by Language
步骤如下:
- 创建一个SonarQube插件
- 增加相关依赖
- 创建自定义rules
- 生成插件的jar包
- 将该jar包放在SONARQUBE_HOME/extensions/plugins目录下
- 重启SonarQube
添加maven依赖
UTF-8
UTF-8
1.8
5.6
4.2
1.17
1.20
4.12
1.4
1.1.3
org.sonarsource.sonarqube
sonar-plugin-api
${sonar-plugin-api.version}
provided
org.sonarsource.java
sonar-java-plugin
${sonar-java-plugin.version}
sonar-plugin
provided
org.sonarsource.java
java-checks-testkit
${sonar-java-plugin.version}
provided
org.codehaus.sonar.sslr
sslr-testing-harness
${sslr-testing-harness.version}
test
junit
junit
${junit.version}
test
org.easytesting
fest-assert
${fest-assert.version}
test
ch.qos.logback
logback-classic
${logback-classic.version}
test
org.codehaus.sonar.sslr-squid-bridge
sslr-squid-bridge
2.6
org.codehaus.sonar
sonar-plugin-api
com.google.code.gson
gson
2.6.2
com.google.guava
guava
19.0
commons-codec
commons-codec
1.10
commons-io
commons-io
2.4
commons-lang
commons-lang
2.6
org.sonarsource.sonar-packaging-maven-plugin
sonar-packaging-maven-plugin
${sonar-packaging-maven-plugin.version}
true
java-custom
Java Custom Rules
com.xixicat.sonar.MySonarPlugin
true
5.6
这里的依赖要小心配置,记得exclude掉sonar-plugin-api,才可以加载其他相关依赖,然后显示依赖用到的jar,否则容易报class not found
编写plugin
创建plugin入口
public class MySonarPlugin implements Plugin {
public void define(Context context) {
// server extensions -> objects are instantiated during server startup
context.addExtension(MyJavaRulesDefinition.class);
// batch extensions -> objects are instantiated during code analysis
context.addExtension(MyJavaFileCheckRegistrar.class);
}
}
这个类实现了org.sonar.api.Plugin接口,主要添加两类扩展:
- server extensions
在sonarqube server启动时实例化,实现org.sonar.api.server.rule.RulesDefinition接口
public class MyJavaRulesDefinition implements RulesDefinition {
public static final String REPOSITORY_KEY = "myRepo";
public void define(Context context) {
NewRepository repository = context.createRepository(REPOSITORY_KEY, Java.KEY);
repository.setName("my sonar repo");
AnnotationBasedRulesDefinition.load(repository, "java", RulesList.getChecks());
repository.done();
}
}
public class RulesList {
private RulesList() {
}
public static List getChecks() {
return ImmutableList.builder().addAll(getJavaChecks()).addAll(getJavaTestChecks()).build();
}
public static List> getJavaChecks() {
return ImmutableList.>builder()
.add(AvoidSmallerLengthVariableNameRule.class)
.build();
}
public static List> getJavaTestChecks() {
return ImmutableList.>builder()
.build();
}
}
- batch extensions
在分析代码的时候实例化,实现org.sonar.plugins.java.api.CheckRegistrar接口
public class MyJavaFileCheckRegistrar implements CheckRegistrar {
public void register(RegistrarContext registrarContext) {
// Call to registerClassesForRepository to associate the classes with the correct repository key
registrarContext.registerClassesForRepository(MyJavaRulesDefinition.REPOSITORY_KEY,
Arrays.asList(checkClasses()), Arrays.asList(testCheckClasses()));
}
/**
* Lists all the checks provided by the plugin
*/
public static Class extends JavaCheck>[] checkClasses() {
return new Class[] { // List of rules to be included here
AvoidSmallerLengthVariableNameRule.class
};
}
/**
* Lists all the test checks provided by the plugin
*/
public static Class extends JavaCheck>[] testCheckClasses() {
return new Class[] {};
}
}
创建规则
import org.sonar.api.server.rule.RulesDefinition;
import org.sonar.check.Priority;
import org.sonar.check.Rule;
import org.sonar.check.RuleProperty;
import org.sonar.plugins.java.api.JavaFileScanner;
import org.sonar.plugins.java.api.JavaFileScannerContext;
import org.sonar.plugins.java.api.tree.BaseTreeVisitor;
import org.sonar.plugins.java.api.tree.VariableTree;
import org.sonar.squidbridge.annotations.SqaleConstantRemediation;
import org.sonar.squidbridge.annotations.SqaleSubCharacteristic;
@Rule(key = "AvoidSmallerLengthLocalVariableName",
name = "Avoid usage of the smaller length in local variable name",
description = "This rule detects usage of smaller length local variable name. Variable name should not be smaller than 4 characters.",
tags = {"coding-guideline"},
priority = Priority.MINOR)
@SqaleSubCharacteristic(RulesDefinition.SubCharacteristics.ARCHITECTURE_CHANGEABILITY)
//SQALE全称是Software Quality Assessment based on Lifecycle Expectations,是一套评估代码质量的方法。
@SqaleConstantRemediation("10min") //纠正所需时间
public class AvoidSmallerLengthVariableNameRule extends BaseTreeVisitor implements JavaFileScanner {
private static final String DEFAULT_VALUE = "SmallerLengthLocalVariable";
private JavaFileScannerContext context;
/**
* Avoid usage of the smaller length in local variable name in Quality profiles.
* The key
*/
@RuleProperty(
defaultValue = DEFAULT_VALUE,
description = "Avoid usage of the smaller length in local variable name")
protected String name;
public void scanFile(JavaFileScannerContext context) {
this.context = context;
scan(context.getTree());
}
@Override
public void visitVariable(VariableTree tree) {
String variableName = tree.simpleName().name();
System.out.println("Scanning the variable : " + variableName);
if(variableName.length() < 4) {
context.reportIssue(this,tree, "Variable length is less than 4 characters");
}
super.visitVariable(tree);
}
}
打包plugin
mvn clean package sonar-packaging:sonar-plugin
拷贝到plugins
cp target/sonar-rule-demo-0.0.1-SNAPSHOT.jar ~/sonar/extensions/plugins
run
docker run --rm \
-e JAVA_OPTS='-Xmx1g' \
-v /Users/xixicat/sonar/data:/opt/sonarqube/data \
-v /Users/xixicat/sonar/extensions:/opt/sonarqube/extensions \
-p 9000:9000 -p 9092:9092 \
-e SONARQUBE_JDBC_USERNAME=sonar \
-e SONARQUBE_JDBC_PASSWORD=sonar \
sonarqube:lts-alpine
查看自定义的规则
doc
- Build Plugin
- Support of Custom Rules by Language
- Adding Coding Rules using Java
- java-custom-rules
- Custom-Java-Plugin-For-SONAR
- Analyzing with SonarQube Scanner
- How to create custom rules in Sonarqube for java and implement the same?