aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZipeng WU <zipeng.wu@sonarsource.com>2023-06-09 15:30:19 +0200
committersonartech <sonartech@sonarsource.com>2023-06-14 09:51:06 +0000
commit451a379605676df360745519038b5ae2770a00ea (patch)
treeecf9402f3ec708c4f4137de3c563a263adb2aa04
parent32d9d255b2704696c3ab4aabcd2e443563c1f945 (diff)
downloadsonarqube-451a379605676df360745519038b5ae2770a00ea.tar.gz
sonarqube-451a379605676df360745519038b5ae2770a00ea.zip
SONAR-19454 Update the api/alm_integrations/import_gitlab_project API (#8493)
Co-authored-by: Nolwenn Cadic <nolwenn.cadic@sonarsource.com>
-rw-r--r--server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/gitlab/ImportGitLabProjectActionIT.java92
-rw-r--r--server/sonar-webserver-webapi/src/it/java/org/sonar/server/newcodeperiod/NewCodeDefinitionResolverTest.java148
-rw-r--r--server/sonar-webserver-webapi/src/it/java/org/sonar/server/newcodeperiod/NewCodePeriodUtilsTest.java217
-rw-r--r--server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/CreateActionIT.java9
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/gitlab/ImportGitLabProjectAction.java51
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/newcodeperiod/NewCodeDefinitionResolver.java148
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/newcodeperiod/NewCodePeriodUtils.java190
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/newcodeperiod/ws/SetAction.java126
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/CreateAction.java62
-rw-r--r--server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java2
10 files changed, 569 insertions, 476 deletions
diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/gitlab/ImportGitLabProjectActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/gitlab/ImportGitLabProjectActionIT.java
index 17c8b80921f..a2748b8af42 100644
--- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/gitlab/ImportGitLabProjectActionIT.java
+++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/gitlab/ImportGitLabProjectActionIT.java
@@ -29,10 +29,13 @@ import org.sonar.alm.client.gitlab.GitlabHttpClient;
import org.sonar.alm.client.gitlab.Project;
import org.sonar.api.utils.System2;
import org.sonar.core.i18n.I18n;
+import org.sonar.core.platform.EditionProvider;
+import org.sonar.core.platform.PlatformEditionProvider;
import org.sonar.core.util.SequenceUuidFactory;
import org.sonar.db.DbTester;
import org.sonar.db.alm.setting.AlmSettingDto;
import org.sonar.db.component.BranchDto;
+import org.sonar.db.newcodeperiod.NewCodePeriodDto;
import org.sonar.db.project.ProjectDto;
import org.sonar.db.user.UserDto;
import org.sonar.server.almintegration.ws.ImportHelper;
@@ -40,6 +43,7 @@ import org.sonar.server.almintegration.ws.ProjectKeyGenerator;
import org.sonar.server.component.ComponentUpdater;
import org.sonar.server.es.TestProjectIndexers;
import org.sonar.server.favorite.FavoriteUpdater;
+import org.sonar.server.newcodeperiod.NewCodeDefinitionResolver;
import org.sonar.server.permission.PermissionTemplateService;
import org.sonar.server.project.DefaultBranchNameResolver;
import org.sonar.server.project.ProjectDefaultVisibility;
@@ -58,8 +62,11 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.sonar.db.component.BranchDto.DEFAULT_MAIN_BRANCH_NAME;
+import static org.sonar.db.newcodeperiod.NewCodePeriodType.NUMBER_OF_DAYS;
import static org.sonar.db.permission.GlobalPermission.PROVISION_PROJECTS;
import static org.sonar.server.tester.UserSessionRule.standalone;
+import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NEW_CODE_DEFINITION_TYPE;
+import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NEW_CODE_DEFINITION_VALUE;
public class ImportGitLabProjectActionIT {
@@ -83,8 +90,11 @@ public class ImportGitLabProjectActionIT {
private final ImportHelper importHelper = new ImportHelper(db.getDbClient(), userSession);
private final ProjectDefaultVisibility projectDefaultVisibility = mock(ProjectDefaultVisibility.class);
private final ProjectKeyGenerator projectKeyGenerator = mock(ProjectKeyGenerator.class);
+ private PlatformEditionProvider editionProvider = mock(PlatformEditionProvider.class);
+ private NewCodeDefinitionResolver newCodeDefinitionResolver = new NewCodeDefinitionResolver(db.getDbClient(), editionProvider);
private final ImportGitLabProjectAction importGitLabProjectAction = new ImportGitLabProjectAction(
- db.getDbClient(), userSession, projectDefaultVisibility, gitlabHttpClient, componentUpdater, importHelper, projectKeyGenerator);
+ db.getDbClient(), userSession, projectDefaultVisibility, gitlabHttpClient, componentUpdater, importHelper, projectKeyGenerator, newCodeDefinitionResolver,
+ defaultBranchNameResolver);
private final WsActionTester ws = new WsActionTester(importGitLabProjectAction);
@Before
@@ -94,7 +104,9 @@ public class ImportGitLabProjectActionIT {
}
@Test
- public void import_project() {
+ public void import_project_developer_edition() {
+ when(editionProvider.get()).thenReturn(Optional.of(EditionProvider.Edition.DEVELOPER));
+
UserDto user = db.users().insertUser();
userSession.logIn(user).addPermission(PROVISION_PROJECTS);
AlmSettingDto almSetting = db.almSettings().insertGitlabAlmSetting();
@@ -111,6 +123,8 @@ public class ImportGitLabProjectActionIT {
Projects.CreateWsResponse response = ws.newRequest()
.setParam("almSetting", almSetting.getKey())
.setParam("gitlabProjectId", "12345")
+ .setParam(PARAM_NEW_CODE_DEFINITION_TYPE, "NUMBER_OF_DAYS")
+ .setParam(PARAM_NEW_CODE_DEFINITION_VALUE, "30")
.executeProtobuf(Projects.CreateWsResponse.class);
verify(gitlabHttpClient).getProject(almSetting.getUrl(), "PAT", 12345L);
@@ -122,6 +136,48 @@ public class ImportGitLabProjectActionIT {
Optional<ProjectDto> projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey());
assertThat(projectDto).isPresent();
assertThat(db.getDbClient().projectAlmSettingDao().selectByProject(db.getSession(), projectDto.get())).isPresent();
+
+ assertThat(db.getDbClient().newCodePeriodDao().selectByProject(db.getSession(), projectDto.get().getUuid()))
+ .isPresent()
+ .get()
+ .extracting(NewCodePeriodDto::getType, NewCodePeriodDto::getValue, NewCodePeriodDto::getBranchUuid)
+ .containsExactly(NUMBER_OF_DAYS, "30", null);
+ }
+
+ @Test
+ public void import_project_community_edition() {
+ when(editionProvider.get()).thenReturn(Optional.of(EditionProvider.Edition.COMMUNITY));
+
+ UserDto user = db.users().insertUser();
+ userSession.logIn(user).addPermission(PROVISION_PROJECTS);
+ AlmSettingDto almSetting = db.almSettings().insertGitlabAlmSetting();
+ db.almPats().insert(dto -> {
+ dto.setAlmSettingUuid(almSetting.getUuid());
+ dto.setUserUuid(user.getUuid());
+ dto.setPersonalAccessToken("PAT");
+ });
+ Project project = getGitlabProject();
+ when(gitlabHttpClient.getProject(any(), any(), any())).thenReturn(project);
+ when(gitlabHttpClient.getBranches(any(), any(), any())).thenReturn(singletonList(new GitLabBranch("master", true)));
+ when(projectKeyGenerator.generateUniqueProjectKey(project.getPathWithNamespace())).thenReturn(PROJECT_KEY_NAME);
+
+ Projects.CreateWsResponse response = ws.newRequest()
+ .setParam("almSetting", almSetting.getKey())
+ .setParam("gitlabProjectId", "12345")
+ .setParam(PARAM_NEW_CODE_DEFINITION_TYPE, "NUMBER_OF_DAYS")
+ .setParam(PARAM_NEW_CODE_DEFINITION_VALUE, "30")
+ .executeProtobuf(Projects.CreateWsResponse.class);
+
+ Projects.CreateWsResponse.Project result = response.getProject();
+
+ Optional<ProjectDto> projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey());
+
+ String projectUuid = projectDto.get().getUuid();
+ assertThat(db.getDbClient().newCodePeriodDao().selectByBranch(db.getSession(), projectUuid, projectUuid))
+ .isPresent()
+ .get()
+ .extracting(NewCodePeriodDto::getType, NewCodePeriodDto::getValue, NewCodePeriodDto::getBranchUuid)
+ .containsExactly(NUMBER_OF_DAYS, "30", projectUuid);
}
@Test
@@ -197,6 +253,38 @@ public class ImportGitLabProjectActionIT {
}
+ @Test
+ public void import_project_without_NCD() {
+ UserDto user = db.users().insertUser();
+ userSession.logIn(user).addPermission(PROVISION_PROJECTS);
+ AlmSettingDto almSetting = db.almSettings().insertGitlabAlmSetting();
+ db.almPats().insert(dto -> {
+ dto.setAlmSettingUuid(almSetting.getUuid());
+ dto.setUserUuid(user.getUuid());
+ dto.setPersonalAccessToken("PAT");
+ });
+ Project project = getGitlabProject();
+ when(gitlabHttpClient.getProject(any(), any(), any())).thenReturn(project);
+ when(gitlabHttpClient.getBranches(any(), any(), any())).thenReturn(singletonList(new GitLabBranch("master", true)));
+ when(projectKeyGenerator.generateUniqueProjectKey(project.getPathWithNamespace())).thenReturn(PROJECT_KEY_NAME);
+
+ Projects.CreateWsResponse response = ws.newRequest()
+ .setParam("almSetting", almSetting.getKey())
+ .setParam("gitlabProjectId", "12345")
+ .executeProtobuf(Projects.CreateWsResponse.class);
+
+ verify(gitlabHttpClient).getProject(almSetting.getUrl(), "PAT", 12345L);
+
+ Projects.CreateWsResponse.Project result = response.getProject();
+ assertThat(result.getKey()).isEqualTo(PROJECT_KEY_NAME);
+ assertThat(result.getName()).isEqualTo(project.getName());
+
+ Optional<ProjectDto> projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey());
+ assertThat(projectDto).isPresent();
+ assertThat(db.getDbClient().projectAlmSettingDao().selectByProject(db.getSession(), projectDto.get())).isPresent();
+ }
+
+
private Project getGitlabProject() {
return new Project(randomAlphanumeric(5), randomAlphanumeric(5));
}
diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/newcodeperiod/NewCodeDefinitionResolverTest.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/newcodeperiod/NewCodeDefinitionResolverTest.java
new file mode 100644
index 00000000000..8aa503e2eaa
--- /dev/null
+++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/newcodeperiod/NewCodeDefinitionResolverTest.java
@@ -0,0 +1,148 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.newcodeperiod;
+
+import java.util.Optional;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.utils.System2;
+import org.sonar.core.platform.PlatformEditionProvider;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.DbTester;
+import org.sonar.db.component.ComponentDbTester;
+import org.sonar.db.newcodeperiod.NewCodePeriodDto;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatNoException;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.mock;
+import static org.sonar.db.newcodeperiod.NewCodePeriodType.NUMBER_OF_DAYS;
+import static org.sonar.db.newcodeperiod.NewCodePeriodType.PREVIOUS_VERSION;
+import static org.sonar.db.newcodeperiod.NewCodePeriodType.REFERENCE_BRANCH;
+import static org.sonar.db.newcodeperiod.NewCodePeriodType.SPECIFIC_ANALYSIS;
+
+public class NewCodeDefinitionResolverTest {
+
+ @Rule
+ public DbTester db = DbTester.create(System2.INSTANCE, true);
+
+ private static final String DEFAULT_PROJECT_ID = "12345";
+
+ private static final String MAIN_BRANCH = "main";
+ private ComponentDbTester componentDb = new ComponentDbTester(db);
+
+ private DbSession dbSession = db.getSession();
+ private DbClient dbClient = db.getDbClient();
+ private PlatformEditionProvider editionProvider = mock(PlatformEditionProvider.class);
+ private NewCodeDefinitionResolver newCodeDefinitionResolver = new NewCodeDefinitionResolver(db.getDbClient(), editionProvider);
+
+ @Test
+ public void createNewCodeDefinition_throw_IAE_if_no_valid_type() {
+ assertThatThrownBy(() -> newCodeDefinitionResolver.createNewCodeDefinition(dbSession, DEFAULT_PROJECT_ID, MAIN_BRANCH, "nonValid", null))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Invalid type: nonValid");
+ }
+
+ @Test
+ public void createNewCodeDefinition_throw_IAE_if_type_is_not_allowed() {
+ assertThatThrownBy(() -> newCodeDefinitionResolver.createNewCodeDefinition(dbSession, DEFAULT_PROJECT_ID, MAIN_BRANCH, SPECIFIC_ANALYSIS.name(), null))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Invalid type 'SPECIFIC_ANALYSIS'. `newCodeDefinitionType` can only be set with types: [PREVIOUS_VERSION, NUMBER_OF_DAYS, REFERENCE_BRANCH]");
+ }
+
+ @Test
+ public void createNewCodeDefinition_throw_IAE_if_no_value_for_days() {
+ assertThatThrownBy(() -> newCodeDefinitionResolver.createNewCodeDefinition(dbSession, DEFAULT_PROJECT_ID, MAIN_BRANCH, NUMBER_OF_DAYS.name(), null))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("New code definition type 'NUMBER_OF_DAYS' requires a newCodeDefinitionValue");
+ }
+
+ @Test
+ public void createNewCodeDefinition_throw_IAE_if_days_is_invalid() {
+ assertThatThrownBy(() -> newCodeDefinitionResolver.createNewCodeDefinition(dbSession, DEFAULT_PROJECT_ID, MAIN_BRANCH, NUMBER_OF_DAYS.name(), "unknown"))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Failed to parse number of days: unknown");
+ }
+
+ @Test
+ public void createNewCodeDefinition_throw_IAE_if_value_is_set_for_reference_branch() {
+ assertThatThrownBy(() -> newCodeDefinitionResolver.createNewCodeDefinition(dbSession, DEFAULT_PROJECT_ID, MAIN_BRANCH, REFERENCE_BRANCH.name(), "feature/zw"))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Unexpected value for newCodeDefinitionType 'REFERENCE_BRANCH'");
+ }
+
+ @Test
+ public void createNewCodeDefinition_throw_IAE_if_previous_version_type_and_value_provided() {
+ assertThatThrownBy(() -> newCodeDefinitionResolver.createNewCodeDefinition(dbSession, DEFAULT_PROJECT_ID, MAIN_BRANCH, PREVIOUS_VERSION.name(), "10.2.3"))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Unexpected value for newCodeDefinitionType 'PREVIOUS_VERSION'");
+ }
+
+ @Test
+ public void createNewCodeDefinition_persist_previous_version_type() {
+ newCodeDefinitionResolver.createNewCodeDefinition(dbSession, DEFAULT_PROJECT_ID, MAIN_BRANCH, PREVIOUS_VERSION.name(), null);
+
+ Optional<NewCodePeriodDto> newCodePeriodDto = dbClient.newCodePeriodDao().selectByProject(dbSession, DEFAULT_PROJECT_ID);
+ assertThat(newCodePeriodDto).map(NewCodePeriodDto::getType).hasValue(PREVIOUS_VERSION);
+ }
+
+ @Test
+ public void createNewCodeDefinition_return_days_value_for_number_of_days_type() {
+ String numberOfDays = "30";
+
+ newCodeDefinitionResolver.createNewCodeDefinition(dbSession, DEFAULT_PROJECT_ID, MAIN_BRANCH, NUMBER_OF_DAYS.name(), numberOfDays);
+
+ Optional<NewCodePeriodDto> newCodePeriodDto = dbClient.newCodePeriodDao().selectByProject(dbSession, DEFAULT_PROJECT_ID);
+
+ assertThat(newCodePeriodDto)
+ .isPresent()
+ .get()
+ .extracting(NewCodePeriodDto::getType, NewCodePeriodDto::getValue)
+ .containsExactly(NUMBER_OF_DAYS, numberOfDays);
+ }
+
+ @Test
+ public void createNewCodeDefinition_return_branch_value_for_reference_branch_type() {
+ newCodeDefinitionResolver.createNewCodeDefinition(dbSession, DEFAULT_PROJECT_ID, MAIN_BRANCH, REFERENCE_BRANCH.name(), null);
+
+ Optional<NewCodePeriodDto> newCodePeriodDto = dbClient.newCodePeriodDao().selectByProject(dbSession, DEFAULT_PROJECT_ID);
+
+ assertThat(newCodePeriodDto)
+ .isPresent()
+ .get()
+ .extracting(NewCodePeriodDto::getType, NewCodePeriodDto::getValue)
+ .containsExactly(REFERENCE_BRANCH, MAIN_BRANCH);
+ }
+
+ @Test
+ public void checkNewCodeDefinitionParam_throw_IAE_if_newCodeDefinitionValue_is_provided_without_newCodeDefinitionType() {
+ assertThatThrownBy(() -> newCodeDefinitionResolver.checkNewCodeDefinitionParam(null, "anyvalue"))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("New code definition type is required when new code definition value is provided");
+ }
+
+ @Test
+ public void checkNewCodeDefinitionParam_do_not_throw_when_both_value_and_type_are_provided() {
+ assertThatNoException()
+ .isThrownBy(() -> newCodeDefinitionResolver.checkNewCodeDefinitionParam("PREVIOUS_VERSION", "anyvalue"));
+ }
+
+}
diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/newcodeperiod/NewCodePeriodUtilsTest.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/newcodeperiod/NewCodePeriodUtilsTest.java
deleted file mode 100644
index 088b98769b8..00000000000
--- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/newcodeperiod/NewCodePeriodUtilsTest.java
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.newcodeperiod;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.utils.System2;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.db.DbTester;
-import org.sonar.db.component.BranchDto;
-import org.sonar.db.component.ComponentDbTester;
-import org.sonar.db.component.ComponentDto;
-import org.sonar.db.component.SnapshotDto;
-import org.sonar.db.project.ProjectDto;
-
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
-import static org.sonar.db.newcodeperiod.NewCodePeriodType.NUMBER_OF_DAYS;
-import static org.sonar.db.newcodeperiod.NewCodePeriodType.PREVIOUS_VERSION;
-import static org.sonar.db.newcodeperiod.NewCodePeriodType.REFERENCE_BRANCH;
-import static org.sonar.db.newcodeperiod.NewCodePeriodType.SPECIFIC_ANALYSIS;
-import static org.sonar.server.newcodeperiod.NewCodePeriodUtils.getNewCodeDefinitionValue;
-import static org.sonar.server.newcodeperiod.NewCodePeriodUtils.getNewCodeDefinitionValueProjectCreation;
-import static org.sonar.server.newcodeperiod.NewCodePeriodUtils.validateType;
-
-public class NewCodePeriodUtilsTest {
-
- @Rule
- public DbTester db = DbTester.create(System2.INSTANCE, true);
-
- private static final String MAIN_BRANCH = "main";
- private ComponentDbTester componentDb = new ComponentDbTester(db);
-
- private DbSession dbSession = db.getSession();
- private DbClient dbClient = db.getDbClient();
- @Test
- public void validateType_throw_IAE_if_no_valid_type() {
- assertThatThrownBy(() -> validateType("nonValid", false, false))
- .isInstanceOf(IllegalArgumentException.class)
- .hasMessageContaining("Invalid type: nonValid");
- }
-
- @Test
- public void validateType_throw_IAE_if_type_is_invalid_for_global() {
- assertThatThrownBy(() -> validateType("SPECIFIC_ANALYSIS", true, false))
- .isInstanceOf(IllegalArgumentException.class)
- .hasMessageContaining("Invalid type 'SPECIFIC_ANALYSIS'. Overall setting can only be set with types: [PREVIOUS_VERSION, NUMBER_OF_DAYS]");
- }
-
- @Test
- public void validateType_throw_IAE_if_type_is_invalid_for_project() {
- assertThatThrownBy(() -> validateType("SPECIFIC_ANALYSIS", false, false))
- .isInstanceOf(IllegalArgumentException.class)
- .hasMessageContaining("Invalid type 'SPECIFIC_ANALYSIS'. Projects can only be set with types: [PREVIOUS_VERSION, NUMBER_OF_DAYS, REFERENCE_BRANCH]");
- }
-
- @Test
- public void validateType_return_type_for_branch() {
- assertThat(validateType("REFERENCE_BRANCH", false, true)).isEqualTo(REFERENCE_BRANCH);
- }
-
- @Test
- public void validateType_return_type_for_project() {
- assertThat(validateType("REFERENCE_BRANCH", false, false)).isEqualTo(REFERENCE_BRANCH);
- }
-
- @Test
- public void validateType_return_type_for_overall() {
- assertThat(validateType("PREVIOUS_VERSION", true, false)).isEqualTo(PREVIOUS_VERSION);
- }
-
- @Test
- public void getNCDValue_throw_IAE_if_no_value_for_days() {
- assertThatThrownBy(() -> getNewCodeDefinitionValue(dbSession, dbClient, NUMBER_OF_DAYS, null, null, null))
- .isInstanceOf(IllegalArgumentException.class)
- .hasMessageContaining("New code definition type 'NUMBER_OF_DAYS' requires a value");
- }
-
- @Test
- public void getNCDValue_throw_IAE_if_no_value_for_reference_branch() {
- assertThatThrownBy(() -> getNewCodeDefinitionValue(dbSession, dbClient, REFERENCE_BRANCH, null, null, null))
- .isInstanceOf(IllegalArgumentException.class)
- .hasMessageContaining("New code definition type 'REFERENCE_BRANCH' requires a value");
- }
-
- @Test
- public void getNCDValue_throw_IAE_if_no_value_for_analysis() {
- assertThatThrownBy(() -> getNewCodeDefinitionValue(dbSession, dbClient, SPECIFIC_ANALYSIS, null, null, null))
- .isInstanceOf(IllegalArgumentException.class)
- .hasMessageContaining("New code definition type 'SPECIFIC_ANALYSIS' requires a value");
- }
-
- @Test
- public void getNCDValue_throw_IAE_if_days_is_invalid() {
- assertThatThrownBy(() -> getNewCodeDefinitionValue(dbSession, dbClient, NUMBER_OF_DAYS, null, null, "unknown"))
- .isInstanceOf(IllegalArgumentException.class)
- .hasMessageContaining("Failed to parse number of days: unknown");
- }
-
- @Test
- public void getNCDValue_throw_IAE_if_previous_version_type_and_value_provided() {
- assertThatThrownBy(() -> getNewCodeDefinitionValue(dbSession, dbClient, PREVIOUS_VERSION, null, null, "someValue"))
- .isInstanceOf(IllegalArgumentException.class)
- .hasMessageContaining("Unexpected value for type 'PREVIOUS_VERSION'");
- }
-
- @Test
- public void getNCDValue_return_empty_for_previous_version_type() {
- assertThat(getNewCodeDefinitionValue(dbSession, dbClient, PREVIOUS_VERSION, null, null, null)).isEmpty();
- }
-
- @Test
- public void getNCDValue_return_days_value_for_number_of_days_type() {
- String numberOfDays = "30";
-
- assertThat(getNewCodeDefinitionValue(dbSession, dbClient, NUMBER_OF_DAYS, null, null, numberOfDays))
- .isPresent()
- .get()
- .isEqualTo(numberOfDays);
- }
-
- @Test
- public void getNCDValue_return_specific_analysis_uuid_for_specific_analysis_type() {
- ComponentDto project = componentDb.insertPublicProject().getMainBranchComponent();
- SnapshotDto analysisMaster = db.components().insertSnapshot(project);
- ProjectDto projectDto = new ProjectDto().setUuid(project.uuid());
- BranchDto branchDto = new BranchDto().setUuid(project.uuid());
- String numberOfDays = "30";
-
- assertThat(getNewCodeDefinitionValue(dbSession, dbClient, SPECIFIC_ANALYSIS, projectDto, branchDto, analysisMaster.getUuid()))
- .isPresent()
- .get()
- .isEqualTo(analysisMaster.getUuid());
- }
-
- @Test
- public void getNCDValue_return_branch_value_for_reference_branch_type() {
- String branchKey = "main";
-
- assertThat(getNewCodeDefinitionValue(dbSession, dbClient, REFERENCE_BRANCH, null, null, branchKey))
- .isPresent()
- .get()
- .isEqualTo(branchKey);
- }
-
- @Test
- public void getNCDValueProjectCreation_throw_IAE_if_no_value_for_days() {
- assertThatThrownBy(() -> getNewCodeDefinitionValueProjectCreation(NUMBER_OF_DAYS, null, MAIN_BRANCH))
- .isInstanceOf(IllegalArgumentException.class)
- .hasMessageContaining("New code definition type 'NUMBER_OF_DAYS' requires a value");
- }
-
- @Test
- public void getNCDValueProjectCreation_throw_IAE_if_days_is_invalid() {
- assertThatThrownBy(() -> getNewCodeDefinitionValueProjectCreation(NUMBER_OF_DAYS, "unknown", MAIN_BRANCH))
- .isInstanceOf(IllegalArgumentException.class)
- .hasMessageContaining("Failed to parse number of days: unknown");
- }
-
- @Test
- public void getNCDValueProjectCreation_throw_IAE_if_previous_version_type_and_value_provided() {
- assertThatThrownBy(() -> getNewCodeDefinitionValueProjectCreation(PREVIOUS_VERSION, "someValue", MAIN_BRANCH))
- .isInstanceOf(IllegalArgumentException.class)
- .hasMessageContaining("Unexpected value for type 'PREVIOUS_VERSION'");
- }
-
- @Test
- public void getNCDValueProjectCreation_return_empty_for_previous_version_type() {
- assertThat(getNewCodeDefinitionValueProjectCreation(PREVIOUS_VERSION, null, MAIN_BRANCH)).isEmpty();
- }
-
- @Test
- public void getNCDValueProjectCreation_return_days_value_for_number_of_days_type() {
- String numberOfDays = "30";
-
- assertThat(getNewCodeDefinitionValueProjectCreation(NUMBER_OF_DAYS, numberOfDays, MAIN_BRANCH))
- .isPresent()
- .get()
- .isEqualTo(numberOfDays);
- }
-
- @Test
- public void getNCDValueProjectCreation_return_branch_value_for_reference_branch_type() {
- String branchKey = "main";
-
- assertThat(getNewCodeDefinitionValueProjectCreation(REFERENCE_BRANCH, null, branchKey))
- .isPresent()
- .get()
- .isEqualTo(branchKey);
- }
-
- @Test
- public void getNCDValueProjectCreation_throw_IAE_fiif_reference_branch_type_and_value_provided() {
- assertThatThrownBy(() -> getNewCodeDefinitionValueProjectCreation(REFERENCE_BRANCH, "someValue", MAIN_BRANCH))
- .isInstanceOf(IllegalArgumentException.class)
- .hasMessageContaining("Unexpected value for type 'REFERENCE_BRANCH'");
- }
-
-}
diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/CreateActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/CreateActionIT.java
index dcfa88bdd86..9b4128ae968 100644
--- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/CreateActionIT.java
+++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/CreateActionIT.java
@@ -43,6 +43,7 @@ import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.favorite.FavoriteUpdater;
import org.sonar.server.l18n.I18nRule;
+import org.sonar.server.newcodeperiod.NewCodeDefinitionResolver;
import org.sonar.server.permission.PermissionTemplateService;
import org.sonar.server.project.DefaultBranchNameResolver;
import org.sonar.server.project.ProjectDefaultVisibility;
@@ -66,8 +67,8 @@ import static org.sonar.db.component.BranchDto.DEFAULT_MAIN_BRANCH_NAME;
import static org.sonar.db.newcodeperiod.NewCodePeriodType.NUMBER_OF_DAYS;
import static org.sonar.db.newcodeperiod.NewCodePeriodType.REFERENCE_BRANCH;
import static org.sonar.db.permission.GlobalPermission.PROVISION_PROJECTS;
-import static org.sonar.server.newcodeperiod.NewCodePeriodUtils.NEW_CODE_PERIOD_TYPE_DESCRIPTION_PROJECT_CREATION;
-import static org.sonar.server.newcodeperiod.NewCodePeriodUtils.NEW_CODE_PERIOD_VALUE_DESCRIPTION_PROJECT_CREATION;
+import static org.sonar.server.newcodeperiod.NewCodeDefinitionResolver.NEW_CODE_PERIOD_TYPE_DESCRIPTION_PROJECT_CREATION;
+import static org.sonar.server.newcodeperiod.NewCodeDefinitionResolver.NEW_CODE_PERIOD_VALUE_DESCRIPTION_PROJECT_CREATION;
import static org.sonar.server.project.Visibility.PRIVATE;
import static org.sonar.test.JsonAssert.assertJson;
import static org.sonarqube.ws.client.WsRequest.Method.POST;
@@ -99,12 +100,14 @@ public class CreateActionIT {
private final PermissionTemplateService permissionTemplateService = mock(PermissionTemplateService.class);
private PlatformEditionProvider editionProvider = mock(PlatformEditionProvider.class);
+
+ private NewCodeDefinitionResolver newCodeDefinitionResolver = new NewCodeDefinitionResolver(db.getDbClient(), editionProvider);
private final WsActionTester ws = new WsActionTester(
new CreateAction(
db.getDbClient(), userSession,
new ComponentUpdater(db.getDbClient(), i18n, system2, permissionTemplateService, new FavoriteUpdater(db.getDbClient()),
projectIndexers, new SequenceUuidFactory(), defaultBranchNameResolver, true),
- projectDefaultVisibility, editionProvider, defaultBranchNameResolver));
+ projectDefaultVisibility, defaultBranchNameResolver, newCodeDefinitionResolver));
@Before
public void before() {
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/gitlab/ImportGitLabProjectAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/gitlab/ImportGitLabProjectAction.java
index d6032ea42b5..e895173cf7d 100644
--- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/gitlab/ImportGitLabProjectAction.java
+++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/gitlab/ImportGitLabProjectAction.java
@@ -21,6 +21,7 @@ package org.sonar.server.almintegration.ws.gitlab;
import java.util.Optional;
import javax.annotation.Nullable;
+import javax.inject.Inject;
import org.sonar.alm.client.gitlab.GitLabBranch;
import org.sonar.alm.client.gitlab.GitlabHttpClient;
import org.sonar.alm.client.gitlab.Project;
@@ -38,6 +39,8 @@ import org.sonar.server.almintegration.ws.ImportHelper;
import org.sonar.server.almintegration.ws.ProjectKeyGenerator;
import org.sonar.server.component.ComponentCreationData;
import org.sonar.server.component.ComponentUpdater;
+import org.sonar.server.newcodeperiod.NewCodeDefinitionResolver;
+import org.sonar.server.project.DefaultBranchNameResolver;
import org.sonar.server.project.ProjectDefaultVisibility;
import org.sonar.server.user.UserSession;
import org.sonarqube.ws.Projects.CreateWsResponse;
@@ -45,7 +48,12 @@ import org.sonarqube.ws.Projects.CreateWsResponse;
import static java.util.Objects.requireNonNull;
import static org.sonar.api.resources.Qualifiers.PROJECT;
import static org.sonar.server.component.NewComponent.newComponentBuilder;
+import static org.sonar.server.newcodeperiod.NewCodeDefinitionResolver.NEW_CODE_PERIOD_TYPE_DESCRIPTION_PROJECT_CREATION;
+import static org.sonar.server.newcodeperiod.NewCodeDefinitionResolver.NEW_CODE_PERIOD_VALUE_DESCRIPTION_PROJECT_CREATION;
+import static org.sonar.server.newcodeperiod.NewCodeDefinitionResolver.checkNewCodeDefinitionParam;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
+import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NEW_CODE_DEFINITION_TYPE;
+import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NEW_CODE_DEFINITION_VALUE;
public class ImportGitLabProjectAction implements AlmIntegrationsWsAction {
@@ -58,10 +66,14 @@ public class ImportGitLabProjectAction implements AlmIntegrationsWsAction {
private final ComponentUpdater componentUpdater;
private final ImportHelper importHelper;
private final ProjectKeyGenerator projectKeyGenerator;
+ private final NewCodeDefinitionResolver newCodeDefinitionResolver;
+ private final DefaultBranchNameResolver defaultBranchNameResolver;
+ @Inject
public ImportGitLabProjectAction(DbClient dbClient, UserSession userSession,
ProjectDefaultVisibility projectDefaultVisibility, GitlabHttpClient gitlabHttpClient,
- ComponentUpdater componentUpdater, ImportHelper importHelper, ProjectKeyGenerator projectKeyGenerator) {
+ ComponentUpdater componentUpdater, ImportHelper importHelper, ProjectKeyGenerator projectKeyGenerator, NewCodeDefinitionResolver newCodeDefinitionResolver,
+ DefaultBranchNameResolver defaultBranchNameResolver) {
this.dbClient = dbClient;
this.userSession = userSession;
this.projectDefaultVisibility = projectDefaultVisibility;
@@ -69,6 +81,8 @@ public class ImportGitLabProjectAction implements AlmIntegrationsWsAction {
this.componentUpdater = componentUpdater;
this.importHelper = importHelper;
this.projectKeyGenerator = projectKeyGenerator;
+ this.newCodeDefinitionResolver = newCodeDefinitionResolver;
+ this.defaultBranchNameResolver = defaultBranchNameResolver;
}
@Override
@@ -86,6 +100,14 @@ public class ImportGitLabProjectAction implements AlmIntegrationsWsAction {
action.createParam(PARAM_GITLAB_PROJECT_ID)
.setRequired(true)
.setDescription("GitLab project ID");
+
+ action.createParam(PARAM_NEW_CODE_DEFINITION_TYPE)
+ .setDescription(NEW_CODE_PERIOD_TYPE_DESCRIPTION_PROJECT_CREATION)
+ .setSince("10.1");
+
+ action.createParam(PARAM_NEW_CODE_DEFINITION_VALUE)
+ .setDescription(NEW_CODE_PERIOD_VALUE_DESCRIPTION_PROJECT_CREATION)
+ .setSince("10.1");
}
@Override
@@ -96,12 +118,13 @@ public class ImportGitLabProjectAction implements AlmIntegrationsWsAction {
private CreateWsResponse doHandle(Request request) {
importHelper.checkProvisionProjectPermission();
- AlmSettingDto almSettingDto = importHelper.getAlmSetting(request);
- String userUuid = importHelper.getUserUuid();
+
+ String newCodeDefinitionType = request.param(PARAM_NEW_CODE_DEFINITION_TYPE);
+ String newCodeDefinitionValue = request.param(PARAM_NEW_CODE_DEFINITION_VALUE);
+
try (DbSession dbSession = dbClient.openSession(false)) {
- Optional<AlmPatDto> almPatDto = dbClient.almPatDao().selectByUserAndAlmSetting(dbSession, userUuid, almSettingDto);
- String pat = almPatDto.map(AlmPatDto::getPersonalAccessToken)
- .orElseThrow(() -> new IllegalArgumentException(String.format("personal access token for '%s' is missing", almSettingDto.getKey())));
+ AlmSettingDto almSettingDto = importHelper.getAlmSetting(request);
+ String pat = getPat(dbSession, almSettingDto);
long gitlabProjectId = request.mandatoryParamAsLong(PARAM_GITLAB_PROJECT_ID);
@@ -109,15 +132,31 @@ public class ImportGitLabProjectAction implements AlmIntegrationsWsAction {
Project gitlabProject = gitlabHttpClient.getProject(gitlabUrl, pat, gitlabProjectId);
Optional<String> almMainBranchName = getAlmDefaultBranch(pat, gitlabProjectId, gitlabUrl);
+
ComponentCreationData componentCreationData = createProject(dbSession, gitlabProject, almMainBranchName.orElse(null));
ProjectDto projectDto = Optional.ofNullable(componentCreationData.projectDto()).orElseThrow();
populateMRSetting(dbSession, gitlabProjectId, projectDto, almSettingDto);
+
+ checkNewCodeDefinitionParam(newCodeDefinitionType, newCodeDefinitionValue);
+
+ if (newCodeDefinitionType != null) {
+ newCodeDefinitionResolver.createNewCodeDefinition(dbSession, projectDto.getUuid(), almMainBranchName.orElse(defaultBranchNameResolver.getEffectiveMainBranchName()),
+ newCodeDefinitionType, newCodeDefinitionValue);
+ }
+
componentUpdater.commitAndIndex(dbSession, componentCreationData.mainBranchComponent());
return ImportHelper.toCreateResponse(projectDto);
}
}
+ private String getPat(DbSession dbSession, AlmSettingDto almSettingDto) {
+ String userUuid = importHelper.getUserUuid();
+ Optional<AlmPatDto> almPatDto = dbClient.almPatDao().selectByUserAndAlmSetting(dbSession, userUuid, almSettingDto);
+ return almPatDto.map(AlmPatDto::getPersonalAccessToken)
+ .orElseThrow(() -> new IllegalArgumentException(String.format("personal access token for '%s' is missing", almSettingDto.getKey())));
+ }
+
private Optional<String> getAlmDefaultBranch(String pat, long gitlabProjectId, String gitlabUrl) {
Optional<GitLabBranch> almMainBranch = gitlabHttpClient.getBranches(gitlabUrl, pat, gitlabProjectId).stream().filter(GitLabBranch::isDefault).findFirst();
return almMainBranch.map(GitLabBranch::getName);
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/newcodeperiod/NewCodeDefinitionResolver.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/newcodeperiod/NewCodeDefinitionResolver.java
new file mode 100644
index 00000000000..968ffc732c1
--- /dev/null
+++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/newcodeperiod/NewCodeDefinitionResolver.java
@@ -0,0 +1,148 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.newcodeperiod;
+
+import com.google.common.base.Preconditions;
+import java.util.EnumSet;
+import java.util.Locale;
+import java.util.Optional;
+import javax.annotation.Nullable;
+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.newcodeperiod.NewCodePeriodDto;
+import org.sonar.db.newcodeperiod.NewCodePeriodParser;
+import org.sonar.db.newcodeperiod.NewCodePeriodType;
+
+import static org.sonar.db.newcodeperiod.NewCodePeriodType.NUMBER_OF_DAYS;
+import static org.sonar.db.newcodeperiod.NewCodePeriodType.PREVIOUS_VERSION;
+import static org.sonar.db.newcodeperiod.NewCodePeriodType.REFERENCE_BRANCH;
+
+public class NewCodeDefinitionResolver {
+ private static final String BEGIN_LIST = "<ul>";
+
+ private static final String END_LIST = "</ul>";
+ private static final String BEGIN_ITEM_LIST = "<li>";
+ private static final String END_ITEM_LIST = "</li>";
+
+ public static final String NEW_CODE_PERIOD_TYPE_DESCRIPTION_PROJECT_CREATION = "Type<br/>" +
+ "New code definitions of the following types are allowed:" +
+ BEGIN_LIST +
+ BEGIN_ITEM_LIST + PREVIOUS_VERSION.name() + END_ITEM_LIST +
+ BEGIN_ITEM_LIST + NUMBER_OF_DAYS.name() + END_ITEM_LIST +
+ BEGIN_ITEM_LIST + REFERENCE_BRANCH.name() + " - will default to the main branch." + END_ITEM_LIST +
+ END_LIST;
+
+ public static final String NEW_CODE_PERIOD_VALUE_DESCRIPTION_PROJECT_CREATION = "Value<br/>" +
+ "For each new code definition type, a different value is expected:" +
+ BEGIN_LIST +
+ BEGIN_ITEM_LIST + "no value, when the new code definition type is " + PREVIOUS_VERSION.name() + " and " + REFERENCE_BRANCH.name() + END_ITEM_LIST +
+ BEGIN_ITEM_LIST + "a number between 1 and 90, when the new code definition type is " + NUMBER_OF_DAYS.name() + END_ITEM_LIST +
+ END_LIST;
+
+ private static final String UNEXPECTED_VALUE_ERROR_MESSAGE = "Unexpected value for newCodeDefinitionType '%s'";
+
+ private static final EnumSet<NewCodePeriodType> projectCreationNCDTypes = EnumSet.of(PREVIOUS_VERSION, NUMBER_OF_DAYS, REFERENCE_BRANCH);
+
+ private final DbClient dbClient;
+ private final PlatformEditionProvider editionProvider;
+
+ public NewCodeDefinitionResolver(DbClient dbClient, PlatformEditionProvider editionProvider) {
+ this.dbClient = dbClient;
+ this.editionProvider = editionProvider;
+ }
+
+ public void createNewCodeDefinition(DbSession dbSession, String projectUuid, String defaultBranchName, String newCodeDefinitionType, String newCodeDefinitionValue) {
+
+ boolean isCommunityEdition = editionProvider.get().filter(EditionProvider.Edition.COMMUNITY::equals).isPresent();
+ NewCodePeriodType newCodePeriodType = parseNewCodeDefinitionType(newCodeDefinitionType);
+
+ NewCodePeriodDto dto = new NewCodePeriodDto();
+ dto.setType(newCodePeriodType);
+ dto.setProjectUuid(projectUuid);
+
+ if (isCommunityEdition) {
+ dto.setBranchUuid(projectUuid);
+ }
+
+ getNewCodeDefinitionValueProjectCreation(newCodePeriodType, newCodeDefinitionValue, defaultBranchName).ifPresent(dto::setValue);
+
+ if (!CaycUtils.isNewCodePeriodCompliant(dto.getType(), dto.getValue())) {
+ throw new IllegalArgumentException("Failed to set the New Code Definition. The given value is not compatible with the Clean as You Code methodology. "
+ + "Please refer to the documentation for compliant options.");
+ }
+
+ dbClient.newCodePeriodDao().insert(dbSession, dto);
+ }
+
+ public static void checkNewCodeDefinitionParam(String newCodeDefinitionType, String newCodeDefinitionValue) {
+ if (newCodeDefinitionType == null && newCodeDefinitionValue != null) {
+ throw new IllegalArgumentException("New code definition type is required when new code definition value is provided");
+ }
+ }
+
+ private static Optional<String> getNewCodeDefinitionValueProjectCreation(NewCodePeriodType type, @Nullable String value, String defaultBranchName) {
+ return switch (type) {
+ case PREVIOUS_VERSION -> {
+ Preconditions.checkArgument(value == null, UNEXPECTED_VALUE_ERROR_MESSAGE, type);
+ yield Optional.empty();
+ }
+ case NUMBER_OF_DAYS -> {
+ requireValue(type, value);
+ yield Optional.of(parseDays(value));
+ }
+ case REFERENCE_BRANCH -> {
+ Preconditions.checkArgument(value == null, UNEXPECTED_VALUE_ERROR_MESSAGE, type);
+ yield Optional.of(defaultBranchName);
+ }
+ default -> throw new IllegalStateException("Unexpected type: " + type);
+ };
+ }
+
+ private static String parseDays(String value) {
+ try {
+ return Integer.toString(NewCodePeriodParser.parseDays(value));
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Failed to parse number of days: " + value);
+ }
+ }
+
+ private static void requireValue(NewCodePeriodType type, @Nullable String value) {
+ Preconditions.checkArgument(value != null, "New code definition type '%s' requires a newCodeDefinitionValue", type);
+ }
+
+ private static NewCodePeriodType parseNewCodeDefinitionType(String typeStr) {
+ NewCodePeriodType type;
+ try {
+ type = NewCodePeriodType.valueOf(typeStr.toUpperCase(Locale.US));
+ } catch (IllegalArgumentException e) {
+ throw new IllegalArgumentException("Invalid type: " + typeStr);
+ }
+ validateType(type);
+ return type;
+ }
+
+ private static void validateType(NewCodePeriodType type) {
+ Preconditions.checkArgument(projectCreationNCDTypes.contains(type), "Invalid type '%s'. `newCodeDefinitionType` can only be set with types: %s",
+ type, projectCreationNCDTypes);
+ }
+
+}
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/newcodeperiod/NewCodePeriodUtils.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/newcodeperiod/NewCodePeriodUtils.java
deleted file mode 100644
index 0b5703841cd..00000000000
--- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/newcodeperiod/NewCodePeriodUtils.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.newcodeperiod;
-
-import com.google.common.base.Preconditions;
-import java.util.EnumSet;
-import java.util.Locale;
-import java.util.Optional;
-import java.util.Set;
-import javax.annotation.Nullable;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.db.component.BranchDto;
-import org.sonar.db.component.SnapshotDto;
-import org.sonar.db.newcodeperiod.NewCodePeriodParser;
-import org.sonar.db.newcodeperiod.NewCodePeriodType;
-import org.sonar.db.project.ProjectDto;
-import org.sonar.server.exceptions.NotFoundException;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static java.lang.String.format;
-import static org.sonar.db.newcodeperiod.NewCodePeriodType.NUMBER_OF_DAYS;
-import static org.sonar.db.newcodeperiod.NewCodePeriodType.PREVIOUS_VERSION;
-import static org.sonar.db.newcodeperiod.NewCodePeriodType.REFERENCE_BRANCH;
-import static org.sonar.db.newcodeperiod.NewCodePeriodType.SPECIFIC_ANALYSIS;
-
-public interface NewCodePeriodUtils {
- String BEGIN_LIST = "<ul>";
-
- String END_LIST = "</ul>";
- String BEGIN_ITEM_LIST = "<li>";
- String END_ITEM_LIST = "</li>";
- String NEW_CODE_PERIOD_TYPE_DESCRIPTION = "Type<br/>" +
- "New code definitions of the following types are allowed:" +
- BEGIN_LIST +
- BEGIN_ITEM_LIST + SPECIFIC_ANALYSIS.name() + " - can be set at branch level only" + END_ITEM_LIST +
- BEGIN_ITEM_LIST + PREVIOUS_VERSION.name() + " - can be set at any level (global, project, branch)" + END_ITEM_LIST +
- BEGIN_ITEM_LIST + NUMBER_OF_DAYS.name() + " - can be set at any level (global, project, branch)" + END_ITEM_LIST +
- BEGIN_ITEM_LIST + REFERENCE_BRANCH.name() + " - can only be set for projects and branches" + END_ITEM_LIST +
- END_LIST;
-
- String NEW_CODE_PERIOD_TYPE_DESCRIPTION_PROJECT_CREATION = "Type<br/>" +
- "New code definitions of the following types are allowed:" +
- BEGIN_LIST +
- BEGIN_ITEM_LIST + PREVIOUS_VERSION.name() + END_ITEM_LIST +
- BEGIN_ITEM_LIST + NUMBER_OF_DAYS.name() + END_ITEM_LIST +
- BEGIN_ITEM_LIST + REFERENCE_BRANCH.name() + " - will default to the main branch. A new code definition should be set for the branch itself. " +
- "Until you do so, this branch will use itself as a reference branch and no code will be considered new for this branch" + END_ITEM_LIST +
- END_LIST;
-
- String NEW_CODE_PERIOD_VALUE_DESCRIPTION = "Value<br/>" +
- "For each type, a different value is expected:" +
- BEGIN_LIST +
- BEGIN_ITEM_LIST + "the uuid of an analysis, when type is " + SPECIFIC_ANALYSIS.name() + END_ITEM_LIST +
- BEGIN_ITEM_LIST + "no value, when type is " + PREVIOUS_VERSION.name() + END_ITEM_LIST +
- BEGIN_ITEM_LIST + "a number between 1 and 90, when type is " + NUMBER_OF_DAYS.name() + END_ITEM_LIST +
- BEGIN_ITEM_LIST + "a string, when type is " + REFERENCE_BRANCH.name() + END_ITEM_LIST +
- END_LIST;
- String NEW_CODE_PERIOD_VALUE_DESCRIPTION_PROJECT_CREATION = "Value<br/>" +
- "For each type, a different value is expected:" +
- BEGIN_LIST +
- BEGIN_ITEM_LIST + "no value, when type is " + PREVIOUS_VERSION.name() + " and " + REFERENCE_BRANCH.name() + END_ITEM_LIST +
- BEGIN_ITEM_LIST + "a number between 1 and 90, when type is " + NUMBER_OF_DAYS.name() + END_ITEM_LIST +
- END_LIST;
-
- String UNEXPECTED_VALUE_ERROR_MESSAGE = "Unexpected value for type '%s'";
-
- static Optional<String> getNewCodeDefinitionValue(DbSession dbSession, DbClient dbClient, NewCodePeriodType type, @Nullable ProjectDto project,
- @Nullable BranchDto branch, @Nullable String value) {
- switch (type) {
- case PREVIOUS_VERSION:
- Preconditions.checkArgument(value == null, UNEXPECTED_VALUE_ERROR_MESSAGE, type);
- return Optional.empty();
- case NUMBER_OF_DAYS:
- requireValue(type, value);
- return Optional.of(parseDays(value));
- case SPECIFIC_ANALYSIS:
- requireValue(type, value);
- requireBranch(type, branch);
- SnapshotDto analysis = getAnalysis(dbSession, value, project, branch, dbClient);
- return Optional.of(analysis.getUuid());
- case REFERENCE_BRANCH:
- requireValue(type, value);
- return Optional.of(value);
- default:
- throw new IllegalStateException("Unexpected type: " + type);
- }
- }
-
- static Optional<String> getNewCodeDefinitionValueProjectCreation(NewCodePeriodType type, @Nullable String value, String defaultBranchName) {
- switch (type) {
- case PREVIOUS_VERSION:
- Preconditions.checkArgument(value == null, UNEXPECTED_VALUE_ERROR_MESSAGE, type);
- return Optional.empty();
- case NUMBER_OF_DAYS:
- requireValue(type, value);
- return Optional.of(parseDays(value));
- case REFERENCE_BRANCH:
- Preconditions.checkArgument(value == null, UNEXPECTED_VALUE_ERROR_MESSAGE, type);
- return Optional.of(defaultBranchName);
- default:
- throw new IllegalStateException("Unexpected type: " + type);
- }
- }
-
- private static String parseDays(String value) {
- try {
- return Integer.toString(NewCodePeriodParser.parseDays(value));
- } catch (Exception e) {
- throw new IllegalArgumentException("Failed to parse number of days: " + value);
- }
- }
-
- private static void requireValue(NewCodePeriodType type, @Nullable String value) {
- Preconditions.checkArgument(value != null, "New code definition type '%s' requires a value", type);
- }
-
- private static void requireBranch(NewCodePeriodType type, @Nullable BranchDto branch) {
- Preconditions.checkArgument(branch != null, "New code definition type '%s' requires a branch", type);
- }
- private static Set<NewCodePeriodType> getInstanceTypes() {
- return EnumSet.of(PREVIOUS_VERSION, NUMBER_OF_DAYS);
- }
-
- private static Set<NewCodePeriodType> getProjectTypes() {
- return EnumSet.of(PREVIOUS_VERSION, NUMBER_OF_DAYS, REFERENCE_BRANCH);
- }
-
- private static Set<NewCodePeriodType> getBranchTypes() {
- return EnumSet.of(PREVIOUS_VERSION, NUMBER_OF_DAYS, SPECIFIC_ANALYSIS, REFERENCE_BRANCH);
- }
-
- static NewCodePeriodType validateType(String typeStr, boolean isOverall, boolean isBranch) {
- NewCodePeriodType type;
- try {
- type = NewCodePeriodType.valueOf(typeStr.toUpperCase(Locale.US));
- } catch (IllegalArgumentException e) {
- throw new IllegalArgumentException("Invalid type: " + typeStr);
- }
-
- if (isOverall) {
- checkType("Overall setting", getInstanceTypes(), type);
- } else if (isBranch) {
- checkType("Branches", getBranchTypes(), type);
- } else {
- checkType("Projects", getProjectTypes(), type);
- }
- return type;
- }
-
- private static SnapshotDto getAnalysis(DbSession dbSession, String analysisUuid, ProjectDto project, BranchDto branch, DbClient dbClient) {
- SnapshotDto snapshotDto = dbClient.snapshotDao().selectByUuid(dbSession, analysisUuid)
- .orElseThrow(() -> new NotFoundException(format("Analysis '%s' is not found", analysisUuid)));
- checkAnalysis(dbSession, project, branch, snapshotDto, dbClient);
- return snapshotDto;
- }
-
- private static void checkAnalysis(DbSession dbSession, ProjectDto project, BranchDto branch, SnapshotDto analysis, DbClient dbClient) {
- BranchDto analysisBranch = dbClient.branchDao().selectByUuid(dbSession, analysis.getComponentUuid()).orElse(null);
- boolean analysisMatchesProjectBranch = analysisBranch != null && analysisBranch.getUuid().equals(branch.getUuid());
-
- checkArgument(analysisMatchesProjectBranch,
- "Analysis '%s' does not belong to branch '%s' of project '%s'",
- analysis.getUuid(), branch.getKey(), project.getKey());
- }
-
- private static void checkType(String name, Set<NewCodePeriodType> validTypes, NewCodePeriodType type) {
- if (!validTypes.contains(type)) {
- throw new IllegalArgumentException(String.format("Invalid type '%s'. %s can only be set with types: %s", type, name, validTypes));
- }
- }
-
-}
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/newcodeperiod/ws/SetAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/newcodeperiod/ws/SetAction.java
index 899398d7651..3c1b6962f6c 100644
--- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/newcodeperiod/ws/SetAction.java
+++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/newcodeperiod/ws/SetAction.java
@@ -19,8 +19,11 @@
*/
package org.sonar.server.newcodeperiod.ws;
+import com.google.common.base.Preconditions;
import java.util.EnumSet;
+import java.util.Locale;
import java.util.Set;
+import javax.annotation.Nullable;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
@@ -31,8 +34,10 @@ import org.sonar.core.platform.PlatformEditionProvider;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.BranchDto;
+import org.sonar.db.component.SnapshotDto;
import org.sonar.db.newcodeperiod.NewCodePeriodDao;
import org.sonar.db.newcodeperiod.NewCodePeriodDto;
+import org.sonar.db.newcodeperiod.NewCodePeriodParser;
import org.sonar.db.newcodeperiod.NewCodePeriodType;
import org.sonar.db.project.ProjectDto;
import org.sonar.server.component.ComponentFinder;
@@ -40,15 +45,12 @@ import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.newcodeperiod.CaycUtils;
import org.sonar.server.user.UserSession;
+import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.String.format;
import static org.sonar.db.newcodeperiod.NewCodePeriodType.NUMBER_OF_DAYS;
import static org.sonar.db.newcodeperiod.NewCodePeriodType.PREVIOUS_VERSION;
import static org.sonar.db.newcodeperiod.NewCodePeriodType.REFERENCE_BRANCH;
import static org.sonar.db.newcodeperiod.NewCodePeriodType.SPECIFIC_ANALYSIS;
-import static org.sonar.server.newcodeperiod.NewCodePeriodUtils.NEW_CODE_PERIOD_TYPE_DESCRIPTION;
-import static org.sonar.server.newcodeperiod.NewCodePeriodUtils.NEW_CODE_PERIOD_VALUE_DESCRIPTION;
-import static org.sonar.server.newcodeperiod.NewCodePeriodUtils.getNewCodeDefinitionValue;
-import static org.sonar.server.newcodeperiod.NewCodePeriodUtils.validateType;
import static org.sonar.server.ws.WsUtils.createHtmlExternalLink;
public class SetAction implements NewCodePeriodsWsAction {
@@ -63,7 +65,8 @@ public class SetAction implements NewCodePeriodsWsAction {
private static final Set<NewCodePeriodType> OVERALL_TYPES = EnumSet.of(PREVIOUS_VERSION, NUMBER_OF_DAYS);
private static final Set<NewCodePeriodType> PROJECT_TYPES = EnumSet.of(PREVIOUS_VERSION, NUMBER_OF_DAYS, REFERENCE_BRANCH);
- private static final Set<NewCodePeriodType> BRANCH_TYPES = EnumSet.of(PREVIOUS_VERSION, NUMBER_OF_DAYS, SPECIFIC_ANALYSIS, REFERENCE_BRANCH);
+ private static final Set<NewCodePeriodType> BRANCH_TYPES = EnumSet.of(PREVIOUS_VERSION, NUMBER_OF_DAYS, SPECIFIC_ANALYSIS,
+ REFERENCE_BRANCH);
private final DbClient dbClient;
private final UserSession userSession;
@@ -93,7 +96,6 @@ public class SetAction implements NewCodePeriodsWsAction {
"Existing projects or branches having a specific new code definition will not be impacted" + END_ITEM_LIST +
BEGIN_ITEM_LIST + "Project key must be provided to update the value for a project" + END_ITEM_LIST +
BEGIN_ITEM_LIST + "Both project and branch keys must be provided to update the value for a branch" + END_ITEM_LIST +
- BEGIN_ITEM_LIST + "New setting must be compliant with the Clean as You Code methodology" + END_ITEM_LIST +
END_LIST +
"Requires one of the following permissions: " +
BEGIN_LIST +
@@ -109,9 +111,25 @@ public class SetAction implements NewCodePeriodsWsAction {
.setDescription("Branch key");
action.createParam(PARAM_TYPE)
.setRequired(true)
- .setDescription(NEW_CODE_PERIOD_VALUE_DESCRIPTION);
+ .setDescription("Type<br/>" +
+ "New code definitions of the following types are allowed:" +
+ BEGIN_LIST +
+ BEGIN_ITEM_LIST + SPECIFIC_ANALYSIS.name() + " - can be set at branch level only" + END_ITEM_LIST +
+ BEGIN_ITEM_LIST + PREVIOUS_VERSION.name() + " - can be set at any level (global, project, branch)" + END_ITEM_LIST +
+ BEGIN_ITEM_LIST + NUMBER_OF_DAYS.name() + " - can be set at any level (global, project, branch)" + END_ITEM_LIST +
+ BEGIN_ITEM_LIST + REFERENCE_BRANCH.name() + " - can only be set for projects and branches" + END_ITEM_LIST +
+ END_LIST
+ );
action.createParam(PARAM_VALUE)
- .setDescription(NEW_CODE_PERIOD_TYPE_DESCRIPTION);
+ .setDescription("Value<br/>" +
+ "For each type, a different value is expected:" +
+ BEGIN_LIST +
+ BEGIN_ITEM_LIST + "the uuid of an analysis, when type is " + SPECIFIC_ANALYSIS.name() + END_ITEM_LIST +
+ BEGIN_ITEM_LIST + "no value, when type is " + PREVIOUS_VERSION.name() + END_ITEM_LIST +
+ BEGIN_ITEM_LIST + "a number between 1 and 90, when type is " + NUMBER_OF_DAYS.name() + END_ITEM_LIST +
+ BEGIN_ITEM_LIST + "a string, when type is " + REFERENCE_BRANCH.name() + END_ITEM_LIST +
+ END_LIST
+ );
}
@Override
@@ -154,11 +172,11 @@ public class SetAction implements NewCodePeriodsWsAction {
userSession.checkIsSystemAdministrator();
}
- getNewCodeDefinitionValue(dbSession, dbClient, type, project, branch, valueStr).ifPresent(dto::setValue);
+ setValue(dbSession, dto, type, project, branch, valueStr);
if (!CaycUtils.isNewCodePeriodCompliant(dto.getType(), dto.getValue())) {
- throw new IllegalArgumentException("Failed to set the New Code Definition. The given value is not compatible with the Clean as You Code methodology. "
- + "Please refer to the documentation for compliant options.");
+ throw new IllegalArgumentException("Failed to set the New Code Definition. The given value is not compatible with the Clean as " +
+ "You Code methodology. Please refer to the documentation for compliant options.");
}
newCodePeriodDao.upsert(dbSession, dto);
@@ -166,6 +184,52 @@ public class SetAction implements NewCodePeriodsWsAction {
}
}
+ private void setValue(DbSession dbSession, NewCodePeriodDto dto, NewCodePeriodType type, @Nullable ProjectDto project,
+ @Nullable BranchDto branch, @Nullable String value) {
+ switch (type) {
+ case PREVIOUS_VERSION -> Preconditions.checkArgument(value == null, "Unexpected value for type '%s'", type);
+ case NUMBER_OF_DAYS -> {
+ requireValue(type, value);
+ dto.setValue(parseDays(value));
+ }
+ case SPECIFIC_ANALYSIS -> {
+ checkValuesForSpecificBranch(type, value, project, branch);
+ dto.setValue(getAnalysis(dbSession, value, project, branch).getUuid());
+ }
+ case REFERENCE_BRANCH -> {
+ requireValue(type, value);
+ dto.setValue(value);
+ }
+ default -> throw new IllegalStateException("Unexpected type: " + type);
+ }
+ }
+
+ private static void checkValuesForSpecificBranch(NewCodePeriodType type, @Nullable String value, @Nullable ProjectDto project, @Nullable BranchDto branch) {
+ requireValue(type, value);
+ requireProject(type, project);
+ requireBranch(type, branch);
+ }
+
+ private static String parseDays(String value) {
+ try {
+ return Integer.toString(NewCodePeriodParser.parseDays(value));
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Failed to parse number of days: " + value);
+ }
+ }
+
+ private static void requireValue(NewCodePeriodType type, @Nullable String value) {
+ Preconditions.checkArgument(value != null, "New code definition type '%s' requires a value", type);
+ }
+
+ private static void requireBranch(NewCodePeriodType type, @Nullable BranchDto branch) {
+ Preconditions.checkArgument(branch != null, "New code definition type '%s' requires a branch", type);
+ }
+
+ private static void requireProject(NewCodePeriodType type, @Nullable ProjectDto project) {
+ Preconditions.checkArgument(project != null, "New code definition type '%s' requires a project", type);
+ }
+
private BranchDto getBranch(DbSession dbSession, ProjectDto project, String branchKey) {
return dbClient.branchDao().selectByBranchKey(dbSession, project.getUuid(), branchKey)
.orElseThrow(() -> new NotFoundException(format("Branch '%s' in project '%s' not found", branchKey, project.getKey())));
@@ -181,4 +245,44 @@ public class SetAction implements NewCodePeriodsWsAction {
.findFirst()
.orElseThrow(() -> new NotFoundException(format("Main branch in project '%s' is not found", project.getKey())));
}
+
+ private static NewCodePeriodType validateType(String typeStr, boolean isOverall, boolean isBranch) {
+ NewCodePeriodType type;
+ try {
+ type = NewCodePeriodType.valueOf(typeStr.toUpperCase(Locale.US));
+ } catch (IllegalArgumentException e) {
+ throw new IllegalArgumentException("Invalid type: " + typeStr);
+ }
+
+ if (isOverall) {
+ checkType("Overall setting", OVERALL_TYPES, type);
+ } else if (isBranch) {
+ checkType("Branches", BRANCH_TYPES, type);
+ } else {
+ checkType("Projects", PROJECT_TYPES, type);
+ }
+ return type;
+ }
+
+ private SnapshotDto getAnalysis(DbSession dbSession, String analysisUuid, ProjectDto project, BranchDto branch) {
+ SnapshotDto snapshotDto = dbClient.snapshotDao().selectByUuid(dbSession, analysisUuid)
+ .orElseThrow(() -> new NotFoundException(format("Analysis '%s' is not found", analysisUuid)));
+ checkAnalysis(dbSession, project, branch, snapshotDto);
+ return snapshotDto;
+ }
+
+ private void checkAnalysis(DbSession dbSession, ProjectDto project, BranchDto branch, SnapshotDto analysis) {
+ BranchDto analysisBranch = dbClient.branchDao().selectByUuid(dbSession, analysis.getComponentUuid()).orElse(null);
+ boolean analysisMatchesProjectBranch = analysisBranch != null && analysisBranch.getUuid().equals(branch.getUuid());
+
+ checkArgument(analysisMatchesProjectBranch,
+ "Analysis '%s' does not belong to branch '%s' of project '%s'",
+ analysis.getUuid(), branch.getKey(), project.getKey());
+ }
+
+ private static void checkType(String name, Set<NewCodePeriodType> validTypes, NewCodePeriodType type) {
+ if (!validTypes.contains(type)) {
+ throw new IllegalArgumentException(String.format("Invalid type '%s'. %s can only be set with types: %s", type, name, validTypes));
+ }
+ }
}
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/CreateAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/CreateAction.java
index 06278fd680d..49a10dc1336 100644
--- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/CreateAction.java
+++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/CreateAction.java
@@ -26,15 +26,11 @@ import org.sonar.api.server.ws.Change;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
-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.component.ComponentDto;
-import org.sonar.db.newcodeperiod.NewCodePeriodDto;
-import org.sonar.db.newcodeperiod.NewCodePeriodType;
import org.sonar.server.component.ComponentUpdater;
-import org.sonar.server.newcodeperiod.CaycUtils;
+import org.sonar.server.newcodeperiod.NewCodeDefinitionResolver;
import org.sonar.server.project.DefaultBranchNameResolver;
import org.sonar.server.project.ProjectDefaultVisibility;
import org.sonar.server.project.Visibility;
@@ -48,10 +44,9 @@ import static org.sonar.core.component.ComponentKeys.MAX_COMPONENT_KEY_LENGTH;
import static org.sonar.db.component.ComponentValidator.MAX_COMPONENT_NAME_LENGTH;
import static org.sonar.db.permission.GlobalPermission.PROVISION_PROJECTS;
import static org.sonar.server.component.NewComponent.newComponentBuilder;
-import static org.sonar.server.newcodeperiod.NewCodePeriodUtils.NEW_CODE_PERIOD_TYPE_DESCRIPTION_PROJECT_CREATION;
-import static org.sonar.server.newcodeperiod.NewCodePeriodUtils.NEW_CODE_PERIOD_VALUE_DESCRIPTION_PROJECT_CREATION;
-import static org.sonar.server.newcodeperiod.NewCodePeriodUtils.getNewCodeDefinitionValueProjectCreation;
-import static org.sonar.server.newcodeperiod.NewCodePeriodUtils.validateType;
+import static org.sonar.server.newcodeperiod.NewCodeDefinitionResolver.NEW_CODE_PERIOD_TYPE_DESCRIPTION_PROJECT_CREATION;
+import static org.sonar.server.newcodeperiod.NewCodeDefinitionResolver.NEW_CODE_PERIOD_VALUE_DESCRIPTION_PROJECT_CREATION;
+import static org.sonar.server.newcodeperiod.NewCodeDefinitionResolver.checkNewCodeDefinitionParam;
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.ACTION_CREATE;
@@ -68,18 +63,18 @@ public class CreateAction implements ProjectsWsAction {
private final UserSession userSession;
private final ComponentUpdater componentUpdater;
private final ProjectDefaultVisibility projectDefaultVisibility;
- private final PlatformEditionProvider editionProvider;
private final DefaultBranchNameResolver defaultBranchNameResolver;
+ private final NewCodeDefinitionResolver newCodeDefinitionResolver;
+
public CreateAction(DbClient dbClient, UserSession userSession, ComponentUpdater componentUpdater,
- ProjectDefaultVisibility projectDefaultVisibility, PlatformEditionProvider editionProvider,
- DefaultBranchNameResolver defaultBranchNameResolver) {
+ ProjectDefaultVisibility projectDefaultVisibility, DefaultBranchNameResolver defaultBranchNameResolver, NewCodeDefinitionResolver newCodeDefinitionResolver) {
this.dbClient = dbClient;
this.userSession = userSession;
this.componentUpdater = componentUpdater;
this.projectDefaultVisibility = projectDefaultVisibility;
- this.editionProvider = editionProvider;
this.defaultBranchNameResolver = defaultBranchNameResolver;
+ this.newCodeDefinitionResolver = newCodeDefinitionResolver;
}
@Override
@@ -125,7 +120,6 @@ public class CreateAction implements ProjectsWsAction {
action.createParam(PARAM_NEW_CODE_DEFINITION_VALUE)
.setDescription(NEW_CODE_PERIOD_VALUE_DESCRIPTION_PROJECT_CREATION)
.setSince("10.1");
-
}
@Override
@@ -137,21 +131,18 @@ public class CreateAction implements ProjectsWsAction {
private CreateWsResponse doHandle(CreateRequest request) {
try (DbSession dbSession = dbClient.openSession(false)) {
userSession.checkPermission(PROVISION_PROJECTS);
- checkNewCodeDefinitionParam(request);
+ checkNewCodeDefinitionParam(request.getNewCodeDefinitionType(), request.getNewCodeDefinitionValue());
ComponentDto componentDto = createProject(request, dbSession);
- if(request.getNewCodeDefinitionType() != null) {
- createNewCodeDefinition(dbSession, request, componentDto.uuid());
+ if (request.getNewCodeDefinitionType() != null) {
+ String defaultBranchName = Optional.ofNullable(request.getMainBranchKey()).orElse(defaultBranchNameResolver.getEffectiveMainBranchName());
+ newCodeDefinitionResolver.createNewCodeDefinition(dbSession, componentDto.uuid(), defaultBranchName, request.getNewCodeDefinitionType(),
+ request.getNewCodeDefinitionValue());
}
componentUpdater.commitAndIndex(dbSession, componentDto);
return toCreateResponse(componentDto);
}
}
- private static void checkNewCodeDefinitionParam(CreateRequest request) {
- if (request.getNewCodeDefinitionType() == null && request.getNewCodeDefinitionValue() != null) {
- throw new IllegalArgumentException("New code definition type is required when new code definition value is provided");
- }
- }
private ComponentDto createProject(CreateRequest request, DbSession dbSession) {
String visibility = request.getVisibility();
boolean changeToPrivate = visibility == null ? projectDefaultVisibility.get(dbSession).isPrivate() : "private".equals(visibility);
@@ -164,32 +155,9 @@ public class CreateAction implements ProjectsWsAction {
.build(),
userSession.isLoggedIn() ? userSession.getUuid() : null,
userSession.isLoggedIn() ? userSession.getLogin() : null,
- request.getMainBranchKey(), s -> {}).mainBranchComponent();
-
- }
- private void createNewCodeDefinition(DbSession dbSession, CreateRequest request, String projectUuid) {
-
- boolean isCommunityEdition = editionProvider.get().filter(EditionProvider.Edition.COMMUNITY::equals).isPresent();
- NewCodePeriodType newCodePeriodType = validateType(request.getNewCodeDefinitionType(), false, isCommunityEdition);
- String newCodePeriodValue = request.getNewCodeDefinitionValue();
- String defaultBranchName = Optional.ofNullable(request.getMainBranchKey()).orElse(defaultBranchNameResolver.getEffectiveMainBranchName());
-
- NewCodePeriodDto dto = new NewCodePeriodDto();
- dto.setType(newCodePeriodType);
- dto.setProjectUuid(projectUuid);
-
- if (isCommunityEdition) {
- dto.setBranchUuid(projectUuid);
- }
-
- getNewCodeDefinitionValueProjectCreation(newCodePeriodType, newCodePeriodValue, defaultBranchName).ifPresent(dto::setValue);
-
- if (!CaycUtils.isNewCodePeriodCompliant(dto.getType(), dto.getValue())) {
- throw new IllegalArgumentException("Failed to set the New Code Definition. The given value is not compatible with the Clean as You Code methodology. "
- + "Please refer to the documentation for compliant options.");
- }
+ request.getMainBranchKey(), s -> {
+ }).mainBranchComponent();
- dbClient.newCodePeriodDao().insert(dbSession, dto);
}
private static CreateRequest toCreateRequest(Request request) {
diff --git a/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java b/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
index 719ef992d5f..e46e8aa5909 100644
--- a/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
+++ b/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
@@ -146,6 +146,7 @@ import org.sonar.server.monitoring.devops.AzureMetricsTask;
import org.sonar.server.monitoring.devops.BitbucketMetricsTask;
import org.sonar.server.monitoring.devops.GithubMetricsTask;
import org.sonar.server.monitoring.devops.GitlabMetricsTask;
+import org.sonar.server.newcodeperiod.NewCodeDefinitionResolver;
import org.sonar.server.newcodeperiod.ws.NewCodePeriodsWsModule;
import org.sonar.server.notification.NotificationModule;
import org.sonar.server.notification.ws.NotificationWsModule;
@@ -508,6 +509,7 @@ public class PlatformLevel4 extends PlatformLevel {
// New Code Periods
new NewCodePeriodsWsModule(),
+ NewCodeDefinitionResolver.class,
// Project Links
new ProjectLinksModule(),