Browse Source

SONAR-20640 Make almSetting optional on ALM import endpoints

tags/10.3.0.82913
Antoine Vigneau 7 months ago
parent
commit
38ab30d708
15 changed files with 522 additions and 147 deletions
  1. 0
    0
      scripts/patches/json
  2. 52
    28
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/ImportHelperIT.java
  3. 65
    17
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/SetPatActionIT.java
  4. 61
    18
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectActionIT.java
  5. 52
    14
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketcloud/ImportBitbucketCloudRepoActionIT.java
  6. 63
    20
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectActionIT.java
  7. 59
    15
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectActionIT.java
  8. 59
    0
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/gitlab/ImportGitLabProjectActionIT.java
  9. 43
    5
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/ImportHelper.java
  10. 43
    14
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/SetPatAction.java
  11. 4
    3
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectAction.java
  12. 4
    3
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketcloud/ImportBitbucketCloudRepoAction.java
  13. 4
    3
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectAction.java
  14. 4
    3
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectAction.java
  15. 9
    4
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/gitlab/ImportGitLabProjectAction.java

+ 0
- 0
scripts/patches/json View File


+ 52
- 28
server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/ImportHelperIT.java View File



import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.sonar.api.impl.ws.SimpleGetRequest;
import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Request;
import org.sonar.api.utils.System2; import org.sonar.api.utils.System2;
import org.sonar.db.DbTester; import org.sonar.db.DbTester;
import org.sonar.db.alm.setting.ALM;
import org.sonar.db.alm.setting.AlmSettingDto; import org.sonar.db.alm.setting.AlmSettingDto;
import org.sonar.db.component.ProjectTesting; import org.sonar.db.component.ProjectTesting;
import org.sonar.db.project.ProjectDto; import org.sonar.db.project.ProjectDto;


import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy; 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; import static org.sonarqube.ws.Projects.CreateWsResponse;


public class ImportHelperIT { 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 System2 system2 = System2.INSTANCE;
private final ProjectDto projectDto = ProjectTesting.newPublicProjectDto(); private final ProjectDto projectDto = ProjectTesting.newPublicProjectDto();
private final Request request = mock(Request.class);
private final Request emptyRequest = new SimpleGetRequest();


@Rule @Rule
public final DbTester db = DbTester.create(system2); public final DbTester db = DbTester.create(system2);
private final ImportHelper underTest = new ImportHelper(db.getDbClient(), userSession); private final ImportHelper underTest = new ImportHelper(db.getDbClient(), userSession);


@Test @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) .isInstanceOf(UnauthorizedException.class)
.hasMessage("Authentication is required"); .hasMessage("Authentication is required");
} }


@Test @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 @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 @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 @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 @Test
public void getAlmSetting_whenAlmSettingExists_shouldReturnActualAlmSetting(){
public void getAlmConfig_whenConfigExists_shouldReturnConfig(){
AlmSettingDto almSettingDto = db.almSettings().insertAzureAlmSetting(); 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()); 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());
}
} }

+ 65
- 17
server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/SetPatActionIT.java View File

import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.exceptions.UnauthorizedException; import org.sonar.server.exceptions.UnauthorizedException;
import org.sonar.server.tester.UserSessionRule; import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.TestRequest;
import org.sonar.server.ws.WsActionTester; import org.sonar.server.ws.WsActionTester;


import static org.assertj.core.api.Assertions.assertThat; 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.assertThatThrownBy;
import static org.assertj.core.api.Assertions.tuple; import static org.assertj.core.api.Assertions.tuple;
import static org.sonar.db.permission.GlobalPermission.PROVISION_PROJECTS; import static org.sonar.db.permission.GlobalPermission.PROVISION_PROJECTS;
@Rule @Rule
public DbTester db = DbTester.create(); 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 @Test
public void set_new_azuredevops_pat() { public void set_new_azuredevops_pat() {
.hasMessage("Username cannot be null for Bitbucket Cloud"); .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 @Test
public void set_new_github_pat() { public void set_new_github_pat() {
UserDto user = db.users().insertUser(); UserDto user = db.users().insertUser();
.hasMessage("Insufficient privileges"); .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 @Test
public void definition() { public void definition() {
WebService.Action def = ws.getDef(); WebService.Action def = ws.getDef();
assertThat(def.isPost()).isTrue(); assertThat(def.isPost()).isTrue();
assertThat(def.params()) assertThat(def.params())
.extracting(WebService.Param::key, WebService.Param::isRequired) .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));
} }


} }

+ 61
- 18
server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectActionIT.java View File

import org.sonar.core.platform.PlatformEditionProvider; import org.sonar.core.platform.PlatformEditionProvider;
import org.sonar.core.util.SequenceUuidFactory; import org.sonar.core.util.SequenceUuidFactory;
import org.sonar.db.DbTester; 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.AlmSettingDto;
import org.sonar.db.alm.setting.ProjectAlmSettingDto; import org.sonar.db.alm.setting.ProjectAlmSettingDto;
import org.sonar.db.component.BranchDto; import org.sonar.db.component.BranchDto;


import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
import static org.assertj.core.api.Assertions.assertThat; 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.assertThatThrownBy;
import static org.assertj.core.api.Assertions.tuple; import static org.assertj.core.api.Assertions.tuple;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; 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.component.BranchDto.DEFAULT_MAIN_BRANCH_NAME;
import static org.sonar.db.newcodeperiod.NewCodePeriodType.NUMBER_OF_DAYS; import static org.sonar.db.newcodeperiod.NewCodePeriodType.NUMBER_OF_DAYS;
import static org.sonar.db.newcodeperiod.NewCodePeriodType.REFERENCE_BRANCH; import static org.sonar.db.newcodeperiod.NewCodePeriodType.REFERENCE_BRANCH;
.hasMessage("personal access token for '" + almSetting.getKey() + "' is missing"); .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 @Test
public void fail_project_already_exists() { public void fail_project_already_exists() {
AlmSettingDto almSetting = configureUserAndAlmSettings(); AlmSettingDto almSetting = configureUserAndAlmSettings();
GENERATED_PROJECT_KEY); 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 @Test
public void define() { public void define() {
WebService.Action def = ws.getDef(); WebService.Action def = ws.getDef();
assertThat(def.params()) assertThat(def.params())
.extracting(WebService.Param::key, WebService.Param::isRequired) .extracting(WebService.Param::key, WebService.Param::isRequired)
.containsExactlyInAnyOrder( .containsExactlyInAnyOrder(
tuple("almSetting", true),
tuple("almSetting", false),
tuple("projectName", true), tuple("projectName", true),
tuple("repositoryName", true), tuple("repositoryName", true),
tuple(PARAM_NEW_CODE_DEFINITION_TYPE, false), tuple(PARAM_NEW_CODE_DEFINITION_TYPE, false),

+ 52
- 14
server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketcloud/ImportBitbucketCloudRepoActionIT.java View File

import org.sonar.core.platform.PlatformEditionProvider; import org.sonar.core.platform.PlatformEditionProvider;
import org.sonar.core.util.SequenceUuidFactory; import org.sonar.core.util.SequenceUuidFactory;
import org.sonar.db.DbTester; 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.AlmSettingDto;
import org.sonar.db.alm.setting.ProjectAlmSettingDto; import org.sonar.db.alm.setting.ProjectAlmSettingDto;
import org.sonar.db.component.BranchDto; import org.sonar.db.component.BranchDto;


import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
import static org.assertj.core.api.Assertions.assertThat; 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.assertThatThrownBy;
import static org.assertj.core.api.Assertions.tuple; import static org.assertj.core.api.Assertions.tuple;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; 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.NUMBER_OF_DAYS;
import static org.sonar.db.newcodeperiod.NewCodePeriodType.REFERENCE_BRANCH; import static org.sonar.db.newcodeperiod.NewCodePeriodType.REFERENCE_BRANCH;
import static org.sonar.db.permission.GlobalPermission.PROVISION_PROJECTS; import static org.sonar.db.permission.GlobalPermission.PROVISION_PROJECTS;
} }


@Test @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(); UserDto user = db.users().insertUser();
userSession.logIn(user).addPermission(PROVISION_PROJECTS); userSession.logIn(user).addPermission(PROVISION_PROJECTS);
AlmPatDto almPatDto = newAlmPatDto();
db.getDbClient().almPatDao().insert(db.getSession(), almPatDto, user.getLogin(), null);


TestRequest request = ws.newRequest() TestRequest request = ws.newRequest()
.setParam("almSetting", "testKey")
.setParam("repositorySlug", "repo");
.setParam("almSetting", "unknown")
.setParam("repositorySlug", "repo-slug");


assertThatThrownBy(request::execute) assertThatThrownBy(request::execute)
.isInstanceOf(NotFoundException.class) .isInstanceOf(NotFoundException.class)
.hasMessageContaining("DevOps Platform Setting 'testKey' not found");
.hasMessage("DevOps Platform configuration 'unknown' not found.");
} }


@Test @Test
public void fail_when_no_creation_project_permission() {
public void importProject_whenNoAlmSettingKeyAndNoConfig_shouldThrow() {
UserDto user = db.users().insertUser(); UserDto user = db.users().insertUser();
userSession.logIn(user);
userSession.logIn(user).addPermission(PROVISION_PROJECTS);


TestRequest request = ws.newRequest() TestRequest request = ws.newRequest()
.setParam("almSetting", "anyvalue");
.setParam("repositorySlug", "repo-slug");


assertThatThrownBy(request::execute) 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 @Test
assertThat(def.params()) assertThat(def.params())
.extracting(WebService.Param::key, WebService.Param::isRequired) .extracting(WebService.Param::key, WebService.Param::isRequired)
.containsExactlyInAnyOrder( .containsExactlyInAnyOrder(
tuple("almSetting", true),
tuple("almSetting", false),
tuple("repositorySlug", true), tuple("repositorySlug", true),
tuple(PARAM_NEW_CODE_DEFINITION_TYPE, false), tuple(PARAM_NEW_CODE_DEFINITION_TYPE, false),
tuple(PARAM_NEW_CODE_DEFINITION_VALUE, false)); tuple(PARAM_NEW_CODE_DEFINITION_VALUE, false));

+ 63
- 20
server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectActionIT.java View File

import org.sonar.core.platform.PlatformEditionProvider; import org.sonar.core.platform.PlatformEditionProvider;
import org.sonar.core.util.SequenceUuidFactory; import org.sonar.core.util.SequenceUuidFactory;
import org.sonar.db.DbTester; 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.AlmSettingDto;
import org.sonar.db.component.BranchDto; import org.sonar.db.component.BranchDto;
import org.sonar.db.newcodeperiod.NewCodePeriodDto; import org.sonar.db.newcodeperiod.NewCodePeriodDto;
import org.sonar.server.project.ProjectDefaultVisibility; import org.sonar.server.project.ProjectDefaultVisibility;
import org.sonar.server.project.Visibility; import org.sonar.server.project.Visibility;
import org.sonar.server.tester.UserSessionRule; import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.TestRequest;
import org.sonar.server.ws.WsActionTester; import org.sonar.server.ws.WsActionTester;
import org.sonarqube.ws.Projects; import org.sonarqube.ws.Projects;


import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
import static org.apache.commons.lang.math.JVMRandom.nextLong; import static org.apache.commons.lang.math.JVMRandom.nextLong;
import static org.assertj.core.api.Assertions.assertThat; 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.assertThatThrownBy;
import static org.assertj.core.api.Assertions.tuple; import static org.assertj.core.api.Assertions.tuple;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; 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.component.BranchDto.DEFAULT_MAIN_BRANCH_NAME;
import static org.sonar.db.newcodeperiod.NewCodePeriodType.NUMBER_OF_DAYS; import static org.sonar.db.newcodeperiod.NewCodePeriodType.NUMBER_OF_DAYS;
import static org.sonar.db.newcodeperiod.NewCodePeriodType.REFERENCE_BRANCH; import static org.sonar.db.newcodeperiod.NewCodePeriodType.REFERENCE_BRANCH;
.hasMessage("personal access token for '" + almSetting.getKey() + "' is missing"); .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 @Test
public void fail_when_no_creation_project_permission() { public void fail_when_no_creation_project_permission() {
UserDto user = db.users().insertUser(); UserDto user = db.users().insertUser();
assertThat(mainBranchName).isEqualTo("default"); 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 @Test
public void definition() { public void definition() {
WebService.Action def = ws.getDef(); WebService.Action def = ws.getDef();
assertThat(def.params()) assertThat(def.params())
.extracting(WebService.Param::key, WebService.Param::isRequired) .extracting(WebService.Param::key, WebService.Param::isRequired)
.containsExactlyInAnyOrder( .containsExactlyInAnyOrder(
tuple("almSetting", true),
tuple("almSetting", false),
tuple("repositorySlug", true), tuple("repositorySlug", true),
tuple("projectKey", true), tuple("projectKey", true),
tuple(PARAM_NEW_CODE_DEFINITION_TYPE, false), tuple(PARAM_NEW_CODE_DEFINITION_TYPE, false),
private AlmSettingDto configureUserAndPatAndAlmSettings() { private AlmSettingDto configureUserAndPatAndAlmSettings() {
UserDto user = db.users().insertUser(); UserDto user = db.users().insertUser();
userSession.logIn(user).addPermission(PROVISION_PROJECTS); userSession.logIn(user).addPermission(PROVISION_PROJECTS);
AlmSettingDto almSetting = db.almSettings().insertGitHubAlmSetting();
AlmSettingDto almSetting = db.almSettings().insertBitbucketAlmSetting();
db.almPats().insert(dto -> { db.almPats().insert(dto -> {
dto.setAlmSettingUuid(almSetting.getUuid()); dto.setAlmSettingUuid(almSetting.getUuid());
dto.setUserUuid(user.getUuid()); dto.setUserUuid(user.getUuid());

+ 59
- 15
server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectActionIT.java View File



import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
import static org.assertj.core.api.Assertions.assertThat; 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.assertThatThrownBy;
import static org.assertj.core.api.Assertions.tuple; import static org.assertj.core.api.Assertions.tuple;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
assertThat(projectDto.orElseThrow().getCreationMethod()).isEqualTo(CreationMethod.ALM_IMPORT_BROWSER); 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) { private Projects.CreateWsResponse callWebService(AlmSettingDto githubAlmSetting) {
return ws.newRequest() return ws.newRequest()
.setParam(PARAM_ALM_SETTING, githubAlmSetting.getKey()) .setParam(PARAM_ALM_SETTING, githubAlmSetting.getKey())
.isInstanceOf(UnauthorizedException.class); .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 @Test
public void fail_when_personal_access_token_doesnt_exist() { public void fail_when_personal_access_token_doesnt_exist() {
AlmSettingDto githubAlmSetting = setupUserAndAlmSettings(); AlmSettingDto githubAlmSetting = setupUserAndAlmSettings();
assertThat(def.params()) assertThat(def.params())
.extracting(WebService.Param::key, WebService.Param::isRequired) .extracting(WebService.Param::key, WebService.Param::isRequired)
.containsExactlyInAnyOrder( .containsExactlyInAnyOrder(
tuple(PARAM_ALM_SETTING, true),
tuple(PARAM_ALM_SETTING, false),
tuple(PARAM_ORGANIZATION, true), tuple(PARAM_ORGANIZATION, true),
tuple(PARAM_REPOSITORY_KEY, true), tuple(PARAM_REPOSITORY_KEY, true),
tuple(PARAM_NEW_CODE_DEFINITION_TYPE, false), tuple(PARAM_NEW_CODE_DEFINITION_TYPE, false),

+ 59
- 0
server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/gitlab/ImportGitLabProjectActionIT.java View File

import org.sonar.server.almintegration.ws.ProjectKeyGenerator; import org.sonar.server.almintegration.ws.ProjectKeyGenerator;
import org.sonar.server.component.ComponentUpdater; import org.sonar.server.component.ComponentUpdater;
import org.sonar.server.es.TestIndexers; import org.sonar.server.es.TestIndexers;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.favorite.FavoriteUpdater; import org.sonar.server.favorite.FavoriteUpdater;
import org.sonar.server.newcodeperiod.NewCodeDefinitionResolver; import org.sonar.server.newcodeperiod.NewCodeDefinitionResolver;
import org.sonar.server.permission.PermissionService; import org.sonar.server.permission.PermissionService;
import org.sonar.server.project.ProjectDefaultVisibility; import org.sonar.server.project.ProjectDefaultVisibility;
import org.sonar.server.project.Visibility; import org.sonar.server.project.Visibility;
import org.sonar.server.tester.UserSessionRule; import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.TestRequest;
import org.sonar.server.ws.WsActionTester; import org.sonar.server.ws.WsActionTester;
import org.sonarqube.ws.Projects; import org.sonarqube.ws.Projects;


import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
import static org.assertj.core.api.Assertions.assertThat; 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.assertj.core.api.Assertions.tuple;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
assertThat(projectDto.orElseThrow().getCreationMethod()).isEqualTo(CreationMethod.ALM_IMPORT_BROWSER); 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() { private AlmSettingDto configureUserAndPatAndAlmSettings() {
UserDto user = db.users().insertUser(); UserDto user = db.users().insertUser();
userSession.logIn(user).addPermission(PROVISION_PROJECTS); userSession.logIn(user).addPermission(PROVISION_PROJECTS);

+ 43
- 5
server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/ImportHelper.java View File

*/ */
package org.sonar.server.almintegration.ws; 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.ServerSide;
import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Request;
import org.sonar.db.DbClient; import org.sonar.db.DbClient;
import org.sonar.db.DbSession; import org.sonar.db.DbSession;
import org.sonar.db.alm.setting.ALM;
import org.sonar.db.alm.setting.AlmSettingDto; import org.sonar.db.alm.setting.AlmSettingDto;
import org.sonar.db.project.ProjectDto; import org.sonar.db.project.ProjectDto;
import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.exceptions.NotFoundException;
userSession.checkLoggedIn().checkPermission(PROVISION_PROJECTS); 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)) { 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() { 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) { public static CreateWsResponse toCreateResponse(ProjectDto projectDto) {

+ 43
- 14
server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/SetPatAction.java View File

package org.sonar.server.almintegration.ws; package org.sonar.server.almintegration.ws;


import com.google.common.base.Strings; import com.google.common.base.Strings;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import javax.annotation.Nullable;
import org.sonar.api.server.ws.Change; import org.sonar.api.server.ws.Change;
import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.Response;
import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.user.UserSession; import org.sonar.server.user.UserSession;


import static java.lang.String.format;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
import static org.sonar.db.alm.setting.ALM.BITBUCKET_CLOUD; import static org.sonar.db.alm.setting.ALM.BITBUCKET_CLOUD;
import static org.sonar.db.permission.GlobalPermission.PROVISION_PROJECTS; import static org.sonar.db.permission.GlobalPermission.PROVISION_PROJECTS;


private final DbClient dbClient; private final DbClient dbClient;
private final UserSession userSession; 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.dbClient = dbClient;
this.userSession = userSession; this.userSession = userSession;
this.importHelper = importHelper;
} }


@Override @Override
.setHandler(this) .setHandler(this)
.setChangelog( .setChangelog(
new Change("9.0", "Bitbucket Cloud support and optional Username parameter were added"), 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) 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) action.createParam(PARAM_PAT)
.setRequired(true) .setRequired(true)
.setMaximumLength(2000) .setMaximumLength(2000)
.setDescription("Personal Access Token"); .setDescription("Personal Access Token");

action.createParam(PARAM_USERNAME) action.createParam(PARAM_USERNAME)
.setRequired(false) .setRequired(false)
.setMaximumLength(2000) .setMaximumLength(2000)
userSession.checkLoggedIn().checkPermission(PROVISION_PROJECTS); userSession.checkLoggedIn().checkPermission(PROVISION_PROJECTS);


String pat = request.mandatoryParam(PARAM_PAT); String pat = request.mandatoryParam(PARAM_PAT);
String almSettingKey = request.mandatoryParam(PARAM_ALM_SETTING);
String username = request.param(PARAM_USERNAME); String username = request.param(PARAM_USERNAME);


String userUuid = requireNonNull(userSession.getUuid(), "User UUID cannot be null"); 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"); 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()) { if (almPatDto.isPresent()) {
AlmPatDto almPat = almPatDto.get(); AlmPatDto almPat = almPatDto.get();
almPat.setPersonalAccessToken(resultingPat); almPat.setPersonalAccessToken(resultingPat);
dbClient.almPatDao().update(dbSession, almPat, userSession.getLogin(), almSetting.getKey());
dbClient.almPatDao().update(dbSession, almPat, userSession.getLogin(), almSettingDto.getKey());
} else { } else {
AlmPatDto almPat = new AlmPatDto() AlmPatDto almPat = new AlmPatDto()
.setPersonalAccessToken(resultingPat) .setPersonalAccessToken(resultingPat)
.setAlmSettingUuid(almSetting.getUuid())
.setAlmSettingUuid(almSettingDto.getUuid())
.setUserUuid(userUuid); .setUserUuid(userUuid);
dbClient.almPatDao().insert(dbSession, almPat, userSession.getLogin(), almSetting.getKey());
dbClient.almPatDao().insert(dbSession, almPat, userSession.getLogin(), almSettingDto.getKey());
} }
dbSession.commit(); 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));
}

} }

+ 4
- 3
server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectAction.java View File

import org.sonar.db.DbClient; import org.sonar.db.DbClient;
import org.sonar.db.DbSession; import org.sonar.db.DbSession;
import org.sonar.db.alm.pat.AlmPatDto; 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.AlmSettingDto;
import org.sonar.db.alm.setting.ProjectAlmSettingDto; import org.sonar.db.alm.setting.ProjectAlmSettingDto;
import org.sonar.db.component.BranchDto; import org.sonar.db.component.BranchDto;
.setSince("8.6") .setSince("8.6")
.setHandler(this) .setHandler(this)
.setChangelog( .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")); new Change("10.3", "Endpoint visibility change from internal to public"));


action.createParam(PARAM_ALM_SETTING) action.createParam(PARAM_ALM_SETTING)
.setRequired(true)
.setMaximumLength(200) .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) action.createParam(PARAM_PROJECT_NAME)
.setRequired(true) .setRequired(true)


private CreateWsResponse doHandle(Request request) { private CreateWsResponse doHandle(Request request) {
importHelper.checkProvisionProjectPermission(); 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 newCodeDefinitionType = request.param(PARAM_NEW_CODE_DEFINITION_TYPE);
String newCodeDefinitionValue = request.param(PARAM_NEW_CODE_DEFINITION_VALUE); String newCodeDefinitionValue = request.param(PARAM_NEW_CODE_DEFINITION_VALUE);

+ 4
- 3
server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketcloud/ImportBitbucketCloudRepoAction.java View File

import org.sonar.db.DbClient; import org.sonar.db.DbClient;
import org.sonar.db.DbSession; import org.sonar.db.DbSession;
import org.sonar.db.alm.pat.AlmPatDto; 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.AlmSettingDto;
import org.sonar.db.alm.setting.ProjectAlmSettingDto; import org.sonar.db.alm.setting.ProjectAlmSettingDto;
import org.sonar.db.component.BranchDto; import org.sonar.db.component.BranchDto;
.setSince("9.0") .setSince("9.0")
.setHandler(this) .setHandler(this)
.setChangelog( .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")); new Change("10.3", "Endpoint visibility change from internal to public"));


action.createParam(PARAM_REPO_SLUG) action.createParam(PARAM_REPO_SLUG)
.setDescription("Bitbucket Cloud repository slug"); .setDescription("Bitbucket Cloud repository slug");


action.createParam(PARAM_ALM_SETTING) action.createParam(PARAM_ALM_SETTING)
.setRequired(true)
.setMaximumLength(200) .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) action.createParam(PARAM_NEW_CODE_DEFINITION_TYPE)
.setDescription(NEW_CODE_PERIOD_TYPE_DESCRIPTION_PROJECT_CREATION) .setDescription(NEW_CODE_PERIOD_TYPE_DESCRIPTION_PROJECT_CREATION)
String newCodeDefinitionValue = request.param(PARAM_NEW_CODE_DEFINITION_VALUE); String newCodeDefinitionValue = request.param(PARAM_NEW_CODE_DEFINITION_VALUE);


String repoSlug = request.mandatoryParam(PARAM_REPO_SLUG); 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()) String workspace = ofNullable(almSettingDto.getAppId())
.orElseThrow(() -> new IllegalArgumentException(String.format("workspace for alm setting %s is missing", almSettingDto.getKey()))); .orElseThrow(() -> new IllegalArgumentException(String.format("workspace for alm setting %s is missing", almSettingDto.getKey())));



+ 4
- 3
server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectAction.java View File

import org.sonar.db.DbClient; import org.sonar.db.DbClient;
import org.sonar.db.DbSession; import org.sonar.db.DbSession;
import org.sonar.db.alm.pat.AlmPatDto; 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.AlmSettingDto;
import org.sonar.db.alm.setting.ProjectAlmSettingDto; import org.sonar.db.alm.setting.ProjectAlmSettingDto;
import org.sonar.db.component.BranchDto; import org.sonar.db.component.BranchDto;
.setSince("8.2") .setSince("8.2")
.setHandler(this) .setHandler(this)
.setChangelog( .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")); new Change("10.3", "Endpoint visibility change from internal to public"));


action.createParam(PARAM_ALM_SETTING) action.createParam(PARAM_ALM_SETTING)
.setRequired(true)
.setMaximumLength(200) .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) action.createParam(PARAM_PROJECT_KEY)
.setRequired(true) .setRequired(true)


private Projects.CreateWsResponse doHandle(Request request) { private Projects.CreateWsResponse doHandle(Request request) {
importHelper.checkProvisionProjectPermission(); importHelper.checkProvisionProjectPermission();
AlmSettingDto almSettingDto = importHelper.getAlmSetting(request);
AlmSettingDto almSettingDto = importHelper.getAlmSettingDtoForAlm(request, ALM.BITBUCKET);


String newCodeDefinitionType = request.param(PARAM_NEW_CODE_DEFINITION_TYPE); String newCodeDefinitionType = request.param(PARAM_NEW_CODE_DEFINITION_TYPE);
String newCodeDefinitionValue = request.param(PARAM_NEW_CODE_DEFINITION_VALUE); String newCodeDefinitionValue = request.param(PARAM_NEW_CODE_DEFINITION_VALUE);

+ 4
- 3
server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectAction.java View File

import org.sonar.db.DbClient; import org.sonar.db.DbClient;
import org.sonar.db.DbSession; import org.sonar.db.DbSession;
import org.sonar.db.alm.pat.AlmPatDto; 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.AlmSettingDto;
import org.sonar.db.alm.setting.ProjectAlmSettingDto; import org.sonar.db.alm.setting.ProjectAlmSettingDto;
import org.sonar.db.component.BranchDto; import org.sonar.db.component.BranchDto;
.setSince("8.4") .setSince("8.4")
.setHandler(this) .setHandler(this)
.setChangelog( .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")); new Change("10.3", "Endpoint visibility change from internal to public"));


action.createParam(PARAM_ALM_SETTING) action.createParam(PARAM_ALM_SETTING)
.setRequired(true)
.setMaximumLength(200) .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) action.createParam(PARAM_ORGANIZATION)
.setRequired(true) .setRequired(true)


private Projects.CreateWsResponse doHandle(Request request) { private Projects.CreateWsResponse doHandle(Request request) {
importHelper.checkProvisionProjectPermission(); importHelper.checkProvisionProjectPermission();
AlmSettingDto almSettingDto = importHelper.getAlmSetting(request);
AlmSettingDto almSettingDto = importHelper.getAlmSettingDtoForAlm(request, ALM.GITHUB);


String newCodeDefinitionType = request.param(PARAM_NEW_CODE_DEFINITION_TYPE); String newCodeDefinitionType = request.param(PARAM_NEW_CODE_DEFINITION_TYPE);
String newCodeDefinitionValue = request.param(PARAM_NEW_CODE_DEFINITION_VALUE); String newCodeDefinitionValue = request.param(PARAM_NEW_CODE_DEFINITION_VALUE);

+ 9
- 4
server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/gitlab/ImportGitLabProjectAction.java View File

import org.sonar.alm.client.gitlab.GitLabBranch; import org.sonar.alm.client.gitlab.GitLabBranch;
import org.sonar.alm.client.gitlab.GitlabHttpClient; import org.sonar.alm.client.gitlab.GitlabHttpClient;
import org.sonar.alm.client.gitlab.Project; 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.Request;
import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService; import org.sonar.api.server.ws.WebService;
import org.sonar.db.DbClient; import org.sonar.db.DbClient;
import org.sonar.db.DbSession; import org.sonar.db.DbSession;
import org.sonar.db.alm.pat.AlmPatDto; 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.AlmSettingDto;
import org.sonar.db.alm.setting.ProjectAlmSettingDto; import org.sonar.db.alm.setting.ProjectAlmSettingDto;
import org.sonar.db.component.BranchDto; import org.sonar.db.component.BranchDto;
import static org.sonar.api.resources.Qualifiers.PROJECT; 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.Category.ALM_IMPORT;
import static org.sonar.db.project.CreationMethod.getCreationMethod; 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.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_TYPE_DESCRIPTION_PROJECT_CREATION;
import static org.sonar.server.newcodeperiod.NewCodeDefinitionResolver.NEW_CODE_PERIOD_VALUE_DESCRIPTION_PROJECT_CREATION; import static org.sonar.server.newcodeperiod.NewCodeDefinitionResolver.NEW_CODE_PERIOD_VALUE_DESCRIPTION_PROJECT_CREATION;
"Requires the 'Create Projects' permission") "Requires the 'Create Projects' permission")
.setPost(true) .setPost(true)
.setSince("8.5") .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) 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) action.createParam(PARAM_GITLAB_PROJECT_ID)
.setRequired(true) .setRequired(true)
.setDescription("GitLab project ID"); .setDescription("GitLab project ID");
String newCodeDefinitionValue = request.param(PARAM_NEW_CODE_DEFINITION_VALUE); String newCodeDefinitionValue = request.param(PARAM_NEW_CODE_DEFINITION_VALUE);


try (DbSession dbSession = dbClient.openSession(false)) { try (DbSession dbSession = dbClient.openSession(false)) {
AlmSettingDto almSettingDto = importHelper.getAlmSetting(request);
AlmSettingDto almSettingDto = importHelper.getAlmSettingDtoForAlm(request, ALM.GITLAB);
String pat = getPat(dbSession, almSettingDto); String pat = getPat(dbSession, almSettingDto);


long gitlabProjectId = request.mandatoryParamAsLong(PARAM_GITLAB_PROJECT_ID); long gitlabProjectId = request.mandatoryParamAsLong(PARAM_GITLAB_PROJECT_ID);

Loading…
Cancel
Save