From: Zipeng WU Date: Fri, 14 May 2021 13:53:50 +0000 (+0200) Subject: SONAR-14804 Identify already imported bitbucket cloud repository when onboarding X-Git-Tag: 9.0.0.45539~169 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=8e4eb316ef602ec28ee7a707adcaa05836b9f780;p=sonarqube.git SONAR-14804 Identify already imported bitbucket cloud repository when onboarding --- diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketcloud/SearchBitbucketCloudReposAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketcloud/SearchBitbucketCloudReposAction.java index 15267d12951..5675392144e 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketcloud/SearchBitbucketCloudReposAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/bitbucketcloud/SearchBitbucketCloudReposAction.java @@ -20,8 +20,11 @@ package org.sonar.server.almintegration.ws.bitbucketcloud; import java.util.List; -import java.util.Optional; +import java.util.Map; import org.sonar.alm.client.bitbucket.bitbucketcloud.BitbucketCloudRestClient; +import java.util.Optional; +import java.util.Set; +import java.util.function.BinaryOperator; import org.sonar.alm.client.bitbucket.bitbucketcloud.Repository; import org.sonar.alm.client.bitbucket.bitbucketcloud.RepositoryList; import org.sonar.api.server.ws.Request; @@ -31,16 +34,20 @@ import org.sonar.db.DbClient; import org.sonar.db.DbSession; 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.project.ProjectDto; import org.sonar.server.almintegration.ws.AlmIntegrationsWsAction; import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.user.UserSession; import org.sonarqube.ws.AlmIntegrations.BBCRepo; import org.sonarqube.ws.AlmIntegrations.SearchBitbucketcloudReposWsResponse; -import org.sonarqube.ws.Common; +import org.sonarqube.ws.Common.Paging; import static java.util.Objects.requireNonNull; import static java.util.Optional.ofNullable; import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toMap; +import static java.util.stream.Collectors.toSet; import static org.sonar.api.server.ws.WebService.Param.PAGE; import static org.sonar.api.server.ws.WebService.Param.PAGE_SIZE; import static org.sonar.db.permission.GlobalPermission.PROVISION_PROJECTS; @@ -48,6 +55,7 @@ import static org.sonar.server.ws.WsUtils.writeProtobuf; public class SearchBitbucketCloudReposAction implements AlmIntegrationsWsAction { + private static final BinaryOperator resolveCollisionByNaturalOrder = (a, b) -> a.compareTo(b) < 0 ? a : b; private static final String PARAM_ALM_SETTING = "almSetting"; private static final String PARAM_REPO_NAME = "repositoryName"; private static final int DEFAULT_PAGE_SIZE = 20; @@ -112,29 +120,45 @@ public class SearchBitbucketCloudReposAction implements AlmIntegrationsWsAction RepositoryList repositoryList = bitbucketCloudRestClient.searchRepos(pat, workspace, repoName, page, pageSize); + Map sqProjectKeyByRepoSlug = getSqProjectKeyByRepoSlug(dbSession, almSettingDto, repositoryList.getValues()); + List bbcRepos = repositoryList.getValues().stream() - .map(repository -> toBBCRepo(repository, workspace)) + .map(repository -> toBBCRepo(repository, workspace, sqProjectKeyByRepoSlug)) .collect(toList()); SearchBitbucketcloudReposWsResponse.Builder builder = SearchBitbucketcloudReposWsResponse.newBuilder() .setIsLastPage(repositoryList.getNext() == null) - .setPaging(Common.Paging.newBuilder() - .setPageIndex(page) - .setPageSize(pageSize) - .build()) + .setPaging(Paging.newBuilder().setPageIndex(page).setPageSize(pageSize).build()) .addAllRepositories(bbcRepos); return builder.build(); } } - private static BBCRepo toBBCRepo(Repository gsonBBCRepo, String workspace) { - return BBCRepo.newBuilder() + private Map getSqProjectKeyByRepoSlug(DbSession dbSession, AlmSettingDto almSettingDto, List repositories) { + Set slugs = repositories.stream().map(Repository::getSlug).collect(toSet()); + + List projectAlmSettingDtos = dbClient.projectAlmSettingDao().selectByAlmSettingAndSlugs(dbSession, almSettingDto, slugs); + + Map repoSlugByProjectUuid = projectAlmSettingDtos.stream() + .collect(toMap(ProjectAlmSettingDto::getProjectUuid, ProjectAlmSettingDto::getAlmSlug)); + + return dbClient.projectDao().selectByUuids(dbSession, repoSlugByProjectUuid.keySet()) + .stream() + .collect(toMap(p -> repoSlugByProjectUuid.get(p.getUuid()), ProjectDto::getKey, resolveCollisionByNaturalOrder)); + } + + private static BBCRepo toBBCRepo(Repository gsonBBCRepo, String workspace, Map sqProjectKeyByRepoSlug) { + BBCRepo.Builder builder = BBCRepo.newBuilder() .setSlug(gsonBBCRepo.getSlug()) .setUuid(gsonBBCRepo.getUuid()) .setName(gsonBBCRepo.getName()) .setWorkspace(workspace) - .setProjectKey(gsonBBCRepo.getProject().getKey()) - .build(); + .setProjectKey(gsonBBCRepo.getProject().getKey()); + + String sqProjectKey = sqProjectKeyByRepoSlug.get(gsonBBCRepo.getSlug()); + ofNullable(sqProjectKey).ifPresent(builder::setSqProjectKey); + + return builder.build(); } } diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/bitbucketcloud/SearchBitbucketCloudReposActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/bitbucketcloud/SearchBitbucketCloudReposActionTest.java index 4f740e6c43a..4d4ded4f9a1 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/bitbucketcloud/SearchBitbucketCloudReposActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/bitbucketcloud/SearchBitbucketCloudReposActionTest.java @@ -76,6 +76,8 @@ public class SearchBitbucketCloudReposActionTest { dto.setPersonalAccessToken("abc:xyz"); dto.setUserUuid(user.getUuid()); }); + ProjectDto projectDto = db.components().insertPrivateProjectDto(); + db.almSettings().insertBitbucketCloudProjectAlmSetting(almSetting, projectDto, s -> s.setAlmSlug("repo-slug-2")); SearchBitbucketcloudReposWsResponse response = ws.newRequest() .setParam("almSetting", almSetting.getKey()) @@ -87,9 +89,36 @@ public class SearchBitbucketCloudReposActionTest { assertThat(response.getPaging().getPageIndex()).isEqualTo(1); assertThat(response.getPaging().getPageSize()).isEqualTo(100); assertThat(response.getRepositoriesList()) - .extracting(BBCRepo::getUuid, BBCRepo::getName, BBCRepo::getSlug, BBCRepo::getProjectKey, BBCRepo::getWorkspace) + .extracting(BBCRepo::getUuid, BBCRepo::getName, BBCRepo::getSlug, BBCRepo::getProjectKey, BBCRepo::getSqProjectKey, BBCRepo::getWorkspace) .containsExactlyInAnyOrder( - tuple("REPO-UUID-ONE", "repoName1", "repo-slug-1", "projectKey1", almSetting.getAppId())); + tuple("REPO-UUID-ONE", "repoName1", "repo-slug-1", "projectKey1", "", almSetting.getAppId()), + tuple("REPO-UUID-TWO", "repoName2", "repo-slug-2", "projectKey2", projectDto.getKey(), almSetting.getAppId())); + } + + @Test + public void use_projectKey_to_disambiguate_when_multiple_projects_are_binded_on_one_bitbucket_repo() { + when(bitbucketCloudRestClient.searchRepos(any(), any(), any(), any(), any())).thenReturn(getRepositoryList()); + UserDto user = db.users().insertUser(); + userSession.logIn(user).addPermission(PROVISION_PROJECTS); + AlmSettingDto almSetting = db.almSettings().insertBitbucketCloudAlmSetting(); + db.almPats().insert(dto -> { + dto.setAlmSettingUuid(almSetting.getUuid()); + dto.setUserUuid(user.getUuid()); + }); + ProjectDto project1 = db.components().insertPrivateProjectDto(p -> p.setDbKey("B")); + ProjectDto project2 = db.components().insertPrivateProjectDto(p -> p.setDbKey("A")); + db.almSettings().insertBitbucketProjectAlmSetting(almSetting, project1, s -> s.setAlmSlug("repo-slug-2")); + db.almSettings().insertBitbucketProjectAlmSetting(almSetting, project2, s -> s.setAlmSlug("repo-slug-2")); + + SearchBitbucketcloudReposWsResponse response = ws.newRequest() + .setParam("almSetting", almSetting.getKey()) + .executeProtobuf(SearchBitbucketcloudReposWsResponse.class); + + assertThat(response.getRepositoriesList()) + .extracting(BBCRepo::getUuid, BBCRepo::getName, BBCRepo::getSlug, BBCRepo::getProjectKey, BBCRepo::getSqProjectKey) + .containsExactlyInAnyOrder( + tuple("REPO-UUID-ONE", "repoName1", "repo-slug-1", "projectKey1", ""), + tuple("REPO-UUID-TWO", "repoName2", "repo-slug-2", "projectKey2", "A")); } @Test @@ -168,7 +197,7 @@ public class SearchBitbucketCloudReposActionTest { private RepositoryList getRepositoryList() { return new RepositoryList( "http://next.url", - asList(getBBCRepo1()), + asList(getBBCRepo1(), getBBCRepo2()), 1, 100); } @@ -178,4 +207,10 @@ public class SearchBitbucketCloudReposActionTest { return new Repository("REPO-UUID-ONE", "repo-slug-1", "repoName1", project1, null); } + private Repository getBBCRepo2() { + Project project2 = new Project("PROJECT-UUID-TWO", "projectKey2", "projectName2"); + Repository repo2 = new Repository("REPO-UUID-TWO", "repo-slug-2", "repoName2", project2, null); + return repo2; + } + }