From 92b58599bc1210a2277c3c1884ad6d281394f6ba Mon Sep 17 00:00:00 2001 From: Nolwenn Cadic <98824442+Nolwenn-cadic-sonarsource@users.noreply.github.com> Date: Mon, 12 Jun 2023 13:52:37 +0200 Subject: [PATCH] SONAR-19456 Update the api/alm_integrations/import_bitbucketserver_project API (#8507) --- .../ImportBitbucketServerProjectActionIT.java | 170 +++++++++++++++++- .../ImportBitbucketServerProjectAction.java | 52 +++++- 2 files changed, 215 insertions(+), 7 deletions(-) diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectActionIT.java index cd81e8c2452..3ac432bb989 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectActionIT.java @@ -19,6 +19,7 @@ */ package org.sonar.server.almintegration.ws.bitbucketserver; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -34,11 +35,14 @@ import org.sonar.alm.client.bitbucketserver.Project; import org.sonar.alm.client.bitbucketserver.Repository; import org.sonar.api.server.ws.WebService; import org.sonar.api.utils.System2; +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; import org.sonar.db.project.ProjectDto; import org.sonar.db.user.UserDto; import org.sonar.server.almintegration.ws.ImportHelper; @@ -51,6 +55,7 @@ import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.exceptions.UnauthorizedException; import org.sonar.server.favorite.FavoriteUpdater; import org.sonar.server.l18n.I18nRule; +import org.sonar.server.newcodeperiod.NewCodeDefinitionResolver; import org.sonar.server.permission.PermissionTemplateService; import org.sonar.server.project.DefaultBranchNameResolver; import org.sonar.server.project.ProjectDefaultVisibility; @@ -71,8 +76,12 @@ 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; import static org.sonar.db.permission.GlobalPermission.PROVISION_PROJECTS; import static org.sonar.db.permission.GlobalPermission.SCAN; +import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NEW_CODE_DEFINITION_TYPE; +import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NEW_CODE_DEFINITION_VALUE; public class ImportBitbucketServerProjectActionIT { private static final String GENERATED_PROJECT_KEY = "TEST_PROJECT_KEY"; @@ -87,6 +96,8 @@ public class ImportBitbucketServerProjectActionIT { private final ProjectDefaultVisibility projectDefaultVisibility = mock(ProjectDefaultVisibility.class); private final BitbucketServerRestClient bitbucketServerRestClient = mock(BitbucketServerRestClient.class); private final DefaultBranchNameResolver defaultBranchNameResolver = mock(DefaultBranchNameResolver.class); + private PlatformEditionProvider editionProvider = mock(PlatformEditionProvider.class); + private NewCodeDefinitionResolver newCodeDefinitionResolver = new NewCodeDefinitionResolver(db.getDbClient(), editionProvider); private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), i18n, System2.INSTANCE, mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestProjectIndexers(), new SequenceUuidFactory(), @@ -95,7 +106,7 @@ public class ImportBitbucketServerProjectActionIT { private final ImportHelper importHelper = new ImportHelper(db.getDbClient(), userSession); private final ProjectKeyGenerator projectKeyGenerator = mock(ProjectKeyGenerator.class); private final WsActionTester ws = new WsActionTester(new ImportBitbucketServerProjectAction(db.getDbClient(), userSession, - bitbucketServerRestClient, projectDefaultVisibility, componentUpdater, importHelper, projectKeyGenerator)); + bitbucketServerRestClient, projectDefaultVisibility, componentUpdater, importHelper, projectKeyGenerator, newCodeDefinitionResolver, defaultBranchNameResolver)); private static BranchesList defaultBranchesList; @@ -142,6 +153,159 @@ public class ImportBitbucketServerProjectActionIT { verify(projectKeyGenerator).generateUniqueProjectKey(requireNonNull(project.getKey()), repo.getSlug()); } + @Test + public void import_project_with_NCD_developer_edition_sets_project_NCD() { + when(editionProvider.get()).thenReturn(Optional.of(EditionProvider.Edition.DEVELOPER)); + + UserDto user = db.users().insertUser(); + userSession.logIn(user).addPermission(PROVISION_PROJECTS); + AlmSettingDto almSetting = db.almSettings().insertGitHubAlmSetting(); + db.almPats().insert(dto -> { + dto.setAlmSettingUuid(almSetting.getUuid()); + dto.setUserUuid(user.getUuid()); + }); + Project project = getGsonBBSProject(); + Repository repo = getGsonBBSRepo(project); + when(bitbucketServerRestClient.getRepo(any(), any(), any(), any())).thenReturn(repo); + when(bitbucketServerRestClient.getBranches(any(), any(), any(), any())).thenReturn(defaultBranchesList); + + Projects.CreateWsResponse response = ws.newRequest() + .setParam("almSetting", almSetting.getKey()) + .setParam("projectKey", "projectKey") + .setParam("repositorySlug", "repo-slug") + .setParam(PARAM_NEW_CODE_DEFINITION_TYPE, "NUMBER_OF_DAYS") + .setParam(PARAM_NEW_CODE_DEFINITION_VALUE, "30") + .executeProtobuf(Projects.CreateWsResponse.class); + + Projects.CreateWsResponse.Project result = response.getProject(); + assertThat(result.getKey()).isEqualTo(GENERATED_PROJECT_KEY); + assertThat(result.getName()).isEqualTo(repo.getName()); + + Optional projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey()); + assertThat(projectDto).isPresent(); + assertThat(db.getDbClient().projectAlmSettingDao().selectByProject(db.getSession(), projectDto.get())).isPresent(); + verify(projectKeyGenerator).generateUniqueProjectKey(requireNonNull(project.getKey()), repo.getSlug()); + + assertThat(db.getDbClient().newCodePeriodDao().selectByProject(db.getSession(), projectDto.get().getUuid())) + .isPresent() + .get() + .extracting(NewCodePeriodDto::getType, NewCodePeriodDto::getValue, NewCodePeriodDto::getBranchUuid) + .containsExactly(NUMBER_OF_DAYS, "30", null); + } + + @Test + public void import_project_with_NCD_community_edition_sets_branch_NCD() { + when(editionProvider.get()).thenReturn(Optional.of(EditionProvider.Edition.COMMUNITY)); + + UserDto user = db.users().insertUser(); + userSession.logIn(user).addPermission(PROVISION_PROJECTS); + AlmSettingDto almSetting = db.almSettings().insertGitHubAlmSetting(); + db.almPats().insert(dto -> { + dto.setAlmSettingUuid(almSetting.getUuid()); + dto.setUserUuid(user.getUuid()); + }); + Project project = getGsonBBSProject(); + Repository repo = getGsonBBSRepo(project); + when(bitbucketServerRestClient.getRepo(any(), any(), any(), any())).thenReturn(repo); + when(bitbucketServerRestClient.getBranches(any(), any(), any(), any())).thenReturn(defaultBranchesList); + + Projects.CreateWsResponse response = ws.newRequest() + .setParam("almSetting", almSetting.getKey()) + .setParam("projectKey", "projectKey") + .setParam("repositorySlug", "repo-slug") + .setParam(PARAM_NEW_CODE_DEFINITION_TYPE, "NUMBER_OF_DAYS") + .setParam(PARAM_NEW_CODE_DEFINITION_VALUE, "30") + .executeProtobuf(Projects.CreateWsResponse.class); + + Projects.CreateWsResponse.Project result = response.getProject(); + + Optional projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey()); + assertThat(projectDto).isPresent(); + + + String projectUuid = projectDto.get().getUuid(); + assertThat(db.getDbClient().newCodePeriodDao().selectByBranch(db.getSession(), projectUuid, projectUuid)) + .isPresent() + .get() + .extracting(NewCodePeriodDto::getType, NewCodePeriodDto::getValue, NewCodePeriodDto::getBranchUuid) + .containsExactly(NUMBER_OF_DAYS, "30", projectUuid); + } + + @Test + public void import_project_reference_branch_ncd_no_default_branch() { + when(editionProvider.get()).thenReturn(Optional.of(EditionProvider.Edition.DEVELOPER)); + when(defaultBranchNameResolver.getEffectiveMainBranchName()).thenReturn("default-branch"); + + UserDto user = db.users().insertUser(); + userSession.logIn(user).addPermission(PROVISION_PROJECTS); + AlmSettingDto almSetting = db.almSettings().insertGitHubAlmSetting(); + db.almPats().insert(dto -> { + dto.setAlmSettingUuid(almSetting.getUuid()); + dto.setUserUuid(user.getUuid()); + }); + Project project = getGsonBBSProject(); + Repository repo = getGsonBBSRepo(project); + when(bitbucketServerRestClient.getRepo(any(), any(), any(), any())).thenReturn(repo); + when(bitbucketServerRestClient.getBranches(any(), any(), any(), any())).thenReturn(new BranchesList()); + + Projects.CreateWsResponse response = ws.newRequest() + .setParam("almSetting", almSetting.getKey()) + .setParam("projectKey", "projectKey") + .setParam("repositorySlug", "repo-slug") + .setParam(PARAM_NEW_CODE_DEFINITION_TYPE, "REFERENCE_BRANCH") + .executeProtobuf(Projects.CreateWsResponse.class); + + Projects.CreateWsResponse.Project result = response.getProject(); + + Optional projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey()); + assertThat(projectDto).isPresent(); + + + String projectUuid = projectDto.get().getUuid(); + assertThat(db.getDbClient().newCodePeriodDao().selectByProject(db.getSession(), projectUuid)) + .isPresent() + .get() + .extracting(NewCodePeriodDto::getType, NewCodePeriodDto::getValue) + .containsExactly(REFERENCE_BRANCH, "default-branch"); + } + + @Test + public void import_project_reference_branch_ncd() { + when(editionProvider.get()).thenReturn(Optional.of(EditionProvider.Edition.DEVELOPER)); + + UserDto user = db.users().insertUser(); + userSession.logIn(user).addPermission(PROVISION_PROJECTS); + AlmSettingDto almSetting = db.almSettings().insertGitHubAlmSetting(); + db.almPats().insert(dto -> { + dto.setAlmSettingUuid(almSetting.getUuid()); + dto.setUserUuid(user.getUuid()); + }); + Project project = getGsonBBSProject(); + Repository repo = getGsonBBSRepo(project); + when(bitbucketServerRestClient.getRepo(any(), any(), any(), any())).thenReturn(repo); + when(bitbucketServerRestClient.getBranches(any(), any(), any(), any())).thenReturn(defaultBranchesList); + + Projects.CreateWsResponse response = ws.newRequest() + .setParam("almSetting", almSetting.getKey()) + .setParam("projectKey", "projectKey") + .setParam("repositorySlug", "repo-slug") + .setParam(PARAM_NEW_CODE_DEFINITION_TYPE, "REFERENCE_BRANCH") + .executeProtobuf(Projects.CreateWsResponse.class); + + Projects.CreateWsResponse.Project result = response.getProject(); + + Optional projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey()); + assertThat(projectDto).isPresent(); + + + String projectUuid = projectDto.get().getUuid(); + assertThat(db.getDbClient().newCodePeriodDao().selectByProject(db.getSession(), projectUuid)) + .isPresent() + .get() + .extracting(NewCodePeriodDto::getType, NewCodePeriodDto::getValue) + .containsExactly(REFERENCE_BRANCH, "default"); + } + @Test public void fail_project_already_exist() { UserDto user = db.users().insertUser(); @@ -321,7 +485,9 @@ public class ImportBitbucketServerProjectActionIT { .containsExactlyInAnyOrder( tuple("almSetting", true), tuple("repositorySlug", true), - tuple("projectKey", true)); + tuple("projectKey", true), + tuple(PARAM_NEW_CODE_DEFINITION_TYPE, false), + tuple(PARAM_NEW_CODE_DEFINITION_VALUE, false)); } private Repository getGsonBBSRepo(Project project) { diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectAction.java index e9e04d747a8..85bc552f2d4 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectAction.java @@ -21,6 +21,7 @@ package org.sonar.server.almintegration.ws.bitbucketserver; import java.util.Optional; import javax.annotation.Nullable; +import javax.inject.Inject; import org.sonar.alm.client.bitbucketserver.BitbucketServerRestClient; import org.sonar.alm.client.bitbucketserver.Branch; import org.sonar.alm.client.bitbucketserver.BranchesList; @@ -40,6 +41,8 @@ import org.sonar.server.almintegration.ws.ProjectKeyGenerator; import org.sonar.server.component.ComponentCreationData; import org.sonar.server.component.ComponentUpdater; import org.sonar.server.component.NewComponent; +import org.sonar.server.newcodeperiod.NewCodeDefinitionResolver; +import org.sonar.server.project.DefaultBranchNameResolver; import org.sonar.server.project.ProjectDefaultVisibility; import org.sonar.server.user.UserSession; import org.sonarqube.ws.Projects; @@ -49,7 +52,12 @@ import static org.sonar.api.resources.Qualifiers.PROJECT; import static org.sonar.server.almintegration.ws.ImportHelper.PARAM_ALM_SETTING; import static org.sonar.server.almintegration.ws.ImportHelper.toCreateResponse; import static org.sonar.server.component.NewComponent.newComponentBuilder; +import static org.sonar.server.newcodeperiod.NewCodeDefinitionResolver.NEW_CODE_PERIOD_TYPE_DESCRIPTION_PROJECT_CREATION; +import static org.sonar.server.newcodeperiod.NewCodeDefinitionResolver.NEW_CODE_PERIOD_VALUE_DESCRIPTION_PROJECT_CREATION; +import static org.sonar.server.newcodeperiod.NewCodeDefinitionResolver.checkNewCodeDefinitionParam; import static org.sonar.server.ws.WsUtils.writeProtobuf; +import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NEW_CODE_DEFINITION_TYPE; +import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NEW_CODE_DEFINITION_VALUE; public class ImportBitbucketServerProjectAction implements AlmIntegrationsWsAction { @@ -64,9 +72,15 @@ public class ImportBitbucketServerProjectAction implements AlmIntegrationsWsActi private final ImportHelper importHelper; private final ProjectKeyGenerator projectKeyGenerator; + private final NewCodeDefinitionResolver newCodeDefinitionResolver; + + private final DefaultBranchNameResolver defaultBranchNameResolver; + + @Inject public ImportBitbucketServerProjectAction(DbClient dbClient, UserSession userSession, BitbucketServerRestClient bitbucketServerRestClient, ProjectDefaultVisibility projectDefaultVisibility, ComponentUpdater componentUpdater, - ImportHelper importHelper, ProjectKeyGenerator projectKeyGenerator) { + ImportHelper importHelper, ProjectKeyGenerator projectKeyGenerator, NewCodeDefinitionResolver newCodeDefinitionResolver, + DefaultBranchNameResolver defaultBranchNameResolver) { this.dbClient = dbClient; this.userSession = userSession; this.bitbucketServerRestClient = bitbucketServerRestClient; @@ -74,6 +88,8 @@ public class ImportBitbucketServerProjectAction implements AlmIntegrationsWsActi this.componentUpdater = componentUpdater; this.importHelper = importHelper; this.projectKeyGenerator = projectKeyGenerator; + this.newCodeDefinitionResolver = newCodeDefinitionResolver; + this.defaultBranchNameResolver = defaultBranchNameResolver; } @Override @@ -101,6 +117,15 @@ public class ImportBitbucketServerProjectAction implements AlmIntegrationsWsActi .setRequired(true) .setMaximumLength(200) .setDescription("BitbucketServer repository slug"); + + + action.createParam(PARAM_NEW_CODE_DEFINITION_TYPE) + .setDescription(NEW_CODE_PERIOD_TYPE_DESCRIPTION_PROJECT_CREATION) + .setSince("10.1"); + + action.createParam(PARAM_NEW_CODE_DEFINITION_VALUE) + .setDescription(NEW_CODE_PERIOD_VALUE_DESCRIPTION_PROJECT_CREATION) + .setSince("10.1"); } @Override @@ -112,12 +137,12 @@ public class ImportBitbucketServerProjectAction implements AlmIntegrationsWsActi private Projects.CreateWsResponse doHandle(Request request) { importHelper.checkProvisionProjectPermission(); AlmSettingDto almSettingDto = importHelper.getAlmSetting(request); - String userUuid = importHelper.getUserUuid(); + + String newCodeDefinitionType = request.param(PARAM_NEW_CODE_DEFINITION_TYPE); + String newCodeDefinitionValue = request.param(PARAM_NEW_CODE_DEFINITION_VALUE); try (DbSession dbSession = dbClient.openSession(false)) { - Optional almPatDto = dbClient.almPatDao().selectByUserAndAlmSetting(dbSession, userUuid, almSettingDto); - String pat = almPatDto.map(AlmPatDto::getPersonalAccessToken) - .orElseThrow(() -> new IllegalArgumentException(String.format("personal access token for '%s' is missing", almSettingDto.getKey()))); + String pat = getPat(dbSession, almSettingDto); String projectKey = request.mandatoryParam(PARAM_PROJECT_KEY); String repoSlug = request.mandatoryParam(PARAM_REPO_SLUG); @@ -132,12 +157,29 @@ public class ImportBitbucketServerProjectAction implements AlmIntegrationsWsActi populatePRSetting(dbSession, repo, projectDto, almSettingDto); + checkNewCodeDefinitionParam(newCodeDefinitionType, newCodeDefinitionValue); + + if (newCodeDefinitionType != null) { + newCodeDefinitionResolver.createNewCodeDefinition(dbSession, projectDto.getUuid(), + Optional.ofNullable(defaultBranchName).orElse(defaultBranchNameResolver.getEffectiveMainBranchName()), + newCodeDefinitionType, newCodeDefinitionValue); + } + componentUpdater.commitAndIndex(dbSession, componentCreationData.mainBranchComponent()); return toCreateResponse(projectDto); } } + private String getPat(DbSession dbSession, AlmSettingDto almSettingDto) { + String userUuid = importHelper.getUserUuid(); + + Optional almPatDot = dbClient.almPatDao().selectByUserAndAlmSetting(dbSession, userUuid, almSettingDto); + return almPatDot.map(AlmPatDto::getPersonalAccessToken) + .orElseThrow(() -> new IllegalArgumentException(String.format("personal access token for '%s' is missing", + almSettingDto.getKey()))); + } + private String getDefaultBranchName(String pat, String projectKey, String repoSlug, String url) { BranchesList branches = bitbucketServerRestClient.getBranches(url, pat, projectKey, repoSlug); Optional defaultBranch = branches.findDefaultBranch(); -- 2.39.5