assertThat(picoContainer.getParent().getParent().getParent().getComponentAdapters()).hasSize(
COMPONENTS_IN_LEVEL_1_AT_CONSTRUCTION
+ 26 // level 1
- + 53 // content of DaoModule
+ + 54 // content of DaoModule
+ 3 // content of EsModule
+ 59 // content of CorePropertyDefinitions
+ 1 // StopFlagContainer
public static final Set<String> TABLES = unmodifiableSet(new HashSet<>(asList(
"active_rules",
"active_rule_parameters",
+ "alm_app_installs",
"analysis_properties",
"ce_activity",
"ce_queue",
CREATE INDEX "COMPONENT_UUID" ON "WEBHOOK_DELIVERIES" ("COMPONENT_UUID");
CREATE INDEX "CE_TASK_UUID" ON "WEBHOOK_DELIVERIES" ("CE_TASK_UUID");
CREATE INDEX "ANALYSIS_UUID" ON "WEBHOOK_DELIVERIES" ("ANALYSIS_UUID");
+
+CREATE TABLE "ALM_APP_INSTALLS" (
+ "UUID" VARCHAR(40) NOT NULL PRIMARY KEY,
+ "ALM_ID" VARCHAR(40) NOT NULL,
+ "OWNER_ID" VARCHAR(4000) NOT NULL,
+ "INSTALL_ID" VARCHAR(4000) NOT NULL,
+ "CREATED_AT" BIGINT NOT NULL,
+ "UPDATED_AT" BIGINT NOT NULL,
+ CONSTRAINT "PK_ALM_APP_INSTALLS" PRIMARY KEY ("UUID")
+);
+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");
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.measure.LiveMeasureDao;
import org.sonar.db.measure.MeasureDao;
import org.sonar.db.measure.custom.CustomMeasureDao;
GroupDao.class,
GroupMembershipDao.class,
GroupPermissionDao.class,
+ AlmAppInstallDao.class,
InternalPropertiesDao.class,
IssueChangeDao.class,
IssueDao.class,
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.measure.LiveMeasureDao;
import org.sonar.db.measure.MeasureDao;
import org.sonar.db.measure.custom.CustomMeasureDao;
private final OrganizationMemberDao organizationMemberDao;
private final QualityProfileDao qualityProfileDao;
private final PropertiesDao propertiesDao;
+ private final AlmAppInstallDao almAppInstallDao;
private final InternalPropertiesDao internalPropertiesDao;
private final SnapshotDao snapshotDao;
private final ComponentDao componentDao;
for (Dao dao : daos) {
map.put(dao.getClass(), dao);
}
+ almAppInstallDao = getDao(map, AlmAppInstallDao.class);
schemaMigrationDao = getDao(map, SchemaMigrationDao.class);
authorizationDao = getDao(map, AuthorizationDao.class);
organizationDao = getDao(map, OrganizationDao.class);
return database;
}
+ public AlmAppInstallDao almAppInstallDao() {
+ return almAppInstallDao;
+ }
+
public SchemaMigrationDao schemaMigrationDao() {
return schemaMigrationDao;
}
}
public WebhookDao webhookDao() {
- return webhookDao ;
+ return webhookDao;
}
public WebhookDeliveryDao webhookDeliveryDao() {
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.session.TransactionIsolationLevel;
import org.sonar.api.Startable;
+import org.sonar.db.alm.AlmAppInstallMapper;
import org.sonar.db.ce.CeActivityMapper;
import org.sonar.db.ce.CeQueueMapper;
import org.sonar.db.ce.CeScannerContextMapper;
Class<?>[] mappers = {
ActiveRuleMapper.class,
AnalysisPropertiesMapper.class,
+ AlmAppInstallMapper.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;
+import java.util.Objects;
+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;
+
+/**
+ * Store instances of installed app in external ALM like GitHub or Bitbucket Cloud.
+ */
+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;
+
+ public AlmAppInstallDao(System2 system2, UuidFactory uuidFactory) {
+ this.system2 = system2;
+ this.uuidFactory = uuidFactory;
+ }
+
+ /**
+ * @param alm Unique identifier of the ALM, like 'bitbucketcloud' or 'github', can't be null
+ * @param ownerId ALM specific identifier of the owner of the app, like team or user uuid for Bitbucket Cloud or organization id for Github, can't be null
+ * @param installId ALM specific identifier of the app installation, can't be null
+ */
+ public void insertOrUpdate(DbSession dbSession, ALM alm, String ownerId, String installId) {
+ checkAlm(alm);
+ checkOwnerId(ownerId);
+ checkArgument(isNotEmpty(installId), "installId can't be null nor empty");
+
+ AlmAppInstallMapper mapper = getMapper(dbSession);
+ long now = system2.now();
+
+ if (mapper.update(alm.getId(), ownerId, installId, now) == 0) {
+ mapper.insert(uuidFactory.create(), alm.getId(), ownerId, installId, now);
+ }
+ }
+
+ public Optional<String> getInstallId(DbSession dbSession, ALM alm, String ownerId) {
+ checkAlm(alm);
+ checkOwnerId(ownerId);
+
+ AlmAppInstallMapper mapper = getMapper(dbSession);
+ return Optional.ofNullable(mapper.selectInstallId(alm.getId(), ownerId));
+ }
+
+ private static void checkAlm(@Nullable ALM alm) {
+ Objects.requireNonNull(alm, "alm can't be null");
+ }
+
+ private static void checkOwnerId(@Nullable String ownerId) {
+ checkArgument(isNotEmpty(ownerId), "ownerId can't be null nor empty");
+ }
+
+ private static AlmAppInstallMapper getMapper(DbSession dbSession) {
+ return dbSession.getMapper(AlmAppInstallMapper.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.CheckForNull;
+import org.apache.ibatis.annotations.Param;
+
+public interface AlmAppInstallMapper {
+
+ @CheckForNull
+ String selectInstallId(@Param("almId") String almId, @Param("ownerId") String ownerId);
+
+ void insert(@Param("uuid") String uuid, @Param("almId") String almId, @Param("ownerId") String ownerId, @Param("installId") String installId, @Param("now") long now);
+
+ int update(@Param("almId") String almId, @Param("ownerId") String ownerId, @Param("installId") String installId, @Param("now") long now);
+
+}
--- /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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.db.alm;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
--- /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.AlmAppInstallMapper">
+
+ <select id="selectInstallId" parameterType="Map" resultType="String">
+ select
+ install_id as installId
+ from
+ alm_app_installs
+ where
+ alm_id = #{almId, jdbcType=VARCHAR}
+ and owner_id = #{ownerId, jdbcType=VARCHAR}
+ </select>
+
+ <insert id="insert" parameterType="Map" useGeneratedKeys="false">
+ INSERT INTO alm_app_installs
+ (
+ uuid,
+ alm_id,
+ owner_id,
+ install_id,
+ created_at,
+ updated_at
+ )
+ VALUES (
+ #{uuid, jdbcType=VARCHAR},
+ #{almId, jdbcType=VARCHAR},
+ #{ownerId, jdbcType=VARCHAR},
+ #{installId, jdbcType=VARCHAR},
+ #{now, jdbcType=BIGINT},
+ #{now, jdbcType=BIGINT}
+ )
+ </insert>
+
+ <update id="update" parameterType="map">
+ update alm_app_installs set
+ install_id = #{installId, jdbcType=VARCHAR},
+ updated_at = #{now, jdbcType=BIGINT}
+ where
+ alm_id = #{almId, jdbcType=VARCHAR}
+ and owner_id = #{ownerId, jdbcType=VARCHAR}
+ </update>
+
+ <delete id="deleteByOwnerId" parameterType="Map">
+ delete from alm_app_installs
+ where
+ alm_id = #{almId, jdbcType=VARCHAR}
+ and owner_id = #{ownerId, jdbcType=VARCHAR}
+ </delete>
+
+
+</mapper>
public void verify_count_of_added_components() {
ComponentContainer container = new ComponentContainer();
new DaoModule().configure(container);
- assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 53);
+ assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 54);
}
}
--- /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.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.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.AlmAppInstallDao.ALM.GITHUB;
+
+public class AlmAppInstallDaoTest {
+
+ private static final String A_UUID = "abcde1234";
+ private static final String A_UUID_2 = "xyz789";
+ private static final String EMPTY_STRING = "";
+ private static final String A_OWNER = "my_org_id";
+ private static final String ANOTHER_OWNER = "another_org";
+ private static final long DATE = 1_600_000_000_000L;
+ private static final long DATE_LATER = 1_700_000_000_000L;
+ private static final String AN_INSTALL = "some install id";
+ private static final String OTHER_INSTALL = "other install id";
+
+ 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 AlmAppInstallDao underTest = new AlmAppInstallDao(system2, uuidFactory);
+
+ @Test
+ public void insert_throws_NPE_if_alm_is_null() {
+ expectAlmNPE();
+
+ underTest.insertOrUpdate(dbSession, null, A_OWNER, AN_INSTALL);
+ }
+
+ @Test
+ public void insert_throws_IAE_if_owner_id_is_null() {
+ expectOwnerIdNullOrEmptyIAE();
+
+ underTest.insertOrUpdate(dbSession, GITHUB, null, AN_INSTALL);
+ }
+
+ @Test
+ public void insert_throws_IAE_if_owner_id_is_empty() {
+ expectOwnerIdNullOrEmptyIAE();
+
+ underTest.insertOrUpdate(dbSession, GITHUB, EMPTY_STRING, AN_INSTALL);
+ }
+
+ @Test
+ public void insert_throws_IAE_if_install_id_is_null() {
+ expectInstallIdNullOrEmptyIAE();
+
+ underTest.insertOrUpdate(dbSession, GITHUB, A_OWNER, null);
+ }
+
+ @Test
+ public void insert_throws_IAE_if_install_id_is_empty() {
+ expectInstallIdNullOrEmptyIAE();
+
+ underTest.insertOrUpdate(dbSession, GITHUB, A_OWNER, EMPTY_STRING);
+ }
+
+ @Test
+ public void insert() {
+ when(uuidFactory.create()).thenReturn(A_UUID);
+ when(system2.now()).thenReturn(DATE);
+ underTest.insertOrUpdate(dbSession, GITHUB, A_OWNER, AN_INSTALL);
+
+ assertThatAlmAppInstall(GITHUB, A_OWNER)
+ .hasInstallId(AN_INSTALL)
+ .hasCreatedAt(DATE)
+ .hasUpdatedAt(DATE);
+ }
+
+ @Test
+ public void update() {
+ when(uuidFactory.create()).thenReturn(A_UUID);
+ when(system2.now()).thenReturn(DATE);
+ underTest.insertOrUpdate(dbSession, GITHUB, A_OWNER, AN_INSTALL);
+
+ when(system2.now()).thenReturn(DATE_LATER);
+ underTest.insertOrUpdate(dbSession, GITHUB, A_OWNER, OTHER_INSTALL);
+
+ assertThatAlmAppInstall(GITHUB, A_OWNER)
+ .hasInstallId(OTHER_INSTALL)
+ .hasCreatedAt(DATE)
+ .hasUpdatedAt(DATE_LATER);
+ }
+
+ @Test
+ public void putMultiple() {
+ when(system2.now()).thenReturn(DATE);
+ when(uuidFactory.create())
+ .thenReturn(A_UUID)
+ .thenReturn(A_UUID_2);
+ underTest.insertOrUpdate(dbSession, GITHUB, A_OWNER, AN_INSTALL);
+ underTest.insertOrUpdate(dbSession, GITHUB, ANOTHER_OWNER, OTHER_INSTALL);
+
+ assertThatAlmAppInstall(GITHUB, A_OWNER)
+ .hasInstallId(AN_INSTALL)
+ .hasCreatedAt(DATE)
+ .hasUpdatedAt(DATE);
+
+ assertThatAlmAppInstall(GITHUB, ANOTHER_OWNER)
+ .hasInstallId(OTHER_INSTALL)
+ .hasCreatedAt(DATE)
+ .hasUpdatedAt(DATE);
+ }
+
+ @Test
+ public void getInstallId_throws_NPE_when_alm_is_null() {
+ expectAlmNPE();
+
+ underTest.getInstallId(dbSession, null, A_OWNER);
+ }
+
+ @Test
+ public void getInstallId_throws_IAE_when_owner_id_is_null() {
+ expectOwnerIdNullOrEmptyIAE();
+
+ underTest.getInstallId(dbSession, GITHUB, null);
+ }
+
+ @Test
+ public void getInstallId_throws_IAE_when_owner_id_is_empty() {
+ expectOwnerIdNullOrEmptyIAE();
+
+ underTest.getInstallId(dbSession, GITHUB, EMPTY_STRING);
+ }
+
+ @Test
+ public void getInstallId_returns_empty_optional_when_entry_does_not_exist_in_DB() {
+ assertThat(underTest.getInstallId(dbSession, GITHUB, A_OWNER)).isEmpty();
+ }
+
+ @Test
+ public void getInstallId_returns_install_id_when_entry_exists() {
+ when(uuidFactory.create()).thenReturn(A_UUID);
+ underTest.insertOrUpdate(dbSession, GITHUB, A_OWNER, AN_INSTALL);
+
+ assertThat(underTest.getInstallId(dbSession, GITHUB, A_OWNER)).contains(AN_INSTALL);
+ }
+
+ private void expectAlmNPE() {
+ expectedException.expect(NullPointerException.class);
+ expectedException.expectMessage("alm can't be null");
+ }
+
+ private void expectOwnerIdNullOrEmptyIAE() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("ownerId can't be null nor empty");
+ }
+
+ private void expectInstallIdNullOrEmptyIAE() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("installId can't be null nor empty");
+ }
+
+ private AlmAppInstallAssert assertThatAlmAppInstall(AlmAppInstallDao.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) {
+ super(asAlmAppInstall(dbTester, dbSession, alm, ownerId), AlmAppInstallAssert.class);
+ }
+
+ private static AlmAppInstall asAlmAppInstall(DbTester dbTester, DbSession dbSession, AlmAppInstallDao.ALM alm, String ownerId) {
+ Map<String, Object> row = dbTester.selectFirst(
+ dbSession,
+ "select" +
+ " install_id as \"installId\", created_at as \"createdAt\", updated_at as \"updatedAt\"" +
+ " from alm_app_installs" +
+ " where alm_id='" + alm.getId() + "' and owner_id='" + ownerId + "'");
+ return new AlmAppInstall(
+ (String) row.get("installId"),
+ (Long) row.get("createdAt"),
+ (Long) row.get("updatedAt"));
+ }
+
+ public void doesNotExist() {
+ isNull();
+ }
+
+ public AlmAppInstallAssert hasInstallId(String expected) {
+ isNotNull();
+
+ if (!Objects.equals(actual.getInstallId(), expected)) {
+ failWithMessage("Expected ALM App Install to have column INSTALL_ID to be <%s> but was <%s>", true, actual.getInstallId());
+ }
+ return this;
+ }
+
+ public AlmAppInstallAssert hasCreatedAt(long expected) {
+ isNotNull();
+
+ if (!Objects.equals(actual.getCreatedAt(), expected)) {
+ failWithMessage("Expected ALM App Install to have column CREATED_AT to be <%s> but was <%s>", expected, actual.getCreatedAt());
+ }
+
+ return this;
+ }
+
+ public AlmAppInstallAssert hasUpdatedAt(long expected) {
+ isNotNull();
+
+ if (!Objects.equals(actual.getUpdatedAt(), expected)) {
+ failWithMessage("Expected ALM App Install to have column UPDATED_AT to be <%s> but was <%s>", expected, actual.getUpdatedAt());
+ }
+
+ return this;
+ }
+
+ }
+
+ private static final class AlmAppInstall {
+ private final String installId;
+ private final Long createdAt;
+ private final Long updatedAt;
+
+ public AlmAppInstall(@Nullable String installId, @Nullable Long createdAt, @Nullable Long updatedAt) {
+ this.installId = installId;
+ this.createdAt = createdAt;
+ this.updatedAt = updatedAt;
+ }
+
+ @CheckForNull
+ public String getInstallId() {
+ return installId;
+ }
+
+ @CheckForNull
+ public Long getCreatedAt() {
+ return createdAt;
+ }
+
+ @CheckForNull
+ public Long getUpdatedAt() {
+ return updatedAt;
+ }
+ }
+}
--- /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.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.UUID_SIZE;
+import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder;
+
+public class CreateAlmAppInstallsTable extends DdlChange {
+
+ private static final String TABLE_NAME = "alm_app_installs";
+
+ 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 OWNER_COLUMN = newVarcharColumnDefBuilder()
+ .setColumnName("owner_id")
+ .setIsNullable(false)
+ .setLimit(MAX_SIZE)
+ .build();
+ private static final VarcharColumnDef INSTALL_COLUMN = newVarcharColumnDefBuilder()
+ .setColumnName("install_id")
+ .setIsNullable(false)
+ .setLimit(MAX_SIZE)
+ .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 CreateAlmAppInstallsTable(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(OWNER_COLUMN)
+ .addColumn(INSTALL_COLUMN)
+ .addColumn(CREATED_AT_COLUMN)
+ .addColumn(UPDATED_AT_COLUMN)
+ .build());
+
+ context.execute(new CreateIndexBuilder(getDialect())
+ .addColumn(ALM_ID_COLUMN)
+ .addColumn(OWNER_COLUMN)
+ .setUnique(true)
+ .setTable(TABLE_NAME)
+ .setName("alm_app_installs_owner")
+ .build());
+ context.execute(new CreateIndexBuilder(getDialect())
+ .addColumn(ALM_ID_COLUMN)
+ .addColumn(INSTALL_COLUMN)
+ .setUnique(true)
+ .setTable(TABLE_NAME)
+ .setName("alm_app_installs_install")
+ .build());
+ }
+ }
+
+ private boolean tableExists() throws SQLException {
+ try (Connection connection = getDatabase().getDataSource().getConnection()) {
+ return DatabaseUtils.tableExists(TABLE_NAME, connection);
+ }
+ }
+}
.add(2101, "Add HASH_METHOD to table users", AddHashMethodToUsersTable.class)
.add(2102, "Populate HASH_METHOD on table users", PopulateHashMethodOnUsers.class)
.add(2103, "Add isExternal boolean to rules", AddRuleExternal.class)
- ;
+ .add(2104, "Create ALM_APP_INSTALLS table", CreateAlmAppInstallsTable.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.v72;
+
+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 CreateAlmAppInstallsTableTest {
+
+ private static final String TABLE = "alm_app_installs";
+
+ @Rule
+ public final CoreDbTester db = CoreDbTester.createForSchema(CreateAlmAppInstallsTableTest.class, "empty.sql");
+
+ private CreateAlmAppInstallsTable underTest = new CreateAlmAppInstallsTable(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, "owner_id", VARCHAR, 4000, false);
+ db.assertColumnDefinition(TABLE, "install_id", VARCHAR, 4000, false);
+ db.assertColumnDefinition(TABLE, "created_at", BIGINT, null, false);
+ db.assertColumnDefinition(TABLE, "updated_at", BIGINT, null, false);
+
+ db.assertUniqueIndex(TABLE, "alm_app_installs_owner", "alm_id", "owner_id");
+ db.assertUniqueIndex(TABLE, "alm_app_installs_install", "alm_id", "install_id");
+ }
+}
@Test
public void verify_migration_count() {
- verifyMigrationCount(underTest, 4);
+ verifyMigrationCount(underTest, 5);
}
}