assertThat(picoContainer.getParent().getParent().getParent().getComponentAdapters()).hasSize(
COMPONENTS_IN_LEVEL_1_AT_CONSTRUCTION
+ 27 // level 1
- + 55 // content of DaoModule
+ + 56 // content of DaoModule
+ 3 // content of EsModule
+ 54 // content of CorePropertyDefinitions
+ 1 // StopFlagContainer
"active_rules",
"active_rule_parameters",
"alm_app_installs",
+ "alm_project_mappings",
"analysis_properties",
"ce_activity",
"ce_queue",
CREATE UNIQUE INDEX "ALM_APP_INSTALLS_OWNER" ON "ALM_APP_INSTALLS" ("ALM_ID", "OWNER_ID");
CREATE UNIQUE INDEX "ALM_APP_INSTALLS_INSTALL" ON "ALM_APP_INSTALLS" ("ALM_ID", "INSTALL_ID");
+CREATE TABLE "ALM_PROJECT_MAPPINGS" (
+ "UUID" VARCHAR(40) NOT NULL,
+ "ALM_ID" VARCHAR(40) NOT NULL,
+ "REPO_ID" VARCHAR(256) NOT NULL,
+ "PROJECT_UUID" VARCHAR(40) NOT NULL,
+ "GITHUB_SLUG" VARCHAR(256) NULL,
+ "URL" VARCHAR(2000) NOT NULL,
+ "CREATED_AT" BIGINT NOT NULL,
+ "UPDATED_AT" BIGINT NOT NULL,
+ CONSTRAINT "PK_ALM_PROJECT_MAPPINGS" PRIMARY KEY ("UUID")
+);
+CREATE UNIQUE INDEX "ALM_PROJECT_MAPPINGS_ALM_REPO" ON "ALM_PROJECT_MAPPINGS" ("ALM_ID", "REPO_ID");
+CREATE UNIQUE INDEX "ALM_PROJECT_MAPPINGS_PROJECT" ON "ALM_PROJECT_MAPPINGS" ("PROJECT_UUID");
+
CREATE TABLE "PROJECT_MAPPINGS" (
"UUID" VARCHAR(40) NOT NULL,
"KEY_TYPE" VARCHAR(200) NOT NULL,
);
CREATE UNIQUE INDEX "KEY_TYPE_KEE" ON "PROJECT_MAPPINGS" ("KEY_TYPE", "KEE");
CREATE INDEX "PROJECT_UUID" ON "PROJECT_MAPPINGS" ("PROJECT_UUID");
-
import java.util.Collections;
import java.util.List;
import org.sonar.core.platform.Module;
+import org.sonar.db.alm.AlmProjectMappingsDao;
import org.sonar.db.ce.CeActivityDao;
import org.sonar.db.ce.CeQueueDao;
import org.sonar.db.ce.CeScannerContextDao;
GroupMembershipDao.class,
GroupPermissionDao.class,
AlmAppInstallDao.class,
+ AlmProjectMappingsDao.class,
InternalPropertiesDao.class,
IssueChangeDao.class,
IssueDao.class,
import java.util.IdentityHashMap;
import java.util.Map;
+import org.sonar.db.alm.AlmProjectMappingsDao;
import org.sonar.db.ce.CeActivityDao;
import org.sonar.db.ce.CeQueueDao;
import org.sonar.db.ce.CeScannerContextDao;
private final QualityProfileDao qualityProfileDao;
private final PropertiesDao propertiesDao;
private final AlmAppInstallDao almAppInstallDao;
+ private final AlmProjectMappingsDao almProjectMappingsDao;
private final InternalPropertiesDao internalPropertiesDao;
private final SnapshotDao snapshotDao;
private final ComponentDao componentDao;
map.put(dao.getClass(), dao);
}
almAppInstallDao = getDao(map, AlmAppInstallDao.class);
+ almProjectMappingsDao = getDao(map, AlmProjectMappingsDao.class);
schemaMigrationDao = getDao(map, SchemaMigrationDao.class);
authorizationDao = getDao(map, AuthorizationDao.class);
organizationDao = getDao(map, OrganizationDao.class);
return almAppInstallDao;
}
+ public AlmProjectMappingsDao almProjectMappingsDao() {
+ return almProjectMappingsDao;
+ }
+
public SchemaMigrationDao schemaMigrationDao() {
return schemaMigrationDao;
}
import org.apache.ibatis.session.TransactionIsolationLevel;
import org.sonar.api.Startable;
import org.sonar.db.alm.AlmAppInstallMapper;
+import org.sonar.db.alm.AlmProjectMappingsMapper;
import org.sonar.db.ce.CeActivityMapper;
import org.sonar.db.ce.CeQueueMapper;
import org.sonar.db.ce.CeScannerContextMapper;
ActiveRuleMapper.class,
AnalysisPropertiesMapper.class,
AlmAppInstallMapper.class,
+ AlmProjectMappingsMapper.class,
AuthorizationMapper.class,
BranchMapper.class,
CeActivityMapper.class,
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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;
+
+import java.util.Locale;
+
+public enum ALM {
+ BITBUCKETCLOUD,
+ GITHUB;
+
+ String getId() {
+ return this.name().toLowerCase(Locale.ENGLISH);
+ }
+}
*/
package org.sonar.db.alm;
-import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import javax.annotation.Nullable;
*/
public class AlmAppInstallDao implements Dao {
- public enum ALM {
- BITBUCKETCLOUD,
- GITHUB;
-
- String getId() {
- return this.name().toLowerCase(Locale.ENGLISH);
- }
- }
-
private final System2 system2;
private final UuidFactory uuidFactory;
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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;
+
+import java.util.Objects;
+import javax.annotation.Nullable;
+import org.sonar.api.utils.System2;
+import org.sonar.core.util.UuidFactory;
+import org.sonar.db.Dao;
+import org.sonar.db.DbSession;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static org.apache.commons.lang.StringUtils.isNotEmpty;
+
+public class AlmProjectMappingsDao implements Dao {
+
+ private final System2 system2;
+ private final UuidFactory uuidFactory;
+
+ public AlmProjectMappingsDao(System2 system2, UuidFactory uuidFactory) {
+ this.system2 = system2;
+ this.uuidFactory = uuidFactory;
+ }
+
+ public void insertOrUpdate(DbSession dbSession, ALM alm, String repoId, String projectUuid, @Nullable String githubSlug, String url) {
+ checkAlm(alm);
+ checkRepoId(repoId);
+ checkArgument(isNotEmpty(projectUuid), "projectUuid can't be null nor empty");
+ checkArgument(isNotEmpty(url), "url can't be null nor empty");
+
+ AlmProjectMappingsMapper mapper = getMapper(dbSession);
+ long now = system2.now();
+
+ if (mapper.update(alm.getId(), repoId, projectUuid, githubSlug, url, now) == 0) {
+ mapper.insert(uuidFactory.create(), alm.getId(), repoId, projectUuid, githubSlug, url, now);
+ }
+ }
+
+ public boolean mappingExists(DbSession dbSession, ALM alm, String repoId) {
+ checkAlm(alm);
+ checkRepoId(repoId);
+
+ return getMapper(dbSession).mappingCount(alm.getId(), repoId) == 1;
+ }
+
+ private static void checkAlm(@Nullable ALM alm) {
+ Objects.requireNonNull(alm, "alm can't be null");
+ }
+
+ private static void checkRepoId(@Nullable String repoId) {
+ checkArgument(isNotEmpty(repoId), "repoId can't be null nor empty");
+ }
+
+ private static AlmProjectMappingsMapper getMapper(DbSession dbSession) {
+ return dbSession.getMapper(AlmProjectMappingsMapper.class);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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;
+
+import javax.annotation.Nullable;
+import org.apache.ibatis.annotations.Param;
+
+public interface AlmProjectMappingsMapper {
+
+ int mappingCount(@Param("almId") String almId, @Param("repoId") String repoId);
+
+ void insert(@Param("uuid") String uuid, @Param("almId") String almId, @Param("repoId") String repoId, @Param("projectUuid") String projectUuid,
+ @Nullable @Param("githubSlug") String githubSlug, @Param("url") String url, @Param("now") long now);
+
+ int update(@Param("almId") String almId, @Param("repoId") String repoId, @Param("projectUuid") String projectUuid,
+ @Nullable @Param("githubSlug") String githubSlug, @Param("url") String url, @Param("now") long now);
+}
profiler.stop();
}
+ void deleteAlmProjectMappings(String rootUuid) {
+ profiler.start("deleteAlmProjectMappings (alm_project_mappings)");
+ purgeMapper.deleteAlmProjectMappingsByProjectUuid(rootUuid);
+ session.commit();
+ profiler.stop();
+ }
+
void deleteBranch(String rootUuid) {
profiler.start("deleteBranch (project_branches)");
purgeMapper.deleteBranchByUuid(rootUuid);
commands.deleteCeQueue(rootUuid);
commands.deleteWebhookDeliveries(rootUuid);
commands.deleteProjectMappings(rootUuid);
+ commands.deleteAlmProjectMappings(rootUuid);
commands.deleteBranch(rootUuid);
commands.deleteLiveMeasures(rootUuid);
}
void deleteProjectMappingsByProjectUuid(@Param("projectUuid") String projectUuid);
+ void deleteAlmProjectMappingsByProjectUuid(@Param("projectUuid") String projectUuid);
+
void deleteBranchByUuid(@Param("uuid") String uuid);
void deleteLiveMeasuresByProjectUuid(@Param("projectUuid") String projectUuid);
--- /dev/null
+<?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.AlmProjectMappingsMapper">
+
+ <select id="mappingCount" parameterType="Map" resultType="int">
+ select
+ count(*) as count
+ from
+ alm_project_mappings
+ where
+ alm_id = #{almId, jdbcType=VARCHAR}
+ and repo_id = #{repoId, jdbcType=VARCHAR}
+ </select>
+
+ <insert id="insert" parameterType="Map" useGeneratedKeys="false">
+ INSERT INTO alm_project_mappings
+ (
+ uuid,
+ alm_id,
+ repo_id,
+ project_uuid,
+ github_slug,
+ url,
+ created_at,
+ updated_at
+ )
+ VALUES (
+ #{uuid, jdbcType=VARCHAR},
+ #{almId, jdbcType=VARCHAR},
+ #{repoId, jdbcType=VARCHAR},
+ #{projectUuid, jdbcType=VARCHAR},
+ #{githubSlug, jdbcType=VARCHAR},
+ #{url, jdbcType=VARCHAR},
+ #{now, jdbcType=BIGINT},
+ #{now, jdbcType=BIGINT}
+ )
+ </insert>
+
+ <update id="update" parameterType="map">
+ update alm_project_mappings set
+ project_uuid = #{projectUuid, jdbcType=VARCHAR},
+ github_slug = #{githubSlug, jdbcType=VARCHAR},
+ url = #{url, jdbcType=VARCHAR},
+ updated_at = #{now, jdbcType=BIGINT}
+ where
+ alm_id = #{almId, jdbcType=VARCHAR}
+ and repo_id = #{repoId, jdbcType=VARCHAR}
+ </update>
+
+</mapper>
delete from project_mappings where project_uuid=#{projectUuid,jdbcType=VARCHAR}
</delete>
+ <delete id="deleteAlmProjectMappingsByProjectUuid">
+ delete from alm_project_mappings where project_uuid=#{projectUuid,jdbcType=VARCHAR}
+ </delete>
+
<delete id="deleteBranchByUuid">
delete from project_branches where uuid=#{uuid,jdbcType=VARCHAR}
</delete>
public void verify_count_of_added_components() {
ComponentContainer container = new ComponentContainer();
new DaoModule().configure(container);
- assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 55);
+ assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 56);
}
}
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.alm.AlmAppInstallDao.ALM.GITHUB;
+import static org.sonar.db.alm.ALM.GITHUB;
public class AlmAppInstallDaoTest {
expectedException.expectMessage("installId can't be null nor empty");
}
- private AlmAppInstallAssert assertThatAlmAppInstall(AlmAppInstallDao.ALM alm, String ownerId) {
+ private AlmAppInstallAssert assertThatAlmAppInstall(ALM alm, String ownerId) {
return new AlmAppInstallAssert(dbTester, dbSession, alm, ownerId);
}
private static class AlmAppInstallAssert extends AbstractAssert<AlmAppInstallAssert, AlmAppInstall> {
- private AlmAppInstallAssert(DbTester dbTester, DbSession dbSession, AlmAppInstallDao.ALM alm, String ownerId) {
+ private AlmAppInstallAssert(DbTester dbTester, DbSession dbSession, ALM alm, String ownerId) {
super(asAlmAppInstall(dbTester, dbSession, alm, ownerId), AlmAppInstallAssert.class);
}
- private static AlmAppInstall asAlmAppInstall(DbTester dbTester, DbSession dbSession, AlmAppInstallDao.ALM alm, String ownerId) {
+ private static AlmAppInstall asAlmAppInstall(DbTester dbTester, DbSession dbSession, ALM alm, String ownerId) {
List<Map<String, Object>> rows = dbTester.select(
dbSession,
"select" +
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import javax.annotation.Nullable;
+import org.assertj.core.api.AbstractAssert;
+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 static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.db.alm.ALM.GITHUB;
+
+public class AlmProjectMappingsDaoTest {
+
+ private static final String A_UUID = "abcde1234";
+ private static final String ANOTHER_UUID = "xyz789";
+ private static final String EMPTY_STRING = "";
+
+ private static final String A_REPO = "my_repo";
+ private static final String ANOTHER_REPO = "another_repo";
+
+ private static final String A_GITHUB_SLUG = null;
+ private static final String ANOTHER_GITHUB_SLUG = "example/foo";
+
+ private static final String A_URL = "foo url";
+ private static final String ANOTHER_URL = "bar url";
+
+ private static final long DATE = 1_600_000_000_000L;
+ private static final long DATE_LATER = 1_700_000_000_000L;
+
+ private System2 system2 = mock(System2.class);
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+ @Rule
+ public DbTester dbTester = DbTester.create(system2);
+
+ private DbSession dbSession = dbTester.getSession();
+ private UuidFactory uuidFactory = mock(UuidFactory.class);
+ private AlmProjectMappingsDao underTest = new AlmProjectMappingsDao(system2, uuidFactory);
+
+ @Test
+ public void insert_throws_NPE_if_alm_is_null() {
+ expectAlmNPE();
+
+ underTest.insertOrUpdate(dbSession, null, A_REPO, A_UUID, A_GITHUB_SLUG, A_URL);
+ }
+
+ @Test
+ public void insert_throws_IAE_if_repo_id_is_null() {
+ expectRepoIdNullOrEmptyIAE();
+
+ underTest.insertOrUpdate(dbSession, GITHUB, null, A_UUID, A_GITHUB_SLUG, A_URL);
+ }
+
+ @Test
+ public void insert_throws_IAE_if_repo_id_is_empty() {
+ expectRepoIdNullOrEmptyIAE();
+
+ underTest.insertOrUpdate(dbSession, GITHUB, EMPTY_STRING, A_UUID, A_GITHUB_SLUG, A_URL);
+ }
+
+ @Test
+ public void insert_throws_IAE_if_project_uuid_is_null() {
+ expectProjectUuidNullOrEmptyIAE();
+
+ underTest.insertOrUpdate(dbSession, GITHUB, A_REPO, null, A_GITHUB_SLUG, A_URL);
+ }
+
+ @Test
+ public void insert_throws_IAE_if_project_uuid_is_empty() {
+ expectProjectUuidNullOrEmptyIAE();
+
+ underTest.insertOrUpdate(dbSession, GITHUB, A_REPO, EMPTY_STRING, A_GITHUB_SLUG, A_URL);
+ }
+
+ @Test
+ public void insert_throws_IAE_if_url_is_null() {
+ expectUrlNullOrEmptyIAE();
+
+ underTest.insertOrUpdate(dbSession, GITHUB, A_REPO, A_UUID, A_GITHUB_SLUG, null);
+ }
+
+ @Test
+ public void insert_throws_IAE_if_url_is_empty() {
+ expectUrlNullOrEmptyIAE();
+
+ underTest.insertOrUpdate(dbSession, GITHUB, A_REPO, A_UUID, A_GITHUB_SLUG, EMPTY_STRING);
+ }
+
+ @Test
+ public void insert() {
+ when(uuidFactory.create()).thenReturn(A_UUID);
+ when(system2.now()).thenReturn(DATE);
+ underTest.insertOrUpdate(dbSession, GITHUB, A_REPO, A_UUID, A_GITHUB_SLUG, A_URL);
+
+ assertThatAlmProjectMapping(GITHUB, A_REPO)
+ .hasProjectUuid(A_UUID)
+ .hasGithubSlug(A_GITHUB_SLUG)
+ .hasUrl(A_URL)
+ .hasCreatedAt(DATE)
+ .hasUpdatedAt(DATE);
+ }
+
+ @Test
+ public void update() {
+ when(uuidFactory.create()).thenReturn(A_UUID);
+ when(system2.now()).thenReturn(DATE);
+ underTest.insertOrUpdate(dbSession, GITHUB, A_REPO, A_UUID, A_GITHUB_SLUG, A_URL);
+
+ when(system2.now()).thenReturn(DATE_LATER);
+ underTest.insertOrUpdate(dbSession, GITHUB, A_REPO, ANOTHER_UUID, ANOTHER_GITHUB_SLUG, ANOTHER_URL);
+
+ assertThatAlmProjectMapping(GITHUB, A_REPO)
+ .hasProjectUuid(ANOTHER_UUID)
+ .hasGithubSlug(ANOTHER_GITHUB_SLUG)
+ .hasUrl(ANOTHER_URL)
+ .hasCreatedAt(DATE)
+ .hasUpdatedAt(DATE_LATER);
+ }
+
+ @Test
+ public void insert_multiple() {
+ when(system2.now()).thenReturn(DATE);
+ when(uuidFactory.create())
+ .thenReturn(A_UUID)
+ .thenReturn(ANOTHER_UUID);
+ underTest.insertOrUpdate(dbSession, GITHUB, A_REPO, A_UUID, A_GITHUB_SLUG, A_URL);
+ underTest.insertOrUpdate(dbSession, GITHUB, ANOTHER_REPO, ANOTHER_UUID, ANOTHER_GITHUB_SLUG, ANOTHER_URL);
+
+ assertThatAlmProjectMapping(GITHUB, A_REPO)
+ .hasProjectUuid(A_UUID)
+ .hasGithubSlug(A_GITHUB_SLUG)
+ .hasUrl(A_URL)
+ .hasCreatedAt(DATE)
+ .hasUpdatedAt(DATE);
+
+ assertThatAlmProjectMapping(GITHUB, ANOTHER_REPO)
+ .hasProjectUuid(ANOTHER_UUID)
+ .hasGithubSlug(ANOTHER_GITHUB_SLUG)
+ .hasUrl(ANOTHER_URL)
+ .hasCreatedAt(DATE)
+ .hasUpdatedAt(DATE);
+ }
+
+ @Test
+ public void mappingExists_throws_NPE_when_alm_is_null() {
+ expectAlmNPE();
+
+ underTest.mappingExists(dbSession, null, A_REPO);
+ }
+
+ @Test
+ public void mappingExists_throws_IAE_when_repo_id_is_null() {
+ expectRepoIdNullOrEmptyIAE();
+
+ underTest.mappingExists(dbSession, GITHUB, null);
+ }
+
+ @Test
+ public void mappingExists_throws_IAE_when_repo_id_is_empty() {
+ expectRepoIdNullOrEmptyIAE();
+
+ underTest.mappingExists(dbSession, GITHUB, EMPTY_STRING);
+ }
+
+ @Test
+ public void mappingExists_returns_false_when_entry_does_not_exist_in_DB() {
+ assertThat(underTest.mappingExists(dbSession, GITHUB, A_REPO)).isFalse();
+ }
+
+ @Test
+ public void mappingExists_returns_true_when_entry_exists() {
+ when(uuidFactory.create()).thenReturn(A_UUID);
+ underTest.insertOrUpdate(dbSession, GITHUB, A_REPO, A_UUID, A_GITHUB_SLUG, A_URL);
+
+ assertThat(underTest.mappingExists(dbSession, GITHUB, A_REPO)).isTrue();
+ }
+
+ private void expectAlmNPE() {
+ expectedException.expect(NullPointerException.class);
+ expectedException.expectMessage("alm can't be null");
+ }
+
+ private void expectRepoIdNullOrEmptyIAE() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("repoId can't be null nor empty");
+ }
+
+ private void expectProjectUuidNullOrEmptyIAE() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("projectUuid can't be null nor empty");
+ }
+
+ private void expectUrlNullOrEmptyIAE() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("url can't be null nor empty");
+ }
+
+ private AlmAppInstallAssert assertThatAlmProjectMapping(ALM alm, String repoId) {
+ return new AlmAppInstallAssert(dbTester, dbSession, alm, repoId);
+ }
+
+ private static class AlmAppInstallAssert extends AbstractAssert<AlmAppInstallAssert, AlmProjectMapping> {
+
+ private AlmAppInstallAssert(DbTester dbTester, DbSession dbSession, ALM alm, String repoId) {
+ super(asAlmProjectMapping(dbTester, dbSession, alm, repoId), AlmAppInstallAssert.class);
+ }
+
+ private static AlmProjectMapping asAlmProjectMapping(DbTester dbTester, DbSession dbSession, ALM alm, String repoId) {
+ List<Map<String, Object>> rows = dbTester.select(
+ dbSession,
+ "select" +
+ " project_uuid as \"projectUuid\", github_slug as \"githubSlug\", url as \"url\", " +
+ " created_at as \"createdAt\", updated_at as \"updatedAt\"" +
+ " from alm_project_mappings" +
+ " where alm_id='" + alm.getId() + "' and repo_id='" + repoId + "'");
+ if (rows.isEmpty()) {
+ return null;
+ }
+ if (rows.size() > 1) {
+ throw new IllegalStateException("Unique index violation");
+ }
+ return new AlmProjectMapping(
+ (String) rows.get(0).get("projectUuid"),
+ (String) rows.get(0).get("githubSlug"),
+ (String) rows.get(0).get("url"),
+ (Long) rows.get(0).get("createdAt"),
+ (Long) rows.get(0).get("updatedAt"));
+ }
+
+ public void doesNotExist() {
+ isNull();
+ }
+
+ AlmAppInstallAssert hasProjectUuid(String expected) {
+ isNotNull();
+
+ if (!Objects.equals(actual.projectUuid, expected)) {
+ failWithMessage("Expected ALM Project Mapping to have column PROJECT_UUID to be <%s> but was <%s>", expected, actual.projectUuid);
+ }
+ return this;
+ }
+
+ AlmAppInstallAssert hasGithubSlug(String expected) {
+ isNotNull();
+
+ if (!Objects.equals(actual.githubSlug, expected)) {
+ failWithMessage("Expected ALM Project Mapping to have column GITHUB_SLUG to be <%s> but was <%s>", expected, actual.githubSlug);
+ }
+ return this;
+ }
+
+ AlmAppInstallAssert hasUrl(String expected) {
+ isNotNull();
+
+ if (!Objects.equals(actual.url, expected)) {
+ failWithMessage("Expected ALM Project Mapping to have column URL to be <%s> but was <%s>", expected, actual.url);
+ }
+ return this;
+ }
+
+ AlmAppInstallAssert hasCreatedAt(long expected) {
+ isNotNull();
+
+ if (!Objects.equals(actual.createdAt, expected)) {
+ failWithMessage("Expected ALM Project Mapping to have column CREATED_AT to be <%s> but was <%s>", expected, actual.createdAt);
+ }
+
+ return this;
+ }
+
+ AlmAppInstallAssert hasUpdatedAt(long expected) {
+ isNotNull();
+
+ if (!Objects.equals(actual.updatedAt, expected)) {
+ failWithMessage("Expected ALM Project Mapping to have column UPDATED_AT to be <%s> but was <%s>", expected, actual.updatedAt);
+ }
+
+ return this;
+ }
+
+ }
+
+ private static final class AlmProjectMapping {
+ private final String projectUuid;
+ private final String githubSlug;
+ private final String url;
+ private final Long createdAt;
+ private final Long updatedAt;
+
+ AlmProjectMapping(@Nullable String projectUuid, @Nullable String githubSlug, @Nullable String url, @Nullable Long createdAt, @Nullable Long updatedAt) {
+ this.projectUuid = projectUuid;
+ this.githubSlug = githubSlug;
+ this.url = url;
+ this.createdAt = createdAt;
+ this.updatedAt = updatedAt;
+ }
+ }
+}
import com.google.common.collect.ImmutableList;
import java.io.ByteArrayInputStream;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.mockito.ArgumentCaptor;
import org.sonar.api.resources.Scopes;
import org.sonar.api.utils.System2;
import org.sonar.core.util.CloseableIterator;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
+import org.sonar.db.alm.ALM;
import org.sonar.db.ce.CeActivityDto;
import org.sonar.db.ce.CeQueueDto;
import org.sonar.db.ce.CeQueueDto.Status;
import org.sonar.db.component.ComponentDbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting;
-import org.sonar.db.component.SnapshotDto;
import org.sonar.db.issue.IssueDto;
import org.sonar.db.measure.MeasureDto;
import org.sonar.db.measure.custom.CustomMeasureDto;
assertThat(dbClient.projectMappingsDao().get(dbSession, "a.key.type", "another.key")).isNotEmpty();
}
+ @Test
+ public void deleteProject_deletes_alm_project_mappings() {
+ ALM alm = ALM.GITHUB;
+ String repoId = "123";
+ String otherRepoId = repoId + "-foo";
+
+ ComponentDto project = dbTester.components().insertPublicProject();
+ dbClient.almProjectMappingsDao().insertOrUpdate(dbSession, alm, repoId, project.uuid(), null, "foo");
+ dbClient.almProjectMappingsDao().insertOrUpdate(dbSession, alm, otherRepoId, "D2", null, "bar");
+
+ underTest.deleteProject(dbSession, project.uuid());
+
+ assertThat(dbClient.almProjectMappingsDao().mappingExists(dbSession, alm, repoId)).isFalse();
+ assertThat(dbClient.almProjectMappingsDao().mappingExists(dbSession, alm, otherRepoId)).isTrue();
+ }
+
@Test
public void deleteNonRootComponents_has_no_effect_when_parameter_is_empty() {
DbSession dbSession = mock(DbSession.class);
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.v73;
+
+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.BigIntegerColumnDef;
+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.MAX_SIZE;
+import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.UUID_SIZE;
+import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder;
+
+public class CreateAlmProjectMappingsTable extends DdlChange {
+
+ private static final String TABLE_NAME = "alm_project_mappings";
+
+ private static final VarcharColumnDef UUID = newVarcharColumnDefBuilder()
+ .setColumnName("uuid")
+ .setLimit(UUID_SIZE)
+ .setIsNullable(false)
+ .build();
+ private static final VarcharColumnDef ALM_ID_COLUMN = newVarcharColumnDefBuilder()
+ .setColumnName("alm_id")
+ .setIsNullable(false)
+ .setLimit(40)
+ .build();
+ private static final VarcharColumnDef REPO_ID_COLUMN = newVarcharColumnDefBuilder()
+ .setColumnName("repo_id")
+ .setIsNullable(false)
+ .setLimit(256)
+ .build();
+ private static final VarcharColumnDef PROJECT_UUID_COLUMN = newVarcharColumnDefBuilder()
+ .setColumnName("project_uuid")
+ .setIsNullable(false)
+ .setLimit(40)
+ .build();
+ private static final VarcharColumnDef GITHUB_SLUG_COLUMN = newVarcharColumnDefBuilder()
+ .setColumnName("github_slug")
+ .setIsNullable(true)
+ .setLimit(256)
+ .build();
+ private static final VarcharColumnDef URL_COLUMN = newVarcharColumnDefBuilder()
+ .setColumnName("url")
+ .setIsNullable(false)
+ .setLimit(2000)
+ .build();
+ private static final BigIntegerColumnDef CREATED_AT_COLUMN = newBigIntegerColumnDefBuilder()
+ .setColumnName("created_at")
+ .setIsNullable(false)
+ .build();
+ private static final BigIntegerColumnDef UPDATED_AT_COLUMN = newBigIntegerColumnDefBuilder()
+ .setColumnName("updated_at")
+ .setIsNullable(false)
+ .build();
+
+ public CreateAlmProjectMappingsTable(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+
+ if (!tableExists()) {
+ context.execute(new CreateTableBuilder(getDialect(), TABLE_NAME)
+ .addPkColumn(UUID)
+ .addColumn(ALM_ID_COLUMN)
+ .addColumn(REPO_ID_COLUMN)
+ .addColumn(PROJECT_UUID_COLUMN)
+ .addColumn(GITHUB_SLUG_COLUMN)
+ .addColumn(URL_COLUMN)
+ .addColumn(CREATED_AT_COLUMN)
+ .addColumn(UPDATED_AT_COLUMN)
+ .build());
+
+ context.execute(new CreateIndexBuilder(getDialect())
+ .addColumn(ALM_ID_COLUMN)
+ .addColumn(REPO_ID_COLUMN)
+ .setUnique(true)
+ .setTable(TABLE_NAME)
+ .setName(TABLE_NAME + "_alm_repo")
+ .build());
+ context.execute(new CreateIndexBuilder(getDialect())
+ .addColumn(PROJECT_UUID_COLUMN)
+ .setUnique(true)
+ .setTable(TABLE_NAME)
+ .setName(TABLE_NAME + "_project")
+ .build());
+ }
+ }
+
+ private boolean tableExists() throws SQLException {
+ try (Connection connection = getDatabase().getDataSource().getConnection()) {
+ return DatabaseUtils.tableExists(TABLE_NAME, connection);
+ }
+ }
+}
.add(2210, "Add 'securityhotspotadmin' permission to templates characteristics already having 'issueadmin'", PopulateHotspotAdminPermissionOnTemplatesCharacteristics.class)
.add(2211, "Set SUBSCRIPTION not nullable in ORGANIZATIONS", SetSubscriptionOnOrganizationsNotNullable.class)
.add(2212, "Add index on ORGANIZATION_MEMBERS", AddIndexOnOrganizationMembers.class)
+ .add(2213, "Create table to store alm project mappings", CreateAlmProjectMappingsTable.class)
;
}
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.v73;
+
+import java.sql.SQLException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.db.CoreDbTester;
+
+import static java.sql.Types.BIGINT;
+import static java.sql.Types.VARCHAR;
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class CreateAlmProjectMappingsTableTest {
+
+ private static final String TABLE = "alm_project_mappings";
+
+ @Rule
+ public final CoreDbTester db = CoreDbTester.createForSchema(CreateAlmProjectMappingsTableTest.class, "empty.sql");
+
+ private CreateAlmProjectMappingsTable underTest = new CreateAlmProjectMappingsTable(db.database());
+
+ @Test
+ public void creates_table_on_empty_db() throws SQLException {
+ underTest.execute();
+
+ checkTable();
+ }
+
+ @Test
+ public void migration_is_reentrant() throws SQLException {
+ underTest.execute();
+ underTest.execute();
+
+ checkTable();
+ }
+
+ private void checkTable() {
+ assertThat(db.countRowsOfTable(TABLE)).isEqualTo(0);
+
+ db.assertColumnDefinition(TABLE, "uuid", VARCHAR, 40, false);
+ db.assertPrimaryKey(TABLE, "pk_" + TABLE, "uuid");
+ db.assertColumnDefinition(TABLE, "alm_id", VARCHAR, 40, false);
+ db.assertColumnDefinition(TABLE, "repo_id", VARCHAR, 256, false);
+ db.assertColumnDefinition(TABLE, "project_uuid", VARCHAR, 40, false);
+ db.assertColumnDefinition(TABLE, "github_slug", VARCHAR, 256, true);
+ db.assertColumnDefinition(TABLE, "url", VARCHAR, 2000, false);
+ db.assertColumnDefinition(TABLE, "created_at", BIGINT, null, false);
+ db.assertColumnDefinition(TABLE, "updated_at", BIGINT, null, false);
+
+ db.assertUniqueIndex(TABLE, TABLE + "_alm_repo", "alm_id", "repo_id");
+ db.assertUniqueIndex(TABLE, TABLE + "_project", "project_uuid");
+ }
+}