diff options
author | Julien Lancelot <julien.lancelot@sonarsource.com> | 2019-10-10 16:37:30 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2019-11-06 10:04:26 +0100 |
commit | ab573e2a2597785da80ac461a1c0a3722e5dfdbc (patch) | |
tree | a7833b89a2a7148fe75104faf015df2605867831 | |
parent | 87faff43bcc6dcd1f2ddc6b51ba8eaf7e65ed034 (diff) | |
download | sonarqube-ab573e2a2597785da80ac461a1c0a3722e5dfdbc.tar.gz sonarqube-ab573e2a2597785da80ac461a1c0a3722e5dfdbc.zip |
SONAR-12512 Allow project binding on multiple GitHub instances
48 files changed, 2292 insertions, 42 deletions
diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java index c44ad41287f..84e259e03e8 100644 --- a/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java +++ b/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java @@ -128,7 +128,7 @@ public class ComputeEngineContainerImplTest { assertThat(picoContainer.getParent().getParent().getParent().getComponentAdapters()).hasSize( COMPONENTS_IN_LEVEL_1_AT_CONSTRUCTION + 27 // level 1 - + 64 // content of DaoModule + + 65 // content of DaoModule + 3 // content of EsModule + 51 // content of CorePropertyDefinitions + 1 // StopFlagContainer diff --git a/server/sonar-db-core/src/main/java/org/sonar/db/version/SqTables.java b/server/sonar-db-core/src/main/java/org/sonar/db/version/SqTables.java index a2b67326dd3..c9f7b490886 100644 --- a/server/sonar-db-core/src/main/java/org/sonar/db/version/SqTables.java +++ b/server/sonar-db-core/src/main/java/org/sonar/db/version/SqTables.java @@ -92,6 +92,7 @@ public final class SqTables { "plugins", "projects", "project_alm_bindings", + "project_alm_settings", "project_branches", "project_links", "project_mappings", diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java b/server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java index add145bf020..450b261ac11 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java @@ -24,9 +24,10 @@ import java.util.Collections; import java.util.List; import org.sonar.core.platform.Module; import org.sonar.db.alm.AlmAppInstallDao; -import org.sonar.db.alm.setting.AlmSettingDao; import org.sonar.db.alm.OrganizationAlmBindingDao; import org.sonar.db.alm.ProjectAlmBindingDao; +import org.sonar.db.alm.setting.AlmSettingDao; +import org.sonar.db.alm.setting.ProjectAlmSettingDao; import org.sonar.db.ce.CeActivityDao; import org.sonar.db.ce.CeQueueDao; import org.sonar.db.ce.CeScannerContextDao; @@ -117,6 +118,7 @@ public class DaoModule extends Module { GroupPermissionDao.class, AlmAppInstallDao.class, AlmSettingDao.class, + ProjectAlmSettingDao.class, ProjectAlmBindingDao.class, InternalComponentPropertiesDao.class, InternalPropertiesDao.class, diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java b/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java index fea23b1b590..6e0d3d800d9 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java @@ -25,6 +25,7 @@ import org.sonar.db.alm.AlmAppInstallDao; import org.sonar.db.alm.OrganizationAlmBindingDao; import org.sonar.db.alm.ProjectAlmBindingDao; import org.sonar.db.alm.setting.AlmSettingDao; +import org.sonar.db.alm.setting.ProjectAlmSettingDao; import org.sonar.db.ce.CeActivityDao; import org.sonar.db.ce.CeQueueDao; import org.sonar.db.ce.CeScannerContextDao; @@ -101,6 +102,7 @@ public class DbClient { private final PropertiesDao propertiesDao; private final AlmAppInstallDao almAppInstallDao; private final AlmSettingDao almSettingDao; + private final ProjectAlmSettingDao projectAlmSettingDao; private final ProjectAlmBindingDao projectAlmBindingDao; private final InternalComponentPropertiesDao internalComponentPropertiesDao; private final InternalPropertiesDao internalPropertiesDao; @@ -168,6 +170,7 @@ public class DbClient { } almAppInstallDao = getDao(map, AlmAppInstallDao.class); almSettingDao = getDao(map, AlmSettingDao.class); + projectAlmSettingDao = getDao(map, ProjectAlmSettingDao.class); projectAlmBindingDao = getDao(map, ProjectAlmBindingDao.class); schemaMigrationDao = getDao(map, SchemaMigrationDao.class); authorizationDao = getDao(map, AuthorizationDao.class); @@ -248,6 +251,10 @@ public class DbClient { return almSettingDao; } + public ProjectAlmSettingDao projectAlmSettingDao() { + return projectAlmSettingDao; + } + public ProjectAlmBindingDao projectAlmBindingsDao() { return projectAlmBindingDao; } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java b/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java index 09cce2fab5a..a52af3d913e 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java @@ -39,6 +39,7 @@ import org.sonar.db.alm.OrganizationAlmBindingMapper; import org.sonar.db.alm.ProjectAlmBindingDto; import org.sonar.db.alm.ProjectAlmBindingMapper; import org.sonar.db.alm.setting.AlmSettingMapper; +import org.sonar.db.alm.setting.ProjectAlmSettingMapper; import org.sonar.db.ce.CeActivityMapper; import org.sonar.db.ce.CeQueueMapper; import org.sonar.db.ce.CeScannerContextMapper; @@ -264,6 +265,7 @@ public class MyBatis implements Startable { PermissionTemplateMapper.class, PluginMapper.class, ProjectAlmBindingMapper.class, + ProjectAlmSettingMapper.class, ProjectLinkMapper.class, ProjectMappingsMapper.class, ProjectQgateAssociationMapper.class, diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/alm/setting/AlmSettingDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/setting/AlmSettingDto.java index 82f5db0b6d2..1ac94d3500f 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/alm/setting/AlmSettingDto.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/setting/AlmSettingDto.java @@ -24,17 +24,55 @@ import javax.annotation.Nullable; public class AlmSettingDto { + /** + * Not empty. Max size is 40. Obviously it is unique. + */ private String uuid; + + /** + * Non-empty and unique functional key. Max size is 40. + */ private String key; + + /** + * Identifier of the ALM, like 'bitbucketcloud' or 'github', can't be null. Max size is 40. + * Note that the db column is named alm_id. + * + * @see org.sonar.db.alm.setting.ALM for the list of available values + */ private String rawAlm; + + /** + * URL of the ALM. Max size is 2000. + * This column will only be fed when alm is GitHub or Bitbucket. + * It will be null when the ALM is Azure DevOps. + */ private String url; + + /** + * Application ID of the GitHub instance. Max size is 80. + * This column will only be fed when alm is GitHub. + * It will be null when the ALM is Azure DevOps or Bitbucket. + */ private String appId; + /** + * Application private key of the GitHub instance. Max size is 2000. + * This column will only be fed when alm is GitHub. + * It will be null when the ALM is Azure DevOps or Bitbucket. + */ private String privateKey; + + /** + * Personal access token of the Azure DevOps instance. Max size is 2000. + * This column will only be fed when alm is Azure DevOps or Bitbucket. + * It will be null when the ALM is GitHub. + */ private String personalAccessToken; + private long updatedAt; private long createdAt; - String getUuid() { + public String getUuid() { return uuid; } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/alm/setting/ProjectAlmSettingDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/setting/ProjectAlmSettingDao.java new file mode 100644 index 00000000000..d809f549b36 --- /dev/null +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/setting/ProjectAlmSettingDao.java @@ -0,0 +1,72 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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.db.alm.setting; + +import java.util.Optional; +import org.sonar.api.utils.System2; +import org.sonar.core.util.UuidFactory; +import org.sonar.db.Dao; +import org.sonar.db.DbSession; +import org.sonar.db.component.ComponentDto; + +public class ProjectAlmSettingDao implements Dao { + + private final System2 system2; + private final UuidFactory uuidFactory; + + public ProjectAlmSettingDao(System2 system2, UuidFactory uuidFactory) { + this.system2 = system2; + this.uuidFactory = uuidFactory; + } + + public void insertOrUpdate(DbSession dbSession, ProjectAlmSettingDto projectAlmSettingDto) { + String uuid = uuidFactory.create(); + long now = system2.now(); + ProjectAlmSettingMapper mapper = getMapper(dbSession); + + if (mapper.update(projectAlmSettingDto, now) == 0) { + mapper.insert(projectAlmSettingDto, uuid, now); + projectAlmSettingDto.setUuid(uuid); + projectAlmSettingDto.setCreatedAt(now); + } + projectAlmSettingDto.setUpdatedAt(now); + } + + public void deleteByProject(DbSession dbSession, ComponentDto project) { + getMapper(dbSession).deleteByProjectUuid(project.uuid()); + } + + public void deleteByAlmSetting(DbSession dbSession, AlmSettingDto almSetting) { + getMapper(dbSession).deleteByAlmSettingUuid(almSetting.getUuid()); + } + + public int countByAlmSetting(DbSession dbSession, AlmSettingDto almSetting) { + return getMapper(dbSession).countByAlmSettingUuid(almSetting.getUuid()); + } + + public Optional<ProjectAlmSettingDto> selectByProject(DbSession dbSession, ComponentDto project) { + return Optional.ofNullable(getMapper(dbSession).selectByProjectUuid(project.uuid())); + } + + private static ProjectAlmSettingMapper getMapper(DbSession dbSession) { + return dbSession.getMapper(ProjectAlmSettingMapper.class); + } + +} diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/alm/setting/ProjectAlmSettingDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/setting/ProjectAlmSettingDto.java new file mode 100644 index 00000000000..2a84043440e --- /dev/null +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/setting/ProjectAlmSettingDto.java @@ -0,0 +1,123 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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.db.alm.setting; + +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; +import org.sonar.db.component.ComponentDto; + +public class ProjectAlmSettingDto { + + /** + * Not empty. Max size is 40. Obviously it is unique. + */ + private String uuid; + + /** + * Non-null UUID of project. Max size is 50. + * @see ComponentDto#uuid() + */ + private String projectUuid; + + /** + * Non-null UUID of the ALM Setting UUID. Max size is 40. + * @see AlmSettingDto#getUuid() + */ + private String almSettingUuid; + + /** + * Identifier of the repository in the ALM. Max size is 256. + * This column will only be fed when alm is GitHub or Bitbucket. + * It will be null when the ALM is Azure DevOps. + */ + private String almRepo; + + /** + * Slug of the repository in the ALM. Max size is 256. + * This column will only be fed when alm is Bitbucket. + * It will be null when the ALM is Azure DevOps, or GitHub. + */ + private String almSlug; + + private long updatedAt; + private long createdAt; + + String getUuid() { + return uuid; + } + + void setUuid(String uuid) { + this.uuid = uuid; + } + + public String getProjectUuid() { + return projectUuid; + } + + public ProjectAlmSettingDto setProjectUuid(String projectUuid) { + this.projectUuid = projectUuid; + return this; + } + + public String getAlmSettingUuid() { + return almSettingUuid; + } + + public ProjectAlmSettingDto setAlmSettingUuid(String almSettingUuid) { + this.almSettingUuid = almSettingUuid; + return this; + } + + @CheckForNull + public String getAlmRepo() { + return almRepo; + } + + public ProjectAlmSettingDto setAlmRepo(@Nullable String almRepo) { + this.almRepo = almRepo; + return this; + } + + @CheckForNull + public String getAlmSlug() { + return almSlug; + } + + public ProjectAlmSettingDto setAlmSlug(@Nullable String almSlug) { + this.almSlug = almSlug; + return this; + } + + long getUpdatedAt() { + return updatedAt; + } + + void setUpdatedAt(long updatedAt) { + this.updatedAt = updatedAt; + } + + long getCreatedAt() { + return createdAt; + } + + void setCreatedAt(long createdAt) { + this.createdAt = createdAt; + } +} diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/alm/setting/ProjectAlmSettingMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/setting/ProjectAlmSettingMapper.java new file mode 100644 index 00000000000..d20d48270d4 --- /dev/null +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/setting/ProjectAlmSettingMapper.java @@ -0,0 +1,39 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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.db.alm.setting; + +import javax.annotation.CheckForNull; +import org.apache.ibatis.annotations.Param; + +public interface ProjectAlmSettingMapper { + + @CheckForNull + ProjectAlmSettingDto selectByProjectUuid(@Param("projectUuid") String projectUuid); + + int countByAlmSettingUuid(@Param("almSettingUuid") String almSettingUuid); + + void insert(@Param("dto") ProjectAlmSettingDto projectAlmSettingDto, @Param("uuid") String uuid, @Param("now") long now); + + int update(@Param("dto") ProjectAlmSettingDto projectAlmSettingDto, @Param("now") long now); + + void deleteByProjectUuid(@Param("projectUuid") String projectUuid); + void deleteByAlmSettingUuid(@Param("almSettingUuid") String almSettingUuid); + +} diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/alm/setting/ProjectAlmSettingMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/alm/setting/ProjectAlmSettingMapper.xml new file mode 100644 index 00000000000..87848bac606 --- /dev/null +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/alm/setting/ProjectAlmSettingMapper.xml @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "mybatis-3-mapper.dtd"> + +<mapper namespace="org.sonar.db.alm.setting.ProjectAlmSettingMapper"> + + <sql id="sqlColumns"> + p.uuid as uuid, + p.project_uuid as projectUuid, + p.alm_setting_uuid as almSettingUuid, + p.alm_repo as almRepo, + p.alm_slug as almSlug, + p.created_at as createdAt, + p.updated_at as updatedAt + </sql> + + <select id="selectByProjectUuid" parameterType="string" resultType="org.sonar.db.alm.setting.ProjectAlmSettingDto"> + select <include refid="sqlColumns"/> + from + project_alm_settings p + where + p.project_uuid = #{projectUuid, jdbcType=VARCHAR} + </select> + + <insert id="insert" parameterType="Map" useGeneratedKeys="false"> + INSERT INTO project_alm_settings + ( + uuid, + project_uuid, + alm_setting_uuid, + alm_repo, + alm_slug, + created_at, + updated_at + ) + VALUES ( + #{uuid, jdbcType=VARCHAR}, + #{dto.projectUuid, jdbcType=VARCHAR}, + #{dto.almSettingUuid, jdbcType=VARCHAR}, + #{dto.almRepo, jdbcType=VARCHAR}, + #{dto.almSlug, jdbcType=VARCHAR}, + #{now, jdbcType=BIGINT}, + #{now, jdbcType=BIGINT} + ) + </insert> + + <update id="update" parameterType="map"> + UPDATE project_alm_settings + SET + alm_setting_uuid = #{dto.almSettingUuid, jdbcType=VARCHAR}, + alm_repo = #{dto.almRepo, jdbcType=VARCHAR}, + alm_slug = #{dto.almSlug, jdbcType=VARCHAR}, + updated_at = #{now, jdbcType=BIGINT} + WHERE + project_uuid = #{dto.projectUuid, jdbcType=VARCHAR} + </update> + + <select id="countByAlmSettingUuid" parameterType="map" resultType="int"> + SELECT + count(1) + FROM + project_alm_settings p + WHERE + alm_setting_uuid = #{almSettingUuid, jdbcType=VARCHAR} + </select> + + <delete id="deleteByAlmSettingUuid" parameterType="String"> + DELETE FROM project_alm_settings WHERE alm_setting_uuid = #{almSettingUuid, jdbcType=VARCHAR} + </delete> + + <delete id="deleteByProjectUuid" parameterType="String"> + DELETE FROM project_alm_settings WHERE project_uuid = #{projectUuid, jdbcType=VARCHAR} + </delete> + +</mapper> diff --git a/server/sonar-db-dao/src/schema/schema-sq.ddl b/server/sonar-db-dao/src/schema/schema-sq.ddl index b286019ea08..6ed58ecce37 100644 --- a/server/sonar-db-dao/src/schema/schema-sq.ddl +++ b/server/sonar-db-dao/src/schema/schema-sq.ddl @@ -568,6 +568,19 @@ ALTER TABLE PROJECT_ALM_BINDINGS ADD CONSTRAINT PK_PROJECT_ALM_BINDINGS PRIMARY CREATE UNIQUE INDEX PROJECT_ALM_BINDINGS_ALM_REPO ON PROJECT_ALM_BINDINGS(ALM_ID, REPO_ID); CREATE UNIQUE INDEX PROJECT_ALM_BINDINGS_PROJECT ON PROJECT_ALM_BINDINGS(PROJECT_UUID); +CREATE TABLE PROJECT_ALM_SETTINGS( + UUID VARCHAR(40) NOT NULL, + ALM_SETTING_UUID VARCHAR(40) NOT NULL, + PROJECT_UUID VARCHAR(50) NOT NULL, + ALM_REPO VARCHAR(256), + ALM_SLUG VARCHAR(256), + UPDATED_AT BIGINT NOT NULL, + CREATED_AT BIGINT NOT NULL +); +ALTER TABLE PROJECT_ALM_SETTINGS ADD CONSTRAINT PK_PROJECT_ALM_SETTINGS PRIMARY KEY(UUID); +CREATE UNIQUE INDEX UNIQ_PROJECT_ALM_SETTINGS ON PROJECT_ALM_SETTINGS(PROJECT_UUID); +CREATE INDEX PROJECT_ALM_SETTINGS_ALM ON PROJECT_ALM_SETTINGS(ALM_SETTING_UUID); + CREATE TABLE PROJECT_BRANCHES( UUID VARCHAR(50) NOT NULL, PROJECT_UUID VARCHAR(50) NOT NULL, diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/DaoModuleTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/DaoModuleTest.java index d805141a0f2..b6dbe6b15ed 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/DaoModuleTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/DaoModuleTest.java @@ -30,6 +30,6 @@ public class DaoModuleTest { public void verify_count_of_added_components() { ComponentContainer container = new ComponentContainer(); new DaoModule().configure(container); - assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 64); + assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 65); } } diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/alm/setting/AlmSettingDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/alm/setting/AlmSettingDaoTest.java index 14dd5311aa4..5fae5cd4eb6 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/alm/setting/AlmSettingDaoTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/alm/setting/AlmSettingDaoTest.java @@ -36,7 +36,7 @@ import static org.sonar.db.almsettings.AlmSettingsTesting.newGithubAlmSettingDto public class AlmSettingDaoTest { - public static final long NOW = 1000000L; + private static final long NOW = 1000000L; private static final String A_UUID = "SOME_UUID"; @Rule public ExpectedException expectedException = ExpectedException.none(); diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/alm/setting/ProjectAlmSettingDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/alm/setting/ProjectAlmSettingDaoTest.java new file mode 100644 index 00000000000..41f28871122 --- /dev/null +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/alm/setting/ProjectAlmSettingDaoTest.java @@ -0,0 +1,132 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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.db.alm.setting; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.utils.System2; +import org.sonar.core.util.UuidFactory; +import org.sonar.db.DbSession; +import org.sonar.db.DbTester; +import org.sonar.db.component.ComponentDto; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.sonar.db.almsettings.AlmSettingsTesting.newGithubProjectAlmSettingDto; + +public class ProjectAlmSettingDaoTest { + + private static final long A_DATE = 1_000_000_000_000L; + private static final long A_DATE_LATER = 1_700_000_000_000L; + + private static final String A_UUID = "SOME_UUID"; + @Rule + public ExpectedException expectedException = ExpectedException.none(); + private System2 system2 = mock(System2.class); + @Rule + public DbTester db = DbTester.create(system2); + + private DbSession dbSession = db.getSession(); + private UuidFactory uuidFactory = mock(UuidFactory.class); + private ProjectAlmSettingDao underTest = new ProjectAlmSettingDao(system2, uuidFactory); + + @Test + public void selectByProject() { + when(uuidFactory.create()).thenReturn(A_UUID); + when(system2.now()).thenReturn(A_DATE); + AlmSettingDto githubAlmSettingDto = db.almSettings().insertGitHubAlmSetting(); + ComponentDto project = db.components().insertPrivateProject(); + ComponentDto anotherProject = db.components().insertPrivateProject(); + ProjectAlmSettingDto githubProjectAlmSettingDto = newGithubProjectAlmSettingDto(githubAlmSettingDto, project); + underTest.insertOrUpdate(dbSession, githubProjectAlmSettingDto); + + assertThat(underTest.selectByProject(dbSession, project).get()) + .extracting(ProjectAlmSettingDto::getUuid, ProjectAlmSettingDto::getAlmSettingUuid, ProjectAlmSettingDto::getProjectUuid, + ProjectAlmSettingDto::getAlmRepo, ProjectAlmSettingDto::getAlmSlug, + ProjectAlmSettingDto::getCreatedAt, ProjectAlmSettingDto::getUpdatedAt) + .containsExactly(A_UUID, githubAlmSettingDto.getUuid(), project.uuid(), + githubProjectAlmSettingDto.getAlmRepo(), githubProjectAlmSettingDto.getAlmSlug(), + A_DATE, A_DATE); + + assertThat(underTest.selectByProject(dbSession, anotherProject)).isNotPresent(); + } + + @Test + public void update_existing_binding() { + when(uuidFactory.create()).thenReturn(A_UUID); + when(system2.now()).thenReturn(A_DATE); + AlmSettingDto githubAlmSetting = db.almSettings().insertGitHubAlmSetting(); + ComponentDto project = db.components().insertPrivateProject(); + ProjectAlmSettingDto projectAlmSettingDto = db.almSettings().insertGitHubProjectAlmSetting(githubAlmSetting, project); + AlmSettingDto anotherGithubAlmSetting = db.almSettings().insertGitHubAlmSetting(); + + when(system2.now()).thenReturn(A_DATE_LATER); + ProjectAlmSettingDto newProjectAlmSettingDto = newGithubProjectAlmSettingDto(anotherGithubAlmSetting, project); + underTest.insertOrUpdate(dbSession, newProjectAlmSettingDto); + + assertThat(underTest.selectByProject(dbSession, project).get()) + .extracting(ProjectAlmSettingDto::getUuid, ProjectAlmSettingDto::getAlmSettingUuid, ProjectAlmSettingDto::getProjectUuid, + ProjectAlmSettingDto::getAlmRepo, ProjectAlmSettingDto::getAlmSlug, + ProjectAlmSettingDto::getCreatedAt, ProjectAlmSettingDto::getUpdatedAt) + .containsExactly(projectAlmSettingDto.getUuid(), anotherGithubAlmSetting.getUuid(), project.uuid(), + newProjectAlmSettingDto.getAlmRepo(), newProjectAlmSettingDto.getAlmSlug(), + A_DATE, A_DATE_LATER); + } + + @Test + public void deleteByProject() { + when(uuidFactory.create()).thenReturn(A_UUID); + when(system2.now()).thenReturn(A_DATE); + AlmSettingDto githubAlmSetting = db.almSettings().insertGitHubAlmSetting(); + ComponentDto project = db.components().insertPrivateProject(); + db.almSettings().insertGitHubProjectAlmSetting(githubAlmSetting, project); + ComponentDto anotherProject = db.components().insertPrivateProject(); + db.almSettings().insertGitHubProjectAlmSetting(githubAlmSetting, anotherProject); + + underTest.deleteByProject(dbSession, project); + + assertThat(underTest.selectByProject(dbSession, project)).isEmpty(); + assertThat(underTest.selectByProject(dbSession, anotherProject)).isNotEmpty(); + } + + @Test + public void deleteByAlmSetting() { + when(uuidFactory.create()).thenReturn(A_UUID); + when(system2.now()).thenReturn(A_DATE); + AlmSettingDto githubAlmSetting = db.almSettings().insertGitHubAlmSetting(); + ComponentDto project1 = db.components().insertPrivateProject(); + ComponentDto project2 = db.components().insertPrivateProject(); + db.almSettings().insertGitHubProjectAlmSetting(githubAlmSetting, project1); + db.almSettings().insertGitHubProjectAlmSetting(githubAlmSetting, project2); + + AlmSettingDto githubAlmSetting1 = db.almSettings().insertGitHubAlmSetting(); + ComponentDto anotherProject = db.components().insertPrivateProject(); + db.almSettings().insertGitHubProjectAlmSetting(githubAlmSetting1, anotherProject); + + underTest.deleteByAlmSetting(dbSession, githubAlmSetting); + + assertThat(underTest.countByAlmSetting(dbSession, githubAlmSetting)).isZero(); + assertThat(underTest.countByAlmSetting(dbSession, githubAlmSetting1)).isEqualTo(1); + } + +} diff --git a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/almsettings/AlmSettingsDbTester.java b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/almsettings/AlmSettingsDbTester.java index 604806e39a8..f0cb2ee71fe 100644 --- a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/almsettings/AlmSettingsDbTester.java +++ b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/almsettings/AlmSettingsDbTester.java @@ -22,11 +22,14 @@ package org.sonar.db.almsettings; import java.util.function.Consumer; import org.sonar.db.DbTester; import org.sonar.db.alm.setting.AlmSettingDto; +import org.sonar.db.alm.setting.ProjectAlmSettingDto; +import org.sonar.db.component.ComponentDto; import static java.util.Arrays.stream; import static org.sonar.db.almsettings.AlmSettingsTesting.newAzureAlmSettingDto; import static org.sonar.db.almsettings.AlmSettingsTesting.newBitbucketAlmSettingDto; import static org.sonar.db.almsettings.AlmSettingsTesting.newGithubAlmSettingDto; +import static org.sonar.db.almsettings.AlmSettingsTesting.newGithubProjectAlmSettingDto; public class AlmSettingsDbTester { @@ -51,6 +54,16 @@ public class AlmSettingsDbTester { return insert(newBitbucketAlmSettingDto(), populators); } + @SafeVarargs + public final ProjectAlmSettingDto insertGitHubProjectAlmSetting(AlmSettingDto githubAlmSetting, ComponentDto project, Consumer<ProjectAlmSettingDto>... populators) { + ProjectAlmSettingDto dto = newGithubProjectAlmSettingDto(githubAlmSetting, project); + stream(populators).forEach(p -> p.accept(dto)); + + db.getDbClient().projectAlmSettingDao().insertOrUpdate(db.getSession(), dto); + db.commit(); + return dto; + } + private AlmSettingDto insert(AlmSettingDto dto, Consumer<AlmSettingDto>[] populators) { stream(populators).forEach(p -> p.accept(dto)); @@ -58,4 +71,5 @@ public class AlmSettingsDbTester { db.commit(); return dto; } + } diff --git a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/almsettings/AlmSettingsTesting.java b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/almsettings/AlmSettingsTesting.java index 885a2947a53..99952b0aa96 100644 --- a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/almsettings/AlmSettingsTesting.java +++ b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/almsettings/AlmSettingsTesting.java @@ -21,6 +21,8 @@ package org.sonar.db.almsettings; 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.component.ComponentDto; import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; @@ -49,4 +51,12 @@ public class AlmSettingsTesting { .setPersonalAccessToken(randomAlphanumeric(2000)) .setAlm(ALM.BITBUCKET); } + + public static ProjectAlmSettingDto newGithubProjectAlmSettingDto(AlmSettingDto githubAlmSetting, ComponentDto project) { + return new ProjectAlmSettingDto() + .setAlmSettingUuid(githubAlmSetting.getUuid()) + .setProjectUuid(project.uuid()) + .setAlmRepo(randomAlphanumeric(256)) + .setAlmSlug(randomAlphanumeric(256)); + } } diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v81/CreateProjectAlmSettingsTable.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v81/CreateProjectAlmSettingsTable.java new file mode 100644 index 00000000000..af1507db728 --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v81/CreateProjectAlmSettingsTable.java @@ -0,0 +1,108 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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.platform.db.migration.version.v81; + +import java.sql.Connection; +import java.sql.SQLException; +import org.sonar.db.Database; +import org.sonar.db.DatabaseUtils; +import org.sonar.server.platform.db.migration.def.VarcharColumnDef; +import org.sonar.server.platform.db.migration.sql.CreateIndexBuilder; +import org.sonar.server.platform.db.migration.sql.CreateTableBuilder; +import org.sonar.server.platform.db.migration.step.DdlChange; + +import static org.sonar.server.platform.db.migration.def.BigIntegerColumnDef.newBigIntegerColumnDefBuilder; +import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.UUID_SIZE; +import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.UUID_VARCHAR_SIZE; +import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder; + +public class CreateProjectAlmSettingsTable extends DdlChange { + + private static final String TABLE_NAME = "project_alm_settings"; + + private static final VarcharColumnDef PROJECT_UUID = newVarcharColumnDefBuilder() + .setColumnName("project_uuid") + .setIsNullable(false) + .setLimit(UUID_VARCHAR_SIZE) + .build(); + + private static final VarcharColumnDef ALM_SETTING_UUID = newVarcharColumnDefBuilder() + .setColumnName("alm_setting_uuid") + .setIsNullable(false) + .setLimit(UUID_SIZE) + .build(); + + public CreateProjectAlmSettingsTable(Database db) { + super(db); + } + + @Override + public void execute(Context context) throws SQLException { + if (tableExists()) { + return; + } + context.execute(new CreateTableBuilder(getDialect(), TABLE_NAME) + .addPkColumn(newVarcharColumnDefBuilder() + .setColumnName("uuid") + .setIsNullable(false) + .setLimit(UUID_SIZE) + .build()) + .addColumn(ALM_SETTING_UUID) + .addColumn(PROJECT_UUID) + .addColumn(newVarcharColumnDefBuilder() + .setColumnName("alm_repo") + .setIsNullable(true) + .setLimit(256) + .build()) + .addColumn(newVarcharColumnDefBuilder() + .setColumnName("alm_slug") + .setIsNullable(true) + .setLimit(256) + .build()) + .addColumn(newBigIntegerColumnDefBuilder() + .setColumnName("updated_at") + .setIsNullable(false) + .build()) + .addColumn(newBigIntegerColumnDefBuilder() + .setColumnName("created_at") + .setIsNullable(false) + .build()) + .build()); + + context.execute(new CreateIndexBuilder() + .setTable(TABLE_NAME) + .addColumn(PROJECT_UUID) + .setName("uniq_project_alm_settings") + .setUnique(true) + .build()); + + context.execute(new CreateIndexBuilder() + .setTable(TABLE_NAME) + .addColumn(ALM_SETTING_UUID) + .setName("project_alm_settings_alm") + .build()); + } + + private boolean tableExists() throws SQLException { + try (Connection connection = getDatabase().getDataSource().getConnection()) { + return DatabaseUtils.tableExists(TABLE_NAME, connection); + } + } +} diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v81/DbVersion81.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v81/DbVersion81.java index b5b2897a92b..f946622d850 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v81/DbVersion81.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v81/DbVersion81.java @@ -26,6 +26,7 @@ public class DbVersion81 implements DbVersion { @Override public void addSteps(MigrationStepRegistry registry) { registry - .add(3100, "Create ALM_SETTINGS table", CreateAlmSettingsTable.class); + .add(3100, "Create ALM_SETTINGS table", CreateAlmSettingsTable.class) + .add(3101, "Create PROJECT_ALM_SETTINGS table", CreateProjectAlmSettingsTable.class); } } diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v81/CreateProjectAlmSettingsTableTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v81/CreateProjectAlmSettingsTableTest.java new file mode 100644 index 00000000000..e5b41e28940 --- /dev/null +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v81/CreateProjectAlmSettingsTableTest.java @@ -0,0 +1,63 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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.platform.db.migration.version.v81; + +import java.sql.SQLException; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.db.CoreDbTester; + +import static java.sql.Types.BIGINT; +import static java.sql.Types.VARCHAR; + +public class CreateProjectAlmSettingsTableTest { + private static final String TABLE_NAME = "project_alm_settings"; + + @Rule + public CoreDbTester dbTester = CoreDbTester.createEmpty(); + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + private CreateProjectAlmSettingsTable underTest = new CreateProjectAlmSettingsTable(dbTester.database()); + + @Test + public void table_has_been_created() throws SQLException { + underTest.execute(); + + dbTester.assertTableExists(TABLE_NAME); + dbTester.assertPrimaryKey(TABLE_NAME, "pk_project_alm_settings", "uuid"); + dbTester.assertUniqueIndex(TABLE_NAME, "uniq_project_alm_settings", "project_uuid"); + dbTester.assertIndex(TABLE_NAME, "project_alm_settings_alm", "alm_setting_uuid"); + + dbTester.assertColumnDefinition(TABLE_NAME, "uuid", VARCHAR, 40, false); + dbTester.assertColumnDefinition(TABLE_NAME, "alm_setting_uuid", VARCHAR, 40, false); + dbTester.assertColumnDefinition(TABLE_NAME, "project_uuid", VARCHAR, 50, false); + dbTester.assertColumnDefinition(TABLE_NAME, "alm_repo", VARCHAR, 256, true); + dbTester.assertColumnDefinition(TABLE_NAME, "alm_slug", VARCHAR, 256, true); + dbTester.assertColumnDefinition(TABLE_NAME, "updated_at", BIGINT, 20, false); + dbTester.assertColumnDefinition(TABLE_NAME, "created_at", BIGINT, 20, false); + + // script should not fail if executed twice + underTest.execute(); + } +} diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v81/DbVersion81Test.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v81/DbVersion81Test.java index a8dcfb748ca..8e6e0fa4f1e 100644 --- a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v81/DbVersion81Test.java +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v81/DbVersion81Test.java @@ -37,7 +37,7 @@ public class DbVersion81Test { @Test public void verify_migration_count() { - verifyMigrationCount(underTest, 1); + verifyMigrationCount(underTest, 2); } } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/AlmSettingsSupport.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/AlmSettingsSupport.java new file mode 100644 index 00000000000..0a940e25c88 --- /dev/null +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/AlmSettingsSupport.java @@ -0,0 +1,46 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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; + +import org.sonar.db.alm.setting.ALM; +import org.sonarqube.ws.AlmSettings; + +import static java.lang.String.format; + +class AlmSettingsSupport { + + private AlmSettingsSupport() { + // Only static methods here for the moment + } + + static AlmSettings.Alm toAlmWs(ALM alm) { + switch (alm) { + case GITHUB: + return AlmSettings.Alm.github; + case BITBUCKET: + return AlmSettings.Alm.bitbucket; + case AZURE_DEVOPS: + return AlmSettings.Alm.azure; + default: + throw new IllegalStateException(format("Unknown ALM '%s'", alm.name())); + } + } +} diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/AlmSettingsWsModule.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/AlmSettingsWsModule.java index f78aa97b7ac..7c970d2da77 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/AlmSettingsWsModule.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/AlmSettingsWsModule.java @@ -33,6 +33,12 @@ public class AlmSettingsWsModule extends Module { CreateAzureAction.class, UpdateAzureAction.class, CreateBitBucketAction.class, - UpdateBitbucketAction.class); + UpdateBitbucketAction.class, + SetGithubBindingAction.class, + DeleteBindingAction.class, + GetBindingAction.class, + ListAction.class, + CountBindingAction.class + ); } } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/CountBindingAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/CountBindingAction.java new file mode 100644 index 00000000000..a874360385d --- /dev/null +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/CountBindingAction.java @@ -0,0 +1,82 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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; + +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.server.exceptions.NotFoundException; +import org.sonar.server.user.UserSession; +import org.sonarqube.ws.AlmSettings.CountBindingWsResponse; + +import static java.lang.String.format; +import static org.sonar.server.ws.WsUtils.writeProtobuf; + +public class CountBindingAction implements AlmSettingsWsAction { + + private static final String PARAM_ALM_SETTING = "almSetting"; + + private final DbClient dbClient; + private final UserSession userSession; + + public CountBindingAction(DbClient dbClient, UserSession userSession) { + this.dbClient = dbClient; + this.userSession = userSession; + } + + @Override + public void define(WebService.NewController context) { + WebService.NewAction action = context.createAction("count_binding") + .setDescription("Count number of project bound to an ALM setting.<br/>" + + "Requires the 'Administer System' permission") + .setSince("8.1") + .setResponseExample(getClass().getResource("count_binding-example.json")) + .setHandler(this); + + action + .createParam(PARAM_ALM_SETTING) + .setDescription("ALM setting key") + .setRequired(true); + } + + @Override + public void handle(Request request, Response response) throws Exception { + userSession.checkIsSystemAdministrator(); + CountBindingWsResponse wsResponse = doHandle(request); + writeProtobuf(wsResponse, request, response); + } + + private CountBindingWsResponse doHandle(Request request) { + String almSettingKey = request.mandatoryParam(PARAM_ALM_SETTING); + try (DbSession dbSession = dbClient.openSession(false)) { + AlmSettingDto almSetting = dbClient.almSettingDao().selectByKey(dbSession, almSettingKey) + .orElseThrow(() -> new NotFoundException(format("ALM setting with key '%s' cannot be found", almSettingKey))); + int projectsBound = dbClient.projectAlmSettingDao().countByAlmSetting(dbSession, almSetting); + return CountBindingWsResponse.newBuilder() + .setKey(almSetting.getKey()) + .setProjects(projectsBound) + .build(); + } + } +} diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/CreateGithubAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/CreateGithubAction.java index 6412a90293c..8a98643bef5 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/CreateGithubAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/CreateGithubAction.java @@ -38,7 +38,7 @@ public class CreateGithubAction implements AlmSettingsWsAction { private static final String PARAM_PRIVATE_KEY = "privateKey"; private final DbClient dbClient; - private UserSession userSession; + private final UserSession userSession; public CreateGithubAction(DbClient dbClient, UserSession userSession) { this.dbClient = dbClient; diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/DeleteAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/DeleteAction.java index 57b3186011f..62c3ef47df7 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/DeleteAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/DeleteAction.java @@ -36,7 +36,7 @@ public class DeleteAction implements AlmSettingsWsAction { private static final String PARAM_KEY = "key"; private final DbClient dbClient; - private UserSession userSession; + private final UserSession userSession; public DeleteAction(DbClient dbClient, UserSession userSession) { this.dbClient = dbClient; @@ -71,6 +71,7 @@ public class DeleteAction implements AlmSettingsWsAction { try (DbSession dbSession = dbClient.openSession(false)) { AlmSettingDto almSettingDto = dbClient.almSettingDao().selectByKey(dbSession, key) .orElseThrow(() -> new NotFoundException(format("No ALM setting with key '%s' has been found", key))); + dbClient.projectAlmSettingDao().deleteByAlmSetting(dbSession, almSettingDto); dbClient.almSettingDao().delete(dbSession, almSettingDto); dbSession.commit(); } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/DeleteBindingAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/DeleteBindingAction.java new file mode 100644 index 00000000000..b1004102cea --- /dev/null +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/DeleteBindingAction.java @@ -0,0 +1,78 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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; + +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.component.ComponentDto; +import org.sonar.server.component.ComponentFinder; +import org.sonar.server.user.UserSession; + +import static org.sonar.api.web.UserRole.ADMIN; + +public class DeleteBindingAction implements AlmSettingsWsAction { + + private static final String PARAM_PROJECT = "project"; + + private final DbClient dbClient; + private final UserSession userSession; + private final ComponentFinder componentFinder; + + public DeleteBindingAction(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("delete_binding") + .setDescription("Delete the ALM setting binding of a project.<br/>" + + "Requires the 'Administer' permission on the project") + .setSince("8.1") + .setPost(true) + .setHandler(this); + + action + .createParam(PARAM_PROJECT) + .setDescription("Project key") + .setRequired(true); + } + + @Override + public void handle(Request request, Response response) throws Exception { + doHandle(request); + response.noContent(); + } + + private void doHandle(Request request) { + String projectKey = request.mandatoryParam(PARAM_PROJECT); + try (DbSession dbSession = dbClient.openSession(false)) { + ComponentDto project = componentFinder.getByKey(dbSession, projectKey); + userSession.checkComponentPermission(ADMIN, project); + dbClient.projectAlmSettingDao().deleteByProject(dbSession, project); + dbSession.commit(); + } + } +} diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/GetBindingAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/GetBindingAction.java new file mode 100644 index 00000000000..e210967e937 --- /dev/null +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/GetBindingAction.java @@ -0,0 +1,94 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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; + +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.component.ComponentDto; +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.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.<br/>" + + "Requires the 'Administer' permission on the project") + .setSince("8.1") + .setResponseExample(getClass().getResource("get_binding-example.json")) + .setHandler(this); + + action + .createParam(PARAM_PROJECT) + .setDescription("Project key") + .setRequired(true); + } + + @Override + public void handle(Request request, Response response) throws Exception { + 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)) { + ComponentDto project = componentFinder.getByKey(dbSession, projectKey); + userSession.checkComponentPermission(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); + return builder.build(); + } + } +} diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ListAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ListAction.java new file mode 100644 index 00000000000..5ebec5bd7eb --- /dev/null +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ListAction.java @@ -0,0 +1,95 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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; + +import java.util.List; +import java.util.stream.Collectors; +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.component.ComponentDto; +import org.sonar.server.component.ComponentFinder; +import org.sonar.server.user.UserSession; +import org.sonarqube.ws.AlmSettings.AlmSetting; +import org.sonarqube.ws.AlmSettings.ListWsResponse; + +import static java.util.Optional.ofNullable; +import static org.sonar.api.web.UserRole.ADMIN; +import static org.sonar.server.ws.WsUtils.writeProtobuf; + +public class ListAction implements AlmSettingsWsAction { + + private static final String PARAM_PROJECT = "project"; + + private final DbClient dbClient; + private final UserSession userSession; + private final ComponentFinder componentFinder; + + public ListAction(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("list") + .setDescription("List ALM setting available for a given project.<br/>" + + "Requires the 'Administer' permission on the project") + .setSince("8.1") + .setResponseExample(getClass().getResource("list-example.json")) + .setHandler(this); + + action + .createParam(PARAM_PROJECT) + .setDescription("Project key") + .setRequired(true); + } + + @Override + public void handle(Request request, Response response) throws Exception { + ListWsResponse wsResponse = doHandle(request); + writeProtobuf(wsResponse, request, response); + } + + private ListWsResponse doHandle(Request request) { + String projectKey = request.mandatoryParam(PARAM_PROJECT); + try (DbSession dbSession = dbClient.openSession(false)) { + ComponentDto project = componentFinder.getByKey(dbSession, projectKey); + userSession.checkComponentPermission(ADMIN, project); + List<AlmSettingDto> settings = dbClient.almSettingDao().selectAll(dbSession); + List<AlmSetting> wsAlmSettings = settings.stream() + .map(almSetting -> { + AlmSetting.Builder almSettingBuilder = AlmSetting.newBuilder() + .setKey(almSetting.getKey()) + .setAlm(AlmSettingsSupport.toAlmWs(almSetting.getAlm())); + ofNullable(almSetting.getUrl()).ifPresent(almSettingBuilder::setUrl); + return almSettingBuilder.build(); + }) + .collect(Collectors.toList()); + return ListWsResponse.newBuilder() + .addAllAlmSettings(wsAlmSettings).build(); + } + } + +} diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ListDefinitionsAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ListDefinitionsAction.java index 51e93401592..7cbea4ff489 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ListDefinitionsAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ListDefinitionsAction.java @@ -42,7 +42,7 @@ import static org.sonarqube.ws.AlmSettings.ListDefinitionsWsResponse; public class ListDefinitionsAction implements AlmSettingsWsAction { private final DbClient dbClient; - private UserSession userSession; + private final UserSession userSession; public ListDefinitionsAction(DbClient dbClient, UserSession userSession) { this.dbClient = dbClient; diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/SetGithubBindingAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/SetGithubBindingAction.java new file mode 100644 index 00000000000..6740ee25cca --- /dev/null +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/SetGithubBindingAction.java @@ -0,0 +1,99 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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; + +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.component.ComponentDto; +import org.sonar.server.component.ComponentFinder; +import org.sonar.server.exceptions.NotFoundException; +import org.sonar.server.user.UserSession; + +import static java.lang.String.format; +import static org.sonar.api.web.UserRole.ADMIN; + +public class SetGithubBindingAction implements AlmSettingsWsAction { + + private static final String PARAM_ALM_SETTING = "almSetting"; + private static final String PARAM_PROJECT = "project"; + private static final String PARAM_REPOSITORY = "repository"; + + private final DbClient dbClient; + private final UserSession userSession; + private final ComponentFinder componentFinder; + + public SetGithubBindingAction(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("set_github_binding") + .setDescription("Bind a GitHub ALM instance to a project.<br/>" + + "If the project was already bound to a previous GitHub ALM instance, the binding will be updated to the new one." + + "Requires the 'Administer' permission on the project") + .setPost(true) + .setSince("8.1") + .setHandler(this); + + action.createParam(PARAM_ALM_SETTING) + .setRequired(true) + .setDescription("GitHub ALM setting key"); + action.createParam(PARAM_PROJECT) + .setRequired(true) + .setDescription("Project key"); + action.createParam(PARAM_REPOSITORY) + .setRequired(true) + .setMaximumLength(256) + .setDescription("GitHub Repository"); + } + + @Override + public void handle(Request request, Response response) throws Exception { + doHandle(request); + response.noContent(); + } + + private void doHandle(Request request) { + String almSetting = request.mandatoryParam(PARAM_ALM_SETTING); + String projectKey = request.mandatoryParam(PARAM_PROJECT); + String repository = request.mandatoryParam(PARAM_REPOSITORY); + try (DbSession dbSession = dbClient.openSession(false)) { + ComponentDto project = componentFinder.getByKey(dbSession, projectKey); + userSession.checkComponentPermission(ADMIN, project); + AlmSettingDto almSettingDto = dbClient.almSettingDao().selectByKey(dbSession, almSetting) + .orElseThrow(() -> new NotFoundException(format("No ALM setting with almSetting '%s' has been found", almSetting))); + dbClient.projectAlmSettingDao().insertOrUpdate(dbSession, new ProjectAlmSettingDto() + .setProjectUuid(project.uuid()) + .setAlmSettingUuid(almSettingDto.getUuid()) + .setAlmRepo(repository) + .setAlmSlug(null)); + dbSession.commit(); + } + } + +} diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/UpdateGitHubAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/UpdateGitHubAction.java index d2e05875764..face95be6bb 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/UpdateGitHubAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/UpdateGitHubAction.java @@ -40,7 +40,7 @@ public class UpdateGitHubAction implements AlmSettingsWsAction { private static final String PARAM_PRIVATE_KEY = "privateKey"; private final DbClient dbClient; - private UserSession userSession; + private final UserSession userSession; public UpdateGitHubAction(DbClient dbClient, UserSession userSession) { this.dbClient = dbClient; diff --git a/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/almsettings/count_binding-example.json b/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/almsettings/count_binding-example.json new file mode 100644 index 00000000000..d6c189ec17e --- /dev/null +++ b/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/almsettings/count_binding-example.json @@ -0,0 +1,4 @@ +{ + "key": "GitHub Server - Dev Team", + "projects": 3 +} diff --git a/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/almsettings/get_binding-example.json b/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/almsettings/get_binding-example.json new file mode 100644 index 00000000000..146dff339bb --- /dev/null +++ b/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/almsettings/get_binding-example.json @@ -0,0 +1,6 @@ +{ + "key": "GitHub Server - Dev Team", + "alm": "github", + "repository": "team/project", + "url": "https://github.enterprise.com" +} diff --git a/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/almsettings/list-example.json b/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/almsettings/list-example.json new file mode 100644 index 00000000000..624dbadd03f --- /dev/null +++ b/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/almsettings/list-example.json @@ -0,0 +1,9 @@ +{ + "almSettings": [ + { + "key": "GitHub Server - Dev Team", + "alm": "github", + "url": "https://github.enterprise.com" + } + ] +} diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/AlmSettingsWsModuleTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/AlmSettingsWsModuleTest.java index b94904fa053..e5e5bdffc92 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/AlmSettingsWsModuleTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/AlmSettingsWsModuleTest.java @@ -24,7 +24,6 @@ import org.junit.Test; import org.sonar.core.platform.ComponentContainer; import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER; public class AlmSettingsWsModuleTest { @@ -32,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 + 8); + assertThat(container.size()).isGreaterThan(0); } } diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/CountBindingActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/CountBindingActionTest.java new file mode 100644 index 00000000000..fbc638ff1ce --- /dev/null +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/CountBindingActionTest.java @@ -0,0 +1,127 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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; + +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.component.ComponentDto; +import org.sonar.db.user.UserDto; +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.CountBindingWsResponse; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.groups.Tuple.tuple; +import static org.sonar.test.JsonAssert.assertJson; + +public class CountBindingActionTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); + @Rule + public DbTester db = DbTester.create(); + + private WsActionTester ws = new WsActionTester(new CountBindingAction(db.getDbClient(), userSession)); + + @Test + public void count_binding() { + UserDto user = db.users().insertUser(); + userSession.logIn(user).setSystemAdministrator(); + AlmSettingDto githubAlmSetting = db.almSettings().insertGitHubAlmSetting(); + ComponentDto project1 = db.components().insertPrivateProject(); + ComponentDto project2 = db.components().insertPrivateProject(); + db.almSettings().insertGitHubProjectAlmSetting(githubAlmSetting, project1); + db.almSettings().insertGitHubProjectAlmSetting(githubAlmSetting, project2); + + CountBindingWsResponse response = ws.newRequest() + .setParam("almSetting", githubAlmSetting.getKey()) + .executeProtobuf(CountBindingWsResponse.class); + + assertThat(response.getKey()).isEqualTo(githubAlmSetting.getKey()); + assertThat(response.getProjects()).isEqualTo(2); + } + + @Test + public void fail_when_alm_setting_does_not_exist() { + UserDto user = db.users().insertUser(); + userSession.logIn(user).setSystemAdministrator(); + + expectedException.expect(NotFoundException.class); + expectedException.expectMessage("ALM setting with key 'unknown' cannot be found"); + + ws.newRequest() + .setParam("almSetting", "unknown") + .execute(); + } + + @Test + public void fail_when_missing_system_administer_permission() { + UserDto user = db.users().insertUser(); + userSession.logIn(user); + AlmSettingDto githubAlmSetting = db.almSettings().insertGitHubAlmSetting(); + + expectedException.expect(ForbiddenException.class); + + ws.newRequest() + .setParam("almSetting", githubAlmSetting.getKey()) + .execute(); + } + + @Test + public void json_example() { + UserDto user = db.users().insertUser(); + userSession.logIn(user).setSystemAdministrator(); + AlmSettingDto githubAlmSetting = db.almSettings().insertGitHubAlmSetting( + almSettingDto -> almSettingDto + .setKey("GitHub Server - Dev Team") + .setAppId("12345") + .setPrivateKey("54684654")); + db.almSettings().insertGitHubProjectAlmSetting(githubAlmSetting, db.components().insertPrivateProject()); + db.almSettings().insertGitHubProjectAlmSetting(githubAlmSetting, db.components().insertPrivateProject()); + db.almSettings().insertGitHubProjectAlmSetting(githubAlmSetting, db.components().insertPrivateProject()); + + String response = ws.newRequest() + .setParam("almSetting", githubAlmSetting.getKey()) + .execute().getInput(); + + assertJson(response).isSimilarTo(getClass().getResource("count_binding-example.json")); + } + + @Test + public void definition() { + WebService.Action def = ws.getDef(); + + assertThat(def.since()).isEqualTo("8.1"); + assertThat(def.isPost()).isFalse(); + assertThat(def.params()) + .extracting(WebService.Param::key, WebService.Param::isRequired) + .containsExactlyInAnyOrder(tuple("almSetting", true)); + } + +} diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/DeleteActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/DeleteActionTest.java index aec45c06f25..3e6a7fd65ff 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/DeleteActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/DeleteActionTest.java @@ -25,6 +25,7 @@ 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.component.ComponentDto; import org.sonar.db.user.UserDto; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.NotFoundException; @@ -59,6 +60,27 @@ public class DeleteActionTest { } @Test + public void delete_project_binding_during_deletion() { + UserDto user = db.users().insertUser(); + userSession.logIn(user).setSystemAdministrator(); + AlmSettingDto almSetting = db.almSettings().insertGitHubAlmSetting(); + ComponentDto project = db.components().insertPrivateProject(); + db.almSettings().insertGitHubProjectAlmSetting(almSetting, project); + // Second setting having a project bound on it, should not be impacted by the deletion of the first one + AlmSettingDto anotherAlmSetting2 = db.almSettings().insertGitHubAlmSetting(); + ComponentDto anotherProject = db.components().insertPrivateProject(); + db.almSettings().insertGitHubProjectAlmSetting(anotherAlmSetting2, anotherProject); + + ws.newRequest() + .setParam("key", almSetting.getKey()) + .execute(); + + assertThat(db.getDbClient().almSettingDao().selectAll(db.getSession())).extracting(AlmSettingDto::getUuid).containsExactlyInAnyOrder(anotherAlmSetting2.getUuid()); + assertThat(db.getDbClient().projectAlmSettingDao().selectByProject(db.getSession(), project)).isEmpty(); + assertThat(db.getDbClient().projectAlmSettingDao().selectByProject(db.getSession(), anotherProject)).isNotEmpty(); + } + + @Test public void fail_when_key_does_not_match_existing_alm_setting() { UserDto user = db.users().insertUser(); userSession.logIn(user).setSystemAdministrator(); diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/DeleteBindingActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/DeleteBindingActionTest.java new file mode 100644 index 00000000000..beba04d6e82 --- /dev/null +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/DeleteBindingActionTest.java @@ -0,0 +1,109 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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; + +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.component.ComponentDto; +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 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; + +public class DeleteBindingActionTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); + @Rule + public DbTester db = DbTester.create(); + + private WsActionTester ws = new WsActionTester(new DeleteBindingAction(db.getDbClient(), userSession, new ComponentFinder(db.getDbClient(), null))); + + @Test + public void delete_project_binding() { + UserDto user = db.users().insertUser(); + ComponentDto project = db.components().insertPrivateProject(); + userSession.logIn(user).addProjectPermission(ADMIN, project); + AlmSettingDto githubAlmSetting = db.almSettings().insertGitHubAlmSetting(); + db.almSettings().insertGitHubProjectAlmSetting(githubAlmSetting, project); + + ws.newRequest() + .setParam("project", project.getKey()) + .execute(); + + assertThat(db.getDbClient().projectAlmSettingDao().selectByProject(db.getSession(), project)).isEmpty(); + } + + @Test + public void fail_when_project_does_not_exist() { + UserDto user = db.users().insertUser(); + ComponentDto project = db.components().insertPrivateProject(); + 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() { + UserDto user = db.users().insertUser(); + ComponentDto project = db.components().insertPrivateProject(); + 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 definition() { + WebService.Action def = ws.getDef(); + + assertThat(def.since()).isEqualTo("8.1"); + assertThat(def.isPost()).isTrue(); + assertThat(def.params()) + .extracting(WebService.Param::key, WebService.Param::isRequired) + .containsExactlyInAnyOrder(tuple("project", true)); + } + +} diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/GetBindingActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/GetBindingActionTest.java new file mode 100644 index 00000000000..8b59c81aa8b --- /dev/null +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/GetBindingActionTest.java @@ -0,0 +1,137 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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; + +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.component.ComponentDto; +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))); + + @Test + public void get_project_binding() { + UserDto user = db.users().insertUser(); + ComponentDto project = db.components().insertPrivateProject(); + 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()); + } + + @Test + public void fail_when_project_does_not_exist() { + UserDto user = db.users().insertUser(); + ComponentDto project = db.components().insertPrivateProject(); + 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() { + UserDto user = db.users().insertUser(); + ComponentDto project = db.components().insertPrivateProject(); + 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() { + UserDto user = db.users().insertUser(); + ComponentDto project = db.components().insertPrivateProject(); + 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/java/org/sonar/server/almsettings/ListActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ListActionTest.java new file mode 100644 index 00000000000..72baba18c4a --- /dev/null +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ListActionTest.java @@ -0,0 +1,137 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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; + +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.component.ComponentDto; +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.AlmSetting; +import org.sonarqube.ws.AlmSettings.ListWsResponse; + +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 ListActionTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); + @Rule + public DbTester db = DbTester.create(); + + private WsActionTester ws = new WsActionTester(new ListAction(db.getDbClient(), userSession, new ComponentFinder(db.getDbClient(), null))); + + @Test + public void list() { + UserDto user = db.users().insertUser(); + ComponentDto project = db.components().insertPrivateProject(); + userSession.logIn(user).addProjectPermission(ADMIN, project); + AlmSettingDto githubAlmSetting1 = db.almSettings().insertGitHubAlmSetting(); + AlmSettingDto githubAlmSetting2 = db.almSettings().insertGitHubAlmSetting(); + + ListWsResponse response = ws.newRequest() + .setParam("project", project.getKey()) + .executeProtobuf(AlmSettings.ListWsResponse.class); + + assertThat(response.getAlmSettingsList()) + .extracting(AlmSetting::getAlm, AlmSetting::getKey, AlmSetting::getUrl) + .containsExactlyInAnyOrder( + tuple(AlmSettings.Alm.github, githubAlmSetting1.getKey(), githubAlmSetting1.getUrl()), + tuple(AlmSettings.Alm.github, githubAlmSetting2.getKey(), githubAlmSetting2.getUrl())); + } + + @Test + public void fail_when_project_does_not_exist() { + UserDto user = db.users().insertUser(); + ComponentDto project = db.components().insertPrivateProject(); + 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() { + UserDto user = db.users().insertUser(); + ComponentDto project = db.components().insertPrivateProject(); + 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() { + UserDto user = db.users().insertUser(); + ComponentDto project = db.components().insertPrivateProject(); + 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("list-example.json")); + } + + @Test + public void definition() { + WebService.Action def = ws.getDef(); + + assertThat(def.since()).isEqualTo("8.1"); + assertThat(def.isPost()).isFalse(); + assertThat(def.params()) + .extracting(WebService.Param::key, WebService.Param::isRequired) + .containsExactlyInAnyOrder(tuple("project", true)); + } + +} diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/SetGithubBindingActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/SetGithubBindingActionTest.java new file mode 100644 index 00000000000..78250eb1964 --- /dev/null +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/SetGithubBindingActionTest.java @@ -0,0 +1,149 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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; + +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.component.ComponentDto; +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 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; + +public class SetGithubBindingActionTest { + @Rule + public ExpectedException expectedException = ExpectedException.none(); + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); + @Rule + public DbTester db = DbTester.create(); + + private WsActionTester ws = new WsActionTester(new SetGithubBindingAction(db.getDbClient(), userSession, new ComponentFinder(db.getDbClient(), null))); + + @Test + public void set_github_project_binding() { + UserDto user = db.users().insertUser(); + AlmSettingDto githubAlmSetting = db.almSettings().insertGitHubAlmSetting(); + ComponentDto project = db.components().insertPrivateProject(); + userSession.logIn(user).addProjectPermission(ADMIN, project); + + ws.newRequest() + .setParam("almSetting", githubAlmSetting.getKey()) + .setParam("project", project.getKey()) + .setParam("repository", "myproject") + .execute(); + + assertThat(db.getDbClient().projectAlmSettingDao().selectByProject(db.getSession(), project).get()) + .extracting(ProjectAlmSettingDto::getAlmSettingUuid, ProjectAlmSettingDto::getProjectUuid, ProjectAlmSettingDto::getAlmRepo, ProjectAlmSettingDto::getAlmSlug) + .containsOnly(githubAlmSetting.getUuid(), project.uuid(), "myproject", null); + } + + @Test + public void override_existing_github_project_binding() { + UserDto user = db.users().insertUser(); + AlmSettingDto githubAlmSetting = db.almSettings().insertGitHubAlmSetting(); + ComponentDto project = db.components().insertPrivateProject(); + db.almSettings().insertGitHubProjectAlmSetting(githubAlmSetting, project); + AlmSettingDto anotherGithubAlmSetting = db.almSettings().insertGitHubAlmSetting(); + userSession.logIn(user).addProjectPermission(ADMIN, project); + + ws.newRequest() + .setParam("almSetting", anotherGithubAlmSetting.getKey()) + .setParam("project", project.getKey()) + .setParam("repository", "myproject") + .execute(); + + assertThat(db.getDbClient().projectAlmSettingDao().selectByProject(db.getSession(), project).get()) + .extracting(ProjectAlmSettingDto::getAlmSettingUuid, ProjectAlmSettingDto::getProjectUuid, ProjectAlmSettingDto::getAlmRepo, ProjectAlmSettingDto::getAlmSlug) + .containsOnly(anotherGithubAlmSetting.getUuid(), project.uuid(), "myproject", null); + } + + @Test + public void fail_when_alm_setting_does_not_exist() { + UserDto user = db.users().insertUser(); + ComponentDto project = db.components().insertPrivateProject(); + userSession.logIn(user).addProjectPermission(ADMIN, project); + + expectedException.expect(NotFoundException.class); + expectedException.expectMessage("No ALM setting with almSetting 'unknown' has been found"); + + ws.newRequest() + .setParam("almSetting", "unknown") + .setParam("project", project.getKey()) + .setParam("repository", "myproject") + .execute(); + } + + @Test + public void fail_when_project_does_not_exist() { + UserDto user = db.users().insertUser(); + AlmSettingDto githubAlmSetting = db.almSettings().insertGitHubAlmSetting(); + ComponentDto project = db.components().insertPrivateProject(); + userSession.logIn(user).addProjectPermission(ADMIN, project); + + expectedException.expect(NotFoundException.class); + + ws.newRequest() + .setParam("almSetting", githubAlmSetting.getKey()) + .setParam("project", "unknown") + .setParam("repository", "myproject") + .execute(); + } + + @Test + public void fail_when_missing_administer_permission_on_project() { + UserDto user = db.users().insertUser(); + AlmSettingDto githubAlmSetting = db.almSettings().insertGitHubAlmSetting(); + ComponentDto project = db.components().insertPrivateProject(); + userSession.logIn(user).addProjectPermission(USER, project); + + expectedException.expect(ForbiddenException.class); + + ws.newRequest() + .setParam("almSetting", githubAlmSetting.getKey()) + .setParam("project", project.getKey()) + .setParam("repository", "myproject") + .execute(); + } + + @Test + public void definition() { + WebService.Action def = ws.getDef(); + + assertThat(def.since()).isEqualTo("8.1"); + assertThat(def.isPost()).isTrue(); + assertThat(def.params()) + .extracting(WebService.Param::key, WebService.Param::isRequired) + .containsExactlyInAnyOrder(tuple("almSetting", true), tuple("project", true), tuple("repository", true)); + } +} diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/almsettings/AlmSettingsService.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/almsettings/AlmSettingsService.java index 3392f021f7a..b461504d061 100644 --- a/sonar-ws/src/main/java/org/sonarqube/ws/client/almsettings/AlmSettingsService.java +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/almsettings/AlmSettingsService.java @@ -38,45 +38,57 @@ public class AlmSettingsService extends BaseService { } /** - * * This is a GET request. - * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/alm_settings/list_definitions">Further information about this action online (including a response example)</a> + * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/alm_settings/count_binding">Further information about this action online (including a response example)</a> * @since 8.1 */ - public AlmSettings.ListDefinitionsWsResponse listDefinitions() { + public AlmSettings.CountBindingWsResponse countBinding(CountBindingRequest request) { return call( - new GetRequest(path("list_definitions")), - AlmSettings.ListDefinitionsWsResponse.parser()); + new GetRequest(path("count_binding")) + .setParam("almSetting", request.getAlmSetting()) + .setMediaType(MediaTypes.JSON), + AlmSettings.CountBindingWsResponse.parser()); } /** * * This is a POST request. - * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/alm_settings/create_github">Further information about this action online (including a response example)</a> + * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/alm_settings/create_azure">Further information about this action online (including a response example)</a> * @since 8.1 */ - public void createGithub(CreateGithubRequest request) { + public void createAzure(CreateAzureRequest request) { call( - new PostRequest(path("create_github")) - .setParam("appId", request.getAppId()) + new PostRequest(path("create_azure")) .setParam("key", request.getKey()) - .setParam("privateKey", request.getPrivateKey()) - .setParam("url", request.getUrl()) + .setParam("personalAccessToken", request.getPersonalAccessToken()) .setMediaType(MediaTypes.JSON)).content(); } /** * * This is a POST request. - * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/alm_settings/update_github">Further information about this action online (including a response example)</a> + * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/alm_settings/create_bitbucket">Further information about this action online (including a response example)</a> * @since 8.1 */ - public void updateGithub(UpdateGithubRequest request) { + public void createBitbucket(CreateBitbucketRequest request) { call( - new PostRequest(path("update_github")) + new PostRequest(path("create_bitbucket")) + .setParam("key", request.getKey()) + .setParam("url", request.getUrl()) + .setParam("personalAccessToken", request.getPersonalAccessToken()) + .setMediaType(MediaTypes.JSON)).content(); + } + + /** + * This is a POST request. + * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/alm_settings/create_github">Further information about this action online (including a response example)</a> + * @since 8.1 + */ + public void createGithub(CreateGithubRequest request) { + call( + new PostRequest(path("create_github")) .setParam("appId", request.getAppId()) .setParam("key", request.getKey()) - .setParam("newKey", request.getNewKey()) .setParam("privateKey", request.getPrivateKey()) .setParam("url", request.getUrl()) .setMediaType(MediaTypes.JSON)).content(); @@ -95,17 +107,68 @@ public class AlmSettingsService extends BaseService { .setMediaType(MediaTypes.JSON)).content(); } + + /** + * This is a POST request. + * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/alm_settings/delete_binding">Further information about this action online (including a response example)</a> + * @since 8.1 + */ + public void deleteBinding(DeleteBindingRequest request) { + call( + new PostRequest(path("delete_binding")) + .setParam("project", request.getProject()) + .setMediaType(MediaTypes.JSON)).content(); + } + + /** + * This is a GET request. + * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/alm_settings/get_binding">Further information about this action online (including a response example)</a> + * @since 8.1 + */ + public AlmSettings.GetBindingWsResponse getBinding(GetGithubBindingRequest request) { + return call( + new GetRequest(path("get_binding")) + .setParam("project", request.getProject()) + .setMediaType(MediaTypes.JSON), + AlmSettings.GetBindingWsResponse.parser()); + } + + /** + * This is a GET request. + * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/alm_settings/list">Further information about this action online (including a response example)</a> + * @since 8.1 + */ + public AlmSettings.ListWsResponse list(ListRequest request) { + return call( + new GetRequest(path("list")) + .setParam("project", request.getProject()) + .setMediaType(MediaTypes.JSON), + AlmSettings.ListWsResponse.parser()); + } + /** * + * This is a GET request. + * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/alm_settings/list_definitions">Further information about this action online (including a response example)</a> + * @since 8.1 + */ + public AlmSettings.ListDefinitionsWsResponse listDefinitions() { + return call( + new GetRequest(path("list_definitions")), + AlmSettings.ListDefinitionsWsResponse.parser()); + } + + /** * This is a POST request. - * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/alm_settings/create_azure">Further information about this action online (including a response example)</a> + * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/alm_settings/set_github_binding">Further information about this action online (including a response example)</a> * @since 8.1 */ - public void createAzure(CreateAzureRequest request) { + public void setGithubBinding(SetGithubBindingRequest request) { call( - new PostRequest(path("create_azure")) - .setParam("key", request.getKey()) - .setParam("personalAccessToken", request.getPersonalAccessToken()) + new PostRequest(path("set_github_binding")) + .setParam("almSetting", request.getAlmSetting()) + .setParam("project", request.getProject()) + .setParam("repository", request.getRepository()) .setMediaType(MediaTypes.JSON)).content(); } @@ -127,13 +190,14 @@ public class AlmSettingsService extends BaseService { /** * * This is a POST request. - * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/alm_settings/create_bitbucket">Further information about this action online (including a response example)</a> + * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/alm_settings/update_bitbucket">Further information about this action online (including a response example)</a> * @since 8.1 */ - public void createBitbucket(CreateBitbucketRequest request) { + public void updateBitbucket(UpdateBitbucketRequest request) { call( - new PostRequest(path("create_bitbucket")) + new PostRequest(path("update_bitbucket")) .setParam("key", request.getKey()) + .setParam("newKey", request.getNewKey()) .setParam("url", request.getUrl()) .setParam("personalAccessToken", request.getPersonalAccessToken()) .setMediaType(MediaTypes.JSON)).content(); @@ -142,17 +206,17 @@ public class AlmSettingsService extends BaseService { /** * * This is a POST request. - * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/alm_settings/update_bitbucket">Further information about this action online (including a response example)</a> + * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/alm_settings/update_github">Further information about this action online (including a response example)</a> * @since 8.1 */ - public void updateBitbucket(UpdateBitbucketRequest request) { + public void updateGithub(UpdateGithubRequest request) { call( - new PostRequest(path("update_bitbucket")) + new PostRequest(path("update_github")) + .setParam("appId", request.getAppId()) .setParam("key", request.getKey()) .setParam("newKey", request.getNewKey()) + .setParam("privateKey", request.getPrivateKey()) .setParam("url", request.getUrl()) - .setParam("personalAccessToken", request.getPersonalAccessToken()) .setMediaType(MediaTypes.JSON)).content(); } - } diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/almsettings/CountBindingRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/almsettings/CountBindingRequest.java new file mode 100644 index 00000000000..2a6b3e2ffc8 --- /dev/null +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/almsettings/CountBindingRequest.java @@ -0,0 +1,46 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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.sonarqube.ws.client.almsettings; + +import javax.annotation.Generated; + +/** + * This is part of the internal API. + * This is a POST request. + * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/alm_settings/count_binding">Further information about this action online (including a response example)</a> + * @since 8.1 + */ +@Generated("sonar-ws-generator") +public class CountBindingRequest { + + private String almSetting; + + /** + * This is a mandatory parameter. + */ + public CountBindingRequest setAlmSetting(String almSetting) { + this.almSetting = almSetting; + return this; + } + + public String getAlmSetting() { + return almSetting; + } +} diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/almsettings/DeleteBindingRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/almsettings/DeleteBindingRequest.java new file mode 100644 index 00000000000..0f0ff571c87 --- /dev/null +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/almsettings/DeleteBindingRequest.java @@ -0,0 +1,46 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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.sonarqube.ws.client.almsettings; + +import javax.annotation.Generated; + +/** + * This is part of the internal API. + * This is a POST request. + * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/alm_settings/delete_binding">Further information about this action online (including a response example)</a> + * @since 8.1 + */ +@Generated("sonar-ws-generator") +public class DeleteBindingRequest { + + private String project; + + /** + * This is a mandatory parameter. + */ + public DeleteBindingRequest setProject(String project) { + this.project = project; + return this; + } + + public String getProject() { + return project; + } +} diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/almsettings/GetGithubBindingRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/almsettings/GetGithubBindingRequest.java new file mode 100644 index 00000000000..d38e17c58ec --- /dev/null +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/almsettings/GetGithubBindingRequest.java @@ -0,0 +1,46 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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.sonarqube.ws.client.almsettings; + +import javax.annotation.Generated; + +/** + * This is part of the internal API. + * This is a POST request. + * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/alm_settings/get_github_binding">Further information about this action online (including a response example)</a> + * @since 8.1 + */ +@Generated("sonar-ws-generator") +public class GetGithubBindingRequest { + + private String project; + + /** + * This is a mandatory parameter. + */ + public GetGithubBindingRequest setProject(String project) { + this.project = project; + return this; + } + + public String getProject() { + return project; + } +} diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/almsettings/ListRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/almsettings/ListRequest.java new file mode 100644 index 00000000000..7aa215f1828 --- /dev/null +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/almsettings/ListRequest.java @@ -0,0 +1,46 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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.sonarqube.ws.client.almsettings; + +import javax.annotation.Generated; + +/** + * This is part of the internal API. + * This is a POST request. + * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/alm_settings/list">Further information about this action online (including a response example)</a> + * @since 8.1 + */ +@Generated("sonar-ws-generator") +public class ListRequest { + + private String project; + + /** + * This is a mandatory parameter. + */ + public ListRequest setProject(String project) { + this.project = project; + return this; + } + + public String getProject() { + return project; + } +} diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/almsettings/SetGithubBindingRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/almsettings/SetGithubBindingRequest.java new file mode 100644 index 00000000000..cc8a489ef03 --- /dev/null +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/almsettings/SetGithubBindingRequest.java @@ -0,0 +1,72 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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.sonarqube.ws.client.almsettings; + +import javax.annotation.Generated; + +/** + * This is part of the internal API. + * This is a POST request. + * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/alm_settings/set_github_binding">Further information about this action online (including a response example)</a> + * @since 8.1 + */ +@Generated("sonar-ws-generator") +public class SetGithubBindingRequest { + + private String almSetting; + private String project; + private String repository; + + /** + * This is a mandatory parameter. + */ + public SetGithubBindingRequest setAlmSetting(String almSetting) { + this.almSetting = almSetting; + return this; + } + + public String getAlmSetting() { + return almSetting; + } + + /** + * This is a mandatory parameter. + */ + public SetGithubBindingRequest setProject(String project) { + this.project = project; + return this; + } + + public String getProject() { + return project; + } + + /** + * This is a mandatory parameter. + */ + public SetGithubBindingRequest setRepository(String repository) { + this.repository = repository; + return this; + } + + public String getRepository() { + return repository; + } +} diff --git a/sonar-ws/src/main/protobuf/ws-alm_settings.proto b/sonar-ws/src/main/protobuf/ws-alm_settings.proto index aca6db28614..ce1c9b825fb 100644 --- a/sonar-ws/src/main/protobuf/ws-alm_settings.proto +++ b/sonar-ws/src/main/protobuf/ws-alm_settings.proto @@ -48,3 +48,34 @@ message AlmSettingBitbucket { optional string url = 2; optional string personalAccessToken = 3; } + +// WS api/alm_settings/get_binding +message GetBindingWsResponse { + optional string key = 1; + optional Alm alm = 2; + optional string repository = 3; + optional string url = 4; +} + +enum Alm { + github = 0; + azure = 1; + bitbucket = 2; +} + +// WS api/alm_settings/list +message ListWsResponse { + repeated AlmSetting almSettings = 1; +} + +message AlmSetting { + optional string key = 1; + optional Alm alm = 2; + optional string url = 3; +} + +// WS api/alm_settings/count_binding +message CountBindingWsResponse { + optional string key = 1; + optional int64 projects = 2; +} |