From: Simon Brandhof Date: Mon, 5 Nov 2012 13:22:11 +0000 (+0100) Subject: SONAR-3895 load settings from web service X-Git-Tag: 3.4~400 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=3df00fb97661f12dabe98cd9a279080e586e9c0d;p=sonarqube.git SONAR-3895 load settings from web service --- diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/security/ApplyProjectRolesDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/security/ApplyProjectRolesDecorator.java index fc5e21bc95f..d2a4e7b3f81 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/security/ApplyProjectRolesDecorator.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/security/ApplyProjectRolesDecorator.java @@ -23,6 +23,7 @@ import com.google.common.collect.ImmutableSet; import org.slf4j.LoggerFactory; import org.sonar.api.batch.Decorator; import org.sonar.api.batch.DecoratorContext; +import org.sonar.api.batch.DryRunIncompatible; import org.sonar.api.resources.Project; import org.sonar.api.resources.Qualifiers; import org.sonar.api.resources.Resource; @@ -30,6 +31,7 @@ import org.sonar.api.security.ResourcePermissions; import java.util.Set; +@DryRunIncompatible public class ApplyProjectRolesDecorator implements Decorator { private final ResourcePermissions resourcePermissions; diff --git a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/CpdPlugin.java b/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/CpdPlugin.java index d911beb4399..81ac5d09f36 100644 --- a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/CpdPlugin.java +++ b/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/CpdPlugin.java @@ -20,7 +20,11 @@ package org.sonar.plugins.cpd; import com.google.common.collect.ImmutableList; -import org.sonar.api.*; +import org.sonar.api.CoreProperties; +import org.sonar.api.Properties; +import org.sonar.api.Property; +import org.sonar.api.PropertyType; +import org.sonar.api.SonarPlugin; import org.sonar.plugins.cpd.decorators.DuplicationDensityDecorator; import org.sonar.plugins.cpd.decorators.SumDuplicationsDecorator; import org.sonar.plugins.cpd.index.IndexFactory; @@ -37,6 +41,15 @@ import java.util.List; module = true, global = true, category = CoreProperties.CATEGORY_DUPLICATIONS, + type = PropertyType.BOOLEAN), + @Property( + key = CoreProperties.CPD_SKIP_PROPERTY, + defaultValue = "false", + name = "Skip", + description = "Disable detection of duplications", + // not displayed in UI + project = false, module = false, global = false, + category = CoreProperties.CATEGORY_DUPLICATIONS, type = PropertyType.BOOLEAN) }) public final class CpdPlugin extends SonarPlugin { diff --git a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/CpdSensor.java b/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/CpdSensor.java index 754ef176ee0..bd3f6420710 100644 --- a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/CpdSensor.java +++ b/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/CpdSensor.java @@ -26,6 +26,7 @@ import org.slf4j.LoggerFactory; import org.sonar.api.CoreProperties; import org.sonar.api.batch.Sensor; import org.sonar.api.batch.SensorContext; +import org.sonar.api.config.Settings; import org.sonar.api.resources.Project; public class CpdSensor implements Sensor { @@ -34,10 +35,12 @@ public class CpdSensor implements Sensor { private CpdEngine sonarEngine; private CpdEngine sonarBridgeEngine; + private Settings settings; - public CpdSensor(SonarEngine sonarEngine, SonarBridgeEngine sonarBridgeEngine) { + public CpdSensor(SonarEngine sonarEngine, SonarBridgeEngine sonarBridgeEngine, Settings settings) { this.sonarEngine = sonarEngine; this.sonarBridgeEngine = sonarBridgeEngine; + this.settings = settings; } public boolean shouldExecuteOnProject(Project project) { @@ -65,9 +68,11 @@ public class CpdSensor implements Sensor { @VisibleForTesting boolean isSkipped(Project project) { - Configuration conf = project.getConfiguration(); - return conf.getBoolean("sonar.cpd." + project.getLanguageKey() + ".skip", - conf.getBoolean(CoreProperties.CPD_SKIP_PROPERTY, false)); + String key = "sonar.cpd." + project.getLanguageKey() + ".skip"; + if (settings.hasKey(key)) { + return settings.getBoolean(key); + } + return settings.getBoolean(CoreProperties.CPD_SKIP_PROPERTY); } public void analyse(Project project, SensorContext context) { diff --git a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/index/IndexFactory.java b/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/index/IndexFactory.java index 033e359ec00..21335c46d0a 100644 --- a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/index/IndexFactory.java +++ b/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/index/IndexFactory.java @@ -38,15 +38,6 @@ public class IndexFactory implements BatchExtension { private final ResourcePersister resourcePersister; private final DuplicationDao dao; - /** - * For dry run, where is no access to database. - */ - public IndexFactory(Settings settings) { - this.settings = settings; - this.resourcePersister = null; - this.dao = null; - } - public IndexFactory(Settings settings, ResourcePersister resourcePersister, DuplicationDao dao) { this.settings = settings; this.resourcePersister = resourcePersister; @@ -54,23 +45,28 @@ public class IndexFactory implements BatchExtension { } public SonarDuplicationsIndex create(Project project) { - if (isCrossProject(project)) { - LOG.info("Cross-project analysis enabled"); + if (verifyCrossProject(project, LOG)) { return new SonarDuplicationsIndex(new DbDuplicationsIndex(resourcePersister, project, dao)); - } else { - LOG.info("Cross-project analysis disabled"); - return new SonarDuplicationsIndex(); } + return new SonarDuplicationsIndex(); } - /** - * @return true, if was enabled by user and database is available - */ @VisibleForTesting - boolean isCrossProject(Project project) { - return settings.getBoolean(CoreProperties.CPD_CROSS_RPOJECT) - && resourcePersister != null && dao != null - && StringUtils.isBlank(project.getBranch()); - } + boolean verifyCrossProject(Project project, Logger logger) { + boolean crossProject = false; + if (settings.getBoolean(CoreProperties.CPD_CROSS_RPOJECT)) { + if (settings.getBoolean("sonar.dryRun")) { + logger.info("Cross-project analysis disabled. Not supported on dry runs."); + } else if (StringUtils.isNotBlank(project.getBranch())) { + logger.info("Cross-project analysis disabled. Not supported on project branches."); + } else { + logger.info("Cross-project analysis enabled"); + crossProject = true; + } + } else { + logger.info("Cross-project analysis disabled"); + } + return crossProject; + } } diff --git a/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/CpdPluginTest.java b/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/CpdPluginTest.java index 0c309396e55..a3ec3f05048 100644 --- a/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/CpdPluginTest.java +++ b/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/CpdPluginTest.java @@ -19,14 +19,14 @@ */ package org.sonar.plugins.cpd; -import static org.hamcrest.number.OrderingComparisons.greaterThan; -import static org.junit.Assert.assertThat; import org.junit.Test; +import static org.fest.assertions.Assertions.assertThat; + public class CpdPluginTest { @Test public void getExtensions() { - assertThat(new CpdPlugin().getExtensions().size(), greaterThan(1)); + assertThat(new CpdPlugin().getExtensions()).hasSize(6); } } diff --git a/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/CpdSensorTest.java b/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/CpdSensorTest.java index d49dd75daf2..4d17611c5f0 100644 --- a/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/CpdSensorTest.java +++ b/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/CpdSensorTest.java @@ -22,70 +22,55 @@ package org.sonar.plugins.cpd; import org.apache.commons.configuration.PropertiesConfiguration; import org.junit.Before; import org.junit.Test; +import org.sonar.api.config.PropertyDefinitions; +import org.sonar.api.config.Settings; import org.sonar.api.resources.Java; import org.sonar.api.resources.Language; import org.sonar.api.resources.Project; import org.sonar.plugins.cpd.index.IndexFactory; -import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertTrue; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; +import static org.fest.assertions.Assertions.assertThat; import static org.mockito.Mockito.mock; public class CpdSensorTest { - private SonarEngine sonarEngine; - private SonarBridgeEngine sonarBridgeEngine; - private CpdSensor sensor; + SonarEngine sonarEngine; + SonarBridgeEngine sonarBridgeEngine; + CpdSensor sensor; + Settings settings; @Before public void setUp() { - IndexFactory indexFactory = new IndexFactory(null); + IndexFactory indexFactory = mock(IndexFactory.class); sonarEngine = new SonarEngine(indexFactory); sonarBridgeEngine = new SonarBridgeEngine(indexFactory); - sensor = new CpdSensor(sonarEngine, sonarBridgeEngine); + settings = new Settings(new PropertyDefinitions(CpdPlugin.class)); + sensor = new CpdSensor(sonarEngine, sonarBridgeEngine, settings); } @Test - public void generalSkip() { - PropertiesConfiguration conf = new PropertiesConfiguration(); - conf.setProperty("sonar.cpd.skip", "true"); - - Project project = createJavaProject().setConfiguration(conf); - - assertTrue(sensor.isSkipped(project)); + public void test_global_skip() { + settings.setProperty("sonar.cpd.skip", true); + assertThat(sensor.isSkipped(createJavaProject())).isTrue(); } @Test - public void doNotSkipByDefault() { - Project project = createJavaProject().setConfiguration(new PropertiesConfiguration()); - - assertFalse(sensor.isSkipped(project)); + public void should_not_skip_by_default() { + assertThat(sensor.isSkipped(createJavaProject())).isFalse(); } @Test - public void shouldSkipByLanguage() { - - Project phpProject = createPhpProject(); - phpProject.getConfiguration().setProperty("sonar.cpd.skip", "false"); - phpProject.getConfiguration().setProperty("sonar.cpd.php.skip", "true"); - assertTrue(sensor.isSkipped(phpProject)); - - Project javaProject = createJavaProject(); - javaProject.getConfiguration().setProperty("sonar.cpd.skip", "false"); - javaProject.getConfiguration().setProperty("sonar.cpd.php.skip", "true"); - assertFalse(sensor.isSkipped(javaProject)); - + public void should_skip_by_language() { + settings.setProperty("sonar.cpd.skip", false); + settings.setProperty("sonar.cpd.php.skip", true); + assertThat(sensor.isSkipped(createPhpProject())).isTrue(); + assertThat(sensor.isSkipped(createJavaProject())).isFalse(); } @Test - public void engine() { - Project phpProject = createPhpProject(); - Project javaProject = createJavaProject(); - - assertThat(sensor.getEngine(javaProject), is((CpdEngine) sonarEngine)); - assertThat(sensor.getEngine(phpProject), is((CpdEngine) sonarBridgeEngine)); + public void test_engine() { + assertThat(sensor.getEngine(createJavaProject())).isSameAs(sonarEngine); + assertThat(sensor.getEngine(createPhpProject())).isSameAs(sonarBridgeEngine); } private Project createJavaProject() { diff --git a/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/index/IndexFactoryTest.java b/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/index/IndexFactoryTest.java index 840a08a1af9..e73bffa4acc 100644 --- a/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/index/IndexFactoryTest.java +++ b/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/index/IndexFactoryTest.java @@ -21,54 +21,57 @@ package org.sonar.plugins.cpd.index; import org.junit.Before; import org.junit.Test; +import org.slf4j.Logger; import org.sonar.api.CoreProperties; import org.sonar.api.config.Settings; import org.sonar.api.resources.Project; import org.sonar.batch.index.ResourcePersister; import org.sonar.core.duplication.DuplicationDao; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; +import static org.fest.assertions.Assertions.assertThat; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; public class IndexFactoryTest { - private Project project; - private Settings settings; + Project project; + Settings settings; + IndexFactory factory; + Logger logger; @Before public void setUp() { project = new Project("foo"); settings = new Settings(); + factory = new IndexFactory(settings, mock(ResourcePersister.class), mock(DuplicationDao.class)); + logger = mock(Logger.class); } @Test public void crossProjectEnabled() { settings.setProperty(CoreProperties.CPD_CROSS_RPOJECT, "true"); - IndexFactory factory = new IndexFactory(settings, mock(ResourcePersister.class), mock(DuplicationDao.class)); - assertThat(factory.isCrossProject(project), is(true)); + assertThat(factory.verifyCrossProject(project, logger)).isTrue(); } @Test public void noCrossProjectWithBranch() { settings.setProperty(CoreProperties.CPD_CROSS_RPOJECT, "true"); - IndexFactory factory = new IndexFactory(settings, mock(ResourcePersister.class), mock(DuplicationDao.class)); project.setBranch("branch"); - assertThat(factory.isCrossProject(project), is(false)); + assertThat(factory.verifyCrossProject(project, logger)).isFalse(); } @Test - public void noCrossProjectWithoutDatabase() { + public void cross_project_should_be_disabled_on_dry_run() { settings.setProperty(CoreProperties.CPD_CROSS_RPOJECT, "true"); - IndexFactory factory = new IndexFactory(settings); - assertThat(factory.isCrossProject(project), is(false)); + settings.setProperty("sonar.dryRun", "true"); + assertThat(factory.verifyCrossProject(project, logger)).isFalse(); + verify(logger).info("Cross-project analysis disabled. Not supported on dry runs."); } @Test public void crossProjectDisabled() { settings.setProperty(CoreProperties.CPD_CROSS_RPOJECT, "false"); - IndexFactory factory = new IndexFactory(settings, mock(ResourcePersister.class), mock(DuplicationDao.class)); - assertThat(factory.isCrossProject(project), is(false)); + assertThat(factory.verifyCrossProject(project, logger)).isFalse(); } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchModule.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchModule.java index 590d503bcf1..0414d6ee424 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchModule.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchModule.java @@ -34,7 +34,6 @@ import org.sonar.batch.components.PastSnapshotFinderByDays; import org.sonar.batch.components.PastSnapshotFinderByPreviousAnalysis; import org.sonar.batch.components.PastSnapshotFinderByPreviousVersion; import org.sonar.batch.components.PastSnapshotFinderByVersion; -import org.sonar.batch.config.BatchDatabaseSettingsLoader; import org.sonar.batch.index.DefaultIndex; import org.sonar.batch.index.DefaultPersistenceManager; import org.sonar.batch.index.DefaultResourcePersister; @@ -111,7 +110,7 @@ public class BatchModule extends Module { container.addSingleton(BatchDatabase.class); container.addSingleton(MyBatis.class); container.addSingleton(DatabaseVersion.class); - container.addSingleton(DatabaseBatchCompatibility.class); + container.addSingleton(DatabaseCompatibility.class); for (Class daoClass : DaoUtils.getDaoClasses()) { container.addSingleton(daoClass); } @@ -120,7 +119,6 @@ public class BatchModule extends Module { container.addSingleton(DefaultDatabaseConnector.class); container.addSingleton(JpaDatabaseSession.class); container.addSingleton(BatchDatabaseSessionFactory.class); - container.addSingleton(BatchDatabaseSettingsLoader.class); } private void registerBatchExtensions() { diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapModule.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapModule.java index bff8f081095..6951993e578 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapModule.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapModule.java @@ -27,6 +27,7 @@ import org.sonar.batch.FakeMavenPluginExecutor; import org.sonar.batch.MavenPluginExecutor; import org.sonar.batch.ServerMetadata; import org.sonar.batch.config.BootstrapSettings; +import org.sonar.batch.config.BootstrapSettingsLoader; import org.sonar.core.config.Logback; import org.sonar.wsclient.Sonar; @@ -60,6 +61,7 @@ public class BootstrapModule extends Module { container.addSingleton(HttpDownloader.class); container.addSingleton(UriReader.class); container.addSingleton(PluginDownloader.class); + container.addSingleton(BootstrapSettingsLoader.class); for (Object component : boostrapperComponents) { if (component != null) { container.addSingleton(component); diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/DatabaseBatchCompatibility.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/DatabaseBatchCompatibility.java deleted file mode 100644 index 9017d3225bf..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/DatabaseBatchCompatibility.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2008-2012 SonarSource - * mailto:contact AT sonarsource DOT com - * - * Sonar 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. - * - * Sonar 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 Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.batch.bootstrap; - -import org.sonar.api.BatchComponent; -import org.sonar.api.config.Settings; -import org.sonar.api.database.DatabaseProperties; -import org.sonar.core.persistence.BadDatabaseVersion; -import org.sonar.core.persistence.DatabaseVersion; - -/** - * Detects if database is not up-to-date with the version required by the batch. - */ -public class DatabaseBatchCompatibility implements BatchComponent { - - private DatabaseVersion version; - private Settings settings; - private ServerClient server; - - public DatabaseBatchCompatibility(DatabaseVersion version, ServerClient server, Settings settings) { - this.version = version; - this.server = server; - this.settings = settings; - } - - public void start() { - checkCorrectServerId(); - checkDatabaseStatus(); - } - - private void checkCorrectServerId() { - if (!version.getSonarCoreId().equals(server.getServerId())) { - StringBuilder message = new StringBuilder("The current batch process and the configured remote server do not share the same DB configuration.\n"); - message.append("\t- Batch side: "); - message.append(settings.getString(DatabaseProperties.PROP_URL)); - message.append(" ("); - String userName = settings.getString(DatabaseProperties.PROP_USER); - message.append(userName == null ? "sonar" : userName); - message.append(" / *****)\n\t- Server side: check the configuration at "); - message.append(server.getURL()); - message.append("/system\n"); - throw new BadDatabaseVersion(message.toString()); - } - } - - private void checkDatabaseStatus() { - DatabaseVersion.Status status = version.getStatus(); - if (status == DatabaseVersion.Status.REQUIRES_DOWNGRADE) { - throw new BadDatabaseVersion("Database relates to a more recent version of Sonar. Please check your settings (JDBC settings, version of Maven plugin)"); - } - if (status == DatabaseVersion.Status.REQUIRES_UPGRADE) { - throw new BadDatabaseVersion("Database must be upgraded. Please browse " + server.getURL() + "/setup"); - } - if (status != DatabaseVersion.Status.UP_TO_DATE) { - // Support other future values - throw new BadDatabaseVersion("Unknown database status: " + status); - } - } - -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/DatabaseCompatibility.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/DatabaseCompatibility.java new file mode 100644 index 00000000000..3d1c06ec579 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/DatabaseCompatibility.java @@ -0,0 +1,80 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.bootstrap; + +import org.sonar.api.BatchComponent; +import org.sonar.api.CoreProperties; +import org.sonar.api.config.Settings; +import org.sonar.api.database.DatabaseProperties; +import org.sonar.core.persistence.BadDatabaseVersion; +import org.sonar.core.persistence.DatabaseVersion; + +/** + * Detects if database is not up-to-date with the version required by the batch. + */ +public class DatabaseCompatibility implements BatchComponent { + + private DatabaseVersion version; + private Settings settings; + private ServerClient server; + + public DatabaseCompatibility(DatabaseVersion version, ServerClient server, Settings settings) { + this.version = version; + this.server = server; + this.settings = settings; + } + + public void start() { + if (!settings.getBoolean("sonar.dryRun")) { + checkCorrectServerId(); + checkDatabaseStatus(); + } + } + + private void checkCorrectServerId() { + if (!settings.getString(CoreProperties.SERVER_ID).equals(server.getServerId())) { + StringBuilder message = new StringBuilder("The current batch process and the configured remote server do not share the same DB configuration.\n"); + message.append("\t- Batch side: "); + message.append(settings.getString(DatabaseProperties.PROP_URL)); + message.append(" ("); + String userName = settings.getString(DatabaseProperties.PROP_USER); + message.append(userName == null ? "sonar" : userName); + message.append(" / *****)\n\t- Server side: check the configuration at "); + message.append(server.getURL()); + message.append("/system\n"); + throw new BadDatabaseVersion(message.toString()); + } + } + + private void checkDatabaseStatus() { + DatabaseVersion.Status status = version.getStatus(); + if (status == DatabaseVersion.Status.REQUIRES_DOWNGRADE) { + throw new BadDatabaseVersion("Database relates to a more recent version of Sonar. Please check your settings (JDBC settings, version of Maven plugin)"); + } + if (status == DatabaseVersion.Status.REQUIRES_UPGRADE) { + throw new BadDatabaseVersion("Database must be upgraded. Please browse " + server.getURL() + "/setup"); + } + if (status != DatabaseVersion.Status.UP_TO_DATE) { + // Support other future values + throw new BadDatabaseVersion("Unknown database status: " + status); + } + } + +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectExclusions.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectExclusions.java index 050dae89154..9b078d2f249 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectExclusions.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectExclusions.java @@ -42,7 +42,9 @@ public class ProjectExclusions implements BatchComponent { private Settings settings; private ProjectReactor reactor; - public ProjectExclusions(Settings settings, ProjectReactor reactor, ProjectBuilder[] projectBuilders) { + public ProjectExclusions(Settings settings, ProjectReactor reactor, + // exclusions are applied when the project is completely defined by extensions + ProjectBuilder[] projectBuilders) { this.settings = settings; this.reactor = reactor; } diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectModule.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectModule.java index 4d3450b6247..0acaa7c9ba0 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectModule.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectModule.java @@ -73,8 +73,8 @@ public class ProjectModule extends Module { } ProjectDefinition projectDefinition = container.getComponentByType(ProjectTree.class).getProjectDefinition(project); container.addSingleton(projectDefinition); - container.addSingleton(project); container.addSingleton(project.getConfiguration()); + container.addSingleton(project); container.addSingleton(ProjectSettings.class); container.addSingleton(UnsupportedProperties.class); diff --git a/sonar-batch/src/main/java/org/sonar/batch/config/BatchDatabaseSettingsLoader.java b/sonar-batch/src/main/java/org/sonar/batch/config/BatchDatabaseSettingsLoader.java deleted file mode 100644 index 8a03eb01053..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/config/BatchDatabaseSettingsLoader.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2008-2012 SonarSource - * mailto:contact AT sonarsource DOT com - * - * Sonar 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. - * - * Sonar 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 Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.batch.config; - -import org.apache.commons.lang.StringUtils; -import org.sonar.api.CoreProperties; -import org.sonar.api.batch.bootstrap.ProjectReactor; -import org.sonar.core.properties.PropertiesDao; -import org.sonar.core.properties.PropertyDto; - -import java.util.List; - -/** - * @since 2.12 - */ -public final class BatchDatabaseSettingsLoader { - - private PropertiesDao propertiesDao; - private BootstrapSettings settings; - private ProjectReactor reactor; - - public BatchDatabaseSettingsLoader(PropertiesDao propertiesDao, BootstrapSettings settings, ProjectReactor reactor) { - this.propertiesDao = propertiesDao; - this.settings = settings; - this.reactor = reactor; - } - - public void start() { - String branch = settings.getString(CoreProperties.PROJECT_BRANCH_PROPERTY); - String projectKey = reactor.getRoot().getKey(); - if (StringUtils.isNotBlank(branch)) { - projectKey = String.format("%s:%s", projectKey, branch); - } - setIfNotDefined(propertiesDao.selectProjectProperties(projectKey)); - setIfNotDefined(propertiesDao.selectGlobalProperties()); - settings.updateDeprecatedCommonsConfiguration(); - } - - private void setIfNotDefined(List dbProperties) { - for (PropertyDto dbProperty : dbProperties) { - if (!settings.hasKey(dbProperty.getKey())) { - settings.setProperty(dbProperty.getKey(), dbProperty.getValue()); - } - } - } -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/config/BootstrapSettings.java b/sonar-batch/src/main/java/org/sonar/batch/config/BootstrapSettings.java index a2267e87cc7..1d7caab9509 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/config/BootstrapSettings.java +++ b/sonar-batch/src/main/java/org/sonar/batch/config/BootstrapSettings.java @@ -28,7 +28,7 @@ import org.sonar.core.config.ConfigurationUtils; /** * @since 2.12 */ -public final class BootstrapSettings extends Settings { +public class BootstrapSettings extends Settings { private Configuration deprecatedConfiguration; private ProjectReactor reactor; diff --git a/sonar-batch/src/main/java/org/sonar/batch/config/BootstrapSettingsLoader.java b/sonar-batch/src/main/java/org/sonar/batch/config/BootstrapSettingsLoader.java new file mode 100644 index 00000000000..02563c7a240 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/config/BootstrapSettingsLoader.java @@ -0,0 +1,69 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.config; + +import org.apache.commons.lang.StringUtils; +import org.slf4j.LoggerFactory; +import org.sonar.api.CoreProperties; +import org.sonar.api.batch.bootstrap.ProjectReactor; +import org.sonar.wsclient.Sonar; +import org.sonar.wsclient.services.Property; +import org.sonar.wsclient.services.PropertyQuery; + +import java.util.List; + +/** + * Load global settings and project settings. Note that the definition of modules is + * incomplete before the execution of ProjectBuilder extensions, so module settings + * are not loaded yet. + * @since 3.4 + */ +public final class BootstrapSettingsLoader { + + private BootstrapSettings settings; + private ProjectReactor reactor; + private Sonar wsClient; + + public BootstrapSettingsLoader(BootstrapSettings settings, ProjectReactor reactor, Sonar wsClient) { + this.settings = settings; + this.reactor = reactor; + this.wsClient = wsClient; + } + + public void start() { + LoggerFactory.getLogger(BootstrapSettingsLoader.class).info("Load project settings"); + String branch = settings.getString(CoreProperties.PROJECT_BRANCH_PROPERTY); + String projectKey = reactor.getRoot().getKey(); + if (StringUtils.isNotBlank(branch)) { + projectKey = String.format("%s:%s", projectKey, branch); + } + List wsProperties = wsClient.findAll(PropertyQuery.createForAll().setResourceKeyOrId(projectKey)); + for (Property wsProperty : wsProperties) { + setIfNotDefined(wsProperty); + } + settings.updateDeprecatedCommonsConfiguration(); + } + + private void setIfNotDefined(Property wsProperty) { + if (!settings.hasKey(wsProperty.getKey())) { + settings.setProperty(wsProperty.getKey(), wsProperty.getValue()); + } + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/config/ProjectSettings.java b/sonar-batch/src/main/java/org/sonar/batch/config/ProjectSettings.java index d470a9cdb02..330100f328b 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/config/ProjectSettings.java +++ b/sonar-batch/src/main/java/org/sonar/batch/config/ProjectSettings.java @@ -22,14 +22,16 @@ package org.sonar.batch.config; import com.google.common.collect.Lists; import org.apache.commons.configuration.Configuration; import org.apache.commons.lang.StringUtils; +import org.slf4j.LoggerFactory; import org.sonar.api.CoreProperties; import org.sonar.api.batch.bootstrap.ProjectDefinition; -import org.sonar.api.config.PropertyDefinitions; import org.sonar.api.config.Settings; -import org.sonar.api.resources.Project; import org.sonar.core.config.ConfigurationUtils; -import org.sonar.core.properties.PropertiesDao; -import org.sonar.core.properties.PropertyDto; +import org.sonar.wsclient.Sonar; +import org.sonar.wsclient.services.Property; +import org.sonar.wsclient.services.PropertyQuery; + +import javax.annotation.Nullable; import java.util.List; @@ -39,81 +41,77 @@ import java.util.List; public class ProjectSettings extends Settings { private Configuration deprecatedCommonsConf; - private ProjectDefinition projectDefinition; - private PropertiesDao propertiesDao; - public ProjectSettings(PropertyDefinitions definitions, ProjectDefinition projectDefinition, PropertiesDao propertiesDao, Project project) { - super(definitions); - this.deprecatedCommonsConf = project.getConfiguration(); // Configuration is not a parameter to be sure that the project conf is used, not the global one - this.projectDefinition = projectDefinition; - this.propertiesDao = propertiesDao; - load(); - } + public ProjectSettings(BootstrapSettings bootstrapSettings, ProjectDefinition project, + Sonar wsClient, Configuration deprecatedCommonsConf) { + super(bootstrapSettings.getDefinitions()); - public ProjectSettings load() { - clear(); + LoggerFactory.getLogger(ProjectSettings.class).info("Load module settings"); + this.deprecatedCommonsConf = deprecatedCommonsConf; + if (project.getParent() == null) { + // root project -> no need to reload settings + copy(bootstrapSettings); + } else { + init(project, bootstrapSettings, wsClient); + } + } - // hack to obtain "sonar.branch" before loading settings from database - loadBuildProperties(); - addEnvironmentVariables(); - addSystemProperties(); - String branch = getString(CoreProperties.PROJECT_BRANCH_PROPERTY); - clear(); + private void copy(BootstrapSettings bootstrapSettings) { + setProperties(bootstrapSettings); + } - // order is important -> bottom-up. The last one overrides all the others. - loadDatabaseGlobalSettings(); - loadDatabaseProjectSettings(projectDefinition, branch); - loadBuildProperties(); + private ProjectSettings init(ProjectDefinition project, BootstrapSettings bootstrapSettings, Sonar wsClient) { + addPersistedProperties(project, bootstrapSettings, wsClient); + addBuildProperties(project); addEnvironmentVariables(); addSystemProperties(); - - updateDeprecatedCommonsConfiguration(); - return this; } - private void loadBuildProperties() { - List orderedProjects = getOrderedProjects(projectDefinition); - for (ProjectDefinition p : orderedProjects) { - addProperties(p.getProperties()); - } - } - - private void loadDatabaseProjectSettings(ProjectDefinition projectDef, String branch) { - if (projectDef.getParent() != null) { - loadDatabaseProjectSettings(projectDef.getParent(), branch); - } - String projectKey = projectDef.getKey(); + private void addPersistedProperties(ProjectDefinition project, BootstrapSettings bootstrapSettings, Sonar wsClient) { + String branch = bootstrapSettings.getString(CoreProperties.PROJECT_BRANCH_PROPERTY); + String projectKey = project.getKey(); if (StringUtils.isNotBlank(branch)) { projectKey = String.format("%s:%s", projectKey, branch); } - List props = propertiesDao.selectProjectProperties(projectKey); - for (PropertyDto dbProperty : props) { - setProperty(dbProperty.getKey(), dbProperty.getValue()); + List wsProperties = wsClient.findAll(PropertyQuery.createForAll().setResourceKeyOrId(projectKey)); + for (Property wsProperty : wsProperties) { + setProperty(wsProperty.getKey(), wsProperty.getValue()); } } - private void loadDatabaseGlobalSettings() { - List props = propertiesDao.selectGlobalProperties(); - for (PropertyDto dbProperty : props) { - setProperty(dbProperty.getKey(), dbProperty.getValue()); + private void addBuildProperties(ProjectDefinition project) { + List orderedProjects = getTopDownParentProjects(project); + for (ProjectDefinition p : orderedProjects) { + addProperties(p.getProperties()); } } - private void updateDeprecatedCommonsConfiguration() { - ConfigurationUtils.copyToCommonsConfiguration(properties, deprecatedCommonsConf); - } - /** - * From root to module + * From root to given project */ - static List getOrderedProjects(ProjectDefinition project) { + static List getTopDownParentProjects(ProjectDefinition project) { List result = Lists.newArrayList(); - ProjectDefinition pd = project; - while (pd != null) { - result.add(0, pd); - pd = pd.getParent(); + ProjectDefinition p = project; + while (p != null) { + result.add(0, p); + p = p.getParent(); } return result; } + + @Override + protected void doOnSetProperty(String key, @Nullable String value) { + deprecatedCommonsConf.setProperty(key, value); + } + + @Override + protected void doOnRemoveProperty(String key) { + deprecatedCommonsConf.clearProperty(key); + } + + @Override + protected void doOnClearProperties() { + deprecatedCommonsConf.clear(); + } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/local/DryRunDatabase.java b/sonar-batch/src/main/java/org/sonar/batch/local/DryRunDatabase.java index c2f69706d58..4149940feb8 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/local/DryRunDatabase.java +++ b/sonar-batch/src/main/java/org/sonar/batch/local/DryRunDatabase.java @@ -71,6 +71,7 @@ public class DryRunDatabase implements BatchComponent { return; } + LOG.info("Install dry run database"); File databaseFile = tempDirectories.getFile("dry_run", "db.h2.db"); downloadDatabase(reactor.getRoot().getKey(), databaseFile); @@ -79,8 +80,6 @@ public class DryRunDatabase implements BatchComponent { } private void downloadDatabase(String projectKey, File toFile) { - LOG.info("Downloading DryRun database for project [{}]", projectKey); - try { server.download(API_SYNCHRO + "?resource=" + projectKey, toFile); } catch (SonarException e) { @@ -95,8 +94,6 @@ public class DryRunDatabase implements BatchComponent { } private void replaceSettings(String databasePath) { - LOG.info("Overriding database settings"); - settings .setProperty("sonar.jdbc.schema", "") .setProperty(DatabaseProperties.PROP_DIALECT, DIALECT) diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/DatabaseBatchCompatibilityTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/DatabaseBatchCompatibilityTest.java deleted file mode 100644 index bddab1a63ec..00000000000 --- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/DatabaseBatchCompatibilityTest.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2008-2012 SonarSource - * mailto:contact AT sonarsource DOT com - * - * Sonar 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. - * - * Sonar 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 Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.batch.bootstrap; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.config.Settings; -import org.sonar.api.database.DatabaseProperties; -import org.sonar.api.utils.SonarException; -import org.sonar.core.persistence.BadDatabaseVersion; -import org.sonar.core.persistence.DatabaseVersion; - -import java.io.IOException; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class DatabaseBatchCompatibilityTest { - - @Rule - public ExpectedException thrown = ExpectedException.none(); - - private DatabaseVersion databaseVersion; - private ServerClient server; - private Settings settings; - - @Before - public void init() throws Exception { - databaseVersion = mock(DatabaseVersion.class); - when(databaseVersion.getSonarCoreId()).thenReturn("123456"); - - server = mock(ServerClient.class); - when(server.getURL()).thenReturn("http://localhost:9000"); - when(server.getServerId()).thenReturn("123456"); - - settings = new Settings(); - settings.setProperty(DatabaseProperties.PROP_URL, "jdbc:postgresql://localhost/foo"); - settings.setProperty(DatabaseProperties.PROP_USER, "bar"); - } - - @Test - public void shouldFailIfRequiresDowngrade() { - when(databaseVersion.getStatus()).thenReturn(DatabaseVersion.Status.REQUIRES_DOWNGRADE); - - thrown.expect(BadDatabaseVersion.class); - thrown.expectMessage("Database relates to a more recent version of Sonar. Please check your settings (JDBC settings, version of Maven plugin)"); - - new DatabaseBatchCompatibility(databaseVersion, server, settings).start(); - } - - @Test - public void shouldFailIfRequiresUpgrade() { - when(databaseVersion.getStatus()).thenReturn(DatabaseVersion.Status.REQUIRES_UPGRADE); - - thrown.expect(BadDatabaseVersion.class); - thrown.expectMessage("Database must be upgraded."); - - new DatabaseBatchCompatibility(databaseVersion, server, settings).start(); - } - - @Test - public void shouldFailIfNotSameServerId() throws Exception { - DatabaseVersion version = mock(DatabaseVersion.class); - when(version.getSonarCoreId()).thenReturn("1111111"); - - thrown.expect(BadDatabaseVersion.class); - thrown.expectMessage("The current batch process and the configured remote server do not share the same DB configuration."); - thrown.expectMessage("- Batch side: jdbc:postgresql://localhost/foo (bar / *****)"); - thrown.expectMessage("- Server side: check the configuration at http://localhost:9000/system"); - - new DatabaseBatchCompatibility(version, server, settings).start(); - } - - @Test - public void shouldUseDefaultUserNameWhenFaillingIfNotSameServerIdAndNoUserNameFound() throws Exception { - DatabaseVersion version = mock(DatabaseVersion.class); - when(version.getSonarCoreId()).thenReturn("1111111"); - - settings.removeProperty(DatabaseProperties.PROP_USER); - - thrown.expect(BadDatabaseVersion.class); - thrown.expectMessage("- Batch side: jdbc:postgresql://localhost/foo (sonar / *****)"); - - new DatabaseBatchCompatibility(version, server, settings).start(); - } - - @Test - public void shouldFailIfCantGetServerId() throws Exception { - when(server.getServerId()).thenThrow(new IllegalStateException()); - - thrown.expect(IllegalStateException.class); - - new DatabaseBatchCompatibility(mock(DatabaseVersion.class), server, settings).start(); - } - - @Test - public void shouldDoNothingIfUpToDate() { - when(databaseVersion.getStatus()).thenReturn(DatabaseVersion.Status.UP_TO_DATE); - new DatabaseBatchCompatibility(databaseVersion, server, settings).start(); - // no error - } -} diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/DatabaseCompatibilityTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/DatabaseCompatibilityTest.java new file mode 100644 index 00000000000..41489b7b530 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/DatabaseCompatibilityTest.java @@ -0,0 +1,128 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.bootstrap; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.CoreProperties; +import org.sonar.api.config.Settings; +import org.sonar.api.database.DatabaseProperties; +import org.sonar.core.persistence.BadDatabaseVersion; +import org.sonar.core.persistence.DatabaseVersion; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class DatabaseCompatibilityTest { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + DatabaseVersion databaseVersion; + ServerClient server; + Settings settings; + + @Before + public void init() { + server = mock(ServerClient.class); + when(server.getURL()).thenReturn("http://localhost:9000"); + when(server.getServerId()).thenReturn("123456"); + + settings = new Settings(); + settings.setProperty(DatabaseProperties.PROP_URL, "jdbc:postgresql://localhost/foo"); + settings.setProperty(DatabaseProperties.PROP_USER, "bar"); + settings.setProperty(CoreProperties.SERVER_ID, "123456"); + settings.setProperty("sonar.dryRun", false); + + databaseVersion = mock(DatabaseVersion.class); + } + + @Test + public void shouldFailIfRequiresDowngrade() { + when(databaseVersion.getStatus()).thenReturn(DatabaseVersion.Status.REQUIRES_DOWNGRADE); + + thrown.expect(BadDatabaseVersion.class); + thrown.expectMessage("Database relates to a more recent version of Sonar. Please check your settings (JDBC settings, version of Maven plugin)"); + + new DatabaseCompatibility(databaseVersion, server, settings).start(); + } + + @Test + public void shouldFailIfRequiresUpgrade() { + when(databaseVersion.getStatus()).thenReturn(DatabaseVersion.Status.REQUIRES_UPGRADE); + + thrown.expect(BadDatabaseVersion.class); + thrown.expectMessage("Database must be upgraded."); + + new DatabaseCompatibility(databaseVersion, server, settings).start(); + } + + @Test + public void shouldFailIfNotSameServerId() throws Exception { + settings.setProperty(CoreProperties.SERVER_ID, "11111111"); + + thrown.expect(BadDatabaseVersion.class); + thrown.expectMessage("The current batch process and the configured remote server do not share the same DB configuration."); + thrown.expectMessage("- Batch side: jdbc:postgresql://localhost/foo (bar / *****)"); + thrown.expectMessage("- Server side: check the configuration at http://localhost:9000/system"); + + new DatabaseCompatibility(databaseVersion, server, settings).start(); + } + + @Test + public void shouldUseDefaultUserNameWhenFaillingIfNotSameServerIdAndNoUserNameFound() throws Exception { + settings.setProperty(CoreProperties.SERVER_ID, "11111111"); + + settings.removeProperty(DatabaseProperties.PROP_USER); + + thrown.expect(BadDatabaseVersion.class); + thrown.expectMessage("- Batch side: jdbc:postgresql://localhost/foo (sonar / *****)"); + + new DatabaseCompatibility(databaseVersion, server, settings).start(); + } + + @Test + public void shouldFailIfCantGetServerId() throws Exception { + when(server.getServerId()).thenThrow(new IllegalStateException()); + + thrown.expect(IllegalStateException.class); + + new DatabaseCompatibility(mock(DatabaseVersion.class), server, settings).start(); + } + + @Test + public void shouldDoNothingIfUpToDate() { + when(databaseVersion.getStatus()).thenReturn(DatabaseVersion.Status.UP_TO_DATE); + new DatabaseCompatibility(databaseVersion, server, settings).start(); + // no error + } + + @Test + public void should_not_verify_compatibility_if_dry_run() { + settings.setProperty(CoreProperties.SERVER_ID, "11111111"); + settings.setProperty("sonar.dryRun", true); + + new DatabaseCompatibility(databaseVersion, server, settings).start(); + + // no failure + } +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectModuleTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectModuleTest.java index 2cacc9a4931..adad9113158 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectModuleTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectModuleTest.java @@ -22,6 +22,8 @@ package org.sonar.batch.bootstrap; import org.apache.commons.configuration.PropertiesConfiguration; import org.junit.Test; import org.mockito.Matchers; +import org.mockito.MockSettings; +import org.mockito.Mockito; import org.sonar.api.batch.InstantiationStrategy; import org.sonar.api.batch.bootstrap.ProjectDefinition; import org.sonar.api.database.model.Snapshot; @@ -29,9 +31,11 @@ import org.sonar.api.platform.ComponentContainer; import org.sonar.api.resources.Project; import org.sonar.api.resources.Resource; import org.sonar.batch.ProjectTree; +import org.sonar.batch.config.BootstrapSettings; import org.sonar.batch.config.ProjectSettings; import org.sonar.batch.index.ResourcePersister; import org.sonar.core.properties.PropertiesDao; +import org.sonar.wsclient.Sonar; import static org.fest.assertions.Assertions.assertThat; import static org.mockito.Matchers.any; @@ -58,7 +62,8 @@ public class ProjectModuleTest { container.addSingleton(extensionInstaller); container.addSingleton(projectTree); container.addSingleton(resourcePersister); - container.addSingleton(mock(PropertiesDao.class)); + container.addSingleton(mock(Sonar.class)); + container.addSingleton(mock(BootstrapSettings.class)); } }; diff --git a/sonar-batch/src/test/java/org/sonar/batch/config/ProjectSettingsTest.java b/sonar-batch/src/test/java/org/sonar/batch/config/ProjectSettingsTest.java index eede4877e50..753a09921a8 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/config/ProjectSettingsTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/config/ProjectSettingsTest.java @@ -37,7 +37,7 @@ public class ProjectSettingsTest { grandParent.addSubProject(parent); parent.addSubProject(child); - List hierarchy = ProjectSettings.getOrderedProjects(child); + List hierarchy = ProjectSettings.getTopDownParentProjects(child); assertThat(hierarchy.get(0), Is.is(grandParent)); assertThat(hierarchy.get(1), Is.is(parent)); assertThat(hierarchy.get(2), Is.is(child)); 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 793723d6af0..3ed5fba82fe 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 @@ -66,17 +66,6 @@ public class DatabaseVersion implements BatchComponent, ServerComponent { } } - public String getSonarCoreId() { - SqlSession session = mybatis.openSession(); - try { - PropertyDto serverIdProperty = session.getMapper(PropertiesMapper.class).selectByKey(new PropertyDto().setKey(CoreProperties.SERVER_ID)); - // this property can't be NULL - return serverIdProperty.getValue(); - } finally { - MyBatis.closeQuietly(session); - } - } - public Status getStatus() { return getStatus(getVersion(), LAST_VERSION); } diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/DbTemplate.java b/sonar-core/src/main/java/org/sonar/core/persistence/DbTemplate.java index e83bf0c0cb3..611400aab51 100644 --- a/sonar-core/src/main/java/org/sonar/core/persistence/DbTemplate.java +++ b/sonar-core/src/main/java/org/sonar/core/persistence/DbTemplate.java @@ -41,7 +41,7 @@ public class DbTemplate implements ServerComponent { private static final Logger LOG = LoggerFactory.getLogger(DbTemplate.class); public DbTemplate copyTable(DataSource source, DataSource dest, String table, String... whereClauses) { - LOG.info("Copy table " + table); + LOG.debug("Copy table %s", table); String selectQuery = "select * from " + table; if (whereClauses.length > 0) { diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/DefaultDatabase.java b/sonar-core/src/main/java/org/sonar/core/persistence/DefaultDatabase.java index 82d3736f629..5f6c01e4429 100644 --- a/sonar-core/src/main/java/org/sonar/core/persistence/DefaultDatabase.java +++ b/sonar-core/src/main/java/org/sonar/core/persistence/DefaultDatabase.java @@ -66,6 +66,7 @@ public class DefaultDatabase implements Database { initSettings(); initDatasource(); checkConnection(); + doAfterStart(); return this; } catch (Exception e) { @@ -73,6 +74,13 @@ public class DefaultDatabase implements Database { } } + /** + * Override to execute post-startup code. + */ + protected void doAfterStart() { + + } + @VisibleForTesting void initSettings() { initProperties(); @@ -93,7 +101,7 @@ public class DefaultDatabase implements Database { if (dialect == null) { throw new IllegalStateException("Can not guess the JDBC dialect. Please check the property sonar.jdbc.url."); } - if (H2.ID.equals(dialect.getId())) { + if (H2.ID.equals(dialect.getId()) && !settings.getBoolean("sonar.dryRun")) { LoggerFactory.getLogger(DefaultDatabase.class).warn("H2 database should be used for evaluation purpose only"); } if (!properties.containsKey("sonar.jdbc.driverClassName")) { diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/DryRunDatabaseFactory.java b/sonar-core/src/main/java/org/sonar/core/persistence/DryRunDatabaseFactory.java index 9c8b5252482..6530140510d 100644 --- a/sonar-core/src/main/java/org/sonar/core/persistence/DryRunDatabaseFactory.java +++ b/sonar-core/src/main/java/org/sonar/core/persistence/DryRunDatabaseFactory.java @@ -63,10 +63,6 @@ public class DryRunDatabaseFactory implements ServerComponent { } private void copy(DataSource source, DataSource dest, Integer resourceId) { - String notSecured = "NOT (prop_key LIKE '%.secured')"; - String defaultProperty = "((user_id IS NULL) AND (resource_id IS NULL))"; - String projectProperty = (null == resourceId) ? "" : " OR (resource_id='" + resourceId + "')"; - new DbTemplate() .copyTable(source, dest, "active_rules") .copyTable(source, dest, "active_rule_parameters") @@ -74,7 +70,6 @@ public class DryRunDatabaseFactory implements ServerComponent { .copyTable(source, dest, "characteristic_edges") .copyTable(source, dest, "characteristic_properties") .copyTable(source, dest, "metrics") - .copyTable(source, dest, "properties", notSecured, defaultProperty + projectProperty) .copyTable(source, dest, "quality_models") .copyTable(source, dest, "rules") .copyTable(source, dest, "rules_parameters") diff --git a/sonar-core/src/test/java/org/sonar/core/persistence/DatabaseVersionTest.java b/sonar-core/src/test/java/org/sonar/core/persistence/DatabaseVersionTest.java index df1dce3e426..a0278eed475 100644 --- a/sonar-core/src/test/java/org/sonar/core/persistence/DatabaseVersionTest.java +++ b/sonar-core/src/test/java/org/sonar/core/persistence/DatabaseVersionTest.java @@ -19,12 +19,10 @@ */ package org.sonar.core.persistence; -import org.hamcrest.core.Is; + import org.junit.Test; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.nullValue; -import static org.junit.Assert.assertThat; +import static org.fest.assertions.Assertions.assertThat; public class DatabaseVersionTest extends AbstractDaoTestCase { @Test @@ -33,7 +31,7 @@ public class DatabaseVersionTest extends AbstractDaoTestCase { Integer version = new DatabaseVersion(getMyBatis()).getVersion(); - assertThat(version, Is.is(123)); + assertThat(version).isEqualTo(123); } @Test @@ -42,23 +40,14 @@ public class DatabaseVersionTest extends AbstractDaoTestCase { Integer version = new DatabaseVersion(getMyBatis()).getVersion(); - assertThat(version, nullValue()); - } - - @Test - public void getSonarCoreId() { - setupData("getSonarCoreId"); - - String sonarCoreId = new DatabaseVersion(getMyBatis()).getSonarCoreId(); - - assertThat(sonarCoreId, is("123456")); + assertThat(version).isNull(); } @Test public void getStatus() { - assertThat(DatabaseVersion.getStatus(null, 150), is(DatabaseVersion.Status.FRESH_INSTALL)); - assertThat(DatabaseVersion.getStatus(123, 150), is(DatabaseVersion.Status.REQUIRES_UPGRADE)); - assertThat(DatabaseVersion.getStatus(150, 150), is(DatabaseVersion.Status.UP_TO_DATE)); - assertThat(DatabaseVersion.getStatus(200, 150), is(DatabaseVersion.Status.REQUIRES_DOWNGRADE)); + assertThat(DatabaseVersion.getStatus(null, 150)).isEqualTo(DatabaseVersion.Status.FRESH_INSTALL); + assertThat(DatabaseVersion.getStatus(123, 150)).isEqualTo(DatabaseVersion.Status.REQUIRES_UPGRADE); + assertThat(DatabaseVersion.getStatus(150, 150)).isEqualTo(DatabaseVersion.Status.UP_TO_DATE); + assertThat(DatabaseVersion.getStatus(200, 150)).isEqualTo(DatabaseVersion.Status.REQUIRES_DOWNGRADE); } } diff --git a/sonar-core/src/test/java/org/sonar/core/persistence/DryRunDatabaseFactoryTest.java b/sonar-core/src/test/java/org/sonar/core/persistence/DryRunDatabaseFactoryTest.java index b44340a1fc5..aa284c22e13 100644 --- a/sonar-core/src/test/java/org/sonar/core/persistence/DryRunDatabaseFactoryTest.java +++ b/sonar-core/src/test/java/org/sonar/core/persistence/DryRunDatabaseFactoryTest.java @@ -66,8 +66,8 @@ public class DryRunDatabaseFactoryTest extends AbstractDaoTestCase { byte[] database = localDatabaseFactory.createDatabaseForDryRun(1); dataSource = createDatabase(database); - assertThat(rowCount("PROPERTIES")).isEqualTo(2); - assertThat(rowCount("PROJECTS")).isZero(); + assertThat(rowCount("metrics")).isEqualTo(2); + assertThat(rowCount("projects")).isZero(); } private BasicDataSource createDatabase(byte[] db) throws IOException { diff --git a/sonar-core/src/test/resources/org/sonar/core/persistence/DatabaseVersionTest/getSonarCoreId.xml b/sonar-core/src/test/resources/org/sonar/core/persistence/DatabaseVersionTest/getSonarCoreId.xml deleted file mode 100644 index 44b1e8eb5be..00000000000 --- a/sonar-core/src/test/resources/org/sonar/core/persistence/DatabaseVersionTest/getSonarCoreId.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/sonar-core/src/test/resources/org/sonar/core/persistence/DryRunDatabaseFactoryTest/should_create_database.xml b/sonar-core/src/test/resources/org/sonar/core/persistence/DryRunDatabaseFactoryTest/should_create_database.xml index 0e266518906..3f7360668de 100644 --- a/sonar-core/src/test/resources/org/sonar/core/persistence/DryRunDatabaseFactoryTest/should_create_database.xml +++ b/sonar-core/src/test/resources/org/sonar/core/persistence/DryRunDatabaseFactoryTest/should_create_database.xml @@ -1,9 +1,8 @@ - - - - - +