]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-4876 Allow the user to specify the key to be used for a module
authorJulien HENRY <julien.henry@sonarsource.com>
Tue, 26 Nov 2013 16:55:38 +0000 (17:55 +0100)
committerJulien HENRY <julien.henry@sonarsource.com>
Tue, 26 Nov 2013 16:55:38 +0000 (17:55 +0100)
sonar-batch/src/main/java/org/sonar/batch/scan/DefaultProjectBootstrapper.java
sonar-batch/src/test/java/org/sonar/batch/scan/DefaultProjectBootstrapperTest.java
sonar-batch/src/test/resources/org/sonar/batch/scan/DefaultProjectBootstrapperTest/multi-module-definitions-moduleKey/module1/sources/Fake.java [new file with mode: 0644]
sonar-batch/src/test/resources/org/sonar/batch/scan/DefaultProjectBootstrapperTest/multi-module-definitions-moduleKey/module2/src/Fake.java [new file with mode: 0644]
sonar-batch/src/test/resources/org/sonar/batch/scan/DefaultProjectBootstrapperTest/multi-module-definitions-moduleKey/sonar-project.properties [new file with mode: 0644]
sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java

index 5ca8e682c65b1950a9d92dc86a267c6e29ad1412..4c00baf33ffcf3a364262f67d3b207d43e59c902 100644 (file)
@@ -97,7 +97,7 @@ class DefaultProjectBootstrapper implements ProjectBootstrapper {
   /**
    * Array of all mandatory properties required for a child project before its properties get merged with its parent ones.
    */
-  private static final String[] MANDATORY_PROPERTIES_FOR_CHILD = {CoreProperties.PROJECT_KEY_PROPERTY, CoreProperties.PROJECT_NAME_PROPERTY};
+  private static final String[] MANDATORY_PROPERTIES_FOR_CHILD = {CoreProperties.MODULE_KEY_PROPERTY, CoreProperties.PROJECT_NAME_PROPERTY};
 
   /**
    * Properties that must not be passed from the parent project to its children.
@@ -181,8 +181,6 @@ class DefaultProjectBootstrapper implements ProjectBootstrapper {
   }
 
   private ProjectDefinition loadChildProject(ProjectDefinition parentProject, Properties moduleProps, String moduleId) {
-    setProjectKeyAndNameIfNotDefined(moduleProps, moduleId);
-
     final File baseDir;
     if (moduleProps.containsKey(PROPERTY_PROJECT_BASEDIR)) {
       baseDir = getFileFromPath(moduleProps.getProperty(PROPERTY_PROJECT_BASEDIR), parentProject.getBaseDir());
@@ -202,14 +200,14 @@ class DefaultProjectBootstrapper implements ProjectBootstrapper {
       tryToFindAndLoadPropsFile(baseDir, moduleProps, moduleId);
     }
 
+    setModuleKeyAndNameIfNotDefined(moduleProps, moduleId, parentProject.getKey());
+
     // and finish
     checkMandatoryProperties(moduleProps, MANDATORY_PROPERTIES_FOR_CHILD);
     validateDirectories(moduleProps, baseDir, moduleId);
 
     mergeParentProperties(moduleProps, parentProject.getProperties());
 
-    prefixProjectKeyWithParentKey(moduleProps, parentProject.getKey());
-
     return defineProject(moduleProps, parentProject);
   }
 
@@ -266,13 +264,20 @@ class DefaultProjectBootstrapper implements ProjectBootstrapper {
   }
 
   @VisibleForTesting
-  protected static void setProjectKeyAndNameIfNotDefined(Properties childProps, String moduleId) {
-    if (!childProps.containsKey(CoreProperties.PROJECT_KEY_PROPERTY)) {
-      childProps.put(CoreProperties.PROJECT_KEY_PROPERTY, moduleId);
+  protected static void setModuleKeyAndNameIfNotDefined(Properties childProps, String moduleId, String parentKey) {
+    if (!childProps.containsKey(CoreProperties.MODULE_KEY_PROPERTY)) {
+      if (!childProps.containsKey(CoreProperties.PROJECT_KEY_PROPERTY)) {
+        childProps.put(CoreProperties.MODULE_KEY_PROPERTY, parentKey + ":" + moduleId);
+      } else {
+        String childKey = childProps.getProperty(CoreProperties.PROJECT_KEY_PROPERTY);
+        childProps.put(CoreProperties.MODULE_KEY_PROPERTY, parentKey + ":" + childKey);
+      }
     }
     if (!childProps.containsKey(CoreProperties.PROJECT_NAME_PROPERTY)) {
       childProps.put(CoreProperties.PROJECT_NAME_PROPERTY, moduleId);
     }
+    // For backward compatibility with ProjectDefinition
+    childProps.put(CoreProperties.PROJECT_KEY_PROPERTY, childProps.getProperty(CoreProperties.MODULE_KEY_PROPERTY));
   }
 
   @VisibleForTesting
@@ -284,12 +289,6 @@ class DefaultProjectBootstrapper implements ProjectBootstrapper {
     }
   }
 
-  @VisibleForTesting
-  protected static void prefixProjectKeyWithParentKey(Properties childProps, String parentKey) {
-    String childKey = childProps.getProperty(CoreProperties.PROJECT_KEY_PROPERTY);
-    childProps.put(CoreProperties.PROJECT_KEY_PROPERTY, parentKey + ":" + childKey);
-  }
-
   private static void setProjectBaseDir(File baseDir, Properties childProps, String moduleId) {
     if (!baseDir.isDirectory()) {
       throw new IllegalStateException("The base directory of the module '" + moduleId + "' does not exist: " + baseDir.getAbsolutePath());
@@ -309,9 +308,9 @@ class DefaultProjectBootstrapper implements ProjectBootstrapper {
         missing.append(mandatoryProperty);
       }
     }
-    String projectKey = props.getProperty(CoreProperties.PROJECT_KEY_PROPERTY);
+    String moduleKey = StringUtils.defaultIfBlank(props.getProperty(CoreProperties.MODULE_KEY_PROPERTY), props.getProperty(CoreProperties.PROJECT_KEY_PROPERTY));
     if (missing.length() != 0) {
-      throw new IllegalStateException("You must define the following mandatory properties for '" + (projectKey == null ? "Unknown" : projectKey) + "': " + missing);
+      throw new IllegalStateException("You must define the following mandatory properties for '" + (moduleKey == null ? "Unknown" : moduleKey) + "': " + missing);
     }
   }
 
index f42129fdc22639af97254daa86c4773090a53e19..caedb3c46a18471615e3c372961f1f5b169c72f6 100644 (file)
@@ -207,6 +207,25 @@ public class DefaultProjectBootstrapperTest {
     assertThat(module2.getProperties().getProperty("module2.sonar.projectKey")).isNull();
   }
 
+  // SONAR-4876
+  @Test
+  public void shouldDefineMultiModuleProjectWithModuleKey() throws IOException {
+    ProjectDefinition rootProject = loadProjectDefinition("multi-module-definitions-moduleKey");
+
+    // CHECK ROOT
+    // module properties must have been cleaned
+    assertThat(rootProject.getProperties().getProperty("module1.sonar.moduleKey")).isNull();
+    assertThat(rootProject.getProperties().getProperty("module2.sonar.moduleKey")).isNull();
+
+    // CHECK MODULES
+    List<ProjectDefinition> modules = rootProject.getSubProjects();
+    assertThat(modules.size()).isEqualTo(2);
+
+    // Module 2
+    ProjectDefinition module2 = modules.get(1);
+    assertThat(module2.getKey()).isEqualTo("com.foo.project.module2");
+  }
+
   @Test
   public void shouldDefineMultiModuleProjectWithDefinitionsModule1Inherited() throws IOException {
     ProjectDefinition rootProject = loadProjectDefinition("multi-module-definitions-in-each-module-inherited");
@@ -530,7 +549,7 @@ public class DefaultProjectBootstrapperTest {
 
   @Test
   public void shouldInitRootWorkDir() {
-    DefaultProjectBootstrapper builder = new DefaultProjectBootstrapper(new BootstrapSettings(new BootstrapProperties(Maps.<String, String> newHashMap())));
+    DefaultProjectBootstrapper builder = new DefaultProjectBootstrapper(new BootstrapSettings(new BootstrapProperties(Maps.<String, String>newHashMap())));
     File baseDir = new File("target/tmp/baseDir");
 
     File workDir = builder.initRootProjectWorkDir(baseDir);
@@ -540,7 +559,7 @@ public class DefaultProjectBootstrapperTest {
 
   @Test
   public void shouldInitWorkDirWithCustomRelativeFolder() {
-    Map<String, String> props = Maps.<String, String> newHashMap();
+    Map<String, String> props = Maps.<String, String>newHashMap();
     props.put("sonar.working.directory", ".foo");
     DefaultProjectBootstrapper builder = new DefaultProjectBootstrapper(new BootstrapSettings(new BootstrapProperties(props)));
     File baseDir = new File("target/tmp/baseDir");
@@ -552,7 +571,7 @@ public class DefaultProjectBootstrapperTest {
 
   @Test
   public void shouldInitRootWorkDirWithCustomAbsoluteFolder() {
-    Map<String, String> props = Maps.<String, String> newHashMap();
+    Map<String, String> props = Maps.<String, String>newHashMap();
     props.put("sonar.working.directory", new File("src").getAbsolutePath());
     DefaultProjectBootstrapper builder = new DefaultProjectBootstrapper(new BootstrapSettings(new BootstrapProperties(props)));
     File baseDir = new File("target/tmp/baseDir");
@@ -562,15 +581,6 @@ public class DefaultProjectBootstrapperTest {
     assertThat(workDir).isEqualTo(new File("src").getAbsoluteFile());
   }
 
-  @Test
-  public void shouldReturnPrefixedKey() {
-    Properties props = new Properties();
-    props.put("sonar.projectKey", "my-module-key");
-
-    DefaultProjectBootstrapper.prefixProjectKeyWithParentKey(props, "my-parent-key");
-    assertThat(props.getProperty("sonar.projectKey")).isEqualTo("my-parent-key:my-module-key");
-  }
-
   @Test
   public void shouldFailIf2ModulesWithSameKey() {
     Properties props = new Properties();
@@ -597,18 +607,18 @@ public class DefaultProjectBootstrapperTest {
   }
 
   @Test
-  public void shouldSetProjectKeyIfNotPresent() {
+  public void shouldSetModuleKeyIfNotPresent() {
     Properties props = new Properties();
     props.put("sonar.projectVersion", "1.0");
 
     // should be set
-    DefaultProjectBootstrapper.setProjectKeyAndNameIfNotDefined(props, "foo");
-    assertThat(props.getProperty("sonar.projectKey")).isEqualTo("foo");
+    DefaultProjectBootstrapper.setModuleKeyAndNameIfNotDefined(props, "foo", "parent");
+    assertThat(props.getProperty("sonar.moduleKey")).isEqualTo("parent:foo");
     assertThat(props.getProperty("sonar.projectName")).isEqualTo("foo");
 
     // but not this 2nd time
-    DefaultProjectBootstrapper.setProjectKeyAndNameIfNotDefined(props, "bar");
-    assertThat(props.getProperty("sonar.projectKey")).isEqualTo("foo");
+    DefaultProjectBootstrapper.setModuleKeyAndNameIfNotDefined(props, "bar", "parent");
+    assertThat(props.getProperty("sonar.moduleKey")).isEqualTo("parent:foo");
     assertThat(props.getProperty("sonar.projectName")).isEqualTo("foo");
   }
 
@@ -621,7 +631,7 @@ public class DefaultProjectBootstrapperTest {
   }
 
   private ProjectDefinition loadProjectDefinition(String projectFolder) throws IOException {
-    Map<String, String> props = Maps.<String, String> newHashMap();
+    Map<String, String> props = Maps.<String, String>newHashMap();
     Properties runnerProps = DefaultProjectBootstrapper.toProperties(TestUtils.getResource(this.getClass(), projectFolder + "/sonar-project.properties"));
     for (final String name : runnerProps.stringPropertyNames()) {
       props.put(name, runnerProps.getProperty(name));
diff --git a/sonar-batch/src/test/resources/org/sonar/batch/scan/DefaultProjectBootstrapperTest/multi-module-definitions-moduleKey/module1/sources/Fake.java b/sonar-batch/src/test/resources/org/sonar/batch/scan/DefaultProjectBootstrapperTest/multi-module-definitions-moduleKey/module1/sources/Fake.java
new file mode 100644 (file)
index 0000000..b2e6462
--- /dev/null
@@ -0,0 +1 @@
+Fake
diff --git a/sonar-batch/src/test/resources/org/sonar/batch/scan/DefaultProjectBootstrapperTest/multi-module-definitions-moduleKey/module2/src/Fake.java b/sonar-batch/src/test/resources/org/sonar/batch/scan/DefaultProjectBootstrapperTest/multi-module-definitions-moduleKey/module2/src/Fake.java
new file mode 100644 (file)
index 0000000..b2e6462
--- /dev/null
@@ -0,0 +1 @@
+Fake
diff --git a/sonar-batch/src/test/resources/org/sonar/batch/scan/DefaultProjectBootstrapperTest/multi-module-definitions-moduleKey/sonar-project.properties b/sonar-batch/src/test/resources/org/sonar/batch/scan/DefaultProjectBootstrapperTest/multi-module-definitions-moduleKey/sonar-project.properties
new file mode 100644 (file)
index 0000000..6def807
--- /dev/null
@@ -0,0 +1,19 @@
+sonar.projectKey=com.foo.project
+sonar.projectName=Foo Project
+sonar.projectVersion=1.0-SNAPSHOT
+sonar.projectDescription=Description of Foo Project
+
+sonar.sources=sources
+sonar.tests=tests
+sonar.binaries=target/classes
+
+sonar.modules=module1,\
+              module2
+
+# Mandatory properties for module1 are all inferred from the module ID
+
+module2.sonar.moduleKey=com.foo.project.module2
+module2.sonar.projectName=Foo Module 2
+# redefine some properties
+module2.sonar.projectDescription=Description of Module 2
+module2.sonar.sources=src
index a9e07108eeb59f18ab4315e78a6a9984a4e3f60b..2ca4a37cc2931d206ed50703b889542d19cde85c 100644 (file)
@@ -136,6 +136,11 @@ public interface CoreProperties {
    */
   String PROJECT_KEY_PROPERTY = "sonar.projectKey";
 
+  /**
+   * @since 4.1
+   */
+  String MODULE_KEY_PROPERTY = "sonar.moduleKey";
+
   /**
    * @since 2.6
    */