diff options
author | Aurelien Poscia <aurelien.poscia@sonarsource.com> | 2022-07-13 14:48:11 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2022-07-14 20:03:48 +0000 |
commit | e840bd147581e8d73bd8f74c5488f1cde5844308 (patch) | |
tree | aab348ff31aba260e6c836f7b26d1f3352c4fa77 /server/sonar-server-common | |
parent | 70d175ec3b14e379a6a52de4124a0dfd0ca26a3e (diff) | |
download | sonarqube-e840bd147581e8d73bd8f74c5488f1cde5844308.tar.gz sonarqube-e840bd147581e8d73bd8f74c5488f1cde5844308.zip |
SONAR-16635 Use plugin-api htmlDesc to populate web api/rule/*** rule.htmlDesc and /api/hotspots/show fields
Diffstat (limited to 'server/sonar-server-common')
2 files changed, 13 insertions, 94 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 ad34b1f81d4..9492aaa3f1c 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 @@ -19,85 +19,34 @@ */ package org.sonar.server.rule; +import com.google.common.collect.MoreCollectors; 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.RuleDescriptionSectionContextDto; import org.sonar.db.rule.RuleDescriptionSectionDto; import org.sonar.db.rule.RuleDto; import org.sonar.markdown.Markdown; -import static java.util.Comparator.comparing; -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 is 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" - ); - @CheckForNull public String getDescriptionAsHtml(RuleDto ruleDto) { if (ruleDto.getDescriptionFormat() == null) { return null; } Collection<RuleDescriptionSectionDto> ruleDescriptionSectionDtos = ruleDto.getRuleDescriptionSectionDtos(); - return retrieveDescription(ruleDescriptionSectionDtos, RuleType.valueOf(ruleDto.getType()), Objects.requireNonNull(ruleDto.getDescriptionFormat())); + return retrieveDescription(ruleDescriptionSectionDtos, Objects.requireNonNull(ruleDto.getDescriptionFormat())); } @CheckForNull - private static String retrieveDescription(Collection<RuleDescriptionSectionDto> ruleDescriptionSectionDtos, - RuleType ruleType, RuleDto.Format descriptionFormat) { - if (ruleDescriptionSectionDtos.isEmpty()) { - return null; - } - Map<String, String> sectionKeyToHtml = ruleDescriptionSectionDtos.stream() - //TODO MMF-2765, merge operation on toMap should not be needed anymore - .sorted(comparing(RuleDescriptionSectionDto::getKey).thenComparing(s -> Optional.ofNullable(s.getContext()).map(RuleDescriptionSectionContextDto::getKey).orElse(null))) - .collect(toMap(RuleDescriptionSectionDto::getKey, section -> toHtml(descriptionFormat, section), (k1, k2) -> k1)); - if (sectionKeyToHtml.containsKey(DEFAULT_KEY)) { - return sectionKeyToHtml.get(DEFAULT_KEY); - } else { - return concatHtmlSections(sectionKeyToHtml, ruleType); - } - } - - 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)) { - Optional.ofNullable(titleMapping.get(sectionKey)).ifPresent(title -> builder.append("<h2>").append(title).append("</h2>")); - builder.append(sectionKeyToHtml.get(sectionKey)).append("<br/>"); - } - } - return builder.toString(); + private static String retrieveDescription(Collection<RuleDescriptionSectionDto> ruleDescriptionSectionDtos, RuleDto.Format descriptionFormat) { + return ruleDescriptionSectionDtos.stream() + .filter(RuleDescriptionSectionDto::isDefault) + .collect(MoreCollectors.toOptional()) + .map(section -> toHtml(descriptionFormat, section)) + .orElse(null); } private static String toHtml(RuleDto.Format descriptionFormat, RuleDescriptionSectionDto ruleDescriptionSectionDto) { 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 8466dfaaa4f..2268e2e408b 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 @@ -19,20 +19,13 @@ */ package org.sonar.server.rule; -import java.util.Optional; -import org.apache.commons.lang.RandomStringUtils; -import org.jetbrains.annotations.Nullable; import org.junit.Test; import org.sonar.api.rules.RuleType; -import org.sonar.db.rule.RuleDescriptionSectionContextDto; 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.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.createDefaultRuleDescriptionSection; @@ -57,33 +50,17 @@ public class RuleDescriptionFormatterTest { } @Test - public void concatHtmlDescriptionSections() { + public void getDescriptionAsHtml_ignoresAdvancedSections() { 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>"); - var section4 = createRuleDescriptionSection(INTRODUCTION_SECTION_KEY, "<div>Introduction with no title</div>"); - var section5ctx1 = createRuleDescriptionSection(RESOURCES_SECTION_KEY, "<div>CTX_1</div>", "CTX_1"); - var section5ctx2 = createRuleDescriptionSection(RESOURCES_SECTION_KEY, "<div>CTX_2</div>", "CTX_2"); + var defaultRuleDescriptionSection = createDefaultRuleDescriptionSection("uuid_432", "default description"); RuleDto rule = new RuleDto().setDescriptionFormat(RuleDto.Format.HTML) .setType(RuleType.SECURITY_HOTSPOT) .addRuleDescriptionSectionDto(section1) .addRuleDescriptionSectionDto(section2) - .addRuleDescriptionSectionDto(section3) - .addRuleDescriptionSectionDto(section4) - .addRuleDescriptionSectionDto(section5ctx2) - .addRuleDescriptionSectionDto(section5ctx1); + .addRuleDescriptionSectionDto(defaultRuleDescriptionSection); String html = ruleDescriptionFormatter.getDescriptionAsHtml(rule); - assertThat(html) - .isEqualTo( - "<div>Introduction with no title</div><br/>" - + "<h2>What is 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/>" - + "<div>CTX_1</div><br/>" - ); + assertThat(html).isEqualTo(defaultRuleDescriptionSection.getContent()); } @Test @@ -102,13 +79,6 @@ public class RuleDescriptionFormatterTest { } private static RuleDescriptionSectionDto createRuleDescriptionSection(String key, String content) { - return createRuleDescriptionSection(key, content, null); - } - - private static RuleDescriptionSectionDto createRuleDescriptionSection(String key, String content, @Nullable String contextKey) { - RuleDescriptionSectionContextDto context = Optional.ofNullable(contextKey) - .map(c -> RuleDescriptionSectionContextDto.of(contextKey, contextKey + RandomStringUtils.randomAlphanumeric(20))) - .orElse(null); - return RuleDescriptionSectionDto.builder().key(key).content(content).context(context).build(); + return RuleDescriptionSectionDto.builder().key(key).content(content).build(); } } |