From 38ab30d7083ae942d83c655deefcf213e6fa7cfe Mon Sep 17 00:00:00 2001 From: Antoine Vigneau Date: Wed, 4 Oct 2023 15:47:29 +0200 Subject: [PATCH] SONAR-20640 Make almSetting optional on ALM import endpoints --- scripts/patches/json | 0 .../almintegration/ws/ImportHelperIT.java | 80 +++++++++++------- .../almintegration/ws/SetPatActionIT.java | 82 ++++++++++++++---- .../ws/azure/ImportAzureProjectActionIT.java | 79 ++++++++++++++---- .../ImportBitbucketCloudRepoActionIT.java | 66 +++++++++++---- .../ImportBitbucketServerProjectActionIT.java | 83 ++++++++++++++----- .../github/ImportGithubProjectActionIT.java | 74 +++++++++++++---- .../gitlab/ImportGitLabProjectActionIT.java | 59 +++++++++++++ .../almintegration/ws/ImportHelper.java | 48 +++++++++-- .../almintegration/ws/SetPatAction.java | 57 +++++++++---- .../ws/azure/ImportAzureProjectAction.java | 7 +- .../ImportBitbucketCloudRepoAction.java | 7 +- .../ImportBitbucketServerProjectAction.java | 7 +- .../ws/github/ImportGithubProjectAction.java | 7 +- .../ws/gitlab/ImportGitLabProjectAction.java | 13 ++- 15 files changed, 522 insertions(+), 147 deletions(-) create mode 100644 scripts/patches/json diff --git a/scripts/patches/json b/scripts/patches/json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/ImportHelperIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/ImportHelperIT.java index 8f1fa9486c8..ad7f49c3dba 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/ImportHelperIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/ImportHelperIT.java @@ -21,9 +21,11 @@ package org.sonar.server.almintegration.ws; import org.junit.Rule; import org.junit.Test; +import org.sonar.api.impl.ws.SimpleGetRequest; import org.sonar.api.server.ws.Request; import org.sonar.api.utils.System2; import org.sonar.db.DbTester; +import org.sonar.db.alm.setting.ALM; import org.sonar.db.alm.setting.AlmSettingDto; import org.sonar.db.component.ProjectTesting; import org.sonar.db.project.ProjectDto; @@ -33,17 +35,16 @@ import org.sonar.server.tester.UserSessionRule; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.sonar.db.almsettings.AlmSettingsTesting.newGithubAlmSettingDto; +import static org.sonar.server.almintegration.ws.ImportHelper.PARAM_ALM_SETTING; import static org.sonarqube.ws.Projects.CreateWsResponse; public class ImportHelperIT { - private static final AlmSettingDto ALM_SETTING_WITH_WEBHOOK_SECRET = newGithubAlmSettingDto().setWebhookSecret("webhook_secret"); + // We use a GitHub ALM just because we have to use one. Tests are not specific to GitHub. + private static final ALM GITHUB_ALM = ALM.GITHUB; private final System2 system2 = System2.INSTANCE; private final ProjectDto projectDto = ProjectTesting.newPublicProjectDto(); - private final Request request = mock(Request.class); + private final Request emptyRequest = new SimpleGetRequest(); @Rule public final DbTester db = DbTester.create(system2); @@ -55,50 +56,73 @@ public class ImportHelperIT { private final ImportHelper underTest = new ImportHelper(db.getDbClient(), userSession); @Test - public void it_throws_exception_when_provisioning_project_without_permission() { - assertThatThrownBy(() -> underTest.checkProvisionProjectPermission()) + public void checkProvisionProjectPermission_whenNoPermissions_shouldThrow() { + assertThatThrownBy(underTest::checkProvisionProjectPermission) .isInstanceOf(UnauthorizedException.class) .hasMessage("Authentication is required"); } @Test - public void it_throws_exception_on_get_alm_setting_when_key_is_empty() { - assertThatThrownBy(() -> underTest.getAlmSetting(request)) - .isInstanceOf(NotFoundException.class); + public void getAlmConfig_whenNoAlmSettingKeyAndNoConfig_shouldThrow() { + assertThatThrownBy(() -> underTest.getAlmSettingDtoForAlm(emptyRequest, GITHUB_ALM)) + .isInstanceOf(NotFoundException.class) + .hasMessage("There is no GITHUB configuration for DevOps Platform. Please add one."); } @Test - public void it_throws_exception_on_get_alm_setting_when_key_is_not_found() { - when(request.mandatoryParam(ImportHelper.PARAM_ALM_SETTING)).thenReturn("key"); - assertThatThrownBy(() -> underTest.getAlmSetting(request)) - .isInstanceOf(NotFoundException.class) - .hasMessage("DevOps Platform Setting 'key' not found"); + public void getAlmConfig_whenNoAlmSettingKeyAndOnlyOneConfig_shouldReturnConfig() { + AlmSettingDto githubAlmSettingDto = db.almSettings().insertGitHubAlmSetting(); + + AlmSettingDto almSettingDto = underTest.getAlmSettingDtoForAlm(emptyRequest, GITHUB_ALM); + + assertThat(almSettingDto).usingRecursiveComparison().isEqualTo(githubAlmSettingDto); } @Test - public void it_throws_exception_when_user_uuid_is_null() { - assertThatThrownBy(() -> underTest.getUserUuid()) - .isInstanceOf(NullPointerException.class) - .hasMessage("User UUID cannot be null"); + public void getAlmConfig_whenNoAlmSettingKeyAndMultipleConfigs_shouldThrow() { + db.almSettings().insertGitHubAlmSetting(); + db.almSettings().insertGitHubAlmSetting(); + + assertThatThrownBy(() -> underTest.getAlmSettingDtoForAlm(emptyRequest, GITHUB_ALM)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Parameter almSetting is required as there are multiple DevOps Platform configurations."); } @Test - public void it_returns_create_response() { - CreateWsResponse response = ImportHelper.toCreateResponse(projectDto); - CreateWsResponse.Project project = response.getProject(); + public void getAlmConfig_whenAlmSettingKeyProvidedButDoesNotExist_shouldThrow() { + Request request = new SimpleGetRequest() + .setParam(PARAM_ALM_SETTING, "key"); - assertThat(project).extracting(CreateWsResponse.Project::getKey, CreateWsResponse.Project::getName, - CreateWsResponse.Project::getQualifier) - .containsExactly(projectDto.getKey(), projectDto.getName(), projectDto.getQualifier()); + assertThatThrownBy(() -> underTest.getAlmSettingDtoForAlm(request, GITHUB_ALM)) + .isInstanceOf(NotFoundException.class) + .hasMessage("DevOps Platform configuration 'key' not found."); } @Test - public void getAlmSetting_whenAlmSettingExists_shouldReturnActualAlmSetting(){ + public void getAlmConfig_whenConfigExists_shouldReturnConfig(){ AlmSettingDto almSettingDto = db.almSettings().insertAzureAlmSetting(); - when( request.mandatoryParam(ImportHelper.PARAM_ALM_SETTING)).thenReturn(almSettingDto.getKey()); + Request request = new SimpleGetRequest() + .setParam(PARAM_ALM_SETTING, almSettingDto.getKey()); - AlmSettingDto result = underTest.getAlmSetting(request); + AlmSettingDto result = underTest.getAlmSettingDtoForAlm(request, GITHUB_ALM); assertThat(result.getUuid()).isEqualTo(almSettingDto.getUuid()); } + + @Test + public void getUserUuid_whenUserUuidNull_shouldThrow() { + assertThatThrownBy(underTest::getUserUuid) + .isInstanceOf(NullPointerException.class) + .hasMessage("User UUID cannot be null."); + } + + @Test + public void toCreateResponse_shouldReturnProjectResponse() { + CreateWsResponse response = ImportHelper.toCreateResponse(projectDto); + CreateWsResponse.Project project = response.getProject(); + + assertThat(project).extracting(CreateWsResponse.Project::getKey, CreateWsResponse.Project::getName, + CreateWsResponse.Project::getQualifier) + .containsExactly(projectDto.getKey(), projectDto.getName(), projectDto.getQualifier()); + } } diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/SetPatActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/SetPatActionIT.java index c90746b6c96..51ad06f01af 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/SetPatActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/SetPatActionIT.java @@ -32,9 +32,11 @@ import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.exceptions.UnauthorizedException; import org.sonar.server.tester.UserSessionRule; +import org.sonar.server.ws.TestRequest; import org.sonar.server.ws.WsActionTester; 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.assertj.core.api.Assertions.tuple; import static org.sonar.db.permission.GlobalPermission.PROVISION_PROJECTS; @@ -46,7 +48,9 @@ public class SetPatActionIT { @Rule public DbTester db = DbTester.create(); - private final WsActionTester ws = new WsActionTester(new SetPatAction(db.getDbClient(), userSession)); + public ImportHelper importHelper = new ImportHelper(db.getDbClient(), userSession); + + private final WsActionTester ws = new WsActionTester(new SetPatAction(db.getDbClient(), userSession, importHelper)); @Test public void set_new_azuredevops_pat() { @@ -159,21 +163,6 @@ public class SetPatActionIT { .hasMessage("Username cannot be null for Bitbucket Cloud"); } - @Test - public void fail_when_alm_setting_unknow() { - UserDto user = db.users().insertUser(); - userSession.logIn(user).addPermission(PROVISION_PROJECTS); - - assertThatThrownBy(() -> { - ws.newRequest() - .setParam("almSetting", "notExistingKey") - .setParam("pat", "12345678987654321") - .execute(); - }) - .isInstanceOf(NotFoundException.class) - .hasMessage("DevOps Platform Setting 'notExistingKey' not found"); - } - @Test public void set_new_github_pat() { UserDto user = db.users().insertUser(); @@ -208,6 +197,62 @@ public class SetPatActionIT { .hasMessage("Insufficient privileges"); } + @Test + public void setPat_whenAlmSettingKeyDoesNotExist_shouldThrow() { + UserDto user = db.users().insertUser(); + userSession.logIn(user).addPermission(PROVISION_PROJECTS); + + TestRequest request = ws.newRequest() + .setParam("almSetting", "unknown") + .setParam("pat", "12345678987654321"); + + assertThatThrownBy(request::execute) + .isInstanceOf(NotFoundException.class) + .hasMessage("DevOps Platform configuration 'unknown' not found."); + } + + @Test + public void setPat_whenNoAlmSettingKeyAndNoConfig_shouldThrow() { + UserDto user = db.users().insertUser(); + userSession.logIn(user).addPermission(PROVISION_PROJECTS); + + TestRequest request = ws.newRequest() + .setParam("pat", "12345678987654321"); + + assertThatThrownBy(request::execute) + .isInstanceOf(NotFoundException.class) + .hasMessage("There is no configuration for DevOps Platform. Please add one."); + } + + @Test + public void setPat_whenNoAlmSettingKeyAndMultipleConfigs_shouldThrow() { + UserDto user = db.users().insertUser(); + userSession.logIn(user).addPermission(PROVISION_PROJECTS); + + db.almSettings().insertAzureAlmSetting(); + db.almSettings().insertGitHubAlmSetting(); + + TestRequest request = ws.newRequest() + .setParam("pat", "12345678987654321"); + + assertThatThrownBy(request::execute) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Parameter almSetting is required as there are multiple DevOps Platform configurations."); + } + + @Test + public void setPat_whenNoAlmSettingKeyAndOnlyOneConfig_shouldImport() { + UserDto user = db.users().insertUser(); + userSession.logIn(user).addPermission(PROVISION_PROJECTS); + + db.almSettings().insertAzureAlmSetting(); + + TestRequest request = ws.newRequest() + .setParam("pat", "12345678987654321"); + + assertThatNoException().isThrownBy(request::execute); + } + @Test public void definition() { WebService.Action def = ws.getDef(); @@ -216,7 +261,10 @@ public class SetPatActionIT { assertThat(def.isPost()).isTrue(); assertThat(def.params()) .extracting(WebService.Param::key, WebService.Param::isRequired) - .containsExactlyInAnyOrder(tuple("almSetting", true), tuple("pat", true), tuple("username", false)); + .containsExactlyInAnyOrder( + tuple("almSetting", false), + tuple("pat", true), + tuple("username", false)); } } diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectActionIT.java index 9023b1c850b..ce94342cfbf 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectActionIT.java @@ -33,7 +33,6 @@ 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.pat.AlmPatDto; import org.sonar.db.alm.setting.AlmSettingDto; import org.sonar.db.alm.setting.ProjectAlmSettingDto; import org.sonar.db.component.BranchDto; @@ -65,13 +64,13 @@ import org.sonarqube.ws.Projects; import static java.util.Objects.requireNonNull; 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.assertj.core.api.Assertions.tuple; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.sonar.db.alm.integration.pat.AlmPatsTesting.newAlmPatDto; 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; @@ -371,21 +370,6 @@ public class ImportAzureProjectActionIT { .hasMessage("personal access token for '" + almSetting.getKey() + "' is missing"); } - @Test - public void fail_check_alm_setting_not_found() { - UserDto user = db.users().insertUser(); - userSession.logIn(user).addPermission(PROVISION_PROJECTS); - AlmPatDto almPatDto = newAlmPatDto(); - db.getDbClient().almPatDao().insert(db.getSession(), almPatDto, user.getLogin(), null); - - TestRequest request = ws.newRequest() - .setParam("almSetting", "testKey"); - - assertThatThrownBy(request::execute) - .isInstanceOf(NotFoundException.class) - .hasMessage("DevOps Platform Setting 'testKey' not found"); - } - @Test public void fail_project_already_exists() { AlmSettingDto almSetting = configureUserAndAlmSettings(); @@ -405,6 +389,65 @@ public class ImportAzureProjectActionIT { GENERATED_PROJECT_KEY); } + @Test + public void importProject_whenAlmSettingKeyDoesNotExist_shouldThrow() { + UserDto user = db.users().insertUser(); + userSession.logIn(user).addPermission(PROVISION_PROJECTS); + + TestRequest request = ws.newRequest() + .setParam("almSetting", "unknown") + .setParam("projectName", "project-name") + .setParam("repositoryName", "repo-name"); + + assertThatThrownBy(request::execute) + .isInstanceOf(NotFoundException.class) + .hasMessage("DevOps Platform configuration 'unknown' not found."); + } + + @Test + public void importProject_whenNoAlmSettingKeyAndNoConfig_shouldThrow() { + UserDto user = db.users().insertUser(); + userSession.logIn(user).addPermission(PROVISION_PROJECTS); + + TestRequest request = ws.newRequest() + .setParam("projectName", "project-name") + .setParam("repositoryName", "repo-name"); + + assertThatThrownBy(request::execute) + .isInstanceOf(NotFoundException.class) + .hasMessage("There is no AZURE_DEVOPS configuration for DevOps Platform. Please add one."); + } + + @Test + public void importProject_whenNoAlmSettingKeyAndMultipleConfigs_shouldThrow() { + UserDto user = db.users().insertUser(); + userSession.logIn(user).addPermission(PROVISION_PROJECTS); + + db.almSettings().insertAzureAlmSetting(); + db.almSettings().insertAzureAlmSetting(); + + TestRequest request = ws.newRequest() + .setParam("projectName", "project-name") + .setParam("repositoryName", "repo-name"); + + assertThatThrownBy(request::execute) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Parameter almSetting is required as there are multiple DevOps Platform configurations."); + } + + @Test + public void importProject_whenNoAlmSettingKeyAndOnlyOneConfig_shouldImport() { + AlmSettingDto almSetting = configureUserAndAlmSettings(); + mockAzureInteractions(almSetting); + + TestRequest request = ws.newRequest() + .setParam("projectName", "project-name") + .setParam("repositoryName", "repo-name"); + + assertThatNoException().isThrownBy(request::execute); + } + + @Test public void define() { WebService.Action def = ws.getDef(); @@ -414,7 +457,7 @@ public class ImportAzureProjectActionIT { assertThat(def.params()) .extracting(WebService.Param::key, WebService.Param::isRequired) .containsExactlyInAnyOrder( - tuple("almSetting", true), + tuple("almSetting", false), tuple("projectName", true), tuple("repositoryName", true), tuple(PARAM_NEW_CODE_DEFINITION_TYPE, false), diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketcloud/ImportBitbucketCloudRepoActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketcloud/ImportBitbucketCloudRepoActionIT.java index 7cbc4ab1c1c..b117980269e 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketcloud/ImportBitbucketCloudRepoActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketcloud/ImportBitbucketCloudRepoActionIT.java @@ -33,7 +33,6 @@ 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.pat.AlmPatDto; import org.sonar.db.alm.setting.AlmSettingDto; import org.sonar.db.alm.setting.ProjectAlmSettingDto; import org.sonar.db.component.BranchDto; @@ -65,13 +64,13 @@ import org.sonarqube.ws.Projects; import static java.util.Objects.requireNonNull; 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.assertj.core.api.Assertions.tuple; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.sonar.db.alm.integration.pat.AlmPatsTesting.newAlmPatDto; 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; @@ -354,32 +353,71 @@ public class ImportBitbucketCloudRepoActionIT { } @Test - public void fail_check_alm_setting_not_found() { + public void fail_when_no_creation_project_permission() { + UserDto user = db.users().insertUser(); + userSession.logIn(user); + + TestRequest request = ws.newRequest() + .setParam("almSetting", "anyvalue"); + + assertThatThrownBy(request::execute) + .isInstanceOf(ForbiddenException.class) + .hasMessageContaining("Insufficient privileges"); + } + + @Test + public void importProject_whenAlmSettingKeyDoesNotExist_shouldThrow() { UserDto user = db.users().insertUser(); userSession.logIn(user).addPermission(PROVISION_PROJECTS); - AlmPatDto almPatDto = newAlmPatDto(); - db.getDbClient().almPatDao().insert(db.getSession(), almPatDto, user.getLogin(), null); TestRequest request = ws.newRequest() - .setParam("almSetting", "testKey") - .setParam("repositorySlug", "repo"); + .setParam("almSetting", "unknown") + .setParam("repositorySlug", "repo-slug"); assertThatThrownBy(request::execute) .isInstanceOf(NotFoundException.class) - .hasMessageContaining("DevOps Platform Setting 'testKey' not found"); + .hasMessage("DevOps Platform configuration 'unknown' not found."); } @Test - public void fail_when_no_creation_project_permission() { + public void importProject_whenNoAlmSettingKeyAndNoConfig_shouldThrow() { UserDto user = db.users().insertUser(); - userSession.logIn(user); + userSession.logIn(user).addPermission(PROVISION_PROJECTS); TestRequest request = ws.newRequest() - .setParam("almSetting", "anyvalue"); + .setParam("repositorySlug", "repo-slug"); assertThatThrownBy(request::execute) - .isInstanceOf(ForbiddenException.class) - .hasMessageContaining("Insufficient privileges"); + .isInstanceOf(NotFoundException.class) + .hasMessage("There is no BITBUCKET_CLOUD configuration for DevOps Platform. Please add one."); + } + + @Test + public void importProject_whenNoAlmSettingKeyAndMultipleConfigs_shouldThrow() { + UserDto user = db.users().insertUser(); + userSession.logIn(user).addPermission(PROVISION_PROJECTS); + + db.almSettings().insertBitbucketCloudAlmSetting(); + db.almSettings().insertBitbucketCloudAlmSetting(); + + TestRequest request = ws.newRequest() + .setParam("repositorySlug", "repo-slug"); + + assertThatThrownBy(request::execute) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Parameter almSetting is required as there are multiple DevOps Platform configurations."); + } + + @Test + public void importProject_whenNoAlmSettingKeyAndOnlyOneConfig_shouldImport() { + configureUserAndPatAndAlmSettings(); + mockBitbucketCloudRepo(); + + TestRequest request = ws.newRequest() + .setParam("projectKey", "projectKey") + .setParam("repositorySlug", "repo-slug"); + + assertThatNoException().isThrownBy(request::execute); } @Test @@ -391,7 +429,7 @@ public class ImportBitbucketCloudRepoActionIT { assertThat(def.params()) .extracting(WebService.Param::key, WebService.Param::isRequired) .containsExactlyInAnyOrder( - tuple("almSetting", true), + tuple("almSetting", false), tuple("repositorySlug", true), tuple(PARAM_NEW_CODE_DEFINITION_TYPE, false), tuple(PARAM_NEW_CODE_DEFINITION_VALUE, false)); diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectActionIT.java index 659d2206448..3ad01c29fda 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectActionIT.java @@ -38,7 +38,6 @@ 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.pat.AlmPatDto; import org.sonar.db.alm.setting.AlmSettingDto; import org.sonar.db.component.BranchDto; import org.sonar.db.newcodeperiod.NewCodePeriodDto; @@ -63,6 +62,7 @@ import org.sonar.server.project.DefaultBranchNameResolver; import org.sonar.server.project.ProjectDefaultVisibility; import org.sonar.server.project.Visibility; import org.sonar.server.tester.UserSessionRule; +import org.sonar.server.ws.TestRequest; import org.sonar.server.ws.WsActionTester; import org.sonarqube.ws.Projects; @@ -70,13 +70,13 @@ import static java.util.Objects.requireNonNull; import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; import static org.apache.commons.lang.math.JVMRandom.nextLong; 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.assertj.core.api.Assertions.tuple; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.sonar.db.alm.integration.pat.AlmPatsTesting.newAlmPatDto; 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; @@ -358,22 +358,6 @@ public class ImportBitbucketServerProjectActionIT { .hasMessage("personal access token for '" + almSetting.getKey() + "' is missing"); } - @Test - public void fail_check_alm_setting_not_found() { - UserDto user = db.users().insertUser(); - userSession.logIn(user).addPermission(PROVISION_PROJECTS); - AlmPatDto almPatDto = newAlmPatDto(); - db.getDbClient().almPatDao().insert(db.getSession(), almPatDto, user.getLogin(), null); - - assertThatThrownBy(() -> { - ws.newRequest() - .setParam("almSetting", "testKey") - .execute(); - }) - .isInstanceOf(NotFoundException.class) - .hasMessage("DevOps Platform Setting 'testKey' not found"); - } - @Test public void fail_when_no_creation_project_permission() { UserDto user = db.users().insertUser(); @@ -438,6 +422,65 @@ public class ImportBitbucketServerProjectActionIT { assertThat(mainBranchName).isEqualTo("default"); } + @Test + public void importProject_whenAlmSettingKeyDoesNotExist_shouldThrow() { + UserDto user = db.users().insertUser(); + userSession.logIn(user).addPermission(PROVISION_PROJECTS); + + TestRequest request = ws.newRequest() + .setParam("almSetting", "unknown") + .setParam("projectKey", "projectKey") + .setParam("repositorySlug", "repo-slug"); + + assertThatThrownBy(request::execute) + .isInstanceOf(NotFoundException.class) + .hasMessage("DevOps Platform configuration 'unknown' not found."); + } + + @Test + public void importProject_whenNoAlmSettingKeyAndNoConfig_shouldThrow() { + UserDto user = db.users().insertUser(); + userSession.logIn(user).addPermission(PROVISION_PROJECTS); + + TestRequest request = ws.newRequest() + .setParam("projectKey", "projectKey") + .setParam("repositorySlug", "repo-slug"); + + assertThatThrownBy(request::execute) + .isInstanceOf(NotFoundException.class) + .hasMessage("There is no BITBUCKET configuration for DevOps Platform. Please add one."); + } + + @Test + public void importProject_whenNoAlmSettingKeyAndMultipleConfigs_shouldThrow() { + UserDto user = db.users().insertUser(); + userSession.logIn(user).addPermission(PROVISION_PROJECTS); + + db.almSettings().insertBitbucketAlmSetting(); + db.almSettings().insertBitbucketAlmSetting(); + + TestRequest request = ws.newRequest() + .setParam("projectKey", "projectKey") + .setParam("repositorySlug", "repo-slug"); + + assertThatThrownBy(request::execute) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Parameter almSetting is required as there are multiple DevOps Platform configurations."); + } + + @Test + public void importProject_whenNoAlmSettingKeyAndOnlyOneConfig_shouldImport() { + configureUserAndPatAndAlmSettings(); + Project project = getGsonBBSProject(); + mockBitbucketServerRepo(project); + + TestRequest request = ws.newRequest() + .setParam("projectKey", "projectKey") + .setParam("repositorySlug", "repo-slug"); + + assertThatNoException().isThrownBy(request::execute); + } + @Test public void definition() { WebService.Action def = ws.getDef(); @@ -447,7 +490,7 @@ public class ImportBitbucketServerProjectActionIT { assertThat(def.params()) .extracting(WebService.Param::key, WebService.Param::isRequired) .containsExactlyInAnyOrder( - tuple("almSetting", true), + tuple("almSetting", false), tuple("repositorySlug", true), tuple("projectKey", true), tuple(PARAM_NEW_CODE_DEFINITION_TYPE, false), @@ -457,7 +500,7 @@ public class ImportBitbucketServerProjectActionIT { private AlmSettingDto configureUserAndPatAndAlmSettings() { UserDto user = db.users().insertUser(); userSession.logIn(user).addPermission(PROVISION_PROJECTS); - AlmSettingDto almSetting = db.almSettings().insertGitHubAlmSetting(); + AlmSettingDto almSetting = db.almSettings().insertBitbucketAlmSetting(); db.almPats().insert(dto -> { dto.setAlmSettingUuid(almSetting.getUuid()); dto.setUserUuid(user.getUuid()); diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectActionIT.java index ab0840a0eda..a066fdb639a 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectActionIT.java @@ -76,6 +76,7 @@ import org.sonarqube.ws.Projects; import static java.util.Objects.requireNonNull; 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.assertj.core.api.Assertions.tuple; import static org.mockito.ArgumentMatchers.any; @@ -361,6 +362,63 @@ public class ImportGithubProjectActionIT { assertThat(projectDto.orElseThrow().getCreationMethod()).isEqualTo(CreationMethod.ALM_IMPORT_BROWSER); } + @Test + public void importProject_whenAlmSettingKeyDoesNotExist_shouldThrow() { + UserDto user = db.users().insertUser(); + userSession.logIn(user).addPermission(GlobalPermission.PROVISION_PROJECTS); + + TestRequest request = ws.newRequest() + .setParam(PARAM_ALM_SETTING, "unknown") + .setParam(PARAM_ORGANIZATION, "test") + .setParam(PARAM_REPOSITORY_KEY, "test/repo"); + assertThatThrownBy(request::execute) + .isInstanceOf(NotFoundException.class) + .hasMessage("DevOps Platform configuration 'unknown' not found."); + } + + @Test + public void importProject_whenNoAlmSettingKeyAndNoConfig_shouldThrow() { + UserDto user = db.users().insertUser(); + userSession.logIn(user).addPermission(GlobalPermission.PROVISION_PROJECTS); + + TestRequest request = ws.newRequest() + .setParam(PARAM_ORGANIZATION, "test") + .setParam(PARAM_REPOSITORY_KEY, "test/repo"); + assertThatThrownBy(request::execute) + .isInstanceOf(NotFoundException.class) + .hasMessage("There is no GITHUB configuration for DevOps Platform. Please add one."); + } + + @Test + public void importProject_whenNoAlmSettingKeyAndMultipleConfigs_shouldThrow() { + UserDto user = db.users().insertUser(); + userSession.logIn(user).addPermission(GlobalPermission.PROVISION_PROJECTS); + db.almSettings().insertGitHubAlmSetting(); + db.almSettings().insertGitHubAlmSetting(); + + TestRequest request = ws.newRequest() + .setParam(PARAM_ORGANIZATION, "test") + .setParam(PARAM_REPOSITORY_KEY, "test/repo"); + assertThatThrownBy(request::execute) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Parameter almSetting is required as there are multiple DevOps Platform configurations."); + } + + @Test + public void importProject_whenNoAlmSettingKeyAndOnlyOneConfig_shouldImport() { + AlmSettingDto githubAlmSetting = setupUserWithPatAndAlmSettings(); + + mockGithubInteractions(); + when(gitHubSettings.isProvisioningEnabled()).thenReturn(true); + + TestRequest request = ws.newRequest() + .setParam(PARAM_ALM_SETTING, githubAlmSetting.getKey()) + .setParam(PARAM_ORGANIZATION, "octocat") + .setParam(PARAM_REPOSITORY_KEY, "octocat/" + PROJECT_KEY_NAME); + + assertThatNoException().isThrownBy(request::execute); + } + private Projects.CreateWsResponse callWebService(AlmSettingDto githubAlmSetting) { return ws.newRequest() .setParam(PARAM_ALM_SETTING, githubAlmSetting.getKey()) @@ -395,20 +453,6 @@ public class ImportGithubProjectActionIT { .isInstanceOf(UnauthorizedException.class); } - @Test - public void fail_when_almSetting_does_not_exist() { - UserDto user = db.users().insertUser(); - userSession.logIn(user).addPermission(GlobalPermission.PROVISION_PROJECTS); - - TestRequest request = ws.newRequest() - .setParam(PARAM_ALM_SETTING, "unknown") - .setParam(PARAM_ORGANIZATION, "test") - .setParam(PARAM_REPOSITORY_KEY, "test/repo"); - assertThatThrownBy(request::execute) - .isInstanceOf(NotFoundException.class) - .hasMessage("DevOps Platform Setting 'unknown' not found"); - } - @Test public void fail_when_personal_access_token_doesnt_exist() { AlmSettingDto githubAlmSetting = setupUserAndAlmSettings(); @@ -431,7 +475,7 @@ public class ImportGithubProjectActionIT { assertThat(def.params()) .extracting(WebService.Param::key, WebService.Param::isRequired) .containsExactlyInAnyOrder( - tuple(PARAM_ALM_SETTING, true), + tuple(PARAM_ALM_SETTING, false), tuple(PARAM_ORGANIZATION, true), tuple(PARAM_REPOSITORY_KEY, true), tuple(PARAM_NEW_CODE_DEFINITION_TYPE, false), 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 1c21c09a770..b1c8414e7db 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 @@ -44,6 +44,7 @@ import org.sonar.server.almintegration.ws.ImportHelper; import org.sonar.server.almintegration.ws.ProjectKeyGenerator; import org.sonar.server.component.ComponentUpdater; import org.sonar.server.es.TestIndexers; +import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.favorite.FavoriteUpdater; import org.sonar.server.newcodeperiod.NewCodeDefinitionResolver; import org.sonar.server.permission.PermissionService; @@ -53,6 +54,7 @@ import org.sonar.server.project.DefaultBranchNameResolver; import org.sonar.server.project.ProjectDefaultVisibility; import org.sonar.server.project.Visibility; import org.sonar.server.tester.UserSessionRule; +import org.sonar.server.ws.TestRequest; import org.sonar.server.ws.WsActionTester; import org.sonarqube.ws.Projects; @@ -60,6 +62,8 @@ import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; 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.assertj.core.api.Assertions.tuple; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; @@ -267,6 +271,61 @@ public class ImportGitLabProjectActionIT { assertThat(projectDto.orElseThrow().getCreationMethod()).isEqualTo(CreationMethod.ALM_IMPORT_BROWSER); } + @Test + public void importProject_whenAlmSettingKeyDoesNotExist_shouldThrow() { + UserDto user = db.users().insertUser(); + userSession.logIn(user).addPermission(PROVISION_PROJECTS); + + TestRequest request = ws.newRequest() + .setParam("almSetting", "unknown") + .setParam("gitlabProjectId", "12345"); + + assertThatThrownBy(request::execute) + .isInstanceOf(NotFoundException.class) + .hasMessage("DevOps Platform configuration 'unknown' not found."); + } + + @Test + public void importProject_whenNoAlmSettingKeyAndNoConfig_shouldThrow() { + UserDto user = db.users().insertUser(); + userSession.logIn(user).addPermission(PROVISION_PROJECTS); + + TestRequest request = ws.newRequest() + .setParam("gitlabProjectId", "12345"); + + assertThatThrownBy(request::execute) + .isInstanceOf(NotFoundException.class) + .hasMessage("There is no GITLAB configuration for DevOps Platform. Please add one."); + } + + @Test + public void importProject_whenNoAlmSettingKeyAndMultipleConfigs_shouldThrow() { + UserDto user = db.users().insertUser(); + userSession.logIn(user).addPermission(PROVISION_PROJECTS); + + db.almSettings().insertGitlabAlmSetting(); + db.almSettings().insertGitlabAlmSetting(); + + TestRequest request = ws.newRequest() + .setParam("gitlabProjectId", "12345"); + + assertThatThrownBy(request::execute) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Parameter almSetting is required as there are multiple DevOps Platform configurations."); + } + + @Test + public void importProject_whenNoAlmSettingKeyAndOnlyOneConfig_shouldImport() { + configureUserAndPatAndAlmSettings(); + mockGitlabProject(emptyList()); + + TestRequest request = ws.newRequest() + .setParam("gitlabProjectId", "12345"); + + assertThatNoException().isThrownBy(request::execute); + } + + private AlmSettingDto configureUserAndPatAndAlmSettings() { UserDto user = db.users().insertUser(); userSession.logIn(user).addPermission(PROVISION_PROJECTS); diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/ImportHelper.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/ImportHelper.java index bc26b726f7a..cfa1f1200c4 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/ImportHelper.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/ImportHelper.java @@ -19,10 +19,13 @@ */ package org.sonar.server.almintegration.ws; +import java.util.List; +import javax.annotation.Nullable; import org.sonar.api.server.ServerSide; import org.sonar.api.server.ws.Request; import org.sonar.db.DbClient; import org.sonar.db.DbSession; +import org.sonar.db.alm.setting.ALM; import org.sonar.db.alm.setting.AlmSettingDto; import org.sonar.db.project.ProjectDto; import org.sonar.server.exceptions.NotFoundException; @@ -51,16 +54,51 @@ public class ImportHelper { userSession.checkLoggedIn().checkPermission(PROVISION_PROJECTS); } - public AlmSettingDto getAlmSetting(Request request) { - String almSettingKey = request.mandatoryParam(PARAM_ALM_SETTING); + public AlmSettingDto getAlmSettingDto(Request request) { + return getAlmSettingDto(request, null); + } + + public AlmSettingDto getAlmSettingDtoForAlm(Request request, ALM alm) { + return getAlmSettingDto(request, alm); + } + + private AlmSettingDto getAlmSettingDto(Request request, @Nullable ALM alm) { try (DbSession dbSession = dbClient.openSession(false)) { - return dbClient.almSettingDao().selectByKey(dbSession, almSettingKey) - .orElseThrow(() -> new NotFoundException(String.format("DevOps Platform Setting '%s' not found", almSettingKey))); + String almSettingKey = request.param(PARAM_ALM_SETTING); + if (almSettingKey != null) { + return getAlmSettingDtoFromKey(dbSession, almSettingKey); + } + return getUniqueAlmSettingDtoForAlm(dbSession, alm); + } + } + + private AlmSettingDto getAlmSettingDtoFromKey(DbSession dbSession, String almSettingKey) { + return dbClient.almSettingDao().selectByKey(dbSession, almSettingKey) + .orElseThrow(() -> new NotFoundException(String.format("DevOps Platform configuration '%s' not found.", almSettingKey))); + } + + private AlmSettingDto getUniqueAlmSettingDtoForAlm(DbSession dbSession, @Nullable ALM alm) { + List almSettingDtos = getAlmSettingDtos(dbSession, alm); + + if (almSettingDtos.isEmpty()) { + String almString = alm == null ? "" : (alm.name() + " "); + throw new NotFoundException("There is no " + almString + "configuration for DevOps Platform. Please add one."); + } + if (almSettingDtos.size() == 1) { + return almSettingDtos.get(0); + } + throw new IllegalArgumentException(String.format("Parameter %s is required as there are multiple DevOps Platform configurations.", PARAM_ALM_SETTING)); + } + + private List getAlmSettingDtos(DbSession dbSession, @Nullable ALM alm) { + if (alm == null) { + return dbClient.almSettingDao().selectAll(dbSession); } + return dbClient.almSettingDao().selectByAlm(dbSession, alm); } public String getUserUuid() { - return requireNonNull(userSession.getUuid(), "User UUID cannot be null"); + return requireNonNull(userSession.getUuid(), "User UUID cannot be null."); } public static CreateWsResponse toCreateResponse(ProjectDto projectDto) { diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/SetPatAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/SetPatAction.java index 0743d3e8220..a2a866afde1 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/SetPatAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/SetPatAction.java @@ -20,7 +20,9 @@ package org.sonar.server.almintegration.ws; import com.google.common.base.Strings; +import java.util.List; import java.util.Optional; +import javax.annotation.Nullable; import org.sonar.api.server.ws.Change; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; @@ -33,7 +35,6 @@ import org.sonar.db.alm.setting.AlmSettingDto; import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.user.UserSession; -import static java.lang.String.format; import static java.util.Objects.requireNonNull; import static org.sonar.db.alm.setting.ALM.BITBUCKET_CLOUD; import static org.sonar.db.permission.GlobalPermission.PROVISION_PROJECTS; @@ -46,10 +47,12 @@ public class SetPatAction implements AlmIntegrationsWsAction { private final DbClient dbClient; private final UserSession userSession; + private final ImportHelper importHelper; - public SetPatAction(DbClient dbClient, UserSession userSession) { + public SetPatAction(DbClient dbClient, UserSession userSession, ImportHelper importHelper) { this.dbClient = dbClient; this.userSession = userSession; + this.importHelper = importHelper; } @Override @@ -62,15 +65,17 @@ public class SetPatAction implements AlmIntegrationsWsAction { .setHandler(this) .setChangelog( new Change("9.0", "Bitbucket Cloud support and optional Username parameter were added"), - new Change("10.3", "Allow setting Personal Access Tokens for all DevOps platforms")); + new Change("10.3", "Allow setting Personal Access Tokens for all DevOps platforms"), + new Change("10.3", String.format("Parameter %s becomes optional if you have only one DevOps Platform configuration", PARAM_ALM_SETTING))); action.createParam(PARAM_ALM_SETTING) - .setRequired(true) - .setDescription("DevOps Platform setting key"); + .setDescription("DevOps Platform configuration key. This parameter is optional if you have only one single DevOps Platform integration."); + action.createParam(PARAM_PAT) .setRequired(true) .setMaximumLength(2000) .setDescription("Personal Access Token"); + action.createParam(PARAM_USERNAME) .setRequired(false) .setMaximumLength(2000) @@ -88,32 +93,56 @@ public class SetPatAction implements AlmIntegrationsWsAction { userSession.checkLoggedIn().checkPermission(PROVISION_PROJECTS); String pat = request.mandatoryParam(PARAM_PAT); - String almSettingKey = request.mandatoryParam(PARAM_ALM_SETTING); String username = request.param(PARAM_USERNAME); String userUuid = requireNonNull(userSession.getUuid(), "User UUID cannot be null"); - AlmSettingDto almSetting = dbClient.almSettingDao().selectByKey(dbSession, almSettingKey) - .orElseThrow(() -> new NotFoundException(format("DevOps Platform Setting '%s' not found", almSettingKey))); + AlmSettingDto almSettingDto = importHelper.getAlmSettingDto(request); - if (almSetting.getAlm().equals(BITBUCKET_CLOUD)) { + if (almSettingDto.getAlm().equals(BITBUCKET_CLOUD)) { Preconditions.checkArgument(!Strings.isNullOrEmpty(username), "Username cannot be null for Bitbucket Cloud"); } - String resultingPat = CredentialsEncoderHelper.encodeCredentials(almSetting.getAlm(), pat, username); + String resultingPat = CredentialsEncoderHelper.encodeCredentials(almSettingDto.getAlm(), pat, username); - Optional almPatDto = dbClient.almPatDao().selectByUserAndAlmSetting(dbSession, userUuid, almSetting); + Optional almPatDto = dbClient.almPatDao().selectByUserAndAlmSetting(dbSession, userUuid, almSettingDto); if (almPatDto.isPresent()) { AlmPatDto almPat = almPatDto.get(); almPat.setPersonalAccessToken(resultingPat); - dbClient.almPatDao().update(dbSession, almPat, userSession.getLogin(), almSetting.getKey()); + dbClient.almPatDao().update(dbSession, almPat, userSession.getLogin(), almSettingDto.getKey()); } else { AlmPatDto almPat = new AlmPatDto() .setPersonalAccessToken(resultingPat) - .setAlmSettingUuid(almSetting.getUuid()) + .setAlmSettingUuid(almSettingDto.getUuid()) .setUserUuid(userUuid); - dbClient.almPatDao().insert(dbSession, almPat, userSession.getLogin(), almSetting.getKey()); + dbClient.almPatDao().insert(dbSession, almPat, userSession.getLogin(), almSettingDto.getKey()); } dbSession.commit(); } } + + public AlmSettingDto getAlmConfig(@Nullable String almSettingKey) { + try (DbSession dbSession = dbClient.openSession(false)) { + if (almSettingKey != null) { + return getAlmSettingDtoFromKey(dbSession, almSettingKey); + } + return getAlmSettingDtoFromAlm(dbSession); + } + } + + private AlmSettingDto getAlmSettingDtoFromKey(DbSession dbSession, String almSettingKey) { + return dbClient.almSettingDao().selectByKey(dbSession, almSettingKey) + .orElseThrow(() -> new NotFoundException(String.format("DevOps Platform configuration '%s' not found.", almSettingKey))); + } + + private AlmSettingDto getAlmSettingDtoFromAlm(DbSession dbSession) { + List almSettingDtos = dbClient.almSettingDao().selectAll(dbSession); + if (almSettingDtos.isEmpty()) { + throw new NotFoundException("There is no configuration for DevOps Platforms. Please add one."); + } + if (almSettingDtos.size() == 1) { + return almSettingDtos.get(0); + } + throw new IllegalArgumentException(String.format("Parameter %s is required as there are multiple DevOps Platform configurations.", PARAM_ALM_SETTING)); + } + } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectAction.java index 31f371d5bcd..4f3b4e22ebf 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectAction.java @@ -30,6 +30,7 @@ import org.sonar.api.server.ws.WebService; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.alm.pat.AlmPatDto; +import org.sonar.db.alm.setting.ALM; import org.sonar.db.alm.setting.AlmSettingDto; import org.sonar.db.alm.setting.ProjectAlmSettingDto; import org.sonar.db.component.BranchDto; @@ -102,12 +103,12 @@ public class ImportAzureProjectAction implements AlmIntegrationsWsAction { .setSince("8.6") .setHandler(this) .setChangelog( + new Change("10.3", String.format("Parameter %s becomes optional if you have only one configuration for Azure", PARAM_ALM_SETTING)), new Change("10.3", "Endpoint visibility change from internal to public")); action.createParam(PARAM_ALM_SETTING) - .setRequired(true) .setMaximumLength(200) - .setDescription("DevOps Platform setting key"); + .setDescription("DevOps Platform configuration key. This parameter is optional if you have only one Azure integration."); action.createParam(PARAM_PROJECT_NAME) .setRequired(true) @@ -136,7 +137,7 @@ public class ImportAzureProjectAction implements AlmIntegrationsWsAction { private CreateWsResponse doHandle(Request request) { importHelper.checkProvisionProjectPermission(); - AlmSettingDto almSettingDto = importHelper.getAlmSetting(request); + AlmSettingDto almSettingDto = importHelper.getAlmSettingDtoForAlm(request, ALM.AZURE_DEVOPS); String newCodeDefinitionType = request.param(PARAM_NEW_CODE_DEFINITION_TYPE); String newCodeDefinitionValue = request.param(PARAM_NEW_CODE_DEFINITION_VALUE); diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketcloud/ImportBitbucketCloudRepoAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketcloud/ImportBitbucketCloudRepoAction.java index c1b275d1402..23ee5b8aea2 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketcloud/ImportBitbucketCloudRepoAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketcloud/ImportBitbucketCloudRepoAction.java @@ -31,6 +31,7 @@ import org.sonar.api.server.ws.WebService; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.alm.pat.AlmPatDto; +import org.sonar.db.alm.setting.ALM; import org.sonar.db.alm.setting.AlmSettingDto; import org.sonar.db.alm.setting.ProjectAlmSettingDto; import org.sonar.db.component.BranchDto; @@ -102,6 +103,7 @@ public class ImportBitbucketCloudRepoAction implements AlmIntegrationsWsAction { .setSince("9.0") .setHandler(this) .setChangelog( + new Change("10.3", String.format("Parameter %s becomes optional if you have only one configuration for BitBucket Cloud", PARAM_ALM_SETTING)), new Change("10.3", "Endpoint visibility change from internal to public")); action.createParam(PARAM_REPO_SLUG) @@ -110,9 +112,8 @@ public class ImportBitbucketCloudRepoAction implements AlmIntegrationsWsAction { .setDescription("Bitbucket Cloud repository slug"); action.createParam(PARAM_ALM_SETTING) - .setRequired(true) .setMaximumLength(200) - .setDescription("DevOps Platform setting key"); + .setDescription("DevOps Platform configuration key. This parameter is optional if you have only one BitBucket Cloud integration."); action.createParam(PARAM_NEW_CODE_DEFINITION_TYPE) .setDescription(NEW_CODE_PERIOD_TYPE_DESCRIPTION_PROJECT_CREATION) @@ -137,7 +138,7 @@ public class ImportBitbucketCloudRepoAction implements AlmIntegrationsWsAction { String newCodeDefinitionValue = request.param(PARAM_NEW_CODE_DEFINITION_VALUE); String repoSlug = request.mandatoryParam(PARAM_REPO_SLUG); - AlmSettingDto almSettingDto = importHelper.getAlmSetting(request); + AlmSettingDto almSettingDto = importHelper.getAlmSettingDtoForAlm(request, ALM.BITBUCKET_CLOUD); String workspace = ofNullable(almSettingDto.getAppId()) .orElseThrow(() -> new IllegalArgumentException(String.format("workspace for alm setting %s is missing", almSettingDto.getKey()))); diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectAction.java index cb2a8fc0174..19f2bc3d7d9 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectAction.java @@ -33,6 +33,7 @@ import org.sonar.api.server.ws.WebService; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.alm.pat.AlmPatDto; +import org.sonar.db.alm.setting.ALM; import org.sonar.db.alm.setting.AlmSettingDto; import org.sonar.db.alm.setting.ProjectAlmSettingDto; import org.sonar.db.component.BranchDto; @@ -107,12 +108,12 @@ public class ImportBitbucketServerProjectAction implements AlmIntegrationsWsActi .setSince("8.2") .setHandler(this) .setChangelog( + new Change("10.3", String.format("Parameter %s becomes optional if you have only one configuration for BitBucket Server", PARAM_ALM_SETTING)), new Change("10.3", "Endpoint visibility change from internal to public")); action.createParam(PARAM_ALM_SETTING) - .setRequired(true) .setMaximumLength(200) - .setDescription("DevOps Platform setting key"); + .setDescription("DevOps Platform configuration key. This parameter is optional if you have only one BitBucket Server integration."); action.createParam(PARAM_PROJECT_KEY) .setRequired(true) @@ -142,7 +143,7 @@ public class ImportBitbucketServerProjectAction implements AlmIntegrationsWsActi private Projects.CreateWsResponse doHandle(Request request) { importHelper.checkProvisionProjectPermission(); - AlmSettingDto almSettingDto = importHelper.getAlmSetting(request); + AlmSettingDto almSettingDto = importHelper.getAlmSettingDtoForAlm(request, ALM.BITBUCKET); String newCodeDefinitionType = request.param(PARAM_NEW_CODE_DEFINITION_TYPE); String newCodeDefinitionValue = request.param(PARAM_NEW_CODE_DEFINITION_VALUE); diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectAction.java index 13f4dea54e5..7660f86b869 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectAction.java @@ -35,6 +35,7 @@ import org.sonar.auth.github.GitHubSettings; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.alm.pat.AlmPatDto; +import org.sonar.db.alm.setting.ALM; import org.sonar.db.alm.setting.AlmSettingDto; import org.sonar.db.alm.setting.ProjectAlmSettingDto; import org.sonar.db.component.BranchDto; @@ -117,12 +118,12 @@ public class ImportGithubProjectAction implements AlmIntegrationsWsAction { .setSince("8.4") .setHandler(this) .setChangelog( + new Change("10.3", String.format("Parameter %s becomes optional if you have only one configuration for GitHub", PARAM_ALM_SETTING)), new Change("10.3", "Endpoint visibility change from internal to public")); action.createParam(PARAM_ALM_SETTING) - .setRequired(true) .setMaximumLength(200) - .setDescription("DevOps Platform setting key"); + .setDescription("DevOps Platform configuration key. This parameter is optional if you have only one GitHub integration."); action.createParam(PARAM_ORGANIZATION) .setRequired(true) @@ -151,7 +152,7 @@ public class ImportGithubProjectAction implements AlmIntegrationsWsAction { private Projects.CreateWsResponse doHandle(Request request) { importHelper.checkProvisionProjectPermission(); - AlmSettingDto almSettingDto = importHelper.getAlmSetting(request); + AlmSettingDto almSettingDto = importHelper.getAlmSettingDtoForAlm(request, ALM.GITHUB); String newCodeDefinitionType = request.param(PARAM_NEW_CODE_DEFINITION_TYPE); String newCodeDefinitionValue = request.param(PARAM_NEW_CODE_DEFINITION_VALUE); 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 e3155575f71..c532245f5e3 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 @@ -25,12 +25,14 @@ 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; +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.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.alm.pat.AlmPatDto; +import org.sonar.db.alm.setting.ALM; import org.sonar.db.alm.setting.AlmSettingDto; import org.sonar.db.alm.setting.ProjectAlmSettingDto; import org.sonar.db.component.BranchDto; @@ -52,6 +54,7 @@ import static java.util.Objects.requireNonNull; import static org.sonar.api.resources.Qualifiers.PROJECT; import static org.sonar.db.project.CreationMethod.Category.ALM_IMPORT; import static org.sonar.db.project.CreationMethod.getCreationMethod; +import static org.sonar.server.almintegration.ws.ImportHelper.PARAM_ALM_SETTING; 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; @@ -97,11 +100,13 @@ public class ImportGitLabProjectAction implements AlmIntegrationsWsAction { "Requires the 'Create Projects' permission") .setPost(true) .setSince("8.5") - .setHandler(this); + .setHandler(this) + .setChangelog( + new Change("10.3", String.format("Parameter %s becomes optional if you have only one configuration for GitLab", PARAM_ALM_SETTING))); action.createParam(ImportHelper.PARAM_ALM_SETTING) - .setRequired(true) - .setDescription("DevOps Platform setting key"); + .setDescription("DevOps Platform configuration key. This parameter is optional if you have only one GitLab integration."); + action.createParam(PARAM_GITLAB_PROJECT_ID) .setRequired(true) .setDescription("GitLab project ID"); @@ -128,7 +133,7 @@ public class ImportGitLabProjectAction implements AlmIntegrationsWsAction { String newCodeDefinitionValue = request.param(PARAM_NEW_CODE_DEFINITION_VALUE); try (DbSession dbSession = dbClient.openSession(false)) { - AlmSettingDto almSettingDto = importHelper.getAlmSetting(request); + AlmSettingDto almSettingDto = importHelper.getAlmSettingDtoForAlm(request, ALM.GITLAB); String pat = getPat(dbSession, almSettingDto); long gitlabProjectId = request.mandatoryParamAsLong(PARAM_GITLAB_PROJECT_ID); -- 2.39.5