• sonar自定义规则


    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依赖

    <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

    编写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<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);
        }
    }

    打包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

  • 相关阅读:
    Java IO: 读取classpath资源
    Java IO: Reader和Writer
    Java IO: 读写zip文件
    OpenFlow运行机制总结
    OpenFlow流表概述
    Java日志系统(学习总结)
    卷积神经网络重要回顾
    Java Servlet学习笔记
    fragment实例
    Fragment应用
  • 原文地址:https://www.cnblogs.com/xiang--liu/p/9710101.html
Copyright © 2020-2023  润新知