aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java1
-rw-r--r--server/sonar-db-core/src/main/java/org/sonar/db/version/SqTables.java1
-rw-r--r--server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl12
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java2
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java7
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java4
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/mapping/ProjectMappingDto.java65
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/mapping/ProjectMappingsDao.java79
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/mapping/ProjectMappingsMapper.java33
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeCommands.java7
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeDao.java1
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java2
-rw-r--r--server/sonar-db-dao/src/main/resources/org/sonar/db/mapping/ProjectMappingsMapper.xml45
-rw-r--r--server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml4
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/DaoModuleTest.java2
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/mapping/ProjectMappingsDaoTest.java249
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeDaoTest.java12
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v72/CreateProjectMappingsTable.java103
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v72/DbVersion72.java1
-rw-r--r--server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/CreateProjectMappingsTableTest.java67
-rw-r--r--server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/DbVersion72Test.java2
-rw-r--r--server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v72/CreateProjectMappingsTableTest/empty.sql0
22 files changed, 697 insertions, 2 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 819fb4bd472..52c53b1dbb3 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
@@ -120,6 +120,7 @@ public class ComputeEngineContainerImplTest {
COMPONENTS_IN_LEVEL_1_AT_CONSTRUCTION
+ 27 // level 1
+ 54 // content of DaoModule
+ + 55 // content of DaoModule
+ 3 // content of EsModule
+ 59 // 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 cf7e5586769..f33d7f5f575 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
@@ -87,6 +87,7 @@ public final class SqTables {
"projects",
"project_branches",
"project_links",
+ "project_mappings",
"project_measures",
"project_qprofiles",
"properties",
diff --git a/server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl b/server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl
index 2ebc5a39f71..dd2e3a3317e 100644
--- a/server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl
+++ b/server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl
@@ -797,3 +797,15 @@ CREATE TABLE "ALM_APP_INSTALLS" (
);
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 "PROJECT_MAPPINGS" (
+ "UUID" VARCHAR(40) NOT NULL PRIMARY KEY,
+ "KEY_TYPE" VARCHAR(200) NOT NULL,
+ "KEE" VARCHAR(4000) NOT NULL,
+ "PROJECT_UUID" VARCHAR(40) NOT NULL,
+ "CREATED_AT" BIGINT NOT NULL,
+ CONSTRAINT "PK_PROJECT_MAPPINGS" PRIMARY KEY ("UUID")
+);
+CREATE UNIQUE INDEX "KEY_TYPE_KEE" ON "PROJECT_MAPPINGS" ("KEY_TYPE", "KEE");
+CREATE INDEX "PROJECT_UUID" ON "PROJECT_MAPPINGS" ("PROJECT_UUID");
+
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 a7aeef31af0..ff37086215a 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
@@ -40,6 +40,7 @@ import org.sonar.db.event.EventDao;
import org.sonar.db.issue.IssueChangeDao;
import org.sonar.db.issue.IssueDao;
import org.sonar.db.alm.AlmAppInstallDao;
+import org.sonar.db.mapping.ProjectMappingsDao;
import org.sonar.db.measure.LiveMeasureDao;
import org.sonar.db.measure.MeasureDao;
import org.sonar.db.measure.custom.CustomMeasureDao;
@@ -117,6 +118,7 @@ public class DaoModule extends Module {
PermissionTemplateDao.class,
PluginDao.class,
ProjectLinkDao.class,
+ ProjectMappingsDao.class,
ProjectQgateAssociationDao.class,
PropertiesDao.class,
PurgeDao.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 99732f30f36..31d0465dcd4 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
@@ -38,6 +38,7 @@ import org.sonar.db.event.EventDao;
import org.sonar.db.issue.IssueChangeDao;
import org.sonar.db.issue.IssueDao;
import org.sonar.db.alm.AlmAppInstallDao;
+import org.sonar.db.mapping.ProjectMappingsDao;
import org.sonar.db.measure.LiveMeasureDao;
import org.sonar.db.measure.MeasureDao;
import org.sonar.db.measure.custom.CustomMeasureDao;
@@ -136,6 +137,7 @@ public class DbClient {
private final LiveMeasureDao liveMeasureDao;
private final WebhookDao webhookDao;
private final WebhookDeliveryDao webhookDeliveryDao;
+ private final ProjectMappingsDao projectMappingsDao;
public DbClient(Database database, MyBatis myBatis, DBSessions dbSessions, Dao... daos) {
this.database = database;
@@ -200,6 +202,7 @@ public class DbClient {
liveMeasureDao = getDao(map, LiveMeasureDao.class);
webhookDao = getDao(map, WebhookDao.class);
webhookDeliveryDao = getDao(map, WebhookDeliveryDao.class);
+ projectMappingsDao = getDao(map, ProjectMappingsDao.class);
}
public DbSession openSession(boolean batch) {
@@ -435,4 +438,8 @@ public class DbClient {
public WebhookDeliveryDao webhookDeliveryDao() {
return webhookDeliveryDao;
}
+
+ public ProjectMappingsDao projectMappingsDao() {
+ return projectMappingsDao;
+ }
}
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 bbd97e3fcfa..82967d9b259 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
@@ -63,6 +63,8 @@ import org.sonar.db.issue.IssueChangeMapper;
import org.sonar.db.issue.IssueDto;
import org.sonar.db.issue.IssueMapper;
import org.sonar.db.issue.ShortBranchIssueDto;
+import org.sonar.db.mapping.ProjectMappingDto;
+import org.sonar.db.mapping.ProjectMappingsMapper;
import org.sonar.db.measure.LiveMeasureMapper;
import org.sonar.db.measure.MeasureDto;
import org.sonar.db.measure.MeasureMapper;
@@ -176,6 +178,7 @@ public class MyBatis implements Startable {
confBuilder.loadAlias("PermissionTemplateUser", PermissionTemplateUserDto.class);
confBuilder.loadAlias("Plugin", PluginDto.class);
confBuilder.loadAlias("ProjectQgateAssociation", ProjectQgateAssociationDto.class);
+ confBuilder.loadAlias("ProjectMapping", ProjectMappingDto.class);
confBuilder.loadAlias("PurgeableAnalysis", PurgeableAnalysisDto.class);
confBuilder.loadAlias("QualityGateCondition", QualityGateConditionDto.class);
confBuilder.loadAlias("QualityGate", QualityGateDto.class);
@@ -232,6 +235,7 @@ public class MyBatis implements Startable {
PermissionTemplateCharacteristicMapper.class,
PermissionTemplateMapper.class,
PluginMapper.class,
+ ProjectMappingsMapper.class,
ProjectQgateAssociationMapper.class,
PropertiesMapper.class,
PurgeMapper.class,
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/mapping/ProjectMappingDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/mapping/ProjectMappingDto.java
new file mode 100644
index 00000000000..7c1bd12c4c2
--- /dev/null
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/mapping/ProjectMappingDto.java
@@ -0,0 +1,65 @@
+/*
+ * 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.mapping;
+
+/**
+ * Generic purpose way to attach data to a project. For example to store the identifier
+ * of the project in a remote system (ALM).
+ * The pair (keyType, key) is unique.
+ * Data is automatically purged when project is deleted.
+ */
+public final class ProjectMappingDto {
+ private String uuid;
+ private String keyType;
+ private String key;
+ private String projectUuid;
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ public void setUuid(String uuid) {
+ this.uuid = uuid;
+ }
+
+ public String getKeyType() {
+ return keyType;
+ }
+
+ public void setKeyType(String keyType) {
+ this.keyType = keyType;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ public String getProjectUuid() {
+ return projectUuid;
+ }
+
+ public void setProjectUuid(String projectUuid) {
+ this.projectUuid = projectUuid;
+ }
+}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/mapping/ProjectMappingsDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/mapping/ProjectMappingsDao.java
new file mode 100644
index 00000000000..bf9a728fd1b
--- /dev/null
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/mapping/ProjectMappingsDao.java
@@ -0,0 +1,79 @@
+/*
+ * 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.mapping;
+
+import java.util.Optional;
+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 ProjectMappingsDao implements Dao {
+
+ private final System2 system2;
+ private final UuidFactory uuidFactory;
+
+ public ProjectMappingsDao(System2 system2, UuidFactory uuidFactory) {
+ this.system2 = system2;
+ this.uuidFactory = uuidFactory;
+ }
+
+ public void put(DbSession dbSession, String keyType, String key, String projectUuid) {
+ checkKeyType(keyType);
+ checkKey(key);
+ checkArgument(isNotEmpty(projectUuid), "projectUuid can't be null nor empty");
+
+ ProjectMappingsMapper mapper = getMapper(dbSession);
+ mapper.deleteByKey(keyType, key);
+ long now = system2.now();
+ mapper.put(uuidFactory.create(), keyType, key, projectUuid, now);
+ }
+
+ public Optional<ProjectMappingDto> get(DbSession dbSession, String keyType, String key) {
+ checkKeyType(keyType);
+ checkKey(key);
+
+ ProjectMappingsMapper mapper = getMapper(dbSession);
+ return Optional.ofNullable(mapper.selectByKey(keyType, key));
+ }
+
+ public void clear(DbSession dbSession, String keyType, String key) {
+ checkKeyType(keyType);
+ checkKey(key);
+ ProjectMappingsMapper mapper = getMapper(dbSession);
+ mapper.deleteByKey(keyType, key);
+ }
+
+ private static void checkKeyType(@Nullable String keyType) {
+ checkArgument(keyType != null && !keyType.isEmpty(), "key type can't be null nor empty");
+ }
+
+ private static void checkKey(@Nullable String key) {
+ checkArgument(key != null && !key.isEmpty(), "key can't be null nor empty");
+ }
+
+ private static ProjectMappingsMapper getMapper(DbSession dbSession) {
+ return dbSession.getMapper(ProjectMappingsMapper.class);
+ }
+}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/mapping/ProjectMappingsMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/mapping/ProjectMappingsMapper.java
new file mode 100644
index 00000000000..c59db398b8d
--- /dev/null
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/mapping/ProjectMappingsMapper.java
@@ -0,0 +1,33 @@
+/*
+ * 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.mapping;
+
+import javax.annotation.CheckForNull;
+import org.apache.ibatis.annotations.Param;
+
+public interface ProjectMappingsMapper {
+
+ @CheckForNull
+ ProjectMappingDto selectByKey(@Param("keyType") String keyType, @Param("key") String key);
+
+ void put(@Param("uuid") String uuid, @Param("keyType") String keyType, @Param("key") String key, @Param("projectUuid") String projectUuid, @Param("createdAt") long createdAt);
+
+ void deleteByKey(@Param("keyType") String keyType, @Param("key") String key);
+}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeCommands.java b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeCommands.java
index 4e346364ee9..bab365e9f53 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeCommands.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeCommands.java
@@ -291,6 +291,13 @@ class PurgeCommands {
profiler.stop();
}
+ void deleteProjectMappings(String rootUuid) {
+ profiler.start("deleteProjectMappings (project_mappings)");
+ purgeMapper.deleteProjectMappingsByProjectUuid(rootUuid);
+ session.commit();
+ profiler.stop();
+ }
+
void deleteBranch(String rootUuid) {
profiler.start("deleteBranch (project_branches)");
purgeMapper.deleteBranchByUuid(rootUuid);
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeDao.java
index 0d6a2d09d91..1270cdde241 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeDao.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeDao.java
@@ -202,6 +202,7 @@ public class PurgeDao implements Dao {
commands.deleteCeActivity(rootUuid);
commands.deleteCeQueue(rootUuid);
commands.deleteWebhookDeliveries(rootUuid);
+ commands.deleteProjectMappings(rootUuid);
commands.deleteBranch(rootUuid);
commands.deleteLiveMeasures(rootUuid);
}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java
index a9dec7bb5b2..bbf0be4b2d2 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java
@@ -108,6 +108,8 @@ public interface PurgeMapper {
void deleteWebhookDeliveriesByProjectUuid(@Param("projectUuid") String projectUuid);
+ void deleteProjectMappingsByProjectUuid(@Param("projectUuid") String projectUuid);
+
void deleteBranchByUuid(@Param("uuid") String uuid);
void deleteLiveMeasuresByProjectUuid(@Param("projectUuid") String projectUuid);
diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/mapping/ProjectMappingsMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/mapping/ProjectMappingsMapper.xml
new file mode 100644
index 00000000000..551eda2c4e1
--- /dev/null
+++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/mapping/ProjectMappingsMapper.xml
@@ -0,0 +1,45 @@
+<?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.mapping.ProjectMappingsMapper">
+
+ <select id="selectByKey" parameterType="Map" resultType="ProjectMapping">
+ select
+ uuid as "uuid",
+ key_type as "key_type",
+ kee as "key",
+ project_uuid as projectUuid
+ from
+ project_mappings
+ where
+ key_type = #{keyType, jdbcType=VARCHAR}
+ and kee = #{key, jdbcType=VARCHAR}
+ </select>
+
+ <insert id="put" parameterType="Map" useGeneratedKeys="false">
+ INSERT INTO project_mappings
+ (
+ uuid,
+ key_type,
+ kee,
+ project_uuid,
+ created_at
+ )
+ VALUES (
+ #{uuid,jdbcType=VARCHAR},
+ #{keyType,jdbcType=VARCHAR},
+ #{key,jdbcType=VARCHAR},
+ #{projectUuid,jdbcType=VARCHAR},
+ #{createdAt,jdbcType=BIGINT}
+ )
+ </insert>
+
+ <delete id="deleteByKey" parameterType="Map">
+ delete from project_mappings
+ where
+ key_type=#{keyType,jdbcType=VARCHAR}
+ and kee=#{key,jdbcType=VARCHAR}
+ </delete>
+
+
+</mapper>
diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml
index b8af25a7598..b1657baf79b 100644
--- a/server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml
+++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml
@@ -360,6 +360,10 @@
delete from webhook_deliveries where component_uuid=#{projectUuid,jdbcType=VARCHAR}
</delete>
+ <delete id="deleteProjectMappingsByProjectUuid">
+ delete from project_mappings where project_uuid=#{projectUuid,jdbcType=VARCHAR}
+ </delete>
+
<delete id="deleteBranchByUuid">
delete from project_branches where uuid=#{uuid,jdbcType=VARCHAR}
</delete>
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 213eeb67ccb..60d417966bd 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 + 54);
+ assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 55);
}
}
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/mapping/ProjectMappingsDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/mapping/ProjectMappingsDaoTest.java
new file mode 100644
index 00000000000..eeca63b8358
--- /dev/null
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/mapping/ProjectMappingsDaoTest.java
@@ -0,0 +1,249 @@
+/*
+ * 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.mapping;
+
+import java.util.Map;
+import java.util.Objects;
+import javax.annotation.CheckForNull;
+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.SequenceUuidFactory;
+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;
+
+public class ProjectMappingsDaoTest {
+
+ private static final String EMPTY_STRING = "";
+ private static final String A_KEY_TYPE = "a_key_type";
+ private static final String A_KEY = "a_key";
+ private static final String ANOTHER_KEY = "another_key";
+ private static final long DATE = 1_600_000_000_000L;
+ private static final String PROJECT_UUID = "123456789";
+ private static final String OTHER_PROJECT_UUID = "987654321";
+
+ 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 ProjectMappingsDao underTest = new ProjectMappingsDao(system2, new SequenceUuidFactory());
+
+ @Test
+ public void put_throws_IAE_if_key_type_is_null() {
+ expectKeyTypeNullOrEmptyIAE();
+
+ underTest.put(dbSession, null, A_KEY, PROJECT_UUID);
+ }
+
+ @Test
+ public void put_throws_IAE_if_key_is_null() {
+ expectKeyNullOrEmptyIAE();
+
+ underTest.put(dbSession, A_KEY_TYPE, null, PROJECT_UUID);
+ }
+
+ @Test
+ public void put_throws_IAE_if_key_is_empty() {
+ expectKeyNullOrEmptyIAE();
+
+ underTest.put(dbSession, A_KEY_TYPE, EMPTY_STRING, PROJECT_UUID);
+ }
+
+ @Test
+ public void save_throws_IAE_if_project_uuid_is_null() {
+ expectValueNullOrEmptyIAE();
+
+ underTest.put(dbSession, A_KEY_TYPE, A_KEY, null);
+ }
+
+ @Test
+ public void put_throws_IAE_if_project_uuid_is_empty() {
+ expectValueNullOrEmptyIAE();
+
+ underTest.put(dbSession, A_KEY_TYPE, A_KEY, EMPTY_STRING);
+ }
+
+ @Test
+ public void put() {
+ when(system2.now()).thenReturn(DATE);
+ underTest.put(dbSession, A_KEY_TYPE, A_KEY, PROJECT_UUID);
+
+ assertThatProjectMapping(A_KEY_TYPE, A_KEY)
+ .hasProjectUuid(PROJECT_UUID)
+ .hasCreatedAt(DATE);
+ }
+
+ @Test
+ public void clear() {
+ when(system2.now()).thenReturn(DATE);
+ underTest.put(dbSession, A_KEY_TYPE, A_KEY, PROJECT_UUID);
+
+ assertThatProjectMapping(A_KEY_TYPE, A_KEY)
+ .hasProjectUuid(PROJECT_UUID)
+ .hasCreatedAt(DATE);
+
+ underTest.clear(dbSession, A_KEY_TYPE, A_KEY);
+
+ assertThat(underTest.get(dbSession, A_KEY_TYPE, A_KEY)).isEmpty();
+ }
+
+ @Test
+ public void putMultiple() {
+ when(system2.now()).thenReturn(DATE);
+ underTest.put(dbSession, A_KEY_TYPE, A_KEY, PROJECT_UUID);
+ underTest.put(dbSession, A_KEY_TYPE, ANOTHER_KEY, OTHER_PROJECT_UUID);
+
+ assertThatProjectMapping(A_KEY_TYPE, A_KEY)
+ .hasProjectUuid(PROJECT_UUID)
+ .hasCreatedAt(DATE);
+
+ assertThatProjectMapping(A_KEY_TYPE, ANOTHER_KEY)
+ .hasProjectUuid(OTHER_PROJECT_UUID)
+ .hasCreatedAt(DATE);
+ }
+
+ @Test
+ public void get_throws_IAE_when_key_type_is_null() {
+ expectKeyTypeNullOrEmptyIAE();
+
+ underTest.get(dbSession, null, A_KEY);
+ }
+
+ @Test
+ public void get_throws_IAE_when_key_is_null() {
+ expectKeyNullOrEmptyIAE();
+
+ underTest.get(dbSession, A_KEY_TYPE, null);
+ }
+
+ @Test
+ public void get_throws_IAE_when_key_is_empty() {
+ expectKeyNullOrEmptyIAE();
+
+ underTest.get(dbSession, A_KEY_TYPE, EMPTY_STRING);
+ }
+
+ @Test
+ public void get_returns_empty_optional_when_mapping_does_not_exist_in_DB() {
+ assertThat(underTest.get(dbSession, A_KEY_TYPE, A_KEY)).isEmpty();
+ }
+
+ @Test
+ public void get_returns_project_uuid_when_mapping_has_project_uuid_stored() {
+ underTest.put(dbSession, A_KEY_TYPE, A_KEY, PROJECT_UUID);
+
+ assertThat(underTest.get(dbSession, A_KEY_TYPE, A_KEY).get().getProjectUuid()).isEqualTo(PROJECT_UUID);
+ }
+
+ private void expectKeyTypeNullOrEmptyIAE() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("key type can't be null nor empty");
+ }
+
+ private void expectKeyNullOrEmptyIAE() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("key can't be null nor empty");
+ }
+
+ private void expectValueNullOrEmptyIAE() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("projectUuid can't be null nor empty");
+ }
+
+ private ProjectMappingAssert assertThatProjectMapping(String keyType, String key) {
+ return new ProjectMappingAssert(dbTester, dbSession, keyType, key);
+ }
+
+ private static class ProjectMappingAssert extends AbstractAssert<ProjectMappingAssert, ProjectMapping> {
+
+ private ProjectMappingAssert(DbTester dbTester, DbSession dbSession, String internalMappingKeyType, String internalMappingKey) {
+ super(asProjectMapping(dbTester, dbSession, internalMappingKeyType, internalMappingKey), ProjectMappingAssert.class);
+ }
+
+ private static ProjectMapping asProjectMapping(DbTester dbTester, DbSession dbSession, String projectMappingKeyType, String projectMappingKey) {
+ Map<String, Object> row = dbTester.selectFirst(
+ dbSession,
+ "select" +
+ " project_uuid as \"projectUuid\", created_at as \"createdAt\"" +
+ " from project_mappings" +
+ " where key_type='"+projectMappingKeyType+"' and kee='" + projectMappingKey + "'");
+ return new ProjectMapping(
+ (String) row.get("projectUuid"),
+ (Long) row.get("createdAt"));
+ }
+
+ public void doesNotExist() {
+ isNull();
+ }
+
+
+ public ProjectMappingAssert hasProjectUuid(String expected) {
+ isNotNull();
+
+ if (!Objects.equals(actual.getProjectUuid(), expected)) {
+ failWithMessage("Expected Internal mapping to have column VALUE to be <%s> but was <%s>", true, actual.getProjectUuid());
+ }
+ return this;
+ }
+
+ public ProjectMappingAssert hasCreatedAt(long expected) {
+ isNotNull();
+
+ if (!Objects.equals(actual.getCreatedAt(), expected)) {
+ failWithMessage("Expected Internal mapping to have column CREATED_AT to be <%s> but was <%s>", expected, actual.getCreatedAt());
+ }
+
+ return this;
+ }
+
+ }
+
+ private static final class ProjectMapping {
+ private final String projectUuid;
+ private final Long createdAt;
+
+ public ProjectMapping(@Nullable String projectUuid, @Nullable Long createdAt) {
+ this.projectUuid = projectUuid;
+ this.createdAt = createdAt;
+ }
+
+ @CheckForNull
+ public String getProjectUuid() {
+ return projectUuid;
+ }
+
+ @CheckForNull
+ public Long getCreatedAt() {
+ return createdAt;
+ }
+ }
+}
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeDaoTest.java
index 6ef07206f31..c2ba89ca811 100644
--- a/server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeDaoTest.java
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeDaoTest.java
@@ -533,6 +533,18 @@ public class PurgeDaoTest {
}
@Test
+ public void deleteProject_deletes_project_mappings() {
+ ComponentDto project = dbTester.components().insertPublicProject();
+ dbClient.projectMappingsDao().put(dbSession, "a.key.type", "a.key", project.uuid());
+ dbClient.projectMappingsDao().put(dbSession, "a.key.type", "another.key", "D2");
+
+ underTest.deleteProject(dbSession, project.uuid());
+
+ assertThat(dbClient.projectMappingsDao().get(dbSession, "a.key.type", "a.key")).isEmpty();
+ assertThat(dbClient.projectMappingsDao().get(dbSession, "a.key.type", "another.key")).isNotEmpty();
+ }
+
+ @Test
public void deleteNonRootComponents_has_no_effect_when_parameter_is_empty() {
DbSession dbSession = mock(DbSession.class);
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v72/CreateProjectMappingsTable.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v72/CreateProjectMappingsTable.java
new file mode 100644
index 00000000000..0417cb1c877
--- /dev/null
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v72/CreateProjectMappingsTable.java
@@ -0,0 +1,103 @@
+/*
+ * 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.v72;
+
+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.newVarcharColumnDefBuilder;
+
+public class CreateProjectMappingsTable extends DdlChange {
+
+ private static final String TABLE_NAME = "project_mappings";
+
+ private static final VarcharColumnDef UUID_COLUMN = VarcharColumnDef.newVarcharColumnDefBuilder()
+ .setColumnName("uuid")
+ .setIsNullable(false)
+ .setLimit(VarcharColumnDef.UUID_SIZE)
+ .build();
+ private static final VarcharColumnDef KEY_TYPE_COLUMN = newVarcharColumnDefBuilder()
+ .setColumnName("key_type")
+ .setIsNullable(false)
+ .setLimit(200)
+ .build();
+ private static final VarcharColumnDef KEE_COLUMN = newVarcharColumnDefBuilder()
+ .setColumnName("kee")
+ .setIsNullable(false)
+ .setLimit(MAX_SIZE)
+ .build();
+ private static final VarcharColumnDef PROJECT_UUID = VarcharColumnDef.newVarcharColumnDefBuilder()
+ .setColumnName("project_uuid")
+ .setIsNullable(false)
+ .setLimit(VarcharColumnDef.UUID_SIZE)
+ .build();
+ private static final BigIntegerColumnDef CREATED_AT_COLUMN = newBigIntegerColumnDefBuilder()
+ .setColumnName("created_at")
+ .setIsNullable(false)
+ .build();
+
+ public CreateProjectMappingsTable(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+
+ if (!tableExists()) {
+ context.execute(new CreateTableBuilder(getDialect(), TABLE_NAME)
+ .addPkColumn(UUID_COLUMN)
+ .addColumn(KEY_TYPE_COLUMN)
+ .addColumn(KEE_COLUMN)
+ .addColumn(PROJECT_UUID)
+ .addColumn(CREATED_AT_COLUMN)
+ .build());
+
+ context.execute(new CreateIndexBuilder(getDialect())
+ .addColumn(KEY_TYPE_COLUMN)
+ .addColumn(KEE_COLUMN)
+ .setUnique(true)
+ .setTable(TABLE_NAME)
+ .setName("key_type_kee")
+ .build());
+
+ context.execute(new CreateIndexBuilder(getDialect())
+ .addColumn(PROJECT_UUID)
+ .setUnique(false)
+ .setTable(TABLE_NAME)
+ .setName("project_uuid")
+ .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/v72/DbVersion72.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v72/DbVersion72.java
index 803381a4234..8400eb1a14e 100644
--- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v72/DbVersion72.java
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v72/DbVersion72.java
@@ -33,6 +33,7 @@ public class DbVersion72 implements DbVersion {
.add(2103, "Add isExternal boolean to rules", AddRuleExternal.class)
.add(2104, "Create ALM_APP_INSTALLS table", CreateAlmAppInstallsTable.class)
.add(2105, "Add LINE_HASHES_VERSION to table FILE_SOURCES", AddLineHashesVersionToFileSources.class)
+ .add(2106, "Create PROJECT_MAPPINGS table", CreateProjectMappingsTable.class)
;
}
}
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/CreateProjectMappingsTableTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/CreateProjectMappingsTableTest.java
new file mode 100644
index 00000000000..19f3d6bbfd8
--- /dev/null
+++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/CreateProjectMappingsTableTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.v72;
+
+import java.sql.SQLException;
+import java.sql.Types;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.db.CoreDbTester;
+
+import static java.sql.Types.VARCHAR;
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class CreateProjectMappingsTableTest {
+
+ private static final String TABLE = "project_mappings";
+
+ @Rule
+ public final CoreDbTester db = CoreDbTester.createForSchema(CreateProjectMappingsTableTest.class, "empty.sql");
+
+ private CreateProjectMappingsTable underTest = new CreateProjectMappingsTable(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() {
+ db.assertColumnDefinition(TABLE, "uuid", Types.VARCHAR, 40, false);
+ db.assertColumnDefinition(TABLE, "key_type", VARCHAR, 200, false);
+ db.assertColumnDefinition(TABLE, "kee", VARCHAR, 4000, false);
+ db.assertColumnDefinition(TABLE, "project_uuid", Types.VARCHAR, 40, false);
+ db.assertColumnDefinition(TABLE, "created_at", Types.BIGINT, 20, false);
+
+ db.assertUniqueIndex(TABLE, "key_type_kee", "key_type", "kee");
+ db.assertIndex(TABLE, "project_uuid", "project_uuid");
+ assertThat(db.countRowsOfTable(TABLE)).isEqualTo(0);
+ }
+}
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/DbVersion72Test.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/DbVersion72Test.java
index eb251a545de..1cb135035ac 100644
--- a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/DbVersion72Test.java
+++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/DbVersion72Test.java
@@ -34,7 +34,7 @@ public class DbVersion72Test {
@Test
public void verify_migration_count() {
- verifyMigrationCount(underTest, 6);
+ verifyMigrationCount(underTest, 7);
}
}
diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v72/CreateProjectMappingsTableTest/empty.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v72/CreateProjectMappingsTableTest/empty.sql
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v72/CreateProjectMappingsTableTest/empty.sql