From 8ebda8b077a812835b4997d2dec5229870da0322 Mon Sep 17 00:00:00 2001 From: Nolwenn Cadic <98824442+Nolwenn-cadic-sonarsource@users.noreply.github.com> Date: Mon, 12 Jun 2023 13:45:13 +0200 Subject: [PATCH] SONAR-19455 Update the api/alm_integrations/import_github_project API (#8500) --- .../github/ImportGithubProjectActionIT.java | 156 +++++++++++++++++- .../ws/github/ImportGithubProjectAction.java | 54 +++++- 2 files changed, 200 insertions(+), 10 deletions(-) diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectActionIT.java index e1bb458e98e..52ac7f05a48 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectActionIT.java @@ -28,10 +28,13 @@ import org.sonar.alm.client.github.GithubApplicationClientImpl; import org.sonar.api.server.ws.WebService; import org.sonar.api.utils.System2; import org.sonar.core.i18n.I18n; +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.setting.AlmSettingDto; import org.sonar.db.component.BranchDto; +import org.sonar.db.newcodeperiod.NewCodePeriodDto; import org.sonar.db.permission.GlobalPermission; import org.sonar.db.project.ProjectDto; import org.sonar.db.user.UserDto; @@ -42,6 +45,7 @@ import org.sonar.server.es.TestProjectIndexers; import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.exceptions.UnauthorizedException; import org.sonar.server.favorite.FavoriteUpdater; +import org.sonar.server.newcodeperiod.NewCodeDefinitionResolver; import org.sonar.server.permission.PermissionTemplateService; import org.sonar.server.project.DefaultBranchNameResolver; import org.sonar.server.project.ProjectDefaultVisibility; @@ -58,10 +62,14 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; 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.server.almintegration.ws.ImportHelper.PARAM_ALM_SETTING; import static org.sonar.server.almintegration.ws.github.ImportGithubProjectAction.PARAM_ORGANIZATION; import static org.sonar.server.almintegration.ws.github.ImportGithubProjectAction.PARAM_REPOSITORY_KEY; import static org.sonar.server.tester.UserSessionRule.standalone; +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 ImportGithubProjectActionIT { @@ -85,8 +93,11 @@ public class ImportGithubProjectActionIT { private final ImportHelper importHelper = new ImportHelper(db.getDbClient(), userSession); private final ProjectKeyGenerator projectKeyGenerator = mock(ProjectKeyGenerator.class); private final ProjectDefaultVisibility projectDefaultVisibility = mock(ProjectDefaultVisibility.class); + private PlatformEditionProvider editionProvider = mock(PlatformEditionProvider.class); + private NewCodeDefinitionResolver newCodeDefinitionResolver = new NewCodeDefinitionResolver(db.getDbClient(), editionProvider); private final WsActionTester ws = new WsActionTester(new ImportGithubProjectAction(db.getDbClient(), userSession, - projectDefaultVisibility, appClient, componentUpdater, importHelper, projectKeyGenerator)); + projectDefaultVisibility, appClient, componentUpdater, importHelper, projectKeyGenerator, newCodeDefinitionResolver, + defaultBranchNameResolver)); @Before public void before() { @@ -99,7 +110,8 @@ public class ImportGithubProjectActionIT { AlmSettingDto githubAlmSetting = setupAlm(); db.almPats().insert(p -> p.setAlmSettingUuid(githubAlmSetting.getUuid()).setUserUuid(userSession.getUuid())); - GithubApplicationClient.Repository repository = new GithubApplicationClient.Repository(1L, PROJECT_KEY_NAME, false, "octocat/" + PROJECT_KEY_NAME, + GithubApplicationClient.Repository repository = new GithubApplicationClient.Repository(1L, PROJECT_KEY_NAME, false, + "octocat/" + PROJECT_KEY_NAME, "https://github.sonarsource.com/api/v3/repos/octocat/" + PROJECT_KEY_NAME, "default-branch"); when(appClient.getRepository(any(), any(), any(), any())).thenReturn(Optional.of(repository)); when(projectKeyGenerator.generateUniqueProjectKey(repository.getFullName())).thenReturn(PROJECT_KEY_NAME); @@ -117,9 +129,143 @@ public class ImportGithubProjectActionIT { Optional projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey()); assertThat(projectDto).isPresent(); assertThat(db.getDbClient().projectAlmSettingDao().selectByProject(db.getSession(), projectDto.get())).isPresent(); - Optional mainBranch = db.getDbClient().branchDao().selectByProject(db.getSession(), projectDto.get()).stream().filter(BranchDto::isMain).findAny(); + Optional mainBranch = + db.getDbClient().branchDao().selectByProject(db.getSession(), projectDto.get()).stream().filter(BranchDto::isMain).findAny(); assertThat(mainBranch).isPresent(); assertThat(mainBranch.get().getKey()).isEqualTo("default-branch"); + + } + + @Test + public void importProject_withNCD_developer_edition() { + when(editionProvider.get()).thenReturn(Optional.of(EditionProvider.Edition.DEVELOPER)); + + AlmSettingDto githubAlmSetting = setupAlm(); + db.almPats().insert(p -> p.setAlmSettingUuid(githubAlmSetting.getUuid()).setUserUuid(userSession.getUuid())); + + GithubApplicationClient.Repository repository = new GithubApplicationClient.Repository(1L, PROJECT_KEY_NAME, false, + "octocat/" + PROJECT_KEY_NAME, + "https://github.sonarsource.com/api/v3/repos/octocat/" + PROJECT_KEY_NAME, "default-branch"); + when(appClient.getRepository(any(), any(), any(), any())).thenReturn(Optional.of(repository)); + when(projectKeyGenerator.generateUniqueProjectKey(repository.getFullName())).thenReturn(PROJECT_KEY_NAME); + + Projects.CreateWsResponse response = ws.newRequest() + .setParam(PARAM_ALM_SETTING, githubAlmSetting.getKey()) + .setParam(PARAM_ORGANIZATION, "octocat") + .setParam(PARAM_REPOSITORY_KEY, "octocat/" + PROJECT_KEY_NAME) + .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(); + + 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 importProject_withNCD_community_edition() { + when(editionProvider.get()).thenReturn(Optional.of(EditionProvider.Edition.COMMUNITY)); + + AlmSettingDto githubAlmSetting = setupAlm(); + db.almPats().insert(p -> p.setAlmSettingUuid(githubAlmSetting.getUuid()).setUserUuid(userSession.getUuid())); + + GithubApplicationClient.Repository repository = new GithubApplicationClient.Repository(1L, PROJECT_KEY_NAME, false, + "octocat/" + PROJECT_KEY_NAME, + "https://github.sonarsource.com/api/v3/repos/octocat/" + PROJECT_KEY_NAME, "default-branch"); + when(appClient.getRepository(any(), any(), any(), any())).thenReturn(Optional.of(repository)); + when(projectKeyGenerator.generateUniqueProjectKey(repository.getFullName())).thenReturn(PROJECT_KEY_NAME); + + Projects.CreateWsResponse response = ws.newRequest() + .setParam(PARAM_ALM_SETTING, githubAlmSetting.getKey()) + .setParam(PARAM_ORGANIZATION, "octocat") + .setParam(PARAM_REPOSITORY_KEY, "octocat/" + PROJECT_KEY_NAME) + .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 importProject_reference_branch_ncd_no_default_branch() { + when(editionProvider.get()).thenReturn(Optional.of(EditionProvider.Edition.DEVELOPER)); + when(defaultBranchNameResolver.getEffectiveMainBranchName()).thenReturn("default-branch"); + + AlmSettingDto githubAlmSetting = setupAlm(); + db.almPats().insert(p -> p.setAlmSettingUuid(githubAlmSetting.getUuid()).setUserUuid(userSession.getUuid())); + + GithubApplicationClient.Repository repository = new GithubApplicationClient.Repository(1L, PROJECT_KEY_NAME, false, + "octocat/" + PROJECT_KEY_NAME, + "https://github.sonarsource.com/api/v3/repos/octocat/" + PROJECT_KEY_NAME, null); + when(appClient.getRepository(any(), any(), any(), any())).thenReturn(Optional.of(repository)); + when(projectKeyGenerator.generateUniqueProjectKey(repository.getFullName())).thenReturn(PROJECT_KEY_NAME); + + Projects.CreateWsResponse response = ws.newRequest() + .setParam(PARAM_ALM_SETTING, githubAlmSetting.getKey()) + .setParam(PARAM_ORGANIZATION, "octocat") + .setParam(PARAM_REPOSITORY_KEY, "octocat/" + PROJECT_KEY_NAME) + .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(); + + assertThat(db.getDbClient().newCodePeriodDao().selectByProject(db.getSession(), projectDto.get().getUuid())) + .isPresent() + .get() + .extracting(NewCodePeriodDto::getType, NewCodePeriodDto::getValue) + .containsExactly(REFERENCE_BRANCH, "default-branch"); + } + + @Test + public void importProject_reference_branch_ncd() { + when(editionProvider.get()).thenReturn(Optional.of(EditionProvider.Edition.DEVELOPER)); + + AlmSettingDto githubAlmSetting = setupAlm(); + db.almPats().insert(p -> p.setAlmSettingUuid(githubAlmSetting.getUuid()).setUserUuid(userSession.getUuid())); + + GithubApplicationClient.Repository repository = new GithubApplicationClient.Repository(1L, PROJECT_KEY_NAME, false, + "octocat/" + PROJECT_KEY_NAME, + "https://github.sonarsource.com/api/v3/repos/octocat/" + PROJECT_KEY_NAME, "mainBranch"); + when(appClient.getRepository(any(), any(), any(), any())).thenReturn(Optional.of(repository)); + when(projectKeyGenerator.generateUniqueProjectKey(repository.getFullName())).thenReturn(PROJECT_KEY_NAME); + + Projects.CreateWsResponse response = ws.newRequest() + .setParam(PARAM_ALM_SETTING, githubAlmSetting.getKey()) + .setParam(PARAM_ORGANIZATION, "octocat") + .setParam(PARAM_REPOSITORY_KEY, "octocat/" + PROJECT_KEY_NAME) + .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(); + + assertThat(db.getDbClient().newCodePeriodDao().selectByProject(db.getSession(), projectDto.get().getUuid())) + .isPresent() + .get() + .extracting(NewCodePeriodDto::getType, NewCodePeriodDto::getValue) + .containsExactly(REFERENCE_BRANCH, "mainBranch"); } @Test @@ -199,7 +345,9 @@ public class ImportGithubProjectActionIT { .containsExactlyInAnyOrder( tuple(PARAM_ALM_SETTING, 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_VALUE, false)); } private AlmSettingDto setupAlm() { diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectAction.java index 3214b185cc5..56fbda88008 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectAction.java @@ -20,6 +20,7 @@ package org.sonar.server.almintegration.ws.github; import java.util.Optional; +import javax.inject.Inject; import org.sonar.alm.client.github.GithubApplicationClient; import org.sonar.alm.client.github.GithubApplicationClient.Repository; import org.sonar.alm.client.github.GithubApplicationClientImpl; @@ -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.exceptions.NotFoundException; +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 ImportGithubProjectAction implements AlmIntegrationsWsAction { @@ -64,8 +72,15 @@ public class ImportGithubProjectAction implements AlmIntegrationsWsAction { private final ImportHelper importHelper; private final ProjectKeyGenerator projectKeyGenerator; + private final NewCodeDefinitionResolver newCodeDefinitionResolver; + + private final DefaultBranchNameResolver defaultBranchNameResolver; + + @Inject public ImportGithubProjectAction(DbClient dbClient, UserSession userSession, ProjectDefaultVisibility projectDefaultVisibility, - GithubApplicationClientImpl githubApplicationClient, ComponentUpdater componentUpdater, ImportHelper importHelper, ProjectKeyGenerator projectKeyGenerator) { + GithubApplicationClientImpl githubApplicationClient, ComponentUpdater componentUpdater, ImportHelper importHelper, + ProjectKeyGenerator projectKeyGenerator, NewCodeDefinitionResolver newCodeDefinitionResolver, + DefaultBranchNameResolver defaultBranchNameResolver) { this.dbClient = dbClient; this.userSession = userSession; this.projectDefaultVisibility = projectDefaultVisibility; @@ -73,6 +88,8 @@ public class ImportGithubProjectAction implements AlmIntegrationsWsAction { this.componentUpdater = componentUpdater; this.importHelper = importHelper; this.projectKeyGenerator = projectKeyGenerator; + this.newCodeDefinitionResolver = newCodeDefinitionResolver; + this.defaultBranchNameResolver = defaultBranchNameResolver; } @Override @@ -100,6 +117,14 @@ public class ImportGithubProjectAction implements AlmIntegrationsWsAction { .setRequired(true) .setMaximumLength(256) .setDescription("GitHub repository key"); + + 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 @@ -111,13 +136,13 @@ public class ImportGithubProjectAction implements AlmIntegrationsWsAction { 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)) { - AccessToken accessToken = dbClient.almPatDao().selectByUserAndAlmSetting(dbSession, userUuid, almSettingDto) - .map(AlmPatDto::getPersonalAccessToken) - .map(UserAccessToken::new) - .orElseThrow(() -> new IllegalArgumentException("No personal access token found")); + AccessToken accessToken = getAccessToken(dbSession, almSettingDto); String githubOrganization = request.mandatoryParam(PARAM_ORGANIZATION); String repositoryKey = request.mandatoryParam(PARAM_REPOSITORY_KEY); @@ -130,12 +155,29 @@ public class ImportGithubProjectAction implements AlmIntegrationsWsAction { ProjectDto projectDto = Optional.ofNullable(componentCreationData.projectDto()).orElseThrow(); populatePRSetting(dbSession, repository, projectDto, almSettingDto); + + checkNewCodeDefinitionParam(newCodeDefinitionType, newCodeDefinitionValue); + + if (newCodeDefinitionType != null) { + newCodeDefinitionResolver.createNewCodeDefinition(dbSession, projectDto.getUuid(), + Optional.ofNullable(repository.getDefaultBranch()).orElse(defaultBranchNameResolver.getEffectiveMainBranchName()), + newCodeDefinitionType, newCodeDefinitionValue); + } + componentUpdater.commitAndIndex(dbSession, componentCreationData.mainBranchComponent()); return toCreateResponse(projectDto); } } + private AccessToken getAccessToken(DbSession dbSession, AlmSettingDto almSettingDto) { + String userUuid = importHelper.getUserUuid(); + return dbClient.almPatDao().selectByUserAndAlmSetting(dbSession, userUuid, almSettingDto) + .map(AlmPatDto::getPersonalAccessToken) + .map(UserAccessToken::new) + .orElseThrow(() -> new IllegalArgumentException("No personal access token found")); + } + private ComponentCreationData createProject(DbSession dbSession, Repository repo, String mainBranchName) { boolean visibility = projectDefaultVisibility.get(dbSession).isPrivate(); String uniqueProjectKey = projectKeyGenerator.generateUniqueProjectKey(repo.getFullName()); -- 2.39.5