]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-4713 Fail on unprovisioned project
authorJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>
Tue, 1 Oct 2013 07:25:34 +0000 (09:25 +0200)
committerJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>
Tue, 1 Oct 2013 07:36:21 +0000 (09:36 +0200)
Add new property to make provisioning mandatory
Turn ProjectReactorValidator into an IoC-managed component
Add check at project scan bootstrap to fail if project does not exist

plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java
sonar-batch/src/main/java/org/sonar/batch/scan/ProjectReactorReady.java
sonar-batch/src/main/java/org/sonar/batch/scan/ProjectReactorValidator.java
sonar-batch/src/main/java/org/sonar/batch/scan/ScanTask.java
sonar-batch/src/test/java/org/sonar/batch/scan/ProjectReactorReadyTest.java
sonar-batch/src/test/java/org/sonar/batch/scan/ProjectReactorValidatorTest.java
sonar-batch/src/test/java/org/sonar/batch/scan/ScanTaskTest.java
sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java

index 5c12d99859a5a90b6e7fe5c62351b9ed4c4e8142..ac4dbd8b359c339afe801c47b779bb87196bc7c2 100644 (file)
@@ -377,8 +377,16 @@ public final class CorePlugin extends SonarPlugin {
         .description("Forcing user authentication stops un-logged users to access SonarQube.")
         .type(PropertyType.BOOLEAN)
         .category(CoreProperties.CATEGORY_SECURITY)
+        .build(),
+
+      PropertyDefinition.builder(CoreProperties.CORE_PREVENT_AUTOMATIC_PROJECT_CREATION)
+        .defaultValue(Boolean.toString(false))
+        .name("Prevent automatic project creation")
+        .description("Set to true to prevent automatic project creation at first analysis and force project provisioning.")
+        .type(PropertyType.BOOLEAN)
+        .category(CoreProperties.CATEGORY_SECURITY)
         .build()
-    );
+      );
   }
 
 }
index 7ac565a96613221f45c1b6aebd42984e40a647e9..d6569adedefdf7229608b97f4340092badf3ee68 100644 (file)
@@ -20,9 +20,8 @@
 package org.sonar.batch.scan;
 
 import org.sonar.api.batch.bootstrap.ProjectBuilder;
-import org.sonar.api.batch.bootstrap.internal.ProjectBuilderContext;
 import org.sonar.api.batch.bootstrap.ProjectReactor;
-import org.sonar.api.config.Settings;
+import org.sonar.api.batch.bootstrap.internal.ProjectBuilderContext;
 
 import javax.annotation.Nullable;
 
@@ -40,19 +39,19 @@ import javax.annotation.Nullable;
 public class ProjectReactorReady {
 
   private final ProjectReactor reactor;
-  private final Settings settings;
   private ProjectBuilder[] projectBuilders;
   private ProjectExclusions exclusions;
+  private ProjectReactorValidator validator;
 
-  public ProjectReactorReady(ProjectExclusions exclusions, ProjectReactor reactor, Settings settings, @Nullable ProjectBuilder[] projectBuilders) {
+  public ProjectReactorReady(ProjectExclusions exclusions, ProjectReactor reactor, @Nullable ProjectBuilder[] projectBuilders, ProjectReactorValidator validator) {
     this.exclusions = exclusions;
     this.reactor = reactor;
-    this.settings = settings;
     this.projectBuilders = projectBuilders;
+    this.validator = validator;
   }
 
-  public ProjectReactorReady(ProjectExclusions exclusions, ProjectReactor reactor, Settings settings) {
-    this(exclusions, reactor, settings, new ProjectBuilder[0]);
+  public ProjectReactorReady(ProjectExclusions exclusions, ProjectReactor reactor, ProjectReactorValidator validator) {
+    this(exclusions, reactor, new ProjectBuilder[0], validator);
   }
 
   public void start() {
@@ -67,7 +66,6 @@ public class ProjectReactorReady {
     exclusions.apply();
 
     // 3 Validate final reactor
-    ProjectReactorValidator validator = new ProjectReactorValidator(settings);
     validator.validate(reactor);
   }
 }
index 79668e2c3f00ea2e2946f3591e167bf72d2b1b0b..539da5974e7f8924718b483f66289a49eacfa26a 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.batch.scan;
 
+import org.sonar.core.resource.ResourceDao;
 import com.google.common.base.Joiner;
 import org.apache.commons.lang.math.NumberUtils;
 import org.codehaus.plexus.util.StringUtils;
@@ -39,12 +40,21 @@ public class ProjectReactorValidator {
 
   private static final String VALID_MODULE_KEY_REGEXP = "[0-9a-zA-Z\\-_\\.:]+";
   private final Settings settings;
+  private final ResourceDao resourceDao;
 
-  public ProjectReactorValidator(Settings settings) {
+  public ProjectReactorValidator(Settings settings, ResourceDao resourceDao) {
     this.settings = settings;
+    this.resourceDao = resourceDao;
   }
 
   public void validate(ProjectReactor reactor) {
+    if (settings.getBoolean(CoreProperties.CORE_PREVENT_AUTOMATIC_PROJECT_CREATION)) {
+      String projectKey = reactor.getRoot().getKey();
+      if (resourceDao.findByKey(projectKey) == null) {
+        throw new SonarException("Unable to scan non-existing project " + projectKey);
+      }
+    }
+
     List<String> validationMessages = new ArrayList<String>();
     for (ProjectDefinition moduleDef : reactor.getProjects()) {
       validateModule(moduleDef, validationMessages);
index b3aa45d7c08c7aca16af40ea01d3776d56a5ce85..4438112c1d87e7a778dc21d6e7a0829b5fd58ef0 100644 (file)
@@ -51,6 +51,7 @@ public class ScanTask implements Task {
         new Phases().enable(Phases.Phase.values()),
         DefaultProjectTree.class,
         ProjectExclusions.class,
+        ProjectReactorValidator.class,
         ProjectReactorReady.class,
         DefaultProfileLoader.class,
         DefaultSensorMatcher.class);
index 7d15154e0b4731081fde907f6a56a5a8a13f7856..cc5a7aa9133b6d0a29a441bc0b7049c9fc7c5110 100644 (file)
@@ -22,7 +22,6 @@ package org.sonar.batch.scan;
 import org.junit.Test;
 import org.sonar.api.batch.bootstrap.ProjectBuilder;
 import org.sonar.api.batch.bootstrap.ProjectReactor;
-import org.sonar.api.config.Settings;
 
 import static org.mockito.Mockito.mock;
 
@@ -30,14 +29,14 @@ public class ProjectReactorReadyTest {
   @Test
   public void should_do_nothing() {
     // it's only a barrier
-    ProjectReactorReady barrier = new ProjectReactorReady(mock(ProjectExclusions.class), mock(ProjectReactor.class), new Settings(),
-        new ProjectBuilder[] {mock(ProjectBuilder.class)});
+    ProjectReactorReady barrier = new ProjectReactorReady(mock(ProjectExclusions.class), mock(ProjectReactor.class),
+        new ProjectBuilder[] {mock(ProjectBuilder.class)}, mock(ProjectReactorValidator.class));
     barrier.start();
   }
 
   @Test
   public void project_builders_should_be_optional() {
-    ProjectReactorReady barrier = new ProjectReactorReady(mock(ProjectExclusions.class), mock(ProjectReactor.class), new Settings());
+    ProjectReactorReady barrier = new ProjectReactorReady(mock(ProjectExclusions.class), mock(ProjectReactor.class), mock(ProjectReactorValidator.class));
     barrier.start();
   }
 }
index efd2b6a7540d930b4da77a4e21f2c9988939eea7..34887e221886f41b83fa30810394b7abd45a346c 100644 (file)
@@ -26,8 +26,13 @@ import org.junit.rules.ExpectedException;
 import org.sonar.api.CoreProperties;
 import org.sonar.api.batch.bootstrap.ProjectDefinition;
 import org.sonar.api.batch.bootstrap.ProjectReactor;
+import org.sonar.api.component.Component;
 import org.sonar.api.config.Settings;
 import org.sonar.api.utils.SonarException;
+import org.sonar.core.resource.ResourceDao;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 public class ProjectReactorValidatorTest {
 
@@ -36,11 +41,31 @@ public class ProjectReactorValidatorTest {
 
   private ProjectReactorValidator validator;
   private Settings settings;
+  private ResourceDao resourceDao;
 
   @Before
   public void prepare() {
     settings = new Settings();
-    validator = new ProjectReactorValidator(settings);
+    resourceDao = mock(ResourceDao.class);
+    validator = new ProjectReactorValidator(settings, resourceDao);
+  }
+
+  @Test
+  public void not_fail_if_prosivioning_enforced_and_project_exists() throws Exception {
+    String key = "project-key";
+    settings.setProperty(CoreProperties.CORE_PREVENT_AUTOMATIC_PROJECT_CREATION, true);
+    when(resourceDao.findByKey(key)).thenReturn(mock(Component.class));
+    ProjectReactor reactor = createProjectReactor(key);
+    validator.validate(reactor);
+  }
+
+  @Test(expected = SonarException.class)
+  public void fail_if_prosivioning_enforced_and_project_not_provisioned() throws Exception {
+    String key = "project-key";
+    settings.setProperty(CoreProperties.CORE_PREVENT_AUTOMATIC_PROJECT_CREATION, true);
+    when(resourceDao.findByKey(key)).thenReturn(null);
+    ProjectReactor reactor = createProjectReactor(key);
+    validator.validate(reactor);
   }
 
   @Test
index 8be63457c6405802ceb86807e12a12a38c1a1045..cfae60c9bb5672e41d3109b96a7924075031cd92 100644 (file)
@@ -19,6 +19,8 @@
  */
 package org.sonar.batch.scan;
 
+import org.sonar.core.resource.ResourceDao;
+
 import org.junit.Test;
 import org.sonar.api.CoreProperties;
 import org.sonar.api.batch.bootstrap.ProjectReactor;
@@ -27,7 +29,6 @@ import org.sonar.api.platform.ComponentContainer;
 import org.sonar.batch.ProjectConfigurator;
 import org.sonar.batch.bootstrap.TaskContainer;
 import org.sonar.batch.phases.Phases;
-
 import static org.fest.assertions.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
 
@@ -42,7 +43,7 @@ public class ScanTaskTest {
   public void should_enable_all_phases() {
     ScanTask task = new ScanTask(mock(TaskContainer.class));
     ComponentContainer projectScanContainer = new ComponentContainer();
-    projectScanContainer.add(mock(ProjectConfigurator.class), mock(ProjectReactor.class), mock(Settings.class), mock(ProjectSettingsReady.class));
+    projectScanContainer.add(mock(ProjectConfigurator.class), mock(ProjectReactor.class), mock(Settings.class), mock(ProjectSettingsReady.class), mock(ResourceDao.class));
     task.scan(projectScanContainer);
 
     Phases phases = projectScanContainer.getComponentByType(Phases.class);
index b410c6bc2953963a5e2a3482342cf88fe7f2fb2f..9aa3b74b85bf5d3b8ffa3b1dd9708f58aad456a5 100644 (file)
@@ -465,4 +465,9 @@ public interface CoreProperties {
    * @since 3.7
    */
   String DRY_RUN_READ_TIMEOUT_SEC = "sonar.dryRun.readTimeout";
+
+  /**
+   * @since 4.0
+   */
+  String CORE_PREVENT_AUTOMATIC_PROJECT_CREATION = "sonar.preventAutoProjectCreation";
 }