From ef4e8f0650d828b862810e4365c70f3fd2201ecd Mon Sep 17 00:00:00 2001 From: Mathieu Suen <59278745+mathieu-suen-sonarsource@users.noreply.github.com> Date: Mon, 26 Apr 2021 09:44:58 +0200 Subject: [PATCH] SONAR-13645 Make github onboarding resiliant to project name/key change Co-authored-by: Pierre --- .../github/ListGithubRepositoriesAction.java | 61 +++++++++++++++---- .../ListGithubRepositoriesActionTest.java | 9 ++- 2 files changed, 56 insertions(+), 14 deletions(-) diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/github/ListGithubRepositoriesAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/github/ListGithubRepositoriesAction.java index a0872a6a4cb..1451788e347 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/github/ListGithubRepositoriesAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/github/ListGithubRepositoriesAction.java @@ -19,8 +19,14 @@ */ package org.sonar.server.almintegration.ws.github; +import java.util.Comparator; import java.util.List; +import java.util.Map; import java.util.Optional; +import java.util.Set; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.stream.Collectors; import org.sonar.alm.client.github.GithubApplicationClient; import org.sonar.alm.client.github.GithubApplicationClient.Repository; import org.sonar.alm.client.github.GithubApplicationClientImpl; @@ -33,6 +39,8 @@ 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.ProjectAlmSettingDao; +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; @@ -45,7 +53,6 @@ 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.api.server.ws.WebService.Param.TEXT_QUERY; import static org.sonar.db.permission.GlobalPermission.PROVISION_PROJECTS; -import static org.sonar.server.almintegration.ws.github.ImportGithubProjectAction.getProjectKeyFromRepository; import static org.sonar.server.ws.WsUtils.writeProtobuf; public class ListGithubRepositoriesAction implements AlmIntegrationsWsAction { @@ -56,11 +63,13 @@ public class ListGithubRepositoriesAction implements AlmIntegrationsWsAction { private final DbClient dbClient; private final UserSession userSession; private final GithubApplicationClient githubApplicationClient; + private final ProjectAlmSettingDao projectAlmSettingDao; - public ListGithubRepositoriesAction(DbClient dbClient, UserSession userSession, GithubApplicationClientImpl githubApplicationClient) { + public ListGithubRepositoriesAction(DbClient dbClient, UserSession userSession, GithubApplicationClientImpl githubApplicationClient, ProjectAlmSettingDao projectAlmSettingDao) { this.dbClient = dbClient; this.userSession = userSession; this.githubApplicationClient = githubApplicationClient; + this.projectAlmSettingDao = projectAlmSettingDao; } @Override @@ -131,20 +140,46 @@ public class ListGithubRepositoriesAction implements AlmIntegrationsWsAction { List repositoryList = repositories.getRepositories(); if (repositoryList != null) { - repositoryList.forEach(repository -> { - Optional sonarQubeKey = dbClient.projectDao().selectProjectByKey(dbSession, getProjectKeyFromRepository(repository)).map(ProjectDto::getKey); - response.addRepositories(AlmIntegrations.GithubRepository.newBuilder() - .setId(repository.getId()) - .setKey(repository.getFullName()) - .setName(repository.getName()) - .setUrl(repository.getUrl()) - .setSqProjectKey(sonarQubeKey.orElse("")) - .build()); - } - ); + + Set repo = repositoryList.stream().map(Repository::getFullName).collect(Collectors.toSet()); + List projectAlmSettingDtos = projectAlmSettingDao.selectByAlmSettingAndRepos(dbSession, almSettingDto, repo); + + Map projectsDtoByAlmRepo = getProjectDtoByAlmRepo(dbSession, projectAlmSettingDtos); + + for (Repository repository : repositoryList) { + AlmIntegrations.GithubRepository.Builder builder = AlmIntegrations.GithubRepository.newBuilder() + .setId(repository.getId()) + .setKey(repository.getFullName()) + .setName(repository.getName()) + .setUrl(repository.getUrl()); + + if (projectsDtoByAlmRepo.containsKey(repository.getFullName())) { + Optional.ofNullable(projectsDtoByAlmRepo.get(repository.getFullName())) + .ifPresent(p -> builder.setSqProjectKey(p.getKey())); + } + + response.addRepositories(builder.build()); + } } return response.build(); } } + + private Map getProjectDtoByAlmRepo(DbSession dbSession, List projectAlmSettingDtos) { + Map projectAlmSettingDtoByProjectUuid = projectAlmSettingDtos.stream() + .collect(Collectors.toMap(ProjectAlmSettingDto::getProjectUuid, Function.identity())); + + Set projectUuids = projectAlmSettingDtos.stream().map(ProjectAlmSettingDto::getProjectUuid).collect(Collectors.toSet()); + + return dbClient.projectDao().selectByUuids(dbSession, projectUuids) + .stream() + .collect(Collectors.toMap(projectDto -> projectAlmSettingDtoByProjectUuid.get(projectDto.getUuid()).getAlmRepo(), + Function.identity(), resolveNameCollisionOperatorByNaturalOrder())); + } + + private static BinaryOperator resolveNameCollisionOperatorByNaturalOrder() { + Comparator comparator = Comparator.comparing(ProjectDto::getKey); + return (a, b) -> comparator.compare(a, b) > 0 ? b : a; + } } diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/github/ListGithubRepositoriesActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/github/ListGithubRepositoriesActionTest.java index 66fd47a2ad2..9e73e35f682 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/github/ListGithubRepositoriesActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/github/ListGithubRepositoriesActionTest.java @@ -29,6 +29,7 @@ import org.sonar.api.utils.System2; 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.ProjectAlmSettingDao; import org.sonar.db.permission.GlobalPermission; import org.sonar.db.project.ProjectDto; import org.sonar.db.user.UserDto; @@ -63,7 +64,9 @@ public class ListGithubRepositoriesActionTest { @Rule public DbTester db = DbTester.create(system2); - private final WsActionTester ws = new WsActionTester(new ListGithubRepositoriesAction(db.getDbClient(), userSession, appClient)); + private final ProjectAlmSettingDao projectAlmSettingDao = db.getDbClient().projectAlmSettingDao(); + + private final WsActionTester ws = new WsActionTester(new ListGithubRepositoriesAction(db.getDbClient(), userSession, appClient, projectAlmSettingDao)); @Test public void fail_when_missing_create_project_permission() { @@ -112,6 +115,10 @@ public class ListGithubRepositoriesActionTest { .collect(Collectors.toList()))); ProjectDto project = db.components().insertPrivateProjectDto(componentDto -> componentDto.setDbKey("github_HelloWorld")); + db.almSettings().insertGitHubProjectAlmSetting(githubAlmSettings, project, projectAlmSettingDto -> projectAlmSettingDto.setAlmRepo("github/HelloWorld")); + + ProjectDto project2 = db.components().insertPrivateProjectDto(componentDto -> componentDto.setDbKey("github_HelloWorld2")); + db.almSettings().insertGitHubProjectAlmSetting(githubAlmSettings, project2, projectAlmSettingDto -> projectAlmSettingDto.setAlmRepo("github/HelloWorld")); ListGithubRepositoriesWsResponse response = ws.newRequest() .setParam(ListGithubRepositoriesAction.PARAM_ALM_SETTING, githubAlmSettings.getKey()) -- 2.39.5