]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-13357 Custom hotspot rule's description isn't split into tabs
authorPhilippe Perrin <philippe.perrin@sonarsource.com>
Tue, 23 Feb 2021 16:22:27 +0000 (17:22 +0100)
committersonartech <sonartech@sonarsource.com>
Thu, 25 Feb 2021 20:07:33 +0000 (20:07 +0000)
server/sonar-server-common/src/main/java/org/sonar/server/rule/HotspotRuleDescription.java
server/sonar-server-common/src/main/java/org/sonar/server/rule/RuleDescriptionFormatter.java [new file with mode: 0644]
server/sonar-server-common/src/test/java/org/sonar/server/rule/HotspotRuleDescriptionTest.java
server/sonar-server-common/src/test/java/org/sonar/server/rule/RuleDescriptionFormatterTest.java [new file with mode: 0644]
server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/ShowAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/RuleDescriptionFormatter.java [deleted file]
server/sonar-webserver-webapi/src/test/java/org/sonar/server/hotspot/ws/ShowActionTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/RuleDescriptionFormatterTest.java [deleted file]
sonar-markdown/src/main/java/org/sonar/markdown/HtmlHeadingChannel.java
sonar-markdown/src/test/java/org/sonar/markdown/MarkdownTest.java

index 11b2607e2dc4559fea31f27dff67f2edf96b9517..01c434924f5f544b57f438d14719b62457cebe2b 100644 (file)
@@ -48,7 +48,7 @@ public class HotspotRuleDescription {
   }
 
   public static HotspotRuleDescription from(RuleDefinitionDto dto) {
-    String description = dto.getDescription();
+    String description = dto.isCustomRule() ? RuleDescriptionFormatter.getDescriptionAsHtml(dto) : dto.getDescription();
     return from(description);
   }
 
@@ -111,12 +111,12 @@ public class HotspotRuleDescription {
       if (endIndex == -1) {
         endIndex = description.length();
       }
-      return new String[] {
+      return new String[]{
         description.substring(0, beginningIndex) + description.substring(endIndex),
         description.substring(beginningIndex, endIndex)
       };
     } else {
-      return new String[] {description, ""};
+      return new String[]{description, ""};
     }
 
   }
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
new file mode 100644 (file)
index 0000000..7a5ba9b
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.rule;
+
+import org.sonar.db.rule.RuleDefinitionDto;
+import org.sonar.db.rule.RuleDto;
+import org.sonar.markdown.Markdown;
+
+import static java.lang.String.format;
+
+public class RuleDescriptionFormatter {
+
+  private RuleDescriptionFormatter() { /* static helpers */ }
+
+  public static String getDescriptionAsHtml(RuleDefinitionDto ruleDto) {
+    String description = ruleDto.getDescription();
+    RuleDto.Format descriptionFormat = ruleDto.getDescriptionFormat();
+    if (description != null && descriptionFormat != null) {
+      switch (descriptionFormat) {
+        case MARKDOWN:
+          return Markdown.convertToHtml(description);
+        case HTML:
+          return description;
+        default:
+          throw new IllegalStateException(format("Rule description format '%s' is unknown for key '%s'", descriptionFormat, ruleDto.getKey().toString()));
+      }
+    }
+    return null;
+  }
+
+}
index a5c71d5e72b22e077a98aa047919bc358b1159d7..f936c385a0037c472d37ab71ee41eeaaf9201c8e 100644 (file)
@@ -25,6 +25,7 @@ import com.tngtech.java.junit.dataprovider.UseDataProvider;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.sonar.db.rule.RuleDefinitionDto;
+import org.sonar.db.rule.RuleDto;
 import org.sonar.db.rule.RuleTesting;
 
 import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
@@ -145,6 +146,43 @@ public class HotspotRuleDescriptionTest {
     assertThat(result.getFixIt().get()).isEqualTo(RECOMMENTEDCODINGPRACTICE + SEE);
   }
 
+  @Test
+  public void parse_custom_rule_description() {
+    String ruleDescription = "This is the custom rule description";
+    String exceptionsContent = "This the exceptions section content";
+    String askContent = "This is the ask section content";
+    String recommendedContent = "This is the recommended section content";
+
+    RuleDefinitionDto dto = RuleTesting.newRule()
+      .setTemplateUuid("123")
+      .setDescriptionFormat(RuleDto.Format.MARKDOWN)
+      .setDescription(
+        ruleDescription + "\n"
+        + "== Exceptions" + "\n"
+        + exceptionsContent + "\n"
+        + "== Ask Yourself Whether" + "\n"
+        + askContent + "\n"
+        + "== Recommended Secure Coding Practices" + "\n"
+        + recommendedContent + "\n"
+      );
+
+    HotspotRuleDescription result = HotspotRuleDescription.from(dto);
+
+    assertThat(result.getRisk().get()).hasToString(
+      ruleDescription + "<br/>"
+      + "<h2>Exceptions</h2>"
+      + exceptionsContent + "<br/>"
+    );
+    assertThat(result.getVulnerable().get()).hasToString(
+        "<h2>Ask Yourself Whether</h2>"
+        + askContent + "<br/>"
+    );
+    assertThat(result.getFixIt().get()).hasToString(
+      "<h2>Recommended Secure Coding Practices</h2>"
+        + recommendedContent + "<br/>"
+    );
+  }
+
   /*
    * Bunch of static constant to create rule description.
    */
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
new file mode 100644 (file)
index 0000000..2eb3bf8
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.rule;
+
+import org.junit.Test;
+import org.sonar.db.rule.RuleDefinitionDto;
+import org.sonar.db.rule.RuleDto;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class RuleDescriptionFormatterTest {
+
+  @Test
+  public void getMarkdownDescriptionAsHtml() {
+    RuleDefinitionDto rule = new RuleDefinitionDto().setDescription("*md* ``description``").setDescriptionFormat(RuleDto.Format.MARKDOWN);
+    String html = RuleDescriptionFormatter.getDescriptionAsHtml(rule);
+    assertThat(html).isEqualTo("<strong>md</strong> <code>description</code>");
+  }
+
+  @Test
+  public void getHtmlDescriptionAsIs() {
+    String description = "<span class=\"example\">*md* ``description``</span>";
+    RuleDefinitionDto rule = new RuleDefinitionDto().setDescription(description).setDescriptionFormat(RuleDto.Format.HTML);
+    String html = RuleDescriptionFormatter.getDescriptionAsHtml(rule);
+    assertThat(html).isEqualTo(description);
+  }
+
+  @Test
+  public void handleNullDescription() {
+    RuleDefinitionDto rule = new RuleDefinitionDto().setDescription(null).setDescriptionFormat(RuleDto.Format.HTML);
+    String result = RuleDescriptionFormatter.getDescriptionAsHtml(rule);
+    assertThat(result).isNull();
+  }
+
+  @Test
+  public void handleNullDescriptionFormat() {
+    RuleDefinitionDto rule = new RuleDefinitionDto().setDescription("whatever").setDescriptionFormat(null);
+    String result = RuleDescriptionFormatter.getDescriptionAsHtml(rule);
+    assertThat(result).isNull();
+  }
+}
index 20661d253e0f063fdceed64fd4064b2428b14726..d05d9d1eaca8a428ba8c53a472f9e6c966282779 100644 (file)
@@ -45,7 +45,6 @@ import org.sonar.server.issue.IssueChangeWSSupport.Load;
 import org.sonar.server.issue.TextRangeResponseFormatter;
 import org.sonar.server.issue.ws.UserResponseFormatter;
 import org.sonar.server.rule.HotspotRuleDescription;
-import org.sonar.server.rule.RuleDescriptionFormatter;
 import org.sonar.server.security.SecurityStandards;
 import org.sonar.server.text.MacroInterpreter;
 import org.sonarqube.ws.Common;
@@ -169,17 +168,10 @@ public class ShowAction implements HotspotsWsAction {
       .setSecurityCategory(sqCategory.getKey())
       .setVulnerabilityProbability(sqCategory.getVulnerability().name());
 
-    if (ruleDefinitionDto.isCustomRule()) {
-      String htmlDescription = RuleDescriptionFormatter.getDescriptionAsHtml(ruleDefinitionDto);
-      if (htmlDescription != null) {
-        ruleBuilder.setRiskDescription(macroInterpreter.interpret(htmlDescription));
-      }
-    } else {
-      HotspotRuleDescription hotspotRuleDescription = HotspotRuleDescription.from(ruleDefinitionDto);
-      hotspotRuleDescription.getVulnerable().ifPresent(ruleBuilder::setVulnerabilityDescription);
-      hotspotRuleDescription.getRisk().ifPresent(ruleBuilder::setRiskDescription);
-      hotspotRuleDescription.getFixIt().ifPresent(ruleBuilder::setFixRecommendations);
-    }
+    HotspotRuleDescription hotspotRuleDescription = HotspotRuleDescription.from(ruleDefinitionDto);
+    hotspotRuleDescription.getVulnerable().ifPresent(ruleBuilder::setVulnerabilityDescription);
+    hotspotRuleDescription.getRisk().ifPresent(ruleBuilder::setRiskDescription);
+    hotspotRuleDescription.getFixIt().ifPresent(ruleBuilder::setFixRecommendations);
 
     responseBuilder.setRule(ruleBuilder.build());
   }
@@ -232,7 +224,7 @@ public class ShowAction implements HotspotsWsAction {
     boolean hotspotOnProject = Objects.equals(project.uuid(), componentUuid);
     ComponentDto component = hotspotOnProject ? project
       : dbClient.componentDao().selectByUuid(dbSession, componentUuid)
-        .orElseThrow(() -> new NotFoundException(format("Component with uuid '%s' does not exist", componentUuid)));
+      .orElseThrow(() -> new NotFoundException(format("Component with uuid '%s' does not exist", componentUuid)));
 
     return new Components(project, component);
   }
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/RuleDescriptionFormatter.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/RuleDescriptionFormatter.java
deleted file mode 100644 (file)
index 7a5ba9b..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2021 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.server.rule;
-
-import org.sonar.db.rule.RuleDefinitionDto;
-import org.sonar.db.rule.RuleDto;
-import org.sonar.markdown.Markdown;
-
-import static java.lang.String.format;
-
-public class RuleDescriptionFormatter {
-
-  private RuleDescriptionFormatter() { /* static helpers */ }
-
-  public static String getDescriptionAsHtml(RuleDefinitionDto ruleDto) {
-    String description = ruleDto.getDescription();
-    RuleDto.Format descriptionFormat = ruleDto.getDescriptionFormat();
-    if (description != null && descriptionFormat != null) {
-      switch (descriptionFormat) {
-        case MARKDOWN:
-          return Markdown.convertToHtml(description);
-        case HTML:
-          return description;
-        default:
-          throw new IllegalStateException(format("Rule description format '%s' is unknown for key '%s'", descriptionFormat, ruleDto.getKey().toString()));
-      }
-    }
-    return null;
-  }
-
-}
index 13ff6d1b1626bae6b2e880990a1c14ab9311480e..dfc9a5cfaa59912f5c360cbd7d6e593b963ca225 100644 (file)
@@ -387,24 +387,20 @@ public class ShowActionTest {
     userSessionRule.logIn().addProjectPermission(UserRole.USER, project);
     ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
 
-    String description = "<div>line1\nline2</div>";
-    String parsedDescription = "&lt;div&gt;line1<br/>line2&lt;/div&gt;";
-    String resultingDescription = "!" + parsedDescription + "!";
+    String description = "== Title\n<div>line1\nline2</div>";
 
     RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT,
       r -> r.setTemplateUuid("123")
         .setDescription(description)
         .setDescriptionFormat(MARKDOWN));
 
-    doReturn(resultingDescription).when(macroInterpreter).interpret(parsedDescription);
-
     IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file);
     mockChangelogAndCommentsFormattingContext();
 
     Hotspots.ShowWsResponse response = newRequest(hotspot)
       .executeProtobuf(Hotspots.ShowWsResponse.class);
 
-    assertThat(response.getRule().getRiskDescription()).isEqualTo(resultingDescription);
+    assertThat(response.getRule().getRiskDescription()).isEqualTo("<h2>Title</h2>&lt;div&gt;line1<br/>line2&lt;/div&gt;");
   }
 
   @Test
diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/RuleDescriptionFormatterTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/RuleDescriptionFormatterTest.java
deleted file mode 100644 (file)
index 2eb3bf8..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2021 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.server.rule;
-
-import org.junit.Test;
-import org.sonar.db.rule.RuleDefinitionDto;
-import org.sonar.db.rule.RuleDto;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class RuleDescriptionFormatterTest {
-
-  @Test
-  public void getMarkdownDescriptionAsHtml() {
-    RuleDefinitionDto rule = new RuleDefinitionDto().setDescription("*md* ``description``").setDescriptionFormat(RuleDto.Format.MARKDOWN);
-    String html = RuleDescriptionFormatter.getDescriptionAsHtml(rule);
-    assertThat(html).isEqualTo("<strong>md</strong> <code>description</code>");
-  }
-
-  @Test
-  public void getHtmlDescriptionAsIs() {
-    String description = "<span class=\"example\">*md* ``description``</span>";
-    RuleDefinitionDto rule = new RuleDefinitionDto().setDescription(description).setDescriptionFormat(RuleDto.Format.HTML);
-    String html = RuleDescriptionFormatter.getDescriptionAsHtml(rule);
-    assertThat(html).isEqualTo(description);
-  }
-
-  @Test
-  public void handleNullDescription() {
-    RuleDefinitionDto rule = new RuleDefinitionDto().setDescription(null).setDescriptionFormat(RuleDto.Format.HTML);
-    String result = RuleDescriptionFormatter.getDescriptionAsHtml(rule);
-    assertThat(result).isNull();
-  }
-
-  @Test
-  public void handleNullDescriptionFormat() {
-    RuleDefinitionDto rule = new RuleDefinitionDto().setDescription("whatever").setDescriptionFormat(null);
-    String result = RuleDescriptionFormatter.getDescriptionAsHtml(rule);
-    assertThat(result).isNull();
-  }
-}
index 808e79e0300850b1575d354bb3b167720cc7a0b3..fbd1dd7102107e7a95662bfb99431ac2d15c788c 100644 (file)
@@ -71,7 +71,7 @@ public class HtmlHeadingChannel extends RegexChannel<MarkdownOutput> {
     CharSequence headingText = token.subSequence(index, token.length());
 
     output.append("<h" + headingLevel + ">");
-    output.append(headingText);
+    output.append(headingText.toString().trim());
     output.append("</h" + headingLevel + ">");
   }
 }
index 865c2281aeb48624819b60fed0327dc8747e3648..553aae54adf0e4d284c88c459b67e2abbca7d447 100644 (file)
@@ -61,8 +61,8 @@ public class MarkdownTest {
 
   @Test
   public void shouldDecorateHeadings() {
-    assertThat(Markdown.convertToHtml("  = Top\r== Sub\r\n=== Subsub\n ==== \n 1.five"))
-        .isEqualTo("<h1>Top\r</h1><h2>Sub\r\n</h2><h3>Subsub\n</h3><h4></h4> 1.five");
+    assertThat(Markdown.convertToHtml("  = Top\r== Sub\r\n=== Sub sub\n ==== \n 1.five"))
+        .isEqualTo("<h1>Top</h1><h2>Sub</h2><h3>Sub sub</h3><h4></h4> 1.five");
   }
 
   @Test