diff options
author | Pierre Guillot <pierre.guillot@sonarsource.com> | 2024-12-10 15:29:09 +0100 |
---|---|---|
committer | Steve Marion <steve.marion@sonarsource.com> | 2024-12-18 11:13:21 +0100 |
commit | d639a965bce7acafb004906cd07a8f0b5f7af993 (patch) | |
tree | 647cd646abddb12dfeeef7e637aa33b4658f1049 /server/sonar-webserver-webapi-v2 | |
parent | 451c1c2e4856ec3df87f86189fcdb25b31794027 (diff) | |
download | sonarqube-d639a965bce7acafb004906cd07a8f0b5f7af993.tar.gz sonarqube-d639a965bce7acafb004906cd07a8f0b5f7af993.zip |
SONAR-22998 fetch active rules with a dedicated endpoint
Co-authored-by: Julien HENRY <julien.henry@sonarsource.com>
Diffstat (limited to 'server/sonar-webserver-webapi-v2')
8 files changed, 358 insertions, 0 deletions
diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/WebApiEndpoints.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/WebApiEndpoints.java index d77f2fda48a..1d053c5049f 100644 --- a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/WebApiEndpoints.java +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/WebApiEndpoints.java @@ -51,6 +51,7 @@ public class WebApiEndpoints { public static final String ANALYSIS_DOMAIN = "/analysis"; public static final String VERSION_ENDPOINT = ANALYSIS_DOMAIN + "/version"; public static final String JRE_ENDPOINT = ANALYSIS_DOMAIN + "/jres"; + public static final String ACTIVE_RULES_ENDPOINT = ANALYSIS_DOMAIN + "/active_rules"; public static final String SCANNER_ENGINE_ENDPOINT = ANALYSIS_DOMAIN + "/engine"; private WebApiEndpoints() { diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/analysis/controller/ActiveRulesController.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/analysis/controller/ActiveRulesController.java new file mode 100644 index 00000000000..905420589a3 --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/analysis/controller/ActiveRulesController.java @@ -0,0 +1,47 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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.analysis.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import java.util.List; +import org.sonar.server.rule.ActiveRuleRestReponse; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +import static org.sonar.server.v2.WebApiEndpoints.ACTIVE_RULES_ENDPOINT; +import static org.springframework.http.HttpStatus.OK; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + +@RequestMapping(value = ACTIVE_RULES_ENDPOINT, produces = APPLICATION_JSON_VALUE) +@ResponseStatus(OK) +@RestController +public interface ActiveRulesController { + + String PROJECT_KEY_PARAM_DESCRIPTION = "Project Key"; + + @GetMapping + @Operation(summary = "Get all active rules for a specific project", description = "Used by the scanner-engine to get all active rules for a given project.") + List<ActiveRuleRestReponse.ActiveRule> getActiveRules(@RequestParam(value = "projectKey") @Parameter(description = PROJECT_KEY_PARAM_DESCRIPTION) String projectKey); + +} diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/analysis/controller/DefaultActiveRulesController.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/analysis/controller/DefaultActiveRulesController.java new file mode 100644 index 00000000000..9a51bd5972b --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/analysis/controller/DefaultActiveRulesController.java @@ -0,0 +1,38 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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.analysis.controller; + +import java.util.List; +import org.sonar.server.rule.ActiveRuleRestReponse; +import org.sonar.server.v2.api.analysis.service.ActiveRulesHandler; + +public class DefaultActiveRulesController implements ActiveRulesController { + + private final ActiveRulesHandler activeRulesHandler; + + public DefaultActiveRulesController(ActiveRulesHandler activeRulesHandler) { + this.activeRulesHandler = activeRulesHandler; + } + + @Override + public List<ActiveRuleRestReponse.ActiveRule> getActiveRules(String projectKey) { + return activeRulesHandler.getActiveRules(projectKey); + } +} diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/analysis/service/ActiveRulesHandler.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/analysis/service/ActiveRulesHandler.java new file mode 100644 index 00000000000..d14a66a6d7a --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/analysis/service/ActiveRulesHandler.java @@ -0,0 +1,27 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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.analysis.service; + +import java.util.List; +import org.sonar.server.rule.ActiveRuleRestReponse; + +public interface ActiveRulesHandler { + List<ActiveRuleRestReponse.ActiveRule> getActiveRules(String projectKey); +} diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/analysis/service/ActiveRulesHandlerImpl.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/analysis/service/ActiveRulesHandlerImpl.java new file mode 100644 index 00000000000..8b4562bc4f9 --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/analysis/service/ActiveRulesHandlerImpl.java @@ -0,0 +1,47 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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.analysis.service; + +import java.util.List; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.server.rule.ActiveRuleRestReponse; +import org.sonar.server.rule.ActiveRuleService; + +public class ActiveRulesHandlerImpl implements ActiveRulesHandler { + + private final DbClient dbClient; + private final ActiveRuleService activeRuleService; + + public ActiveRulesHandlerImpl(DbClient dbClient, ActiveRuleService activeRuleService) { + this.dbClient = dbClient; + this.activeRuleService = activeRuleService; + } + + @Override + public List<ActiveRuleRestReponse.ActiveRule> getActiveRules(String projectKey) { + try (DbSession dbSession = dbClient.openSession(false)) { + return dbClient.projectDao().selectProjectByKey(dbSession, projectKey) + .map(projectDto -> activeRuleService.buildActiveRules(projectDto.getUuid())) + .orElse(activeRuleService.buildDefaultActiveRules()); + } + } + +} 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 20880ad7420..2ae1170b7af 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 @@ -48,16 +48,21 @@ import org.sonar.server.platform.ServerFileSystem; import org.sonar.server.platform.db.migration.DatabaseMigrationState; import org.sonar.server.platform.db.migration.version.DatabaseVersion; import org.sonar.server.qualitygate.QualityGateConditionsValidator; +import org.sonar.server.rule.ActiveRuleService; import org.sonar.server.rule.RuleDescriptionFormatter; import org.sonar.server.setting.SettingsChangeNotifier; import org.sonar.server.user.SystemPasscode; import org.sonar.server.user.UserSession; +import org.sonar.server.v2.api.analysis.controller.ActiveRulesController; +import org.sonar.server.v2.api.analysis.controller.DefaultActiveRulesController; import org.sonar.server.v2.api.analysis.controller.DefaultJresController; import org.sonar.server.v2.api.analysis.controller.DefaultScannerEngineController; import org.sonar.server.v2.api.analysis.controller.DefaultVersionController; import org.sonar.server.v2.api.analysis.controller.JresController; import org.sonar.server.v2.api.analysis.controller.ScannerEngineController; import org.sonar.server.v2.api.analysis.controller.VersionController; +import org.sonar.server.v2.api.analysis.service.ActiveRulesHandler; +import org.sonar.server.v2.api.analysis.service.ActiveRulesHandlerImpl; import org.sonar.server.v2.api.analysis.service.JresHandler; import org.sonar.server.v2.api.analysis.service.JresHandlerImpl; import org.sonar.server.v2.api.analysis.service.ScannerEngineHandler; @@ -227,4 +232,19 @@ public class PlatformLevel4WebConfig { return new DefaultModeController(userSession, dbClient, configuration, settingsChangeNotifier, notificationManager, qualityGateConditionsValidator); } + @Bean + public ActiveRuleService activeRuleService(DbClient dbClient, Languages languages) { + return new ActiveRuleService(dbClient, languages); + } + + @Bean + public ActiveRulesHandler activeRulesHandler(DbClient dbClient, ActiveRuleService activeRuleService) { + return new ActiveRulesHandlerImpl(dbClient, activeRuleService); + } + + @Bean + public ActiveRulesController activeRulesController(ActiveRulesHandler activeRulesHandler) { + return new DefaultActiveRulesController(activeRulesHandler); + } + } diff --git a/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/api/analysis/controller/DefaultActiveRulesControllerTest.java b/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/api/analysis/controller/DefaultActiveRulesControllerTest.java new file mode 100644 index 00000000000..c35ecfda28a --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/api/analysis/controller/DefaultActiveRulesControllerTest.java @@ -0,0 +1,107 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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.analysis.controller; + +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.Test; +import org.sonar.api.issue.impact.Severity; +import org.sonar.api.issue.impact.SoftwareQuality; +import org.sonar.server.rule.ActiveRuleRestReponse; +import org.sonar.server.v2.api.analysis.service.ActiveRulesHandler; +import org.springframework.test.web.servlet.MockMvc; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.sonar.server.v2.WebApiEndpoints.ACTIVE_RULES_ENDPOINT; +import static org.sonar.server.v2.api.ControllerTester.getMockMvc; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +class DefaultActiveRulesControllerTest { + + private final ActiveRulesHandler handler = mock(ActiveRulesHandler.class); + + private final MockMvc mockMvc = getMockMvc(new DefaultActiveRulesController(handler)); + + @Test + void getActiveRules_shouldReturnActiveRulesAsJson() throws Exception { + var minimalAr = new ActiveRuleRestReponse.ActiveRule( + new ActiveRuleRestReponse.RuleKey("xoo", "rule1"), + "Rule 1", + "MAJOR", + "2024-12-09", + "2024-12-09", + null, + "java", + null, + "qProfileKey", + List.of(), + List.of(), + Map.of()); + var maximalAr = new ActiveRuleRestReponse.ActiveRule( + new ActiveRuleRestReponse.RuleKey("xoo", "rule1"), + "Rule 1", + "MAJOR", + "2024-12-09", + "2024-12-09", + "someInternalKey", + "java", + "templateKey", + "qProfileKey", + List.of(new ActiveRuleRestReponse.RuleKey("old", "rule")), + List.of(new ActiveRuleRestReponse.Param("key", "value")), + Map.of(SoftwareQuality.MAINTAINABILITY, Severity.HIGH)); + when(handler.getActiveRules("someKey")).thenReturn(List.of(minimalAr, maximalAr)); + + String expectedJson = """ + [ + { + "ruleKey":{"repository":"xoo","rule":"rule1"}, + "name":"Rule 1", + "severity":"MAJOR", + "createdAt":"2024-12-09", + "updatedAt":"2024-12-09", + "language":"java", + "qProfileKey":"qProfileKey" + }, + { + "ruleKey":{"repository":"xoo","rule":"rule1"}, + "name":"Rule 1","severity":"MAJOR", + "createdAt":"2024-12-09", + "updatedAt":"2024-12-09", + "internalKey":"someInternalKey", + "language":"java", + "templateRuleKey":"templateKey", + "qProfileKey":"qProfileKey", + "deprecatedKeys":[{"repository":"old","rule":"rule"}], + "params":[{"key":"key","value":"value"}], + "impacts":{"MAINTAINABILITY":"HIGH"}} + ] + """; + + mockMvc.perform(get(ACTIVE_RULES_ENDPOINT + "?projectKey=someKey")) + .andExpectAll( + status().isOk(), + content().json(expectedJson, true)); + } + +} diff --git a/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/api/analysis/service/ActiveRulesHandlerImplTest.java b/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/api/analysis/service/ActiveRulesHandlerImplTest.java new file mode 100644 index 00000000000..26c8983195a --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/api/analysis/service/ActiveRulesHandlerImplTest.java @@ -0,0 +1,71 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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.analysis.service; + +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.project.ProjectDto; +import org.sonar.server.rule.ActiveRuleRestReponse; +import org.sonar.server.rule.ActiveRuleService; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.RETURNS_DEEP_STUBS; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class ActiveRulesHandlerImplTest { + + private final DbClient dbClient = mock(DbClient.class, RETURNS_DEEP_STUBS); + private final DbSession dbSession = mock(); + private final ActiveRuleService activeRuleService = mock(ActiveRuleService.class); + + @BeforeEach + void setup() { + when(dbClient.openSession(false)).thenReturn(dbSession); + } + + ActiveRulesHandlerImpl underTest = new ActiveRulesHandlerImpl(dbClient, activeRuleService); + + @Test + void getActiveRules_returns_default_quality_profile_for_unknown_project() { + var defaultActiveRule1 = mock(ActiveRuleRestReponse.ActiveRule.class); + when(activeRuleService.buildDefaultActiveRules()).thenReturn(List.of(defaultActiveRule1)); + + List<ActiveRuleRestReponse.ActiveRule> result = underTest.getActiveRules("unknown-project"); + + assertThat(result).containsExactly(defaultActiveRule1); + } + + @Test + void getActiveRules_returns_associated_quality_profile_for_known_project() { + when(dbClient.projectDao().selectProjectByKey(dbSession, "my-project")).thenReturn(Optional.of(new ProjectDto().setUuid("someProjectUuid"))); + var activeRule1 = mock(ActiveRuleRestReponse.ActiveRule.class); + when(activeRuleService.buildActiveRules("someProjectUuid")).thenReturn(List.of(activeRule1)); + + List<ActiveRuleRestReponse.ActiveRule> result = underTest.getActiveRules("my-project"); + + assertThat(result).containsExactly(activeRule1); + } + +} |