SonarQube 自定义插件,启动失败

SonarQube custom plugin, failing on startup

我正在开发自定义 SonarQube 插件来创建项目特定的规则集。已编写自定义规则,并且该规则已使用 JUnit 成功执行。下面是自定义的sonarqube规则。

@Rule(key = StringConstants.AVOID_SOCKETS_API_KEY)
public class AvoidSocketsApiRule extends IssuableSubscriptionVisitor {

    @Override
    public List<Tree.Kind> nodesToVisit() {
        return ImmutableList.of(Tree.Kind.VARIABLE);
    }

    @Override
    public void visitNode(final Tree tree) {
        final VariableTree variableTree = (VariableTree) tree;
        final Type type = variableTree.symbol().type();
        if (type.is(StringConstants.SOCKET_CHANNEL) || type.is(StringConstants.SERVER_SOCKET_CHANNEL)
                || type.is(StringConstants.ASYNC_SOCKET_CHANNEL) || type.is(StringConstants.ASYNC_SERVER_SOCKET_CHANNEL)) {
            this.reportIssue(variableTree.simpleName(), StringConstants.AVOID_SOCKETS_API_MESSAGE);
        }

    }

}

当我将应用程序打包到声纳插件中并部署到声纳库时,它给了我一个非法状态异常。我能够使用 Junit 重现该问题。

@Test
    public void test() {
        final CustomRulesDefinition rulesDefinition = new CustomRulesDefinition();
        final RulesDefinition.Context context = new RulesDefinition.Context();
        rulesDefinition.define(context);
        final RulesDefinition.Repository repository = context.repository(StringConstants.REPOSITORY_KEY);

        assertThat(repository.name()).isEqualTo(StringConstants.REPOSITORY_NAME);
        assertThat(repository.language()).isEqualTo(StringConstants.LANG);
        assertThat(repository.rules()).hasSize(RulesList.getChecks().size());

        this.assertAllRuleParametersHaveDescription(repository);
    }

    private void assertAllRuleParametersHaveDescription(final Repository repository) {
        for (final Rule rule : repository.rules()) {
            for (final Param param : rule.params()) {
                assertThat(param.description()).as("description for " + param.key()).isNotEmpty();
            }
        }
    }

显示的错误如下所示。我找不到修复程序,感谢您在这里提供意见。

java.lang.IllegalStateException: Name of rule [repository=custom-ruleset, key=AvoidSocketsApi] is empty
    at org.sonar.api.server.rule.RulesDefinition$NewRule.validate(RulesDefinition.java:888)
    at org.sonar.api.server.rule.RulesDefinition$NewRule.access0(RulesDefinition.java:659)
    at org.sonar.api.server.rule.RulesDefinition$RepositoryImpl.<init>(RulesDefinition.java:566)
    at org.sonar.api.server.rule.RulesDefinition$RepositoryImpl.<init>(RulesDefinition.java:540)
    at org.sonar.api.server.rule.RulesDefinition$Context.registerRepository(RulesDefinition.java:436)
    at org.sonar.api.server.rule.RulesDefinition$Context.access0(RulesDefinition.java:380)
    at org.sonar.api.server.rule.RulesDefinition$NewRepositoryImpl.done(RulesDefinition.java:512)
    at com.deloitte.sonar.java.CustomRulesDefinition.define(CustomRulesDefinition.java:83)
    at com.deloitte.sonar.java.CustomRulesDefinitionTest.test(CustomRulesDefinitionTest.java:19)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access[=12=]0(ParentRunner.java:58)
    at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

下面是pom.xml

<properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <sonar.plugin.api.version>5.6</sonar.plugin.api.version>
        <java.plugin.version>4.2</java.plugin.version>
        <junit.version>4.12</junit.version>
        <sslr.version>1.21</sslr.version>
        <gson.version>2.6.2</gson.version>
        <slf4j.version>1.6.2</slf4j.version>
        <logback.version>0.9.30</logback.version>
        <fest.assert.version>1.4</fest.assert.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>${java.plugin.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.sonarsource.java</groupId>
            <artifactId>java-frontend</artifactId>
            <version>${java.plugin.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.sonarsource.sslr-squid-bridge</groupId>
            <artifactId>sslr-squid-bridge</artifactId>
            <version>2.6.1</version>
            <exclusions>
                <exclusion>
                    <groupId>org.sonarsource.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>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>${gson.version}</version>
        </dependency>
        <dependency>
            <groupId>org.sonarsource.java</groupId>
            <artifactId>java-checks-testkit</artifactId>
            <version>${java.plugin.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.sonarsource.sslr</groupId>
            <artifactId>sslr-testing-harness</artifactId>
            <version>${sslr.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>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>${logback.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </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>
                    <pluginClass>com.suraj.sonar.java.RulesPlugin</pluginClass>
                    <pluginDescription>Plugin for custom rules</pluginDescription>
                    <pluginOrganizationName>Suraj</pluginOrganizationName>
                    <pluginOrganizationUrl>surajmuraleedharanc.com</pluginOrganizationUrl>
                    <sonarLintSupported>true</sonarLintSupported>
                    <sonarQubeMinVersion>${sonar.plugin.api.version}</sonarQubeMinVersion>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>

        </plugins>
    </build>

您问题的症结似乎是:为什么我的规则通过单元测试有效,但通过 SonarQube 服务器引发异常?

您的单元测试只是执行一些逻辑。它不知道也不关心 "rule".

的概念

但是服务器处理的不是逻辑,而是规则(规则本身包含逻辑)。根据定义,规则必须具有(除其他外)名称。 The custom rule quick start guide 给出了详细信息,但本质上,您需要添加以下内容:

@Rule(
  key = "avoidSocketsApi",
  name = "The \"Sockets\" API should not be used",
  description = "...",
  priority = Priority.CRITICAL,
  tags = {"bug"})
public class AvoidSocketsApiRule extends IssuableSubscriptionVisitor {