*/
Optional<Repository> getRepository(String appUrl, AccessToken accessToken, String repositoryKey);
+ Set<GsonRepositoryTeam> getRepositoryTeams(String appUrl, AccessToken accessToken, String orgName, String repoName);
-
- Set<GsonRepositoryTeam> getRepositoryTeams(String appUrl, AppInstallationToken accessToken, String orgName, String repoName);
-
- Set<GsonRepositoryCollaborator> getRepositoryCollaborators(String appUrl, AppInstallationToken accessToken, String orgName, String repoName);
+ Set<GsonRepositoryCollaborator> getRepositoryCollaborators(String appUrl, AccessToken accessToken, String orgName, String repoName);
class Repositories {
private int total;
}
@Override
- public Set<GsonRepositoryTeam> getRepositoryTeams(String appUrl, AppInstallationToken accessToken, String orgName, String repoName) {
+ public Set<GsonRepositoryTeam> getRepositoryTeams(String appUrl, AccessToken accessToken, String orgName, String repoName) {
return Set
.copyOf(executePaginatedQuery(appUrl, accessToken, format("/repos/%s/%s/teams", orgName, repoName), resp -> GSON.fromJson(resp, REPOSITORY_TEAM_LIST_TYPE)));
}
@Override
- public Set<GsonRepositoryCollaborator> getRepositoryCollaborators(String appUrl, AppInstallationToken accessToken, String orgName, String repoName) {
+ public Set<GsonRepositoryCollaborator> getRepositoryCollaborators(String appUrl, AccessToken accessToken, String orgName, String repoName) {
return Set
.copyOf(
executePaginatedQuery(
import org.sonar.db.user.UserDto;
import org.sonar.server.almintegration.ws.ImportHelper;
import org.sonar.server.almintegration.ws.ProjectKeyGenerator;
-import org.sonar.server.almsettings.ws.GitHubDevOpsPlatformService;
+import org.sonar.server.almsettings.ws.GithubProjectCreatorFactory;
import org.sonar.server.component.ComponentUpdater;
import org.sonar.server.es.EsTester;
import org.sonar.server.es.IndexersImpl;
private final ManagedProjectService managedProjectService = mock(ManagedProjectService.class);
private final GithubPermissionConverter githubPermissionConverter = new GithubPermissionConverter();
- private final GitHubDevOpsPlatformService gitHubDevOpsPlatformService = new GitHubDevOpsPlatformService(db.getDbClient(),
+ private final GithubProjectCreatorFactory gitHubProjectCreatorFactory = new GithubProjectCreatorFactory(db.getDbClient(),
null, appClient, projectDefaultVisibility, projectKeyGenerator, userSession, componentUpdater, gitHubSettings, githubPermissionConverter);
private final WsActionTester ws = new WsActionTester(new ImportGithubProjectAction(db.getDbClient(), managedProjectService, userSession,
- componentUpdater, importHelper, newCodeDefinitionResolver, defaultBranchNameResolver, gitHubDevOpsPlatformService));
+ componentUpdater, importHelper, newCodeDefinitionResolver, defaultBranchNameResolver, gitHubProjectCreatorFactory));
@Before
public void before() {
import org.sonar.db.project.CreationMethod;
import org.sonar.db.project.ProjectDto;
import org.sonar.db.user.UserDto;
-import org.sonar.server.almsettings.ws.DevOpsPlatformService;
-import org.sonar.server.almsettings.ws.GitHubDevOpsPlatformService;
+import org.sonar.server.almsettings.ws.DevOpsProjectCreatorFactory;
+import org.sonar.server.almsettings.ws.GithubProjectCreatorFactory;
import org.sonar.server.component.ComponentCreationData;
import org.sonar.server.component.ComponentCreationParameters;
import org.sonar.server.component.ComponentUpdater;
private final BranchSupportDelegate branchSupportDelegate = mock(BranchSupportDelegate.class);
private final BranchSupport branchSupport = spy(new BranchSupport(branchSupportDelegate));
- private final DevOpsPlatformService devOpsPlatformService = new GitHubDevOpsPlatformService(db.getDbClient(), null,
+ private final DevOpsProjectCreatorFactory devOpsProjectCreatorFactory = new GithubProjectCreatorFactory(db.getDbClient(), null,
null, projectDefaultVisibility, null, userSession, componentUpdater, null, null);
private final ManagedInstanceService managedInstanceService = mock();
private final ReportSubmitter underTest = new ReportSubmitter(queue, userSession, componentUpdater, permissionTemplateService, db.getDbClient(), branchSupport,
- projectDefaultVisibility, devOpsPlatformService, managedInstanceService);
+ projectDefaultVisibility, devOpsProjectCreatorFactory, managedInstanceService);
@Before
public void before() {
package org.sonar.server.ce.queue;
import java.io.InputStream;
-import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
-import org.sonar.alm.client.github.AppInstallationToken;
import org.sonar.alm.client.github.GithubApplicationClient;
import org.sonar.alm.client.github.GithubGlobalSettingsValidator;
-import org.sonar.alm.client.github.config.GithubAppConfiguration;
-import org.sonar.alm.client.github.config.GithubAppInstallation;
import org.sonar.api.utils.System2;
import org.sonar.auth.github.GitHubSettings;
import org.sonar.ce.queue.CeQueue;
import org.sonar.db.project.ProjectDto;
import org.sonar.db.user.UserDto;
import org.sonar.server.almintegration.ws.ProjectKeyGenerator;
-import org.sonar.server.almsettings.ws.DelegatingDevOpsPlatformService;
-import org.sonar.server.almsettings.ws.DevOpsPlatformService;
+import org.sonar.server.almsettings.ws.DelegatingDevOpsProjectCreatorFactory;
+import org.sonar.server.almsettings.ws.DevOpsProjectCreator;
+import org.sonar.server.almsettings.ws.DevOpsProjectCreatorFactory;
import org.sonar.server.almsettings.ws.DevOpsProjectDescriptor;
-import org.sonar.server.almsettings.ws.GitHubDevOpsPlatformService;
+import org.sonar.server.almsettings.ws.GithubProjectCreator;
+import org.sonar.server.almsettings.ws.GithubProjectCreationParameters;
+import org.sonar.server.almsettings.ws.GithubProjectCreatorFactory;
import org.sonar.server.component.ComponentUpdater;
import org.sonar.server.es.TestIndexers;
import org.sonar.server.exceptions.BadRequestException;
import static java.util.Collections.emptyMap;
import static java.util.stream.IntStream.rangeClosed;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
private static final String PROJECT_UUID = "P1";
private static final String PROJECT_NAME = "My Project";
private static final String TASK_UUID = "TASK_1";
+ private static final Map<String, String> CHARACTERISTICS = Map.of("random", "data");
@Rule
public final UserSessionRule userSession = UserSessionRule.standalone();
private final GitHubSettings gitHubSettings = mock();
private final ProjectKeyGenerator projectKeyGenerator = mock();
- private final DevOpsPlatformService devOpsPlatformService = new DelegatingDevOpsPlatformService(
- Set.of(new GitHubDevOpsPlatformService(db.getDbClient(), githubGlobalSettingsValidator,
- githubApplicationClient, projectDefaultVisibility, projectKeyGenerator, userSession, componentUpdater, gitHubSettings, null)));
+ private final GithubProjectCreatorFactory githubProjectCreatorFactory = new GithubProjectCreatorFactory(db.getDbClient(), githubGlobalSettingsValidator,
+ githubApplicationClient, projectDefaultVisibility, projectKeyGenerator, userSession, componentUpdater, gitHubSettings, null);
+ private final DevOpsProjectCreatorFactory devOpsProjectCreatorFactory = new DelegatingDevOpsProjectCreatorFactory(Set.of(githubProjectCreatorFactory));
- private final DevOpsPlatformService devOpsPlatformServiceSpy = spy(devOpsPlatformService);
+ private final DevOpsProjectCreatorFactory devOpsProjectCreatorFactorySpy = spy(devOpsProjectCreatorFactory);
private final ManagedInstanceService managedInstanceService = mock();
private final ReportSubmitter underTest = new ReportSubmitter(queue, userSession, componentUpdater, permissionTemplateService, db.getDbClient(), ossEditionBranchSupport,
- projectDefaultVisibility, devOpsPlatformServiceSpy, managedInstanceService);
+ projectDefaultVisibility, devOpsProjectCreatorFactorySpy, managedInstanceService);
@Before
public void before() {
assertLocalProjectWasCreated();
}
- @Test
- public void submit_whenReportIsForANewGithubProjectWithoutValidAlmSettings_throws() {
- userSession.addPermission(GlobalPermission.SCAN).addPermission(PROVISION_PROJECTS);
- when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), any(), eq(PROJECT_KEY))).thenReturn(true);
- mockSuccessfulPrepareSubmitCall();
-
- Map<String, String> characteristics = Map.of("random", "data");
- DevOpsProjectDescriptor projectDescriptor = new DevOpsProjectDescriptor(ALM.GITHUB, "apiUrl", "orga/repo");
- when(devOpsPlatformServiceSpy.getDevOpsProjectDescriptor(characteristics)).thenReturn(Optional.of(projectDescriptor));
-
- assertThatIllegalArgumentException().isThrownBy(() -> underTest.submit(PROJECT_KEY, PROJECT_NAME, characteristics, IOUtils.toInputStream("{binary}", UTF_8)))
- .withMessage("The project orga/repo could not be created. It was auto-detected as a GITHUB project and no valid DevOps platform configuration were found to access apiUrl");
-
- assertNoProjectWasCreated();
- }
-
- private void assertNoProjectWasCreated() {
- assertThat(db.getDbClient().projectDao().selectAll(db.getSession())).isEmpty();
- }
@Test
public void submit_whenReportIsForANewProjectWithValidAlmSettingsAutoProvisioningOnAndPermOnGh_createsProjectWithBinding() {
when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), any(), eq(PROJECT_KEY))).thenReturn(true);
mockSuccessfulPrepareSubmitCall();
- Map<String, String> characteristics = Map.of("random", "data");
- DevOpsProjectDescriptor projectDescriptor = new DevOpsProjectDescriptor(ALM.GITHUB, "apiUrl", "orga/repo");
-
- AlmSettingDto almSettingDto = mockInteractionsWithDevOpsPlatformServiceSpyBeforeProjectCreation(characteristics, projectDescriptor);
- when(devOpsPlatformServiceSpy.isScanAllowedUsingPermissionsFromDevopsPlatform(almSettingDto, projectDescriptor)).thenReturn(true);
+ DevOpsProjectCreator devOpsProjectCreator = mockAlmSettingDtoAndDevOpsProjectCreator(CHARACTERISTICS);
+ doReturn(true).when(devOpsProjectCreator).isScanAllowedUsingPermissionsFromDevopsPlatform();
- underTest.submit(PROJECT_KEY, PROJECT_NAME, characteristics, IOUtils.toInputStream("{binary}", UTF_8));
+ underTest.submit(PROJECT_KEY, PROJECT_NAME, CHARACTERISTICS, IOUtils.toInputStream("{binary}", UTF_8));
assertProjectWasCreatedWithBinding();
}
- @Test
- public void submit_whenReportIsForANewProjectWithProjectDescriptorAndNoValidAlmSettingsAndAutoProvisioningOn_throws() {
- userSession.addPermission(GlobalPermission.SCAN).addPermission(PROVISION_PROJECTS);
- when(managedInstanceService.isInstanceExternallyManaged()).thenReturn(true);
- when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), any(), eq(PROJECT_KEY))).thenReturn(true);
- mockSuccessfulPrepareSubmitCall();
-
- Map<String, String> characteristics = Map.of("random", "data");
- DevOpsProjectDescriptor projectDescriptor = new DevOpsProjectDescriptor(ALM.GITHUB, "apiUrl", "orga/repo");
- doReturn(Optional.of(projectDescriptor)).when(devOpsPlatformServiceSpy).getDevOpsProjectDescriptor(characteristics);
-
- assertThatIllegalArgumentException()
- .isThrownBy(() -> underTest.submit(PROJECT_KEY, PROJECT_NAME, characteristics, IOUtils.toInputStream("{binary}", UTF_8)))
- .withMessage("The project orga/repo could not be created. It was auto-detected as a GITHUB project and no valid DevOps platform configuration were found to access apiUrl");
-
- assertNoProjectWasCreated();
- }
-
@Test
public void submit_whenReportIsForANewProjectWithoutDevOpsMetadataAndAutoProvisioningOn_shouldCreateLocalProject() {
userSession.addPermission(GlobalPermission.SCAN).addPermission(PROVISION_PROJECTS);
when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), any(), eq(PROJECT_KEY))).thenReturn(true);
mockSuccessfulPrepareSubmitCall();
- Map<String, String> characteristics = Map.of("random", "data");
-
- underTest.submit(PROJECT_KEY, PROJECT_NAME, characteristics, IOUtils.toInputStream("{binary}", UTF_8));
+ underTest.submit(PROJECT_KEY, PROJECT_NAME, CHARACTERISTICS, IOUtils.toInputStream("{binary}", UTF_8));
assertLocalProjectWasCreated();
}
@Test
public void submit_whenReportIsForANewProjectWithValidAlmSettings_createsProjectWithDevOpsBinding() {
userSession.addPermission(GlobalPermission.SCAN).addPermission(PROVISION_PROJECTS);
- when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), any(), eq(PROJECT_KEY))).thenReturn(true);
mockSuccessfulPrepareSubmitCall();
- Map<String, String> characteristics = Map.of("random", "data");
- DevOpsProjectDescriptor projectDescriptor = new DevOpsProjectDescriptor(ALM.GITHUB, "apiUrl", "orga/repo");
+ mockAlmSettingDtoAndDevOpsProjectCreator(CHARACTERISTICS);
- mockInteractionsWithDevOpsPlatformServiceSpyBeforeProjectCreation(characteristics, projectDescriptor);
+ when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), any(), eq(PROJECT_KEY))).thenReturn(true);
- underTest.submit(PROJECT_KEY, PROJECT_NAME, characteristics, IOUtils.toInputStream("{binary}", UTF_8));
+ underTest.submit(PROJECT_KEY, PROJECT_NAME, CHARACTERISTICS, IOUtils.toInputStream("{binary}", UTF_8));
assertProjectWasCreatedWithBinding();
}
assertThat(db.getDbClient().projectAlmSettingDao().selectByProject(db.getSession(), projectDto.getUuid())).isPresent();
}
- private AlmSettingDto mockInteractionsWithDevOpsPlatformServiceSpyBeforeProjectCreation(Map<String, String> characteristics, DevOpsProjectDescriptor projectDescriptor) {
- doReturn(Optional.of(projectDescriptor)).when(devOpsPlatformServiceSpy).getDevOpsProjectDescriptor(characteristics);
+ private DevOpsProjectCreator mockAlmSettingDtoAndDevOpsProjectCreator(Map<String, String> characteristics) {
AlmSettingDto almSettingDto = mock(AlmSettingDto.class);
when(almSettingDto.getAlm()).thenReturn(ALM.GITHUB);
when(almSettingDto.getUrl()).thenReturn("https://www.toto.com");
- when(almSettingDto.getUuid()).thenReturn("TEST_GH");
- doReturn(Optional.of(almSettingDto)).when(devOpsPlatformServiceSpy).getValidAlmSettingDto(any(), eq(projectDescriptor));
- mockGithubInteractions(almSettingDto);
- return almSettingDto;
+ when(almSettingDto.getUuid()).thenReturn("uuid_gh_1");
+
+ mockGithubRepository();
+
+ DevOpsProjectDescriptor projectDescriptor = new DevOpsProjectDescriptor(ALM.GITHUB, "apiUrl", "orga/repo");
+ GithubProjectCreationParameters githubProjectCreationParameters = new GithubProjectCreationParameters(projectDescriptor, almSettingDto, mock(), true, managedInstanceService.isInstanceExternallyManaged(), userSession);
+ DevOpsProjectCreator devOpsProjectCreator = spy(new GithubProjectCreator(db.getDbClient(), githubApplicationClient, null, projectKeyGenerator, componentUpdater, githubProjectCreationParameters));
+ doReturn(Optional.of(devOpsProjectCreator)).when(devOpsProjectCreatorFactorySpy).getDevOpsProjectCreator(any(), eq(characteristics));
+ return devOpsProjectCreator;
}
- private void mockGithubInteractions(AlmSettingDto almSettingDto) {
- GithubAppConfiguration githubAppConfiguration = mock(GithubAppConfiguration.class);
- when(githubGlobalSettingsValidator.validate(almSettingDto)).thenReturn(githubAppConfiguration);
- GithubAppInstallation githubAppInstallation = mock(GithubAppInstallation.class);
- when(githubAppInstallation.installationId()).thenReturn("5435345");
- when(githubApplicationClient.getWhitelistedGithubAppInstallations(any())).thenReturn(List.of(githubAppInstallation));
- when(githubApplicationClient.createAppInstallationToken(any(), anyLong())).thenReturn(Optional.of(mock(AppInstallationToken.class)));
- when(githubApplicationClient.createAppInstallationToken(any(), anyLong())).thenReturn(Optional.of(mock(AppInstallationToken.class)));
- when(githubApplicationClient.getInstallationId(eq(githubAppConfiguration), any())).thenReturn(Optional.of(5435345L));
+ private void mockGithubRepository() {
GithubApplicationClient.Repository repository = mock(GithubApplicationClient.Repository.class);
when(repository.getDefaultBranch()).thenReturn("defaultBranch");
when(repository.getFullName()).thenReturn("orga/repoName");
when(repository.getName()).thenReturn("repoName");
when(githubApplicationClient.getRepository(any(), any(), any())).thenReturn(Optional.of(repository));
- when(projectKeyGenerator.generateUniqueProjectKey(repository.getFullName())).thenReturn("projectKey");
}
@Test
import org.sonar.db.alm.setting.ALM;
import org.sonar.db.alm.setting.AlmSettingDto;
import org.sonar.db.component.BranchDto;
+import org.sonar.db.project.CreationMethod;
import org.sonar.db.project.ProjectDto;
import org.sonar.server.almintegration.ws.AlmIntegrationsWsAction;
import org.sonar.server.almintegration.ws.ImportHelper;
+import org.sonar.server.almsettings.ws.DevOpsProjectCreator;
import org.sonar.server.almsettings.ws.DevOpsProjectDescriptor;
-import org.sonar.server.almsettings.ws.GitHubDevOpsPlatformService;
+import org.sonar.server.almsettings.ws.GithubProjectCreatorFactory;
import org.sonar.server.component.ComponentCreationData;
import org.sonar.server.component.ComponentUpdater;
import org.sonar.server.management.ManagedProjectService;
import org.sonarqube.ws.Projects;
import static java.util.Objects.requireNonNull;
+import static org.sonar.db.project.CreationMethod.Category.ALM_IMPORT;
+import static org.sonar.db.project.CreationMethod.getCreationMethod;
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.newcodeperiod.NewCodeDefinitionResolver.NEW_CODE_PERIOD_TYPE_DESCRIPTION_PROJECT_CREATION;
private final DefaultBranchNameResolver defaultBranchNameResolver;
- private final GitHubDevOpsPlatformService gitHubDevOpsPlatformService;
+ private final GithubProjectCreatorFactory githubProjectCreatorFactory;
@Inject
public ImportGithubProjectAction(DbClient dbClient, ManagedProjectService managedProjectService, UserSession userSession,
ComponentUpdater componentUpdater, ImportHelper importHelper,
NewCodeDefinitionResolver newCodeDefinitionResolver,
- DefaultBranchNameResolver defaultBranchNameResolver, GitHubDevOpsPlatformService gitHubDevOpsPlatformService) {
+ DefaultBranchNameResolver defaultBranchNameResolver, GithubProjectCreatorFactory githubProjectCreatorFactory) {
this.dbClient = dbClient;
this.managedProjectService = managedProjectService;
this.userSession = userSession;
this.importHelper = importHelper;
this.newCodeDefinitionResolver = newCodeDefinitionResolver;
this.defaultBranchNameResolver = defaultBranchNameResolver;
- this.gitHubDevOpsPlatformService = gitHubDevOpsPlatformService;
+ this.githubProjectCreatorFactory = githubProjectCreatorFactory;
}
@Override
String url = requireNonNull(almSettingDto.getUrl(), "DevOps Platform url cannot be null");
DevOpsProjectDescriptor devOpsProjectDescriptor = new DevOpsProjectDescriptor(ALM.GITHUB, url, repositoryKey);
- ComponentCreationData componentCreationData = gitHubDevOpsPlatformService.createProjectAndBindToDevOpsPlatform(dbSession, almSettingDto, accessToken,
- devOpsProjectDescriptor);
+
+ Optional<DevOpsProjectCreator> devOpsProjectCreator = githubProjectCreatorFactory.getDevOpsProjectCreator(dbSession, almSettingDto, accessToken, devOpsProjectDescriptor);
+ CreationMethod creationMethod = getCreationMethod(ALM_IMPORT, userSession.isAuthenticatedBrowserSession());
+ ComponentCreationData componentCreationData = devOpsProjectCreator.get().createProjectAndBindToDevOpsPlatform(dbSession, creationMethod, null);
checkNewCodeDefinitionParam(newCodeDefinitionType, newCodeDefinitionValue);
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.almsettings.ws;
-
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import javax.annotation.Priority;
-import org.apache.commons.lang.NotImplementedException;
-import org.sonar.alm.client.github.security.AccessToken;
-import org.sonar.api.server.ServerSide;
-import org.sonar.db.DbSession;
-import org.sonar.db.alm.setting.ALM;
-import org.sonar.db.alm.setting.AlmSettingDto;
-import org.sonar.server.component.ComponentCreationData;
-
-@ServerSide
-@Priority(1)
-public class DelegatingDevOpsPlatformService implements DevOpsPlatformService {
-
- private final Set<DevOpsPlatformService> delegates;
-
- public DelegatingDevOpsPlatformService(Set<DevOpsPlatformService> delegates) {
- this.delegates = delegates;
- }
-
- @Override
- public ALM getDevOpsPlatform() {
- throw new NotImplementedException();
- }
-
- @Override
- public Optional<DevOpsProjectDescriptor> getDevOpsProjectDescriptor(Map<String, String> characteristics) {
- return delegates.stream()
- .flatMap(delegate -> delegate.getDevOpsProjectDescriptor(characteristics).stream())
- .findFirst();
- }
-
- @Override
- public Optional<AlmSettingDto> getValidAlmSettingDto(DbSession dbSession, DevOpsProjectDescriptor devOpsProjectDescriptor) {
- return findDelegate(devOpsProjectDescriptor.alm())
- .flatMap(delegate -> delegate.getValidAlmSettingDto(dbSession, devOpsProjectDescriptor));
- }
-
- @Override
- public boolean isScanAllowedUsingPermissionsFromDevopsPlatform(AlmSettingDto almSettingDto, DevOpsProjectDescriptor devOpsProjectDescriptor) {
- return findDelegate(devOpsProjectDescriptor.alm())
- .map(delegate -> delegate.isScanAllowedUsingPermissionsFromDevopsPlatform(almSettingDto, devOpsProjectDescriptor))
- .orElseThrow(() -> new IllegalStateException("No delegate found to handle projects on " + devOpsProjectDescriptor.alm()));
- }
-
- @Override
- public ComponentCreationData createProjectAndBindToDevOpsPlatform(DbSession dbSession, String projectKey, AlmSettingDto almSettingDto,
- DevOpsProjectDescriptor devOpsProjectDescriptor) {
- return findDelegate(almSettingDto.getAlm())
- .map(delegate -> delegate.createProjectAndBindToDevOpsPlatform(dbSession, projectKey, almSettingDto, devOpsProjectDescriptor))
- .orElseThrow(() -> new IllegalStateException("Impossible to bind project to ALM platform " + almSettingDto.getAlm()));
- }
-
- @Override
- public ComponentCreationData createProjectAndBindToDevOpsPlatform(DbSession dbSession, AlmSettingDto almSettingDto, AccessToken accessToken,
- DevOpsProjectDescriptor devOpsProjectDescriptor) {
- return findDelegate(almSettingDto.getAlm())
- .map(delegate -> delegate.createProjectAndBindToDevOpsPlatform(dbSession, almSettingDto, accessToken, devOpsProjectDescriptor))
- .orElseThrow(() -> new IllegalStateException("Impossible to bind project to ALM platform " + almSettingDto.getAlm()));
- }
-
- private Optional<DevOpsPlatformService> findDelegate(ALM alm) {
- return delegates.stream()
- .filter(delegate -> delegate.getDevOpsPlatform().equals(alm))
- .findFirst();
- }
-
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.almsettings.ws;
+
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import javax.annotation.Priority;
+import org.sonar.api.server.ServerSide;
+import org.sonar.db.DbSession;
+
+@ServerSide
+@Priority(1)
+public class DelegatingDevOpsProjectCreatorFactory implements DevOpsProjectCreatorFactory {
+
+ private final Set<DevOpsProjectCreatorFactory> delegates;
+
+ public DelegatingDevOpsProjectCreatorFactory(Set<DevOpsProjectCreatorFactory> delegates) {
+ this.delegates = delegates;
+ }
+
+ @Override
+ public Optional<DevOpsProjectCreator> getDevOpsProjectCreator(DbSession dbSession, Map<String, String> characteristics) {
+ return delegates.stream()
+ .flatMap(delegate -> delegate.getDevOpsProjectCreator(dbSession, characteristics).stream())
+ .findFirst();
+ }
+
+
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.almsettings.ws;
-
-import java.util.Map;
-import java.util.Optional;
-import org.sonar.alm.client.github.security.AccessToken;
-import org.sonar.db.DbSession;
-import org.sonar.db.alm.setting.ALM;
-import org.sonar.db.alm.setting.AlmSettingDto;
-import org.sonar.server.component.ComponentCreationData;
-
-public interface DevOpsPlatformService {
-
- ALM getDevOpsPlatform();
-
- Optional<DevOpsProjectDescriptor> getDevOpsProjectDescriptor(Map<String, String> characteristics);
-
- Optional<AlmSettingDto> getValidAlmSettingDto(DbSession dbSession, DevOpsProjectDescriptor devOpsProjectDescriptor);
-
- boolean isScanAllowedUsingPermissionsFromDevopsPlatform(AlmSettingDto almSettingDto, DevOpsProjectDescriptor devOpsProjectDescriptor);
-
- ComponentCreationData createProjectAndBindToDevOpsPlatform(DbSession dbSession, String projectKey, AlmSettingDto almSettingDto, DevOpsProjectDescriptor devOpsProjectDescriptor);
-
- ComponentCreationData createProjectAndBindToDevOpsPlatform(DbSession dbSession, AlmSettingDto almSettingDto, AccessToken accessToken,
- DevOpsProjectDescriptor devOpsProjectDescriptor);
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.almsettings.ws;
+
+import javax.annotation.Nullable;
+import org.sonar.db.DbSession;
+import org.sonar.db.project.CreationMethod;
+import org.sonar.server.component.ComponentCreationData;
+
+public interface DevOpsProjectCreator {
+
+ boolean isScanAllowedUsingPermissionsFromDevopsPlatform();
+
+ ComponentCreationData createProjectAndBindToDevOpsPlatform(DbSession dbSession, CreationMethod creationMethod, @Nullable String projectKey);
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.almsettings.ws;
+
+import java.util.Map;
+import java.util.Optional;
+import org.sonar.db.DbSession;
+
+public interface DevOpsProjectCreatorFactory {
+
+ Optional<DevOpsProjectCreator> getDevOpsProjectCreator(DbSession dbSession, Map<String, String> characteristics);
+
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.almsettings.ws;
-
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-import javax.annotation.Nullable;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.alm.client.github.AppInstallationToken;
-import org.sonar.alm.client.github.GithubApplicationClient;
-import org.sonar.alm.client.github.GithubGlobalSettingsValidator;
-import org.sonar.alm.client.github.api.GsonRepositoryCollaborator;
-import org.sonar.alm.client.github.api.GsonRepositoryTeam;
-import org.sonar.alm.client.github.config.GithubAppConfiguration;
-import org.sonar.alm.client.github.security.AccessToken;
-import org.sonar.api.server.ServerSide;
-import org.sonar.api.web.UserRole;
-import org.sonar.auth.github.GitHubSettings;
-import org.sonar.auth.github.GithubPermissionConverter;
-import org.sonar.auth.github.GsonRepositoryPermissions;
-import org.sonar.db.DbClient;
-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.ProjectAlmSettingDto;
-import org.sonar.db.project.CreationMethod;
-import org.sonar.db.project.ProjectDto;
-import org.sonar.db.provisioning.GithubPermissionsMappingDto;
-import org.sonar.db.user.GroupDto;
-import org.sonar.server.almintegration.ws.ProjectKeyGenerator;
-import org.sonar.server.component.ComponentCreationData;
-import org.sonar.server.component.ComponentCreationParameters;
-import org.sonar.server.component.ComponentUpdater;
-import org.sonar.server.component.NewComponent;
-import org.sonar.server.exceptions.NotFoundException;
-import org.sonar.server.project.ProjectDefaultVisibility;
-import org.sonar.server.user.UserSession;
-
-import static java.lang.String.format;
-import static java.util.Objects.requireNonNull;
-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.SCANNER_API_DEVOPS_AUTO_CONFIG;
-import static org.sonar.db.project.CreationMethod.getCreationMethod;
-import static org.sonar.server.component.NewComponent.newComponentBuilder;
-
-@ServerSide
-public class GitHubDevOpsPlatformService implements DevOpsPlatformService {
- private static final Logger LOG = LoggerFactory.getLogger(GitHubDevOpsPlatformService.class);
-
- public static final String DEVOPS_PLATFORM_URL = "devOpsPlatformUrl";
- public static final String DEVOPS_PLATFORM_PROJECT_IDENTIFIER = "devOpsPlatformProjectIdentifier";
-
- private final DbClient dbClient;
- private final GithubGlobalSettingsValidator githubGlobalSettingsValidator;
- private final GithubApplicationClient githubApplicationClient;
- private final ProjectDefaultVisibility projectDefaultVisibility;
- private final ProjectKeyGenerator projectKeyGenerator;
- private final UserSession userSession;
- private final ComponentUpdater componentUpdater;
- private final GitHubSettings gitHubSettings;
- private final GithubPermissionConverter githubPermissionConverter;
-
- public GitHubDevOpsPlatformService(DbClient dbClient, GithubGlobalSettingsValidator githubGlobalSettingsValidator,
- GithubApplicationClient githubApplicationClient, ProjectDefaultVisibility projectDefaultVisibility, ProjectKeyGenerator projectKeyGenerator, UserSession userSession,
- ComponentUpdater componentUpdater, GitHubSettings gitHubSettings, GithubPermissionConverter githubPermissionConverter) {
- this.dbClient = dbClient;
- this.githubGlobalSettingsValidator = githubGlobalSettingsValidator;
- this.githubApplicationClient = githubApplicationClient;
- this.projectDefaultVisibility = projectDefaultVisibility;
- this.projectKeyGenerator = projectKeyGenerator;
- this.userSession = userSession;
- this.componentUpdater = componentUpdater;
- this.gitHubSettings = gitHubSettings;
- this.githubPermissionConverter = githubPermissionConverter;
- }
-
- @Override
- public ALM getDevOpsPlatform() {
- return ALM.GITHUB;
- }
-
- @Override
- public Optional<DevOpsProjectDescriptor> getDevOpsProjectDescriptor(Map<String, String> characteristics) {
- String githubApiUrl = characteristics.get(DEVOPS_PLATFORM_URL);
- String githubRepository = characteristics.get(DEVOPS_PLATFORM_PROJECT_IDENTIFIER);
- if (githubApiUrl != null && githubRepository != null) {
- return Optional.of(new DevOpsProjectDescriptor(ALM.GITHUB, githubApiUrl, githubRepository));
- }
- return Optional.empty();
- }
-
- @Override
- public Optional<AlmSettingDto> getValidAlmSettingDto(DbSession dbSession, DevOpsProjectDescriptor devOpsProjectDescriptor) {
- Optional<AlmSettingDto> configurationToUse = dbClient.almSettingDao().selectByAlm(dbSession, getDevOpsPlatform()).stream()
- .filter(almSettingDto -> devOpsProjectDescriptor.url().equals(almSettingDto.getUrl()))
- .filter(almSettingDto -> findInstallationIdToAccessRepo(devOpsProjectDescriptor, almSettingDto))
- .findFirst();
- if (configurationToUse.isPresent()) {
- LOG.info("DevOps configuration {} auto-detected", configurationToUse.get().getKey());
- } else {
- LOG.info("Could not auto-detect a DevOps configuration for project {} (api url {})",
- devOpsProjectDescriptor.projectIdentifier(), devOpsProjectDescriptor.url());
- }
- return configurationToUse;
- }
-
- private boolean findInstallationIdToAccessRepo(DevOpsProjectDescriptor devOpsProjectDescriptor, AlmSettingDto almSettingDto) {
- GithubAppConfiguration githubAppConfiguration = githubGlobalSettingsValidator.validate(almSettingDto);
- return findInstallationIdToAccessRepo(almSettingDto, githubAppConfiguration, devOpsProjectDescriptor.projectIdentifier()).isPresent();
- }
-
- @Override
- public boolean isScanAllowedUsingPermissionsFromDevopsPlatform(AlmSettingDto almSettingDto, DevOpsProjectDescriptor devOpsProjectDescriptor) {
- GithubAppConfiguration githubAppConfiguration = githubGlobalSettingsValidator.validate(almSettingDto);
- long installationId = findInstallationIdToAccessRepo(almSettingDto, githubAppConfiguration, devOpsProjectDescriptor.projectIdentifier())
- .orElseThrow(() -> new IllegalStateException(format("Impossible to find the repository %s on GitHub, using the devops config %s.",
- devOpsProjectDescriptor.projectIdentifier(), almSettingDto.getKey())));
- return isScanAllowedUsingPermissionsFromGithub(devOpsProjectDescriptor.projectIdentifier(), githubAppConfiguration, installationId);
- }
-
- private boolean isScanAllowedUsingPermissionsFromGithub(String organizationAndRepository, GithubAppConfiguration githubAppConfiguration, long installationId) {
- AppInstallationToken accessToken = generateAppInstallationToken(githubAppConfiguration, installationId);
-
- String[] orgaAndRepoTokenified = organizationAndRepository.split("/");
- String organization = orgaAndRepoTokenified[0];
- String repository = orgaAndRepoTokenified[1];
-
- Set<GithubPermissionsMappingDto> permissionsMappingDtos = dbClient.githubPermissionsMappingDao().findAll(dbClient.openSession(false));
-
- boolean userHasDirectAccessToRepo = doesUserHaveScanPermission(githubAppConfiguration.getApiEndpoint(), accessToken, organization, repository, permissionsMappingDtos);
- if (userHasDirectAccessToRepo) {
- return true;
- }
- return doesUserBelongToAGroupWithScanPermission(githubAppConfiguration.getApiEndpoint(), accessToken, organization, repository, permissionsMappingDtos);
- }
-
- private boolean doesUserHaveScanPermission(String apiEndpoint, AppInstallationToken accessToken, String organization, String repository,
- Set<GithubPermissionsMappingDto> permissionsMappingDtos) {
- Set<GsonRepositoryCollaborator> repositoryCollaborators = githubApplicationClient.getRepositoryCollaborators(apiEndpoint, accessToken, organization, repository);
-
- String externalLogin = userSession.getExternalIdentity().map(UserSession.ExternalIdentity::login).orElse(null);
- if (externalLogin == null) {
- return false;
- }
- return repositoryCollaborators.stream()
- .filter(gsonRepositoryCollaborator -> externalLogin.equals(gsonRepositoryCollaborator.name()))
- .findAny()
- .map(gsonRepositoryCollaborator -> hasScanPermission(permissionsMappingDtos, gsonRepositoryCollaborator.roleName(), gsonRepositoryCollaborator.permissions()))
- .orElse(false);
- }
-
- private boolean doesUserBelongToAGroupWithScanPermission(String apiUrl, AppInstallationToken accessToken, String organization, String repository,
- Set<GithubPermissionsMappingDto> permissionsMappingDtos) {
- Set<GsonRepositoryTeam> repositoryTeams = githubApplicationClient.getRepositoryTeams(apiUrl, accessToken, organization, repository);
-
- Set<String> groupsOfUser = findUserMembershipOnSonarQube(organization);
- return repositoryTeams.stream()
- .filter(team -> hasScanPermission(permissionsMappingDtos, team.permission(), team.permissions()))
- .map(GsonRepositoryTeam::name)
- .anyMatch(groupsOfUser::contains);
- }
-
- private Set<String> findUserMembershipOnSonarQube(String organization) {
- return userSession.getGroups().stream()
- .map(GroupDto::getName)
- .filter(groupName -> groupName.contains("/"))
- .map(name -> name.replaceFirst(organization + "/", ""))
- .collect(Collectors.toSet());
- }
-
- private boolean hasScanPermission(Set<GithubPermissionsMappingDto> permissionsMappingDtos, String role, GsonRepositoryPermissions permissions) {
- Set<String> sonarqubePermissions = githubPermissionConverter.toSonarqubeRolesWithFallbackOnRepositoryPermissions(permissionsMappingDtos,
- role, permissions);
- return sonarqubePermissions.contains(UserRole.SCAN);
- }
-
- @Override
- public ComponentCreationData createProjectAndBindToDevOpsPlatform(DbSession dbSession, String projectKey, AlmSettingDto almSettingDto,
- DevOpsProjectDescriptor devOpsProjectDescriptor) {
- GithubAppConfiguration githubAppConfiguration = githubGlobalSettingsValidator.validate(almSettingDto);
- GithubApplicationClient.Repository repository = findInstallationIdToAccessRepo(almSettingDto, githubAppConfiguration, devOpsProjectDescriptor.projectIdentifier())
- .flatMap(installationId -> findRepositoryOnGithub(devOpsProjectDescriptor.projectIdentifier(), githubAppConfiguration, installationId))
- .orElseThrow(() -> new IllegalStateException(format("Impossible to find the repository %s on GitHub, using the devops config %s.",
- devOpsProjectDescriptor.projectIdentifier(), almSettingDto.getKey())));
-
- return createProjectAndBindToDevOpsPlatform(dbSession, projectKey, almSettingDto, repository, SCANNER_API_DEVOPS_AUTO_CONFIG);
- }
-
- private Optional<Long> findInstallationIdToAccessRepo(AlmSettingDto almSettingDto, GithubAppConfiguration githubAppConfiguration, String repositoryKey) {
- try {
- return githubApplicationClient.getInstallationId(githubAppConfiguration, repositoryKey);
- } catch (Exception exception) {
- LOG.info(format("Could not use DevOps configuration '%s' to access repo %s. Error: %s", almSettingDto.getKey(), repositoryKey, exception.getMessage()));
- return Optional.empty();
- }
- }
-
- private Optional<GithubApplicationClient.Repository> findRepositoryOnGithub(String organizationAndRepository,
- GithubAppConfiguration githubAppConfiguration, long installationId) {
- AppInstallationToken accessToken = generateAppInstallationToken(githubAppConfiguration, installationId);
- return githubApplicationClient.getRepository(githubAppConfiguration.getApiEndpoint(), accessToken, organizationAndRepository);
- }
-
- private AppInstallationToken generateAppInstallationToken(GithubAppConfiguration githubAppConfiguration, long installationId) {
- return githubApplicationClient.createAppInstallationToken(githubAppConfiguration, installationId)
- .orElseThrow(() -> new IllegalStateException(format("Error while generating token for GitHub Api Url %s (installation id: %s)",
- githubAppConfiguration.getApiEndpoint(), installationId)));
- }
-
- @Override
- public ComponentCreationData createProjectAndBindToDevOpsPlatform(DbSession dbSession, AlmSettingDto almSettingDto, AccessToken accessToken,
- DevOpsProjectDescriptor devOpsProjectDescriptor) {
- String url = requireNonNull(almSettingDto.getUrl(), "DevOps Platform url cannot be null");
- GithubApplicationClient.Repository repository = githubApplicationClient.getRepository(url, accessToken, devOpsProjectDescriptor.projectIdentifier())
- .orElseThrow(() -> new NotFoundException(String.format("GitHub repository '%s' not found", devOpsProjectDescriptor)));
-
- CreationMethod creationMethod = getCreationMethod(ALM_IMPORT, userSession.isAuthenticatedBrowserSession());
- return createProjectAndBindToDevOpsPlatform(dbSession, null, almSettingDto, repository, creationMethod);
- }
-
- private ComponentCreationData createProjectAndBindToDevOpsPlatform(DbSession dbSession, @Nullable String projectKey, AlmSettingDto almSettingDto,
- GithubApplicationClient.Repository repository, CreationMethod creationMethod) {
- ComponentCreationData componentCreationData = createProject(dbSession, projectKey, repository, creationMethod);
- ProjectDto projectDto = Optional.ofNullable(componentCreationData.projectDto()).orElseThrow();
- createProjectAlmSettingDto(dbSession, repository, projectDto, almSettingDto);
- return componentCreationData;
- }
-
- private ComponentCreationData createProject(DbSession dbSession, @Nullable String projectKey, GithubApplicationClient.Repository repository, CreationMethod creationMethod) {
- boolean visibility = projectDefaultVisibility.get(dbSession).isPrivate();
- NewComponent projectComponent = newComponentBuilder()
- .setKey(Optional.ofNullable(projectKey).orElse(getUniqueProjectKey(repository)))
- .setName(repository.getName())
- .setPrivate(visibility)
- .setQualifier(PROJECT)
- .build();
- ComponentCreationParameters componentCreationParameters = ComponentCreationParameters.builder()
- .newComponent(projectComponent)
- .userLogin(userSession.getLogin())
- .userUuid(userSession.getUuid())
- .mainBranchName(repository.getDefaultBranch())
- .isManaged(gitHubSettings.isProvisioningEnabled())
- .creationMethod(creationMethod)
- .build();
- return componentUpdater.createWithoutCommit(dbSession, componentCreationParameters);
- }
-
- private String getUniqueProjectKey(GithubApplicationClient.Repository repository) {
- return projectKeyGenerator.generateUniqueProjectKey(repository.getFullName());
- }
-
- private void createProjectAlmSettingDto(DbSession dbSession, GithubApplicationClient.Repository repo, ProjectDto projectDto, AlmSettingDto almSettingDto) {
- ProjectAlmSettingDto projectAlmSettingDto = new ProjectAlmSettingDto()
- .setAlmSettingUuid(almSettingDto.getUuid())
- .setAlmRepo(repo.getFullName())
- .setAlmSlug(null)
- .setProjectUuid(projectDto.getUuid())
- .setSummaryCommentEnabled(true)
- .setMonorepo(false);
- dbClient.projectAlmSettingDao().insertOrUpdate(dbSession, projectAlmSettingDto, almSettingDto.getKey(), projectDto.getName(), projectDto.getKey());
- }
-
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.almsettings.ws;
+
+import org.sonar.alm.client.github.security.AccessToken;
+import org.sonar.db.alm.setting.AlmSettingDto;
+import org.sonar.server.user.UserSession;
+
+public record GithubProjectCreationParameters(DevOpsProjectDescriptor devOpsProjectDescriptor, AlmSettingDto almSettingDto, AccessToken appInstallationToken,
+ boolean projectsArePrivateByDefault, boolean isProvisioningEnabled, UserSession userSession) {
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.almsettings.ws;
+
+import java.util.Optional;
+import java.util.Set;
+import javax.annotation.Nullable;
+import org.sonar.alm.client.github.GithubApplicationClient;
+import org.sonar.alm.client.github.api.GsonRepositoryCollaborator;
+import org.sonar.alm.client.github.api.GsonRepositoryTeam;
+import org.sonar.alm.client.github.security.AccessToken;
+import org.sonar.api.web.UserRole;
+import org.sonar.auth.github.GithubPermissionConverter;
+import org.sonar.auth.github.GsonRepositoryPermissions;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.alm.setting.AlmSettingDto;
+import org.sonar.db.alm.setting.ProjectAlmSettingDto;
+import org.sonar.db.project.CreationMethod;
+import org.sonar.db.project.ProjectDto;
+import org.sonar.db.provisioning.GithubPermissionsMappingDto;
+import org.sonar.db.user.GroupDto;
+import org.sonar.server.almintegration.ws.ProjectKeyGenerator;
+import org.sonar.server.component.ComponentCreationData;
+import org.sonar.server.component.ComponentCreationParameters;
+import org.sonar.server.component.ComponentUpdater;
+import org.sonar.server.component.NewComponent;
+import org.sonar.server.user.UserSession;
+
+import static java.util.Objects.requireNonNull;
+import static java.util.stream.Collectors.toSet;
+import static org.sonar.api.resources.Qualifiers.PROJECT;
+import static org.sonar.server.component.NewComponent.newComponentBuilder;
+
+public class GithubProjectCreator implements DevOpsProjectCreator {
+
+ private final DbClient dbClient;
+ private final GithubApplicationClient githubApplicationClient;
+ private final GithubPermissionConverter githubPermissionConverter;
+ private final ProjectKeyGenerator projectKeyGenerator;
+ private final ComponentUpdater componentUpdater;
+ private final GithubProjectCreationParameters githubProjectCreationParameters;
+ private final DevOpsProjectDescriptor devOpsProjectDescriptor;
+ private final AccessToken appInstallationToken;
+ private final UserSession userSession;
+ private final AlmSettingDto almSettingDto;
+
+ public GithubProjectCreator(DbClient dbClient, GithubApplicationClient githubApplicationClient, GithubPermissionConverter githubPermissionConverter,
+ ProjectKeyGenerator projectKeyGenerator, ComponentUpdater componentUpdater, GithubProjectCreationParameters githubProjectCreationParameters) {
+
+ this.dbClient = dbClient;
+ this.githubApplicationClient = githubApplicationClient;
+ this.githubPermissionConverter = githubPermissionConverter;
+ this.projectKeyGenerator = projectKeyGenerator;
+ this.componentUpdater = componentUpdater;
+ this.githubProjectCreationParameters = githubProjectCreationParameters;
+ devOpsProjectDescriptor = githubProjectCreationParameters.devOpsProjectDescriptor();
+ appInstallationToken = githubProjectCreationParameters.appInstallationToken();
+ userSession = githubProjectCreationParameters.userSession();
+ almSettingDto = githubProjectCreationParameters.almSettingDto();
+ }
+
+ @Override
+ public boolean isScanAllowedUsingPermissionsFromDevopsPlatform() {
+ String[] orgaAndRepoTokenified = devOpsProjectDescriptor.projectIdentifier().split("/");
+ String organization = orgaAndRepoTokenified[0];
+ String repository = orgaAndRepoTokenified[1];
+
+ Set<GithubPermissionsMappingDto> permissionsMappingDtos = dbClient.githubPermissionsMappingDao().findAll(dbClient.openSession(false));
+
+ boolean userHasDirectAccessToRepo = doesUserHaveScanPermission(organization, repository, permissionsMappingDtos);
+ if (userHasDirectAccessToRepo) {
+ return true;
+ }
+ return doesUserBelongToAGroupWithScanPermission(organization, repository, permissionsMappingDtos);
+ }
+
+ private boolean doesUserHaveScanPermission(String organization, String repository, Set<GithubPermissionsMappingDto> permissionsMappingDtos) {
+ Set<GsonRepositoryCollaborator> repositoryCollaborators = githubApplicationClient.getRepositoryCollaborators(devOpsProjectDescriptor.url(), appInstallationToken, organization,
+ repository);
+
+ String externalLogin = userSession.getExternalIdentity().map(UserSession.ExternalIdentity::login).orElse(null);
+ if (externalLogin == null) {
+ return false;
+ }
+ return repositoryCollaborators.stream()
+ .filter(gsonRepositoryCollaborator -> externalLogin.equals(gsonRepositoryCollaborator.name()))
+ .findAny()
+ .map(gsonRepositoryCollaborator -> hasScanPermission(permissionsMappingDtos, gsonRepositoryCollaborator.roleName(), gsonRepositoryCollaborator.permissions()))
+ .orElse(false);
+ }
+
+ private boolean doesUserBelongToAGroupWithScanPermission(String organization, String repository,
+ Set<GithubPermissionsMappingDto> permissionsMappingDtos) {
+ Set<GsonRepositoryTeam> repositoryTeams = githubApplicationClient.getRepositoryTeams(devOpsProjectDescriptor.url(), appInstallationToken, organization, repository);
+
+ Set<String> groupsOfUser = findUserMembershipOnSonarQube(organization);
+ return repositoryTeams.stream()
+ .filter(team -> hasScanPermission(permissionsMappingDtos, team.permission(), team.permissions()))
+ .map(GsonRepositoryTeam::name)
+ .anyMatch(groupsOfUser::contains);
+ }
+
+ private Set<String> findUserMembershipOnSonarQube(String organization) {
+ return userSession.getGroups().stream()
+ .map(GroupDto::getName)
+ .filter(groupName -> groupName.contains("/"))
+ .map(name -> name.replaceFirst(organization + "/", ""))
+ .collect(toSet());
+ }
+
+ private boolean hasScanPermission(Set<GithubPermissionsMappingDto> permissionsMappingDtos, String role, GsonRepositoryPermissions permissions) {
+ Set<String> sonarqubePermissions = githubPermissionConverter.toSonarqubeRolesWithFallbackOnRepositoryPermissions(permissionsMappingDtos,
+ role, permissions);
+ return sonarqubePermissions.contains(UserRole.SCAN);
+ }
+
+ @Override
+ public ComponentCreationData createProjectAndBindToDevOpsPlatform(DbSession dbSession, CreationMethod creationMethod, @Nullable String projectKey) {
+ String url = requireNonNull(almSettingDto.getUrl(), "DevOps Platform url cannot be null");
+ GithubApplicationClient.Repository repository = githubApplicationClient.getRepository(url, appInstallationToken, devOpsProjectDescriptor.projectIdentifier())
+ .orElseThrow(() -> new IllegalStateException(
+ String.format("Impossible to find the repository '%s' on GitHub, using the devops config %s", devOpsProjectDescriptor.projectIdentifier(), almSettingDto.getKey())));
+
+ return createProjectAndBindToDevOpsPlatform(dbSession, projectKey, almSettingDto, repository, creationMethod);
+ }
+
+ private ComponentCreationData createProjectAndBindToDevOpsPlatform(DbSession dbSession, @Nullable String projectKey, AlmSettingDto almSettingDto,
+ GithubApplicationClient.Repository repository, CreationMethod creationMethod) {
+ ComponentCreationData componentCreationData = createProject(dbSession, projectKey, repository, creationMethod);
+ ProjectDto projectDto = Optional.ofNullable(componentCreationData.projectDto()).orElseThrow();
+ createProjectAlmSettingDto(dbSession, repository, projectDto, almSettingDto);
+ return componentCreationData;
+ }
+
+ private ComponentCreationData createProject(DbSession dbSession, @Nullable String projectKey, GithubApplicationClient.Repository repository, CreationMethod creationMethod) {
+ NewComponent projectComponent = newComponentBuilder()
+ .setKey(Optional.ofNullable(projectKey).orElse(getUniqueProjectKey(repository)))
+ .setName(repository.getName())
+ .setPrivate(githubProjectCreationParameters.projectsArePrivateByDefault())
+ .setQualifier(PROJECT)
+ .build();
+ ComponentCreationParameters componentCreationParameters = ComponentCreationParameters.builder()
+ .newComponent(projectComponent)
+ .userLogin(userSession.getLogin())
+ .userUuid(userSession.getUuid())
+ .mainBranchName(repository.getDefaultBranch())
+ .isManaged(githubProjectCreationParameters.isProvisioningEnabled())
+ .creationMethod(creationMethod)
+ .build();
+ return componentUpdater.createWithoutCommit(dbSession, componentCreationParameters);
+ }
+
+ private String getUniqueProjectKey(GithubApplicationClient.Repository repository) {
+ return projectKeyGenerator.generateUniqueProjectKey(repository.getFullName());
+ }
+
+ private void createProjectAlmSettingDto(DbSession dbSession, GithubApplicationClient.Repository repo, ProjectDto projectDto, AlmSettingDto almSettingDto) {
+ ProjectAlmSettingDto projectAlmSettingDto = new ProjectAlmSettingDto()
+ .setAlmSettingUuid(almSettingDto.getUuid())
+ .setAlmRepo(repo.getFullName())
+ .setAlmSlug(null)
+ .setProjectUuid(projectDto.getUuid())
+ .setSummaryCommentEnabled(true)
+ .setMonorepo(false);
+ dbClient.projectAlmSettingDao().insertOrUpdate(dbSession, projectAlmSettingDto, almSettingDto.getKey(), projectDto.getName(), projectDto.getKey());
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.almsettings.ws;
+
+import java.util.Map;
+import java.util.Optional;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.alm.client.github.AppInstallationToken;
+import org.sonar.alm.client.github.GithubApplicationClient;
+import org.sonar.alm.client.github.GithubGlobalSettingsValidator;
+import org.sonar.alm.client.github.config.GithubAppConfiguration;
+import org.sonar.alm.client.github.security.AccessToken;
+import org.sonar.api.server.ServerSide;
+import org.sonar.auth.github.GitHubSettings;
+import org.sonar.auth.github.GithubPermissionConverter;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.alm.setting.ALM;
+import org.sonar.db.alm.setting.AlmSettingDto;
+import org.sonar.server.almintegration.ws.ProjectKeyGenerator;
+import org.sonar.server.component.ComponentUpdater;
+import org.sonar.server.project.ProjectDefaultVisibility;
+import org.sonar.server.user.UserSession;
+
+import static java.lang.String.format;
+import static org.sonar.core.ce.CeTaskCharacteristics.DEVOPS_PLATFORM_PROJECT_IDENTIFIER;
+import static org.sonar.core.ce.CeTaskCharacteristics.DEVOPS_PLATFORM_URL;
+
+@ServerSide
+public class GithubProjectCreatorFactory implements DevOpsProjectCreatorFactory {
+ private static final Logger LOG = LoggerFactory.getLogger(GithubProjectCreatorFactory.class);
+
+ private final DbClient dbClient;
+ private final GithubGlobalSettingsValidator githubGlobalSettingsValidator;
+ private final GithubApplicationClient githubApplicationClient;
+ private final ProjectDefaultVisibility projectDefaultVisibility;
+ private final ProjectKeyGenerator projectKeyGenerator;
+ private final UserSession userSession;
+ private final ComponentUpdater componentUpdater;
+ private final GitHubSettings gitHubSettings;
+ private final GithubPermissionConverter githubPermissionConverter;
+
+ public GithubProjectCreatorFactory(DbClient dbClient, GithubGlobalSettingsValidator githubGlobalSettingsValidator,
+ GithubApplicationClient githubApplicationClient, ProjectDefaultVisibility projectDefaultVisibility, ProjectKeyGenerator projectKeyGenerator, UserSession userSession,
+ ComponentUpdater componentUpdater, GitHubSettings gitHubSettings, GithubPermissionConverter githubPermissionConverter) {
+ this.dbClient = dbClient;
+ this.githubGlobalSettingsValidator = githubGlobalSettingsValidator;
+ this.githubApplicationClient = githubApplicationClient;
+ this.projectDefaultVisibility = projectDefaultVisibility;
+ this.projectKeyGenerator = projectKeyGenerator;
+ this.userSession = userSession;
+ this.componentUpdater = componentUpdater;
+ this.gitHubSettings = gitHubSettings;
+ this.githubPermissionConverter = githubPermissionConverter;
+ }
+
+ @Override
+ public Optional<DevOpsProjectCreator> getDevOpsProjectCreator(DbSession dbSession, Map<String, String> characteristics) {
+ String githubApiUrl = characteristics.get(DEVOPS_PLATFORM_URL);
+ String githubRepository = characteristics.get(DEVOPS_PLATFORM_PROJECT_IDENTIFIER);
+ if (githubApiUrl == null || githubRepository == null) {
+ return Optional.empty();
+ }
+ DevOpsProjectDescriptor devOpsProjectDescriptor = new DevOpsProjectDescriptor(ALM.GITHUB, githubApiUrl, githubRepository);
+
+ Optional<DevOpsProjectCreator> githubProjectCreator = dbClient.almSettingDao().selectByAlm(dbSession, ALM.GITHUB).stream()
+ .filter(almSettingDto -> devOpsProjectDescriptor.url().equals(almSettingDto.getUrl()))
+ .map(almSettingDto -> findInstallationIdAndCreateDevOpsProjectCreator(dbSession, devOpsProjectDescriptor, almSettingDto))
+ .flatMap(Optional::stream)
+ .findFirst();
+
+ if (githubProjectCreator.isPresent()) {
+ return githubProjectCreator;
+ }
+
+ throw new IllegalStateException(format("The project %s could not be created. It was auto-detected as a %s project "
+ + "and no valid DevOps platform configuration were found to access %s. Please check with a SonarQube administrator.",
+ devOpsProjectDescriptor.projectIdentifier(), devOpsProjectDescriptor.alm(), devOpsProjectDescriptor.url()));
+ }
+
+ private Optional<DevOpsProjectCreator> findInstallationIdAndCreateDevOpsProjectCreator(DbSession dbSession, DevOpsProjectDescriptor devOpsProjectDescriptor,
+ AlmSettingDto almSettingDto) {
+ GithubAppConfiguration githubAppConfiguration = githubGlobalSettingsValidator.validate(almSettingDto);
+ return findInstallationIdToAccessRepo(githubAppConfiguration, devOpsProjectDescriptor.projectIdentifier())
+ .map(installationId -> generateAppInstallationToken(githubAppConfiguration, installationId))
+ .map(appInstallationToken -> createGithubProjectCreator(dbSession, devOpsProjectDescriptor, almSettingDto, appInstallationToken));
+ }
+
+ private Optional<Long> findInstallationIdToAccessRepo(GithubAppConfiguration githubAppConfiguration, String repositoryKey) {
+ return githubApplicationClient.getInstallationId(githubAppConfiguration, repositoryKey);
+ }
+
+ private AppInstallationToken generateAppInstallationToken(GithubAppConfiguration githubAppConfiguration, long installationId) {
+ return githubApplicationClient.createAppInstallationToken(githubAppConfiguration, installationId)
+ .orElseThrow(() -> new IllegalStateException(format("Error while generating token for GitHub Api Url %s (installation id: %s)",
+ githubAppConfiguration.getApiEndpoint(), installationId)));
+ }
+
+ private GithubProjectCreator createGithubProjectCreator(DbSession dbSession, DevOpsProjectDescriptor devOpsProjectDescriptor, AlmSettingDto almSettingDto,
+ AppInstallationToken appInstallationToken) {
+ LOG.info("DevOps configuration {} auto-detected for project {}", almSettingDto.getKey(), devOpsProjectDescriptor.projectIdentifier());
+ GithubProjectCreationParameters githubProjectCreationParameters = new GithubProjectCreationParameters(devOpsProjectDescriptor,
+ almSettingDto, appInstallationToken, projectDefaultVisibility.get(dbSession).isPrivate(), gitHubSettings.isProvisioningEnabled(), userSession);
+ return new GithubProjectCreator(dbClient, githubApplicationClient, githubPermissionConverter, projectKeyGenerator, componentUpdater,
+ githubProjectCreationParameters);
+ }
+
+ public Optional<DevOpsProjectCreator> getDevOpsProjectCreator(DbSession dbSession, AlmSettingDto almSettingDto, AccessToken accessToken,
+ DevOpsProjectDescriptor devOpsProjectDescriptor) {
+ GithubProjectCreationParameters githubProjectCreationParameters = new GithubProjectCreationParameters(devOpsProjectDescriptor,
+ almSettingDto, accessToken, projectDefaultVisibility.get(dbSession).isPrivate(), gitHubSettings.isProvisioningEnabled(), userSession);
+ return Optional.of(
+ new GithubProjectCreator(dbClient, githubApplicationClient, githubPermissionConverter, projectKeyGenerator, componentUpdater, githubProjectCreationParameters)
+ );
+ }
+
+}
import java.util.List;
import java.util.Map;
import java.util.Optional;
-import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.Scopes;
import org.sonar.ce.task.CeTask;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
-import org.sonar.db.alm.setting.AlmSettingDto;
import org.sonar.db.ce.CeTaskTypes;
import org.sonar.db.component.BranchDto;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.permission.GlobalPermission;
-import org.sonar.server.almsettings.ws.DevOpsPlatformService;
-import org.sonar.server.almsettings.ws.DevOpsProjectDescriptor;
+import org.sonar.server.almsettings.ws.DevOpsProjectCreator;
+import org.sonar.server.almsettings.ws.DevOpsProjectCreatorFactory;
import org.sonar.server.component.ComponentCreationData;
import org.sonar.server.component.ComponentCreationParameters;
import org.sonar.server.component.ComponentUpdater;
import static java.lang.String.format;
import static org.apache.commons.lang.StringUtils.defaultIfBlank;
import static org.sonar.db.project.CreationMethod.SCANNER_API;
+import static org.sonar.db.project.CreationMethod.SCANNER_API_DEVOPS_AUTO_CONFIG;
import static org.sonar.server.component.NewComponent.newComponentBuilder;
import static org.sonar.server.user.AbstractUserSession.insufficientPrivilegesException;
private final DbClient dbClient;
private final BranchSupport branchSupport;
private final ProjectDefaultVisibility projectDefaultVisibility;
- private final DevOpsPlatformService devOpsPlatformService;
+ private final DevOpsProjectCreatorFactory devOpsProjectCreatorFactory;
private final ManagedInstanceService managedInstanceService;
public ReportSubmitter(CeQueue queue, UserSession userSession, ComponentUpdater componentUpdater,
PermissionTemplateService permissionTemplateService, DbClient dbClient, BranchSupport branchSupport, ProjectDefaultVisibility projectDefaultVisibility,
- DevOpsPlatformService devOpsPlatformService, ManagedInstanceService managedInstanceService) {
+ DevOpsProjectCreatorFactory devOpsProjectCreatorFactory, ManagedInstanceService managedInstanceService) {
this.queue = queue;
this.userSession = userSession;
this.componentUpdater = componentUpdater;
this.dbClient = dbClient;
this.branchSupport = branchSupport;
this.projectDefaultVisibility = projectDefaultVisibility;
- this.devOpsPlatformService = devOpsPlatformService;
+ this.devOpsProjectCreatorFactory = devOpsProjectCreatorFactory;
this.managedInstanceService = managedInstanceService;
}
DbSession dbSession, BranchSupport.ComponentKey componentKey) {
userSession.checkPermission(GlobalPermission.PROVISION_PROJECTS);
- DevOpsProjectDescriptor devOpsProjectDescriptor = devOpsPlatformService.getDevOpsProjectDescriptor(characteristics).orElse(null);
- AlmSettingDto almSettingDto = getAlmSettingDto(dbSession, devOpsProjectDescriptor);
+ DevOpsProjectCreator devOpsProjectCreator = devOpsProjectCreatorFactory.getDevOpsProjectCreator(dbSession, characteristics).orElse(null);
- throwIfNoValidDevOpsConfigurationFoundForDevOpsProject(devOpsProjectDescriptor, almSettingDto);
- throwIfCurrentUserWouldNotHaveScanPermission(projectKey, dbSession, devOpsProjectDescriptor, almSettingDto);
+ throwIfCurrentUserWouldNotHaveScanPermission(projectKey, dbSession, devOpsProjectCreator);
- if (almSettingDto != null) {
- return devOpsPlatformService.createProjectAndBindToDevOpsPlatform(dbSession, projectKey, almSettingDto, devOpsProjectDescriptor);
+ if (devOpsProjectCreator != null) {
+ return devOpsProjectCreator.createProjectAndBindToDevOpsPlatform(dbSession, SCANNER_API_DEVOPS_AUTO_CONFIG, projectKey);
}
return createProject(dbSession, componentKey.getKey(), defaultIfBlank(projectName, projectKey));
}
- @CheckForNull
- private AlmSettingDto getAlmSettingDto(DbSession dbSession, @Nullable DevOpsProjectDescriptor devOpsProjectDescriptor) {
- if (devOpsProjectDescriptor != null) {
- return devOpsPlatformService.getValidAlmSettingDto(dbSession, devOpsProjectDescriptor).orElse(null);
- }
- return null;
- }
-
- private static void throwIfNoValidDevOpsConfigurationFoundForDevOpsProject(@Nullable DevOpsProjectDescriptor devOpsProjectDescriptor, @Nullable AlmSettingDto almSettingDto) {
- if (devOpsProjectDescriptor != null && almSettingDto == null) {
- throw new IllegalArgumentException(format("The project %s could not be created. It was auto-detected as a %s project "
- + "and no valid DevOps platform configuration were found to access %s",
- devOpsProjectDescriptor.projectIdentifier(), devOpsProjectDescriptor.alm(), devOpsProjectDescriptor.url()));
- }
- }
-
- private void throwIfCurrentUserWouldNotHaveScanPermission(String projectKey, DbSession dbSession, @Nullable DevOpsProjectDescriptor devOpsProjectDescriptor,
- @Nullable AlmSettingDto almSettingDto) {
- if (!wouldCurrentUserHaveScanPermission(projectKey, dbSession, devOpsProjectDescriptor, almSettingDto)) {
+ private void throwIfCurrentUserWouldNotHaveScanPermission(String projectKey, DbSession dbSession, @Nullable DevOpsProjectCreator devOpsProjectCreator) {
+ if (!wouldCurrentUserHaveScanPermission(projectKey, dbSession, devOpsProjectCreator)) {
throw insufficientPrivilegesException();
}
}
- private boolean wouldCurrentUserHaveScanPermission(String projectKey, DbSession dbSession, @Nullable DevOpsProjectDescriptor devOpsProjectDescriptor,
- @Nullable AlmSettingDto almSettingDto) {
- if (managedInstanceService.isInstanceExternallyManaged() && almSettingDto != null && devOpsProjectDescriptor != null) {
- return devOpsPlatformService.isScanAllowedUsingPermissionsFromDevopsPlatform(almSettingDto, devOpsProjectDescriptor);
+ private boolean wouldCurrentUserHaveScanPermission(String projectKey, DbSession dbSession, @Nullable DevOpsProjectCreator devOpsProjectCreator) {
+ if (managedInstanceService.isInstanceExternallyManaged() && devOpsProjectCreator != null) {
+ return devOpsProjectCreator.isScanAllowedUsingPermissionsFromDevopsPlatform();
}
return permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(dbSession, userSession.getUuid(), projectKey);
}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.almsettings.ws;
-
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import org.apache.commons.lang.NotImplementedException;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.sonar.db.DbSession;
-import org.sonar.db.alm.setting.ALM;
-import org.sonar.db.alm.setting.AlmSettingDto;
-
-import static java.util.Collections.emptySet;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class DelegatingDevOpsPlatformServiceTest {
-
- private static final DelegatingDevOpsPlatformService NO_DEVOPS_PLATFORMS = new DelegatingDevOpsPlatformService(emptySet());
- private static final DelegatingDevOpsPlatformService MULTIPLE_DEVOPS_PLATFORMS = new DelegatingDevOpsPlatformService(
- Set.of(mockGitHubDevOpsPlatformService(), mockAzureDevOpsPlatformService()));
-
- @Mock
- private DbSession dbSession;
-
- @Test
- public void getDevOpsPlatform_shouldThrow() {
- assertThatThrownBy(NO_DEVOPS_PLATFORMS::getDevOpsPlatform)
- .isInstanceOf(NotImplementedException.class);
- }
-
- @Test
- public void getDevOpsProjectDescriptor_whenNoDelegates_shouldReturnOptionalEmpty() {
- Optional<DevOpsProjectDescriptor> devOpsProjectDescriptor = NO_DEVOPS_PLATFORMS.getDevOpsProjectDescriptor(Map.of());
-
- assertThat(devOpsProjectDescriptor).isEmpty();
- }
-
- @Test
- public void getDevOpsProjectDescriptor_whenDelegates_shouldReturnDelegateResponse() {
- Optional<DevOpsProjectDescriptor> devOpsProjectDescriptor = MULTIPLE_DEVOPS_PLATFORMS.getDevOpsProjectDescriptor(Map.of(
- "githubUrl", "githubUrl"
- ));
-
- assertThat(devOpsProjectDescriptor)
- .isPresent()
- .get().usingRecursiveComparison().isEqualTo(new DevOpsProjectDescriptor(ALM.GITHUB, "githubUrl", "githubRepo"));
- }
-
- @Test
- public void getValidAlmSettingDto_whenNoDelegates_shouldReturnOptionalEmpty() {
- Optional<AlmSettingDto> almSettingDto = NO_DEVOPS_PLATFORMS.getValidAlmSettingDto(dbSession, mock(DevOpsProjectDescriptor.class));
-
- assertThat(almSettingDto).isEmpty();
- }
-
- @Test
- public void getValidAlmSettingDto_whenDelegates_shouldReturnDelegateResponse() {
- Optional<AlmSettingDto> almSettingDto = MULTIPLE_DEVOPS_PLATFORMS.getValidAlmSettingDto(dbSession, new DevOpsProjectDescriptor(ALM.GITHUB, "githubUrl", "githubRepo"));
-
- assertThat(almSettingDto)
- .isPresent()
- .get()
- .usingRecursiveComparison().isEqualTo(new AlmSettingDto().setAlm(ALM.GITHUB));
- }
-
- @Test
- public void isScanAllowedUsingPermissionsFromDevopsPlatform_whenNoDelegates_shouldThrow() {
- DevOpsProjectDescriptor devOpsProjectDescriptor = mock();
- when(devOpsProjectDescriptor.alm()).thenReturn(ALM.GITHUB);
-
- assertThatIllegalStateException()
- .isThrownBy(() -> NO_DEVOPS_PLATFORMS.isScanAllowedUsingPermissionsFromDevopsPlatform(mock(), devOpsProjectDescriptor))
- .withMessage("No delegate found to handle projects on GITHUB");
- }
-
- @Test
- public void isScanAllowedUsingPermissionsFromDevopsPlatform_whenDelegates_shouldReturnDelegateResponse() {
- DevOpsProjectDescriptor devOpsProjectDescriptor = mock();
- when(devOpsProjectDescriptor.alm()).thenReturn(ALM.GITHUB);
-
- boolean isScanAllowed = MULTIPLE_DEVOPS_PLATFORMS.isScanAllowedUsingPermissionsFromDevopsPlatform(mock(), devOpsProjectDescriptor);
-
- assertThat(isScanAllowed).isTrue();
- }
-
- private static DevOpsPlatformService mockGitHubDevOpsPlatformService() {
- DevOpsPlatformService mockDevOpsPlatformService = mock();
- when(mockDevOpsPlatformService.getDevOpsPlatform()).thenReturn(ALM.GITHUB);
- when(mockDevOpsPlatformService.getDevOpsProjectDescriptor(Map.of("githubUrl", "githubUrl")))
- .thenReturn(Optional.of(new DevOpsProjectDescriptor(ALM.GITHUB, "githubUrl", "githubRepo")));
- when(mockDevOpsPlatformService.getValidAlmSettingDto(any(), any()))
- .thenReturn(Optional.of(new AlmSettingDto().setAlm(ALM.GITHUB)));
- when(mockDevOpsPlatformService.isScanAllowedUsingPermissionsFromDevopsPlatform(any(), any())).thenReturn(true);
- return mockDevOpsPlatformService;
- }
-
- private static DevOpsPlatformService mockAzureDevOpsPlatformService() {
- DevOpsPlatformService mockDevOpsPlatformService = mock();
- when(mockDevOpsPlatformService.getDevOpsPlatform()).thenReturn(ALM.AZURE_DEVOPS);
- when(mockDevOpsPlatformService.getDevOpsProjectDescriptor(Map.of("azureUrl", "azureUrl")))
- .thenReturn(Optional.of(new DevOpsProjectDescriptor(ALM.AZURE_DEVOPS, "azureUrl", "azureProject")));
- when(mockDevOpsPlatformService.getValidAlmSettingDto(any(), any()))
- .thenReturn(Optional.of(new AlmSettingDto().setAlm(ALM.AZURE_DEVOPS)));
- return mockDevOpsPlatformService;
- }
-
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.almsettings.ws;
+
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import org.junit.Test;
+import org.sonar.db.DbSession;
+
+import static java.util.Collections.emptySet;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class DelegatingDevOpsProjectCreatorFactoryTest {
+
+ private static final DbSession DB_SESSION = mock();
+ private static final Map<String, String> CHARACTERISTICS = Map.of("toto", "tata");
+
+ @Test
+ public void getDevOpsProjectDescriptor_whenNoDelegates_shouldReturnEmptyOptional() {
+ DelegatingDevOpsProjectCreatorFactory noDelegates = new DelegatingDevOpsProjectCreatorFactory(emptySet());
+ Optional<DevOpsProjectCreator> devOpsProjectCreator = noDelegates.getDevOpsProjectCreator(DB_SESSION, CHARACTERISTICS);
+ assertThat(devOpsProjectCreator).isEmpty();
+ }
+
+ @Test
+ public void getDevOpsProjectDescriptor_whenNoDelegatesReturningACreator_shouldReturnEmptyOptional() {
+ DelegatingDevOpsProjectCreatorFactory delegates = new DelegatingDevOpsProjectCreatorFactory(Set.of(mock(), mock()));
+ Optional<DevOpsProjectCreator> devOpsProjectCreator = delegates.getDevOpsProjectCreator(DB_SESSION, CHARACTERISTICS);
+
+ assertThat(devOpsProjectCreator).isEmpty();
+ }
+
+ @Test
+ public void getDevOpsProjectDescriptor_whenOneDelegatesReturningACreator_shouldDelegate() {
+ DevOpsProjectCreatorFactory successfulDelegate = mock();
+ DevOpsProjectCreator devOpsProjectCreator = mock();
+ when(successfulDelegate.getDevOpsProjectCreator(DB_SESSION, CHARACTERISTICS)).thenReturn(Optional.of(devOpsProjectCreator));
+ DelegatingDevOpsProjectCreatorFactory delegates = new DelegatingDevOpsProjectCreatorFactory(Set.of(mock(), successfulDelegate));
+
+ assertThat(delegates.getDevOpsProjectCreator(DB_SESSION, CHARACTERISTICS)).contains(devOpsProjectCreator);
+ }
+
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.almsettings.ws;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Answers;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
-import org.sonar.alm.client.github.AppInstallationToken;
-import org.sonar.alm.client.github.GithubApplicationClient;
-import org.sonar.alm.client.github.GithubGlobalSettingsValidator;
-import org.sonar.alm.client.github.api.GsonRepositoryCollaborator;
-import org.sonar.alm.client.github.api.GsonRepositoryTeam;
-import org.sonar.alm.client.github.config.GithubAppConfiguration;
-import org.sonar.api.resources.Qualifiers;
-import org.sonar.api.testfixtures.log.LogTester;
-import org.sonar.api.utils.log.LoggerLevel;
-import org.sonar.api.web.UserRole;
-import org.sonar.auth.github.GitHubSettings;
-import org.sonar.auth.github.GithubPermissionConverter;
-import org.sonar.auth.github.GsonRepositoryPermissions;
-import org.sonar.db.DbClient;
-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.ProjectAlmSettingDao;
-import org.sonar.db.alm.setting.ProjectAlmSettingDto;
-import org.sonar.db.project.CreationMethod;
-import org.sonar.db.project.ProjectDto;
-import org.sonar.db.provisioning.GithubPermissionsMappingDto;
-import org.sonar.db.user.GroupDto;
-import org.sonar.server.almintegration.ws.ProjectKeyGenerator;
-import org.sonar.server.component.ComponentCreationData;
-import org.sonar.server.component.ComponentCreationParameters;
-import org.sonar.server.component.ComponentUpdater;
-import org.sonar.server.component.NewComponent;
-import org.sonar.server.project.ProjectDefaultVisibility;
-import org.sonar.server.project.Visibility;
-import org.sonar.server.user.UserSession;
-
-import static java.util.Objects.requireNonNull;
-import static java.util.stream.Collectors.toSet;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-import static org.sonar.server.almsettings.ws.GitHubDevOpsPlatformService.DEVOPS_PLATFORM_PROJECT_IDENTIFIER;
-import static org.sonar.server.almsettings.ws.GitHubDevOpsPlatformService.DEVOPS_PLATFORM_URL;
-
-@RunWith(MockitoJUnitRunner.class)
-public class GitHubDevOpsPlatformServiceTest {
- @Rule
- public LogTester logTester = new LogTester().setLevel(LoggerLevel.WARN);
-
- private static final DevOpsProjectDescriptor GITHUB_PROJECT_DESCRIPTOR = new DevOpsProjectDescriptor(ALM.GITHUB, "url", "repo");
- private static final long APP_INSTALLATION_ID = 534534534543L;
- private static final String USER_LOGIN = "user-login-1";
- private static final String USER_UUID = "user-uuid-1";
- private static final String PROJECT_KEY = "projectKey";
- private static final String PROJECT_NAME = "projectName";
- private static final String MAIN_BRANCH_NAME = "defaultBranch";
- private static final String ORGANIZATION_NAME = "orgname";
- private static final String GITHUB_REPO_FULL_NAME = ORGANIZATION_NAME + "/" + PROJECT_NAME;
- private static final String GITHUB_API_URL = "https://api.toto.com";
- private static final DevOpsProjectDescriptor DEV_OPS_PROJECT_DESCRIPTOR = new DevOpsProjectDescriptor(ALM.GITHUB, GITHUB_API_URL, GITHUB_REPO_FULL_NAME);
-
- @Mock
- private DbSession dbSession;
- @Mock
- private GithubGlobalSettingsValidator githubGlobalSettingsValidator;
- @Mock
- private GithubApplicationClient githubApplicationClient;
-
- @Mock
- private ComponentUpdater componentUpdater;
-
- @Mock(answer = Answers.RETURNS_DEEP_STUBS)
- private DbClient dbClient;
- @Mock
- private UserSession userSession;
-
- @Mock(answer = Answers.RETURNS_DEEP_STUBS)
- private ProjectDefaultVisibility projectDefaultVisibility;
-
- @Mock
- private ProjectKeyGenerator projectKeyGenerator;
-
- @Mock
- private GitHubSettings gitHubSettings;
-
- @Mock
- private GithubPermissionConverter githubPermissionConverter;
-
- @InjectMocks
- private GitHubDevOpsPlatformService gitHubDevOpsPlatformService;
-
- @Captor
- ArgumentCaptor<ComponentCreationParameters> componentCreationParametersCaptor;
- @Captor
- ArgumentCaptor<ProjectAlmSettingDto> projectAlmSettingDtoCaptor;
-
- @Before
- public void setup() {
- when(userSession.getLogin()).thenReturn(USER_LOGIN);
- when(userSession.getUuid()).thenReturn(USER_UUID);
- }
-
- @Test
- public void getDevOpsPlatform_shouldReturnGitHub() {
- assertThat(gitHubDevOpsPlatformService.getDevOpsPlatform())
- .isEqualTo(ALM.GITHUB);
- }
-
- @Test
- public void getDevOpsProjectDescriptor_whenNoCharacteristics_shouldReturnEmpty() {
- Optional<DevOpsProjectDescriptor> devOpsProjectDescriptor = gitHubDevOpsPlatformService.getDevOpsProjectDescriptor(Map.of());
-
- assertThat(devOpsProjectDescriptor).isEmpty();
- }
-
- @Test
- public void getDevOpsProjectDescriptor_whenValidCharacteristics_shouldReturn() {
- Optional<DevOpsProjectDescriptor> devOpsProjectDescriptor = gitHubDevOpsPlatformService.getDevOpsProjectDescriptor(Map.of(
- DEVOPS_PLATFORM_URL, GITHUB_PROJECT_DESCRIPTOR.url(),
- DEVOPS_PLATFORM_PROJECT_IDENTIFIER, GITHUB_PROJECT_DESCRIPTOR.projectIdentifier()
- ));
-
- assertThat(devOpsProjectDescriptor)
- .isPresent()
- .get().usingRecursiveComparison().isEqualTo(GITHUB_PROJECT_DESCRIPTOR);
- }
-
- @Test
- public void getValidAlmSettingDto_whenNoAlmSetting_shouldReturnEmpty() {
- Optional<AlmSettingDto> almSettingDto = gitHubDevOpsPlatformService.getValidAlmSettingDto(dbSession, GITHUB_PROJECT_DESCRIPTOR);
-
- assertThat(almSettingDto).isEmpty();
- }
-
- @Test
- public void getValidAlmSettingDto_whenMultipleAlmSetting_shouldReturnTheRightOne() {
- AlmSettingDto mockGitHubAlmSettingDtoNoAccess = mockGitHubAlmSettingDto(false);
- AlmSettingDto mockGitHubAlmSettingDtoAccess = mockGitHubAlmSettingDto(true);
- when(dbClient.almSettingDao().selectByAlm(dbSession, ALM.GITHUB)).thenReturn(List.of(mockGitHubAlmSettingDtoNoAccess, mockGitHubAlmSettingDtoAccess));
-
- Optional<AlmSettingDto> almSettingDto = gitHubDevOpsPlatformService.getValidAlmSettingDto(dbSession, GITHUB_PROJECT_DESCRIPTOR);
-
- assertThat(almSettingDto)
- .isPresent()
- .get().isEqualTo(mockGitHubAlmSettingDtoAccess);
- }
-
- private AlmSettingDto mockGitHubAlmSettingDto(boolean repoAccess) {
- AlmSettingDto mockAlmSettingDto = mock();
- when(mockAlmSettingDto.getUrl()).thenReturn(GITHUB_PROJECT_DESCRIPTOR.url());
- GithubAppConfiguration mockGithubAppConfiguration = mock(GithubAppConfiguration.class);
- when(githubGlobalSettingsValidator.validate(mockAlmSettingDto)).thenReturn(mockGithubAppConfiguration);
- when(githubApplicationClient.getInstallationId(eq(mockGithubAppConfiguration), any())).thenReturn(repoAccess ? Optional.of(1L) : Optional.empty());
- return mockAlmSettingDto;
- }
-
- @Test
- public void createProjectAndBindToDevOpsPlatform_whenRepoNotFound_throws() {
-
- AlmSettingDto almSettingDto = mockAlmSettingDto();
- GithubAppConfiguration githubAppConfiguration = mockGitHubAppConfiguration(almSettingDto);
- when(githubApplicationClient.getInstallationId(githubAppConfiguration, GITHUB_REPO_FULL_NAME)).thenReturn(Optional.empty());
-
- assertThatIllegalStateException().isThrownBy(
- () -> gitHubDevOpsPlatformService.createProjectAndBindToDevOpsPlatform(dbSession, PROJECT_KEY, almSettingDto, DEV_OPS_PROJECT_DESCRIPTOR))
- .withMessage("Impossible to find the repository orgname/projectName on GitHub, using the devops config devops-platform-config-1.");
- }
-
- @Test
- public void createProjectAndBindToDevOpsPlatform_whenRepoFoundOnGitHub_successfullyCreatesProject() {
- // given
- AlmSettingDto almSettingDto = mockAlmSettingDto();
- mockExistingGitHubRepository(almSettingDto);
-
- ComponentCreationData componentCreationData = mockProjectCreation();
- ProjectAlmSettingDao projectAlmSettingDao = mock();
- when(dbClient.projectAlmSettingDao()).thenReturn(projectAlmSettingDao);
-
- // when
- ComponentCreationData actualComponentCreationData = gitHubDevOpsPlatformService.createProjectAndBindToDevOpsPlatform(dbSession, PROJECT_KEY, almSettingDto,
- DEV_OPS_PROJECT_DESCRIPTOR);
-
- // then
- assertThat(actualComponentCreationData).isEqualTo(componentCreationData);
-
- ComponentCreationParameters componentCreationParameters = componentCreationParametersCaptor.getValue();
- assertComponentCreationParametersContainsCorrectInformation(componentCreationParameters);
- assertThat(componentCreationParameters.isManaged()).isFalse();
- assertThat(componentCreationParameters.newComponent().isPrivate()).isFalse();
-
- verify(projectAlmSettingDao).insertOrUpdate(eq(dbSession), projectAlmSettingDtoCaptor.capture(), eq("devops-platform-config-1"), eq(PROJECT_NAME), eq(PROJECT_KEY));
- ProjectAlmSettingDto projectAlmSettingDto = projectAlmSettingDtoCaptor.getValue();
- assertAlmSettingsDtoContainsCorrectInformation(almSettingDto, requireNonNull(componentCreationData.projectDto()), projectAlmSettingDto);
-
- assertThat(logTester.getLogs()).isEmpty();
- }
-
- @Test
- public void createProjectAndBindToDevOpsPlatform_whenRepoFoundOnGitHubAndAutoProvisioningOn_successfullyCreatesProject() {
- // given
- when(projectDefaultVisibility.get(any())).thenReturn(Visibility.PRIVATE);
- when(gitHubSettings.isProvisioningEnabled()).thenReturn(true);
-
- AlmSettingDto almSettingDto = mockAlmSettingDto();
- mockExistingGitHubRepository(almSettingDto);
-
- ComponentCreationData componentCreationData = mockProjectCreation();
- ProjectAlmSettingDao projectAlmSettingDao = mock();
- when(dbClient.projectAlmSettingDao()).thenReturn(projectAlmSettingDao);
-
- // when
- ComponentCreationData actualComponentCreationData = gitHubDevOpsPlatformService.createProjectAndBindToDevOpsPlatform(dbSession, PROJECT_KEY, almSettingDto,
- DEV_OPS_PROJECT_DESCRIPTOR);
-
- // then
- assertThat(actualComponentCreationData).isEqualTo(componentCreationData);
-
- ComponentCreationParameters componentCreationParameters = componentCreationParametersCaptor.getValue();
- assertComponentCreationParametersContainsCorrectInformation(componentCreationParameters);
- assertThat(componentCreationParameters.isManaged()).isTrue();
- assertThat(componentCreationParameters.newComponent().isPrivate()).isTrue();
-
- verify(projectAlmSettingDao).insertOrUpdate(eq(dbSession), projectAlmSettingDtoCaptor.capture(), eq("devops-platform-config-1"), eq(PROJECT_NAME), eq(PROJECT_KEY));
- ProjectAlmSettingDto projectAlmSettingDto = projectAlmSettingDtoCaptor.getValue();
- assertAlmSettingsDtoContainsCorrectInformation(almSettingDto, requireNonNull(componentCreationData.projectDto()), projectAlmSettingDto);
-
- assertThat(logTester.getLogs()).isEmpty();
- }
-
- @Test
- public void createProjectAndBindToDevOpsPlatform_whenWrongToken_throws() {
- AlmSettingDto almSettingDto = mockAlmSettingDto();
- mockExistingGitHubRepository(almSettingDto);
-
- when(githubApplicationClient.createAppInstallationToken(any(), anyLong())).thenReturn(Optional.empty());
-
- assertThatIllegalStateException().isThrownBy(
- () -> gitHubDevOpsPlatformService.createProjectAndBindToDevOpsPlatform(dbSession, PROJECT_KEY, almSettingDto, DEV_OPS_PROJECT_DESCRIPTOR))
- .withMessage("Error while generating token for GitHub Api Url https://api.toto.com (installation id: 534534534543)");
- }
-
- @Test
- public void isScanAllowedUsingPermissionsFromDevopsPlatform_whenUserIsCollaboratorWithScan_returnsTrue() {
- // given
- AlmSettingDto almSettingDto = mockAlmSettingDto();
-
- GsonRepositoryCollaborator collaborator1 = mockCollaborator("collaborator1", 1, "role1");
- GsonRepositoryCollaborator collaborator2 = mockCollaborator("collaborator2", 2, "role2");
- mockGithubCollaboratorsFromApi(almSettingDto, collaborator1, collaborator2);
- bindSessionToCollaborator(collaborator2);
-
- mockPermissionsConversion(collaborator2, "another_perm", UserRole.SCAN);
-
- // when
- boolean isGranted = gitHubDevOpsPlatformService.isScanAllowedUsingPermissionsFromDevopsPlatform(almSettingDto, DEV_OPS_PROJECT_DESCRIPTOR);
-
- // then
- assertThat(isGranted).isTrue();
- }
-
- @Test
- public void isScanAllowedUsingPermissionsFromDevopsPlatform_whenUserIsCollaboratorButWithoutScan_returnsFalse() {
- // given
- AlmSettingDto almSettingDto = mockAlmSettingDto();
-
- GsonRepositoryCollaborator collaborator1 = mockCollaborator("collaborator1", 1, "role1");
- mockGithubCollaboratorsFromApi(almSettingDto, collaborator1);
- bindSessionToCollaborator(collaborator1);
-
- mockPermissionsConversion(collaborator1, "admin");
-
- // when
- boolean isGranted = gitHubDevOpsPlatformService.isScanAllowedUsingPermissionsFromDevopsPlatform(almSettingDto, DEV_OPS_PROJECT_DESCRIPTOR);
-
- // then
- assertThat(isGranted).isFalse();
- }
-
- @Test
- public void isScanAllowedUsingPermissionsFromDevopsPlatform_whenRepoFoundOnGitHubAndUserIsCollaboratorButWithoutScan_returnsFalse() {
- // given
- AlmSettingDto almSettingDto = mockAlmSettingDto();
-
- GsonRepositoryCollaborator collaborator1 = mockCollaborator("collaborator1", 1, "role1");
- mockGithubCollaboratorsFromApi(almSettingDto, collaborator1);
- bindSessionToCollaborator(collaborator1);
-
- mockPermissionsConversion(collaborator1, "admin");
-
- // when
- boolean isGranted = gitHubDevOpsPlatformService.isScanAllowedUsingPermissionsFromDevopsPlatform(almSettingDto, DEV_OPS_PROJECT_DESCRIPTOR);
-
- // then
- assertThat(isGranted).isFalse();
- }
-
- @Test
- public void isScanAllowedUsingPermissionsFromDevopsPlatform_whenRepoFoundOnGitHubAndUserIsNotExternal_returnsFalse() {
- // given
- AlmSettingDto almSettingDto = mockAlmSettingDto();
-
- GsonRepositoryCollaborator collaborator1 = mockCollaborator("collaborator1", 1, "role1");
- mockGithubCollaboratorsFromApi(almSettingDto, collaborator1);
- mockPermissionsConversion(collaborator1, "admin");
-
- // when
- boolean isGranted = gitHubDevOpsPlatformService.isScanAllowedUsingPermissionsFromDevopsPlatform(almSettingDto, DEV_OPS_PROJECT_DESCRIPTOR);
-
- // then
- assertThat(isGranted).isFalse();
- }
-
- private void mockPermissionsConversion(GsonRepositoryCollaborator collaborator, String... sqPermissions) {
- Set<GithubPermissionsMappingDto> githubPermissionsMappingDtos = mockPermissionsMappingsDtos();
- when(githubPermissionConverter.toSonarqubeRolesWithFallbackOnRepositoryPermissions(githubPermissionsMappingDtos, collaborator.roleName(), collaborator.permissions()))
- .thenReturn(Arrays.stream(sqPermissions).collect(toSet()));
- }
-
- private void bindSessionToCollaborator(GsonRepositoryCollaborator collaborator1) {
- UserSession.ExternalIdentity externalIdentity = new UserSession.ExternalIdentity(String.valueOf(collaborator1.id()), collaborator1.name());
- when(userSession.getExternalIdentity()).thenReturn(Optional.of(externalIdentity));
- }
-
- private static GsonRepositoryCollaborator mockCollaborator(String collaborator1, int id, String role1) {
- return new GsonRepositoryCollaborator(collaborator1, id, role1,
- new GsonRepositoryPermissions(false, false, false, false, false));
- }
-
- private void mockGithubCollaboratorsFromApi(AlmSettingDto almSettingDto, GsonRepositoryCollaborator... repositoryCollaborators) {
- GithubAppConfiguration githubAppConfiguration = mockGitHubAppConfiguration(almSettingDto);
- when(githubApplicationClient.getInstallationId(githubAppConfiguration, GITHUB_REPO_FULL_NAME)).thenReturn(Optional.of(APP_INSTALLATION_ID));
- AppInstallationToken appInstallationToken = mockAppInstallationToken(githubAppConfiguration, APP_INSTALLATION_ID);
- when(githubApplicationClient.getRepositoryCollaborators(GITHUB_API_URL, appInstallationToken, ORGANIZATION_NAME, PROJECT_NAME))
- .thenReturn(Arrays.stream(repositoryCollaborators).collect(toSet()));
- }
-
- @Test
- public void isScanAllowedUsingPermissionsFromDevopsPlatform_whenInstallationIdNotFound_throws() {
- // given
- AlmSettingDto almSettingDto = mockAlmSettingDto();
-
- when(githubApplicationClient.getInstallationId(any(), any())).thenReturn(Optional.empty());
-
- // when
- assertThatIllegalStateException()
- .isThrownBy(() -> gitHubDevOpsPlatformService.isScanAllowedUsingPermissionsFromDevopsPlatform(almSettingDto, DEV_OPS_PROJECT_DESCRIPTOR))
- .withMessage("Impossible to find the repository orgname/projectName on GitHub, using the devops config devops-platform-config-1.");
- }
-
- @Test
- public void isScanAllowedUsingPermissionsFromDevopsPlatform_whenUserIsMemberOfAGroupWithScan_returnsTrue() {
- // given
- AlmSettingDto almSettingDto = mockAlmSettingDto();
-
- GsonRepositoryTeam team1 = mockGithubTeam("team1", 1, "role1");
- GsonRepositoryTeam team2 = mockGithubTeam("team2", 2, "role2");
- mockTeamsFromApi(almSettingDto, team1, team2);
- bindGroupsToUser(team1.name(), team2.name());
-
- mockPermissionsConversion(team1, "another_perm", UserRole.SCAN);
-
- // when
- boolean isGranted = gitHubDevOpsPlatformService.isScanAllowedUsingPermissionsFromDevopsPlatform(almSettingDto, DEV_OPS_PROJECT_DESCRIPTOR);
-
- // then
- assertThat(isGranted).isTrue();
- }
-
- @Test
- public void isScanAllowedUsingPermissionsFromDevopsPlatform_whenUserIsMemberOfAGroupWithoutScanPermission_returnsFalse() {
- // given
- AlmSettingDto almSettingDto = mockAlmSettingDto();
-
- GsonRepositoryTeam team1 = mockGithubTeam("team1", 1, "role1");
- mockTeamsFromApi(almSettingDto, team1);
- bindGroupsToUser(team1.name(), "another_local_team");
-
- mockPermissionsConversion(team1, "another_perm", "admin");
-
- // when
- boolean isGranted = gitHubDevOpsPlatformService.isScanAllowedUsingPermissionsFromDevopsPlatform(almSettingDto, DEV_OPS_PROJECT_DESCRIPTOR);
-
- // then
- assertThat(isGranted).isFalse();
- }
-
- @Test
- public void isScanAllowedUsingPermissionsFromDevopsPlatform_whenUserIsNotMemberOfAGroupWithScanPermission_returnsFalse() {
- // given
- AlmSettingDto almSettingDto = mockAlmSettingDto();
-
- GsonRepositoryTeam team1 = mockGithubTeam("team1", 1, "role1");
- mockTeamsFromApi(almSettingDto, team1);
- bindGroupsToUser("another_local_team");
-
- mockPermissionsConversion(team1, "another_perm", UserRole.SCAN);
-
- // when
- boolean isGranted = gitHubDevOpsPlatformService.isScanAllowedUsingPermissionsFromDevopsPlatform(almSettingDto, DEV_OPS_PROJECT_DESCRIPTOR);
-
- // then
- assertThat(isGranted).isFalse();
- }
-
- private void bindGroupsToUser(String... groupNames) {
- Set<GroupDto> groupDtos = Arrays.stream(groupNames)
- .map(groupName -> new GroupDto().setName(ORGANIZATION_NAME + "/" + groupName).setUuid("uuid_" + groupName))
- .collect(toSet());
- when(userSession.getGroups()).thenReturn(groupDtos);
- }
-
- private static GsonRepositoryTeam mockGithubTeam(String name, int id, String role) {
- return new GsonRepositoryTeam(name, id, name + "slug", role, new GsonRepositoryPermissions(false, false, false, false, false));
- }
-
- private void mockTeamsFromApi(AlmSettingDto almSettingDto, GsonRepositoryTeam... repositoryTeams) {
- GithubAppConfiguration githubAppConfiguration = mockGitHubAppConfiguration(almSettingDto);
- when(githubApplicationClient.getInstallationId(githubAppConfiguration, GITHUB_REPO_FULL_NAME)).thenReturn(Optional.of(APP_INSTALLATION_ID));
- AppInstallationToken appInstallationToken = mockAppInstallationToken(githubAppConfiguration, APP_INSTALLATION_ID);
- when(githubApplicationClient.getRepositoryTeams(GITHUB_API_URL, appInstallationToken, ORGANIZATION_NAME, PROJECT_NAME))
- .thenReturn(Arrays.stream(repositoryTeams).collect(toSet()));
- }
-
- private void mockPermissionsConversion(GsonRepositoryTeam team, String... sqPermissions) {
- Set<GithubPermissionsMappingDto> githubPermissionsMappingDtos = mockPermissionsMappingsDtos();
- when(githubPermissionConverter.toSonarqubeRolesWithFallbackOnRepositoryPermissions(githubPermissionsMappingDtos, team.permission(), team.permissions()))
- .thenReturn(Arrays.stream(sqPermissions).collect(toSet()));
- }
-
- private Set<GithubPermissionsMappingDto> mockPermissionsMappingsDtos() {
- Set<GithubPermissionsMappingDto> githubPermissionsMappingDtos = Set.of(mock(GithubPermissionsMappingDto.class));
- when(dbClient.githubPermissionsMappingDao().findAll(any())).thenReturn(githubPermissionsMappingDtos);
- return githubPermissionsMappingDtos;
- }
-
- private void mockExistingGitHubRepository(AlmSettingDto almSettingDto) {
- GithubAppConfiguration githubAppConfiguration = mockGitHubAppConfiguration(almSettingDto);
- when(githubApplicationClient.getInstallationId(githubAppConfiguration, GITHUB_REPO_FULL_NAME)).thenReturn(Optional.of(APP_INSTALLATION_ID));
- AppInstallationToken appInstallationToken = mockAppInstallationToken(githubAppConfiguration, APP_INSTALLATION_ID);
- mockGitHubRepository(appInstallationToken);
- }
-
- private GithubAppConfiguration mockGitHubAppConfiguration(AlmSettingDto almSettingDto) {
- GithubAppConfiguration githubAppConfiguration = mock();
- when(githubGlobalSettingsValidator.validate(almSettingDto)).thenReturn(githubAppConfiguration);
- when(githubAppConfiguration.getApiEndpoint()).thenReturn(GITHUB_API_URL);
- return githubAppConfiguration;
- }
-
- private void mockGitHubRepository(AppInstallationToken appInstallationToken) {
- GithubApplicationClient.Repository repository = mock();
- when(repository.getDefaultBranch()).thenReturn(MAIN_BRANCH_NAME);
- when(repository.getName()).thenReturn(PROJECT_NAME);
- when(repository.getFullName()).thenReturn(GITHUB_REPO_FULL_NAME);
- when(githubApplicationClient.getRepository(GITHUB_API_URL, appInstallationToken, GITHUB_REPO_FULL_NAME)).thenReturn(Optional.of(repository));
- when(projectKeyGenerator.generateUniqueProjectKey(repository.getFullName())).thenReturn("generated_" + PROJECT_KEY);
- }
-
- private AppInstallationToken mockAppInstallationToken(GithubAppConfiguration githubAppConfiguration, long appInstallationId) {
- AppInstallationToken appInstallationToken = mock();
- when(githubApplicationClient.createAppInstallationToken(githubAppConfiguration, appInstallationId)).thenReturn(Optional.of(appInstallationToken));
- return appInstallationToken;
- }
-
- private static AlmSettingDto mockAlmSettingDto() {
- AlmSettingDto almSettingDto = mock();
- when(almSettingDto.getUuid()).thenReturn("almsetting-uuid-1");
- when(almSettingDto.getKey()).thenReturn("devops-platform-config-1");
- return almSettingDto;
- }
-
- private ComponentCreationData mockProjectCreation() {
- ComponentCreationData componentCreationData = mock();
- mockProjectDto(componentCreationData);
- when(componentUpdater.createWithoutCommit(eq(dbSession), componentCreationParametersCaptor.capture())).thenReturn(componentCreationData);
- return componentCreationData;
- }
-
- private static ProjectDto mockProjectDto(ComponentCreationData componentCreationData) {
- ProjectDto projectDto = mock();
- when(projectDto.getName()).thenReturn(PROJECT_NAME);
- when(projectDto.getKey()).thenReturn(PROJECT_KEY);
- when(projectDto.getUuid()).thenReturn("project-uuid-1");
- when(componentCreationData.projectDto()).thenReturn(projectDto);
- return projectDto;
- }
-
- private static void assertComponentCreationParametersContainsCorrectInformation(ComponentCreationParameters componentCreationParameters) {
- assertThat(componentCreationParameters.creationMethod()).isEqualTo(CreationMethod.SCANNER_API_DEVOPS_AUTO_CONFIG);
- assertThat(componentCreationParameters.mainBranchName()).isEqualTo(MAIN_BRANCH_NAME);
- assertThat(componentCreationParameters.userLogin()).isEqualTo(USER_LOGIN);
- assertThat(componentCreationParameters.userUuid()).isEqualTo(USER_UUID);
-
- NewComponent newComponent = componentCreationParameters.newComponent();
- assertThat(newComponent.isProject()).isTrue();
- assertThat(newComponent.qualifier()).isEqualTo(Qualifiers.PROJECT);
- assertThat(newComponent.key()).isEqualTo(PROJECT_KEY);
- assertThat(newComponent.name()).isEqualTo(PROJECT_NAME);
- }
-
- private static void assertAlmSettingsDtoContainsCorrectInformation(AlmSettingDto almSettingDto, ProjectDto projectDto, ProjectAlmSettingDto projectAlmSettingDto) {
- assertThat(projectAlmSettingDto.getAlmRepo()).isEqualTo(GITHUB_REPO_FULL_NAME);
- assertThat(projectAlmSettingDto.getAlmSlug()).isNull();
- assertThat(projectAlmSettingDto.getAlmSettingUuid()).isEqualTo(almSettingDto.getUuid());
- assertThat(projectAlmSettingDto.getProjectUuid()).isEqualTo(projectDto.getUuid());
- assertThat(projectAlmSettingDto.getMonorepo()).isFalse();
- assertThat(projectAlmSettingDto.getSummaryCommentEnabled()).isTrue();
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.almsettings.ws;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.sonar.alm.client.github.AppInstallationToken;
+import org.sonar.alm.client.github.GithubApplicationClient;
+import org.sonar.alm.client.github.GithubGlobalSettingsValidator;
+import org.sonar.auth.github.GitHubSettings;
+import org.sonar.auth.github.GithubPermissionConverter;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.alm.setting.ALM;
+import org.sonar.db.alm.setting.AlmSettingDto;
+import org.sonar.server.almintegration.ws.ProjectKeyGenerator;
+import org.sonar.server.component.ComponentUpdater;
+import org.sonar.server.project.ProjectDefaultVisibility;
+import org.sonar.server.user.UserSession;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.core.ce.CeTaskCharacteristics.DEVOPS_PLATFORM_PROJECT_IDENTIFIER;
+import static org.sonar.core.ce.CeTaskCharacteristics.DEVOPS_PLATFORM_URL;
+
+@RunWith(MockitoJUnitRunner.class)
+public class GithubProjectCreatorFactoryTest {
+ private static final String EXCEPTION_MESSAGE =
+ "The project orgname/projectName could not be created. It was auto-detected as a GITHUB project and no valid DevOps platform configuration were found to access https://api.toto.com."
+ + " Please check with a SonarQube administrator.";
+
+ private static final String PROJECT_NAME = "projectName";
+ private static final String ORGANIZATION_NAME = "orgname";
+ private static final String GITHUB_REPO_FULL_NAME = ORGANIZATION_NAME + "/" + PROJECT_NAME;
+ private static final String GITHUB_API_URL = "https://api.toto.com";
+
+ private static final DevOpsProjectDescriptor GITHUB_PROJECT_DESCRIPTOR = new DevOpsProjectDescriptor(ALM.GITHUB, GITHUB_API_URL, GITHUB_REPO_FULL_NAME);
+ private static final Map<String, String> VALID_GITHUB_PROJECT_COORDINATES = Map.of(
+ DEVOPS_PLATFORM_URL, GITHUB_PROJECT_DESCRIPTOR.url(),
+ DEVOPS_PLATFORM_PROJECT_IDENTIFIER, GITHUB_PROJECT_DESCRIPTOR.projectIdentifier()
+ );
+ private static final long APP_INSTALLATION_ID = 534534534543L;
+
+ @Mock
+ private DbSession dbSession;
+ @Mock
+ private GithubGlobalSettingsValidator githubGlobalSettingsValidator;
+ @Mock
+ private GithubApplicationClient githubApplicationClient;
+
+ @Mock
+ private ComponentUpdater componentUpdater;
+
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private DbClient dbClient;
+ @Mock
+ private UserSession userSession;
+
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private ProjectDefaultVisibility projectDefaultVisibility;
+
+ @Mock
+ private ProjectKeyGenerator projectKeyGenerator;
+
+ @Mock
+ private GitHubSettings gitHubSettings;
+
+ @Mock
+ private GithubPermissionConverter githubPermissionConverter;
+
+ @Mock
+ private AppInstallationToken appInstallationToken;
+
+ @InjectMocks
+ private GithubProjectCreatorFactory githubProjectCreatorFactory;
+
+ @Test
+ public void getDevOpsProjectCreator_whenNoCharacteristics_shouldReturnEmpty() {
+ Optional<DevOpsProjectCreator> devOpsProjectCreator = githubProjectCreatorFactory.getDevOpsProjectCreator(dbSession, Map.of());
+
+ assertThat(devOpsProjectCreator).isEmpty();
+ }
+
+ @Test
+ public void getDevOpsProjectCreator_whenValidCharacteristicsButNoAlmSettingDao_shouldThrow() {
+ assertThatIllegalStateException().isThrownBy(() -> githubProjectCreatorFactory.getDevOpsProjectCreator(dbSession, VALID_GITHUB_PROJECT_COORDINATES))
+ .withMessage(EXCEPTION_MESSAGE);
+ }
+
+ @Test
+ public void getDevOpsProjectCreator_whenValidCharacteristicsButInvalidAlmSettingDto_shouldThrow() {
+ AlmSettingDto almSettingDto = mockAlmSettingDto(true);
+ IllegalArgumentException error = new IllegalArgumentException("error happened");
+ when(githubGlobalSettingsValidator.validate(almSettingDto)).thenThrow(error);
+
+ assertThatIllegalArgumentException().isThrownBy(() -> githubProjectCreatorFactory.getDevOpsProjectCreator(dbSession, VALID_GITHUB_PROJECT_COORDINATES))
+ .isSameAs(error);
+ }
+
+ @Test
+ public void getDevOpsProjectCreator_whenAppHasNoAccessToRepo_shouldThrow() {
+ mockAlmSettingDto(true);
+ when(githubApplicationClient.getInstallationId(any(), eq(GITHUB_REPO_FULL_NAME))).thenReturn(Optional.empty());
+
+ assertThatIllegalStateException().isThrownBy(() -> githubProjectCreatorFactory.getDevOpsProjectCreator(dbSession, VALID_GITHUB_PROJECT_COORDINATES))
+ .withMessage(EXCEPTION_MESSAGE);
+ }
+
+ @Test
+ public void getDevOpsProjectCreator_whenNotPossibleToGenerateToken_shouldThrow() {
+ AlmSettingDto almSettingDto = mockAlmSettingDto(true);
+ when(githubApplicationClient.getInstallationId(any(), eq(GITHUB_REPO_FULL_NAME))).thenReturn(Optional.of(APP_INSTALLATION_ID));
+ when(githubGlobalSettingsValidator.validate(almSettingDto)).thenReturn(mock());
+ when(githubApplicationClient.createAppInstallationToken(any(), eq(APP_INSTALLATION_ID))).thenReturn(Optional.empty());
+
+ assertThatIllegalStateException().isThrownBy(() -> githubProjectCreatorFactory.getDevOpsProjectCreator(dbSession, VALID_GITHUB_PROJECT_COORDINATES))
+ .withMessage("Error while generating token for GitHub Api Url null (installation id: 1)");
+ }
+
+ @Test
+ public void getDevOpsProjectCreator_whenOneValidAlmSetting_shouldInstantiateDevOpsProjectCreator() {
+ AlmSettingDto almSettingDto = mockAlmSettingDto(true);
+ mockSuccesfullGithubInteraction();
+
+ DevOpsProjectCreator devOpsProjectCreator = githubProjectCreatorFactory.getDevOpsProjectCreator(dbSession, VALID_GITHUB_PROJECT_COORDINATES).orElseThrow();
+
+ GithubProjectCreator expectedGithubProjectCreator = getExpectedGithubProjectCreator(almSettingDto, false, false);
+ assertThat(devOpsProjectCreator).usingRecursiveComparison().isEqualTo(expectedGithubProjectCreator);
+ }
+
+ @Test
+ public void getDevOpsProjectCreator_whenOneValidAlmSettingAndPublicByDefaultAndAutoProviisoningEnabled_shouldInstantiateDevOpsProjectCreator() {
+ when(projectDefaultVisibility.get(any()).isPrivate()).thenReturn(true);
+ when(gitHubSettings.isProvisioningEnabled()).thenReturn(true);
+
+ AlmSettingDto almSettingDto = mockAlmSettingDto(true);
+ mockSuccesfullGithubInteraction();
+
+ DevOpsProjectCreator devOpsProjectCreator = githubProjectCreatorFactory.getDevOpsProjectCreator(dbSession, VALID_GITHUB_PROJECT_COORDINATES).orElseThrow();
+
+ GithubProjectCreator expectedGithubProjectCreator = getExpectedGithubProjectCreator(almSettingDto, true, true);
+ assertThat(devOpsProjectCreator).usingRecursiveComparison().isEqualTo(expectedGithubProjectCreator);
+ }
+
+ @Test
+ public void getDevOpsProjectCreator_whenOneMatchingAndOneNotMatchingAlmSetting_shouldInstantiateDevOpsProjectCreator() {
+ AlmSettingDto matchingAlmSettingDto = mockAlmSettingDto(true);
+ AlmSettingDto notMatchingAlmSettingDto = mockAlmSettingDto(false);
+ when(dbClient.almSettingDao().selectByAlm(dbSession, ALM.GITHUB)).thenReturn(List.of(notMatchingAlmSettingDto, matchingAlmSettingDto));
+
+ mockSuccesfullGithubInteraction();
+
+ DevOpsProjectCreator devOpsProjectCreator = githubProjectCreatorFactory.getDevOpsProjectCreator(dbSession, VALID_GITHUB_PROJECT_COORDINATES).orElseThrow();
+
+ GithubProjectCreator expectedGithubProjectCreator = getExpectedGithubProjectCreator(matchingAlmSettingDto, false, false);
+ assertThat(devOpsProjectCreator).usingRecursiveComparison().isEqualTo(expectedGithubProjectCreator);
+ }
+
+ @Test
+ public void getDevOpsProjectCreatorFromImport_shouldInstantiateDevOpsProjectCreator() {
+ AlmSettingDto mockAlmSettingDto = mockAlmSettingDto(true);
+
+ mockSuccesfullGithubInteraction();
+
+ DevOpsProjectCreator devOpsProjectCreator = githubProjectCreatorFactory.getDevOpsProjectCreator(dbSession, mockAlmSettingDto, appInstallationToken, GITHUB_PROJECT_DESCRIPTOR)
+ .orElseThrow();
+
+ GithubProjectCreator expectedGithubProjectCreator = getExpectedGithubProjectCreator(mockAlmSettingDto, false, false);
+ assertThat(devOpsProjectCreator).usingRecursiveComparison().isEqualTo(expectedGithubProjectCreator);
+ }
+
+ private void mockSuccesfullGithubInteraction() {
+ when(githubApplicationClient.getInstallationId(any(), eq(GITHUB_REPO_FULL_NAME))).thenReturn(Optional.of(APP_INSTALLATION_ID));
+ when(githubApplicationClient.createAppInstallationToken(any(), eq(APP_INSTALLATION_ID))).thenReturn(Optional.of(appInstallationToken));
+ }
+
+ private GithubProjectCreator getExpectedGithubProjectCreator(AlmSettingDto almSettingDto, boolean projectsArePrivateByDefault, boolean isInstanceManaged) {
+ DevOpsProjectDescriptor devOpsProjectDescriptor = new DevOpsProjectDescriptor(ALM.GITHUB, almSettingDto.getUrl(), GITHUB_REPO_FULL_NAME);
+ GithubProjectCreationParameters githubProjectCreationParameters = new GithubProjectCreationParameters(devOpsProjectDescriptor,
+ almSettingDto, appInstallationToken, projectsArePrivateByDefault, isInstanceManaged, userSession);
+ return new GithubProjectCreator(dbClient, githubApplicationClient, githubPermissionConverter, projectKeyGenerator, componentUpdater, githubProjectCreationParameters);
+ }
+
+
+ private AlmSettingDto mockAlmSettingDto(boolean repoAccess) {
+ AlmSettingDto almSettingDto = mock();
+ when(almSettingDto.getUrl()).thenReturn(repoAccess ? GITHUB_PROJECT_DESCRIPTOR.url() : "anotherUrl");
+
+ when(dbClient.almSettingDao().selectByAlm(dbSession, ALM.GITHUB)).thenReturn(List.of(almSettingDto));
+ return almSettingDto;
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.almsettings.ws;
+
+import java.util.Arrays;
+import java.util.Optional;
+import java.util.Set;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.sonar.alm.client.github.GithubApplicationClient;
+import org.sonar.alm.client.github.api.GsonRepositoryCollaborator;
+import org.sonar.alm.client.github.api.GsonRepositoryTeam;
+import org.sonar.alm.client.github.security.AccessToken;
+import org.sonar.api.resources.Qualifiers;
+import org.sonar.api.web.UserRole;
+import org.sonar.auth.github.GithubPermissionConverter;
+import org.sonar.auth.github.GsonRepositoryPermissions;
+import org.sonar.db.DbClient;
+import org.sonar.db.alm.setting.ALM;
+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.CreationMethod;
+import org.sonar.db.project.ProjectDto;
+import org.sonar.db.provisioning.GithubPermissionsMappingDto;
+import org.sonar.db.user.GroupDto;
+import org.sonar.server.almintegration.ws.ProjectKeyGenerator;
+import org.sonar.server.component.ComponentCreationData;
+import org.sonar.server.component.ComponentCreationParameters;
+import org.sonar.server.component.ComponentUpdater;
+import org.sonar.server.component.NewComponent;
+import org.sonar.server.user.UserSession;
+
+import static java.util.Objects.requireNonNull;
+import static java.util.stream.Collectors.toSet;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.sonar.db.project.CreationMethod.ALM_IMPORT_API;
+import static org.sonar.db.project.CreationMethod.SCANNER_API_DEVOPS_AUTO_CONFIG;
+
+@RunWith(MockitoJUnitRunner.class)
+public class GithubProjectCreatorTest {
+
+ private static final String ORGANIZATION_NAME = "orga2";
+ private static final String REPOSITORY_NAME = "repo1";
+
+ private static final String MAIN_BRANCH_NAME = "defaultBranch";
+ private static final DevOpsProjectDescriptor DEVOPS_PROJECT_DESCRIPTOR = new DevOpsProjectDescriptor(ALM.GITHUB, "http://api.com", ORGANIZATION_NAME + "/" + REPOSITORY_NAME);
+ private static final String ALM_SETTING_KEY = "github_config_1";
+ private static final String USER_LOGIN = "userLogin";
+ private static final String USER_UUID = "userUuid";
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private DbClient dbClient;
+ @Mock
+ private GithubApplicationClient githubApplicationClient;
+ @Mock
+ private GithubPermissionConverter githubPermissionConverter;
+ @Mock
+ private ProjectKeyGenerator projectKeyGenerator;
+ @Mock
+ private ComponentUpdater componentUpdater;
+ @Mock
+ private GithubProjectCreationParameters githubProjectCreationParameters;
+ @Mock
+ private AccessToken appInstallationToken;
+ @Mock
+ private UserSession userSession;
+ @Mock
+ private AlmSettingDto almSettingDto;
+
+ private GithubProjectCreator githubProjectCreator;
+
+ @Captor
+ ArgumentCaptor<ComponentCreationParameters> componentCreationParametersCaptor;
+ @Captor
+ ArgumentCaptor<ProjectAlmSettingDto> projectAlmSettingDtoCaptor;
+
+ @Before
+ public void setup() {
+ when(userSession.getLogin()).thenReturn(USER_LOGIN);
+ when(userSession.getUuid()).thenReturn(USER_UUID);
+
+ when(almSettingDto.getUrl()).thenReturn(DEVOPS_PROJECT_DESCRIPTOR.url());
+ when(almSettingDto.getKey()).thenReturn(ALM_SETTING_KEY);
+
+ when(githubProjectCreationParameters.devOpsProjectDescriptor()).thenReturn(DEVOPS_PROJECT_DESCRIPTOR);
+ when(githubProjectCreationParameters.userSession()).thenReturn(userSession);
+ when(githubProjectCreationParameters.appInstallationToken()).thenReturn(appInstallationToken);
+ when(githubProjectCreationParameters.almSettingDto()).thenReturn(almSettingDto);
+
+ githubProjectCreator = new GithubProjectCreator(dbClient, githubApplicationClient, githubPermissionConverter, projectKeyGenerator, componentUpdater,
+ githubProjectCreationParameters);
+
+ /* when(githubProjectCreationParameters.almSettingDto()).thenReturn();
+ when(githubProjectCreationParameters.almSettingDto()).thenReturn();
+ when(githubProjectCreationParameters.almSettingDto()).thenReturn();
+ when(githubProjectCreationParameters.almSettingDto()).thenReturn();*/
+ }
+
+ @Test
+ public void isScanAllowedUsingPermissionsFromDevopsPlatform_whenUserIsNotAGitHubUser_returnsFalse() {
+ assertThat(githubProjectCreator.isScanAllowedUsingPermissionsFromDevopsPlatform()).isFalse();
+ }
+
+ @Test
+ public void isScanAllowedUsingPermissionsFromDevopsPlatform_whenCollaboratorHasDirectAccessButNoScanPermissions_returnsFalse() {
+ GsonRepositoryCollaborator collaborator1 = mockCollaborator("collaborator1", 1, "role1", "read", "admin");
+ mockGithubCollaboratorsFromApi(collaborator1);
+ bindSessionToCollaborator(collaborator1);
+
+ assertThat(githubProjectCreator.isScanAllowedUsingPermissionsFromDevopsPlatform()).isFalse();
+ }
+
+ @Test
+ public void isScanAllowedUsingPermissionsFromDevopsPlatform_whenCollaboratorHasDirectAccess_returnsTrue() {
+ GsonRepositoryCollaborator collaborator1 = mockCollaborator("collaborator1", 1, "role1", "read", "admin");
+ GsonRepositoryCollaborator collaborator2 = mockCollaborator("collaborator2", 2, "role2", "read", "scan");
+ mockGithubCollaboratorsFromApi(collaborator1, collaborator2);
+ bindSessionToCollaborator(collaborator2);
+
+ assertThat(githubProjectCreator.isScanAllowedUsingPermissionsFromDevopsPlatform()).isTrue();
+ }
+
+ @Test
+ public void isScanAllowedUsingPermissionsFromDevopsPlatform_whenAccessViaTeamButNoScanPermissions_returnsFalse() {
+ GsonRepositoryTeam team2 = mockGithubTeam("team2", 2, "role2", "another_perm", UserRole.ADMIN);
+ mockTeamsFromApi(team2);
+ bindGroupsToUser(team2.name());
+
+ assertThat(githubProjectCreator.isScanAllowedUsingPermissionsFromDevopsPlatform()).isFalse();
+ }
+
+ @Test
+ public void isScanAllowedUsingPermissionsFromDevopsPlatform_whenAccessViaTeam_returnsTrue() {
+ GsonRepositoryTeam team1 = mockGithubTeam("team1", 1, "role1", "read", "another_perm");
+ GsonRepositoryTeam team2 = mockGithubTeam("team2", 2, "role2", "another_perm", UserRole.SCAN);
+ mockTeamsFromApi(team1, team2);
+ bindGroupsToUser(team1.name(), team2.name());
+
+ assertThat(githubProjectCreator.isScanAllowedUsingPermissionsFromDevopsPlatform()).isTrue();
+ }
+
+ @Test
+ public void isScanAllowedUsingPermissionsFromDevopsPlatform_whenAccessViaTeamButUserNotInTeam_returnsFalse() {
+ GsonRepositoryTeam team1 = mockGithubTeam("team1", 1, "role1", "read", "another_perm");
+ GsonRepositoryTeam team2 = mockGithubTeam("team2", 2, "role2", "another_perm", UserRole.SCAN);
+ mockTeamsFromApi(team1, team2);
+ bindGroupsToUser(team1.name());
+
+ assertThat(githubProjectCreator.isScanAllowedUsingPermissionsFromDevopsPlatform()).isFalse();
+ }
+
+ private void bindSessionToCollaborator(GsonRepositoryCollaborator collaborator1) {
+ UserSession.ExternalIdentity externalIdentity = new UserSession.ExternalIdentity(String.valueOf(collaborator1.id()), collaborator1.name());
+ when(userSession.getExternalIdentity()).thenReturn(Optional.of(externalIdentity));
+ }
+
+ private GsonRepositoryCollaborator mockCollaborator(String collaboratorLogin, int id, String role1, String... sqPermissions) {
+ GsonRepositoryCollaborator collaborator = new GsonRepositoryCollaborator(collaboratorLogin, id, role1,
+ new GsonRepositoryPermissions(false, false, false, false, false));
+ mockPermissionsConversion(collaborator, sqPermissions);
+ return collaborator;
+ }
+
+ private void mockGithubCollaboratorsFromApi(GsonRepositoryCollaborator... repositoryCollaborators) {
+ Set<GsonRepositoryCollaborator> collaborators = Arrays.stream(repositoryCollaborators).collect(toSet());
+ when(githubApplicationClient.getRepositoryCollaborators(DEVOPS_PROJECT_DESCRIPTOR.url(), appInstallationToken, ORGANIZATION_NAME, REPOSITORY_NAME)).thenReturn(collaborators);
+ }
+
+ private GsonRepositoryTeam mockGithubTeam(String name, int id, String role, String... sqPermissions) {
+ GsonRepositoryTeam gsonRepositoryTeam = new GsonRepositoryTeam(name, id, name + "slug", role, new GsonRepositoryPermissions(false, false, false, false, false));
+ mockPermissionsConversion(gsonRepositoryTeam, sqPermissions);
+ return gsonRepositoryTeam;
+ }
+
+ private void mockTeamsFromApi(GsonRepositoryTeam... repositoryTeams) {
+ when(githubApplicationClient.getRepositoryTeams(DEVOPS_PROJECT_DESCRIPTOR.url(), appInstallationToken, ORGANIZATION_NAME, REPOSITORY_NAME))
+ .thenReturn(Arrays.stream(repositoryTeams).collect(toSet()));
+ }
+
+ private void mockPermissionsConversion(GsonRepositoryCollaborator collaborator, String... sqPermissions) {
+ Set<GithubPermissionsMappingDto> githubPermissionsMappingDtos = mockPermissionsMappingsDtos();
+ when(githubPermissionConverter.toSonarqubeRolesWithFallbackOnRepositoryPermissions(githubPermissionsMappingDtos, collaborator.roleName(), collaborator.permissions()))
+ .thenReturn(Arrays.stream(sqPermissions).collect(toSet()));
+ }
+
+ private void mockPermissionsConversion(GsonRepositoryTeam team, String... sqPermissions) {
+ Set<GithubPermissionsMappingDto> githubPermissionsMappingDtos = mockPermissionsMappingsDtos();
+ when(githubPermissionConverter.toSonarqubeRolesWithFallbackOnRepositoryPermissions(githubPermissionsMappingDtos, team.permission(), team.permissions()))
+ .thenReturn(Arrays.stream(sqPermissions).collect(toSet()));
+ }
+
+ private Set<GithubPermissionsMappingDto> mockPermissionsMappingsDtos() {
+ Set<GithubPermissionsMappingDto> githubPermissionsMappingDtos = Set.of(mock(GithubPermissionsMappingDto.class));
+ when(dbClient.githubPermissionsMappingDao().findAll(any())).thenReturn(githubPermissionsMappingDtos);
+ return githubPermissionsMappingDtos;
+ }
+
+ private void bindGroupsToUser(String... groupNames) {
+ Set<GroupDto> groupDtos = Arrays.stream(groupNames)
+ .map(groupName -> new GroupDto().setName(ORGANIZATION_NAME + "/" + groupName).setUuid("uuid_" + groupName))
+ .collect(toSet());
+ when(userSession.getGroups()).thenReturn(groupDtos);
+ }
+
+ @Test
+ public void createProjectAndBindToDevOpsPlatform_whenRepoNotFound_throws() {
+ assertThatIllegalStateException().isThrownBy(
+ () -> githubProjectCreator.createProjectAndBindToDevOpsPlatform(mock(), SCANNER_API_DEVOPS_AUTO_CONFIG, null))
+ .withMessage("Impossible to find the repository 'orga2/repo1' on GitHub, using the devops config " + ALM_SETTING_KEY);
+ }
+
+ @Test
+ public void createProjectAndBindToDevOpsPlatformFromScanner_whenRepoFoundOnGitHub_successfullyCreatesProject() {
+ // given
+ mockGitHubRepository();
+
+ ComponentCreationData componentCreationData = mockProjectCreation("generated_orga2/repo1");
+ ProjectAlmSettingDao projectAlmSettingDao = mock();
+ when(dbClient.projectAlmSettingDao()).thenReturn(projectAlmSettingDao);
+
+ // when
+ ComponentCreationData actualComponentCreationData = githubProjectCreator.createProjectAndBindToDevOpsPlatform(dbClient.openSession(true),
+ SCANNER_API_DEVOPS_AUTO_CONFIG, null);
+
+ // then
+ assertThat(actualComponentCreationData).isEqualTo(componentCreationData);
+
+ ComponentCreationParameters componentCreationParameters = componentCreationParametersCaptor.getValue();
+ assertComponentCreationParametersContainsCorrectInformation(componentCreationParameters, "generated_orga2/repo1", SCANNER_API_DEVOPS_AUTO_CONFIG);
+ assertThat(componentCreationParameters.isManaged()).isFalse();
+ assertThat(componentCreationParameters.newComponent().isPrivate()).isFalse();
+
+ verify(projectAlmSettingDao).insertOrUpdate(any(), projectAlmSettingDtoCaptor.capture(), eq(ALM_SETTING_KEY), eq(REPOSITORY_NAME), eq("generated_orga2/repo1"));
+ ProjectAlmSettingDto projectAlmSettingDto = projectAlmSettingDtoCaptor.getValue();
+ assertAlmSettingsDtoContainsCorrectInformation(almSettingDto, requireNonNull(componentCreationData.projectDto()), projectAlmSettingDto);
+ }
+
+ @Test
+ public void createProjectAndBindToDevOpsPlatformFromApi_whenRepoFoundOnGitHub_successfullyCreatesProject() {
+ // given
+ String projectKey = "customProjectKey";
+ mockGitHubRepository();
+
+ ComponentCreationData componentCreationData = mockProjectCreation(projectKey);
+ ProjectAlmSettingDao projectAlmSettingDao = mock();
+ when(dbClient.projectAlmSettingDao()).thenReturn(projectAlmSettingDao);
+
+ // when
+ ComponentCreationData actualComponentCreationData = githubProjectCreator.createProjectAndBindToDevOpsPlatform(dbClient.openSession(true), ALM_IMPORT_API, projectKey);
+
+ // then
+ assertThat(actualComponentCreationData).isEqualTo(componentCreationData);
+
+ ComponentCreationParameters componentCreationParameters = componentCreationParametersCaptor.getValue();
+ assertComponentCreationParametersContainsCorrectInformation(componentCreationParameters, projectKey, ALM_IMPORT_API);
+ assertThat(componentCreationParameters.isManaged()).isFalse();
+ assertThat(componentCreationParameters.newComponent().isPrivate()).isFalse();
+
+ verify(projectAlmSettingDao).insertOrUpdate(any(), projectAlmSettingDtoCaptor.capture(), eq(ALM_SETTING_KEY), eq(REPOSITORY_NAME), eq(projectKey));
+ ProjectAlmSettingDto projectAlmSettingDto = projectAlmSettingDtoCaptor.getValue();
+ assertAlmSettingsDtoContainsCorrectInformation(almSettingDto, requireNonNull(componentCreationData.projectDto()), projectAlmSettingDto);
+ }
+
+ public void createProjectAndBindToDevOpsPlatformFromApi_whenRepoFoundOnGitHubAutoProvisioningOnAndRepoPrivate_successfullyCreatesProject() {
+ // given
+ when(githubProjectCreationParameters.projectsArePrivateByDefault()).thenReturn(true);
+ when(githubProjectCreationParameters.isProvisioningEnabled()).thenReturn(true);
+
+ String projectKey = "customProjectKey";
+ mockGitHubRepository();
+
+ ComponentCreationData componentCreationData = mockProjectCreation(projectKey);
+ ProjectAlmSettingDao projectAlmSettingDao = mock();
+ when(dbClient.projectAlmSettingDao()).thenReturn(projectAlmSettingDao);
+
+ // when
+ ComponentCreationData actualComponentCreationData = githubProjectCreator.createProjectAndBindToDevOpsPlatform(dbClient.openSession(true), ALM_IMPORT_API, projectKey);
+
+ // then
+ assertThat(actualComponentCreationData).isEqualTo(componentCreationData);
+
+ ComponentCreationParameters componentCreationParameters = componentCreationParametersCaptor.getValue();
+ assertComponentCreationParametersContainsCorrectInformation(componentCreationParameters, projectKey, ALM_IMPORT_API);
+ assertThat(componentCreationParameters.isManaged()).isTrue();
+ assertThat(componentCreationParameters.newComponent().isPrivate()).isTrue();
+
+ verify(projectAlmSettingDao).insertOrUpdate(any(), projectAlmSettingDtoCaptor.capture(), eq(ALM_SETTING_KEY), eq(REPOSITORY_NAME), eq(projectKey));
+ ProjectAlmSettingDto projectAlmSettingDto = projectAlmSettingDtoCaptor.getValue();
+ assertAlmSettingsDtoContainsCorrectInformation(almSettingDto, requireNonNull(componentCreationData.projectDto()), projectAlmSettingDto);
+ }
+
+ private void mockGitHubRepository() {
+ GithubApplicationClient.Repository repository = mock();
+ when(repository.getDefaultBranch()).thenReturn(MAIN_BRANCH_NAME);
+ when(repository.getName()).thenReturn(REPOSITORY_NAME);
+ when(repository.getFullName()).thenReturn(DEVOPS_PROJECT_DESCRIPTOR.projectIdentifier());
+ when(githubApplicationClient.getRepository(DEVOPS_PROJECT_DESCRIPTOR.url(), appInstallationToken, DEVOPS_PROJECT_DESCRIPTOR.projectIdentifier())).thenReturn(
+ Optional.of(repository));
+ when(projectKeyGenerator.generateUniqueProjectKey(repository.getFullName())).thenReturn("generated_" + DEVOPS_PROJECT_DESCRIPTOR.projectIdentifier());
+ }
+
+ private ComponentCreationData mockProjectCreation(String projectKey) {
+ ComponentCreationData componentCreationData = mock();
+ ProjectDto projectDto = mockProjectDto(projectKey);
+ when(componentCreationData.projectDto()).thenReturn(projectDto);
+ when(componentUpdater.createWithoutCommit(any(), componentCreationParametersCaptor.capture())).thenReturn(componentCreationData);
+ return componentCreationData;
+ }
+
+ private static ProjectDto mockProjectDto(String projectKey) {
+ ProjectDto projectDto = mock();
+ when(projectDto.getName()).thenReturn(REPOSITORY_NAME);
+ when(projectDto.getKey()).thenReturn(projectKey);
+ when(projectDto.getUuid()).thenReturn("project-uuid-1");
+ return projectDto;
+ }
+
+ private static void assertComponentCreationParametersContainsCorrectInformation(ComponentCreationParameters componentCreationParameters, String expectedKey,
+ CreationMethod expectedCreationMethod) {
+ assertThat(componentCreationParameters.creationMethod()).isEqualTo(expectedCreationMethod);
+ assertThat(componentCreationParameters.mainBranchName()).isEqualTo(MAIN_BRANCH_NAME);
+ assertThat(componentCreationParameters.userLogin()).isEqualTo(USER_LOGIN);
+ assertThat(componentCreationParameters.userUuid()).isEqualTo(USER_UUID);
+
+ NewComponent newComponent = componentCreationParameters.newComponent();
+ assertThat(newComponent.isProject()).isTrue();
+ assertThat(newComponent.qualifier()).isEqualTo(Qualifiers.PROJECT);
+ assertThat(newComponent.key()).isEqualTo(expectedKey);
+ assertThat(newComponent.name()).isEqualTo(REPOSITORY_NAME);
+ }
+
+ private static void assertAlmSettingsDtoContainsCorrectInformation(AlmSettingDto almSettingDto, ProjectDto projectDto, ProjectAlmSettingDto projectAlmSettingDto) {
+ assertThat(projectAlmSettingDto.getAlmRepo()).isEqualTo(DEVOPS_PROJECT_DESCRIPTOR.projectIdentifier());
+ assertThat(projectAlmSettingDto.getAlmSlug()).isNull();
+ assertThat(projectAlmSettingDto.getAlmSettingUuid()).isEqualTo(almSettingDto.getUuid());
+ assertThat(projectAlmSettingDto.getProjectUuid()).isEqualTo(projectDto.getUuid());
+ assertThat(projectAlmSettingDto.getMonorepo()).isFalse();
+ assertThat(projectAlmSettingDto.getSummaryCommentEnabled()).isTrue();
+ }
+}
import org.sonar.server.almintegration.ws.github.GithubProvisioningWs;
import org.sonar.server.almsettings.MultipleAlmFeature;
import org.sonar.server.almsettings.ws.AlmSettingsWsModule;
-import org.sonar.server.almsettings.ws.DelegatingDevOpsPlatformService;
-import org.sonar.server.almsettings.ws.GitHubDevOpsPlatformService;
+import org.sonar.server.almsettings.ws.DelegatingDevOpsProjectCreatorFactory;
+import org.sonar.server.almsettings.ws.GithubProjectCreatorFactory;
import org.sonar.server.authentication.AuthenticationModule;
import org.sonar.server.authentication.DefaultAdminCredentialsVerifierImpl;
import org.sonar.server.authentication.DefaultAdminCredentialsVerifierNotificationHandler;
DefaultBranchNameResolver.class,
DefaultDocumentationLinkGenerator.class,
DelegatingManagedServices.class,
- DelegatingDevOpsPlatformService.class,
+ DelegatingDevOpsProjectCreatorFactory.class,
// batch
new BatchWsModule(),
GithubApplicationHttpClientImpl.class,
GithubProvisioningConfigValidator.class,
GithubProvisioningWs.class,
- GitHubDevOpsPlatformService.class,
+ GithubProjectCreatorFactory.class,
GithubPermissionConverter.class,
BitbucketCloudRestClientConfiguration.class,
BitbucketServerRestClient.class,