From: Antoine Vigneau Date: Tue, 10 Oct 2023 09:10:59 +0000 (+0200) Subject: SONAR-20699 Infer GitHub DevOps Platform from scanner information X-Git-Tag: 10.3.0.82913~134 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=da75e87d29efe342fa2761def532f0ea94f71cd1;p=sonarqube.git SONAR-20699 Infer GitHub DevOps Platform from scanner information --- diff --git a/server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/GithubApplicationClient.java b/server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/GithubApplicationClient.java index 11848ba0f4a..7ecfb54acec 100644 --- a/server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/GithubApplicationClient.java +++ b/server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/GithubApplicationClient.java @@ -46,6 +46,12 @@ public interface GithubApplicationClient { GithubBinding.GsonApp getApp(GithubAppConfiguration githubAppConfiguration); + /** + * Retrieve the installation id for the given accountName. + * @throws IllegalArgumentException if one of the arguments is invalid (for example, wrong private key) + */ + Optional getInstallationId(GithubAppConfiguration githubAppConfiguration, String repositorySlug); + /** * Lists all the organizations accessible to the access token provided. */ diff --git a/server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/GithubApplicationClientImpl.java b/server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/GithubApplicationClientImpl.java index ceb5a2f93ab..6b242deba7b 100644 --- a/server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/GithubApplicationClientImpl.java +++ b/server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/GithubApplicationClientImpl.java @@ -145,6 +145,14 @@ public class GithubApplicationClientImpl implements GithubApplicationClient { } } + @Override + public Optional getInstallationId(GithubAppConfiguration githubAppConfiguration, String repositorySlug) { + AppToken appToken = appSecurity.createAppToken(githubAppConfiguration.getId(), githubAppConfiguration.getPrivateKey()); + String endpoint = String.format("/repos/%s/installation", repositorySlug); + return get(githubAppConfiguration.getApiEndpoint(), appToken, endpoint, GithubBinding.GsonInstallation.class) + .map(GithubBinding.GsonInstallation::getId); + } + @Override public Organizations listOrganizations(String appUrl, AccessToken accessToken, int page, int pageSize) { checkPageArgs(page, pageSize); diff --git a/server/sonar-alm-client/src/test/java/org/sonar/alm/client/github/GithubApplicationClientImplTest.java b/server/sonar-alm-client/src/test/java/org/sonar/alm/client/github/GithubApplicationClientImplTest.java index c516cfafb35..855f8f66e7c 100644 --- a/server/sonar-alm-client/src/test/java/org/sonar/alm/client/github/GithubApplicationClientImplTest.java +++ b/server/sonar-alm-client/src/test/java/org/sonar/alm/client/github/GithubApplicationClientImplTest.java @@ -235,6 +235,39 @@ public class GithubApplicationClientImplTest { assertThatCode(() -> underTest.checkAppPermissions(githubAppConfiguration)).isNull(); } + @Test + public void getInstallationId_returns_installation_id_of_given_account() throws IOException { + AppToken appToken = new AppToken(APP_JWT_TOKEN); + when(appSecurity.createAppToken(githubAppConfiguration.getId(), githubAppConfiguration.getPrivateKey())).thenReturn(appToken); + when(httpClient.get(appUrl, appToken, "/repos/torvalds/linux/installation")) + .thenReturn(new OkGetResponse("{" + + " \"id\": 2," + + " \"account\": {" + + " \"login\": \"torvalds\"" + + " }" + + "}")); + + assertThat(underTest.getInstallationId(githubAppConfiguration, "torvalds/linux")).hasValue(2L); + } + + @Test + public void getInstallationId_throws_IAE_if_fail_to_create_app_token() { + when(appSecurity.createAppToken(githubAppConfiguration.getId(), githubAppConfiguration.getPrivateKey())).thenThrow(IllegalArgumentException.class); + + assertThatThrownBy(() -> underTest.getInstallationId(githubAppConfiguration, "torvalds")) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + public void getInstallationId_return_empty_if_no_installation_found_for_githubAccount() throws IOException { + AppToken appToken = new AppToken(APP_JWT_TOKEN); + when(appSecurity.createAppToken(githubAppConfiguration.getId(), githubAppConfiguration.getPrivateKey())).thenReturn(appToken); + when(httpClient.get(appUrl, appToken, "/repos/torvalds/linux/installation")) + .thenReturn(new ErrorGetResponse(404, null)); + + assertThat(underTest.getInstallationId(githubAppConfiguration, "torvalds")).isEmpty(); + } + @Test @UseDataProvider("githubServers") public void createUserAccessToken_returns_empty_if_access_token_cant_be_created(String apiUrl, String appUrl) throws IOException { diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/DelegatingDevOpsPlatformService.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/DelegatingDevOpsPlatformService.java new file mode 100644 index 00000000000..514b583e734 --- /dev/null +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/DelegatingDevOpsPlatformService.java @@ -0,0 +1,66 @@ +/* + * 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.api.server.ServerSide; +import org.sonar.db.DbSession; +import org.sonar.db.alm.setting.ALM; +import org.sonar.db.alm.setting.AlmSettingDto; + +@ServerSide +@Priority(1) +public class DelegatingDevOpsPlatformService implements DevOpsPlatformService { + + private final Set delegates; + + public DelegatingDevOpsPlatformService(Set delegates) { + this.delegates = delegates; + } + + @Override + public ALM getDevOpsPlatform() { + throw new NotImplementedException(); + } + + @Override + public Optional getDevOpsProjectDescriptor(Map characteristics) { + return delegates.stream() + .flatMap(delegate -> delegate.getDevOpsProjectDescriptor(characteristics).stream()) + .findFirst(); + } + + @Override + public Optional getValidAlmSettingDto(DbSession dbSession, DevOpsProjectDescriptor devOpsProjectDescriptor) { + return findDelegate(devOpsProjectDescriptor.alm()) + .flatMap(delegate -> delegate.getValidAlmSettingDto(dbSession, devOpsProjectDescriptor)); + } + + private Optional findDelegate(ALM alm) { + return delegates.stream() + .filter(delegate -> delegate.getDevOpsPlatform().equals(alm)) + .findFirst(); + } + +} diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/DevOpsPlatformService.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/DevOpsPlatformService.java new file mode 100644 index 00000000000..e685e1bf9d3 --- /dev/null +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/DevOpsPlatformService.java @@ -0,0 +1,36 @@ +/* + * 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; +import org.sonar.db.alm.setting.ALM; +import org.sonar.db.alm.setting.AlmSettingDto; + +public interface DevOpsPlatformService { + + ALM getDevOpsPlatform(); + + Optional getDevOpsProjectDescriptor(Map characteristics); + + Optional getValidAlmSettingDto(DbSession dbSession, DevOpsProjectDescriptor devOpsProjectDescriptor); + +} diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/DevOpsProjectDescriptor.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/DevOpsProjectDescriptor.java new file mode 100644 index 00000000000..23db5627433 --- /dev/null +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/DevOpsProjectDescriptor.java @@ -0,0 +1,25 @@ +/* + * 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.db.alm.setting.ALM; + +public record DevOpsProjectDescriptor(ALM alm, String url, String projectIdentifier) { +} diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/GitHubDevOpsPlatformService.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/GitHubDevOpsPlatformService.java new file mode 100644 index 00000000000..2afec24eea7 --- /dev/null +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/GitHubDevOpsPlatformService.java @@ -0,0 +1,78 @@ +/* + * 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.GithubApplicationClient; +import org.sonar.alm.client.github.GithubGlobalSettingsValidator; +import org.sonar.alm.client.github.config.GithubAppConfiguration; +import org.sonar.api.server.ServerSide; +import org.sonar.db.DbSession; +import org.sonar.db.alm.setting.ALM; +import org.sonar.db.alm.setting.AlmSettingDao; +import org.sonar.db.alm.setting.AlmSettingDto; + +@ServerSide +public class GitHubDevOpsPlatformService implements DevOpsPlatformService { + + public static final String DEVOPS_PLATFORM_URL = "devOpsPlatformUrl"; + public static final String DEVOPS_PLATFORM_PROJECT_IDENTIFIER = "devOpsPlatformProjectIdentifier"; + + private final AlmSettingDao almSettingDao; + private final GithubGlobalSettingsValidator githubGlobalSettingsValidator; + private final GithubApplicationClient githubApplicationClient; + + public GitHubDevOpsPlatformService(AlmSettingDao almSettingDao, GithubGlobalSettingsValidator githubGlobalSettingsValidator, + GithubApplicationClient githubApplicationClient) { + this.almSettingDao = almSettingDao; + this.githubGlobalSettingsValidator = githubGlobalSettingsValidator; + this.githubApplicationClient = githubApplicationClient; + } + + @Override + public ALM getDevOpsPlatform() { + return ALM.GITHUB; + } + + @Override + public Optional getDevOpsProjectDescriptor(Map 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 getValidAlmSettingDto(DbSession dbSession, DevOpsProjectDescriptor devOpsProjectDescriptor) { + return almSettingDao.selectByAlm(dbSession, getDevOpsPlatform()).stream() + .filter(almSettingDto -> devOpsProjectDescriptor.url().equals(almSettingDto.getUrl())) + .filter(almSettingDto -> hasAccessToRepo(almSettingDto, devOpsProjectDescriptor.projectIdentifier())) + .findFirst(); + } + + private boolean hasAccessToRepo(AlmSettingDto almSettingDto, String repo) { + GithubAppConfiguration githubAppConfiguration = githubGlobalSettingsValidator.validate(almSettingDto); + return githubApplicationClient.getInstallationId(githubAppConfiguration, repo).isPresent(); + } + +} diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/DelegatingDevOpsPlatformServiceTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/DelegatingDevOpsPlatformServiceTest.java new file mode 100644 index 00000000000..0a7e7460cf3 --- /dev/null +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/DelegatingDevOpsPlatformServiceTest.java @@ -0,0 +1,109 @@ +/* + * 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.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 = NO_DEVOPS_PLATFORMS.getDevOpsProjectDescriptor(Map.of()); + + assertThat(devOpsProjectDescriptor).isEmpty(); + } + + @Test + public void getDevOpsProjectDescriptor_whenDelegates_shouldReturnDelegateResponse() { + Optional 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 = NO_DEVOPS_PLATFORMS.getValidAlmSettingDto(dbSession, mock(DevOpsProjectDescriptor.class)); + + assertThat(almSettingDto).isEmpty(); + } + + @Test + public void getValidAlmSettingDto_whenDelegates_shouldReturnDelegateResponse() { + Optional almSettingDto = MULTIPLE_DEVOPS_PLATFORMS.getValidAlmSettingDto(dbSession, new DevOpsProjectDescriptor(ALM.GITHUB, "githubUrl", "githubRepo")); + + assertThat(almSettingDto) + .isPresent() + .get() + .usingRecursiveComparison().isEqualTo(new AlmSettingDto().setAlm(ALM.GITHUB)); + } + + 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))); + 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; + } + +} diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/GitHubDevOpsPlatformServiceTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/GitHubDevOpsPlatformServiceTest.java new file mode 100644 index 00000000000..2cf2a07f83f --- /dev/null +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/GitHubDevOpsPlatformServiceTest.java @@ -0,0 +1,120 @@ +/* + * 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.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +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.db.DbSession; +import org.sonar.db.alm.setting.ALM; +import org.sonar.db.alm.setting.AlmSettingDao; +import org.sonar.db.alm.setting.AlmSettingDto; + +import static java.util.Collections.emptyList; +import static org.assertj.core.api.Assertions.assertThat; +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.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 { + + private static final DevOpsProjectDescriptor GITHUB_PROJECT_DESCRIPTOR = new DevOpsProjectDescriptor(ALM.GITHUB, "url", "repo"); + + @Mock + private DbSession dbSession; + @Mock + private AlmSettingDao almSettingDao; + @Mock + private GithubGlobalSettingsValidator githubGlobalSettingsValidator; + @Mock + private GithubApplicationClient githubApplicationClient; + @InjectMocks + private GitHubDevOpsPlatformService gitHubDevOpsPlatformService; + + @Test + public void getDevOpsPlatform_shouldReturnGitHub() { + assertThat(gitHubDevOpsPlatformService.getDevOpsPlatform()) + .isEqualTo(ALM.GITHUB); + } + + @Test + public void getDevOpsProjectDescriptor_whenNoCharacteristics_shouldReturnEmpty() { + Optional devOpsProjectDescriptor = gitHubDevOpsPlatformService.getDevOpsProjectDescriptor(Map.of()); + + assertThat(devOpsProjectDescriptor).isEmpty(); + } + + @Test + public void getDevOpsProjectDescriptor_whenValidCharacteristics_shouldReturn() { + Optional 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() { + when(almSettingDao.selectByAlm(dbSession, ALM.GITHUB)).thenReturn(emptyList()); + + Optional 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(almSettingDao.selectByAlm(dbSession, ALM.GITHUB)).thenReturn(List.of(mockGitHubAlmSettingDtoNoAccess, mockGitHubAlmSettingDtoAccess)); + + Optional 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; + } + +} diff --git a/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java b/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java index 7345e963bf0..097e0d363d5 100644 --- a/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java +++ b/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java @@ -62,6 +62,8 @@ import org.sonar.server.almintegration.ws.ProjectKeyGenerator; 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.authentication.AuthenticationModule; import org.sonar.server.authentication.DefaultAdminCredentialsVerifierImpl; import org.sonar.server.authentication.DefaultAdminCredentialsVerifierNotificationHandler; @@ -307,6 +309,7 @@ public class PlatformLevel4 extends PlatformLevel { DefaultBranchNameResolver.class, DefaultDocumentationLinkGenerator.class, DelegatingManagedServices.class, + DelegatingDevOpsPlatformService.class, // batch new BatchWsModule(), @@ -548,6 +551,7 @@ public class PlatformLevel4 extends PlatformLevel { GithubApplicationHttpClientImpl.class, GithubProvisioningConfigValidator.class, GithubProvisioningWs.class, + GitHubDevOpsPlatformService.class, BitbucketCloudRestClientConfiguration.class, BitbucketServerRestClient.class, GitlabHttpClient.class,