aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-webserver-webapi
diff options
context:
space:
mode:
authorAnita Stanisz <106669481+anita-stanisz-sonarsource@users.noreply.github.com>2024-11-27 16:13:20 +0100
committersonartech <sonartech@sonarsource.com>2024-11-29 20:03:07 +0000
commit8f0a4b81ff51e1332032a1661c0495b933479ec2 (patch)
treef33276424cc11674472832decf792222bfe4f5e1 /server/sonar-webserver-webapi
parentc2f6540d095189ada11bd529114acd3cad2efe9b (diff)
downloadsonarqube-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')
-rw-r--r--server/sonar-webserver-webapi/src/it/java/org/sonar/server/ai/code/assurance/AiCodeAssuranceEntitlementTest.java54
-rw-r--r--server/sonar-webserver-webapi/src/it/java/org/sonar/server/ai/code/assurance/AiCodeAssuranceVerifierTest.java59
-rw-r--r--server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualitygate/ws/ListActionIT.java98
-rw-r--r--server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualitygate/ws/ShowActionIT.java98
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/ai/code/assurance/AiCodeAssuranceEntitlement.java36
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/ai/code/assurance/AiCodeAssuranceVerifier.java13
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/ListAction.java6
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGateActionsSupport.java54
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGateWsModule.java1
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsSupport.java19
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/ShowAction.java6
-rw-r--r--server/sonar-webserver-webapi/src/main/resources/org/sonar/server/qualitygate/ws/list-example.json6
-rw-r--r--server/sonar-webserver-webapi/src/main/resources/org/sonar/server/qualitygate/ws/show-example.json3
-rw-r--r--server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/QualityGateWsModuleTest.java2
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);
}
}