1. 程式人生 > >SonarQube外掛開發自定義規則(1)簡易demo

SonarQube外掛開發自定義規則(1)簡易demo

1、maven依賴

本開發教程適用於sonarqube5.x、6.x。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>wxtx</groupId
>
<artifactId>TestSonar</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>sonar-plugin</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <sonar.version>6.3</sonar.version
>
<!-- this 6.3 is only required to be compliant with SonarLint and it is required even if you just want to be compliant with SonarQube 5.6 --> <java.plugin.version>4.7.1.9272</java.plugin.version> <sslr.version>1.21</sslr.version> <gson.version
>
2.6.2</gson.version> </properties> <dependencies> <dependency> <groupId>org.sonarsource.sonarqube</groupId> <artifactId>sonar-plugin-api</artifactId> <version>${sonar.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.sonarsource.java</groupId> <artifactId>sonar-java-plugin</artifactId> <type>sonar-plugin</type> <version>${java.plugin.version}</version> </dependency> <dependency> <groupId>org.sonarsource.java</groupId> <artifactId>java-frontend</artifactId> <version>${java.plugin.version}</version> </dependency> <dependency> <groupId>org.sonarsource.sslr-squid-bridge</groupId> <artifactId>sslr-squid-bridge</artifactId> <version>2.6.1</version> <exclusions> <exclusion> <groupId>org.codehaus.sonar.sslr</groupId> <artifactId>sslr-core</artifactId> </exclusion> <exclusion> <groupId>org.codehaus.sonar</groupId> <artifactId>sonar-plugin-api</artifactId> </exclusion> <exclusion> <groupId>org.codehaus.sonar.sslr</groupId> <artifactId>sslr-xpath</artifactId> </exclusion> <exclusion> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> </exclusion> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.sonarsource.java</groupId> <artifactId>java-checks-testkit</artifactId> <version>${java.plugin.version}</version> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>${gson.version}</version> </dependency> <dependency> <groupId>org.sonarsource.sslr</groupId> <artifactId>sslr-testing-harness</artifactId> <version>${sslr.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.6.2</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> </dependency> <dependency> <groupId>org.assertj</groupId> <artifactId>assertj-core</artifactId> <version>3.6.1</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>0.9.30</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.sonarsource.sonar-packaging-maven-plugin</groupId> <artifactId>sonar-packaging-maven-plugin</artifactId> <version>1.17</version> <extensions>true</extensions> <configuration> <pluginDescription>test</pluginDescription> <pluginKey>java-custom</pluginKey> <pluginName>Java Custom Rules</pluginName> <pluginClass>wxtx.com.MySonarPlugin</pluginClass> <sonarLintSupported>true</sonarLintSupported> <sonarQubeMinVersion>5.6</sonarQubeMinVersion> <!-- allow to depend on API 6.x but run on LTS --> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.6.0</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project>

2、制定規則

/**
 * @author 孫澤明
 * 抽象類命名使用TXAbstract或TXBase開頭
 */
@Rule(
    // 規則id
    key = "TXAbstractClassNameCheck",
    // 規則名稱
    name = "抽象類命名使用TXAbstract或TXBase開頭",
    // 規則介紹
    description = "抽象類命名使用TXAbstract或TXBase開頭",
    // 規則標籤
    tags = {"wxtx-java"},
    // 規則級別
    priority = Priority.MINOR)
@SqaleSubCharacteristic(RulesDefinition.SubCharacteristics.ARCHITECTURE_CHANGEABILITY)
// 糾正錯誤所需時間
@SqaleConstantRemediation("10min")
public class TXAbstractClassNameCheck extends BaseTreeVisitor implements JavaFileScanner {
    private JavaFileScannerContext context;
    public void scanFile(JavaFileScannerContext context) {
        this.context = context;
        scan(context.getTree());
    }

    @Override
    public void visitClass(ClassTree tree) {
        if(tree == null || tree.simpleName() == null){
            super.visitClass(tree);
            return;
        }

        String className = tree.simpleName().name();
        boolean isAbstract = tree.symbol().isAbstract();
        if(isAbstract && isNameIll(className)){
            context.reportIssue(this, tree, "抽象類命名使用TXAbstract或TXBase開頭");
        }
        super.visitClass(tree);
    }

    private boolean isNameIll(String className){
        return !className.startsWith("TXAbstract") && !className.startsWith("TXBase");
    }
}

3、註冊規則

3.1、自定義外掛入口

public class TXSonarPlugin implements Plugin  {
    public void define(Context context) {
        context.addExtension(TXJavaRulesDefinition.class);
        context.addExtension(TXJavaFileCheckRegistrar.class);
    }
}

3.2、server extensions
在sonarqube server啟動時例項化,實現org.sonar.api.server.rule.RulesDefinition介面

public class TXJavaRulesDefinition implements RulesDefinition {
    public static final String REPOSITORY_KEY = "TXRepo";
    public void define(Context context) {
        NewRepository repository = context.createRepository(REPOSITORY_KEY,Java.KEY);
        repository.setName("Java編碼規範");
        AnnotationBasedRulesDefinition.load(repository, "java",TXRulesList.getChecks());
        repository.done();
    }
}

3.3、batch extensions
在分析程式碼的時候例項化,實現org.sonar.plugins.java.api.CheckRegistrar介面

public class TXJavaFileCheckRegistrar implements CheckRegistrar {
     public void register(RegistrarContext registrarContext) {
            registrarContext.registerClassesForRepository(TXJavaRulesDefinition.REPOSITORY_KEY,
                    Arrays.asList(checkClasses()), Arrays.asList(testCheckClasses()));
        }

        public static Class<? extends JavaCheck>[] checkClasses() {
            new Class[] {TXAbstractClassNameCheck.class};
        }
        @SuppressWarnings("unchecked")
        public static Class<? extends JavaCheck>[] testCheckClasses() {
            return new Class[] {};
        }
}
public class TXRulesList {

    private TXRulesList() {
    }
    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(TXAbstractClassNameCheck.class).build();
    }
    public static List<Class<? extends JavaCheck>> getJavaTestChecks() {
        return ImmutableList.<Class<? extends JavaCheck>>builder().build();
    }
}

4、輸出

maven執行命令mvn clean install輸出jar包,其中修改MANIFEST.MF的Plugin-Dependencies,例如:

Manifest-Version: 1.0
Plugin-Dependencies: META-INF/lib/*
Plugin-Description: test
Plugin-BuildDate: 2017-11-08T12:12:27+0800
Archiver-Version: Plexus Archiver
SonarLint-Supported: true
Built-By: Administrator
Plugin-License: 
Plugin-Version: 0.0.1-SNAPSHOT
Sonar-Version: 5.6
Plugin-Developers: 
Plugin-ChildFirstClassLoader: false
Plugin-Key: javacustom
Plugin-Class: wxtx.com.MySonarPlugin
Created-By: Apache Maven 3.3.9
Build-Jdk: 1.8.0_144
Plugin-Name: Java Custom Rules

並將依賴的jar包複製進META-INF/lib/目錄下(例如guava、sonar-plugin-api)

5、測試

5.1、將自定義外掛jar放到sonar下的extensions/plugins路徑下
5.2、啟動SonarQube
5.3、啟用規則:登入admin賬號後,點選activate按鈕啟用規則
這裡寫圖片描述

6、參考