【问题标题】:Sonar Web Plugin声纳网络插件
【发布时间】:2023-04-05 20:29:02
【问题描述】:

谁能指出我为 sonarqube 网络插件添加自定义配置文件规则的方向?

我在 javascript 中看到过 xpath 规则,但 web 插件不包含类似的东西。

具体来说,我正在尝试编写一些规则来检查 WCAG2.0A 的合规性。我知道我缺少的第一条规则是检查页面上的重复 ID。

如果网络插件不支持自定义规则,谁能提供有关如何从源代码构建插件的资源?

【问题讨论】:

    标签: java sonarqube


    【解决方案1】:

    目前无法向 Web 插件添加自定义规则。 随意讨论您希望添加到用户邮件列表中的新规则:user [at] sonar.codehaus.org。 构建它: mvn install

    【讨论】:

      【解决方案2】:

      模板 在 SonarQube 网络插件中可用,用于为 HTML 或 JSP 文档创建简单的规则。模板可以通过用户定义的参数进行定制。 (这可以在 SonarQube 网页界面中完成,不需要任何编码)。

      可用模板:(在 sonar-web-plugin-2.6 版本中)

      • 跟踪缺少所需的子元素

      • 跟踪缺少所需的父元素

      • 跟踪被禁止的父元素的存在

      • 跟踪不允许的属性的使用

      • 跟踪不允许的子元素的使用

      模板规则示例:

      • 创建一个规则,检查 HTML 文档中的所有 “area” 元素是否具有 “alt” 子元素。

        1. 选择“跟踪缺少所需的子元素”模板。
        2. 点击自定义规则“创建”按钮。
        3. 在“自定义规则”对话框中输入新规则的名称和说明。
        4. 输入父元素“area”和子元素“alt”。
        5. 保存规则。

      要创建模板未提供的规则,您需要修改插件源代码(需要 Java 编码)。请参阅我的其他回复。

      【讨论】:

        【解决方案3】:

        这里有一个向 SonarQube 网络插件源代码添加新规则 "empty-heading" 的教程。您需要编写一些 Java 代码。

        提示:可以通过自定义模板来创建一些简单的规则,而无需任何编码。 (见我的第一反应)

        示例规则:

        设置插件:

        1. 在开始之前,您需要在您的机器上安装 Java 8、Maven 3 和 Git。您还需要访问 SonarQube 服务器。您可以从这里下载服务器。 https://www.sonarqube.org/downloads/

        2. 下载 SonarQube 网络插件源代码。

          $ git clone https://github.com/SonarSource/sonar-web.git

        3. 使用 Maven 构建插件项目。

          $ mvn clean install

        4. 将 Maven 项目导入 IDE 进行开发。

        为插件添加代码:

        1. 将 Rule 类 HeadingNotEmptyCheck.java 添加到 src/main/java
        /*
         * SonarSource :: Web :: Sonar Plugin
         * Copyright (c) 2010-2017 SonarSource SA and Matthijs Galesloot
         * sonarqube@googlegroups.com
         *
         * Licensed under the Apache License, Version 2.0 (the "License");
         * you may not use this file except in compliance with the License.
         * You may obtain a copy of the License at
         *
         * http://www.apache.org/licenses/LICENSE-2.0
         *
         * Unless required by applicable law or agreed to in writing, software
         * distributed under the License is distributed on an "AS IS" BASIS,
         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
         * See the License for the specific language governing permissions and
         * limitations under the License.
         */
        package org.sonar.plugins.web.checks.coding;
        
        import java.util.List;
        import org.apache.commons.lang.StringUtils;
        import org.sonar.check.Rule;
        import org.sonar.plugins.web.checks.AbstractPageCheck;
        import org.sonar.plugins.web.node.Node;
        import org.sonar.plugins.web.node.TagNode;
        import org.sonar.plugins.web.node.TextNode;
        
        @Rule(key = "HeadingNotEmptyCheck")
        public class HeadingNotEmptyCheck extends AbstractPageCheck {
        
            private static final String[] headingTagsArray = StringUtils.split("H1,H2,H3,H4,H5,H6", ',');
            private TagNode startHeadingNode;
            private TextNode textNode;
        
            @Override
            public void startDocument(List<Node> nodes) {
                startHeadingNode = null;
                textNode = null;
            }
        
            @Override
            public void startElement(TagNode element) {
                if (isHeading(element)) {
                    this.startHeadingNode = element;
                    this.textNode = null;
                }
            }
        
            @Override
            public void endElement(TagNode element) {
                if (isHeading(element)) {
                    if (startHeadingNode == null || !startHeadingNode.getNodeName().equals(element.getNodeName())) {
                        createViolation(element.getStartLinePosition(),
                                "The tag \"" + element.getNodeName() + "\" has no corresponding start tag.");
                        this.textNode = null;
                        return;
                    }
                    // found matching start tag for end tag
                    startHeadingNode = null;
        
                    if (textNode == null) {
                        createViolation(element.getStartLinePosition(),
                                "The tag \"" + element.getNodeName() + "\" heading must not be empty.");
                        return;
                    }
                }
            }
        
            @Override
            public void characters(TextNode textNode) {
                if (!textNode.isBlank()) {
                    this.textNode = textNode; 
                }
            }
        
            private boolean isHeading(TagNode node) {
                for (String headingTag : headingTagsArray) {
                    if (node.equalsElementName(headingTag)) {
                        return true;
                    }
                }
                return false;
            }
        }
        
        1. 更新 CheckClasses.java 以注册新的规则类
        public final class CheckClasses {
        
          private static final List<Class> CLASSES = ImmutableList.of(
            ...,
            HeadingNotEmptyCheck.class,
            ...
        
        1. 将 HeadingNotEmptyCheck.html 规则描述添加到 src/main/resources、org/sonar/l10n/web/rules/Web/ 文件夹。
        <p>When at least one heading element (marked by &lt;h1&gt; through &lt;h6&gt;) is present, it is a best practice to ensure it contains content.</p>
        <h2>Noncompliant Code Example</h2>
        <pre>
        &lt;div&gt;
          &lt;h1&gt;&lt;/h1&gt; &lt;!-- Noncompliant; empty content --&gt;
          &lt;h2&gt;&lt;/h2&gt; &lt;!-- Noncompliant; empty content --&gt;
        &lt;/div&gt;
        </pre>
        <h2>Compliant Solution</h2>
        <pre>
        &lt;div&gt;
          &lt;h1&gt;&lt;/h1&gt;
          &lt;h2&gt;&lt;/h2&gt;
        &lt;/div&gt;
        </pre>
        
        1. 将 HeadingNotEmptyCheck.json 规则描述添加到 src/main/resources、org/sonar/l10n/web/rules/Web/ 文件夹中
        {
          "title": "Headings must not be empty ",
          "type": "BUG",
          "status": "ready",
          "remediation": {
            "func": "Constant\/Issue",
            "constantCost": "2min"
          },
          "tags": [
            "accessibility",
            "bug"
          ],
          "defaultSeverity": "Minor"
        }
        
        1. 将 JUnit 测试 HeadingNotEmptyCheckTest.java 添加到 src/test/java
        /*
         * SonarSource :: Web :: Sonar Plugin
         * Copyright (c) 2010-2017 SonarSource SA and Matthijs Galesloot
         * sonarqube@googlegroups.com
         *
         * Licensed under the Apache License, Version 2.0 (the "License");
         * you may not use this file except in compliance with the License.
         * You may obtain a copy of the License at
         *
         * http://www.apache.org/licenses/LICENSE-2.0
         *
         * Unless required by applicable law or agreed to in writing, software
         * distributed under the License is distributed on an "AS IS" BASIS,
         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
         * See the License for the specific language governing permissions and
         * limitations under the License.
         */
        package org.sonar.plugins.web.checks.coding;
        
        import java.io.File;
        
        import org.junit.Rule;
        import org.junit.Test;
        import org.sonar.plugins.web.checks.CheckMessagesVerifierRule;
        import org.sonar.plugins.web.checks.TestHelper;
        import org.sonar.plugins.web.visitor.WebSourceCode;
        
        public class HeadingNotEmptyCheckTest {
            @Rule
            public CheckMessagesVerifierRule checkMessagesVerifier = new CheckMessagesVerifierRule();
        
            @Test
            public void testRule() {
                HeadingNotEmptyCheck check = new HeadingNotEmptyCheck();
        
                WebSourceCode sourceCode = TestHelper.scan(new File("src/test/resources/checks/HeadingNotEmptyCheck.html"),
                        check);
        
                checkMessagesVerifier.verify(sourceCode.getIssues()).next().atLine(8)
                        .withMessage("The tag \"h1\" heading must not be empty.").next().atLine(12)
                        .withMessage("The tag \"h2\" heading must not be empty.").next();
            }
        }
        
        1. 将测试文件 HeadingNotEmptyCheck.html 添加到 src/test/resources, checks/ 文件夹中
        <!DOCTYPE html>
        <html>
        <head>
        <title>Title of the document</title>
        </head>
        <body>
            <!-- invalid empty heading -->
            <h1></h1>
            <!-- valid heading -->
            <h1>h1 has content</h1>
            <!-- invalid empty heading -->
            <h2></h2>
            <!-- valid heading -->
            <h2>h2 has content</h2>
            <!-- invalid nested heading -->
            <h1>h1 has content
                <h2>h2 has content</h2>
            </h1>
        </body>
        </html>
        

        测试和部署插件:

        1. 运行 HeadingNotEmptyCheckTest JUnit 测试用例。如果成功,您就可以构建和部署插件了。

        2. 使用 Maven 构建插件项目。

          $ mvn clean install

        3. 将插件构建工件复制到 SonarQube 插件文件夹。

          GIT_REPO\sonar-web\sonar-web-plugin\target\sonar-web-plugin-[VERSION].jar -> \sonarqube-6.2\extensions\plugins

        4. 重启 SonarQube 服务器

        5. 在 SonarQube 服务器上验证新规则

          登录 SonarQube,选择“规则”菜单,过滤语言“Web”,您应该会看到新规则“标题不得为空”

        【讨论】:

          猜你喜欢
          • 2013-02-23
          • 1970-01-01
          • 1970-01-01
          • 2011-01-20
          • 2014-06-10
          • 2016-02-20
          • 2012-03-06
          • 2011-02-05
          • 1970-01-01
          相关资源
          最近更新 更多