sonarqube插件自定义

本文介绍了如何在SonarQube中安装第三方插件如MyBatis和SQL插件,以及如何自定义插件编写,包括创建Maven项目、实现Plugin和QualityProfile定义,最后展示了规则匹配与扫描的实践过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、sonarqube代码扫描中有很多插件可以扩展我们的扫描规则,比如mybatis插件、sql插件,这些可以在设置->应用市场->搜索->下载即可。

另外还有一些不在应用市场中的插件,可以在github中下载然后打包,将jar包放在sonarqube的 sonarqube-8.9.1/extensions/plugins目录下,重启sonarqube服务即可。

sql插件地址:

https://github.com/gretard/sonar-sql-plugin/releases

mybatis插件地址

https://github.com/donhui/sonar-mybatis/releases/

plsql插件地址

https://github.com/felipebz/zpa/releases

二、sonarqube提供了自定义插件写法的例子,供大家参考学习

三、自定义插件

1.新建一个maven项目,在pom文件中添加如下依赖,注意packaging一定要写,不然启动的时候会报plugin-key找不到。

<?xml version="1.0" encoding="UTF-8"?>
<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>com.csii</groupId>
    <artifactId>sonar-cola</artifactId>
    <packaging>sonar-plugin</packaging>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <sonar.apiVersion>7.9</sonar.apiVersion>
        <jdk.min.version>1.8</jdk.min.version>
        <sonar.sources>src/main/java,src/main/resources</sonar.sources>
    </properties>

    <description>Rules to check SQL statements in MyBatis Mapper XML files</description>

    <dependencies>
        <dependency>
            <groupId>org.sonarsource.sonarqube</groupId>
            <artifactId>sonar-plugin-api</artifactId>
            <version>${sonar.apiVersion}</version>
            <scope>provided</scope>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.sonarsource.sonar-packaging-maven-plugin</groupId>
                <artifactId>sonar-packaging-maven-plugin</artifactId>
                <version>1.18.0.372</version>
                <extensions>true</extensions>
                <configuration>
                    <pluginClass>com.csii.plugin.MyPlugin</pluginClass>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.5.1</version>
                <configuration>
                    <source>${jdk.min.version}</source>
                    <target>${jdk.min.version}</target>
                </configuration>
            </plugin>
            <plugin>
                <!-- UTF-8 bundles are not supported by Java, so they must be converted during build -->
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>native2ascii-maven-plugin</artifactId>
                <version>1.0-beta-1</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>native2ascii</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

2.编写Plugin类,实现Plugin接口,重写define方法,这里是plugin的定义

 3.质量配置,实现BuiltInQualityProfileDefinition接口,设置质量的语言和规则的名称,多个规则则定义多个。

 4.定义规则,实现RulesDefinition接口,主要设置了规则的xml文件路径,语言类型,规则的key和name。

5.规则xml文件

<mylint-rules>
    <rule>
        <key>MyRule1</key>
        <name>不应该使用Statement,建议使用PrepareStatement</name>
        <internalKey>MyRule1</internalKey>
        <description>不应该使用Statement,建议使用PrepareStatement
        </description>
        <severity>MINOR</severity>
        <cardinality>SINGLE</cardinality>
        <status>READY</status>
        <type>BUG</type>
        <tag>mylint</tag>
        <remediationFunction>CONSTANT_ISSUE</remediationFunction>
        <remediationFunctionBaseEffort>20min</remediationFunctionBaseEffort>
    </rule>
</mylint-rules>

6.扫描文件的类,实现Senior接口,这里主要是做代码扫描和规则匹配,添加问题的功能。

package com.csii.plugin.rules;

import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.sensor.Sensor;
import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.batch.sensor.SensorDescriptor;
import org.sonar.api.batch.sensor.issue.NewIssue;
import org.sonar.api.batch.sensor.issue.NewIssueLocation;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;

import java.io.*;

import static com.csii.plugin.rules.MyLintRulesDefinition.REPO_KEY;

public class MyLintSensor  implements Sensor {

    private static final Logger LOGGER = Loggers.get(MyLintSensor.class);

    @Override
    public void describe(SensorDescriptor descriptor) {
        descriptor.name("MyLint Sensor");
        descriptor.onlyOnLanguage("java");
    }

    @Override
    public void execute(SensorContext context) {
        FileSystem fs = context.fileSystem();
        Iterable<InputFile> javaFiles = fs.inputFiles(fs.predicates().hasLanguage("java"));
        BufferedReader input = null;
        try {
            for (InputFile javaFile : javaFiles) {
                String path = javaFile.uri().getPath();
                File file = new File(path);
                input = new BufferedReader (new FileReader(file));
                String text;
                int line = 0;
                CheckBoolFlag f = new CheckBoolFlag();
                f.setFlag(false);
                while((text = input.readLine()) != null) {
                    line++;
                    LOGGER.info("java text==============="+text+ " line ====="+line);
                    text = text.trim();
                    if (f.isFlag()){
                        if (text.endsWith("*/")) {
                            f.setFlag(false);
                        }else{
                            continue;
                        }
                    }
                    if (text.startsWith("/*")&&text.endsWith("*/")){
                        continue;
                    }else if (text.startsWith("/*")&&(!text.endsWith("*/"))){
                        f.setFlag(true);
                        continue;
                    }
                    if (text.startsWith("//")){
                        continue;
                    }
                    matchAndCheckRules(context,text,javaFile,line);
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (input != null){
                try {
                    input.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void matchAndCheckRules(SensorContext context, String text, InputFile file, int line){
        if (text.contains(".createStatement()")){
            LOGGER.info("java text==============="+text+ " line ====="+line);
            RuleKey ruleKey = RuleKey.of(REPO_KEY,"MyRule1");
            NewIssue newIssue = context.newIssue()
                    .forRule(ruleKey);
            NewIssueLocation primaryLocation = newIssue.newLocation()
                    .on(file)
                    .at(file.selectLine(line))
                    .message("不应该使用Statement,建议使用PrepareStatement");
            newIssue.at(primaryLocation);
            newIssue.save();
        }
    }

}

class CheckBoolFlag {

    private boolean flag;

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }
}

7.将打包的jar包放在plugins目录下,重启服务。

四、配置规则生效

在质量配置,搜索java,可以看到我们自己定义的规则在列表中,现在需要让他生效。

 有如下方法可以让其生效:

①设置为默认

②为其设置项目

 ③复制出一个新的规则,修改父规则为系统规则,然后设置为默认规则,这样系统规则也会生效,而我们的规则也会生效。

 五、扫描测试,可以看到我们自定义的插件是可以正常工作的。

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值