"CREATED_AT" BIGINT NOT NULL,
"UPDATED_AT" BIGINT NOT NULL,
"EXCLUDE_FROM_PURGE" BOOLEAN DEFAULT FALSE NOT NULL,
- "NEED_ISSUE_SYNC" BOOLEAN NOT NULL
+ "NEED_ISSUE_SYNC" BOOLEAN NOT NULL,
+ "IS_MAIN" BOOLEAN NOT NULL
);
ALTER TABLE "PROJECT_BRANCHES" ADD CONSTRAINT "PK_PROJECT_BRANCHES" PRIMARY KEY("UUID");
CREATE UNIQUE INDEX "UNIQ_PROJECT_BRANCHES" ON "PROJECT_BRANCHES"("BRANCH_TYPE" NULLS FIRST, "PROJECT_UUID" NULLS FIRST, "KEE" NULLS FIRST);
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.v100;
+
+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.BooleanColumnDef;
+import org.sonar.server.platform.db.migration.def.ColumnDef;
+import org.sonar.server.platform.db.migration.sql.AddColumnsBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+public class AddIsMainColumnInProjectBranches extends DdlChange {
+
+ private static final String TABLE_NAME = "project_branches";
+ private static final String COLUMN_NAME = "is_main";
+
+ public AddIsMainColumnInProjectBranches(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ try (Connection c = getDatabase().getDataSource().getConnection()) {
+ if (!DatabaseUtils.tableColumnExists(c, TABLE_NAME, COLUMN_NAME)) {
+ ColumnDef columnDef = BooleanColumnDef.newBooleanColumnDefBuilder()
+ .setColumnName(COLUMN_NAME)
+ .setIsNullable(true)
+ .build();
+ context.execute(new AddColumnsBuilder(getDialect(), TABLE_NAME).addColumn(columnDef).build());
+ }
+ }
+
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.v100;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.def.BooleanColumnDef;
+import org.sonar.server.platform.db.migration.sql.AlterColumnsBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+public class AlterIsMainColumnInProjectBranches extends DdlChange {
+
+ private static final String TABLE_NAME = "project_branches";
+ private static final String COLUMN_NAME = "is_main";
+
+ public AlterIsMainColumnInProjectBranches(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ BooleanColumnDef newColumnDef = new BooleanColumnDef.Builder()
+ .setColumnName(COLUMN_NAME)
+ .setIsNullable(false)
+ .build();
+ context.execute(new AlterColumnsBuilder(getDialect(), TABLE_NAME).updateColumn(newColumnDef).build());
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.v100;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.step.DataChange;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+
+public class UpdateIsMainColumnInProjectBranches extends DataChange {
+
+ public UpdateIsMainColumnInProjectBranches(Database db) {
+ super(db);
+ }
+
+ @Override
+ protected void execute(Context context) throws SQLException {
+ MassUpdate massUpdate = context.prepareMassUpdate();
+
+ massUpdate.select("select uuid from project_branches where project_uuid = uuid");
+ massUpdate.update("update project_branches set is_main = ? where uuid = ?");
+ massUpdate.execute((row, update) -> {
+ String uuid = row.getString(1);
+ update.setBoolean(1, true);
+ update.setString(2, uuid);
+ return true;
+ });
+ }
+}
import org.sonar.server.platform.db.migration.step.MigrationStepRegistry;
import org.sonar.server.platform.db.migration.version.DbVersion;
+import org.sonar.server.platform.db.migration.version.v100.AddIsMainColumnInProjectBranches;
+import org.sonar.server.platform.db.migration.version.v100.AlterIsMainColumnInProjectBranches;
+import org.sonar.server.platform.db.migration.version.v100.UpdateIsMainColumnInProjectBranches;
// ignoring bad number formatting, as it's indented that we align the migration numbers to SQ versions
@SuppressWarnings("java:S3937")
.add(10_1_002, "Add index on 'scm_accounts.scm_account'", CreateIndexForScmAccountOnScmAccountsTable.class)
.add(10_1_003, "Add index on 'users.email'", CreateIndexForEmailOnUsersTable.class)
.add(10_1_004, "Drop 'scm_accounts' column in 'users' table", DropScmAccountsInUsers.class)
+ .add(10_1_005, "Add column 'is_main' to 'project_branches' table", AddIsMainColumnInProjectBranches.class)
+ .add(10_1_006, "Update value of 'is_main' in 'project_branches' table", UpdateIsMainColumnInProjectBranches.class)
+ .add(10_1_007, "Alter column 'is_main' in 'project_branches' table - make it not nullable", AlterIsMainColumnInProjectBranches.class)
;
}
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.v100;
+
+import java.sql.SQLException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.db.CoreDbTester;
+
+import static java.sql.Types.BOOLEAN;
+
+public class AddIsMainColumnInProjectBranchesTest {
+
+ private static final String TABLE_NAME = "project_branches";
+ private static final String COLUMN_NAME = "is_main";
+
+ @Rule
+ public final CoreDbTester db = CoreDbTester.createForSchema(AddIsMainColumnInProjectBranchesTest.class, "schema.sql");
+
+ private final AddIsMainColumnInProjectBranches underTest = new AddIsMainColumnInProjectBranches(db.database());
+
+ @Test
+ public void is_main_column_exists_with_null_value() throws SQLException {
+ db.assertColumnDoesNotExist(TABLE_NAME, COLUMN_NAME);
+ underTest.execute();
+ db.assertColumnDefinition(TABLE_NAME, COLUMN_NAME, BOOLEAN, null, null);
+ }
+
+ @Test
+ public void migration_is_reentrant() throws SQLException {
+ db.assertColumnDoesNotExist(TABLE_NAME, COLUMN_NAME);
+ underTest.execute();
+ underTest.execute();
+ db.assertColumnDefinition(TABLE_NAME, COLUMN_NAME, BOOLEAN, null, null);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.v100;
+
+import java.sql.SQLException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.db.CoreDbTester;
+
+import static java.sql.Types.BOOLEAN;
+
+public class AlterIsMainColumnInProjectBranchesTest {
+
+ private static final String TABLE_NAME = "project_branches";
+ private static final String COLUMN_NAME = "is_main";
+
+ @Rule
+ public final CoreDbTester db = CoreDbTester.createForSchema(AlterIsMainColumnInProjectBranchesTest.class, "schema.sql");
+
+ private final AlterIsMainColumnInProjectBranches underTest = new AlterIsMainColumnInProjectBranches(db.database());
+
+ @Test
+ public void execute_shouldNotBeNullable() throws SQLException {
+ db.assertColumnDefinition(TABLE_NAME, COLUMN_NAME, BOOLEAN, null, true);
+ underTest.execute();
+ db.assertColumnDefinition(TABLE_NAME, COLUMN_NAME, BOOLEAN, null, false);
+ }
+
+ @Test
+ public void migration_is_reentrant() throws SQLException {
+ db.assertColumnDefinition(TABLE_NAME, COLUMN_NAME, BOOLEAN, null, true);
+ underTest.execute();
+ underTest.execute();
+ db.assertColumnDefinition(TABLE_NAME, COLUMN_NAME, BOOLEAN, null, false);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.v100;
+
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Collectors;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.core.util.UuidFactory;
+import org.sonar.core.util.UuidFactoryFast;
+import org.sonar.db.CoreDbTester;
+import org.sonar.server.platform.db.migration.step.DataChange;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class UpdateIsMainColumnInProjectBranchesTest {
+
+ private final UuidFactory uuidFactory = UuidFactoryFast.getInstance();
+
+ @Rule
+ public CoreDbTester db = CoreDbTester.createForSchema(UpdateIsMainColumnInProjectBranchesTest.class, "schema.sql");
+
+ private final DataChange underTest = new UpdateIsMainColumnInProjectBranches(db.database());
+
+ private static int not_random_value_always_incremented = 0;
+
+ @Test
+ public void migration_updates_is_main_if_row_has_the_same_uuids() throws SQLException {
+ String branchUuid1 = insertProjectBranch(true);
+ String branchUuid2 = insertProjectBranch(false);
+
+ underTest.execute();
+
+ assertBranchIsMain(branchUuid1);
+ assertBranchIsNotMain(branchUuid2);
+ }
+
+ @Test
+ public void migration_should_be_reentrant() throws SQLException {
+ String branchUuid1 = insertProjectBranch(true);
+ String branchUuid2 = insertProjectBranch(false);
+
+ underTest.execute();
+ // re-entrant
+ underTest.execute();
+
+ assertBranchIsMain(branchUuid1);
+ assertBranchIsNotMain(branchUuid2);
+ }
+
+ private void assertBranchIsMain(String branchUuid) {
+ assertBranchIs(branchUuid, true);
+ }
+
+ private void assertBranchIsNotMain(String branchUuid) {
+ assertBranchIs(branchUuid, false);
+ }
+
+ private void assertBranchIs(String branchUuid, boolean isMain) {
+ String selectSql = String.format("select is_main from project_branches where uuid='%s'", branchUuid);
+ assertThat(db.select(selectSql).stream()
+ .map(row -> row.get("IS_MAIN"))
+ .collect(Collectors.toList()))
+ .containsExactlyInAnyOrder(isMain);
+ }
+
+ private String insertProjectBranch(boolean sameUuids) {
+ Map<String, Object> map = new HashMap<>();
+ String uuid = uuidFactory.create();
+ map.put("UUID", uuid);
+ if(sameUuids) {
+ map.put("PROJECT_UUID", uuid);
+ } else {
+ map.put("PROJECT_UUID", "uuid" + not_random_value_always_incremented++);
+ }
+ map.put("KEE", "randomKey");
+ map.put("BRANCH_TYPE", "BRANCH");
+ map.put("MERGE_BRANCH_UUID", null);
+ map.put("CREATED_AT", System.currentTimeMillis());
+ map.put("UPDATED_AT", System.currentTimeMillis());
+ map.put("PULL_REQUEST_BINARY", null);
+ map.put("EXCLUDE_FROM_PURGE", true);
+ map.put("NEED_ISSUE_SYNC", false);
+ map.put("IS_MAIN", false);
+ db.executeInsert("project_branches", map);
+ return uuid;
+ }
+}
--- /dev/null
+CREATE TABLE "PROJECT_BRANCHES"(
+ "UUID" CHARACTER VARYING(50) NOT NULL,
+ "PROJECT_UUID" CHARACTER VARYING(50) NOT NULL,
+ "KEE" CHARACTER VARYING(255) NOT NULL,
+ "BRANCH_TYPE" CHARACTER VARYING(12) NOT NULL,
+ "MERGE_BRANCH_UUID" CHARACTER VARYING(50),
+ "PULL_REQUEST_BINARY" BINARY LARGE OBJECT,
+ "MANUAL_BASELINE_ANALYSIS_UUID" CHARACTER VARYING(40),
+ "CREATED_AT" BIGINT NOT NULL,
+ "UPDATED_AT" BIGINT NOT NULL,
+ "EXCLUDE_FROM_PURGE" BOOLEAN DEFAULT FALSE NOT NULL,
+ "NEED_ISSUE_SYNC" BOOLEAN NOT NULL
+);
+ALTER TABLE "PROJECT_BRANCHES" ADD CONSTRAINT "PK_PROJECT_BRANCHES" PRIMARY KEY("UUID");
+CREATE UNIQUE INDEX "UNIQ_PROJECT_BRANCHES" ON "PROJECT_BRANCHES"("BRANCH_TYPE" NULLS FIRST, "PROJECT_UUID" NULLS FIRST, "KEE" NULLS FIRST);
--- /dev/null
+CREATE TABLE "PROJECT_BRANCHES"(
+ "UUID" CHARACTER VARYING(50) NOT NULL,
+ "PROJECT_UUID" CHARACTER VARYING(50) NOT NULL,
+ "KEE" CHARACTER VARYING(255) NOT NULL,
+ "BRANCH_TYPE" CHARACTER VARYING(12) NOT NULL,
+ "MERGE_BRANCH_UUID" CHARACTER VARYING(50),
+ "PULL_REQUEST_BINARY" BINARY LARGE OBJECT,
+ "MANUAL_BASELINE_ANALYSIS_UUID" CHARACTER VARYING(40),
+ "CREATED_AT" BIGINT NOT NULL,
+ "UPDATED_AT" BIGINT NOT NULL,
+ "EXCLUDE_FROM_PURGE" BOOLEAN DEFAULT FALSE NOT NULL,
+ "NEED_ISSUE_SYNC" BOOLEAN NOT NULL,
+ "IS_MAIN" BOOLEAN
+);
+ALTER TABLE "PROJECT_BRANCHES" ADD CONSTRAINT "PK_PROJECT_BRANCHES" PRIMARY KEY("UUID");
+CREATE UNIQUE INDEX "UNIQ_PROJECT_BRANCHES" ON "PROJECT_BRANCHES"("BRANCH_TYPE" NULLS FIRST, "PROJECT_UUID" NULLS FIRST, "KEE" NULLS FIRST);
--- /dev/null
+CREATE TABLE "PROJECT_BRANCHES"(
+ "UUID" CHARACTER VARYING(50) NOT NULL,
+ "PROJECT_UUID" CHARACTER VARYING(50) NOT NULL,
+ "KEE" CHARACTER VARYING(255) NOT NULL,
+ "BRANCH_TYPE" CHARACTER VARYING(12) NOT NULL,
+ "MERGE_BRANCH_UUID" CHARACTER VARYING(50),
+ "PULL_REQUEST_BINARY" BINARY LARGE OBJECT,
+ "MANUAL_BASELINE_ANALYSIS_UUID" CHARACTER VARYING(40),
+ "CREATED_AT" BIGINT NOT NULL,
+ "UPDATED_AT" BIGINT NOT NULL,
+ "EXCLUDE_FROM_PURGE" BOOLEAN DEFAULT FALSE NOT NULL,
+ "NEED_ISSUE_SYNC" BOOLEAN NOT NULL,
+ "IS_MAIN" BOOLEAN
+);
+ALTER TABLE "PROJECT_BRANCHES" ADD CONSTRAINT "PK_PROJECT_BRANCHES" PRIMARY KEY("UUID");
+CREATE UNIQUE INDEX "UNIQ_PROJECT_BRANCHES" ON "PROJECT_BRANCHES"("BRANCH_TYPE" NULLS FIRST, "PROJECT_UUID" NULLS FIRST, "KEE" NULLS FIRST);