From 65e6d0fcea6605c0967adea83fef6ec6afcb5d41 Mon Sep 17 00:00:00 2001 From: Julien HENRY Date: Thu, 12 Dec 2024 17:21:22 +0100 Subject: SONAR-18646 Drop htmlDesc from api/rules/show and api/rules/search --- .../rule/converter/RuleRestResponseGenerator.java | 3 -- .../org/sonar/server/rule/ws/CreateActionIT.java | 3 -- .../org/sonar/server/rule/ws/SearchActionIT.java | 1 - .../org/sonar/server/rule/ws/ShowActionIT.java | 62 +++++++++------------- .../org/sonar/server/rule/ws/UpdateActionIT.java | 40 +++++++------- .../java/org/sonar/server/rule/ws/RuleMapper.java | 25 --------- .../sonar/server/rule/ws/RulesWsParameters.java | 5 ++ .../org/sonar/server/rule/ws/SearchAction.java | 3 +- .../java/org/sonar/server/rule/ws/ShowAction.java | 3 +- sonar-ws/src/main/protobuf/ws-rules.proto | 1 - 10 files changed, 54 insertions(+), 92 deletions(-) diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/converter/RuleRestResponseGenerator.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/converter/RuleRestResponseGenerator.java index 8c6765ba9fe..fcd5138c48a 100644 --- a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/converter/RuleRestResponseGenerator.java +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/converter/RuleRestResponseGenerator.java @@ -144,13 +144,10 @@ public class RuleRestResponseGenerator { .map(sectionDto -> toDescriptionSectionResponse(ruleDto, sectionDto)) .toList()); - String htmlDescription = ruleDescriptionFormatter.getDescriptionAsHtml(ruleDto); if (MARKDOWN.equals(ruleDto.getDescriptionFormat())) { Optional.ofNullable(ruleDto.getDefaultRuleDescriptionSection()) .map(RuleDescriptionSectionDto::getContent) .ifPresent(builder::setMarkdownDescription); - } else if (htmlDescription != null) { - builder.setMarkdownDescription(macroInterpreter.interpret(htmlDescription)); } } diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/CreateActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/CreateActionIT.java index ebb4b714130..897136c0b45 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/CreateActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/CreateActionIT.java @@ -115,7 +115,6 @@ public class CreateActionIT { "key": "java:MY_CUSTOM", "repo": "java", "name": "My custom rule", - "htmlDesc": "Description", "severity": "MAJOR", "status": "BETA", "type": "BUG", @@ -175,7 +174,6 @@ public class CreateActionIT { "key": "java:MY_CUSTOM", "repo": "java", "name": "My custom rule", - "htmlDesc": "Description", "severity": "INFO", "status": "BETA", "type": "VULNERABILITY", @@ -231,7 +229,6 @@ public class CreateActionIT { " \"key\": \"java:MY_CUSTOM\",\n" + " \"repo\": \"java\",\n" + " \"name\": \"My custom rule\",\n" + - " \"htmlDesc\": \"Description\",\n" + " \"severity\": \"MAJOR\",\n" + " \"status\": \"REMOVED\",\n" + " \"isTemplate\": false\n" + diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/SearchActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/SearchActionIT.java index 216f77cfcf8..b7b3255c820 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/SearchActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/SearchActionIT.java @@ -378,7 +378,6 @@ class SearchActionIT { // not returned fields assertThat(result.hasGapDescription()).isFalse(); - assertThat(result.hasHtmlDesc()).isFalse(); assertThat(result.hasIsTemplate()).isFalse(); assertThat(result.hasLang()).isFalse(); assertThat(result.hasName()).isFalse(); diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/ShowActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/ShowActionIT.java index 6573293956b..7ef03042fd2 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/ShowActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/ShowActionIT.java @@ -329,9 +329,13 @@ class ShowActionIT { .setParam("key", customRule.getKey().toString()) .executeProtobuf(ShowResponse.class); - assertThat(result.getRule().getHtmlDesc()).isEqualTo(INTERPRETED); + assertThat(result.getRule().getMdDesc()).isEqualTo("
line1\nline2
"); assertThat(result.getRule().getTemplateKey()).isEqualTo(templateRule.getKey().toString()); - verify(macroInterpreter, times(2)).interpret("<div>line1
line2</div>"); + verify(macroInterpreter, times(1)).interpret("<div>line1
line2</div>"); + + assertThat(result.getRule().getDescriptionSections().getDescriptionSectionsList()) + .extracting(Rule.DescriptionSection::getKey, Rule.DescriptionSection::getContent) + .containsExactly(tuple(DEFAULT_KEY, INTERPRETED)); } @Test @@ -370,8 +374,8 @@ class ShowActionIT { Rule resultRule = result.getRule(); assertThat(resultRule) - .extracting(Rule::getName, Rule::getHtmlDesc, Rule::getSeverity, Rule::getType) - .containsExactlyInAnyOrder("adhoc name", "<div>desc2</div>", Severity.BLOCKER, VULNERABILITY); + .extracting(Rule::getName, Rule::getSeverity, Rule::getType) + .containsExactlyInAnyOrder("adhoc name", Severity.BLOCKER, VULNERABILITY); assertThat(resultRule.getDescriptionSections().getDescriptionSectionsList()) .extracting(Rule.DescriptionSection::getKey, Rule.DescriptionSection::getContent) @@ -398,8 +402,6 @@ class ShowActionIT { .executeProtobuf(ShowResponse.class); Rule resultRule = result.getRule(); - assertThat(resultRule.getHtmlDesc()).isEmpty(); - assertThat(resultRule.getMdDesc()).isEqualTo(resultRule.getHtmlDesc()); assertThat(resultRule.getDescriptionSections().getDescriptionSectionsList()) .extracting(Rule.DescriptionSection::getKey, Rule.DescriptionSection::getContent, section -> section.getContext().getKey(), section -> section.getContext().getDisplayName()) @@ -424,7 +426,6 @@ class ShowActionIT { .executeProtobuf(ShowResponse.class); Rule resultRule = result.getRule(); - assertThat(resultRule.getHtmlDesc()).isEqualTo(INTERPRETED); assertThat(resultRule.getDescriptionSections().getDescriptionSectionsList()) .extracting(Rule.DescriptionSection::getKey, Rule.DescriptionSection::getContent) .containsExactly(tuple(DEFAULT_KEY, INTERPRETED)); @@ -444,38 +445,11 @@ class ShowActionIT { .executeProtobuf(ShowResponse.class); Rule resultRule = result.getRule(); - assertThat(resultRule.getHtmlDesc()).isEqualTo(INTERPRETED); assertThat(resultRule.getDescriptionSections().getDescriptionSectionsList()) .extracting(Rule.DescriptionSection::getKey, Rule.DescriptionSection::getContent) .containsExactly(tuple(DEFAULT_KEY, INTERPRETED)); } - @Test - void show_if_advanced_sections_and_default_filters_out_default() { - when(macroInterpreter.interpret(anyString())).thenAnswer(invocation -> invocation.getArgument(0)); - - RuleDescriptionSectionDto section1 = createRuleDescriptionSection(ROOT_CAUSE_SECTION_KEY, "
Root is Root
"); - RuleDescriptionSectionDto defaultSection = createDefaultRuleDescriptionSection(uuidFactory.create(), "This is the default section"); - - RuleDto rule = createRuleWithDescriptionSections(section1, defaultSection); - rule.setType(RuleType.SECURITY_HOTSPOT); - rule.setNoteUserUuid(userDto.getUuid()); - db.rules().insert(rule); - - ShowResponse result = ws.newRequest() - .setParam(PARAM_KEY, rule.getKey().toString()) - .executeProtobuf(ShowResponse.class); - - Rule resultRule = result.getRule(); - assertThat(resultRule.getHtmlDesc()).contains(defaultSection.getContent()); - - assertThat(resultRule.getMdDesc()).isEqualTo(resultRule.getHtmlDesc()); - - assertThat(resultRule.getDescriptionSections().getDescriptionSectionsList()) - .extracting(Rule.DescriptionSection::getKey, Rule.DescriptionSection::getContent) - .containsExactlyInAnyOrder(tuple(ROOT_CAUSE_SECTION_KEY, "
Root is Root
")); - } - @Test void show_rule_markdown_description() { when(macroInterpreter.interpret(anyString())).thenAnswer(invocation -> invocation.getArgument(0)); @@ -493,7 +467,7 @@ class ShowActionIT { Rule resultRule = result.getRule(); - assertThat(resultRule.getHtmlDesc()).contains("toto is toto"); + assertThat(getDefaultSection(resultRule)).contains("toto is toto"); assertThat(resultRule.getMdDesc()).contains("*toto is toto*"); assertThat(resultRule.getDescriptionSections().getDescriptionSectionsList()) @@ -501,6 +475,14 @@ class ShowActionIT { .contains(tuple(DEFAULT_KEY, "toto is toto")); } + private static String getDefaultSection(Rule rule) { + return rule.getDescriptionSections().getDescriptionSectionsList().stream() + .filter(s -> "default".equals(s.getKey())) + .findFirst() + .map(Rule.DescriptionSection::getContent) + .orElse(null); + } + @Test void ignore_predefined_info_on_adhoc_rule() { RuleDto externalRule = newRule(createDefaultRuleDescriptionSection(uuidFactory.create(), "
predefined desc
")) @@ -524,7 +506,7 @@ class ShowActionIT { Rule resultRule = result.getRule(); assertThat(resultRule) - .extracting(Rule::getName, Rule::getHtmlDesc, Rule::getSeverity, Rule::getType) + .extracting(Rule::getName, ShowActionIT::getDefaultSection, Rule::getSeverity, Rule::getType) .containsExactlyInAnyOrder("adhoc name", "<div>adhoc desc</div>", Severity.MAJOR, Common.RuleType.CODE_SMELL); } @@ -550,8 +532,12 @@ class ShowActionIT { Rule resultRule = result.getRule(); assertThat(resultRule) - .extracting(Rule::hasName, Rule::hasHtmlDesc, Rule::hasSeverity, Rule::getType) - .containsExactlyInAnyOrder(false, false, false, UNKNOWN); + .extracting(Rule::hasName, ShowActionIT::getDescriptionSectionsCount, Rule::hasSeverity, Rule::getType) + .containsExactlyInAnyOrder(false, 1, false, UNKNOWN); + } + + private static int getDescriptionSectionsCount(Rule r) { + return r.getDescriptionSections().getDescriptionSectionsCount(); } @Test diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/UpdateActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/UpdateActionIT.java index 5c4197ddb81..144ed783e62 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/UpdateActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/UpdateActionIT.java @@ -139,25 +139,27 @@ class UpdateActionIT { .setParam("params", "regex=a.*") .execute(); - assertJson(request.getInput()).isSimilarTo("{\n" + - " \"rule\": {\n" + - " \"key\": \"java:MY_CUSTOM\",\n" + - " \"repo\": \"java\",\n" + - " \"name\": \"My custom rule\",\n" + - " \"htmlDesc\": \"Description\",\n" + - " \"severity\": \"MAJOR\",\n" + - " \"status\": \"BETA\",\n" + - " \"isTemplate\": false,\n" + - " \"templateKey\": \"java:S001\",\n" + - " \"params\": [\n" + - " {\n" + - " \"key\": \"regex\",\n" + - " \"htmlDesc\": \"Reg ex\",\n" + - " \"defaultValue\": \"a.*\"\n" + - " }\n" + - " ]\n" + - " }\n" + - "}\n"); + assertJson(request.getInput()).isSimilarTo(""" + { + "rule": { + "key": "java:MY_CUSTOM", + "repo": "java", + "name": "My custom rule", + "mdDesc": "Description", + "severity": "MAJOR", + "status": "BETA", + "isTemplate": false, + "templateKey": "java:S001", + "params": [ + { + "key": "regex", + "htmlDesc": "Reg ex", + "defaultValue": "a.*" + } + ] + } + } + """); } @Test diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RuleMapper.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RuleMapper.java index a90216e1b55..7c615d3bef9 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RuleMapper.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RuleMapper.java @@ -63,7 +63,6 @@ import static org.sonar.server.rule.ws.RulesWsParameters.FIELD_DEPRECATED_KEYS; import static org.sonar.server.rule.ws.RulesWsParameters.FIELD_DESCRIPTION_SECTIONS; import static org.sonar.server.rule.ws.RulesWsParameters.FIELD_EDUCATION_PRINCIPLES; import static org.sonar.server.rule.ws.RulesWsParameters.FIELD_GAP_DESCRIPTION; -import static org.sonar.server.rule.ws.RulesWsParameters.FIELD_HTML_DESCRIPTION; import static org.sonar.server.rule.ws.RulesWsParameters.FIELD_INTERNAL_KEY; import static org.sonar.server.rule.ws.RulesWsParameters.FIELD_IS_EXTERNAL; import static org.sonar.server.rule.ws.RulesWsParameters.FIELD_IS_TEMPLATE; @@ -179,10 +178,6 @@ public class RuleMapper { private void setAdHocDescription(Rules.Rule.Builder ruleResponse, RuleDto ruleDto, Set fieldsToReturn) { String adHocDescription = ruleDto.getAdHocDescription(); - if (adHocDescription != null && shouldReturnField(fieldsToReturn, FIELD_HTML_DESCRIPTION)) { - ruleResponse.setHtmlDesc(macroInterpreter.interpret(adHocDescription)); - } - if (shouldReturnField(fieldsToReturn, FIELD_DESCRIPTION_SECTIONS) && adHocDescription != null) { ruleResponse.clearDescriptionSections(); ruleResponse.getDescriptionSectionsBuilder().addDescriptionSectionsBuilder() @@ -361,17 +356,9 @@ public class RuleMapper { } private void setDescriptionFields(Rules.Rule.Builder ruleResponse, RuleDto ruleDto, Set fieldsToReturn) { - if (shouldReturnField(fieldsToReturn, FIELD_HTML_DESCRIPTION)) { - String htmlDescription = ruleDescriptionFormatter.getDescriptionAsHtml(ruleDto); - if (htmlDescription != null) { - ruleResponse.setHtmlDesc(macroInterpreter.interpret(htmlDescription)); - } - } - if (shouldReturnField(fieldsToReturn, FIELD_DESCRIPTION_SECTIONS)) { Set ruleDescriptionSectionDtos = ruleDto.getRuleDescriptionSectionDtos(); Set sections = ruleDescriptionSectionDtos.stream() - .filter(sectionDto -> !isDefaultAndMoreThanOneSectionPresent(ruleDescriptionSectionDtos, sectionDto)) .map(sectionDto -> toDescriptionSection(ruleDto, sectionDto)) .collect(Collectors.toSet()); ruleResponse.setDescriptionSections(Rules.Rule.DescriptionSections.newBuilder().addAllDescriptionSections(sections).build()); @@ -382,22 +369,10 @@ public class RuleMapper { Optional.ofNullable(ruleDto.getDefaultRuleDescriptionSection()) .map(RuleDescriptionSectionDto::getContent) .ifPresent(ruleResponse::setMdDesc); - } else { - ruleResponse.setMdDesc(ruleResponse.getHtmlDesc()); } } } - /** - * This was done to preserve backward compatibility with SonarLint until they stop using htmlDesc field in api/rules/[show|search] endpoints, see SONAR-16635 - * - * @deprecated the method should be removed once SonarLint supports rules.descriptionSections fields, I.E in 10.x and DB is cleaned up of non-necessary default sections. - */ - @Deprecated(since = "9.6", forRemoval = true) - private static boolean isDefaultAndMoreThanOneSectionPresent(Set ruleDescriptionSectionDtos, RuleDescriptionSectionDto s) { - return ruleDescriptionSectionDtos.size() > 1 && s.isDefault(); - } - private Rules.Rule.DescriptionSection toDescriptionSection(RuleDto ruleDto, RuleDescriptionSectionDto section) { String htmlContent = ruleDescriptionFormatter.toHtml(ruleDto.getDescriptionFormat(), section); String interpretedHtmlContent = macroInterpreter.interpret(htmlContent); diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RulesWsParameters.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RulesWsParameters.java index 85f468ba652..5b169210967 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RulesWsParameters.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RulesWsParameters.java @@ -68,6 +68,11 @@ public class RulesWsParameters { public static final String FIELD_SYSTEM_TAGS = "sysTags"; public static final String FIELD_LANGUAGE = "lang"; public static final String FIELD_LANGUAGE_NAME = "langName"; + /** + * For backward compatibility with SonarLint we still accept this field in the request, but we won't return it + * @deprecated since 2025.1 + */ + @Deprecated(since = "2025.1") public static final String FIELD_HTML_DESCRIPTION = "htmlDesc"; public static final String FIELD_MARKDOWN_DESCRIPTION = "mdDesc"; diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/SearchAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/SearchAction.java index e3fdcd222e0..b3c7e27d53e 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/SearchAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/SearchAction.java @@ -198,7 +198,8 @@ public class SearchAction implements RulesWsAction { new Change("10.8", "The values 'severity' and 'types' for the 'facets' parameter are not deprecated anymore."), new Change("10.8", "The fields 'type' and 'severity' in the response are not deprecated anymore."), new Change("10.8", "The value 'severity' for the 'f' parameter is not deprecated anymore."), - new Change("2025.2", format("The facet '%s' has been added.", FACET_ACTIVE_IMPACT_SEVERITY))); + new Change("2025.1", format("The facet '%s' has been added.", FACET_ACTIVE_IMPACT_SEVERITY)), + new Change("2025.1", "The deprecated field 'htmlDesc' is not returned anymore, even if specified in the 'f' parameter.")); action.createParam(FACETS) .setDescription("Comma-separated list of the facets to be computed. No facet is computed by default.") diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/ShowAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/ShowAction.java index 41e5be91c2f..990d322ce9e 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/ShowAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/ShowAction.java @@ -88,7 +88,8 @@ public class ShowAction implements RulesWsAction { new Change("10.2", "Add 'impacts', 'cleanCodeAttribute', 'cleanCodeAttributeCategory' fields to the response"), new Change("10.2", "The field 'severity' and 'type' in the response have been deprecated, use 'impacts' instead."), new Change("10.8", format("Possible values '%s' and '%s' for response field 'severity' of 'impacts' have been added.", INFO.name(), BLOCKER.name())), - new Change("10.8", "The field 'severity' and 'type' in the response are not deprecated anymore.")); + new Change("10.8", "The field 'severity' and 'type' in the response are not deprecated anymore."), + new Change("2025.1", "The deprecated field 'htmlDesc' is not returned anymore, even if specified in the 'f' parameter.")); action .createParam(PARAM_KEY) diff --git a/sonar-ws/src/main/protobuf/ws-rules.proto b/sonar-ws/src/main/protobuf/ws-rules.proto index d0e62066763..49373f0deeb 100644 --- a/sonar-ws/src/main/protobuf/ws-rules.proto +++ b/sonar-ws/src/main/protobuf/ws-rules.proto @@ -73,7 +73,6 @@ message Rule { optional string repo = 2; optional string name = 3; optional string createdAt = 4; - optional string htmlDesc = 5 [deprecated = true]; optional string htmlNote = 6; optional string mdDesc = 7; optional string mdNote = 8; -- cgit v1.2.3