From: Léo Geoffroy Date: Fri, 1 Dec 2023 13:21:02 +0000 (+0100) Subject: SONAR-21131 Add response to new endpoint apiv2 rules X-Git-Tag: 10.4.0.87286~335 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=099027380f481f8f1a81ee19d58c9ce76d4b19e6;p=sonarqube.git SONAR-21131 Add response to new endpoint apiv2 rules --- diff --git a/server/sonar-webserver-common/src/main/java/org/sonar/server/common/rule/service/RuleInformation.java b/server/sonar-webserver-common/src/main/java/org/sonar/server/common/rule/service/RuleInformation.java new file mode 100644 index 00000000000..7f1707c4d95 --- /dev/null +++ b/server/sonar-webserver-common/src/main/java/org/sonar/server/common/rule/service/RuleInformation.java @@ -0,0 +1,27 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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.common.rule.service; + +import java.util.List; +import org.sonar.db.rule.RuleDto; +import org.sonar.db.rule.RuleParamDto; + +public record RuleInformation(RuleDto ruleDto, List params) { +} diff --git a/server/sonar-webserver-common/src/main/java/org/sonar/server/common/rule/service/RuleService.java b/server/sonar-webserver-common/src/main/java/org/sonar/server/common/rule/service/RuleService.java index f43f952782b..8ff3568f417 100644 --- a/server/sonar-webserver-common/src/main/java/org/sonar/server/common/rule/service/RuleService.java +++ b/server/sonar-webserver-common/src/main/java/org/sonar/server/common/rule/service/RuleService.java @@ -19,11 +19,9 @@ */ package org.sonar.server.common.rule.service; -import org.sonar.db.rule.RuleDto; - public class RuleService { - RuleDto create(CreateRuleRequest request) { + public RuleInformation create(CreateRuleRequest request) { return null; } diff --git a/server/sonar-webserver-common/src/main/java/org/sonar/server/common/text/Macro.java b/server/sonar-webserver-common/src/main/java/org/sonar/server/common/text/Macro.java new file mode 100644 index 00000000000..bcef7c858f3 --- /dev/null +++ b/server/sonar-webserver-common/src/main/java/org/sonar/server/common/text/Macro.java @@ -0,0 +1,27 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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.common.text; + +public interface Macro { + + String getRegex(); + + String getReplacement(); +} diff --git a/server/sonar-webserver-common/src/main/java/org/sonar/server/common/text/MacroInterpreter.java b/server/sonar-webserver-common/src/main/java/org/sonar/server/common/text/MacroInterpreter.java new file mode 100644 index 00000000000..512a3807822 --- /dev/null +++ b/server/sonar-webserver-common/src/main/java/org/sonar/server/common/text/MacroInterpreter.java @@ -0,0 +1,43 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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.common.text; + +import java.util.List; +import org.sonar.api.platform.Server; +import org.sonar.api.server.ServerSide; + +@ServerSide +public class MacroInterpreter { + private final List macros; + + public MacroInterpreter(Server server) { + this.macros = List.of( + new RuleMacro(server.getContextPath()) + ); + } + + public String interpret(String text) { + String textReplaced = text; + for (Macro macro : macros) { + textReplaced = textReplaced.replaceAll(macro.getRegex(), macro.getReplacement()); + } + return textReplaced; + } +} diff --git a/server/sonar-webserver-common/src/main/java/org/sonar/server/common/text/RuleMacro.java b/server/sonar-webserver-common/src/main/java/org/sonar/server/common/text/RuleMacro.java new file mode 100644 index 00000000000..3b156e65bab --- /dev/null +++ b/server/sonar-webserver-common/src/main/java/org/sonar/server/common/text/RuleMacro.java @@ -0,0 +1,43 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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.common.text; + +class RuleMacro implements Macro { + + private static final String COLON = "%3A"; + private final String contextPath; + + RuleMacro(String contextPath) { + this.contextPath = contextPath; + } + + /** + * First parameter is the repository, second one is the rule key. Exemple : {rule:java:ArchitecturalConstraint} + */ + @Override + public String getRegex() { + return "\\{rule:([a-zA-Z0-9._-]++):([a-zA-Z0-9._-]++)\\}"; + } + + @Override + public String getReplacement() { + return "$2"; + } +} diff --git a/server/sonar-webserver-common/src/main/java/org/sonar/server/common/text/package-info.java b/server/sonar-webserver-common/src/main/java/org/sonar/server/common/text/package-info.java new file mode 100644 index 00000000000..87a2ada2745 --- /dev/null +++ b/server/sonar-webserver-common/src/main/java/org/sonar/server/common/text/package-info.java @@ -0,0 +1,24 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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. + */ +@ParametersAreNonnullByDefault +package org.sonar.server.common.text; + +import javax.annotation.ParametersAreNonnullByDefault; + diff --git a/server/sonar-webserver-common/src/test/java/org/sonar/server/common/text/MacroInterpreterTest.java b/server/sonar-webserver-common/src/test/java/org/sonar/server/common/text/MacroInterpreterTest.java new file mode 100644 index 00000000000..c146a89045c --- /dev/null +++ b/server/sonar-webserver-common/src/test/java/org/sonar/server/common/text/MacroInterpreterTest.java @@ -0,0 +1,59 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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.common.text; + +import org.junit.Before; +import org.junit.Test; +import org.sonar.api.platform.Server; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class MacroInterpreterTest { + + String path = "http://sonar"; + MacroInterpreter interpreter; + + @Before + public void setUp() { + Server server = mock(Server.class); + when(server.getContextPath()).thenReturn(path); + interpreter = new MacroInterpreter(server); + } + + @Test + public void should_do_nothing_if_no_macro_detected() { + String origin = "nothing to do"; + String result = interpreter.interpret(origin); + assertThat(result).isEqualTo(origin); + } + + @Test + public void should_replace_rule_macro() { + // key of repository and rule can contain alphanumeric latin characters, dashes, underscores and dots + String ruleKey = "Some_Repo-Key.1:Some_Rule-Key.1"; + String origin = "See {rule:" + ruleKey + "} for detail."; + String result = interpreter.interpret(origin); + // colon should be escaped + assertThat(result).isEqualTo("See Some_Rule-Key.1 for detail."); + } + +} diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/controller/DefaultRuleController.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/controller/DefaultRuleController.java index a7a0f87d1d4..dae75304e64 100644 --- a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/controller/DefaultRuleController.java +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/controller/DefaultRuleController.java @@ -19,6 +19,7 @@ */ package org.sonar.server.v2.api.rule.controller; +import org.sonar.server.common.rule.service.RuleInformation; import org.sonar.server.common.rule.service.RuleService; import org.sonar.server.user.UserSession; import org.sonar.server.v2.api.rule.converter.RuleRestResponseGenerator; @@ -39,8 +40,9 @@ public class DefaultRuleController implements RuleController { @Override public RuleRestResponse create(RuleCreateRestRequest request) { - return null; - } + RuleInformation ruleInformation = ruleService.create(null); + return ruleRestResponseGenerator.toRuleRestResponse(ruleInformation); + } } 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 3392b26f0fb..f0dd41434c4 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 @@ -19,6 +19,188 @@ */ package org.sonar.server.v2.api.rule.converter; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Optional; +import java.util.Set; +import javax.annotation.CheckForNull; +import org.jetbrains.annotations.Nullable; +import org.sonar.api.resources.Language; +import org.sonar.api.resources.Languages; +import org.sonar.api.rules.CleanCodeAttribute; +import org.sonar.api.rules.RuleType; +import org.sonar.api.server.debt.DebtRemediationFunction; +import org.sonar.api.server.debt.internal.DefaultDebtRemediationFunction; +import org.sonar.api.utils.DateUtils; +import org.sonar.db.issue.ImpactDto; +import org.sonar.db.rule.RuleDescriptionSectionDto; +import org.sonar.db.rule.RuleDto; +import org.sonar.db.rule.RuleParamDto; +import org.sonar.markdown.Markdown; +import org.sonar.server.common.rule.service.RuleInformation; +import org.sonar.server.common.text.MacroInterpreter; +import org.sonar.server.rule.RuleDescriptionFormatter; +import org.sonar.server.v2.api.rule.enums.CleanCodeAttributeCategoryRestEnum; +import org.sonar.server.v2.api.rule.enums.CleanCodeAttributeRestEnum; +import org.sonar.server.v2.api.rule.enums.ImpactSeverityRestEnum; +import org.sonar.server.v2.api.rule.enums.RuleStatusRestEnum; +import org.sonar.server.v2.api.rule.enums.RuleTypeRestEnum; +import org.sonar.server.v2.api.rule.enums.SoftwareQualityRestEnum; +import org.sonar.server.v2.api.rule.response.RuleDescriptionSectionContextRestResponse; +import org.sonar.server.v2.api.rule.response.RuleDescriptionSectionRestResponse; +import org.sonar.server.v2.api.rule.response.RuleImpactRestResponse; +import org.sonar.server.v2.api.rule.response.RuleParameterRestResponse; +import org.sonar.server.v2.api.rule.response.RuleRestResponse; + +import static java.util.Optional.ofNullable; +import static org.sonar.db.rule.RuleDto.Format.MARKDOWN; + public class RuleRestResponseGenerator { + private final Languages languages; + private final MacroInterpreter macroInterpreter; + private final RuleDescriptionFormatter ruleDescriptionFormatter; + + public RuleRestResponseGenerator(Languages languages, MacroInterpreter macroInterpreter, RuleDescriptionFormatter ruleDescriptionFormatter) { + + this.languages = languages; + this.macroInterpreter = macroInterpreter; + this.ruleDescriptionFormatter = ruleDescriptionFormatter; + } + + public RuleRestResponse toRuleRestResponse(RuleInformation ruleInformation) { + + RuleRestResponse.Builder builder = RuleRestResponse.Builder.builder(); + RuleDto ruleDto = ruleInformation.ruleDto(); + builder + .setId(ruleDto.getUuid()) + .setKey(ruleDto.getKey().toString()) + .setRepositoryKey(ruleDto.getRepositoryKey()) + .setName(ruleDto.getName()) + .setSeverity(ruleDto.getSeverityString()) + .setType(RuleTypeRestEnum.from(RuleType.valueOf(ruleDto.getType()))) + .setImpacts(toImpactRestResponse(ruleDto.getDefaultImpacts())) + .setCleanCodeAttribute(CleanCodeAttributeRestEnum.from(ruleDto.getCleanCodeAttribute())) + .setCleanCodeAttributeCategory(ofNullable(ruleDto.getCleanCodeAttribute()) + .map(CleanCodeAttribute::getAttributeCategory) + .map(CleanCodeAttributeCategoryRestEnum::from) + .orElse(null)) + .setStatus(RuleStatusRestEnum.from(ruleDto.getStatus())) + .setExternal(ruleDto.isExternal()) + .setCreatedAt(toDateTime(ruleDto.getCreatedAt())) + .setGapDescription(ruleDto.getGapDescription()) + .setHtmlNote(ofNullable(ruleDto.getNoteData()).map(n -> macroInterpreter.interpret(Markdown.convertToHtml(n))).orElse(null)) + .setMarkdownNote(ruleDto.getNoteData()) + .setEducationPrinciples(new ArrayList<>(ruleDto.getEducationPrinciples())) + .setTemplate(ruleDto.isTemplate()) + .setTemplateId(ruleDto.getTemplateUuid()) + .setTags(new ArrayList<>(ruleDto.getTags())) + .setSystemTags(new ArrayList<>(ruleDto.getSystemTags())) + .setLanguageKey(ruleDto.getLanguage()) + .setLanguageName(getLanguageName(ruleDto.getLanguage())) + .setParameters(toRuleParameterResponse(ruleInformation.params())); + + setDescriptionFields(builder, ruleDto); + setRemediationFunctionFields(builder, ruleDto); + + if (ruleDto.isAdHoc()) { + ofNullable(ruleDto.getAdHocName()).ifPresent(builder::setName); + ofNullable(ruleDto.getAdHocDescription()) + .map(this::toDescriptionSectionResponse) + .ifPresent(section -> builder.setDescriptionSections(List.of(section))); + ofNullable(ruleDto.getAdHocSeverity()).ifPresent(builder::setSeverity); + ofNullable(ruleDto.getAdHocType()).ifPresent(type -> builder.setType(RuleTypeRestEnum.from(RuleType.valueOf(type)))); + } + return builder.build(); + } + + private static void setRemediationFunctionFields(RuleRestResponse.Builder builder, RuleDto ruleDto) { + ofNullable(debtRemediationFunction(ruleDto)) + .ifPresent(function -> { + builder.setRemediationFunctionBaseEffort(function.baseEffort()); + builder.setRemediationFunctionGapMultiplier(function.gapMultiplier()); + ofNullable(function.type()).map(Enum::name).ifPresent(builder::setRemediationFunctionType); + }); + } + + private static List toRuleParameterResponse(List ruleParamDtos) { + return ruleParamDtos.stream() + .map(p -> new RuleParameterRestResponse(p.getName(), Markdown.convertToHtml(p.getDescription()), p.getDefaultValue(), p.getType())) + .toList(); + } + + @CheckForNull + private String getLanguageName(@Nullable String languageKey) { + if (languageKey == null) { + return null; + } + Language language = languages.get(languageKey); + return language == null ? languageKey : language.getName(); + } + + private void setDescriptionFields(RuleRestResponse.Builder builder, RuleDto ruleDto) { + builder.setDescriptionSections(ruleDto.getRuleDescriptionSectionDtos().stream() + .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)); + } + } + + private RuleDescriptionSectionRestResponse toDescriptionSectionResponse(RuleDto ruleDto, RuleDescriptionSectionDto section) { + String htmlContent = ruleDescriptionFormatter.toHtml(ruleDto.getDescriptionFormat(), section); + String interpretedHtmlContent = macroInterpreter.interpret(htmlContent); + return new RuleDescriptionSectionRestResponse(section.getKey(), interpretedHtmlContent, + ofNullable(section.getContext()) + .map(c -> new RuleDescriptionSectionContextRestResponse(c.getKey(), c.getDisplayName())) + .orElse(null)); + } + + private RuleDescriptionSectionRestResponse toDescriptionSectionResponse(String description) { + return new RuleDescriptionSectionRestResponse(RuleDescriptionSectionDto.DEFAULT_KEY, macroInterpreter.interpret(description), null); + } + + private static List toImpactRestResponse(Set defaultImpacts) { + return defaultImpacts.stream() + .map(i -> new RuleImpactRestResponse(SoftwareQualityRestEnum.from(i.getSoftwareQuality()), ImpactSeverityRestEnum.from(i.getSeverity()))) + .toList(); + } + + @CheckForNull + private static DebtRemediationFunction defaultDebtRemediationFunction(final RuleDto ruleDto) { + final String function = ruleDto.getDefRemediationFunction(); + if (function == null || function.isEmpty()) { + return null; + } else { + return new DefaultDebtRemediationFunction( + DebtRemediationFunction.Type.valueOf(function.toUpperCase(Locale.ENGLISH)), + ruleDto.getDefRemediationGapMultiplier(), + ruleDto.getDefRemediationBaseEffort()); + } + } + + @CheckForNull + private static DebtRemediationFunction debtRemediationFunction(RuleDto ruleDto) { + final String function = ruleDto.getRemediationFunction(); + if (function == null || function.isEmpty()) { + return defaultDebtRemediationFunction(ruleDto); + } else { + return new DefaultDebtRemediationFunction( + DebtRemediationFunction.Type.valueOf(function.toUpperCase(Locale.ENGLISH)), + ruleDto.getRemediationGapMultiplier(), + ruleDto.getRemediationBaseEffort()); + } + } + + private static String toDateTime(@Nullable Long dateTimeMs) { + return Optional.ofNullable(dateTimeMs).map(DateUtils::formatDateTime).orElse(null); + } + } diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/enums/CleanCodeAttributeCategoryRestEnum.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/enums/CleanCodeAttributeCategoryRestEnum.java new file mode 100644 index 00000000000..bd07a53efb1 --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/enums/CleanCodeAttributeCategoryRestEnum.java @@ -0,0 +1,51 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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.v2.api.rule.enums; + +import java.util.Arrays; +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; +import org.sonar.api.rules.CleanCodeAttributeCategory; + +public enum CleanCodeAttributeCategoryRestEnum { + ADAPTABLE(CleanCodeAttributeCategory.ADAPTABLE), + CONSISTENT(CleanCodeAttributeCategory.CONSISTENT), + INTENTIONAL(CleanCodeAttributeCategory.INTENTIONAL), + RESPONSIBLE(CleanCodeAttributeCategory.RESPONSIBLE); + + private final CleanCodeAttributeCategory cleanCodeAttributeCategory; + + CleanCodeAttributeCategoryRestEnum(CleanCodeAttributeCategory cleanCodeAttributeCategory) { + this.cleanCodeAttributeCategory = cleanCodeAttributeCategory; + } + + @CheckForNull + public static CleanCodeAttributeCategoryRestEnum from(@Nullable CleanCodeAttributeCategory cleanCodeAttributeCategory) { + if (cleanCodeAttributeCategory == null) { + return null; + } + return Arrays.stream(CleanCodeAttributeCategoryRestEnum.values()) + .filter(cleanCodeAttributeCategoryRestEnum -> cleanCodeAttributeCategoryRestEnum.cleanCodeAttributeCategory.equals(cleanCodeAttributeCategory)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Unsupported clean code attribute category: " + cleanCodeAttributeCategory)); + } + + +} diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/enums/CleanCodeAttributeRestEnum.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/enums/CleanCodeAttributeRestEnum.java new file mode 100644 index 00000000000..6bfa406ec02 --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/enums/CleanCodeAttributeRestEnum.java @@ -0,0 +1,62 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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.v2.api.rule.enums; + +import java.util.Arrays; +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; +import org.sonar.api.rules.CleanCodeAttribute; + +public enum CleanCodeAttributeRestEnum { + CONVENTIONAL(CleanCodeAttribute.CONVENTIONAL), + FORMATTED(CleanCodeAttribute.FORMATTED), + IDENTIFIABLE(CleanCodeAttribute.IDENTIFIABLE), + + CLEAR(CleanCodeAttribute.CLEAR), + COMPLETE(CleanCodeAttribute.COMPLETE), + EFFICIENT(CleanCodeAttribute.EFFICIENT), + LOGICAL(CleanCodeAttribute.LOGICAL), + + DISTINCT(CleanCodeAttribute.DISTINCT), + FOCUSED(CleanCodeAttribute.FOCUSED), + MODULAR(CleanCodeAttribute.MODULAR), + TESTED(CleanCodeAttribute.TESTED), + + LAWFUL(CleanCodeAttribute.LAWFUL), + RESPECTFUL(CleanCodeAttribute.RESPECTFUL), + TRUSTWORTHY(CleanCodeAttribute.TRUSTWORTHY); + + private final CleanCodeAttribute cleanCodeAttribute; + + CleanCodeAttributeRestEnum(CleanCodeAttribute cleanCodeAttribute) { + this.cleanCodeAttribute = cleanCodeAttribute; + } + + @CheckForNull + public static CleanCodeAttributeRestEnum from(@Nullable CleanCodeAttribute cleanCodeAttribute) { + if (cleanCodeAttribute == null) { + return null; + } + return Arrays.stream(CleanCodeAttributeRestEnum.values()) + .filter(cleanCodeAttributeRestEnum -> cleanCodeAttributeRestEnum.cleanCodeAttribute.equals(cleanCodeAttribute)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Unsupported clean code attribute: " + cleanCodeAttribute)); + } +} diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/enums/ImpactSeverityRestEnum.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/enums/ImpactSeverityRestEnum.java new file mode 100644 index 00000000000..469797cd31c --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/enums/ImpactSeverityRestEnum.java @@ -0,0 +1,43 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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.v2.api.rule.enums; + +import java.util.Arrays; +import org.sonar.api.issue.impact.Severity; + +public enum ImpactSeverityRestEnum { + LOW(Severity.LOW), + MEDIUM(Severity.MEDIUM), + HIGH(Severity.HIGH); + + private final Severity severity; + + ImpactSeverityRestEnum(Severity severity) { + + this.severity = severity; + } + + public static ImpactSeverityRestEnum from(Severity severity) { + return Arrays.stream(ImpactSeverityRestEnum.values()) + .filter(severityRestResponse -> severityRestResponse.severity.equals(severity)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Unsupported impact severity: " + severity)); + } +} diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/enums/RuleStatusRestEnum.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/enums/RuleStatusRestEnum.java new file mode 100644 index 00000000000..071b6ad53d4 --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/enums/RuleStatusRestEnum.java @@ -0,0 +1,43 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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.v2.api.rule.enums; + +import java.util.Arrays; +import org.sonar.api.rule.RuleStatus; + +public enum RuleStatusRestEnum { + BETA(RuleStatus.BETA), + DEPRECATED(RuleStatus.DEPRECATED), + READY(RuleStatus.READY), + REMOVED(RuleStatus.REMOVED); + + private final RuleStatus ruleStatus; + + RuleStatusRestEnum(RuleStatus ruleStatus) { + this.ruleStatus = ruleStatus; + } + + public static RuleStatusRestEnum from(RuleStatus ruleStatus) { + return Arrays.stream(RuleStatusRestEnum.values()) + .filter(ruleStatusRestEnum -> ruleStatusRestEnum.ruleStatus.equals(ruleStatus)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Unsupported RuleStatus: " + ruleStatus)); + } +} diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/enums/RuleTypeRestEnum.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/enums/RuleTypeRestEnum.java new file mode 100644 index 00000000000..09b2179f018 --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/enums/RuleTypeRestEnum.java @@ -0,0 +1,44 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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.v2.api.rule.enums; + +import java.util.Arrays; +import org.sonar.api.rules.RuleType; + +public enum RuleTypeRestEnum { + CODE_SMELL(RuleType.CODE_SMELL), + BUG(RuleType.BUG), + VULNERABILITY(RuleType.VULNERABILITY), + SECURITY_HOTSPOT(RuleType.SECURITY_HOTSPOT), + ; + + private final RuleType ruleType; + + RuleTypeRestEnum(RuleType ruleType) { + this.ruleType = ruleType; + } + + public static RuleTypeRestEnum from(RuleType ruleType) { + return Arrays.stream(RuleTypeRestEnum.values()) + .filter(ruleTypeRestEnum -> ruleTypeRestEnum.ruleType.equals(ruleType)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Unsupported RuleType: " + ruleType)); + } +} diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/enums/SoftwareQualityRestEnum.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/enums/SoftwareQualityRestEnum.java new file mode 100644 index 00000000000..95ab51416dd --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/enums/SoftwareQualityRestEnum.java @@ -0,0 +1,44 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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.v2.api.rule.enums; + +import java.util.Arrays; +import org.sonar.api.issue.impact.SoftwareQuality; + +public enum SoftwareQualityRestEnum { + MAINTAINABILITY(SoftwareQuality.MAINTAINABILITY), + RELIABILITY(SoftwareQuality.RELIABILITY), + SECURITY(SoftwareQuality.SECURITY); + + + private final SoftwareQuality softwareQuality; + + SoftwareQualityRestEnum(SoftwareQuality softwareQuality) { + + this.softwareQuality = softwareQuality; + } + + public static SoftwareQualityRestEnum from(SoftwareQuality softwareQuality) { + return Arrays.stream(SoftwareQualityRestEnum.values()) + .filter(softwareQualityRest -> softwareQualityRest.softwareQuality.equals(softwareQuality)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Unsupported SoftwareQuality: " + softwareQuality)); + } +} diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/enums/package-info.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/enums/package-info.java new file mode 100644 index 00000000000..394f8f8d4a1 --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/enums/package-info.java @@ -0,0 +1,23 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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. + */ +@ParametersAreNonnullByDefault +package org.sonar.server.v2.api.rule.enums; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/response/RuleDescriptionSectionContextRestResponse.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/response/RuleDescriptionSectionContextRestResponse.java new file mode 100644 index 00000000000..03cf635fd03 --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/response/RuleDescriptionSectionContextRestResponse.java @@ -0,0 +1,31 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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.v2.api.rule.response; + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(accessMode = Schema.AccessMode.READ_ONLY) +public record RuleDescriptionSectionContextRestResponse( + String key, + String displayName + +) { + +} diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/response/RuleDescriptionSectionRestResponse.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/response/RuleDescriptionSectionRestResponse.java new file mode 100644 index 00000000000..f24646b0e62 --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/response/RuleDescriptionSectionRestResponse.java @@ -0,0 +1,35 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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.v2.api.rule.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import javax.annotation.Nullable; + +public record RuleDescriptionSectionRestResponse( + @Schema(accessMode = Schema.AccessMode.READ_ONLY) + String key, + @Schema(accessMode = Schema.AccessMode.READ_ONLY) + String content, + @Nullable + @Schema(accessMode = Schema.AccessMode.READ_ONLY) + RuleDescriptionSectionContextRestResponse context + +) { +} diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/response/RuleImpactRestResponse.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/response/RuleImpactRestResponse.java new file mode 100644 index 00000000000..a0efcf716b8 --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/response/RuleImpactRestResponse.java @@ -0,0 +1,31 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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.v2.api.rule.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import org.sonar.server.v2.api.rule.enums.ImpactSeverityRestEnum; +import org.sonar.server.v2.api.rule.enums.SoftwareQualityRestEnum; + +@Schema(accessMode = Schema.AccessMode.READ_ONLY) +public record RuleImpactRestResponse( + SoftwareQualityRestEnum softwareQuality, + ImpactSeverityRestEnum severity +) { +} diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/response/RuleParameterRestResponse.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/response/RuleParameterRestResponse.java new file mode 100644 index 00000000000..418a67fa025 --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/response/RuleParameterRestResponse.java @@ -0,0 +1,41 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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.v2.api.rule.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import javax.annotation.Nullable; + +public record RuleParameterRestResponse( + + String key, + @Schema(accessMode = Schema.AccessMode.READ_ONLY) + String htmlDescription, + @Nullable + String defaultValue, + @Schema(allowableValues = { + "STRING", + "TEXT", + "BOOLEAN", + "INTEGER", + "FLOAT" + }, accessMode = Schema.AccessMode.READ_ONLY) + String type +) { +} diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/response/RuleRestResponse.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/response/RuleRestResponse.java index 3b1d9f744bc..d9da2d2d3d7 100644 --- a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/response/RuleRestResponse.java +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/rule/response/RuleRestResponse.java @@ -19,5 +19,242 @@ */ package org.sonar.server.v2.api.rule.response; -public record RuleRestResponse() { +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.List; +import javax.annotation.Nullable; +import org.sonar.server.v2.api.rule.enums.CleanCodeAttributeCategoryRestEnum; +import org.sonar.server.v2.api.rule.enums.CleanCodeAttributeRestEnum; +import org.sonar.server.v2.api.rule.enums.RuleStatusRestEnum; +import org.sonar.server.v2.api.rule.enums.RuleTypeRestEnum; + +@Schema(accessMode = Schema.AccessMode.READ_ONLY) +public record RuleRestResponse( + String id, + String key, + String repositoryKey, + String name, + @Nullable + String severity, + RuleTypeRestEnum type, + List impacts, + @Nullable + CleanCodeAttributeRestEnum cleanCodeAttribute, + @Nullable + CleanCodeAttributeCategoryRestEnum cleanCodeAttributeCategory, + @Nullable + RuleStatusRestEnum status, + boolean external, + @Nullable + String createdAt, + List descriptionSections, + @Schema(accessMode = Schema.AccessMode.READ_WRITE) + String markdownDescription, + @Nullable + String gapDescription, + @Nullable + String htmlNote, + @Nullable + String markdownNote, + List educationPrinciples, + boolean template, + @Nullable + String templateId, + @Schema(accessMode = Schema.AccessMode.READ_WRITE) + List tags, + List systemTags, + @Nullable + String languageKey, + @Nullable + String languageName, + List parameters, + String remediationFunctionType, + String remediationFunctionGapMultiplier, + String remediationFunctionBaseEffort +) { + + + public static final class Builder { + private String id; + private String key; + private String repositoryKey; + private String name; + private String severity; + private RuleTypeRestEnum type; + private List impacts; + private CleanCodeAttributeRestEnum cleanCodeAttribute; + private CleanCodeAttributeCategoryRestEnum cleanCodeAttributeCategory; + private RuleStatusRestEnum status; + private boolean external; + private String createdAt; + private List descriptionSections; + private String markdownDescription; + private String gapDescription; + private String htmlNote; + private String markdownNote; + private List educationPrinciples; + private boolean template; + private String templateId; + private List tags; + private List systemTags; + private String languageKey; + private String languageName; + private List parameters; + private String remediationFunctionType; + private String remediationFunctionGapMultiplier; + private String remediationFunctionBaseEffort; + + private Builder() { + } + + public static Builder builder() { + return new Builder(); + } + + public Builder setId(String id) { + this.id = id; + return this; + } + + public Builder setKey(String key) { + this.key = key; + return this; + } + + public Builder setRepositoryKey(String repositoryKey) { + this.repositoryKey = repositoryKey; + return this; + } + + public Builder setName(String name) { + this.name = name; + return this; + } + + public Builder setSeverity(@Nullable String severity) { + this.severity = severity; + return this; + } + + public Builder setType(RuleTypeRestEnum type) { + this.type = type; + return this; + } + + public Builder setImpacts(List impacts) { + this.impacts = impacts; + return this; + } + + public Builder setCleanCodeAttribute(@Nullable CleanCodeAttributeRestEnum cleanCodeAttribute) { + this.cleanCodeAttribute = cleanCodeAttribute; + return this; + } + + public Builder setCleanCodeAttributeCategory(@Nullable CleanCodeAttributeCategoryRestEnum cleanCodeAttributeCategory) { + this.cleanCodeAttributeCategory = cleanCodeAttributeCategory; + return this; + } + + public Builder setStatus(RuleStatusRestEnum status) { + this.status = status; + return this; + } + + public Builder setExternal(boolean external) { + this.external = external; + return this; + } + + public Builder setCreatedAt(@Nullable String createdAt) { + this.createdAt = createdAt; + return this; + } + + public Builder setDescriptionSections(List descriptionSections) { + this.descriptionSections = descriptionSections; + return this; + } + + public Builder setMarkdownDescription(String markdownDescription) { + this.markdownDescription = markdownDescription; + return this; + } + + public Builder setGapDescription(@Nullable String gapDescription) { + this.gapDescription = gapDescription; + return this; + } + + public Builder setHtmlNote(@Nullable String htmlNote) { + this.htmlNote = htmlNote; + return this; + } + + public Builder setMarkdownNote(@Nullable String markdownNote) { + this.markdownNote = markdownNote; + return this; + } + + public Builder setEducationPrinciples(List educationPrinciples) { + this.educationPrinciples = educationPrinciples; + return this; + } + + public Builder setTemplate(boolean template) { + this.template = template; + return this; + } + + public Builder setTemplateId(@Nullable String templateId) { + this.templateId = templateId; + return this; + } + + public Builder setTags(List tags) { + this.tags = tags; + return this; + } + + public Builder setSystemTags(List systemTags) { + this.systemTags = systemTags; + return this; + } + + public Builder setLanguageKey(@Nullable String languageKey) { + this.languageKey = languageKey; + return this; + } + + public Builder setLanguageName(@Nullable String languageName) { + this.languageName = languageName; + return this; + } + + public Builder setParameters(List parameters) { + this.parameters = parameters; + return this; + } + + public Builder setRemediationFunctionType(@Nullable String remediationFunctionType) { + this.remediationFunctionType = remediationFunctionType; + return this; + } + + public Builder setRemediationFunctionGapMultiplier(@Nullable String remediationFunctionGapMultiplier) { + this.remediationFunctionGapMultiplier = remediationFunctionGapMultiplier; + return this; + } + + public Builder setRemediationFunctionBaseEffort(@Nullable String remediationFunctionBaseEffort) { + this.remediationFunctionBaseEffort = remediationFunctionBaseEffort; + return this; + } + + public RuleRestResponse build() { + return new RuleRestResponse(id, key, repositoryKey, name, severity, type, impacts, cleanCodeAttribute, cleanCodeAttributeCategory, + status, external, createdAt, descriptionSections, markdownDescription, gapDescription, htmlNote, markdownNote, + educationPrinciples, template, templateId, tags, systemTags, languageKey, languageName, parameters, remediationFunctionType, + remediationFunctionGapMultiplier, remediationFunctionBaseEffort); + } + } } diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/config/PlatformLevel4WebConfig.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/config/PlatformLevel4WebConfig.java index f00c78388ae..0cb87b69044 100644 --- a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/config/PlatformLevel4WebConfig.java +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/config/PlatformLevel4WebConfig.java @@ -20,6 +20,7 @@ package org.sonar.server.v2.config; import javax.annotation.Nullable; +import org.sonar.api.resources.Languages; import org.sonar.db.DbClient; import org.sonar.server.common.group.service.GroupMembershipService; import org.sonar.server.common.group.service.GroupService; @@ -31,9 +32,11 @@ import org.sonar.server.common.management.ManagedInstanceChecker; import org.sonar.server.common.platform.LivenessChecker; import org.sonar.server.common.platform.LivenessCheckerImpl; import org.sonar.server.common.rule.service.RuleService; +import org.sonar.server.common.text.MacroInterpreter; import org.sonar.server.common.user.service.UserService; import org.sonar.server.health.HealthChecker; import org.sonar.server.platform.NodeInformation; +import org.sonar.server.rule.RuleDescriptionFormatter; import org.sonar.server.user.SystemPasscode; import org.sonar.server.user.UserSession; import org.sonar.server.v2.api.group.controller.DefaultGroupController; @@ -100,8 +103,8 @@ public class PlatformLevel4WebConfig { } @Bean - public RuleRestResponseGenerator ruleRestResponseGenerator() { - return new RuleRestResponseGenerator(); + public RuleRestResponseGenerator ruleRestResponseGenerator(Languages languages, MacroInterpreter macroInterpreter, RuleDescriptionFormatter ruleDescriptionFormatter) { + return new RuleRestResponseGenerator(languages, macroInterpreter, ruleDescriptionFormatter); } @Bean diff --git a/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/api/rule/controller/DefaultRuleControllerTest.java b/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/api/rule/controller/DefaultRuleControllerTest.java index 652a540fa22..83b40df12fa 100644 --- a/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/api/rule/controller/DefaultRuleControllerTest.java +++ b/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/api/rule/controller/DefaultRuleControllerTest.java @@ -27,12 +27,16 @@ import org.sonar.server.common.rule.service.RuleService; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.v2.api.ControllerTester; import org.sonar.server.v2.api.rule.converter.RuleRestResponseGenerator; +import org.sonar.server.v2.api.rule.response.RuleRestResponse; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import static org.sonar.server.v2.WebApiEndpoints.RULES_ENDPOINT; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @RunWith(MockitoJUnitRunner.class) @@ -43,8 +47,9 @@ public class DefaultRuleControllerTest { private final RuleService ruleService = mock(); + private final RuleRestResponseGenerator ruleRestResponseGenerator = mock(); private final MockMvc mockMvc = ControllerTester - .getMockMvc(new DefaultRuleController(userSession, ruleService, new RuleRestResponseGenerator())); + .getMockMvc(new DefaultRuleController(userSession, ruleService, ruleRestResponseGenerator)); @Test @@ -53,4 +58,14 @@ public class DefaultRuleControllerTest { .andExpectAll( status().isOk()); } + + @Test + public void create_shouldReturnExpectedBody() throws Exception { + when(ruleRestResponseGenerator.toRuleRestResponse(any())).thenReturn(RuleRestResponse.Builder.builder().setId("id").build()); + + mockMvc.perform(post(RULES_ENDPOINT).contentType(MediaType.APPLICATION_JSON_VALUE).content("{}")) + .andExpectAll( + status().isOk(), + content().json("{id: 'id'}")); + } } diff --git a/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/api/rule/converter/RuleRestResponseGeneratorTest.java b/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/api/rule/converter/RuleRestResponseGeneratorTest.java new file mode 100644 index 00000000000..1e5d10d5ecc --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/api/rule/converter/RuleRestResponseGeneratorTest.java @@ -0,0 +1,167 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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.v2.api.rule.converter; + +import java.util.List; +import java.util.Locale; +import org.assertj.core.groups.Tuple; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; +import org.sonar.api.resources.Languages; +import org.sonar.api.rule.RuleStatus; +import org.sonar.api.rule.Severity; +import org.sonar.api.rules.RuleType; +import org.sonar.api.server.debt.DebtRemediationFunction; +import org.sonar.api.server.debt.internal.DefaultDebtRemediationFunction; +import org.sonar.api.utils.DateUtils; +import org.sonar.db.rule.RuleDescriptionSectionDto; +import org.sonar.db.rule.RuleDto; +import org.sonar.db.rule.RuleParamDto; +import org.sonar.db.rule.RuleTesting; +import org.sonar.server.common.rule.service.RuleInformation; +import org.sonar.server.common.text.MacroInterpreter; +import org.sonar.server.language.LanguageTesting; +import org.sonar.server.rule.RuleDescriptionFormatter; +import org.sonar.server.v2.api.rule.response.RuleRestResponse; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class RuleRestResponseGeneratorTest { + @Mock + private Languages languages; + + @Mock + private MacroInterpreter macroInterpreter; + + @Mock + RuleDescriptionFormatter ruleDescriptionFormatter; + + @InjectMocks + private RuleRestResponseGenerator ruleRestResponseGenerator; + + + @Test + public void toRuleRestResponse_shouldReturnSameFieldForStandardMapping() { + when(macroInterpreter.interpret(Mockito.anyString())).thenAnswer(invocation -> "interpreted" + invocation.getArgument(0)); + when(ruleDescriptionFormatter.toHtml(any(), any())).thenAnswer(invocation -> "html" + ((RuleDescriptionSectionDto) invocation.getArgument(1)).getContent()); + + RuleDto dto = RuleTesting.newRule(); + when(languages.get(dto.getLanguage())).thenReturn(LanguageTesting.newLanguage(dto.getLanguage(), "languageName")); + + RuleRestResponse ruleRestResponse = ruleRestResponseGenerator.toRuleRestResponse(new RuleInformation(dto, List.of())); + assertThat(ruleRestResponse.id()).isEqualTo(dto.getUuid()); + assertThat(ruleRestResponse.key()).isEqualTo(dto.getKey().toString()); + assertThat(ruleRestResponse.repositoryKey()).isEqualTo(dto.getRepositoryKey()); + assertThat(ruleRestResponse.name()).isEqualTo(dto.getName()); + assertThat(ruleRestResponse.descriptionSections()).extracting(s -> s.key(), s -> s.content(), s -> s.context()) + .containsExactly(dto.getRuleDescriptionSectionDtos().stream().map(s -> tuple(s.getKey(), "interpreted" + "html" + s.getContent(), s.getContext())).toArray(Tuple[]::new)); + assertThat(ruleRestResponse.severity()).isEqualTo(dto.getSeverityString()); + assertThat(ruleRestResponse.type().name()).isEqualTo(RuleType.valueOf(dto.getType()).name()); + assertThat(ruleRestResponse.impacts()).extracting(r -> r.severity().name(), r -> r.softwareQuality().name()) + .containsExactly(dto.getDefaultImpacts().stream().map(e -> tuple(e.getSeverity().name(), e.getSoftwareQuality().name())).toArray(Tuple[]::new)); + assertThat(ruleRestResponse.cleanCodeAttribute().name()).isEqualTo(dto.getCleanCodeAttribute().name()); + assertThat(ruleRestResponse.cleanCodeAttributeCategory().name()).isEqualTo(dto.getCleanCodeAttribute().getAttributeCategory().name()); + assertThat(ruleRestResponse.status().name()).isEqualTo(dto.getStatus().name()); + assertThat(ruleRestResponse.external()).isEqualTo(dto.isExternal()); + assertThat(ruleRestResponse.createdAt()).isEqualTo(DateUtils.formatDateTime(dto.getCreatedAt())); + assertThat(ruleRestResponse.gapDescription()).isEqualTo(dto.getGapDescription()); + assertThat(ruleRestResponse.markdownNote()).isEqualTo(dto.getNoteData()); + assertThat(ruleRestResponse.educationPrinciples()).containsExactlyElementsOf(dto.getEducationPrinciples()); + assertThat(ruleRestResponse.template()).isEqualTo(dto.isTemplate()); + assertThat(ruleRestResponse.templateId()).isEqualTo(dto.getTemplateUuid()); + assertThat(ruleRestResponse.tags()).containsExactlyElementsOf(dto.getTags()); + assertThat(ruleRestResponse.systemTags()).containsExactlyElementsOf(dto.getSystemTags()); + assertThat(ruleRestResponse.languageKey()).isEqualTo(dto.getLanguage()); + assertThat(ruleRestResponse.languageName()).isEqualTo("languageName"); + + DefaultDebtRemediationFunction function = new DefaultDebtRemediationFunction(DebtRemediationFunction.Type.valueOf(dto.getRemediationFunction().toUpperCase(Locale.ENGLISH)), + dto.getRemediationGapMultiplier(), + dto.getRemediationBaseEffort()); + assertThat(ruleRestResponse.remediationFunctionBaseEffort()).isEqualTo(function.baseEffort()); + assertThat(ruleRestResponse.remediationFunctionGapMultiplier()).isEqualTo(function.gapMultiplier()); + assertThat(ruleRestResponse.remediationFunctionType()).isEqualTo(dto.getRemediationFunction()); + } + + @Test + public void toRuleRestResponse_shouldReturnNullFields_whenRuleIsEmpty() { + RuleDto dto = new RuleDto().setRuleKey("key").setRepositoryKey("repoKey").setStatus(RuleStatus.READY).setType(RuleType.BUG.getDbConstant()); + RuleRestResponse ruleRestResponse = ruleRestResponseGenerator.toRuleRestResponse(new RuleInformation(dto, List.of())); + assertThat(ruleRestResponse.cleanCodeAttribute()).isNull(); + assertThat(ruleRestResponse.cleanCodeAttributeCategory()).isNull(); + assertThat(ruleRestResponse.htmlNote()).isNull(); + } + + @Test + public void toRuleRestResponse_shouldReturnParameters_whenParametersAreProvided() { + RuleDto dto = RuleTesting.newRule(); + RuleParamDto ruleParamDto1 = RuleTesting.newRuleParam(dto); + RuleParamDto ruleParamDto2 = RuleTesting.newRuleParam(dto); + RuleRestResponse ruleRestResponse = ruleRestResponseGenerator.toRuleRestResponse(new RuleInformation(dto, List.of(ruleParamDto1, ruleParamDto2))); + + assertThat(ruleRestResponse.parameters()).extracting(p -> p.key(), p -> p.htmlDescription(), p -> p.defaultValue()) + .containsExactlyInAnyOrder(tuple(ruleParamDto1.getName(), ruleParamDto1.getDescription(), ruleParamDto1.getDefaultValue()), + tuple(ruleParamDto2.getName(), ruleParamDto2.getDescription(), ruleParamDto2.getDefaultValue())); + } + + @Test + public void toRuleRestResponse_shouldReturnAdhocInformation_whenRuleIsAdhoc() { + when(macroInterpreter.interpret(Mockito.anyString())).thenAnswer(invocation -> "interpreted" + invocation.getArgument(0)); + RuleDto dto = RuleTesting.newRule(); + dto.setIsAdHoc(true); + dto.setAdHocName("adhocName"); + dto.setAdHocDescription("adhocDescription"); + dto.setAdHocSeverity(Severity.INFO); + dto.setAdHocType(RuleType.BUG.getDbConstant()); + + RuleRestResponse ruleRestResponse = ruleRestResponseGenerator.toRuleRestResponse(new RuleInformation(dto, List.of())); + assertThat(ruleRestResponse.name()).isEqualTo(dto.getAdHocName()); + assertThat(ruleRestResponse.descriptionSections()).extracting(r -> r.key(), r -> r.content(), r -> r.context()) + .containsExactly(tuple("default", "interpreted" + dto.getAdHocDescription(), null)); + assertThat(ruleRestResponse.severity()).isEqualTo(dto.getAdHocSeverity()); + assertThat(ruleRestResponse.type().name()).isEqualTo(RuleType.valueOf(dto.getAdHocType()).name()); + } + + @Test + public void toRuleRestResponse_shouldReturnRemediationFunctions() { + when(macroInterpreter.interpret(Mockito.anyString())).thenAnswer(invocation -> "interpreted" + invocation.getArgument(0)); + RuleDto dto = RuleTesting.newRule(); + dto.setIsAdHoc(true); + dto.setAdHocName("adhocName"); + dto.setAdHocDescription("adhocDescription"); + dto.setAdHocSeverity(Severity.INFO); + dto.setAdHocType(RuleType.BUG.getDbConstant()); + + RuleRestResponse ruleRestResponse = ruleRestResponseGenerator.toRuleRestResponse(new RuleInformation(dto, List.of())); + assertThat(ruleRestResponse.name()).isEqualTo(dto.getAdHocName()); + assertThat(ruleRestResponse.descriptionSections()).extracting(r -> r.key(), r -> r.content(), r -> r.context()) + .containsExactly(tuple("default", "interpreted" + dto.getAdHocDescription(), null)); + assertThat(ruleRestResponse.severity()).isEqualTo(dto.getAdHocSeverity()); + assertThat(ruleRestResponse.type().name()).isEqualTo(RuleType.valueOf(dto.getAdHocType()).name()); + } + +} 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 273a96fc718..0b0df3218f6 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 @@ -31,6 +31,7 @@ import org.sonar.core.util.SequenceUuidFactory; import org.sonar.core.util.UuidFactory; import org.sonar.db.DbTester; import org.sonar.db.rule.RuleDto; +import org.sonar.server.common.text.MacroInterpreter; import org.sonar.server.es.EsTester; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.UnauthorizedException; @@ -38,7 +39,6 @@ import org.sonar.server.rule.RuleCreator; import org.sonar.server.rule.RuleDescriptionFormatter; import org.sonar.server.rule.index.RuleIndexer; import org.sonar.server.tester.UserSessionRule; -import org.sonar.server.text.MacroInterpreter; import org.sonar.server.ws.TestRequest; import org.sonar.server.ws.TestResponse; import org.sonar.server.ws.WsActionTester; diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/ListActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/ListActionIT.java index 814c5072c7f..57b2e71e64c 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/ListActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/ListActionIT.java @@ -33,11 +33,11 @@ import org.sonar.db.DbTester; import org.sonar.db.qualityprofile.QProfileDto; import org.sonar.db.rule.RuleDto; import org.sonar.db.rule.RuleTesting; +import org.sonar.server.common.text.MacroInterpreter; import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.language.LanguageTesting; import org.sonar.server.rule.RuleDescriptionFormatter; import org.sonar.server.tester.UserSessionRule; -import org.sonar.server.text.MacroInterpreter; import org.sonar.server.ws.TestRequest; import org.sonar.server.ws.WsActionTester; import org.sonarqube.ws.Rules; 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 fe0bdae89e6..e7bda7cdc8c 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 @@ -60,6 +60,7 @@ import org.sonar.db.rule.RuleDescriptionSectionDto; import org.sonar.db.rule.RuleDto; import org.sonar.db.rule.RuleParamDto; import org.sonar.db.user.UserDto; +import org.sonar.server.common.text.MacroInterpreter; import org.sonar.server.es.EsTester; import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.language.LanguageTesting; @@ -74,7 +75,6 @@ import org.sonar.server.rule.RuleDescriptionFormatter; import org.sonar.server.rule.index.RuleIndex; import org.sonar.server.rule.index.RuleIndexer; import org.sonar.server.tester.UserSessionRule; -import org.sonar.server.text.MacroInterpreter; import org.sonar.server.util.IntegerTypeValidation; import org.sonar.server.util.StringTypeValidation; import org.sonar.server.util.TypeValidations; 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 1d9720f6fb3..47d6bf61ddf 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 @@ -40,9 +40,9 @@ import org.sonar.db.rule.RuleDescriptionSectionDto; import org.sonar.db.rule.RuleDto; import org.sonar.db.rule.RuleParamDto; import org.sonar.db.user.UserDto; +import org.sonar.server.common.text.MacroInterpreter; import org.sonar.server.rule.RuleDescriptionFormatter; import org.sonar.server.tester.UserSessionRule; -import org.sonar.server.text.MacroInterpreter; import org.sonar.server.ws.WsActionTester; import org.sonarqube.ws.Common; import org.sonarqube.ws.Rules; 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 21385ba831c..72d2e7ad1d3 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 @@ -32,6 +32,7 @@ import org.sonar.db.DbTester; import org.sonar.db.rule.RuleDescriptionSectionDto; import org.sonar.db.rule.RuleDto; import org.sonar.db.user.UserDto; +import org.sonar.server.common.text.MacroInterpreter; import org.sonar.server.es.EsClient; import org.sonar.server.es.EsTester; import org.sonar.server.exceptions.ForbiddenException; @@ -40,7 +41,6 @@ import org.sonar.server.rule.RuleDescriptionFormatter; import org.sonar.server.rule.RuleUpdater; import org.sonar.server.rule.index.RuleIndexer; import org.sonar.server.tester.UserSessionRule; -import org.sonar.server.text.MacroInterpreter; import org.sonar.server.ws.TestResponse; import org.sonar.server.ws.WsAction; import org.sonar.server.ws.WsActionTester; 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 833e375c637..7ac89ed0bac 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 @@ -44,9 +44,9 @@ import org.sonar.db.rule.RuleDto.Scope; import org.sonar.db.rule.RuleParamDto; import org.sonar.db.user.UserDto; import org.sonar.markdown.Markdown; +import org.sonar.server.common.text.MacroInterpreter; import org.sonar.server.rule.RuleDescriptionFormatter; import org.sonar.server.rule.ws.RulesResponseFormatter.SearchResult; -import org.sonar.server.text.MacroInterpreter; import org.sonarqube.ws.Common; import org.sonarqube.ws.Common.RuleScope; import org.sonarqube.ws.Rules; diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/text/Macro.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/text/Macro.java deleted file mode 100644 index 4b81c5db214..00000000000 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/text/Macro.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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.text; - -public interface Macro { - - String getRegex(); - - String getReplacement(); -} diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/text/MacroInterpreter.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/text/MacroInterpreter.java deleted file mode 100644 index f45f94cc655..00000000000 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/text/MacroInterpreter.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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.text; - -import org.sonar.api.server.ServerSide; -import org.sonar.api.platform.Server; - -import java.util.List; - -@ServerSide -public class MacroInterpreter { - private final List macros; - - public MacroInterpreter(Server server) { - this.macros = List.of( - new RuleMacro(server.getContextPath()) - ); - } - - public String interpret(String text) { - String textReplaced = text; - for (Macro macro : macros) { - textReplaced = textReplaced.replaceAll(macro.getRegex(), macro.getReplacement()); - } - return textReplaced; - } -} diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/text/RuleMacro.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/text/RuleMacro.java deleted file mode 100644 index c0d5e344f59..00000000000 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/text/RuleMacro.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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.text; - -class RuleMacro implements Macro { - - private static final String COLON = "%3A"; - private final String contextPath; - - RuleMacro(String contextPath) { - this.contextPath = contextPath; - } - - /** - * First parameter is the repository, second one is the rule key. Exemple : {rule:java:ArchitecturalConstraint} - */ - @Override - public String getRegex() { - return "\\{rule:([a-zA-Z0-9._-]++):([a-zA-Z0-9._-]++)\\}"; - } - - @Override - public String getReplacement() { - return "$2"; - } -} diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/text/package-info.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/text/package-info.java deleted file mode 100644 index 6c434dbd28b..00000000000 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/text/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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. - */ -@ParametersAreNonnullByDefault -package org.sonar.server.text; - -import javax.annotation.ParametersAreNonnullByDefault; - diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/text/MacroInterpreterTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/text/MacroInterpreterTest.java deleted file mode 100644 index d264562ea89..00000000000 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/text/MacroInterpreterTest.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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.text; - -import org.junit.Before; -import org.junit.Test; -import org.sonar.api.platform.Server; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class MacroInterpreterTest { - - String path = "http://sonar"; - MacroInterpreter interpreter; - - @Before - public void setUp() { - Server server = mock(Server.class); - when(server.getContextPath()).thenReturn(path); - interpreter = new MacroInterpreter(server); - } - - @Test - public void should_do_nothing_if_no_macro_detected() { - String origin = "nothing to do"; - String result = interpreter.interpret(origin); - assertThat(result).isEqualTo(origin); - } - - @Test - public void should_replace_rule_macro() { - // key of repository and rule can contain alphanumeric latin characters, dashes, underscores and dots - String ruleKey = "Some_Repo-Key.1:Some_Rule-Key.1"; - String origin = "See {rule:" + ruleKey + "} for detail."; - String result = interpreter.interpret(origin); - // colon should be escaped - assertThat(result).isEqualTo("See Some_Rule-Key.1 for detail."); - } - -} diff --git a/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java b/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java index 5429d9857ff..cafa2315c3a 100644 --- a/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java +++ b/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java @@ -81,6 +81,7 @@ import org.sonar.server.ce.ws.CeWsModule; import org.sonar.server.common.group.service.GroupMembershipService; import org.sonar.server.common.group.service.GroupService; import org.sonar.server.common.rule.service.RuleService; +import org.sonar.server.common.text.MacroInterpreter; import org.sonar.server.component.ComponentCleanerService; import org.sonar.server.component.ComponentFinder; import org.sonar.server.component.ComponentService; @@ -249,7 +250,6 @@ import org.sonar.server.telemetry.TelemetryClient; import org.sonar.server.telemetry.TelemetryDaemon; import org.sonar.server.telemetry.TelemetryDataJsonWriter; import org.sonar.server.telemetry.TelemetryDataLoaderImpl; -import org.sonar.server.text.MacroInterpreter; import org.sonar.server.ui.PageRepository; import org.sonar.server.ui.WebAnalyticsLoaderImpl; import org.sonar.server.ui.ws.NavigationWsModule;