谁能指出我为 sonarqube Web 插件添加自定义配置文件规则的方向?
我在 javascript 中看到了 xpath 规则,但是 web 插件不包含类似的东西。
具体来说,我正在尝试编写一些规则来检查 WCAG2.0A 的合规性。我知道我缺少的第一条规则是检查页面上的重复 ID。
如果网络插件不支持自定义规则,任何人都可以提供有关如何从源代码构建插件的资源吗?
目前无法将自定义规则添加到 Web 插件。随意讨论您希望添加到用户邮件列表中的新规则:user [at] sonar.codehaus.org。构建它: mvn install
这是关于向SonarQube 网络插件源代码添加新规则“空标题”的教程。您需要编写一些Java 代码。
提示:可以通过自定义模板来创建一些简单的规则,而无需任何编码。(见我的第一反应)
在开始之前,您需要在您的机器上安装 Java 8、Maven 3 和 Git。您还需要访问 SonarQube 服务器。您可以从这里下载服务器。 https://www.sonarqube.org/downloads/
下载 SonarQube 网络插件源代码。
$ git clone https://github.com/SonarSource/sonar-web.git
使用 Maven 构建插件项目。
$ mvn 全新安装
将 Maven 项目导入 IDE 进行开发。
/*
* 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;
}
}
public final class CheckClasses {
private static final List<Class> CLASSES = ImmutableList.of(
...,
HeadingNotEmptyCheck.class,
...
<p>When at least one heading element (marked by <h1> through <h6>) is present, it is a best practice to ensure it contains content.</p>
<h2>Noncompliant Code Example</h2>
<pre>
<div>
<h1></h1> <!-- Noncompliant; empty content -->
<h2></h2> <!-- Noncompliant; empty content -->
</div>
</pre>
<h2>Compliant Solution</h2>
<pre>
<div>
<h1></h1>
<h2></h2>
</div>
</pre>
{
"title": "Headings must not be empty ",
"type": "BUG",
"status": "ready",
"remediation": {
"func": "Constant\/Issue",
"constantCost": "2min"
},
"tags": [
"accessibility",
"bug"
],
"defaultSeverity": "Minor"
}
/*
* 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();
}
}
<!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>
运行 HeadingNotEmptyCheckTest JUnit 测试用例。如果它有效,您就可以构建和部署插件了。
使用 Maven 构建插件项目。
$ mvn 全新安装
将插件构建工件复制到 SonarQube 插件文件夹。
GIT_REPO\sonar-web\sonar-web-plugin\target\sonar-web-plugin-[版本].jar -> \sonarqube-6.2\extensions\plugins
重启 SonarQube 服务器
验证 SonarQube 服务器上的新规则
登录 SonarQube,选择“规则”菜单,过滤语言“Web”,您应该会看到新规则“标题不得为空”