From 245d39733aecf8d69914c3e725e34fa5607776d5 Mon Sep 17 00:00:00 2001 From: Zipeng WU Date: Tue, 2 Feb 2021 11:31:16 +0100 Subject: [PATCH] SONAR-14372 move alm GetBinding endpoint to CE --- .../almsettings/ws/AlmSettingsWsModule.java | 1 + .../almsettings/ws/GetBindingAction.java | 100 +++++++++ .../ws/AlmSettingsWsModuleTest.java | 2 +- .../almsettings/ws/GetBindingActionTest.java | 196 ++++++++++++++++++ .../almsettings/ws/get_binding-example.json | 6 + 5 files changed, 304 insertions(+), 1 deletion(-) create mode 100644 server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/GetBindingAction.java create mode 100644 server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/GetBindingActionTest.java create mode 100644 server/sonar-webserver-webapi/src/test/resources/org/sonar/server/almsettings/ws/get_binding-example.json diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/AlmSettingsWsModule.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/AlmSettingsWsModule.java index e1ed3e3fa24..dc5335abd80 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/AlmSettingsWsModule.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/AlmSettingsWsModule.java @@ -31,6 +31,7 @@ public class AlmSettingsWsModule extends Module { ListAction.class, ListDefinitionsAction.class, ValidateAction.class, + GetBindingAction.class, //Azure alm settings, CreateAzureAction.class, UpdateAzureAction.class, diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/GetBindingAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/GetBindingAction.java new file mode 100644 index 00000000000..a6a9ba16e85 --- /dev/null +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/GetBindingAction.java @@ -0,0 +1,100 @@ +/* + * SonarQube + * Copyright (C) 2009-2021 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.api.server.ws.Change; +import org.sonar.api.server.ws.Request; +import org.sonar.api.server.ws.Response; +import org.sonar.api.server.ws.WebService; +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.ProjectDto; +import org.sonar.server.component.ComponentFinder; +import org.sonar.server.exceptions.NotFoundException; +import org.sonar.server.user.UserSession; +import org.sonarqube.ws.AlmSettings.GetBindingWsResponse; + +import static java.lang.String.format; +import static java.util.Optional.ofNullable; +import static org.sonar.api.web.UserRole.ADMIN; +import static org.sonar.server.almsettings.ws.AlmSettingsSupport.toAlmWs; +import static org.sonar.server.ws.WsUtils.writeProtobuf; + +public class GetBindingAction implements AlmSettingsWsAction { + + private static final String PARAM_PROJECT = "project"; + + private final DbClient dbClient; + private final UserSession userSession; + private final ComponentFinder componentFinder; + + public GetBindingAction(DbClient dbClient, UserSession userSession, ComponentFinder componentFinder) { + this.dbClient = dbClient; + this.userSession = userSession; + this.componentFinder = componentFinder; + } + + @Override + public void define(WebService.NewController context) { + WebService.NewAction action = context.createAction("get_binding") + .setDescription("Get ALM binding of a given project.
" + + "Requires the 'Administer' permission on the project") + .setSince("8.1") + .setResponseExample(getClass().getResource("get_binding-example.json")) + .setChangelog(new Change("8.6", "Azure binding now contains the project and repository names")) + .setChangelog(new Change("8.7", "Azure binding now contains a monorepo flag for monorepo feature in Enterprise Edition and above")) + .setHandler(this); + + action + .createParam(PARAM_PROJECT) + .setDescription("Project key") + .setRequired(true); + } + + @Override + public void handle(Request request, Response response) { + GetBindingWsResponse wsResponse = doHandle(request); + writeProtobuf(wsResponse, request, response); + } + + private GetBindingWsResponse doHandle(Request request) { + String projectKey = request.mandatoryParam(PARAM_PROJECT); + try (DbSession dbSession = dbClient.openSession(false)) { + ProjectDto project = componentFinder.getProjectByKey(dbSession, projectKey); + userSession.checkProjectPermission(ADMIN, project); + ProjectAlmSettingDto projectAlmSetting = dbClient.projectAlmSettingDao().selectByProject(dbSession, project) + .orElseThrow(() -> new NotFoundException(format("Project '%s' is not bound to any ALM", project.getKey()))); + AlmSettingDto almSetting = dbClient.almSettingDao().selectByUuid(dbSession, projectAlmSetting.getAlmSettingUuid()) + .orElseThrow(() -> new IllegalStateException(format("ALM setting with uuid '%s' cannot be found", projectAlmSetting.getAlmSettingUuid()))); + + GetBindingWsResponse.Builder builder = GetBindingWsResponse.newBuilder() + .setAlm(toAlmWs(almSetting.getAlm())) + .setKey(almSetting.getKey()); + ofNullable(projectAlmSetting.getAlmRepo()).ifPresent(builder::setRepository); + ofNullable(almSetting.getUrl()).ifPresent(builder::setUrl); + ofNullable(projectAlmSetting.getAlmSlug()).ifPresent(builder::setSlug); + ofNullable(projectAlmSetting.getSummaryCommentEnabled()).ifPresent(builder::setSummaryCommentEnabled); + ofNullable(projectAlmSetting.getMonorepo()).ifPresent(builder::setMonorepo); + return builder.build(); + } + } +} diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/AlmSettingsWsModuleTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/AlmSettingsWsModuleTest.java index bf28d5d8722..d1b9d32d877 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/AlmSettingsWsModuleTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/AlmSettingsWsModuleTest.java @@ -31,7 +31,7 @@ public class AlmSettingsWsModuleTest { public void verify_count_of_added_components() { ComponentContainer container = new ComponentContainer(); new AlmSettingsWsModule().configure(container); - assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 14); + assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 15); } } \ No newline at end of file diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/GetBindingActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/GetBindingActionTest.java new file mode 100644 index 00000000000..14137385a35 --- /dev/null +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/GetBindingActionTest.java @@ -0,0 +1,196 @@ +/* + * SonarQube + * Copyright (C) 2009-2021 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.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.server.ws.WebService; +import org.sonar.db.DbTester; +import org.sonar.db.alm.setting.AlmSettingDto; +import org.sonar.db.alm.setting.ProjectAlmSettingDto; +import org.sonar.db.project.ProjectDto; +import org.sonar.db.user.UserDto; +import org.sonar.server.component.ComponentFinder; +import org.sonar.server.exceptions.ForbiddenException; +import org.sonar.server.exceptions.NotFoundException; +import org.sonar.server.tester.UserSessionRule; +import org.sonar.server.ws.WsActionTester; +import org.sonarqube.ws.AlmSettings; +import org.sonarqube.ws.AlmSettings.GetBindingWsResponse; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.groups.Tuple.tuple; +import static org.sonar.api.web.UserRole.ADMIN; +import static org.sonar.api.web.UserRole.USER; +import static org.sonar.test.JsonAssert.assertJson; + +public class GetBindingActionTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); + @Rule + public DbTester db = DbTester.create(); + + private WsActionTester ws = new WsActionTester(new GetBindingAction(db.getDbClient(), userSession, new ComponentFinder(db.getDbClient(), null))); + + private UserDto user; + private ProjectDto project; + + @Before + public void before() { + user = db.users().insertUser(); + project = db.components().insertPrivateProjectDto(); + } + + @Test + public void get_github_project_binding() { + userSession.logIn(user).addProjectPermission(ADMIN, project); + AlmSettingDto githubAlmSetting = db.almSettings().insertGitHubAlmSetting(); + ProjectAlmSettingDto githubProjectAlmSetting = db.almSettings().insertGitHubProjectAlmSetting(githubAlmSetting, project); + + GetBindingWsResponse response = ws.newRequest() + .setParam("project", project.getKey()) + .executeProtobuf(GetBindingWsResponse.class); + + assertThat(response.getAlm()).isEqualTo(AlmSettings.Alm.github); + assertThat(response.getKey()).isEqualTo(githubAlmSetting.getKey()); + assertThat(response.getRepository()).isEqualTo(githubProjectAlmSetting.getAlmRepo()); + assertThat(response.getUrl()).isEqualTo(githubAlmSetting.getUrl()); + assertThat(response.getSummaryCommentEnabled()).isTrue(); + } + + @Test + public void get_azure_project_binding() { + userSession.logIn(user).addProjectPermission(ADMIN, project); + AlmSettingDto almSetting = db.almSettings().insertAzureAlmSetting(); + ProjectAlmSettingDto projectAlmSettingDto = db.almSettings().insertAzureMonoRepoProjectAlmSetting(almSetting, project); + + GetBindingWsResponse response = ws.newRequest() + .setParam("project", project.getKey()) + .executeProtobuf(GetBindingWsResponse.class); + + assertThat(response.getAlm()).isEqualTo(AlmSettings.Alm.azure); + assertThat(response.getKey()).isEqualTo(almSetting.getKey()); + assertThat(response.getUrl()).isEqualTo(almSetting.getUrl()); + assertThat(response.getRepository()).isEqualTo(projectAlmSettingDto.getAlmRepo()); + assertThat(response.getSlug()).isEqualTo(projectAlmSettingDto.getAlmSlug()); + assertThat(response.hasSummaryCommentEnabled()).isFalse(); + assertThat(response.getMonorepo()).isTrue(); + } + + @Test + public void get_gitlab_project_binding() { + UserDto user = db.users().insertUser(); + ProjectDto project = db.components().insertPrivateProjectDto(); + userSession.logIn(user).addProjectPermission(ADMIN, project); + AlmSettingDto almSetting = db.almSettings().insertGitlabAlmSetting(); + db.almSettings().insertGitlabProjectAlmSetting(almSetting, project); + + GetBindingWsResponse response = ws.newRequest() + .setParam("project", project.getKey()) + .executeProtobuf(GetBindingWsResponse.class); + + assertThat(response.getAlm()).isEqualTo(AlmSettings.Alm.gitlab); + assertThat(response.getKey()).isEqualTo(almSetting.getKey()); + assertThat(response.hasRepository()).isFalse(); + assertThat(response.getUrl()).isEqualTo(almSetting.getUrl()); + assertThat(response.hasUrl()).isTrue(); + assertThat(response.hasSummaryCommentEnabled()).isFalse(); + } + + @Test + public void get_bitbucket_project_binding() { + userSession.logIn(user).addProjectPermission(ADMIN, project); + AlmSettingDto almSetting = db.almSettings().insertBitbucketAlmSetting(); + ProjectAlmSettingDto projectAlmSettingDto = db.almSettings().insertBitbucketProjectAlmSetting(almSetting, project); + + GetBindingWsResponse response = ws.newRequest() + .setParam("project", project.getKey()) + .executeProtobuf(GetBindingWsResponse.class); + + assertThat(response.getAlm()).isEqualTo(AlmSettings.Alm.bitbucket); + assertThat(response.getKey()).isEqualTo(almSetting.getKey()); + assertThat(response.getRepository()).isEqualTo(projectAlmSettingDto.getAlmRepo()); + assertThat(response.getUrl()).isEqualTo(almSetting.getUrl()); + assertThat(response.getSlug()).isEqualTo(projectAlmSettingDto.getAlmSlug()); + assertThat(response.hasSummaryCommentEnabled()).isFalse(); + } + + @Test + public void fail_when_project_does_not_exist() { + userSession.logIn(user).addProjectPermission(ADMIN, project); + AlmSettingDto githubAlmSetting = db.almSettings().insertGitHubAlmSetting(); + db.almSettings().insertGitHubProjectAlmSetting(githubAlmSetting, project); + + expectedException.expect(NotFoundException.class); + + ws.newRequest() + .setParam("project", "unknown") + .execute(); + } + + @Test + public void fail_when_missing_administer_permission_on_project() { + userSession.logIn(user).addProjectPermission(USER, project); + AlmSettingDto githubAlmSetting = db.almSettings().insertGitHubAlmSetting(); + db.almSettings().insertGitHubProjectAlmSetting(githubAlmSetting, project); + + expectedException.expect(ForbiddenException.class); + + ws.newRequest() + .setParam("project", project.getKey()) + .execute(); + } + + @Test + public void json_example() { + userSession.logIn(user).addProjectPermission(ADMIN, project); + AlmSettingDto githubAlmSetting = db.almSettings().insertGitHubAlmSetting( + almSettingDto -> almSettingDto + .setKey("GitHub Server - Dev Team") + .setUrl("https://github.enterprise.com") + .setAppId("12345") + .setPrivateKey("54684654")); + db.almSettings().insertGitHubProjectAlmSetting(githubAlmSetting, project, projectAlmSetting -> projectAlmSetting.setAlmRepo("team/project")); + + String response = ws.newRequest() + .setParam("project", project.getKey()) + .execute().getInput(); + + assertJson(response).isSimilarTo(getClass().getResource("get_binding-example.json")); + } + + @Test + public void definition() { + WebService.Action def = ws.getDef(); + + assertThat(def.since()).isEqualTo("8.1"); + assertThat(def.isPost()).isFalse(); + assertThat(def.responseExampleAsString()).isNotEmpty(); + assertThat(def.params()) + .extracting(WebService.Param::key, WebService.Param::isRequired) + .containsExactlyInAnyOrder(tuple("project", true)); + } + +} diff --git a/server/sonar-webserver-webapi/src/test/resources/org/sonar/server/almsettings/ws/get_binding-example.json b/server/sonar-webserver-webapi/src/test/resources/org/sonar/server/almsettings/ws/get_binding-example.json new file mode 100644 index 00000000000..146dff339bb --- /dev/null +++ b/server/sonar-webserver-webapi/src/test/resources/org/sonar/server/almsettings/ws/get_binding-example.json @@ -0,0 +1,6 @@ +{ + "key": "GitHub Server - Dev Team", + "alm": "github", + "repository": "team/project", + "url": "https://github.enterprise.com" +} -- 2.39.5