diff options
author | Fabrice Bellingard <fabrice.bellingard@sonarsource.com> | 2012-09-06 11:13:20 +0200 |
---|---|---|
committer | Fabrice Bellingard <fabrice.bellingard@sonarsource.com> | 2012-09-06 11:13:20 +0200 |
commit | ad6e774541d5c8d2d9b9df2981c2f2255455898f (patch) | |
tree | 5c9c216248a26f11aa65133d73602b8b78ea726c | |
parent | 2feaf823d3f2d611d6309ff3ee8762b10143a86e (diff) | |
download | sonar-scanner-cli-ad6e774541d5c8d2d9b9df2981c2f2255455898f.tar.gz sonar-scanner-cli-ad6e774541d5c8d2d9b9df2981c2f2255455898f.zip |
SONARPLUGINS-2203 Make sure all Sonar properties start with "sonar."
-rw-r--r-- | src/main/java/org/sonar/runner/model/SonarProjectBuilder.java | 200 | ||||
-rw-r--r-- | src/test/java/org/sonar/runner/model/SonarProjectBuilderTest.java | 29 |
2 files changed, 173 insertions, 56 deletions
diff --git a/src/main/java/org/sonar/runner/model/SonarProjectBuilder.java b/src/main/java/org/sonar/runner/model/SonarProjectBuilder.java index 3bd4b02..f279b84 100644 --- a/src/main/java/org/sonar/runner/model/SonarProjectBuilder.java +++ b/src/main/java/org/sonar/runner/model/SonarProjectBuilder.java @@ -27,6 +27,8 @@ import org.apache.commons.io.filefilter.AndFileFilter; import org.apache.commons.io.filefilter.FileFileFilter; import org.apache.commons.io.filefilter.WildcardFileFilter; import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.sonar.api.batch.bootstrap.ProjectDefinition; import org.sonar.runner.RunnerException; @@ -34,8 +36,10 @@ import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.IOException; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Properties; /** @@ -45,9 +49,37 @@ import java.util.Properties; */ public final class SonarProjectBuilder { + private static final Logger LOG = LoggerFactory.getLogger(SonarProjectBuilder.class); + private static final String PROPERTY_SONAR_MODULES = "sonar.modules"; private static final String PROPERTY_MODULE_FILE = "file"; private static final String PROPERTY_MODULE_PATH = "path"; + + /** + * New properties, to be consistent with Sonar naming conventions + * @since 1.5 + */ + private static final String PROPERTY_SOURCES = "sonar.sources"; + private static final String PROPERTY_TESTS = "sonar.tests"; + private static final String PROPERTY_BINARIES = "sonar.binaries"; + private static final String PROPERTY_LIBRARIES = "sonar.libraries"; + + /** + * Old deprecated properties, replaced by the same ones preceded by "sonar." + */ + private static final String PROPERTY_OLD_SOURCES = "sources"; + private static final String PROPERTY_OLD_TESTS = "tests"; + private static final String PROPERTY_OLD_BINARIES = "binaries"; + private static final String PROPERTY_OLD_LIBRARIES = "libraries"; + private static final Map<String, String> DEPRECATED_PROPS_TO_NEW_PROPS = new HashMap<String, String>() { + { + put(PROPERTY_OLD_SOURCES, PROPERTY_SOURCES); + put(PROPERTY_OLD_TESTS, PROPERTY_TESTS); + put(PROPERTY_OLD_BINARIES, PROPERTY_BINARIES); + put(PROPERTY_OLD_LIBRARIES, PROPERTY_LIBRARIES); + } + }; + /** * @since 1.4 */ @@ -57,7 +89,7 @@ public final class SonarProjectBuilder { /** * Array of all mandatory properties required for a root project. */ - private static final String[] MANDATORY_PROPERTIES_FOR_ROOT = {"sonar.projectKey", "sonar.projectName", "sonar.projectVersion", "sources"}; + private static final String[] MANDATORY_PROPERTIES_FOR_ROOT = {"sonar.projectKey", "sonar.projectName", "sonar.projectVersion", PROPERTY_SOURCES}; /** * Array of all mandatory properties required for a child project. @@ -84,24 +116,47 @@ public final class SonarProjectBuilder { public ProjectDefinition generateProjectDefinition() { checkMandatoryProperties("root project", properties, MANDATORY_PROPERTIES_FOR_ROOT); ProjectDefinition rootProject = defineProject(rootBaseDir, properties); - defineChildren(rootProject, properties); + defineChildren(rootProject); + cleanAndCheckProjectDefinitions(rootProject); return rootProject; } - private void defineChildren(ProjectDefinition rootProject, Properties properties) { - if (properties.containsKey(PROPERTY_SONAR_MODULES)) { - for (String module : getListFromProperty(properties, PROPERTY_SONAR_MODULES)) { - Properties moduleProps = extractModuleProperties(module, properties); + private ProjectDefinition defineProject(File baseDir, Properties properties) { + ProjectDefinition definition = ProjectDefinition.create((Properties) properties.clone()) + .setBaseDir(baseDir) + .setWorkDir(initWorkDir(baseDir)); + return definition; + } + + @VisibleForTesting + protected File initWorkDir(File baseDir) { + String workDir = properties.getProperty(PROPERTY_WORK_DIRECTORY); + if (StringUtils.isBlank(workDir)) { + return new File(baseDir, DEF_VALUE_WORK_DIRECTORY); + } + + File customWorkDir = new File(workDir); + if (customWorkDir.isAbsolute()) { + return customWorkDir; + } + return new File(baseDir, customWorkDir.getPath()); + } + + private void defineChildren(ProjectDefinition parentProject) { + Properties parentProps = parentProject.getProperties(); + if (parentProps.containsKey(PROPERTY_SONAR_MODULES)) { + for (String module : getListFromProperty(parentProps, PROPERTY_SONAR_MODULES)) { + Properties moduleProps = extractModuleProperties(module, parentProps); ProjectDefinition childProject = null; if (moduleProps.containsKey(PROPERTY_MODULE_FILE)) { - childProject = loadChildProjectFromPropertyFile(rootProject, moduleProps, module); + childProject = loadChildProjectFromPropertyFile(parentProject, moduleProps, module); } else { - childProject = loadChildProjectFromProperties(rootProject, moduleProps, module); + childProject = loadChildProjectFromProperties(parentProject, moduleProps, module); } // the child project may have children as well - defineChildren(childProject, moduleProps); + defineChildren(childProject); // and finally add this child project to its parent - rootProject.addSubProject(childProject); + parentProject.addSubProject(childProject); } } } @@ -145,6 +200,7 @@ public final class SonarProjectBuilder { @VisibleForTesting protected static void checkMandatoryProperties(String moduleId, Properties props, String[] mandatoryProps) { + replaceDeprecatedProperties(props); StringBuilder missing = new StringBuilder(); for (String mandatoryProperty : mandatoryProps) { if (!props.containsKey(mandatoryProperty)) { @@ -160,15 +216,99 @@ public final class SonarProjectBuilder { } @VisibleForTesting + protected static void cleanAndCheckProjectDefinitions(ProjectDefinition project) { + if (project.getSubProjects().isEmpty()) { + cleanAndCheckModuleProperties(project); + } else { + cleanAggregatorProjectProperties(project); + + // clean modules properties as well + for (ProjectDefinition module : project.getSubProjects()) { + cleanAndCheckProjectDefinitions(module); + } + } + } + + @VisibleForTesting + protected static void cleanAndCheckModuleProperties(ProjectDefinition project) { + Properties properties = project.getProperties(); + + // We need to check the existence of source directories + String[] sourceDirs = getListFromProperty(properties, PROPERTY_SOURCES); + checkExistenceOfDirectories(project.getKey(), project.getBaseDir(), sourceDirs); + + // And we need to resolve patterns that may have been used in "sonar.libraries" + List<String> libPaths = Lists.newArrayList(); + for (String pattern : getListFromProperty(properties, PROPERTY_LIBRARIES)) { + for (File file : getLibraries(project.getBaseDir(), pattern)) { + libPaths.add(file.getAbsolutePath()); + } + } + properties.remove(PROPERTY_LIBRARIES); + properties.put(PROPERTY_LIBRARIES, StringUtils.join(libPaths, ",")); + } + + @VisibleForTesting + protected static void cleanAggregatorProjectProperties(ProjectDefinition project) { + Properties properties = project.getProperties(); + + // "aggregator" project must not have the following properties: + properties.remove(PROPERTY_SOURCES); + properties.remove(PROPERTY_TESTS); + properties.remove(PROPERTY_BINARIES); + properties.remove(PROPERTY_LIBRARIES); + + // and they don't need properties related to their modules either + Properties clone = (Properties) properties.clone(); + List<String> moduleIds = Lists.newArrayList(getListFromProperty(properties, PROPERTY_SONAR_MODULES)); + for (Entry<Object, Object> entry : clone.entrySet()) { + String key = (String) entry.getKey(); + if (isKeyPrefixedByModuleId(key, moduleIds)) { + properties.remove(key); + } + } + } + + /** + * Replaces the deprecated properties by the new ones, and logs a message to warn the users. + */ + @VisibleForTesting + protected static void replaceDeprecatedProperties(Properties props) { + for (Entry<String, String> entry : DEPRECATED_PROPS_TO_NEW_PROPS.entrySet()) { + String key = entry.getKey(); + if (props.containsKey(key)) { + String newKey = entry.getValue(); + LOG.warn("/!\\ The '{}' property is deprecated and is replaced by '{}'. Don't forget to update your files.", key, newKey); + String value = props.getProperty(key); + props.remove(key); + props.put(newKey, value); + } + } + + } + + @VisibleForTesting protected static void mergeParentProperties(Properties childProps, Properties parentProps) { + List<String> moduleIds = Lists.newArrayList(getListFromProperty(parentProps, PROPERTY_SONAR_MODULES)); for (Map.Entry<Object, Object> entry : parentProps.entrySet()) { String key = (String) entry.getKey(); - if (!childProps.containsKey(key) && !NON_HERITED_PROPERTIES_FOR_CHILD.contains(key)) { + if (!childProps.containsKey(key) + && !NON_HERITED_PROPERTIES_FOR_CHILD.contains(key) + && !isKeyPrefixedByModuleId(key, moduleIds)) { childProps.put(entry.getKey(), entry.getValue()); } } } + private static boolean isKeyPrefixedByModuleId(String key, List<String> moduleIds) { + for (String moduleId : moduleIds) { + if (key.startsWith(moduleId + ".")) { + return true; + } + } + return false; + } + @VisibleForTesting protected static Properties extractModuleProperties(String module, Properties properties) { Properties moduleProps = new Properties(); @@ -183,30 +323,8 @@ public final class SonarProjectBuilder { return moduleProps; } - private ProjectDefinition defineProject(File baseDir, Properties properties) { - ProjectDefinition definition = ProjectDefinition.create((Properties) properties.clone()) - .setBaseDir(baseDir) - .setWorkDir(initWorkDir(baseDir)); - if (!properties.containsKey(PROPERTY_SONAR_MODULES)) { - // this is not a "aggregator" project, so let's specify its sources, tests, ... - String[] sourceDirs = getListFromProperty(properties, "sources"); - checkExistenceOfDirectories(definition.getKey(), baseDir, sourceDirs); - definition.addSourceDirs(sourceDirs); - definition.addTestDirs(getListFromProperty(properties, "tests")); - for (String dir : getListFromProperty(properties, "binaries")) { - definition.addBinaryDir(dir); - } - for (String pattern : getListFromProperty(properties, "libraries")) { - for (File file : getLibraries(baseDir, pattern)) { - definition.addLibrary(file.getAbsolutePath()); - } - } - } - return definition; - } - @VisibleForTesting - protected void checkExistenceOfDirectories(String projectKey, File baseDir, String[] sourceDirs) { + protected static void checkExistenceOfDirectories(String projectKey, File baseDir, String[] sourceDirs) { for (String path : sourceDirs) { File sourceFolder = getFileFromPath(path, baseDir); if (!sourceFolder.isDirectory()) { @@ -217,20 +335,6 @@ public final class SonarProjectBuilder { } - @VisibleForTesting - protected File initWorkDir(File baseDir) { - String workDir = properties.getProperty(PROPERTY_WORK_DIRECTORY); - if (StringUtils.isBlank(workDir)) { - return new File(baseDir, DEF_VALUE_WORK_DIRECTORY); - } - - File customWorkDir = new File(workDir); - if (customWorkDir.isAbsolute()) { - return customWorkDir; - } - return new File(baseDir, customWorkDir.getPath()); - } - /** * Returns files matching specified pattern. */ diff --git a/src/test/java/org/sonar/runner/model/SonarProjectBuilderTest.java b/src/test/java/org/sonar/runner/model/SonarProjectBuilderTest.java index 5495a6b..fe22db6 100644 --- a/src/test/java/org/sonar/runner/model/SonarProjectBuilderTest.java +++ b/src/test/java/org/sonar/runner/model/SonarProjectBuilderTest.java @@ -78,6 +78,9 @@ public class SonarProjectBuilderTest { assertThat(rootProject.getSourceDirs().contains("sources")).isFalse(); assertThat(rootProject.getTestDirs().contains("tests")).isFalse(); assertThat(rootProject.getBinaries().contains("target/classes")).isFalse(); + // and module properties must have been cleaned + assertThat(rootProject.getProperties().getProperty("module1.sonar.projectKey")).isNull(); + assertThat(rootProject.getProperties().getProperty("module2.sonar.projectKey")).isNull(); // CHECK MODULES List<ProjectDefinition> modules = rootProject.getSubProjects(); @@ -93,6 +96,9 @@ public class SonarProjectBuilderTest { assertThat(module1.getSourceDirs()).contains("sources"); assertThat(module1.getTestDirs()).contains("tests"); assertThat(module1.getBinaries()).contains("target/classes"); + // and module properties must have been cleaned + assertThat(rootProject.getProperties().getProperty("module1.sonar.projectKey")).isNull(); + assertThat(rootProject.getProperties().getProperty("module2.sonar.projectKey")).isNull(); // Module 2 ProjectDefinition module2 = modules.get(1); @@ -103,6 +109,9 @@ public class SonarProjectBuilderTest { assertThat(module2.getSourceDirs()).contains("src"); assertThat(module2.getTestDirs()).contains("tests"); assertThat(module2.getBinaries()).contains("target/classes"); + // and module properties must have been cleaned + assertThat(rootProject.getProperties().getProperty("module1.sonar.projectKey")).isNull(); + assertThat(rootProject.getProperties().getProperty("module2.sonar.projectKey")).isNull(); } @Test @@ -165,22 +174,22 @@ public class SonarProjectBuilderTest { @Test public void shouldFailIfMandatoryPropertiesAreNotPresent() { Properties props = new Properties(); - props.setProperty("sources", "src/main/java"); - props.setProperty("tests", "src/test/java"); + props.setProperty("foo1", "bla"); + props.setProperty("foo4", "bla"); thrown.expect(RunnerException.class); - thrown.expectMessage("You must define the following mandatory properties for 'foo': sonar.projectKey, sonar.projectName"); + thrown.expectMessage("You must define the following mandatory properties for 'foo': foo2, foo3"); - SonarProjectBuilder.checkMandatoryProperties("foo", props, new String[] {"sonar.projectKey", "sonar.projectName", "sources"}); + SonarProjectBuilder.checkMandatoryProperties("foo", props, new String[] {"foo1", "foo2", "foo3"}); } @Test public void shouldNotFailIfMandatoryPropertiesArePresent() { Properties props = new Properties(); - props.setProperty("sources", "src/main/java"); - props.setProperty("tests", "src/test/java"); + props.setProperty("foo1", "bla"); + props.setProperty("foo4", "bla"); - SonarProjectBuilder.checkMandatoryProperties("foo", props, new String[] {"sources"}); + SonarProjectBuilder.checkMandatoryProperties("foo", props, new String[] {"foo1"}); // No exception should be thrown } @@ -247,7 +256,9 @@ public class SonarProjectBuilderTest { parentProps.setProperty("toBeMergeProps", "fooParent"); parentProps.setProperty("existingChildProp", "barParent"); parentProps.setProperty("sonar.modules", "mod1,mod2"); - parentProps.setProperty("sonar.projectDescription", "Desc fomr Parent"); + parentProps.setProperty("sonar.projectDescription", "Desc from Parent"); + parentProps.setProperty("mod1.sonar.projectDescription", "Desc for Mod1"); + parentProps.setProperty("mod2.sonar.projectkey", "Key for Mod2"); Properties childProps = new Properties(); childProps.setProperty("existingChildProp", "barChild"); @@ -261,6 +272,8 @@ public class SonarProjectBuilderTest { assertThat(childProps.getProperty("otherProp")).isEqualTo("tutuChild"); assertThat(childProps.getProperty("sonar.modules")).isNull(); assertThat(childProps.getProperty("sonar.projectDescription")).isNull(); + assertThat(childProps.getProperty("mod1.sonar.projectDescription")).isNull(); + assertThat(childProps.getProperty("mod2.sonar.projectkey")).isNull(); } private ProjectDefinition loadProjectDefinition(String projectFolder) throws FileNotFoundException, IOException { |