From: Michal Duda Date: Thu, 29 Nov 2018 14:37:02 +0000 (+0100) Subject: SONAR-11525 analysis warning on module-lvl props X-Git-Tag: 7.6~95 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=e05aea1ebbba8d94c78afdbfac7230563d6df01f;p=sonarqube.git SONAR-11525 analysis warning on module-lvl props Analysis now produces a warning when the property that aggregates all previous module-level properties is not cleared. --- diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v75/DbVersion75.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v75/DbVersion75.java index fd5f6716470..05176b69a7b 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v75/DbVersion75.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v75/DbVersion75.java @@ -31,7 +31,6 @@ public class DbVersion75 implements DbVersion { .add(2401, "Create ORGANIZATION_ALM_BINDINGS table", CreateOrganizationsAlmBindingsTable.class) .add(2402, "Add column USER_EXTERNAL_ID in ALM_APP_INSTALLS", AddUserExternalIdColumnInAlmAppInstall.class) .add(2403, "Set IS_OWNER_USER not nullable in ALM_APP_INSTALLS", SetIsOwnerUserNotNullableInAlmAppInstalls.class) - .add(2404, "Add table EVENT_COMPONENT_CHANGES", AddEventComponentChanges.class) - .add(2405, "Move module and directory properties to a project level property", MigrateModuleProperties.class); + .add(2404, "Add table EVENT_COMPONENT_CHANGES", AddEventComponentChanges.class); } } diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v75/MigrateModuleProperties.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v75/MigrateModuleProperties.java deleted file mode 100644 index 5a7d66c3877..00000000000 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v75/MigrateModuleProperties.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 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.v75; - -import java.sql.SQLException; -import java.util.concurrent.atomic.AtomicReference; -import org.sonar.api.utils.System2; -import org.sonar.db.Database; -import org.sonar.server.platform.db.migration.SupportsBlueGreen; -import org.sonar.server.platform.db.migration.step.DataChange; -import org.sonar.server.platform.db.migration.step.MassUpdate; -import org.sonar.server.platform.db.migration.step.Upsert; - -@SupportsBlueGreen -public class MigrateModuleProperties extends DataChange { - - private static final String NEW_PROPERTY_NAME = "sonar.subprojects.settings.removed"; - - private final System2 system2; - - public MigrateModuleProperties(Database db, System2 system2) { - super(db); - this.system2 = system2; - } - - @Override - protected void execute(Context context) throws SQLException { - long now = system2.now(); - moveModulePropertiesToProjectLevel(context, now); - removeModuleProperties(context); - } - - private static void moveModulePropertiesToProjectLevel(Context context, long time) throws SQLException { - StringBuilder builder = new StringBuilder(); - AtomicReference currentProjectId = new AtomicReference<>(); - AtomicReference currentModuleUuid = new AtomicReference<>(); - - context.prepareSelect("select prop.prop_key, prop.text_value, prop.clob_value, mod.name, mod.uuid, root.id as project_id, root.name as project_name " + - "from properties prop " + - "left join projects mod on mod.id = prop.resource_id " + - "left join projects root on root.uuid = mod.project_uuid " + - "where mod.qualifier = 'BRC'" + - "order by root.uuid, mod.uuid, prop.prop_key") - .scroll(row -> { - String propertyKey = row.getString(1); - String propertyTextValue = row.getString(2); - String propertyClobValue = row.getString(3); - String moduleName = row.getString(4); - String moduleUuid = row.getString(5); - Integer projectId = row.getInt(6); - String projectName = row.getString(7); - - if (!projectId.equals(currentProjectId.get())) { - if (currentProjectId.get() != null) { - insertProjectProperties(context, currentProjectId.get(), builder.toString(), time); - } - - builder.setLength(0); - currentProjectId.set(projectId); - } - - if (!moduleUuid.equals(currentModuleUuid.get())) { - if (currentModuleUuid.get() != null && builder.length() != 0) { - builder.append("\n"); - } - builder.append("# previous settings for sub-project ").append(projectName).append("::").append(moduleName).append("\n"); - currentModuleUuid.set(moduleUuid); - } - - String propertyValue = propertyTextValue == null ? propertyClobValue : propertyTextValue; - builder.append(propertyKey).append("=").append(propertyValue).append("\n"); - }); - - if (builder.length() > 0) { - insertProjectProperties(context, currentProjectId.get(), builder.toString(), time); - } - } - - private static void insertProjectProperties(Context context, int projectId, String content, long time) throws SQLException { - Upsert upsert = context.prepareUpsert("insert into properties (prop_key, resource_id, is_empty, clob_value, created_at) values (?, ?, ?, ?, ?)"); - upsert.setString(1, NEW_PROPERTY_NAME) - .setInt(2, projectId) - .setBoolean(3, false) - .setString(4, content) - .setLong(5, time) - .execute() - .commit(); - } - - private static void removeModuleProperties(Context context) throws SQLException { - MassUpdate massUpdate = context.prepareMassUpdate().rowPluralName("remove module properties"); - massUpdate.select("select prop.id as property_id " + - "from properties prop " + - "left join projects mod on mod.id = prop.resource_id " + - "where mod.qualifier = 'BRC'"); - massUpdate.update("delete from properties where id=?"); - massUpdate.execute((row, update) -> { - update.setInt(1, row.getInt(1)); - return true; - }); - } -} diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v76/DbVersion76.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v76/DbVersion76.java index 235b8af2800..0cdfeaf5f99 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v76/DbVersion76.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v76/DbVersion76.java @@ -29,8 +29,8 @@ public class DbVersion76 implements DbVersion { registry .add(2500, "Create table USER_PROPERTIES", CreateUserPropertiesTable.class) .add(2501, "Add index in table USER_PROPERTIES", AddUniqueIndexInUserPropertiesTable.class) + .add(2502, "Move module and directory properties to a project level property", MigrateModuleProperties.class) .add(2505, "Fix the direction values of certain metrics (prepare for migration of conditions)", FixDirectionOfMetrics.class) - .add(2506, "Migrate quality gate conditions using warning, period and no more supported operations", MigrateNoMoreUsedQualityGateConditions.class) - ; + .add(2506, "Migrate quality gate conditions using warning, period and no more supported operations", MigrateNoMoreUsedQualityGateConditions.class); } } diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v76/MigrateModuleProperties.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v76/MigrateModuleProperties.java new file mode 100644 index 00000000000..fbdf1e5b556 --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v76/MigrateModuleProperties.java @@ -0,0 +1,119 @@ +/* + * 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.v76; + +import java.sql.SQLException; +import java.util.concurrent.atomic.AtomicReference; +import org.sonar.api.utils.System2; +import org.sonar.db.Database; +import org.sonar.server.platform.db.migration.SupportsBlueGreen; +import org.sonar.server.platform.db.migration.step.DataChange; +import org.sonar.server.platform.db.migration.step.MassUpdate; +import org.sonar.server.platform.db.migration.step.Upsert; + +@SupportsBlueGreen +public class MigrateModuleProperties extends DataChange { + + protected static final String NEW_PROPERTY_NAME = "sonar.modules.archivedSettings"; + + private final System2 system2; + + public MigrateModuleProperties(Database db, System2 system2) { + super(db); + this.system2 = system2; + } + + @Override + protected void execute(Context context) throws SQLException { + long now = system2.now(); + moveModulePropertiesToProjectLevel(context, now); + removeModuleProperties(context); + } + + private static void moveModulePropertiesToProjectLevel(Context context, long time) throws SQLException { + StringBuilder builder = new StringBuilder(); + AtomicReference currentProjectId = new AtomicReference<>(); + AtomicReference currentModuleUuid = new AtomicReference<>(); + + context.prepareSelect("select prop.prop_key, prop.text_value, prop.clob_value, mod.name, mod.uuid, root.id as project_id, root.name as project_name " + + "from properties prop " + + "left join projects mod on mod.id = prop.resource_id " + + "left join projects root on root.uuid = mod.project_uuid " + + "where mod.qualifier = 'BRC'" + + "order by root.uuid, mod.uuid, prop.prop_key") + .scroll(row -> { + String propertyKey = row.getString(1); + String propertyTextValue = row.getString(2); + String propertyClobValue = row.getString(3); + String moduleName = row.getString(4); + String moduleUuid = row.getString(5); + Integer projectId = row.getInt(6); + String projectName = row.getString(7); + + if (!projectId.equals(currentProjectId.get())) { + if (currentProjectId.get() != null) { + insertProjectProperties(context, currentProjectId.get(), builder.toString(), time); + } + + builder.setLength(0); + currentProjectId.set(projectId); + } + + if (!moduleUuid.equals(currentModuleUuid.get())) { + if (currentModuleUuid.get() != null && builder.length() != 0) { + builder.append("\n"); + } + builder.append("# previous settings for sub-project ").append(projectName).append("::").append(moduleName).append("\n"); + currentModuleUuid.set(moduleUuid); + } + + String propertyValue = propertyTextValue == null ? propertyClobValue : propertyTextValue; + builder.append(propertyKey).append("=").append(propertyValue).append("\n"); + }); + + if (builder.length() > 0) { + insertProjectProperties(context, currentProjectId.get(), builder.toString(), time); + } + } + + private static void insertProjectProperties(Context context, int projectId, String content, long time) throws SQLException { + Upsert upsert = context.prepareUpsert("insert into properties (prop_key, resource_id, is_empty, clob_value, created_at) values (?, ?, ?, ?, ?)"); + upsert.setString(1, NEW_PROPERTY_NAME) + .setInt(2, projectId) + .setBoolean(3, false) + .setString(4, content) + .setLong(5, time) + .execute() + .commit(); + } + + private static void removeModuleProperties(Context context) throws SQLException { + MassUpdate massUpdate = context.prepareMassUpdate().rowPluralName("remove module properties"); + massUpdate.select("select prop.id as property_id " + + "from properties prop " + + "left join projects mod on mod.id = prop.resource_id " + + "where mod.qualifier = 'BRC'"); + massUpdate.update("delete from properties where id=?"); + massUpdate.execute((row, update) -> { + update.setInt(1, row.getInt(1)); + return true; + }); + } +} diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v75/DbVersion75Test.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v75/DbVersion75Test.java index 1d8a5afbba6..6a0eee289e2 100644 --- a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v75/DbVersion75Test.java +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v75/DbVersion75Test.java @@ -35,6 +35,6 @@ public class DbVersion75Test { @Test public void verify_migration_count() { - verifyMigrationCount(underTest, 6); + verifyMigrationCount(underTest, 5); } } diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v75/MigrateModulePropertiesTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v75/MigrateModulePropertiesTest.java deleted file mode 100644 index 52330c71e0c..00000000000 --- a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v75/MigrateModulePropertiesTest.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * 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.v75; - -import java.sql.SQLException; -import java.util.List; -import java.util.Map; -import javax.annotation.Nullable; -import org.junit.Rule; -import org.junit.Test; -import org.sonar.api.resources.Qualifiers; -import org.sonar.api.resources.Scopes; -import org.sonar.api.utils.System2; -import org.sonar.api.utils.internal.TestSystem2; -import org.sonar.core.util.SequenceUuidFactory; -import org.sonar.core.util.UuidFactory; -import org.sonar.db.CoreDbTester; - -import static java.lang.String.valueOf; -import static org.assertj.core.api.Assertions.assertThat; - -public class MigrateModulePropertiesTest { - private final static long NOW = 50_000_000_000L; - - @Rule - public CoreDbTester db = CoreDbTester.createForSchema(MigrateModulePropertiesTest.class, "schema.sql"); - private System2 system2 = new TestSystem2().setNow(NOW); - private UuidFactory uuidFactory = new SequenceUuidFactory(); - private MigrateModuleProperties underTest = new MigrateModuleProperties(db.database(), system2); - - @Test - public void multi_module_project_migration() throws SQLException { - setupMultiModuleProject(); - - underTest.execute(); - - verifyMultiModuleProjectMigration(); - } - - @Test - public void migration_is_reentrant() throws SQLException { - setupMultiModuleProject(); - - underTest.execute(); - underTest.execute(); - - verifyMultiModuleProjectMigration(); - List> remainingProperties = db.select("select ID from properties"); - assertThat(remainingProperties).hasSize(3); - } - - @Test - public void single_module_project_migration() throws SQLException { - String project2Uuid = uuidFactory.create(); - insertComponent(5, project2Uuid, null, project2Uuid, Qualifiers.PROJECT, "Single module project"); - insertProperty(9, 5, "sonar.coverage.exclusions", "SingleModuleA.java"); - insertProperty(10, 5, "sonar.cp.exclusions", "SingleModuleB.java"); - - underTest.execute(); - - List> properties = db.select("select ID, TEXT_VALUE, CLOB_VALUE " + - "from properties " + - "where PROP_KEY='sonar.subprojects.settings.removed' and RESOURCE_ID = 5"); - assertThat(properties).hasSize(0); - List> remainingProperties = db.select("select ID from properties"); - assertThat(remainingProperties).hasSize(2); - } - - @Test - public void properties_do_not_leak_between_projects() throws SQLException { - setupMultiModuleProject(); - setupSecondMultiModuleProject(); - - underTest.execute(); - - verifyMultiModuleProjectMigration(); - verifySecondMultiModuleProjectMigration(); - } - - private void insertComponent(long id, String uuid, @Nullable String rootUuid, String projectUuid, String qualifier, String name) { - db.executeInsert( - "projects", - "ID", valueOf(id), - "UUID", uuid, - "ROOT_UUID", rootUuid, - "PROJECT_UUID", projectUuid, - "SCOPE", Scopes.PROJECT, - "QUALIFIER", qualifier, - "NAME", name); - } - - private void insertProperty(long id, long componentId, String key, String value) { - db.executeInsert( - "properties", - "ID", valueOf(id), - "RESOURCE_ID", componentId, - "PROP_KEY", key, - "TEXT_VALUE", value, - "IS_EMPTY", false); - } - - private void setupMultiModuleProject() { - String projectUuid = uuidFactory.create(); - String moduleUuid = uuidFactory.create(); - String subModule1Uuid = uuidFactory.create(); - String subModule2Uuid = uuidFactory.create(); - insertComponent(1, projectUuid, null, projectUuid, Qualifiers.PROJECT, "Multi-module project"); - insertComponent(2, moduleUuid, projectUuid, projectUuid, Qualifiers.MODULE, "Module"); - insertComponent(3, subModule1Uuid, moduleUuid, projectUuid, Qualifiers.MODULE, "Submodule 1"); - insertComponent(4, subModule2Uuid, moduleUuid, projectUuid, Qualifiers.MODULE, "Submodule 2"); - insertProperty(1, 1, "sonar.coverage.exclusions", "Proj1.java"); - insertProperty(2, 1, "sonar.cpd.exclusions", "Proj2.java"); - insertProperty(3, 2, "sonar.coverage.exclusions", "ModuleA.java"); - insertProperty(4, 2, "sonar.cpd.exclusions", "ModuleB.java"); - insertProperty(5, 3, "sonar.coverage.exclusions", "Module1A.java"); - insertProperty(6, 3, "sonar.cpd.exclusions", "Moddule1B.java"); - insertProperty(7, 4, "sonar.coverage.exclusions", "Module2A.java"); - insertProperty(8, 4, "sonar.cpd.exclusions", "Module2B.java"); - } - - private void verifyMultiModuleProjectMigration() { - final String expectedResult = "# previous settings for sub-project Multi-module project::Module\n" + - "sonar.coverage.exclusions=ModuleA.java\n" + - "sonar.cpd.exclusions=ModuleB.java\n" + - "\n" + - "# previous settings for sub-project Multi-module project::Submodule 1\n" + - "sonar.coverage.exclusions=Module1A.java\n" + - "sonar.cpd.exclusions=Moddule1B.java\n" + - "\n" + - "# previous settings for sub-project Multi-module project::Submodule 2\n" + - "sonar.coverage.exclusions=Module2A.java\n" + - "sonar.cpd.exclusions=Module2B.java\n"; - - List> properties = db.select("select ID, TEXT_VALUE, CLOB_VALUE " + - "from properties " + - "where PROP_KEY='sonar.subprojects.settings.removed' and RESOURCE_ID = 1"); - - assertThat(properties).hasSize(1); - Map project1Property = properties.get(0); - assertThat(project1Property.get("TEXT_VALUE")).isNull(); - assertThat(project1Property.get("CLOB_VALUE")).isEqualTo(expectedResult); - } - - private void setupSecondMultiModuleProject() { - String project3Uuid = uuidFactory.create(); - String singleModuleUuid = uuidFactory.create(); - insertComponent(6, project3Uuid, null, project3Uuid, Qualifiers.PROJECT, "Another multi-module project"); - insertComponent(7, singleModuleUuid, project3Uuid, project3Uuid, Qualifiers.MODULE, "Module X"); - insertProperty(11, 6, "sonar.coverage.exclusions", "InRoot.java"); - insertProperty(12, 7, "sonar.coverage.exclusions", "InModule.java"); - } - - private void verifySecondMultiModuleProjectMigration() { - final String expectedResult = "# previous settings for sub-project Another multi-module project::Module X\n" + - "sonar.coverage.exclusions=InModule.java\n"; - - List> properties = db.select("select ID, TEXT_VALUE, CLOB_VALUE " + - "from properties " + - "where PROP_KEY='sonar.subprojects.settings.removed' and RESOURCE_ID = 6"); - - assertThat(properties).hasSize(1); - Map project2Property = properties.get(0); - assertThat(project2Property.get("TEXT_VALUE")).isNull(); - assertThat(project2Property.get("CLOB_VALUE")).isEqualTo(expectedResult); - } -} diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v76/DbVersion76Test.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v76/DbVersion76Test.java index bec86f8565a..595ce34382e 100644 --- a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v76/DbVersion76Test.java +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v76/DbVersion76Test.java @@ -35,7 +35,7 @@ public class DbVersion76Test { @Test public void verify_migration_count() { - verifyMigrationCount(underTest, 4); + verifyMigrationCount(underTest, 5); } } diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v76/MigrateModulePropertiesTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v76/MigrateModulePropertiesTest.java new file mode 100644 index 00000000000..4692e49ef14 --- /dev/null +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v76/MigrateModulePropertiesTest.java @@ -0,0 +1,184 @@ +/* + * 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.v76; + +import java.sql.SQLException; +import java.util.List; +import java.util.Map; +import javax.annotation.Nullable; +import org.junit.Rule; +import org.junit.Test; +import org.sonar.api.resources.Qualifiers; +import org.sonar.api.resources.Scopes; +import org.sonar.api.utils.System2; +import org.sonar.api.utils.internal.TestSystem2; +import org.sonar.core.util.SequenceUuidFactory; +import org.sonar.core.util.UuidFactory; +import org.sonar.db.CoreDbTester; + +import static java.lang.String.valueOf; +import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.server.platform.db.migration.version.v76.MigrateModuleProperties.NEW_PROPERTY_NAME; + +public class MigrateModulePropertiesTest { + private static final long NOW = 50_000_000_000L; + + @Rule + public CoreDbTester db = CoreDbTester.createForSchema(MigrateModulePropertiesTest.class, "schema.sql"); + private System2 system2 = new TestSystem2().setNow(NOW); + private UuidFactory uuidFactory = new SequenceUuidFactory(); + private MigrateModuleProperties underTest = new MigrateModuleProperties(db.database(), system2); + + @Test + public void multi_module_project_migration() throws SQLException { + setupMultiModuleProject(); + + underTest.execute(); + + verifyMultiModuleProjectMigration(); + } + + @Test + public void migration_is_reentrant() throws SQLException { + setupMultiModuleProject(); + + underTest.execute(); + underTest.execute(); + + verifyMultiModuleProjectMigration(); + List> remainingProperties = db.select("select ID from properties"); + assertThat(remainingProperties).hasSize(3); + } + + @Test + public void single_module_project_migration() throws SQLException { + String project2Uuid = uuidFactory.create(); + insertComponent(5, project2Uuid, null, project2Uuid, Qualifiers.PROJECT, "Single module project"); + insertProperty(9, 5, "sonar.coverage.exclusions", "SingleModuleA.java"); + insertProperty(10, 5, "sonar.cp.exclusions", "SingleModuleB.java"); + + underTest.execute(); + + List> properties = db.select(String.format("select ID, TEXT_VALUE, CLOB_VALUE " + + "from properties " + + "where PROP_KEY='%s' and RESOURCE_ID = 5", NEW_PROPERTY_NAME)); + assertThat(properties).hasSize(0); + List> remainingProperties = db.select("select ID from properties"); + assertThat(remainingProperties).hasSize(2); + } + + @Test + public void properties_do_not_leak_between_projects() throws SQLException { + setupMultiModuleProject(); + setupSecondMultiModuleProject(); + + underTest.execute(); + + verifyMultiModuleProjectMigration(); + verifySecondMultiModuleProjectMigration(); + } + + private void insertComponent(long id, String uuid, @Nullable String rootUuid, String projectUuid, String qualifier, String name) { + db.executeInsert( + "projects", + "ID", valueOf(id), + "UUID", uuid, + "ROOT_UUID", rootUuid, + "PROJECT_UUID", projectUuid, + "SCOPE", Scopes.PROJECT, + "QUALIFIER", qualifier, + "NAME", name); + } + + private void insertProperty(long id, long componentId, String key, String value) { + db.executeInsert( + "properties", + "ID", valueOf(id), + "RESOURCE_ID", componentId, + "PROP_KEY", key, + "TEXT_VALUE", value, + "IS_EMPTY", false); + } + + private void setupMultiModuleProject() { + String projectUuid = uuidFactory.create(); + String moduleUuid = uuidFactory.create(); + String subModule1Uuid = uuidFactory.create(); + String subModule2Uuid = uuidFactory.create(); + insertComponent(1, projectUuid, null, projectUuid, Qualifiers.PROJECT, "Multi-module project"); + insertComponent(2, moduleUuid, projectUuid, projectUuid, Qualifiers.MODULE, "Module"); + insertComponent(3, subModule1Uuid, moduleUuid, projectUuid, Qualifiers.MODULE, "Submodule 1"); + insertComponent(4, subModule2Uuid, moduleUuid, projectUuid, Qualifiers.MODULE, "Submodule 2"); + insertProperty(1, 1, "sonar.coverage.exclusions", "Proj1.java"); + insertProperty(2, 1, "sonar.cpd.exclusions", "Proj2.java"); + insertProperty(3, 2, "sonar.coverage.exclusions", "ModuleA.java"); + insertProperty(4, 2, "sonar.cpd.exclusions", "ModuleB.java"); + insertProperty(5, 3, "sonar.coverage.exclusions", "Module1A.java"); + insertProperty(6, 3, "sonar.cpd.exclusions", "Moddule1B.java"); + insertProperty(7, 4, "sonar.coverage.exclusions", "Module2A.java"); + insertProperty(8, 4, "sonar.cpd.exclusions", "Module2B.java"); + } + + private void verifyMultiModuleProjectMigration() { + final String expectedResult = "# previous settings for sub-project Multi-module project::Module\n" + + "sonar.coverage.exclusions=ModuleA.java\n" + + "sonar.cpd.exclusions=ModuleB.java\n" + + "\n" + + "# previous settings for sub-project Multi-module project::Submodule 1\n" + + "sonar.coverage.exclusions=Module1A.java\n" + + "sonar.cpd.exclusions=Moddule1B.java\n" + + "\n" + + "# previous settings for sub-project Multi-module project::Submodule 2\n" + + "sonar.coverage.exclusions=Module2A.java\n" + + "sonar.cpd.exclusions=Module2B.java\n"; + + List> properties = db + .select(String.format("select ID, TEXT_VALUE, CLOB_VALUE from properties where PROP_KEY='%s' and RESOURCE_ID = 1", + NEW_PROPERTY_NAME)); + + assertThat(properties).hasSize(1); + Map project1Property = properties.get(0); + assertThat(project1Property.get("TEXT_VALUE")).isNull(); + assertThat(project1Property.get("CLOB_VALUE")).isEqualTo(expectedResult); + } + + private void setupSecondMultiModuleProject() { + String project3Uuid = uuidFactory.create(); + String singleModuleUuid = uuidFactory.create(); + insertComponent(6, project3Uuid, null, project3Uuid, Qualifiers.PROJECT, "Another multi-module project"); + insertComponent(7, singleModuleUuid, project3Uuid, project3Uuid, Qualifiers.MODULE, "Module X"); + insertProperty(11, 6, "sonar.coverage.exclusions", "InRoot.java"); + insertProperty(12, 7, "sonar.coverage.exclusions", "InModule.java"); + } + + private void verifySecondMultiModuleProjectMigration() { + final String expectedResult = "# previous settings for sub-project Another multi-module project::Module X\n" + + "sonar.coverage.exclusions=InModule.java\n"; + + List> properties = db.select(String.format("select ID, TEXT_VALUE, CLOB_VALUE " + + "from properties " + + "where PROP_KEY='%s' and RESOURCE_ID = 6", NEW_PROPERTY_NAME)); + + assertThat(properties).hasSize(1); + Map project2Property = properties.get(0); + assertThat(project2Property.get("TEXT_VALUE")).isNull(); + assertThat(project2Property.get("CLOB_VALUE")).isEqualTo(expectedResult); + } +} diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v75/MigrateModulePropertiesTest/schema.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v75/MigrateModulePropertiesTest/schema.sql deleted file mode 100644 index 1cbb2b7781e..00000000000 --- a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v75/MigrateModulePropertiesTest/schema.sql +++ /dev/null @@ -1,35 +0,0 @@ -CREATE TABLE "PROJECTS" ( - "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), - "KEE" VARCHAR(400), - "UUID" VARCHAR(50) NOT NULL, - "ROOT_UUID" VARCHAR(50), - "PROJECT_UUID" VARCHAR(50) NOT NULL, - "MODULE_UUID" VARCHAR(50), - "MODULE_UUID_PATH" VARCHAR(1500), - "MAIN_BRANCH_PROJECT_UUID" VARCHAR(50), - "NAME" VARCHAR(2000), - "TAGS" VARCHAR(500), - "ENABLED" BOOLEAN NOT NULL DEFAULT TRUE, - "SCOPE" VARCHAR(3), - "QUALIFIER" VARCHAR(10) -); -CREATE UNIQUE INDEX "PROJECTS_KEE" ON "PROJECTS" ("KEE"); -CREATE INDEX "PROJECTS_ROOT_UUID" ON "PROJECTS" ("ROOT_UUID"); -CREATE UNIQUE INDEX "PROJECTS_UUID" ON "PROJECTS" ("UUID"); -CREATE INDEX "PROJECTS_PROJECT_UUID" ON "PROJECTS" ("PROJECT_UUID"); -CREATE INDEX "PROJECTS_MODULE_UUID" ON "PROJECTS" ("MODULE_UUID"); -CREATE INDEX "PROJECTS_QUALIFIER" ON "PROJECTS" ("QUALIFIER"); - -CREATE TABLE "PROPERTIES" ( - "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), - "PROP_KEY" VARCHAR(512) NOT NULL, - "RESOURCE_ID" INTEGER, - "USER_ID" INTEGER, - "TEXT_VALUE" VARCHAR(4000), - "CLOB_VALUE" CLOB(2147483647), - "CREATED_AT" BIGINT, - "IS_EMPTY" BOOLEAN NOT NULL, -); -CREATE INDEX "PROPERTIES_KEY" ON "PROPERTIES" ("PROP_KEY"); - - diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v76/MigrateModulePropertiesTest/schema.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v76/MigrateModulePropertiesTest/schema.sql new file mode 100644 index 00000000000..1cbb2b7781e --- /dev/null +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v76/MigrateModulePropertiesTest/schema.sql @@ -0,0 +1,35 @@ +CREATE TABLE "PROJECTS" ( + "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), + "KEE" VARCHAR(400), + "UUID" VARCHAR(50) NOT NULL, + "ROOT_UUID" VARCHAR(50), + "PROJECT_UUID" VARCHAR(50) NOT NULL, + "MODULE_UUID" VARCHAR(50), + "MODULE_UUID_PATH" VARCHAR(1500), + "MAIN_BRANCH_PROJECT_UUID" VARCHAR(50), + "NAME" VARCHAR(2000), + "TAGS" VARCHAR(500), + "ENABLED" BOOLEAN NOT NULL DEFAULT TRUE, + "SCOPE" VARCHAR(3), + "QUALIFIER" VARCHAR(10) +); +CREATE UNIQUE INDEX "PROJECTS_KEE" ON "PROJECTS" ("KEE"); +CREATE INDEX "PROJECTS_ROOT_UUID" ON "PROJECTS" ("ROOT_UUID"); +CREATE UNIQUE INDEX "PROJECTS_UUID" ON "PROJECTS" ("UUID"); +CREATE INDEX "PROJECTS_PROJECT_UUID" ON "PROJECTS" ("PROJECT_UUID"); +CREATE INDEX "PROJECTS_MODULE_UUID" ON "PROJECTS" ("MODULE_UUID"); +CREATE INDEX "PROJECTS_QUALIFIER" ON "PROJECTS" ("QUALIFIER"); + +CREATE TABLE "PROPERTIES" ( + "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), + "PROP_KEY" VARCHAR(512) NOT NULL, + "RESOURCE_ID" INTEGER, + "USER_ID" INTEGER, + "TEXT_VALUE" VARCHAR(4000), + "CLOB_VALUE" CLOB(2147483647), + "CREATED_AT" BIGINT, + "IS_EMPTY" BOOLEAN NOT NULL, +); +CREATE INDEX "PROPERTIES_KEY" ON "PROPERTIES" ("PROP_KEY"); + + diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java b/sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java index 5bbb4974373..e8066776c78 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java @@ -79,7 +79,6 @@ public interface CoreProperties { */ String CATEGORY_EXTERNAL_ISSUES = "externalIssues"; - /** * @since 2.11 */ @@ -366,7 +365,7 @@ public interface CoreProperties { /** * @since 3.6 */ - //TODO remove? + // TODO remove? String PROFILING_LOG_PROPERTY = "sonar.showProfiling"; /** @@ -527,4 +526,9 @@ public interface CoreProperties { * @since 5.1 */ String DEFAULT_ISSUE_ASSIGNEE = "sonar.issues.defaultAssigneeLogin"; + + /** + * @since 7.6 + */ + String MODULE_LEVEL_ARCHIVED_SETTINGS = "sonar.modules.archivedSettings"; } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectServerSettingsProvider.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectServerSettingsProvider.java index 2a85f416445..88f20ae9772 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectServerSettingsProvider.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectServerSettingsProvider.java @@ -20,17 +20,31 @@ package org.sonar.scanner.scan; import java.util.Map; +import org.apache.commons.lang.StringUtils; import org.picocontainer.injectors.ProviderAdapter; +import org.sonar.api.CoreProperties; +import org.sonar.api.notifications.AnalysisWarnings; +import org.sonar.api.utils.log.Logger; +import org.sonar.api.utils.log.Loggers; import org.sonar.scanner.bootstrap.ScannerProperties; import org.sonar.scanner.repository.settings.SettingsLoader; public class ProjectServerSettingsProvider extends ProviderAdapter { - private ProjectServerSettings singleton; + private static final Logger LOG = Loggers.get(ProjectConfigurationProvider.class); - public ProjectServerSettings provide(SettingsLoader loader, ScannerProperties scannerProperties) { + private static final String MODULE_LEVEL_ARCHIVED_SETTINGS_WARNING = "Please migrate all the properties listed in " + + "`sonar.module.removedProperties` setting to appriopriate project level setting."; + + private ProjectServerSettings singleton = null; + + public ProjectServerSettings provide(SettingsLoader loader, ScannerProperties scannerProperties, AnalysisWarnings analysisWarnings) { if (singleton == null) { Map serverSideSettings = loader.load(scannerProperties.getKeyWithBranch()); + if (StringUtils.isNotBlank(serverSideSettings.get(CoreProperties.MODULE_LEVEL_ARCHIVED_SETTINGS))) { + LOG.warn(MODULE_LEVEL_ARCHIVED_SETTINGS_WARNING); + analysisWarnings.addUnique(MODULE_LEVEL_ARCHIVED_SETTINGS_WARNING); + } singleton = new ProjectServerSettings(serverSideSettings); } return singleton;