aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-server-common
diff options
context:
space:
mode:
authorZipeng WU <zipeng.wu@sonarsource.com>2022-05-05 14:52:04 +0200
committersonartech <sonartech@sonarsource.com>2022-05-09 20:02:59 +0000
commit41af7cd13eed44de4c3941669bdb5968347f454a (patch)
tree050518f3725ee991fb0998f85129562693cffd7e /server/sonar-server-common
parent3637ca1ca97c03bcc110007f9ec52c4cdef60632 (diff)
downloadsonarqube-41af7cd13eed44de4c3941669bdb5968347f454a.tar.gz
sonarqube-41af7cd13eed44de4c3941669bdb5968347f454a.zip
SONAR-16364 Update Rule API to support multiple description sections
Diffstat (limited to 'server/sonar-server-common')
-rw-r--r--server/sonar-server-common/src/main/java/org/sonar/server/rule/RuleDescriptionFormatter.java82
-rw-r--r--server/sonar-server-common/src/test/java/org/sonar/server/rule/RuleDescriptionFormatterTest.java37
2 files changed, 96 insertions, 23 deletions
diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/rule/RuleDescriptionFormatter.java b/server/sonar-server-common/src/main/java/org/sonar/server/rule/RuleDescriptionFormatter.java
index 2de9e1fca83..13db9a72a63 100644
--- a/server/sonar-server-common/src/main/java/org/sonar/server/rule/RuleDescriptionFormatter.java
+++ b/server/sonar-server-common/src/main/java/org/sonar/server/rule/RuleDescriptionFormatter.java
@@ -20,49 +20,93 @@
package org.sonar.server.rule;
import java.util.Collection;
+import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Optional;
+import javax.annotation.CheckForNull;
+import org.sonar.api.rules.RuleType;
import org.sonar.db.rule.RuleDescriptionSectionDto;
import org.sonar.db.rule.RuleDto;
import org.sonar.markdown.Markdown;
import static com.google.common.collect.MoreCollectors.toOptional;
-import static java.lang.String.format;
+import static java.util.stream.Collectors.toMap;
+import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.ASSESS_THE_PROBLEM_SECTION_KEY;
+import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.HOW_TO_FIX_SECTION_KEY;
+import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.INTRODUCTION_SECTION_KEY;
+import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.RESOURCES_SECTION_KEY;
+import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.ROOT_CAUSE_SECTION_KEY;
+import static org.sonar.db.rule.RuleDescriptionSectionDto.DEFAULT_KEY;
+import static org.sonar.db.rule.RuleDto.Format.MARKDOWN;
public class RuleDescriptionFormatter {
+ public static final List<String> SECTION_KEYS = List.of(
+ INTRODUCTION_SECTION_KEY,
+ ROOT_CAUSE_SECTION_KEY,
+ ASSESS_THE_PROBLEM_SECTION_KEY,
+ HOW_TO_FIX_SECTION_KEY,
+ RESOURCES_SECTION_KEY);
+
+ public static final Map<String, String> HOTSPOT_SECTION_TITLES = Map.of(
+ ROOT_CAUSE_SECTION_KEY, "What's the risk ?",
+ ASSESS_THE_PROBLEM_SECTION_KEY, "Assess the risk",
+ HOW_TO_FIX_SECTION_KEY, "How can you fix it ?"
+ );
+
+ public static final Map<String, String> RULE_SECTION_TITLES = Map.of(
+ ROOT_CAUSE_SECTION_KEY, "Why is this an issue ?",
+ HOW_TO_FIX_SECTION_KEY, "How to fix it ?",
+ RESOURCES_SECTION_KEY, "Resources"
+ );
+
private RuleDescriptionFormatter() { /* static helpers */ }
+ @CheckForNull
public static String getDescriptionAsHtml(RuleDto ruleDto) {
if (ruleDto.getDescriptionFormat() == null) {
return null;
}
Collection<RuleDescriptionSectionDto> ruleDescriptionSectionDtos = ruleDto.getRuleDescriptionSectionDtos();
- return retrieveDescription(ruleDescriptionSectionDtos, ruleDto.getRuleKey(), Objects.requireNonNull(ruleDto.getDescriptionFormat()));
+ return retrieveDescription(ruleDescriptionSectionDtos, RuleType.valueOf(ruleDto.getType()), Objects.requireNonNull(ruleDto.getDescriptionFormat()));
}
+ @CheckForNull
private static String retrieveDescription(Collection<RuleDescriptionSectionDto> ruleDescriptionSectionDtos,
- String ruleKey, RuleDto.Format descriptionFormat) {
- Optional<RuleDescriptionSectionDto> ruleDescriptionSectionDto = findDefaultDescription(ruleDescriptionSectionDtos);
- return ruleDescriptionSectionDto
- .map(ruleDescriptionSection -> toHtml(ruleKey, descriptionFormat, ruleDescriptionSection))
- .orElse(null);
+ RuleType ruleType, RuleDto.Format descriptionFormat) {
+ if (ruleDescriptionSectionDtos.isEmpty()) {
+ return null;
+ }
+ Map<String, String> sectionKeyToHtml = ruleDescriptionSectionDtos.stream()
+ .collect(toMap(RuleDescriptionSectionDto::getKey, section -> toHtml(descriptionFormat, section)));
+ if (sectionKeyToHtml.containsKey(DEFAULT_KEY)) {
+ return sectionKeyToHtml.get(DEFAULT_KEY);
+ } else {
+ return concatHtmlSections(sectionKeyToHtml, ruleType);
+ }
}
- private static Optional<RuleDescriptionSectionDto> findDefaultDescription(Collection<RuleDescriptionSectionDto> ruleDescriptionSectionDtos) {
- return ruleDescriptionSectionDtos.stream()
- .filter(RuleDescriptionSectionDto::isDefault)
- .collect(toOptional());
+ private static String concatHtmlSections(Map<String, String> sectionKeyToHtml, RuleType ruleType) {
+ Map<String, String> titleMapping = ruleType.equals(RuleType.SECURITY_HOTSPOT) ? HOTSPOT_SECTION_TITLES : RULE_SECTION_TITLES;
+ var builder = new StringBuilder();
+ for (String sectionKey : SECTION_KEYS) {
+ if (sectionKeyToHtml.containsKey(sectionKey)) {
+ builder.append("<h2>")
+ .append(titleMapping.get(sectionKey))
+ .append("</h2>")
+ .append(sectionKeyToHtml.get(sectionKey))
+ .append("<br/>");
+ }
+ }
+ return builder.toString();
}
- private static String toHtml(String ruleKey, RuleDto.Format descriptionFormat, RuleDescriptionSectionDto ruleDescriptionSectionDto) {
- switch (descriptionFormat) {
- case MARKDOWN:
- return Markdown.convertToHtml(ruleDescriptionSectionDto.getContent());
- case HTML:
- return ruleDescriptionSectionDto.getContent();
- default:
- throw new IllegalStateException(format("Rule description section format '%s' is unknown for rule key '%s'", descriptionFormat, ruleKey));
+ private static String toHtml(RuleDto.Format descriptionFormat, RuleDescriptionSectionDto ruleDescriptionSectionDto) {
+ if (MARKDOWN.equals(descriptionFormat)) {
+ return Markdown.convertToHtml(ruleDescriptionSectionDto.getContent());
+ } else {
+ return ruleDescriptionSectionDto.getContent();
}
}
diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/rule/RuleDescriptionFormatterTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/rule/RuleDescriptionFormatterTest.java
index 7c0879424c0..260bb5ed4f6 100644
--- a/server/sonar-server-common/src/test/java/org/sonar/server/rule/RuleDescriptionFormatterTest.java
+++ b/server/sonar-server-common/src/test/java/org/sonar/server/rule/RuleDescriptionFormatterTest.java
@@ -20,10 +20,14 @@
package org.sonar.server.rule;
import org.junit.Test;
+import org.sonar.api.rules.RuleType;
import org.sonar.db.rule.RuleDescriptionSectionDto;
import org.sonar.db.rule.RuleDto;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.ASSESS_THE_PROBLEM_SECTION_KEY;
+import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.HOW_TO_FIX_SECTION_KEY;
+import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.ROOT_CAUSE_SECTION_KEY;
import static org.sonar.db.rule.RuleDescriptionSectionDto.createDefaultRuleDescriptionSection;
public class RuleDescriptionFormatterTest {
@@ -33,21 +37,43 @@ public class RuleDescriptionFormatterTest {
@Test
public void getMarkdownDescriptionAsHtml() {
- RuleDto rule = new RuleDto().setDescriptionFormat(RuleDto.Format.MARKDOWN).addRuleDescriptionSectionDto(MARKDOWN_SECTION);
+ RuleDto rule = new RuleDto().setDescriptionFormat(RuleDto.Format.MARKDOWN).addRuleDescriptionSectionDto(MARKDOWN_SECTION).setType(RuleType.BUG);
String html = RuleDescriptionFormatter.getDescriptionAsHtml(rule);
assertThat(html).isEqualTo("<strong>md</strong> <code>description</code>");
}
@Test
public void getHtmlDescriptionAsIs() {
- RuleDto rule = new RuleDto().setDescriptionFormat(RuleDto.Format.HTML).addRuleDescriptionSectionDto(HTML_SECTION);
+ RuleDto rule = new RuleDto().setDescriptionFormat(RuleDto.Format.HTML).addRuleDescriptionSectionDto(HTML_SECTION).setType(RuleType.BUG);
String html = RuleDescriptionFormatter.getDescriptionAsHtml(rule);
assertThat(html).isEqualTo(HTML_SECTION.getContent());
}
@Test
+ public void concatHtmlDescriptionSections() {
+ var section1 = createRuleDescriptionSection(ROOT_CAUSE_SECTION_KEY, "<div>Root is Root</div>");
+ var section2 = createRuleDescriptionSection(ASSESS_THE_PROBLEM_SECTION_KEY, "<div>This is not a problem</div>");
+ var section3 = createRuleDescriptionSection(HOW_TO_FIX_SECTION_KEY, "<div>I don't want to fix</div>");
+ RuleDto rule = new RuleDto().setDescriptionFormat(RuleDto.Format.HTML)
+ .setType(RuleType.SECURITY_HOTSPOT)
+ .addRuleDescriptionSectionDto(section1)
+ .addRuleDescriptionSectionDto(section2)
+ .addRuleDescriptionSectionDto(section3);
+ String html = RuleDescriptionFormatter.getDescriptionAsHtml(rule);
+ assertThat(html)
+ .contains(
+ "<h2>What's the risk ?</h2>"
+ + "<div>Root is Root</div><br/>"
+ + "<h2>Assess the risk</h2>"
+ + "<div>This is not a problem</div><br/>"
+ + "<h2>How can you fix it ?</h2>"
+ + "<div>I don't want to fix</div><br/>"
+ );
+ }
+
+ @Test
public void handleEmptyDescription() {
- RuleDto rule = new RuleDto().setDescriptionFormat(RuleDto.Format.HTML);
+ RuleDto rule = new RuleDto().setDescriptionFormat(RuleDto.Format.HTML).setType(RuleType.BUG);
String result = RuleDescriptionFormatter.getDescriptionAsHtml(rule);
assertThat(result).isNull();
}
@@ -55,9 +81,12 @@ public class RuleDescriptionFormatterTest {
@Test
public void handleNullDescriptionFormat() {
RuleDescriptionSectionDto sectionWithNullFormat = createDefaultRuleDescriptionSection("uuid", "whatever");
- RuleDto rule = new RuleDto().addRuleDescriptionSectionDto(sectionWithNullFormat);
+ RuleDto rule = new RuleDto().addRuleDescriptionSectionDto(sectionWithNullFormat).setType(RuleType.BUG);
String result = RuleDescriptionFormatter.getDescriptionAsHtml(rule);
assertThat(result).isNull();
}
+ private static RuleDescriptionSectionDto createRuleDescriptionSection(String key, String content) {
+ return RuleDescriptionSectionDto.builder().key(key).content(content).build();
+ }
}