Sonar並非簡單地把不一樣的代碼檢查工具結果(例如 FindBugs,PMD 等)直接顯示在 Web 頁面上,而是經過不一樣的插件對這些結果進行再加工處理,經過量化的方式度量代碼質量的變化,從而能夠方便地對不一樣規模和種類的工程進行代碼質量管理。java
sonarqubue默認的對java的檢測規則不必定適合咱們,能夠本身去自定義rules。git
Rules-Quality Profile- Sonar way Java
查看激活的規則,能夠禁用,或者更改嚴重級別(Severity)
github
sonar提供XPath或Java方式的擴展,有的語言支持XPath,有的只能支持Java,好比Java語言只支持Java方式的擴展。具體詳見Support of Custom Rules by Languagedocker
建立一個SonarQube插件api
增長相關依賴less
建立自定義rulesmaven
生成插件的jar包ide
將該jar包放在SONARQUBE_HOME/extensions/plugins目錄下工具
重啓SonarQubeui
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <sonar-plugin-api.version>5.6</sonar-plugin-api.version> <sonar-java-plugin.version>4.2</sonar-java-plugin.version> <sonar-packaging-maven-plugin.version>1.17</sonar-packaging-maven-plugin.version> <sslr-testing-harness.version>1.20</sslr-testing-harness.version> <junit.version>4.12</junit.version> <fest-assert.version>1.4</fest-assert.version> <logback-classic.version>1.1.3</logback-classic.version> </properties> <dependencies> <dependency> <groupId>org.sonarsource.sonarqube</groupId> <artifactId>sonar-plugin-api</artifactId> <version>${sonar-plugin-api.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.sonarsource.java</groupId> <artifactId>sonar-java-plugin</artifactId> <version>${sonar-java-plugin.version}</version> <type>sonar-plugin</type> <scope>provided</scope> </dependency> <dependency> <groupId>org.sonarsource.java</groupId> <artifactId>java-checks-testkit</artifactId> <version>${sonar-java-plugin.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.codehaus.sonar.sslr</groupId> <artifactId>sslr-testing-harness</artifactId> <version>${sslr-testing-harness.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.easytesting</groupId> <artifactId>fest-assert</artifactId> <version>${fest-assert.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>${logback-classic.version}</version> <scope>test</scope> </dependency> <!--http://stackoverflow.com/questions/35369058/custom-plugin-for-sonarqube-5-2-produces-noclassdeffounderror--> <!-- https://mvnrepository.com/artifact/org.codehaus.sonar.sslr-squid-bridge/sslr-squid-bridge --> <dependency> <groupId>org.codehaus.sonar.sslr-squid-bridge</groupId> <artifactId>sslr-squid-bridge</artifactId> <version>2.6</version> <!--記得exclude掉sonar-plugin-api,才能夠加載其餘相關依賴--> <exclusions> <exclusion> <groupId>org.codehaus.sonar</groupId> <artifactId>sonar-plugin-api</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.6.2</version> </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>19.0</version> </dependency> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.10</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.6</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.sonarsource.sonar-packaging-maven-plugin</groupId> <artifactId>sonar-packaging-maven-plugin</artifactId> <version>${sonar-packaging-maven-plugin.version}</version> <extensions>true</extensions> <configuration> <pluginKey>java-custom</pluginKey> <pluginName>Java Custom Rules</pluginName> <!-- your plugin class --> <pluginClass>com.xixicat.sonar.MySonarPlugin</pluginClass> <sonarLintSupported>true</sonarLintSupported> <sonarQubeMinVersion>5.6</sonarQubeMinVersion> <!-- allow to depend on API 6.x but run on LTS --> </configuration> </plugin> </plugins> </build>
這裏的依賴要當心配置,記得exclude掉sonar-plugin-api,才能夠加載其餘相關依賴,而後顯示依賴用到的jar,不然容易報class not found
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<Class> getChecks() { return ImmutableList.<Class>builder().addAll(getJavaChecks()).addAll(getJavaTestChecks()).build(); } public static List<Class<? extends JavaCheck>> getJavaChecks() { return ImmutableList.<Class<? extends JavaCheck>>builder() .add(AvoidSmallerLengthVariableNameRule.class) .build(); } public static List<Class<? extends JavaCheck>> getJavaTestChecks() { return ImmutableList.<Class<? extends JavaCheck>>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); } }
mvn clean package sonar-packaging:sonar-plugin
拷貝到plugins
cp target/sonar-rule-demo-0.0.1-SNAPSHOT.jar ~/sonar/extensions/plugins
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