]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-20640 Make almSetting optional on ALM import endpoints
authorAntoine Vigneau <antoine.vigneau@sonarsource.com>
Wed, 4 Oct 2023 13:47:29 +0000 (15:47 +0200)
committersonartech <sonartech@sonarsource.com>
Thu, 5 Oct 2023 20:02:47 +0000 (20:02 +0000)
15 files changed:
scripts/patches/json [new file with mode: 0644]
server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/ImportHelperIT.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/SetPatActionIT.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectActionIT.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketcloud/ImportBitbucketCloudRepoActionIT.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectActionIT.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectActionIT.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/gitlab/ImportGitLabProjectActionIT.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/ImportHelper.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/SetPatAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketcloud/ImportBitbucketCloudRepoAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/gitlab/ImportGitLabProjectAction.java

diff --git a/scripts/patches/json b/scripts/patches/json
new file mode 100644 (file)
index 0000000..e69de29
index 8f1fa9486c858f7ca779b3c4fe68e19e5afa2aff..ad7f49c3dbae4e30029d764b75fb0450003ac262 100644 (file)
@@ -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());
+  }
 }
index c90746b6c963673f5ba25ef7ce6fdb21404f7a0e..51ad06f01af307294fd3d14dabffb7314ed4f535 100644 (file)
@@ -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));
   }
 
 }
index 9023b1c850b8fc5b29011bfff5fb1c2eb322e9c9..ce94342cfbf8fd1cd8d084e3beef5add25025d27 100644 (file)
@@ -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),
index 7cbc4ab1c1c9595a7b1c536d764c0c07bdce3f83..b117980269e2924ef8d2b19dc1dd275eb330cf6a 100644 (file)
@@ -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));
index 659d2206448f3268df566d1fbbfbe7ac54e0cecc..3ad01c29fdab24163bfba7c1a0dc511ddf8cecb1 100644 (file)
@@ -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());
index ab0840a0eda5a83fedce091c8e7d623eba29fa2a..a066fdb639a2b491f83f667584fd6173d4110660 100644 (file)
@@ -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),
index 1c21c09a77092765d52efa57e2c14b4f272895ad..b1c8414e7db8480f0da8a8c7f810020e879ebe89 100644 (file)
@@ -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);
index bc26b726f7ab716c3fcf17a440003ae1c07675c9..cfa1f1200c48356188891aa545f4210fe28cd6b0 100644 (file)
  */
 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<AlmSettingDto> 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<AlmSettingDto> 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) {
index 0743d3e82200f556f51f3fc8d45bf8f60a42ccc9..a2a866afde1af0eeb0829f6fd11fcd64f0ccf382 100644 (file)
@@ -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> almPatDto = dbClient.almPatDao().selectByUserAndAlmSetting(dbSession, userUuid, almSetting);
+      Optional<AlmPatDto> 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<AlmSettingDto> 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));
+  }
+
 }
index 31f371d5bcdf017b6860c768dcebcd257a79daf7..4f3b4e22ebfabfeaaa2645493e2a655edfbc7590 100644 (file)
@@ -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);
index c1b275d1402aa9a64b1a1d15986ebbc0f3f26d74..23ee5b8aea2f5853f886f21a246b02150c58f48d 100644 (file)
@@ -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())));
 
index cb2a8fc017404964ce71c63f69eab6d0c333fd31..19f2bc3d7d92a716913b8c174ab4692b2dc21776 100644 (file)
@@ -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);
index 13f4dea54e5925223bfa644302aed1194df69f1d..7660f86b8695ccae4f96face70e67d88f8c09101 100644 (file)
@@ -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);
index e3155575f716990e0d2894b0a0daf6000315b631..c532245f5e3f246f4135563afd2b5a358fb8940b 100644 (file)
@@ -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);