From: Philippe Perrin Date: Tue, 23 Feb 2021 16:22:27 +0000 (+0100) Subject: SONAR-13357 Custom hotspot rule's description isn't split into tabs X-Git-Tag: 8.8.0.42792~112 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=ffaa8f3cd63239fc25c624955e8e0760dc53ce11;p=sonarqube.git SONAR-13357 Custom hotspot rule's description isn't split into tabs --- diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/rule/HotspotRuleDescription.java b/server/sonar-server-common/src/main/java/org/sonar/server/rule/HotspotRuleDescription.java index 11b2607e2dc..01c434924f5 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/rule/HotspotRuleDescription.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/rule/HotspotRuleDescription.java @@ -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 index 00000000000..7a5ba9b28a9 --- /dev/null +++ b/server/sonar-server-common/src/main/java/org/sonar/server/rule/RuleDescriptionFormatter.java @@ -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; + } + +} diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/rule/HotspotRuleDescriptionTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/rule/HotspotRuleDescriptionTest.java index a5c71d5e72b..f936c385a00 100644 --- a/server/sonar-server-common/src/test/java/org/sonar/server/rule/HotspotRuleDescriptionTest.java +++ b/server/sonar-server-common/src/test/java/org/sonar/server/rule/HotspotRuleDescriptionTest.java @@ -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 + "
" + + "

Exceptions

" + + exceptionsContent + "
" + ); + assertThat(result.getVulnerable().get()).hasToString( + "

Ask Yourself Whether

" + + askContent + "
" + ); + assertThat(result.getFixIt().get()).hasToString( + "

Recommended Secure Coding Practices

" + + recommendedContent + "
" + ); + } + /* * 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 index 00000000000..2eb3bf82478 --- /dev/null +++ b/server/sonar-server-common/src/test/java/org/sonar/server/rule/RuleDescriptionFormatterTest.java @@ -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("md description"); + } + + @Test + public void getHtmlDescriptionAsIs() { + String description = "*md* ``description``"; + 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(); + } +} diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/ShowAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/ShowAction.java index 20661d253e0..d05d9d1eaca 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/ShowAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/ShowAction.java @@ -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 index 7a5ba9b28a9..00000000000 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/RuleDescriptionFormatter.java +++ /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; - } - -} diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/hotspot/ws/ShowActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/hotspot/ws/ShowActionTest.java index 13ff6d1b162..dfc9a5cfaa5 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/hotspot/ws/ShowActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/hotspot/ws/ShowActionTest.java @@ -387,24 +387,20 @@ public class ShowActionTest { userSessionRule.logIn().addProjectPermission(UserRole.USER, project); ComponentDto file = dbTester.components().insertComponent(newFileDto(project)); - String description = "
line1\nline2
"; - String parsedDescription = "<div>line1
line2</div>"; - String resultingDescription = "!" + parsedDescription + "!"; + String description = "== Title\n
line1\nline2
"; 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("

Title

<div>line1
line2</div>"); } @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 index 2eb3bf82478..00000000000 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/RuleDescriptionFormatterTest.java +++ /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("md description"); - } - - @Test - public void getHtmlDescriptionAsIs() { - String description = "*md* ``description``"; - 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(); - } -} diff --git a/sonar-markdown/src/main/java/org/sonar/markdown/HtmlHeadingChannel.java b/sonar-markdown/src/main/java/org/sonar/markdown/HtmlHeadingChannel.java index 808e79e0300..fbd1dd71021 100644 --- a/sonar-markdown/src/main/java/org/sonar/markdown/HtmlHeadingChannel.java +++ b/sonar-markdown/src/main/java/org/sonar/markdown/HtmlHeadingChannel.java @@ -71,7 +71,7 @@ public class HtmlHeadingChannel extends RegexChannel { CharSequence headingText = token.subSequence(index, token.length()); output.append(""); - output.append(headingText); + output.append(headingText.toString().trim()); output.append(""); } } diff --git a/sonar-markdown/src/test/java/org/sonar/markdown/MarkdownTest.java b/sonar-markdown/src/test/java/org/sonar/markdown/MarkdownTest.java index 865c2281aeb..553aae54adf 100644 --- a/sonar-markdown/src/test/java/org/sonar/markdown/MarkdownTest.java +++ b/sonar-markdown/src/test/java/org/sonar/markdown/MarkdownTest.java @@ -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("

Top\r

Sub\r\n

Subsub\n

1.five"); + assertThat(Markdown.convertToHtml(" = Top\r== Sub\r\n=== Sub sub\n ==== \n 1.five")) + .isEqualTo("

Top

Sub

Sub sub

1.five"); } @Test