From d3bddceb9828e3833ab599e5ae4ddde8ccf5b958 Mon Sep 17 00:00:00 2001 From: Duarte Meneses Date: Tue, 11 Oct 2022 14:31:58 -0500 Subject: [PATCH] SONAR-17352 Migrate copy component UUIDs --- .../db/migration/version/v97/DbVersion97.java | 5 +- .../version/v97/FixCopyComponentUuid.java | 67 ++++++++++ .../version/v97/FixCopyComponentUuidTest.java | 124 ++++++++++++++++++ .../v97/FixCopyComponentUuidTest/schema.sql | 57 ++++++++ 4 files changed, 251 insertions(+), 2 deletions(-) create mode 100644 server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v97/FixCopyComponentUuid.java create mode 100644 server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v97/FixCopyComponentUuidTest.java create mode 100644 server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v97/FixCopyComponentUuidTest/schema.sql diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v97/DbVersion97.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v97/DbVersion97.java index 8de3f411b34..e79a9ea9f41 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v97/DbVersion97.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v97/DbVersion97.java @@ -35,7 +35,8 @@ public class DbVersion97 implements DbVersion { .add(6605, "Create index for 'branch_uuid' in 'components'", CreateIndexForComponentsBranchUuid.class) .add(6606, "Drop index for 'kee' in 'components'", DropIndexForComponentsKey.class) - .add(6607, "Remove branch information from 'kee' in 'components'", RemoveBranchInformationFromComponentsKey.class) - .add(6608, "Add unique index on 'kee','branch_uuid' in 'components'", CreateUniqueIndexForComponentsKeeAndBranchUuid.class); + .add(6607, "Fix copy component UUID", FixCopyComponentUuid.class) + .add(6608, "Remove branch information from 'kee' in 'components'", RemoveBranchInformationFromComponentsKey.class) + .add(6609, "Add unique index on 'kee','branch_uuid' in 'components'", CreateUniqueIndexForComponentsKeeAndBranchUuid.class); } } diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v97/FixCopyComponentUuid.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v97/FixCopyComponentUuid.java new file mode 100644 index 00000000000..0494f7c7eb3 --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v97/FixCopyComponentUuid.java @@ -0,0 +1,67 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 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.v97; + +import java.sql.SQLException; +import org.apache.commons.lang.StringUtils; +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 FixCopyComponentUuid extends DataChange { + private static final String BRANCH_IDENTIFIER = ":BRANCH:"; + private static final String SELECT_QUERY = "select kee, uuid, copy_component_uuid from components where copy_component_uuid is not null"; + private static final String UPDATE_QUERY = "update components set copy_component_uuid = ? where uuid = ?"; + + public FixCopyComponentUuid(Database db) { + super(db); + } + + @Override + public void execute(Context context) throws SQLException { + MassUpdate massUpdate = context.prepareMassUpdate(); + massUpdate.select(SELECT_QUERY); + massUpdate.update(UPDATE_QUERY); + massUpdate.execute((row, update) -> { + String componentKey = row.getString(1); + String componentUuid = row.getString(2); + String copyComponentUuid = row.getString(3); + + String branchKey = StringUtils.substringAfterLast(componentKey, BRANCH_IDENTIFIER); + + if (StringUtils.isEmpty(branchKey)) { + return false; + } + + String branchUuid = context.prepareSelect("select uuid from project_branches where project_uuid = ? and branch_type = 'BRANCH' and kee = ?") + .setString(1, copyComponentUuid) + .setString(2, branchKey) + .get(t -> t.getString(1)); + + if (branchUuid != null && !branchUuid.equals(copyComponentUuid)) { + update.setString(1, branchUuid) + .setString(2, componentUuid); + return true; + } + + return false; + }); + } +} diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v97/FixCopyComponentUuidTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v97/FixCopyComponentUuidTest.java new file mode 100644 index 00000000000..d0d4da73287 --- /dev/null +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v97/FixCopyComponentUuidTest.java @@ -0,0 +1,124 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 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.v97; + +import java.sql.SQLException; +import java.util.Map; +import java.util.stream.Collectors; +import javax.annotation.Nullable; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.sonar.db.CoreDbTester; +import org.sonar.server.platform.db.migration.step.DataChange; + +import static java.util.Map.entry; +import static org.assertj.core.api.Assertions.assertThat; + +public class FixCopyComponentUuidTest { + @Rule + public final CoreDbTester db = CoreDbTester.createForSchema(FixCopyComponentUuidTest.class, "schema.sql"); + + private DataChange underTest; + + @Before + public void before() { + underTest = new FixCopyComponentUuid(db.database()); + } + + @Test + public void updates_copy_component_uuid() throws SQLException { + insert(); + + underTest.execute(); + + checkResults(); + } + + @Test + public void should_be_reentrant() throws SQLException { + insert(); + + underTest.execute(); + underTest.execute(); + + checkResults(); + } + + public void checkResults() { + assertThat(getCopyComponentUuidByUuid()) + .containsOnly( + entry("uuid1", ""), + entry("uuid2", ""), + entry("uuid3", ""), + entry("uuid4", "uuid1"), + entry("uuid5", ""), + entry("uuid6", "uuid2") + ); + } + + private void insert() { + // project with a branch + insertBranch("uuid1", "uuid1", "master"); + insertBranch("uuid2", "uuid1", "branch1"); + insertComponents("uuid1", "project1", null, null); + insertComponents("uuid2", "project1:BRANCH:branch1", "uuid1", null); + + // app + insertBranch("uuid3", "uuid3", "master"); + insertComponents("uuid3", "app", null, null); + insertComponents("uuid4", "appb1project1", null, "uuid1"); + + // app branch + insertBranch("uuid5", "uuid3", "b1"); + insertComponents("uuid5", "app:BRANCH:b1", "uuid3", null); + // this copyComponentUuid needs to be fixed to point to uuid2 + insertComponents("uuid6", "appb1project1:BRANCH:branch1", "uuid3", "uuid1"); + } + + private Map getCopyComponentUuidByUuid() { + return db.select("select uuid, copy_component_uuid from components").stream() + .collect(Collectors.toMap(e -> (String) e.get("UUID"), e -> e.get("COPY_COMPONENT_UUID") == null ? "" : (String) e.get("COPY_COMPONENT_UUID"))); + } + + private void insertBranch(String uuid, String projectUuid, String key) { + db.executeInsert("project_branches", + "kee", key, + "uuid", uuid, + "project_uuid", projectUuid, + "branch_type", "BRANCH", + "need_issue_sync", "false", + "created_at", "1", + "updated_at", "1"); + } + + private void insertComponents(String uuid, String key, @Nullable String mainBranchUuid, @Nullable String copyComponentUuid) { + db.executeInsert("components", + "enabled", true, + "uuid", uuid, + "kee", key, + "branch_uuid", "branch_uuid", + "root_uuid", "root_uuid", + "uuid_path", "uuid_path", + "private", false, + "copy_component_uuid", copyComponentUuid, + "main_branch_project_uuid", mainBranchUuid); + } +} diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v97/FixCopyComponentUuidTest/schema.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v97/FixCopyComponentUuidTest/schema.sql new file mode 100644 index 00000000000..2337dc21e0b --- /dev/null +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v97/FixCopyComponentUuidTest/schema.sql @@ -0,0 +1,57 @@ +CREATE TABLE "COMPONENTS"( + "UUID" CHARACTER VARYING(50) NOT NULL, + "KEE" CHARACTER VARYING(1000), + "DEPRECATED_KEE" CHARACTER VARYING(400), + "NAME" CHARACTER VARYING(2000), + "LONG_NAME" CHARACTER VARYING(2000), + "DESCRIPTION" CHARACTER VARYING(2000), + "ENABLED" BOOLEAN DEFAULT TRUE NOT NULL, + "SCOPE" CHARACTER VARYING(3), + "QUALIFIER" CHARACTER VARYING(10), + "PRIVATE" BOOLEAN NOT NULL, + "ROOT_UUID" CHARACTER VARYING(50) NOT NULL, + "LANGUAGE" CHARACTER VARYING(20), + "COPY_COMPONENT_UUID" CHARACTER VARYING(50), + "PATH" CHARACTER VARYING(2000), + "UUID_PATH" CHARACTER VARYING(1500) NOT NULL, + "BRANCH_UUID" CHARACTER VARYING(50) NOT NULL, + "MODULE_UUID" CHARACTER VARYING(50), + "MODULE_UUID_PATH" CHARACTER VARYING(1500), + "MAIN_BRANCH_PROJECT_UUID" CHARACTER VARYING(50), + "B_CHANGED" BOOLEAN, + "B_NAME" CHARACTER VARYING(500), + "B_LONG_NAME" CHARACTER VARYING(500), + "B_DESCRIPTION" CHARACTER VARYING(2000), + "B_ENABLED" BOOLEAN, + "B_QUALIFIER" CHARACTER VARYING(10), + "B_LANGUAGE" CHARACTER VARYING(20), + "B_COPY_COMPONENT_UUID" CHARACTER VARYING(50), + "B_PATH" CHARACTER VARYING(2000), + "B_UUID_PATH" CHARACTER VARYING(1500), + "B_MODULE_UUID" CHARACTER VARYING(50), + "B_MODULE_UUID_PATH" CHARACTER VARYING(1500), + "CREATED_AT" TIMESTAMP +); +CREATE INDEX "PROJECTS_MODULE_UUID" ON "COMPONENTS"("MODULE_UUID" NULLS FIRST); +CREATE INDEX "PROJECTS_QUALIFIER" ON "COMPONENTS"("QUALIFIER" NULLS FIRST); +CREATE INDEX "PROJECTS_ROOT_UUID" ON "COMPONENTS"("ROOT_UUID" NULLS FIRST); +CREATE INDEX "IDX_MAIN_BRANCH_PRJ_UUID" ON "COMPONENTS"("MAIN_BRANCH_PROJECT_UUID" NULLS FIRST); +CREATE UNIQUE INDEX "COMPONENTS_UUID" ON "COMPONENTS"("UUID" NULLS FIRST); +CREATE INDEX "COMPONENTS_BRANCH_UUID" ON "COMPONENTS"("BRANCH_UUID" NULLS FIRST); + +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); + -- 2.39.5