diff options
author | Anita Stanisz <106669481+anita-stanisz-sonarsource@users.noreply.github.com> | 2024-11-27 16:13:20 +0100 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2024-11-29 20:03:07 +0000 |
commit | 8f0a4b81ff51e1332032a1661c0495b933479ec2 (patch) | |
tree | f33276424cc11674472832decf792222bfe4f5e1 /server/sonar-webserver-webapi | |
parent | c2f6540d095189ada11bd529114acd3cad2efe9b (diff) | |
download | sonarqube-8f0a4b81ff51e1332032a1661c0495b933479ec2.tar.gz sonarqube-8f0a4b81ff51e1332032a1661c0495b933479ec2.zip |
SONAR-23619 Add new action to list and show QG endpoints (#12391)
Diffstat (limited to 'server/sonar-webserver-webapi')
14 files changed, 308 insertions, 147 deletions
diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/ai/code/assurance/AiCodeAssuranceEntitlementTest.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/ai/code/assurance/AiCodeAssuranceEntitlementTest.java new file mode 100644 index 00000000000..4cfd615c538 --- /dev/null +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/ai/code/assurance/AiCodeAssuranceEntitlementTest.java @@ -0,0 +1,54 @@ +/* + * 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.ai.code.assurance; + +import java.util.Optional; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.sonar.core.platform.EditionProvider; +import org.sonar.core.platform.PlatformEditionProvider; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class AiCodeAssuranceEntitlementTest { + private final PlatformEditionProvider platformEditionProvider = mock(PlatformEditionProvider.class); + + @ParameterizedTest + @MethodSource("isEnabledParams") + void isEnabled(EditionProvider.Edition edition, boolean expected) { + when(platformEditionProvider.get()).thenReturn(Optional.of(edition)); + AiCodeAssuranceEntitlement underTest = new AiCodeAssuranceEntitlement(platformEditionProvider); + + assertThat(underTest.isEnabled()).isEqualTo(expected); + } + + private static Stream<Arguments> isEnabledParams() { + return Stream.of( + Arguments.of(EditionProvider.Edition.COMMUNITY, false), + Arguments.of(EditionProvider.Edition.DEVELOPER, true), + Arguments.of(EditionProvider.Edition.ENTERPRISE, true), + Arguments.of(EditionProvider.Edition.DATACENTER, true) + ); + } +} diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/ai/code/assurance/AiCodeAssuranceVerifierTest.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/ai/code/assurance/AiCodeAssuranceVerifierTest.java index 0714c002662..1812f18f7e0 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/ai/code/assurance/AiCodeAssuranceVerifierTest.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/ai/code/assurance/AiCodeAssuranceVerifierTest.java @@ -19,14 +19,12 @@ */ package org.sonar.server.ai.code.assurance; -import java.util.Optional; import java.util.stream.Stream; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.sonar.core.platform.EditionProvider.Edition; -import org.sonar.core.platform.PlatformEditionProvider; import org.sonar.db.DbClient; import org.sonar.db.project.ProjectDto; import org.sonar.db.qualitygate.QualityGateDao; @@ -39,7 +37,7 @@ import static org.mockito.Mockito.when; class AiCodeAssuranceVerifierTest { private final ProjectDto projectDto = mock(ProjectDto.class); - private final PlatformEditionProvider platformEditionProvider = mock(PlatformEditionProvider.class); + private final AiCodeAssuranceEntitlement aiCodeAssuranceEntitlement = mock(AiCodeAssuranceEntitlement.class); private final DbClient dbClient = mock(DbClient.class); private final QualityGateDao qualityGateDao = mock(QualityGateDao.class); private AiCodeAssuranceVerifier underTest; @@ -47,8 +45,8 @@ class AiCodeAssuranceVerifierTest { @ParameterizedTest @MethodSource("isAiCodeAssuredForProject") void isAiCodeAssuredForProject(boolean containsAiCode, boolean aiCodeSupportedQg, boolean expected) { - when(platformEditionProvider.get()).thenReturn(Optional.of(Edition.DEVELOPER)); - underTest = new AiCodeAssuranceVerifier(platformEditionProvider, dbClient); + when(aiCodeAssuranceEntitlement.isEnabled()).thenReturn(true); + underTest = new AiCodeAssuranceVerifier(aiCodeAssuranceEntitlement, dbClient); mockProjectAndQualityGate(containsAiCode, aiCodeSupportedQg); when(projectDto.getContainsAiCode()).thenReturn(containsAiCode); @@ -58,9 +56,9 @@ class AiCodeAssuranceVerifierTest { @ParameterizedTest @MethodSource("paramsForGetAiCodeAssurance") - void getAiCodeAssurance(Edition edition, boolean containsAiCode, boolean aiCodeSupportedQg, AiCodeAssurance expected) { - when(platformEditionProvider.get()).thenReturn(Optional.of(edition)); - underTest = new AiCodeAssuranceVerifier(platformEditionProvider, dbClient); + void getAiCodeAssurance(boolean isFeatureEnabled, boolean containsAiCode, boolean aiCodeSupportedQg, AiCodeAssurance expected) { + when(aiCodeAssuranceEntitlement.isEnabled()).thenReturn(isFeatureEnabled); + underTest = new AiCodeAssuranceVerifier(aiCodeAssuranceEntitlement, dbClient); mockProjectAndQualityGate(containsAiCode, aiCodeSupportedQg); assertThat(underTest.getAiCodeAssurance(projectDto)).isEqualTo(expected); @@ -71,8 +69,8 @@ class AiCodeAssuranceVerifierTest { @MethodSource("paramsForDefaultQualityGate") void getAiCodeAssurance_fallback_on_default_qg_when_no_qg_defined_and_contains_ai_code(boolean aiCodeSupportedQg, AiCodeAssurance expected) { - when(platformEditionProvider.get()).thenReturn(Optional.of(Edition.DEVELOPER)); - underTest = new AiCodeAssuranceVerifier(platformEditionProvider, dbClient); + when(aiCodeAssuranceEntitlement.isEnabled()).thenReturn(true); + underTest = new AiCodeAssuranceVerifier(aiCodeAssuranceEntitlement, dbClient); when(projectDto.getContainsAiCode()).thenReturn(true); mockDefaultQg(aiCodeSupportedQg); @@ -81,8 +79,8 @@ class AiCodeAssuranceVerifierTest { @Test void getAiCodeAssurance_no_exception_when_no_default_qg_and_no_qg_defined_and_contains_ai_code() { - when(platformEditionProvider.get()).thenReturn(Optional.of(Edition.DEVELOPER)); - underTest = new AiCodeAssuranceVerifier(platformEditionProvider, dbClient); + when(aiCodeAssuranceEntitlement.isEnabled()).thenReturn(true); + underTest = new AiCodeAssuranceVerifier(aiCodeAssuranceEntitlement, dbClient); when(projectDto.getContainsAiCode()).thenReturn(true); when(dbClient.qualityGateDao()).thenReturn(qualityGateDao); when(qualityGateDao.selectByProjectUuid(any(), any())).thenReturn(null); @@ -116,22 +114,14 @@ class AiCodeAssuranceVerifierTest { private static Stream<Arguments> paramsForGetAiCodeAssurance() { return Stream.of( - Arguments.of(Edition.COMMUNITY, true, true, AiCodeAssurance.NONE), - Arguments.of(Edition.COMMUNITY, true, false, AiCodeAssurance.NONE), - Arguments.of(Edition.COMMUNITY, false, false, AiCodeAssurance.NONE), - Arguments.of(Edition.COMMUNITY, false, true, AiCodeAssurance.NONE), - Arguments.of(Edition.DEVELOPER, true, true, AiCodeAssurance.AI_CODE_ASSURED), - Arguments.of(Edition.DEVELOPER, true, false, AiCodeAssurance.CONTAINS_AI_CODE), - Arguments.of(Edition.DEVELOPER, false, false, AiCodeAssurance.NONE), - Arguments.of(Edition.DEVELOPER, false, true, AiCodeAssurance.NONE), - Arguments.of(Edition.ENTERPRISE, true, true, AiCodeAssurance.AI_CODE_ASSURED), - Arguments.of(Edition.ENTERPRISE, true, false, AiCodeAssurance.CONTAINS_AI_CODE), - Arguments.of(Edition.ENTERPRISE, false, false, AiCodeAssurance.NONE), - Arguments.of(Edition.ENTERPRISE, false, true, AiCodeAssurance.NONE), - Arguments.of(Edition.DATACENTER, true, true, AiCodeAssurance.AI_CODE_ASSURED), - Arguments.of(Edition.DATACENTER, true, false, AiCodeAssurance.CONTAINS_AI_CODE), - Arguments.of(Edition.DATACENTER, false, false, AiCodeAssurance.NONE), - Arguments.of(Edition.DATACENTER, false, true, AiCodeAssurance.NONE) + Arguments.of(false, true, true, AiCodeAssurance.NONE), + Arguments.of(false, true, false, AiCodeAssurance.NONE), + Arguments.of(false, false, false, AiCodeAssurance.NONE), + Arguments.of(false, false, true, AiCodeAssurance.NONE), + Arguments.of(true, true, true, AiCodeAssurance.AI_CODE_ASSURED), + Arguments.of(true, true, false, AiCodeAssurance.CONTAINS_AI_CODE), + Arguments.of(true, false, false, AiCodeAssurance.NONE), + Arguments.of(true, false, true, AiCodeAssurance.NONE) ); } @@ -144,17 +134,4 @@ class AiCodeAssuranceVerifierTest { ); } - private static Stream<Arguments> provideParams() { - return Stream.of( - Arguments.of(Edition.COMMUNITY, true, false), - Arguments.of(Edition.COMMUNITY, false, false), - Arguments.of(Edition.DEVELOPER, true, true), - Arguments.of(Edition.DEVELOPER, false, false), - Arguments.of(Edition.ENTERPRISE, true, true), - Arguments.of(Edition.ENTERPRISE, false, false), - Arguments.of(Edition.DATACENTER, true, true), - Arguments.of(Edition.DATACENTER, false, false) - ); - } - } diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualitygate/ws/ListActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualitygate/ws/ListActionIT.java index 8628a153f26..3d902c3b0b6 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualitygate/ws/ListActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualitygate/ws/ListActionIT.java @@ -21,9 +21,9 @@ package org.sonar.server.qualitygate.ws; import java.util.Collection; import java.util.List; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; import org.mockito.ArgumentMatcher; import org.sonar.api.server.ws.WebService; import org.sonar.db.DbClient; @@ -32,6 +32,7 @@ import org.sonar.db.metric.MetricDto; import org.sonar.db.qualitygate.QualityGateConditionDto; import org.sonar.db.qualitygate.QualityGateDto; import org.sonar.db.user.UserDto; +import org.sonar.server.ai.code.assurance.AiCodeAssuranceEntitlement; import org.sonar.server.component.TestComponentFinder; import org.sonar.server.qualitygate.QualityGateCaycChecker; import org.sonar.server.qualitygate.QualityGateFinder; @@ -56,24 +57,26 @@ import static org.sonar.server.qualitygate.QualityGateCaycStatus.OVER_COMPLIANT; import static org.sonar.test.JsonAssert.assertJson; import static org.sonarqube.ws.Qualitygates.ListWsResponse; -public class ListActionIT { +class ListActionIT { - @Rule - public UserSessionRule userSession = UserSessionRule.standalone(); - @Rule - public DbTester db = DbTester.create(); + @RegisterExtension + UserSessionRule userSession = UserSessionRule.standalone(); + @RegisterExtension + DbTester db = DbTester.create(); private final DbClient dbClient = db.getDbClient(); private final QualityGateFinder qualityGateFinder = new QualityGateFinder(dbClient); private final QualityGateCaycChecker qualityGateCaycChecker = mock(QualityGateCaycChecker.class); private final QualityGateModeChecker qualityGateModeChecker = mock(QualityGateModeChecker.class); + private final AiCodeAssuranceEntitlement aiCodeAssuranceEntitlement = mock(AiCodeAssuranceEntitlement.class); + private final QualityGatesWsSupport wsSupport = new QualityGatesWsSupport(db.getDbClient(), userSession, TestComponentFinder.from(db)); - private final WsActionTester ws = new WsActionTester(new ListAction(db.getDbClient(), - new QualityGatesWsSupport(dbClient, userSession, TestComponentFinder.from(db)), qualityGateFinder, qualityGateCaycChecker, qualityGateModeChecker)); + private final WsActionTester ws = new WsActionTester(new ListAction(db.getDbClient(), wsSupport, qualityGateFinder, + qualityGateCaycChecker, qualityGateModeChecker, new QualityGateActionsSupport(wsSupport, aiCodeAssuranceEntitlement))); - @Before - public void setUp() { + @BeforeEach + void setUp() { when(qualityGateCaycChecker.checkCaycCompliant(any(Collection.class), any(List.class))).thenReturn(COMPLIANT); doReturn(new QualityGateModeChecker.QualityModeResult(false, false)) .when(qualityGateModeChecker).getUsageOfModeMetrics(any(List.class)); @@ -81,7 +84,7 @@ public class ListActionIT { } @Test - public void list_quality_gates() { + void list_quality_gates() { QualityGateDto defaultQualityGate = db.qualityGates().insertQualityGate(); QualityGateDto otherQualityGate = db.qualityGates().insertQualityGate(); db.qualityGates().setDefaultQualityGate(defaultQualityGate); @@ -97,7 +100,7 @@ public class ListActionIT { } @Test - public void test_built_in_flag() { + void test_built_in_flag() { QualityGateDto qualityGate1 = db.qualityGates().insertQualityGate(qualityGate -> qualityGate.setBuiltIn(true)); QualityGateDto qualityGate2 = db.qualityGates().insertQualityGate(qualityGate -> qualityGate.setBuiltIn(false)); db.qualityGates().setDefaultQualityGate(qualityGate1); @@ -113,7 +116,7 @@ public class ListActionIT { } @Test - public void test_ai_code_supported_flag() { + void test_ai_code_supported_flag() { QualityGateDto qualityGateWithAiCodeSupported = db.qualityGates().insertQualityGate(qg -> qg.setAiCodeSupported(true)); QualityGateDto qualityGateWithoutAiCodeSupported = db.qualityGates().insertQualityGate(qg -> qg.setAiCodeSupported(false)); db.qualityGates().setDefaultQualityGate(qualityGateWithAiCodeSupported); @@ -129,7 +132,7 @@ public class ListActionIT { } @Test - public void test_caycStatus_flag() { + void test_caycStatus_flag() { QualityGateDto qualityGate1 = db.qualityGates().insertQualityGate(); QualityGateConditionDto condition1 = db.qualityGates().addCondition(qualityGate1, db.measures().insertMetric()); QualityGateDto qualityGate2 = db.qualityGates().insertQualityGate(); @@ -154,7 +157,7 @@ public class ListActionIT { } @Test - public void execute_shouldReturnExpectedModeFlags() { + void execute_shouldReturnExpectedModeFlags() { QualityGateDto qualityGate1 = db.qualityGates().insertQualityGate(); MetricDto metric1 = db.measures().insertMetric(); db.qualityGates().addCondition(qualityGate1, metric1); @@ -188,7 +191,7 @@ public class ListActionIT { } @Test - public void no_default_quality_gate() { + void no_default_quality_gate() { QualityGateDto qualityGate = db.qualityGates().insertQualityGate(); assertThatThrownBy(() -> ws.newRequest() @@ -198,11 +201,13 @@ public class ListActionIT { } @Test - public void actions_with_quality_gate_administer_permission() { + void actions_with_quality_gate_administer_permission() { + when(aiCodeAssuranceEntitlement.isEnabled()).thenReturn(true); userSession.logIn("john").addPermission(ADMINISTER_QUALITY_GATES); QualityGateDto defaultQualityGate = db.qualityGates().insertQualityGate(qg -> qg.setName("Default").setBuiltIn(false)); QualityGateDto builtInQualityGate = db.qualityGates().insertQualityGate(qg -> qg.setName("Sonar way").setBuiltIn(true)); - QualityGateDto otherQualityGate = db.qualityGates().insertQualityGate(qg -> qg.setName("Sonar way - Without Coverage").setBuiltIn(false)); + QualityGateDto otherQualityGate = + db.qualityGates().insertQualityGate(qg -> qg.setName("Sonar way - Without Coverage").setBuiltIn(false)); db.qualityGates().setDefaultQualityGate(defaultQualityGate); ListWsResponse response = ws.newRequest().executeProtobuf(ListWsResponse.class); @@ -214,15 +219,29 @@ public class ListActionIT { .extracting(QualityGate::getName, qg -> qg.getActions().getRename(), qg -> qg.getActions().getDelete(), qg -> qg.getActions().getManageConditions(), qp -> qp.getActions().getCopy(), qp -> qp.getActions().getSetAsDefault(), qp -> qp.getActions().getAssociateProjects(), - qp -> qp.getActions().getDelegate()) + qp -> qp.getActions().getDelegate(), qg -> qg.getActions().getManageAiCodeAssurance()) .containsExactlyInAnyOrder( - tuple(defaultQualityGate.getName(), true, false, true, true, false, false, true), - tuple(builtInQualityGate.getName(), false, false, false, true, true, true, false), - tuple(otherQualityGate.getName(), true, true, true, true, true, true, true)); + tuple(defaultQualityGate.getName(), true, false, true, true, false, false, true, true), + tuple(builtInQualityGate.getName(), false, false, false, true, true, true, false, false), + tuple(otherQualityGate.getName(), true, true, true, true, true, true, true, true)); } @Test - public void actions_with_quality_gate_delegate_permission() { + void getManageAiCodeAssurance_action_not_available_when_feature_disabled() { + when(aiCodeAssuranceEntitlement.isEnabled()).thenReturn(false); + userSession.logIn("john").addPermission(ADMINISTER_QUALITY_GATES); + QualityGateDto defaultQualityGate = db.qualityGates().insertQualityGate(qg -> qg.setName("Default").setBuiltIn(false)); + db.qualityGates().setDefaultQualityGate(defaultQualityGate); + + ListWsResponse response = ws.newRequest().executeProtobuf(ListWsResponse.class); + + assertThat(response.getQualitygatesList()).hasSize(1); + assertThat(response.getQualitygatesList().get(0).getActions().getManageAiCodeAssurance()).isFalse(); + } + + @Test + void actions_with_quality_gate_delegate_permission() { + when(aiCodeAssuranceEntitlement.isEnabled()).thenReturn(true); QualityGateDto defaultQualityGate = db.qualityGates().insertQualityGate(qg -> qg.setName("Sonar way")); QualityGateDto otherQualityGate = db.qualityGates().insertQualityGate(qg -> qg.setName("Sonar way - Without Coverage")); UserDto user = db.users().insertUser(); @@ -240,17 +259,19 @@ public class ListActionIT { .extracting(QualityGate::getName, qg -> qg.getActions().getRename(), qg -> qg.getActions().getDelete(), qg -> qg.getActions().getManageConditions(), qp -> qp.getActions().getCopy(), qp -> qp.getActions().getSetAsDefault(), qp -> qp.getActions().getAssociateProjects(), - qp -> qp.getActions().getDelegate()) + qp -> qp.getActions().getDelegate(), qg -> qg.getActions().getManageAiCodeAssurance()) .containsExactlyInAnyOrder( - tuple(defaultQualityGate.getName(), false, false, true, false, false, false, true), - tuple(otherQualityGate.getName(), false, false, true, false, false, false, true)); + tuple(defaultQualityGate.getName(), false, false, true, false, false, false, true, false), + tuple(otherQualityGate.getName(), false, false, true, false, false, false, true, false)); } @Test - public void actions_without_quality_gate_administer_permission() { + void actions_without_quality_gate_administer_permission() { + when(aiCodeAssuranceEntitlement.isEnabled()).thenReturn(true); userSession.logIn("john").addPermission(ADMINISTER_QUALITY_PROFILES); QualityGateDto defaultQualityGate = db.qualityGates().insertQualityGate(qg -> qg.setName("Sonar way").setBuiltIn(true)); - QualityGateDto otherQualityGate = db.qualityGates().insertQualityGate(qg -> qg.setName("Sonar way - Without Coverage").setBuiltIn(false)); + QualityGateDto otherQualityGate = + db.qualityGates().insertQualityGate(qg -> qg.setName("Sonar way - Without Coverage").setBuiltIn(false)); db.qualityGates().setDefaultQualityGate(defaultQualityGate); ListWsResponse response = ws.newRequest().executeProtobuf(ListWsResponse.class); @@ -262,18 +283,21 @@ public class ListActionIT { .extracting(QualityGate::getName, qg -> qg.getActions().getRename(), qg -> qg.getActions().getDelete(), qg -> qg.getActions().getManageConditions(), qp -> qp.getActions().getCopy(), qp -> qp.getActions().getSetAsDefault(), qp -> qp.getActions().getAssociateProjects(), - qp -> qp.getActions().getDelegate()) + qp -> qp.getActions().getDelegate(), qg -> qg.getActions().getManageAiCodeAssurance()) .containsExactlyInAnyOrder( - tuple(defaultQualityGate.getName(), false, false, false, false, false, false, false), - tuple(otherQualityGate.getName(), false, false, false, false, false, false, false)); + tuple(defaultQualityGate.getName(), false, false, false, false, false, false, false, false), + tuple(otherQualityGate.getName(), false, false, false, false, false, false, false, false)); } @Test - public void json_example() { + void json_example() { + when(aiCodeAssuranceEntitlement.isEnabled()).thenReturn(true); userSession.logIn("admin").addPermission(ADMINISTER_QUALITY_GATES); - QualityGateDto defaultQualityGate = db.qualityGates().insertQualityGate(qualityGate -> qualityGate.setName("Sonar way").setBuiltIn(true)); + QualityGateDto defaultQualityGate = + db.qualityGates().insertQualityGate(qualityGate -> qualityGate.setName("Sonar way").setBuiltIn(true)); QualityGateConditionDto condition1 = db.qualityGates().addCondition(defaultQualityGate, db.measures().insertMetric()); - QualityGateDto otherQualityGate = db.qualityGates().insertQualityGate(qualityGate -> qualityGate.setName("Sonar way - Without Coverage").setBuiltIn(false)); + QualityGateDto otherQualityGate = db.qualityGates().insertQualityGate(qualityGate -> qualityGate.setName("Sonar way - Without " + + "Coverage").setBuiltIn(false)); QualityGateConditionDto condition2 = db.qualityGates().addCondition(otherQualityGate, db.measures().insertMetric()); db.qualityGates().setDefaultQualityGate(defaultQualityGate); doReturn(COMPLIANT).when(qualityGateCaycChecker).checkCaycCompliant(argThat(hasCondition(condition1)), any(List.class)); @@ -286,7 +310,7 @@ public class ListActionIT { } @Test - public void verify_definition() { + void verify_definition() { WebService.Action action = ws.getDef(); assertThat(action.since()).isEqualTo("4.3"); assertThat(action.key()).isEqualTo("list"); diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualitygate/ws/ShowActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualitygate/ws/ShowActionIT.java index 37d5b0f5d91..b9102b1f7c1 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualitygate/ws/ShowActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualitygate/ws/ShowActionIT.java @@ -21,9 +21,9 @@ package org.sonar.server.qualitygate.ws; import java.util.Collection; import org.assertj.core.api.Assertions; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; import org.sonar.api.server.ws.WebService; import org.sonar.api.server.ws.WebService.Param; import org.sonar.db.DbSession; @@ -32,6 +32,7 @@ import org.sonar.db.metric.MetricDto; import org.sonar.db.qualitygate.QualityGateConditionDto; import org.sonar.db.qualitygate.QualityGateDto; import org.sonar.db.user.UserDto; +import org.sonar.server.ai.code.assurance.AiCodeAssuranceEntitlement; import org.sonar.server.component.TestComponentFinder; import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.qualitygate.QualityGateCaycChecker; @@ -60,27 +61,30 @@ import static org.sonar.server.qualitygate.QualityGateCaycStatus.NON_COMPLIANT; import static org.sonar.test.JsonAssert.assertJson; import static org.sonarqube.ws.Qualitygates.Actions; -public class ShowActionIT { +class ShowActionIT { - @Rule - public UserSessionRule userSession = UserSessionRule.standalone(); - @Rule - public DbTester db = DbTester.create(); + @RegisterExtension + UserSessionRule userSession = UserSessionRule.standalone(); + @RegisterExtension + DbTester db = DbTester.create(); private final QualityGateCaycChecker qualityGateCaycChecker = mock(QualityGateCaycChecker.class); private final QualityGateModeChecker qualityGateModeChecker = mock(QualityGateModeChecker.class); + private final AiCodeAssuranceEntitlement aiCodeAssuranceEntitlement = mock(AiCodeAssuranceEntitlement.class); + private final QualityGatesWsSupport wsSupport = new QualityGatesWsSupport(db.getDbClient(), userSession, TestComponentFinder.from(db)); + private final WsActionTester ws = new WsActionTester( - new ShowAction(db.getDbClient(), new QualityGateFinder(db.getDbClient()), - new QualityGatesWsSupport(db.getDbClient(), userSession, TestComponentFinder.from(db)), qualityGateCaycChecker, qualityGateModeChecker)); + new ShowAction(db.getDbClient(), new QualityGateFinder(db.getDbClient()), wsSupport, qualityGateCaycChecker, qualityGateModeChecker, + new QualityGateActionsSupport(wsSupport, aiCodeAssuranceEntitlement))); - @Before - public void setUp() { + @BeforeEach + void setUp() { when(qualityGateCaycChecker.checkCaycCompliant(any(), any(String.class))).thenReturn(COMPLIANT); when(qualityGateModeChecker.getUsageOfModeMetrics(any())) .thenReturn(new QualityGateModeChecker.QualityModeResult(false, false)); } @Test - public void show() { + void show() { QualityGateDto qualityGate = db.qualityGates().insertQualityGate(); db.qualityGates().setDefaultQualityGate(qualityGate); MetricDto metric1 = db.measures().insertMetric(); @@ -103,7 +107,7 @@ public class ShowActionIT { } @Test - public void show_built_in() { + void show_built_in() { QualityGateDto qualityGate = db.qualityGates().insertQualityGate(qg -> qg.setBuiltIn(true)); db.qualityGates().setDefaultQualityGate(qualityGate); @@ -115,7 +119,7 @@ public class ShowActionIT { } @Test - public void show_ai_code_supported() { + void show_ai_code_supported() { QualityGateDto qualityGate = db.qualityGates().insertQualityGate(); db.qualityGates().setDefaultQualityGate(qualityGate); @@ -135,7 +139,7 @@ public class ShowActionIT { } @Test - public void show_isCaycCompliant() { + void show_isCaycCompliant() { QualityGateDto qualityGate = db.qualityGates().insertQualityGate(); when(qualityGateCaycChecker.checkCaycCompliant(any(DbSession.class), eq(qualityGate.getUuid()))).thenReturn(COMPLIANT); db.qualityGates().setDefaultQualityGate(qualityGate); @@ -148,7 +152,7 @@ public class ShowActionIT { } @Test - public void execute_shouldShowModeFlags() { + void execute_shouldShowModeFlags() { QualityGateDto qualityGate = db.qualityGates().insertQualityGate(); when(qualityGateModeChecker.getUsageOfModeMetrics(any(Collection.class))) .thenReturn(new QualityGateModeChecker.QualityModeResult(true, true)); @@ -163,7 +167,7 @@ public class ShowActionIT { } @Test - public void show_by_name() { + void show_by_name() { QualityGateDto qualityGate = db.qualityGates().insertQualityGate(); db.qualityGates().setDefaultQualityGate(qualityGate); @@ -175,7 +179,7 @@ public class ShowActionIT { } @Test - public void no_condition() { + void no_condition() { QualityGateDto qualityGate = db.qualityGates().insertQualityGate(); db.qualityGates().setDefaultQualityGate(qualityGate); @@ -188,7 +192,8 @@ public class ShowActionIT { } @Test - public void actions() { + void actions() { + when(aiCodeAssuranceEntitlement.isEnabled()).thenReturn(true); userSession.logIn("john").addPermission(ADMINISTER_QUALITY_GATES); QualityGateDto qualityGate = db.qualityGates().insertQualityGate(); QualityGateDto qualityGate2 = db.qualityGates().insertQualityGate(); @@ -205,10 +210,28 @@ public class ShowActionIT { assertThat(actions.getCopy()).isTrue(); assertThat(actions.getSetAsDefault()).isTrue(); assertThat(actions.getAssociateProjects()).isTrue(); + assertThat(actions.getManageAiCodeAssurance()).isTrue(); + } + + @Test + void getManageAiCodeAssurance_action_not_available_when_feature_disabled() { + when(aiCodeAssuranceEntitlement.isEnabled()).thenReturn(false); + userSession.logIn("john").addPermission(ADMINISTER_QUALITY_GATES); + QualityGateDto qualityGate = db.qualityGates().insertQualityGate(); + QualityGateDto qualityGate2 = db.qualityGates().insertQualityGate(); + db.qualityGates().setDefaultQualityGate(qualityGate2); + + ShowWsResponse response = ws.newRequest() + .setParam("name", qualityGate.getName()) + .executeProtobuf(ShowWsResponse.class); + + Actions actions = response.getActions(); + assertThat(actions.getManageAiCodeAssurance()).isFalse(); } @Test - public void actions_on_default() { + void actions_on_default() { + when(aiCodeAssuranceEntitlement.isEnabled()).thenReturn(true); userSession.logIn("john").addPermission(ADMINISTER_QUALITY_GATES); QualityGateDto qualityGate = db.qualityGates().insertQualityGate(); db.qualityGates().setDefaultQualityGate(qualityGate); @@ -224,10 +247,12 @@ public class ShowActionIT { assertThat(actions.getCopy()).isTrue(); assertThat(actions.getSetAsDefault()).isFalse(); assertThat(actions.getAssociateProjects()).isFalse(); + assertThat(actions.getManageAiCodeAssurance()).isTrue(); } @Test - public void actions_on_built_in() { + void actions_on_built_in() { + when(aiCodeAssuranceEntitlement.isEnabled()).thenReturn(true); userSession.logIn("john").addPermission(ADMINISTER_QUALITY_GATES); QualityGateDto qualityGate = db.qualityGates().insertQualityGate(qg -> qg.setBuiltIn(true)); QualityGateDto qualityGate2 = db.qualityGates().insertQualityGate(qg -> qg.setBuiltIn(false)); @@ -244,10 +269,12 @@ public class ShowActionIT { assertThat(actions.getCopy()).isTrue(); assertThat(actions.getSetAsDefault()).isTrue(); assertThat(actions.getAssociateProjects()).isTrue(); + assertThat(actions.getManageAiCodeAssurance()).isFalse(); } @Test - public void actions_when_not_quality_gate_administer() { + void actions_when_not_quality_gate_administer() { + when(aiCodeAssuranceEntitlement.isEnabled()).thenReturn(true); userSession.logIn("john").addPermission(ADMINISTER_QUALITY_PROFILES); QualityGateDto qualityGate = db.qualityGates().insertQualityGate(qg -> qg.setBuiltIn(true)); db.qualityGates().setDefaultQualityGate(qualityGate); @@ -263,10 +290,12 @@ public class ShowActionIT { assertThat(actions.getCopy()).isFalse(); assertThat(actions.getSetAsDefault()).isFalse(); assertThat(actions.getAssociateProjects()).isFalse(); + assertThat(actions.getManageAiCodeAssurance()).isFalse(); } @Test - public void actions_when_delegate_quality_gate_administer() { + void actions_when_delegate_quality_gate_administer() { + when(aiCodeAssuranceEntitlement.isEnabled()).thenReturn(true); QualityGateDto defaultQualityGate = db.qualityGates().insertQualityGate(qg -> qg.setName("Sonar way")); QualityGateDto otherQualityGate = db.qualityGates().insertQualityGate(qg -> qg.setName("Sonar way - Without Coverage")); UserDto user = db.users().insertUser(); @@ -282,9 +311,9 @@ public class ShowActionIT { assertThat(response.getActions()) .extracting( Actions::getRename, Actions::getDelete, Actions::getManageConditions, - Actions::getCopy, Actions::getSetAsDefault, Actions::getAssociateProjects, Actions::getDelegate) + Actions::getCopy, Actions::getSetAsDefault, Actions::getAssociateProjects, Actions::getDelegate, Actions::getManageAiCodeAssurance) .containsExactlyInAnyOrder( - false, false, true, false, false, false, true); + false, false, true, false, false, false, true, false); response = ws.newRequest() .setParam("name", otherQualityGate.getName()) @@ -293,14 +322,14 @@ public class ShowActionIT { assertThat(response.getActions()) .extracting( Actions::getRename, Actions::getDelete, Actions::getManageConditions, - Actions::getCopy, Actions::getSetAsDefault, Actions::getAssociateProjects, Actions::getDelegate) + Actions::getCopy, Actions::getSetAsDefault, Actions::getAssociateProjects, Actions::getDelegate, Actions::getManageAiCodeAssurance) .containsExactlyInAnyOrder( - false, false, true, false, false, false, true); + false, false, true, false, false, false, true, false); } @Test - public void reponse_should_show_isDefault() { + void reponse_should_show_isDefault() { QualityGateDto defaultQualityGate = db.qualityGates().insertQualityGate(); db.qualityGates().setDefaultQualityGate(defaultQualityGate); @@ -320,7 +349,7 @@ public class ShowActionIT { } @Test - public void fail_when_no_name() { + void fail_when_no_name() { QualityGateDto qualityGate = db.qualityGates().insertQualityGate(); assertThatThrownBy(() -> ws.newRequest().execute()) @@ -329,7 +358,7 @@ public class ShowActionIT { } @Test - public void fail_when_condition_is_on_disabled_metric() { + void fail_when_condition_is_on_disabled_metric() { QualityGateDto qualityGate = db.qualityGates().insertQualityGate(); db.qualityGates().setDefaultQualityGate(qualityGate); MetricDto metric = db.measures().insertMetric(); @@ -345,7 +374,7 @@ public class ShowActionIT { } @Test - public void fail_when_quality_name_does_not_exist() { + void fail_when_quality_name_does_not_exist() { QualityGateDto qualityGate = db.qualityGates().insertQualityGate(); assertThatThrownBy(() -> ws.newRequest() @@ -356,7 +385,8 @@ public class ShowActionIT { } @Test - public void json_example() { + void json_example() { + when(aiCodeAssuranceEntitlement.isEnabled()).thenReturn(true); userSession.logIn("admin").addPermission(ADMINISTER_QUALITY_GATES); QualityGateDto qualityGate = db.qualityGates().insertQualityGate(qg -> qg.setName("My Quality Gate")); QualityGateDto qualityGate2 = db.qualityGates().insertQualityGate(qg -> qg.setName("My Quality Gate 2")); @@ -377,7 +407,7 @@ public class ShowActionIT { } @Test - public void verify_definition() { + void verify_definition() { WebService.Action action = ws.getDef(); assertThat(action.since()).isEqualTo("4.3"); assertThat(action.params()) diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ai/code/assurance/AiCodeAssuranceEntitlement.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ai/code/assurance/AiCodeAssuranceEntitlement.java new file mode 100644 index 00000000000..6cc91428d70 --- /dev/null +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ai/code/assurance/AiCodeAssuranceEntitlement.java @@ -0,0 +1,36 @@ +/* + * 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.ai.code.assurance; + +import org.sonar.core.platform.PlatformEditionProvider; + +import static org.sonar.core.platform.EditionProvider.Edition.COMMUNITY; + +public class AiCodeAssuranceEntitlement { + private final boolean isSupported; + + public AiCodeAssuranceEntitlement(PlatformEditionProvider editionProvider) { + this.isSupported = editionProvider.get().map(edition -> !edition.equals(COMMUNITY)).orElse(false); + } + + public boolean isEnabled() { + return isSupported; + } +} diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ai/code/assurance/AiCodeAssuranceVerifier.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ai/code/assurance/AiCodeAssuranceVerifier.java index 0854f8ac757..1dc3a1dd792 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ai/code/assurance/AiCodeAssuranceVerifier.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ai/code/assurance/AiCodeAssuranceVerifier.java @@ -20,30 +20,27 @@ package org.sonar.server.ai.code.assurance; import org.sonar.core.platform.EditionProvider; -import org.sonar.core.platform.PlatformEditionProvider; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.project.ProjectDto; import org.sonar.db.qualitygate.QualityGateDto; -import static org.sonar.core.platform.EditionProvider.Edition.COMMUNITY; - /** * Make sure that for {@link EditionProvider.Edition#COMMUNITY} we'll always get false or {@link AiCodeAssurance#NONE}, no matter of the * value in database. * This is to support correctly downgraded instances. */ public class AiCodeAssuranceVerifier { - private final boolean isSupported; private final DbClient dbClient; + private final AiCodeAssuranceEntitlement entitlement; - public AiCodeAssuranceVerifier(PlatformEditionProvider editionProvider, DbClient dbClient) { + public AiCodeAssuranceVerifier(AiCodeAssuranceEntitlement entitlement, DbClient dbClient) { this.dbClient = dbClient; - this.isSupported = editionProvider.get().map(edition -> !edition.equals(COMMUNITY)).orElse(false); + this.entitlement = entitlement; } public AiCodeAssurance getAiCodeAssurance(ProjectDto projectDto) { - if (!isSupported || !projectDto.getContainsAiCode()) { + if (!entitlement.isEnabled() || !projectDto.getContainsAiCode()) { return AiCodeAssurance.NONE; } try (DbSession dbSession = dbClient.openSession(false)) { @@ -63,7 +60,7 @@ public class AiCodeAssuranceVerifier { } public AiCodeAssurance getAiCodeAssurance(boolean containsAiCode, boolean aiCodeSupportedQg) { - if (!isSupported || !containsAiCode) { + if (!entitlement.isEnabled() || !containsAiCode) { return AiCodeAssurance.NONE; } if (aiCodeSupportedQg) { diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/ListAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/ListAction.java index 860ecb5163f..4964640c6ac 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/ListAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/ListAction.java @@ -49,14 +49,16 @@ public class ListAction implements QualityGatesWsAction { private final QualityGateFinder finder; private final QualityGateCaycChecker qualityGateCaycChecker; private final QualityGateModeChecker qualityGateModeChecker; + private final QualityGateActionsSupport actionsSupport; public ListAction(DbClient dbClient, QualityGatesWsSupport wsSupport, QualityGateFinder finder, QualityGateCaycChecker qualityGateCaycChecker, - QualityGateModeChecker qualityGateModeChecker) { + QualityGateModeChecker qualityGateModeChecker, QualityGateActionsSupport actionsSupport) { this.dbClient = dbClient; this.wsSupport = wsSupport; this.finder = finder; this.qualityGateCaycChecker = qualityGateCaycChecker; this.qualityGateModeChecker = qualityGateModeChecker; + this.actionsSupport = actionsSupport; } @Override @@ -106,7 +108,7 @@ public class ListAction implements QualityGatesWsAction { .setCaycStatus(qualityGateCaycChecker.checkCaycCompliant(conditions, metrics).toString()) .setHasMQRConditions(qualityModeResult.hasMQRConditions()) .setHasStandardConditions(qualityModeResult.hasStandardConditions()) - .setActions(wsSupport.getActions(dbSession, qualityGate, defaultQualityGate)) + .setActions(actionsSupport.getActions(dbSession, qualityGate, defaultQualityGate)) .build(); }) .toList()); diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGateActionsSupport.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGateActionsSupport.java new file mode 100644 index 00000000000..29aee221ee6 --- /dev/null +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGateActionsSupport.java @@ -0,0 +1,54 @@ +/* + * 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.qualitygate.ws; + +import java.util.Objects; +import javax.annotation.Nullable; +import org.sonar.db.DbSession; +import org.sonar.db.qualitygate.QualityGateDto; +import org.sonar.server.ai.code.assurance.AiCodeAssuranceEntitlement; +import org.sonarqube.ws.Qualitygates; + +public class QualityGateActionsSupport { + private final QualityGatesWsSupport wsSupport; + private final AiCodeAssuranceEntitlement aiCodeAssuranceEntitlement; + + public QualityGateActionsSupport(QualityGatesWsSupport wsSupport, AiCodeAssuranceEntitlement aiCodeAssuranceEntitlement) { + this.wsSupport = wsSupport; + this.aiCodeAssuranceEntitlement = aiCodeAssuranceEntitlement; + } + + Qualitygates.Actions getActions(DbSession dbSession, QualityGateDto qualityGate, @Nullable QualityGateDto defaultQualityGate) { + boolean isDefault = defaultQualityGate != null && Objects.equals(defaultQualityGate.getUuid(), qualityGate.getUuid()); + boolean isBuiltIn = qualityGate.isBuiltIn(); + boolean isQualityGateAdmin = wsSupport.isQualityGateAdmin(); + boolean canLimitedEdit = isQualityGateAdmin || wsSupport.hasLimitedPermission(dbSession, qualityGate); + return Qualitygates.Actions.newBuilder() + .setCopy(isQualityGateAdmin) + .setRename(!isBuiltIn && isQualityGateAdmin) + .setManageConditions(!isBuiltIn && canLimitedEdit) + .setDelete(!isDefault && !isBuiltIn && isQualityGateAdmin) + .setSetAsDefault(!isDefault && isQualityGateAdmin) + .setAssociateProjects(!isDefault && isQualityGateAdmin) + .setDelegate(!isBuiltIn && canLimitedEdit) + .setManageAiCodeAssurance(aiCodeAssuranceEntitlement.isEnabled() && !isBuiltIn && isQualityGateAdmin) + .build(); + } +} diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGateWsModule.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGateWsModule.java index d45bfd778b6..f4bbcb878bc 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGateWsModule.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGateWsModule.java @@ -38,6 +38,7 @@ public class QualityGateWsModule extends Module { ProjectStatusAction.class, QualityGatesWs.class, QualityGatesWsSupport.class, + QualityGateActionsSupport.class, RemoveGroupAction.class, RemoveUserAction.class, RenameAction.class, diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsSupport.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsSupport.java index 4c2f41a6b29..406cad4df75 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsSupport.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsSupport.java @@ -19,8 +19,6 @@ */ package org.sonar.server.qualitygate.ws; -import java.util.Objects; -import javax.annotation.Nullable; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.project.ProjectDto; @@ -28,7 +26,6 @@ import org.sonar.db.qualitygate.QualityGateConditionDto; import org.sonar.db.qualitygate.QualityGateDto; import org.sonar.server.component.ComponentFinder; import org.sonar.server.user.UserSession; -import org.sonarqube.ws.Qualitygates; import static com.google.common.base.Preconditions.checkArgument; import static org.sonar.api.web.UserRole.ADMIN; @@ -67,22 +64,6 @@ public class QualityGatesWsSupport { return userSession.hasPermission(ADMINISTER_QUALITY_GATES); } - Qualitygates.Actions getActions(DbSession dbSession, QualityGateDto qualityGate, @Nullable QualityGateDto defaultQualityGate) { - boolean isDefault = defaultQualityGate != null && Objects.equals(defaultQualityGate.getUuid(), qualityGate.getUuid()); - boolean isBuiltIn = qualityGate.isBuiltIn(); - boolean isQualityGateAdmin = isQualityGateAdmin(); - boolean canLimitedEdit = isQualityGateAdmin || hasLimitedPermission(dbSession, qualityGate); - return Qualitygates.Actions.newBuilder() - .setCopy(isQualityGateAdmin) - .setRename(!isBuiltIn && isQualityGateAdmin) - .setManageConditions(!isBuiltIn && canLimitedEdit) - .setDelete(!isDefault && !isBuiltIn && isQualityGateAdmin) - .setSetAsDefault(!isDefault && isQualityGateAdmin) - .setAssociateProjects(!isDefault && isQualityGateAdmin) - .setDelegate(!isBuiltIn && canLimitedEdit) - .build(); - } - void checkCanEdit(QualityGateDto qualityGate) { checkNotBuiltIn(qualityGate); userSession.checkPermission(ADMINISTER_QUALITY_GATES); diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/ShowAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/ShowAction.java index 14ea0695d4b..554b248eb20 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/ShowAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/ShowAction.java @@ -52,14 +52,16 @@ public class ShowAction implements QualityGatesWsAction { private final QualityGatesWsSupport wsSupport; private final QualityGateCaycChecker qualityGateCaycChecker; private final QualityGateModeChecker qualityGateModeChecker; + private final QualityGateActionsSupport actionsSupport; public ShowAction(DbClient dbClient, QualityGateFinder qualityGateFinder, QualityGatesWsSupport wsSupport, QualityGateCaycChecker qualityGateCaycChecker, - QualityGateModeChecker qualityGateModeChecker) { + QualityGateModeChecker qualityGateModeChecker, QualityGateActionsSupport actionsSupport) { this.dbClient = dbClient; this.qualityGateFinder = qualityGateFinder; this.wsSupport = wsSupport; this.qualityGateCaycChecker = qualityGateCaycChecker; this.qualityGateModeChecker = qualityGateModeChecker; + this.actionsSupport = actionsSupport; } @Override @@ -127,7 +129,7 @@ public class ShowAction implements QualityGatesWsAction { .addAllConditions(conditions.stream() .map(toWsCondition(metricsByUuid)) .toList()) - .setActions(wsSupport.getActions(dbSession, qualityGate, defaultQualityGate)) + .setActions(actionsSupport.getActions(dbSession, qualityGate, defaultQualityGate)) .build(); } diff --git a/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/qualitygate/ws/list-example.json b/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/qualitygate/ws/list-example.json index 62345af6717..1c26d2cf875 100644 --- a/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/qualitygate/ws/list-example.json +++ b/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/qualitygate/ws/list-example.json @@ -11,7 +11,8 @@ "associateProjects": false, "delete": false, "manageConditions": false, - "delegate": false + "delegate": false, + "manageAiCodeAssurance": false }, "caycStatus": "compliant", "hasStandardConditions": false, @@ -29,7 +30,8 @@ "associateProjects": true, "delete": true, "manageConditions": true, - "delegate": true + "delegate": true, + "manageAiCodeAssurance": true }, "caycStatus": "non-compliant", "hasStandardConditions": false, diff --git a/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/qualitygate/ws/show-example.json b/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/qualitygate/ws/show-example.json index 67a1cf3455d..08c066078ba 100644 --- a/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/qualitygate/ws/show-example.json +++ b/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/qualitygate/ws/show-example.json @@ -23,7 +23,8 @@ "associateProjects": true, "delete": true, "manageConditions": true, - "delegate": true + "delegate": true, + "manageAiCodeAssurance": true }, "caycStatus": "non-compliant", "isAiCodeSupported": false diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/QualityGateWsModuleTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/QualityGateWsModuleTest.java index 9b796f17d7a..34cee59583a 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/QualityGateWsModuleTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/QualityGateWsModuleTest.java @@ -29,6 +29,6 @@ public class QualityGateWsModuleTest { public void verify_count_of_added_components() { ListContainer container = new ListContainer(); new QualityGateWsModule().configure(container); - assertThat(container.getAddedObjects()).hasSize(23); + assertThat(container.getAddedObjects()).hasSize(24); } } |