.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);
}
}
--- /dev/null
+/*
+ * 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;
+ });
+ }
+}
--- /dev/null
+/*
+ * 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<String, String> 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);
+ }
+}
--- /dev/null
+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);
+