diff options
20 files changed, 817 insertions, 3 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/db/migrations/DatabaseMigrations.java b/server/sonar-server/src/main/java/org/sonar/server/db/migrations/DatabaseMigrations.java index f5ef2c46688..f81424d5c6b 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/db/migrations/DatabaseMigrations.java +++ b/server/sonar-server/src/main/java/org/sonar/server/db/migrations/DatabaseMigrations.java @@ -29,6 +29,7 @@ import org.sonar.server.db.migrations.v45.AddMissingCustomRuleParametersMigratio import org.sonar.server.db.migrations.v45.AddMissingRuleParameterDefaultValuesMigration; import org.sonar.server.db.migrations.v45.DeleteMeasuresOnDeletedProfilesMigration; import org.sonar.server.db.migrations.v50.InsertProjectsAuthorizationUpdatedAtMigration; +import org.sonar.server.db.migrations.v50.PopulateProjectsUuidColumnsMigration; import java.util.List; @@ -63,7 +64,8 @@ public interface DatabaseMigrations { AddMissingCustomRuleParametersMigration.class, // 5.0 - InsertProjectsAuthorizationUpdatedAtMigration.class + InsertProjectsAuthorizationUpdatedAtMigration.class, + PopulateProjectsUuidColumnsMigration.class ); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/db/migrations/v50/PopulateProjectsUuidColumnsMigration.java b/server/sonar-server/src/main/java/org/sonar/server/db/migrations/v50/PopulateProjectsUuidColumnsMigration.java new file mode 100644 index 00000000000..222bd793fa9 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/db/migrations/v50/PopulateProjectsUuidColumnsMigration.java @@ -0,0 +1,113 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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.db.migrations.v50; + +import com.google.common.base.Splitter; +import com.google.common.base.Strings; +import org.sonar.api.resources.Scopes; +import org.sonar.core.persistence.DbSession; +import org.sonar.core.persistence.migration.v50.Component; +import org.sonar.core.persistence.migration.v50.Migration50Mapper; +import org.sonar.server.db.DbClient; +import org.sonar.server.db.migrations.DatabaseMigration; + +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import static com.google.common.collect.Maps.newHashMap; + +/** + * Used in the Active Record Migration 705 + * + * @since 5.0 + */ +public class PopulateProjectsUuidColumnsMigration implements DatabaseMigration { + + private final DbClient db; + + public PopulateProjectsUuidColumnsMigration(DbClient db) { + this.db = db; + } + + @Override + public void execute() { + DbSession session = db.openSession(true); + try { + Migration50Mapper mapper = session.getMapper(Migration50Mapper.class); + + for (Component project : mapper.selectEnabledRootTrkProjects()) { + Map<Long, String> uuidByComponentId = newHashMap(); + Map<Long, Component> componentsBySnapshotId = newHashMap(); + + List<Component> components = mapper.selectComponentChildrenForProjects(project.getId()); + components.add(project); + for (Component component : components) { + componentsBySnapshotId.put(component.getSnapshotId(), component); + + component.setUuid(getOrCreateUuid(component.getId(), uuidByComponentId)); + component.setProjectUuid(getOrCreateUuid(project.getId(), uuidByComponentId)); + } + + for (Component component : components) { + String snapshotPath = component.getSnapshotPath(); + StringBuilder moduleUuidPath = new StringBuilder(); + Component lastModule = null; + if (!Strings.isNullOrEmpty(snapshotPath)) { + for (String s : Splitter.on(".").omitEmptyStrings().split(snapshotPath)) { + Long snapshotId = Long.valueOf(s); + Component currentComponent = componentsBySnapshotId.get(snapshotId); + if (currentComponent.getScope().equals(Scopes.PROJECT)) { + lastModule = currentComponent; + moduleUuidPath.append(currentComponent.getUuid()).append("."); + } + } + } + if (moduleUuidPath.length() > 0) { + component.setModuleUuidPath(moduleUuidPath.toString()); + } + + // Module UUID should contains direct module of a component, but it should be null on the first module + if (lastModule != null && !lastModule.getId().equals(project.getId())) { + component.setModuleUuid(getOrCreateUuid(lastModule.getId(), uuidByComponentId)); + } + + mapper.updateComponentUuids(component); + } + } + + session.commit(); + } finally { + session.close(); + } + } + + private static String getOrCreateUuid(Long componentId, Map<Long, String> uuidByComponentId) { + String uuid = uuidByComponentId.get(componentId); + if (uuid == null) { + String newUuid = UUID.randomUUID().toString(); + uuidByComponentId.put(componentId, newUuid); + return newUuid; + } + return uuid; + } + +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/db/migrations/v50/PopulateProjectsUuidColumnsMigrationTest.java b/server/sonar-server/src/test/java/org/sonar/server/db/migrations/v50/PopulateProjectsUuidColumnsMigrationTest.java new file mode 100644 index 00000000000..9c1fcdb67b5 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/db/migrations/v50/PopulateProjectsUuidColumnsMigrationTest.java @@ -0,0 +1,171 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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.db.migrations.v50; + +import com.google.common.collect.ImmutableSet; +import org.junit.After; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Test; +import org.sonar.core.persistence.DbSession; +import org.sonar.core.persistence.TestDatabase; +import org.sonar.core.persistence.migration.v50.Component; +import org.sonar.core.persistence.migration.v50.Migration50Mapper; +import org.sonar.server.db.DbClient; +import org.sonar.server.db.migrations.DatabaseMigration; + +import static org.fest.assertions.Assertions.assertThat; + +public class PopulateProjectsUuidColumnsMigrationTest { + + @ClassRule + public static TestDatabase db = new TestDatabase().schema(PopulateProjectsUuidColumnsMigrationTest.class, "schema.sql"); + + DbSession session; + + DbClient dbClient; + + Migration50Mapper mapper; + + DatabaseMigration migration; + + @Before + public void setUp() throws Exception { + db.executeUpdateSql("truncate table projects"); + db.executeUpdateSql("truncate table snapshots"); + dbClient = new DbClient(db.database(), db.myBatis()); + session = dbClient.openSession(false); + mapper = session.getMapper(Migration50Mapper.class); + migration = new PopulateProjectsUuidColumnsMigration(dbClient); + } + + @After + public void tearDown() throws Exception { + session.close(); + } + + @Test + public void migrate_projects() throws Exception { + db.prepareDbUnit(getClass(), "migrate_projects.xml"); + + migration.execute(); + session.commit(); + + Component root = mapper.selectComponentByKey("org.struts:struts"); + assertThat(root.getUuid()).isNotNull(); + assertThat(root.getProjectUuid()).isEqualTo(root.getUuid()); + assertThat(root.getModuleUuid()).isNull(); + assertThat(root.getModuleUuidPath()).isNull(); + + Component module = mapper.selectComponentByKey("org.struts:struts-core"); + assertThat(module.getUuid()).isNotNull(); + assertThat(module.getProjectUuid()).isEqualTo(root.getUuid()); + assertThat(module.getModuleUuid()).isNull(); + assertThat(module.getModuleUuidPath()).isEqualTo(root.getUuid() + "."); + + Component subModule = mapper.selectComponentByKey("org.struts:struts-db"); + assertThat(subModule.getUuid()).isNotNull(); + assertThat(subModule.getProjectUuid()).isEqualTo(root.getUuid()); + assertThat(subModule.getModuleUuid()).isEqualTo(module.getUuid()); + assertThat(subModule.getModuleUuidPath()).isEqualTo(root.getUuid() + "." + module.getUuid() + "."); + + Component directory = mapper.selectComponentByKey("org.struts:struts-core:src/org/struts"); + assertThat(directory.getUuid()).isNotNull(); + assertThat(directory.getProjectUuid()).isEqualTo(root.getUuid()); + assertThat(directory.getModuleUuid()).isEqualTo(subModule.getUuid()); + assertThat(directory.getModuleUuidPath()).isEqualTo(root.getUuid() + "." + module.getUuid() + "." + subModule.getUuid() + "."); + + Component file = mapper.selectComponentByKey("org.struts:struts-core:src/org/struts/RequestContext.java"); + assertThat(file.getUuid()).isNotNull(); + assertThat(file.getProjectUuid()).isEqualTo(root.getUuid()); + assertThat(file.getModuleUuid()).isEqualTo(subModule.getUuid()); + assertThat(file.getModuleUuidPath()).isEqualTo(root.getUuid() + "." + module.getUuid() + "." + subModule.getUuid() + "."); + + // Verify that each generated uuid is unique + assertThat(ImmutableSet.of(root.getUuid(), module.getUuid(), subModule.getUuid(), directory.getUuid(), file.getUuid())).hasSize(5); + } + + @Test + public void migrate_provisioned_project() throws Exception { + db.prepareDbUnit(getClass(), "migrate_provisioned_project.xml"); + + migration.execute(); + session.commit(); + + Component root = mapper.selectComponentByKey("org.struts:struts"); + assertThat(root.getUuid()).isNotNull(); + assertThat(root.getProjectUuid()).isEqualTo(root.getUuid()); + assertThat(root.getModuleUuid()).isNull(); + assertThat(root.getModuleUuidPath()).isNull(); + } + + @Test + public void migrate_library() throws Exception { + db.prepareDbUnit(getClass(), "migrate_library.xml"); + + migration.execute(); + session.commit(); + + Component root = mapper.selectComponentByKey("org.hamcrest:hamcrest-library"); + assertThat(root.getUuid()).isNotNull(); + assertThat(root.getProjectUuid()).isEqualTo(root.getUuid()); + assertThat(root.getModuleUuid()).isNull(); + assertThat(root.getModuleUuidPath()).isNull(); + } + + @Test + public void not_migrate_view() throws Exception { + db.prepareDbUnit(getClass(), "migrate_view.xml"); + + migration.execute(); + session.commit(); + + Component root = mapper.selectComponentByKey("view"); + assertThat(root.getUuid()).isNull(); + assertThat(root.getProjectUuid()).isNull(); + assertThat(root.getModuleUuid()).isNull(); + assertThat(root.getModuleUuidPath()).isNull(); + } + + @Test + public void not_migrate_developer() throws Exception { + db.prepareDbUnit(getClass(), "migrate_developer.xml"); + + migration.execute(); + session.commit(); + + Component root = mapper.selectComponentByKey("DEV:developer@company.net"); + assertThat(root.getUuid()).isNull(); + assertThat(root.getProjectUuid()).isNull(); + assertThat(root.getModuleUuid()).isNull(); + assertThat(root.getModuleUuidPath()).isNull(); + } + + @Test + public void not_migrate_technical_projects() throws Exception { + db.prepareDbUnit(getClass(), "not_migrate_technical_projects.xml"); + + migration.execute(); + + db.assertDbUnit(getClass(), "not_migrate_technical_projects.xml"); + } + +} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v50/PopulateProjectsUuidColumnsMigrationTest/migrate_developer.xml b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v50/PopulateProjectsUuidColumnsMigrationTest/migrate_developer.xml new file mode 100644 index 00000000000..9d518e84c76 --- /dev/null +++ b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v50/PopulateProjectsUuidColumnsMigrationTest/migrate_developer.xml @@ -0,0 +1,18 @@ +<dataset> + + <!-- developer --> + <projects id="1" kee="DEV:developer@company.net" name="developer@company.net" long_name="Developer" scope="PRJ" qualifier="DEV" root_id="[null]" description="[null]" + uuid="[null]" project_uuid="[null]" module_uuid="[null]" module_uuid_path="[null]" + enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="[null]" deprecated_kee="[null]" + created_at="2014-09-01" authorization_updated_at="[null]"/> + <snapshots id="1" project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]" + status="P" islast="[true]" purge_status="[null]" + period1_mode="[null]" period1_param="[null]" period1_date="[null]" + period2_mode="[null]" period2_param="[null]" period2_date="[null]" + period3_mode="[null]" period3_param="[null]" period3_date="[null]" + period4_mode="[null]" period4_param="[null]" period4_date="[null]" + period5_mode="[null]" period5_param="[null]" period5_date="[null]" + depth="[null]" scope="PRJ" qualifier="DEV" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" + version="[null]" path=""/> + +</dataset> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v50/PopulateProjectsUuidColumnsMigrationTest/migrate_library.xml b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v50/PopulateProjectsUuidColumnsMigrationTest/migrate_library.xml new file mode 100644 index 00000000000..4740588290e --- /dev/null +++ b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v50/PopulateProjectsUuidColumnsMigrationTest/migrate_library.xml @@ -0,0 +1,10 @@ +<dataset> + + <!-- library --> + <projects id="1" root_id="[null]" scope="PRJ" qualifier="LIB" kee="org.hamcrest:hamcrest-library" name="org.hamcrest:hamcrest-library" + uuid="[null]" project_uuid="[null]" module_uuid="[null]" module_uuid_path="[null]" + description="[null]" long_name="org.hamcrest:hamcrest-library" + enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="[null]" deprecated_kee="[null]" + created_at="2014-06-18" authorization_updated_at="2014-06-18" /> + +</dataset> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v50/PopulateProjectsUuidColumnsMigrationTest/migrate_projects.xml b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v50/PopulateProjectsUuidColumnsMigrationTest/migrate_projects.xml new file mode 100644 index 00000000000..14ba41f91d4 --- /dev/null +++ b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v50/PopulateProjectsUuidColumnsMigrationTest/migrate_projects.xml @@ -0,0 +1,82 @@ +<dataset> + + <!-- root project --> + <projects id="1" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts" + uuid="[null]" project_uuid="[null]" module_uuid="[null]" module_uuid_path="[null]" + description="the description" long_name="Apache Struts" + enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="[null]" deprecated_kee="[null]" + created_at="2014-06-18" authorization_updated_at="2014-06-18" /> + <snapshots id="1" project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]" + status="P" islast="[true]" purge_status="[null]" + period1_mode="[null]" period1_param="[null]" period1_date="[null]" + period2_mode="[null]" period2_param="[null]" period2_date="[null]" + period3_mode="[null]" period3_param="[null]" period3_date="[null]" + period4_mode="[null]" period4_param="[null]" period4_date="[null]" + period5_mode="[null]" period5_param="[null]" period5_date="[null]" + depth="[null]" scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" + version="[null]" path=""/> + + <!-- module --> + <projects id="2" root_id="1" kee="org.struts:struts-core" name="Struts Core" + uuid="[null]" project_uuid="[null]" module_uuid="[null]" module_uuid_path="[null]" + scope="PRJ" qualifier="BRC" long_name="Struts Core" deprecated_kee="[null]" + description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" created_at="2014-06-18" authorization_updated_at="[null]" /> + <snapshots id="2" project_id="2" parent_snapshot_id="1" root_project_id="1" root_snapshot_id="1" + status="P" islast="[true]" purge_status="[null]" + period1_mode="[null]" period1_param="[null]" period1_date="[null]" + period2_mode="[null]" period2_param="[null]" period2_date="[null]" + period3_mode="[null]" period3_param="[null]" period3_date="[null]" + period4_mode="[null]" period4_param="[null]" period4_date="[null]" + period5_mode="[null]" period5_param="[null]" period5_date="[null]" + depth="[null]" scope="PRJ" qualifier="BRC" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" + version="[null]" path="1."/> + + <!-- sub module --> + <projects id="3" root_id="2" kee="org.struts:struts-db" name="Struts Db" + uuid="[null]" project_uuid="[null]" module_uuid="[null]" module_uuid_path="[null]" + scope="PRJ" qualifier="BRC" long_name="Struts Db" deprecated_kee="[null]" + description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" created_at="2014-06-18" authorization_updated_at="[null]" /> + <snapshots id="3" project_id="3" parent_snapshot_id="2" root_project_id="1" root_snapshot_id="1" + status="P" islast="[true]" purge_status="[null]" + period1_mode="[null]" period1_param="[null]" period1_date="[null]" + period2_mode="[null]" period2_param="[null]" period2_date="[null]" + period3_mode="[null]" period3_param="[null]" period3_date="[null]" + period4_mode="[null]" period4_param="[null]" period4_date="[null]" + period5_mode="[null]" period5_param="[null]" period5_date="[null]" + depth="[null]" scope="PRJ" qualifier="BRC" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" + version="[null]" path="1.2."/> + + <!-- directory --> + <projects long_name="org.struts" id="4" scope="DIR" qualifier="DIR" kee="org.struts:struts-core:src/org/struts" + uuid="[null]" project_uuid="[null]" module_uuid="[null]" module_uuid_path="[null]" + name="src/org/struts" root_id="2" + description="[null]" deprecated_kee="[null]" + enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="src/org/struts" created_at="2014-06-18" authorization_updated_at="[null]" /> + <snapshots id="4" project_id="4" parent_snapshot_id="3" root_project_id="1" root_snapshot_id="1" + status="P" islast="[true]" purge_status="[null]" + period1_mode="[null]" period1_param="[null]" period1_date="[null]" + period2_mode="[null]" period2_param="[null]" period2_date="[null]" + period3_mode="[null]" period3_param="[null]" period3_date="[null]" + period4_mode="[null]" period4_param="[null]" period4_date="[null]" + period5_mode="[null]" period5_param="[null]" period5_date="[null]" + depth="[null]" scope="DIR" qualifier="PAC" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" + version="[null]" path="1.2.3."/> + + <!-- file --> + <projects long_name="org.struts.RequestContext" id="5" scope="FIL" qualifier="FIL" kee="org.struts:struts-core:src/org/struts/RequestContext.java" + uuid="[null]" project_uuid="[null]" module_uuid="[null]" module_uuid_path="[null]" + name="RequestContext.java" root_id="2" + description="[null]" deprecated_kee="[null]" + enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="src/org/struts/RequestContext.java" created_at="2014-06-18" authorization_updated_at="[null]" /> + + <snapshots id="5" project_id="5" parent_snapshot_id="4" root_project_id="1" root_snapshot_id="1" + status="P" islast="[true]" purge_status="[null]" + period1_mode="[null]" period1_param="[null]" period1_date="[null]" + period2_mode="[null]" period2_param="[null]" period2_date="[null]" + period3_mode="[null]" period3_param="[null]" period3_date="[null]" + period4_mode="[null]" period4_param="[null]" period4_date="[null]" + period5_mode="[null]" period5_param="[null]" period5_date="[null]" + depth="[null]" scope="FIL" qualifier="CLA" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" + version="[null]" path="1.2.3.4."/> + +</dataset> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v50/PopulateProjectsUuidColumnsMigrationTest/migrate_provisioned_project.xml b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v50/PopulateProjectsUuidColumnsMigrationTest/migrate_provisioned_project.xml new file mode 100644 index 00000000000..a38323d7a19 --- /dev/null +++ b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v50/PopulateProjectsUuidColumnsMigrationTest/migrate_provisioned_project.xml @@ -0,0 +1,10 @@ +<dataset> + + <!-- provisioned project --> + <projects id="1" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts" + uuid="[null]" project_uuid="[null]" module_uuid="[null]" module_uuid_path="[null]" + description="the description" long_name="Apache Struts" + enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="[null]" deprecated_kee="[null]" + created_at="2014-06-18" authorization_updated_at="2014-06-18" /> + +</dataset> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v50/PopulateProjectsUuidColumnsMigrationTest/migrate_view.xml b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v50/PopulateProjectsUuidColumnsMigrationTest/migrate_view.xml new file mode 100644 index 00000000000..79021a863b9 --- /dev/null +++ b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v50/PopulateProjectsUuidColumnsMigrationTest/migrate_view.xml @@ -0,0 +1,18 @@ +<dataset> + + <!-- view --> + <projects id="1" kee="view" name="View" long_name="View" scope="PRJ" qualifier="VW" root_id="[null]" description="[null]" + uuid="[null]" project_uuid="[null]" module_uuid="[null]" module_uuid_path="[null]" + enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="[null]" deprecated_kee="[null]" + created_at="2014-09-01" authorization_updated_at="[null]"/> + <snapshots id="1" project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]" + status="P" islast="[true]" purge_status="[null]" + period1_mode="[null]" period1_param="[null]" period1_date="[null]" + period2_mode="[null]" period2_param="[null]" period2_date="[null]" + period3_mode="[null]" period3_param="[null]" period3_date="[null]" + period4_mode="[null]" period4_param="[null]" period4_date="[null]" + period5_mode="[null]" period5_param="[null]" period5_date="[null]" + depth="[null]" scope="PRJ" qualifier="VW" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" + version="[null]" path=""/> + +</dataset> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v50/PopulateProjectsUuidColumnsMigrationTest/not_migrate_technical_projects-result.xml b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v50/PopulateProjectsUuidColumnsMigrationTest/not_migrate_technical_projects-result.xml new file mode 100644 index 00000000000..302f21763a1 --- /dev/null +++ b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v50/PopulateProjectsUuidColumnsMigrationTest/not_migrate_technical_projects-result.xml @@ -0,0 +1,19 @@ +<dataset> + + <!-- technical project --> + <projects id="1" root_id="[null]" scope="FIL" qualifier="TRK" kee="OS_PLUGINSorg.struts:struts" name="Struts" + uuid="[null]" project_uuid="[null]" module_uuid="[null]" module_uuid_path="[null]" + description="the description" long_name="Apache Struts" + enabled="[true]" language="[null]" copy_resource_id="10" person_id="[null]" path="[null]" deprecated_kee="[null]" + created_at="2014-06-18" authorization_updated_at="2014-06-18" /> + <snapshots id="1" project_id="1" parent_snapshot_id="10" root_project_id="1" root_snapshot_id="10" + status="P" islast="[true]" purge_status="[null]" + period1_mode="[null]" period1_param="[null]" period1_date="[null]" + period2_mode="[null]" period2_param="[null]" period2_date="[null]" + period3_mode="[null]" period3_param="[null]" period3_date="[null]" + period4_mode="[null]" period4_param="[null]" period4_date="[null]" + period5_mode="[null]" period5_param="[null]" period5_date="[null]" + depth="1" scope="FIL" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" + version="[null]" path="10."/> + +</dataset> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v50/PopulateProjectsUuidColumnsMigrationTest/not_migrate_technical_projects.xml b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v50/PopulateProjectsUuidColumnsMigrationTest/not_migrate_technical_projects.xml new file mode 100644 index 00000000000..302f21763a1 --- /dev/null +++ b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v50/PopulateProjectsUuidColumnsMigrationTest/not_migrate_technical_projects.xml @@ -0,0 +1,19 @@ +<dataset> + + <!-- technical project --> + <projects id="1" root_id="[null]" scope="FIL" qualifier="TRK" kee="OS_PLUGINSorg.struts:struts" name="Struts" + uuid="[null]" project_uuid="[null]" module_uuid="[null]" module_uuid_path="[null]" + description="the description" long_name="Apache Struts" + enabled="[true]" language="[null]" copy_resource_id="10" person_id="[null]" path="[null]" deprecated_kee="[null]" + created_at="2014-06-18" authorization_updated_at="2014-06-18" /> + <snapshots id="1" project_id="1" parent_snapshot_id="10" root_project_id="1" root_snapshot_id="10" + status="P" islast="[true]" purge_status="[null]" + period1_mode="[null]" period1_param="[null]" period1_date="[null]" + period2_mode="[null]" period2_param="[null]" period2_date="[null]" + period3_mode="[null]" period3_param="[null]" period3_date="[null]" + period4_mode="[null]" period4_param="[null]" period4_date="[null]" + period5_mode="[null]" period5_param="[null]" period5_date="[null]" + depth="1" scope="FIL" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" + version="[null]" path="10."/> + +</dataset> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v50/PopulateProjectsUuidColumnsMigrationTest/schema.sql b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v50/PopulateProjectsUuidColumnsMigrationTest/schema.sql new file mode 100644 index 00000000000..22b95030079 --- /dev/null +++ b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v50/PopulateProjectsUuidColumnsMigrationTest/schema.sql @@ -0,0 +1,55 @@ +CREATE TABLE "PROJECTS" ( + "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), + "KEE" VARCHAR(400), + "ROOT_ID" INTEGER, + "UUID" VARCHAR(50), + "PROJECT_UUID" VARCHAR(50), + "MODULE_UUID" VARCHAR(50), + "MODULE_UUID_PATH" VARCHAR(4000), + "NAME" VARCHAR(256), + "DESCRIPTION" VARCHAR(2000), + "ENABLED" BOOLEAN NOT NULL DEFAULT TRUE, + "SCOPE" VARCHAR(3), + "QUALIFIER" VARCHAR(10), + "DEPRECATED_KEE" VARCHAR(400), + "PATH" VARCHAR(2000), + "LANGUAGE" VARCHAR(20), + "COPY_RESOURCE_ID" INTEGER, + "LONG_NAME" VARCHAR(256), + "PERSON_ID" INTEGER, + "CREATED_AT" TIMESTAMP, + "AUTHORIZATION_UPDATED_AT" TIMESTAMP +); + +CREATE TABLE "SNAPSHOTS" ( + "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), + "CREATED_AT" TIMESTAMP, + "BUILD_DATE" TIMESTAMP, + "PROJECT_ID" INTEGER NOT NULL, + "PARENT_SNAPSHOT_ID" INTEGER, + "STATUS" VARCHAR(4) NOT NULL DEFAULT 'U', + "PURGE_STATUS" INTEGER, + "ISLAST" BOOLEAN NOT NULL DEFAULT FALSE, + "SCOPE" VARCHAR(3), + "QUALIFIER" VARCHAR(10), + "ROOT_SNAPSHOT_ID" INTEGER, + "VERSION" VARCHAR(500), + "PATH" VARCHAR(500), + "DEPTH" INTEGER, + "ROOT_PROJECT_ID" INTEGER, + "PERIOD1_MODE" VARCHAR(100), + "PERIOD1_PARAM" VARCHAR(100), + "PERIOD1_DATE" TIMESTAMP, + "PERIOD2_MODE" VARCHAR(100), + "PERIOD2_PARAM" VARCHAR(100), + "PERIOD2_DATE" TIMESTAMP, + "PERIOD3_MODE" VARCHAR(100), + "PERIOD3_PARAM" VARCHAR(100), + "PERIOD3_DATE" TIMESTAMP, + "PERIOD4_MODE" VARCHAR(100), + "PERIOD4_PARAM" VARCHAR(100), + "PERIOD4_DATE" TIMESTAMP, + "PERIOD5_MODE" VARCHAR(100), + "PERIOD5_PARAM" VARCHAR(100), + "PERIOD5_DATE" TIMESTAMP +); diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/705_populate_projects_uuid_columns.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/705_populate_projects_uuid_columns.rb new file mode 100644 index 00000000000..a08d370720b --- /dev/null +++ b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/705_populate_projects_uuid_columns.rb @@ -0,0 +1,32 @@ +# +# SonarQube, open source software quality management tool. +# Copyright (C) 2008-2014 SonarSource +# mailto:contact AT sonarsource DOT com +# +# SonarQube 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. +# +# SonarQube 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. +# + +# +# SonarQube 5.0 +# SONAR-5753 +# +class PopulateProjectsUuidColumns < ActiveRecord::Migration + + def self.up + execute_java_migration('org.sonar.server.db.migrations.v50.PopulateProjectsUuidColumnsMigration') + end + +end + diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java b/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java index b3abd5d623e..de50ab9b538 100644 --- a/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java +++ b/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java @@ -33,7 +33,7 @@ import java.util.List; */ public class DatabaseVersion implements BatchComponent, ServerComponent { - public static final int LAST_VERSION = 704; + public static final int LAST_VERSION = 705; /** * List of all the tables. * This list is hardcoded because we didn't succeed in using java.sql.DatabaseMetaData#getTables() in the same way diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java b/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java index 6f9ebbe4461..fba96a99c1b 100644 --- a/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java +++ b/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java @@ -58,6 +58,7 @@ import org.sonar.core.notification.db.NotificationQueueMapper; import org.sonar.core.permission.*; import org.sonar.core.persistence.migration.v44.Migration44Mapper; import org.sonar.core.persistence.migration.v45.Migration45Mapper; +import org.sonar.core.persistence.migration.v50.Migration50Mapper; import org.sonar.core.properties.PropertiesMapper; import org.sonar.core.properties.PropertyDto; import org.sonar.core.purge.PurgeMapper; @@ -180,7 +181,7 @@ public class MyBatis implements BatchComponent, ServerComponent { MeasureMapper.class, MetricMapper.class, QualityGateMapper.class, QualityGateConditionMapper.class, ComponentMapper.class, SnapshotMapper.class, ProjectQgateAssociationMapper.class, AnalysisReportMapper.class, - Migration45Mapper.class + Migration45Mapper.class, Migration50Mapper.class }; loadMappers(conf, mappers); configureLogback(mappers); diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/migration/v50/Component.java b/sonar-core/src/main/java/org/sonar/core/persistence/migration/v50/Component.java new file mode 100644 index 00000000000..b16a9d1e651 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/persistence/migration/v50/Component.java @@ -0,0 +1,121 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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.core.persistence.migration.v50; + +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; + +public class Component { + + private Long id; + private Long projectId; + private Long snapshotId; + private String snapshotPath; + private String scope; + + private String uuid; + private String projectUuid; + private String moduleUuid; + private String moduleUuidPath; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + /** + * Can be null on provisioned projects or library + */ + @CheckForNull + public Long getProjectId() { + return projectId; + } + + public void setProjectId(@Nullable Long projectId) { + this.projectId = projectId; + } + + /** + * Can be null on provisioned projects or library + */ + @CheckForNull + public Long getSnapshotId() { + return snapshotId; + } + + public void setSnapshotId(@Nullable Long snapshotId) { + this.snapshotId = snapshotId; + } + + @CheckForNull + public String getSnapshotPath() { + return snapshotPath; + } + + public void setSnapshotPath(@Nullable String snapshotPath) { + this.snapshotPath = snapshotPath; + } + + public String getScope() { + return scope; + } + + public void setScope(String scope) { + this.scope = scope; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public String getProjectUuid() { + return projectUuid; + } + + public void setProjectUuid(String projectUuid) { + this.projectUuid = projectUuid; + } + + @CheckForNull + public String getModuleUuid() { + return moduleUuid; + } + + public void setModuleUuid(@Nullable String moduleUuid) { + this.moduleUuid = moduleUuid; + } + + @CheckForNull + public String getModuleUuidPath() { + return moduleUuidPath; + } + + public void setModuleUuidPath(@Nullable String moduleUuidPath) { + this.moduleUuidPath = moduleUuidPath; + } +} diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/migration/v50/Migration50Mapper.java b/sonar-core/src/main/java/org/sonar/core/persistence/migration/v50/Migration50Mapper.java new file mode 100644 index 00000000000..72e3f492250 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/persistence/migration/v50/Migration50Mapper.java @@ -0,0 +1,74 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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.core.persistence.migration.v50; + +import org.apache.ibatis.annotations.*; +import org.apache.ibatis.mapping.ResultSetType; +import org.apache.ibatis.mapping.StatementType; + +import java.util.List; + +public interface Migration50Mapper { + + @Select("SELECT " + + " p.id AS \"id\", " + + " s.root_project_id AS \"projectId\", " + + " s.id AS \"snapshotId\", " + + " s.path AS \"snapshotPath\", " + + " p.scope AS \"scope\" " + + "FROM projects p " + + " LEFT OUTER JOIN snapshots s ON s.project_id = p.id AND s.islast = ${_true} " + + " WHERE p.scope = 'PRJ' AND p.qualifier <> 'VW' AND p.qualifier <> 'DEV' AND p.root_id IS NULL AND p.enabled=${_true}") + @Result(javaType = Component.class) + @Options(statementType = StatementType.PREPARED, resultSetType = ResultSetType.FORWARD_ONLY, fetchSize = 200) + List<Component> selectEnabledRootTrkProjects(); + + @Select("SELECT " + + " p.id AS \"id\", " + + " s.root_project_id AS \"projectId\", " + + " s.id AS \"snapshotId\", " + + " s.path AS \"snapshotPath\", " + + " p.scope AS \"scope\" " + + "FROM projects root " + + " INNER JOIN snapshots root_snapshot ON root_snapshot.project_id = root.id AND root_snapshot.islast = ${_true} " + + " INNER JOIN snapshots s ON s.root_snapshot_id = root_snapshot.id AND s.islast = ${_true} " + + " INNER JOIN projects p ON p.id = s.project_id" + + " WHERE root.id = #{id}") + @Result(javaType = Component.class) + List<Component> selectComponentChildrenForProjects(@Param("id") Long projectId); + + @Select("SELECT " + + " p.id AS \"id\", " + + " p.uuid AS \"uuid\", " + + " p.project_uuid AS \"projectUuid\", " + + " p.module_uuid AS \"moduleUuid\", " + + " p.module_uuid_path AS \"moduleUuidPath\" " + + "FROM projects p " + + " WHERE p.kee = #{key}") + @Result(javaType = Component.class) + Component selectComponentByKey(@Param("key") String key); + + @Update("UPDATE projects " + + " SET uuid=#{uuid}, project_uuid=#{projectUuid}, module_uuid=#{moduleUuid}, module_uuid_path=#{moduleUuidPath} " + + " WHERE id=#{id}") + void updateComponentUuids(Component component); + +} diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/migration/v50/package-info.java b/sonar-core/src/main/java/org/sonar/core/persistence/migration/v50/package-info.java new file mode 100644 index 00000000000..af7d784eb29 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/persistence/migration/v50/package-info.java @@ -0,0 +1,24 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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.core.persistence.migration.v50; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/sonar-core/src/main/resources/org/sonar/core/persistence/migration/v50/Migration50Mapper.xml b/sonar-core/src/main/resources/org/sonar/core/persistence/migration/v50/Migration50Mapper.xml new file mode 100644 index 00000000000..1db97943867 --- /dev/null +++ b/sonar-core/src/main/resources/org/sonar/core/persistence/migration/v50/Migration50Mapper.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> + +<mapper namespace="org.sonar.core.persistence.migration.v50.Migration50Mapper"> + +</mapper> + diff --git a/sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql b/sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql index b039308d5bb..6bd7b5bd800 100644 --- a/sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql +++ b/sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql @@ -263,6 +263,7 @@ INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('701'); INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('702'); INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('703'); INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('704'); +INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('705'); INSERT INTO USERS(ID, LOGIN, NAME, EMAIL, CRYPTED_PASSWORD, SALT, CREATED_AT, UPDATED_AT, REMEMBER_TOKEN, REMEMBER_TOKEN_EXPIRES_AT) VALUES (1, 'admin', 'Administrator', '', 'a373a0e667abb2604c1fd571eb4ad47fe8cc0878', '48bc4b0d93179b5103fd3885ea9119498e9d161b', '2011-09-26 22:27:48.0', '2011-09-26 22:27:48.0', null, null); ALTER TABLE USERS ALTER COLUMN ID RESTART WITH 2; diff --git a/sonar-core/src/test/java/org/sonar/core/persistence/migration/v50/ComponentTest.java b/sonar-core/src/test/java/org/sonar/core/persistence/migration/v50/ComponentTest.java new file mode 100644 index 00000000000..cea162271a0 --- /dev/null +++ b/sonar-core/src/test/java/org/sonar/core/persistence/migration/v50/ComponentTest.java @@ -0,0 +1,37 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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.core.persistence.migration.v50; + +import org.junit.Test; + +import static com.google.code.beanmatchers.BeanMatchers.hasValidGettersAndSetters; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.allOf; + +public class ComponentTest { + + @Test + public void test_bean() throws Exception { + assertThat(Component.class, allOf( + hasValidGettersAndSetters())); + } + +} |