diff options
author | Fabrice Bellingard <bellingard@gmail.com> | 2012-09-05 09:04:33 +0000 |
---|---|---|
committer | Fabrice Bellingard <bellingard@gmail.com> | 2012-09-05 09:04:33 +0000 |
commit | c7bcceb0933561fbf90ccc39225e24b47822c5d4 (patch) | |
tree | 1205b78293e9955a2bd2272943caaf5372dcb769 | |
parent | b76a02be6822c6757463057b17f051b76a150e45 (diff) | |
download | sonar-scanner-cli-c7bcceb0933561fbf90ccc39225e24b47822c5d4.tar.gz sonar-scanner-cli-c7bcceb0933561fbf90ccc39225e24b47822c5d4.zip |
SONARPLUGINS-2202 Add multi-module support
23 files changed, 697 insertions, 118 deletions
diff --git a/src/main/java/org/sonar/runner/Launcher.java b/src/main/java/org/sonar/runner/Launcher.java index 797ba39..614662d 100644 --- a/src/main/java/org/sonar/runner/Launcher.java +++ b/src/main/java/org/sonar/runner/Launcher.java @@ -23,29 +23,21 @@ package org.sonar.runner; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.joran.JoranConfigurator; import ch.qos.logback.core.joran.spi.JoranException; -import com.google.common.annotations.VisibleForTesting; import org.apache.commons.configuration.CompositeConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.EnvironmentConfiguration; import org.apache.commons.configuration.MapConfiguration; import org.apache.commons.configuration.SystemConfiguration; import org.apache.commons.io.IOUtils; -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.LoggerFactory; import org.sonar.api.batch.bootstrap.ProjectDefinition; import org.sonar.api.batch.bootstrap.ProjectReactor; import org.sonar.api.utils.SonarException; import org.sonar.batch.Batch; import org.sonar.batch.bootstrapper.EnvironmentInformation; +import org.sonar.runner.model.SonarProjectBuilder; -import java.io.File; -import java.io.FileFilter; -import java.io.IOException; import java.io.InputStream; -import java.util.Properties; /** * Contrary to {@link org.sonar.runner.Runner}, this class is executed within the classloader @@ -67,32 +59,12 @@ public class Launcher { * This method invoked from {@link Main}. Do not rename it. */ public void execute() { - ProjectDefinition project = defineProject(); + ProjectDefinition project = SonarProjectBuilder.create(runner.getProjectDir(), runner.getProperties()).generateProjectDefinition(); Configuration initialConfiguration = getInitialConfiguration(project); initLogging(initialConfiguration); executeBatch(project, initialConfiguration); } - @VisibleForTesting - protected ProjectDefinition defineProject() { - File baseDir = runner.getProjectDir(); - Properties properties = runner.getProperties(); - ProjectDefinition definition = ProjectDefinition.create(properties) - .setBaseDir(baseDir) - .setWorkDir(runner.getWorkDir()) - .addSourceDirs(getList(properties, "sources")) - .addTestDirs(getList(properties, "tests")); - for (String dir : getList(properties, "binaries")) { - definition.addBinaryDir(dir); - } - for (String pattern : getList(properties, "libraries")) { - for (File file : getLibraries(baseDir, pattern)) { - definition.addLibrary(file.getAbsolutePath()); - } - } - return definition; - } - private void executeBatch(ProjectDefinition project, Configuration initialConfiguration) { ProjectReactor reactor = new ProjectReactor(project); Batch batch = Batch.create(reactor, initialConfiguration, new EnvironmentInformation("Runner", runner.getRunnerVersion())); @@ -129,45 +101,6 @@ public class Launcher { return showSql ? "DEBUG" : "WARN"; } - /** - * Returns files matching specified pattern. - * Visibility has been relaxed to make code testable. - */ - static File[] getLibraries(File baseDir, String pattern) { - final int i = Math.max(pattern.lastIndexOf('/'), pattern.lastIndexOf('\\')); - final String dirPath, filePattern; - if (i == -1) { - dirPath = "."; - filePattern = pattern; - } else { - dirPath = pattern.substring(0, i); - filePattern = pattern.substring(i + 1); - } - FileFilter fileFilter = new AndFileFilter(FileFileFilter.FILE, new WildcardFileFilter(filePattern)); - File dir = resolvePath(baseDir, dirPath); - File[] files = dir.listFiles(fileFilter); - if (files == null || files.length == 0) { - throw new RunnerException("No files matching pattern \"" + filePattern + "\" in directory \"" + dir + "\""); - } - return files; - } - - private static File resolvePath(File baseDir, String path) { - File file = new File(path); - if (!file.isAbsolute()) { - try { - file = new File(baseDir, path).getCanonicalFile(); - } catch (IOException e) { - throw new RunnerException("Unable to resolve path \"" + path + "\"", e); - } - } - return file; - } - - private String[] getList(Properties properties, String key) { - return StringUtils.split(properties.getProperty(key, ""), ','); - } - private Configuration getInitialConfiguration(ProjectDefinition project) { CompositeConfiguration configuration = new CompositeConfiguration(); configuration.addConfiguration(new SystemConfiguration()); diff --git a/src/main/java/org/sonar/runner/Runner.java b/src/main/java/org/sonar/runner/Runner.java index 60784df..4224689 100644 --- a/src/main/java/org/sonar/runner/Runner.java +++ b/src/main/java/org/sonar/runner/Runner.java @@ -201,6 +201,10 @@ public final class Runner { try { Thread.currentThread().setContextClassLoader(sonarClassLoader); Class<?> launcherClass = sonarClassLoader.findClass("org.sonar.runner.Launcher"); + // TODO: hack to instantiate SonarProjectBuilder in this classloader otherwise it will be found in the parent one, where no deps are + // available + sonarClassLoader.findClass("org.sonar.runner.model.SonarProjectBuilder"); + // END of hack Constructor<?> constructor = launcherClass.getConstructor(Runner.class); Object launcher = constructor.newInstance(this); Method method = launcherClass.getMethod("execute"); diff --git a/src/main/java/org/sonar/runner/model/SonarProjectBuilder.java b/src/main/java/org/sonar/runner/model/SonarProjectBuilder.java new file mode 100644 index 0000000..1fd4e70 --- /dev/null +++ b/src/main/java/org/sonar/runner/model/SonarProjectBuilder.java @@ -0,0 +1,274 @@ +/* + * Sonar Standalone Runner + * Copyright (C) 2011 SonarSource + * dev@sonar.codehaus.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ + +package org.sonar.runner.model; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.Lists; +import org.apache.commons.io.IOUtils; +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.sonar.api.batch.bootstrap.ProjectDefinition; +import org.sonar.runner.RunnerException; + +import java.io.File; +import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +/** + * Class that creates a Sonar project definition based on a set of properties. + */ +public class SonarProjectBuilder { + + 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"; + /** + * @since 1.4 + */ + private static final String PROPERTY_WORK_DIRECTORY = "sonar.working.directory"; + private static final String DEF_VALUE_WORK_DIRECTORY = ".sonar"; + + /** + * 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"}; + + /** + * Array of all mandatory properties required for a child project. + */ + private static final String[] MANDATORY_PROPERTIES_FOR_CHILD = {"sonar.projectKey", "sonar.projectName"}; + + /** + * Properties that must not be passed from the parent project to its children. + */ + private static final List<String> NON_HERITED_PROPERTIES_FOR_CHILD = Lists.newArrayList("sonar.modules", "sonar.projectDescription"); + + private File rootBaseDir; + private Properties properties; + + private SonarProjectBuilder(File baseDir, Properties properties) { + this.rootBaseDir = baseDir; + this.properties = properties; + } + + public static SonarProjectBuilder create(File baseDir, Properties properties) { + SonarProjectBuilder builder = new SonarProjectBuilder(baseDir, properties); + return builder; + } + + public ProjectDefinition generateProjectDefinition() { + checkMandatoryProperties("root project", properties, MANDATORY_PROPERTIES_FOR_ROOT); + ProjectDefinition rootProject = defineProject(rootBaseDir, properties); + defineChildren(rootProject, properties); + 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); + ProjectDefinition childProject = null; + if (moduleProps.containsKey(PROPERTY_MODULE_FILE)) { + childProject = loadChildProjectFromPropertyFile(rootProject, moduleProps, module); + } else { + childProject = loadChildProjectFromProperties(rootProject, moduleProps, module); + } + // the child project may have children as well + defineChildren(childProject, moduleProps); + // and finally add this child project to its parent + rootProject.addSubProject(childProject); + } + } + } + + private ProjectDefinition loadChildProjectFromProperties(ProjectDefinition rootProject, Properties childProps, String moduleId) { + checkMandatoryProperties(moduleId, childProps, MANDATORY_PROPERTIES_FOR_CHILD); + mergeParentProperties(childProps, rootProject.getProperties()); + File baseDir = null; + if (childProps.containsKey(PROPERTY_MODULE_PATH)) { + baseDir = getFileFromProperty(childProps, PROPERTY_MODULE_PATH, rootProject.getBaseDir()); + } else { + baseDir = new File(rootProject.getBaseDir(), moduleId); + } + if (!baseDir.isDirectory()) { + throw new RunnerException("The base directory of the module '" + moduleId + "' does not exist: " + baseDir.getAbsolutePath()); + } + + return defineProject(baseDir, childProps); + } + + private ProjectDefinition loadChildProjectFromPropertyFile(ProjectDefinition rootProject, Properties moduleProps, String moduleId) { + File propertyFile = getFileFromProperty(moduleProps, PROPERTY_MODULE_FILE, rootProject.getBaseDir()); + if (!propertyFile.isFile()) { + throw new RunnerException("The properties file of the module '" + moduleId + "' does not exist: " + propertyFile.getAbsolutePath()); + } + Properties childProps = new Properties(); + FileInputStream fileInputStream = null; + try { + fileInputStream = new FileInputStream(propertyFile); + childProps.load(fileInputStream); + } catch (IOException e) { + throw new RunnerException("Impossible to read the property file: " + propertyFile.getAbsolutePath(), e); + } finally { + IOUtils.closeQuietly(fileInputStream); + } + checkMandatoryProperties(moduleId, childProps, MANDATORY_PROPERTIES_FOR_CHILD); + mergeParentProperties(childProps, rootProject.getProperties()); + + return defineProject(propertyFile.getParentFile(), childProps); + } + + @VisibleForTesting + protected static void checkMandatoryProperties(String moduleId, Properties props, String[] mandatoryProps) { + StringBuilder missing = new StringBuilder(); + for (String mandatoryProperty : mandatoryProps) { + if (!props.containsKey(mandatoryProperty)) { + if (missing.length() > 0) { + missing.append(", "); + } + missing.append(mandatoryProperty); + } + } + if (missing.length() != 0) { + throw new RunnerException("You must define the following mandatory properties for '" + moduleId + "': " + missing); + } + } + + @VisibleForTesting + protected static void mergeParentProperties(Properties childProps, Properties parentProps) { + for (Map.Entry<Object, Object> entry : parentProps.entrySet()) { + String key = (String) entry.getKey(); + if (!childProps.containsKey(key) && !NON_HERITED_PROPERTIES_FOR_CHILD.contains(key)) { + childProps.put(entry.getKey(), entry.getValue()); + } + } + } + + @VisibleForTesting + protected static Properties extractModuleProperties(String module, Properties properties) { + Properties moduleProps = new Properties(); + String propertyPrefix = module + "."; + int prefixLength = propertyPrefix.length(); + for (Map.Entry<Object, Object> entry : properties.entrySet()) { + String key = (String) entry.getKey(); + if (key.startsWith(propertyPrefix)) { + moduleProps.put(key.substring(prefixLength), entry.getValue()); + } + } + 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, ... + definition.addSourceDirs(getListFromProperty(properties, "sources")); + 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 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. + */ + @VisibleForTesting + protected static File[] getLibraries(File baseDir, String pattern) { + final int i = Math.max(pattern.lastIndexOf('/'), pattern.lastIndexOf('\\')); + final String dirPath, filePattern; + if (i == -1) { + dirPath = "."; + filePattern = pattern; + } else { + dirPath = pattern.substring(0, i); + filePattern = pattern.substring(i + 1); + } + FileFilter fileFilter = new AndFileFilter(FileFileFilter.FILE, new WildcardFileFilter(filePattern)); + File dir = resolvePath(baseDir, dirPath); + File[] files = dir.listFiles(fileFilter); + if (files == null || files.length == 0) { + throw new RunnerException("No files matching pattern \"" + filePattern + "\" in directory \"" + dir + "\""); + } + return files; + } + + private static File resolvePath(File baseDir, String path) { + File file = new File(path); + if (!file.isAbsolute()) { + try { + file = new File(baseDir, path).getCanonicalFile(); + } catch (IOException e) { + throw new RunnerException("Unable to resolve path \"" + path + "\"", e); + } + } + return file; + } + + /** + * Returns a list of comma-separated values, even if they are separated by whitespace characters (space char, EOL, ...) + */ + @VisibleForTesting + protected static String[] getListFromProperty(Properties properties, String key) { + return StringUtils.stripAll(StringUtils.split(properties.getProperty(key, ""), ',')); + } + + /** + * Returns the file denoted by the given property, may it be relative to "baseDir" or absolute. + */ + @VisibleForTesting + protected static File getFileFromProperty(Properties properties, String key, File baseDir) { + File propertyFile = new File(properties.getProperty(key).trim()); + if (!propertyFile.isAbsolute()) { + propertyFile = new File(baseDir, propertyFile.getPath()); + } + return propertyFile; + } + +} diff --git a/src/test/java/org/sonar/runner/LauncherTest.java b/src/test/java/org/sonar/runner/LauncherTest.java index 515daa1..0cec5f5 100644 --- a/src/test/java/org/sonar/runner/LauncherTest.java +++ b/src/test/java/org/sonar/runner/LauncherTest.java @@ -22,61 +22,12 @@ package org.sonar.runner; import org.apache.commons.configuration.BaseConfiguration; import org.apache.commons.configuration.Configuration; import org.junit.Test; -import org.sonar.api.batch.bootstrap.ProjectDefinition; - -import java.io.File; -import java.util.Properties; import static org.fest.assertions.Assertions.assertThat; -import static org.junit.Assert.fail; public class LauncherTest { @Test - public void shouldFilterFiles() throws Exception { - File baseDir = new File(getClass().getResource("/org/sonar/runner/LauncherTest/shouldFilterFiles/").toURI()); - assertThat(Launcher.getLibraries(baseDir, "in*.txt").length).isEqualTo(1); - assertThat(Launcher.getLibraries(baseDir, "*.txt").length).isEqualTo(2); - assertThat(Launcher.getLibraries(baseDir.getParentFile(), "shouldFilterFiles/in*.txt").length).isEqualTo(1); - assertThat(Launcher.getLibraries(baseDir.getParentFile(), "shouldFilterFiles/*.txt").length).isEqualTo(2); - } - - @Test - public void shouldWorkWithAbsolutePath() throws Exception { - File baseDir = new File("not-exists"); - String absolutePattern = new File(getClass().getResource("/org/sonar/runner/LauncherTest/shouldFilterFiles/").toURI()).getAbsolutePath() + "/in*.txt"; - assertThat(Launcher.getLibraries(baseDir.getParentFile(), absolutePattern).length).isEqualTo(1); - } - - @Test - public void shouldThrowExceptionWhenNoFilesMatchingPattern() throws Exception { - File baseDir = new File(getClass().getResource("/org/sonar/runner/LauncherTest/shouldFilterFiles/").toURI()); - try { - Launcher.getLibraries(baseDir, "*.jar"); - fail("Exception expected"); - } catch (RunnerException e) { - assertThat(e.getMessage()).contains("No files matching pattern \"*.jar\" in directory"); - } - } - - @Test - public void shouldDefineProject() { - Properties conf = new Properties(); - conf.setProperty("sources", "src/main/java"); - conf.setProperty("tests", "src/test/java"); - conf.setProperty("binaries", "target/classes"); - conf.setProperty("libraries", "./*.xml"); - Runner runner = Runner.create(conf); - - Launcher launcher = new Launcher(runner); - ProjectDefinition projectDefinition = launcher.defineProject(); - assertThat(projectDefinition.getSourceDirs()).contains("src/main/java"); - assertThat(projectDefinition.getTestDirs()).contains("src/test/java"); - assertThat(projectDefinition.getBinaries()).contains("target/classes"); - assertThat(projectDefinition.getLibraries()).contains(new File("assembly.xml").getAbsolutePath(), new File("pom.xml").getAbsolutePath()); - } - - @Test public void testGetSqlLevel() throws Exception { Configuration conf = new BaseConfiguration(); diff --git a/src/test/java/org/sonar/runner/model/SonarProjectBuilderTest.java b/src/test/java/org/sonar/runner/model/SonarProjectBuilderTest.java new file mode 100644 index 0000000..931e535 --- /dev/null +++ b/src/test/java/org/sonar/runner/model/SonarProjectBuilderTest.java @@ -0,0 +1,316 @@ +/* + * Sonar Standalone Runner + * Copyright (C) 2011 SonarSource + * dev@sonar.codehaus.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.runner.model; + +import org.apache.commons.io.IOUtils; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.batch.bootstrap.ProjectDefinition; +import org.sonar.runner.RunnerException; +import org.sonar.test.TestUtils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.List; +import java.util.Properties; + +import static org.fest.assertions.Assertions.assertThat; + +public class SonarProjectBuilderTest { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void shouldDefineSimpleProject() throws IOException { + ProjectDefinition projectDefinition = loadProjectDefinition("simple-project"); + + assertThat(projectDefinition.getKey()).isEqualTo("com.foo.project"); + assertThat(projectDefinition.getName()).isEqualTo("Foo Project"); + assertThat(projectDefinition.getVersion()).isEqualTo("1.0-SNAPSHOT"); + assertThat(projectDefinition.getDescription()).isEqualTo("Description of Foo Project"); + assertThat(projectDefinition.getSourceDirs()).contains("sources"); + assertThat(projectDefinition.getTestDirs()).contains("tests"); + assertThat(projectDefinition.getBinaries()).contains("target/classes"); + assertThat(projectDefinition.getLibraries()).contains(TestUtils.getResource(this.getClass(), "simple-project/libs/lib2.txt").getAbsolutePath(), + TestUtils.getResource(this.getClass(), "simple-project/libs/lib2.txt").getAbsolutePath()); + } + + @Test + public void shouldDefineMultiModuleProject() throws IOException { + ProjectDefinition rootProject = loadProjectDefinition("multi-module"); + + // CHECK ROOT + assertThat(rootProject.getKey()).isEqualTo("com.foo.project"); + assertThat(rootProject.getName()).isEqualTo("Foo Project"); + assertThat(rootProject.getVersion()).isEqualTo("1.0-SNAPSHOT"); + assertThat(rootProject.getDescription()).isEqualTo("Description of Foo Project"); + // root project must not contain some properties - even if they are defined in the root properties file + assertThat(rootProject.getSourceDirs().contains("sources")).isFalse(); + assertThat(rootProject.getTestDirs().contains("tests")).isFalse(); + assertThat(rootProject.getBinaries().contains("target/classes")).isFalse(); + + // CHECK MODULES + List<ProjectDefinition> modules = rootProject.getSubProjects(); + assertThat(modules.size()).isEqualTo(2); + + // Module 1 + ProjectDefinition module1 = modules.get(0); + assertThat(module1.getKey()).isEqualTo("com.foo.project.module1"); + assertThat(module1.getName()).isEqualTo("Foo Module 1"); + assertThat(module1.getVersion()).isEqualTo("1.0-SNAPSHOT"); + // Description should not be inherited from parent if not set + assertThat(module1.getDescription()).isNull(); + assertThat(module1.getSourceDirs()).contains("sources"); + assertThat(module1.getTestDirs()).contains("tests"); + assertThat(module1.getBinaries()).contains("target/classes"); + + // Module 2 + ProjectDefinition module2 = modules.get(1); + assertThat(module2.getKey()).isEqualTo("com.foo.project.module2"); + assertThat(module2.getName()).isEqualTo("Foo Module 2"); + assertThat(module2.getVersion()).isEqualTo("1.0-SNAPSHOT"); + assertThat(module2.getDescription()).isEqualTo("Description of Module 2"); + assertThat(module2.getSourceDirs()).contains("src"); + assertThat(module2.getTestDirs()).contains("tests"); + assertThat(module2.getBinaries()).contains("target/classes"); + } + + @Test + public void shouldDefineMultiModuleProjectWithPath() throws IOException { + ProjectDefinition rootProject = loadProjectDefinition("multi-module-with-path"); + List<ProjectDefinition> modules = rootProject.getSubProjects(); + assertThat(modules.size()).isEqualTo(1); + assertThat(modules.get(0).getKey()).isEqualTo("com.foo.project.module1"); + } + + @Test + public void shouldDefineMultiModuleProjectWithFile() throws IOException { + ProjectDefinition rootProject = loadProjectDefinition("multi-module-with-file"); + List<ProjectDefinition> modules = rootProject.getSubProjects(); + assertThat(modules.size()).isEqualTo(1); + assertThat(modules.get(0).getKey()).isEqualTo("com.foo.project.module1"); + } + + @Test + public void shouldFailIfUnexistingModuleBaseDir() throws IOException { + thrown.expect(RunnerException.class); + thrown.expectMessage("The base directory of the module 'module1' does not exist: " + + TestUtils.getResource(this.getClass(), "multi-module-with-unexisting-basedir").getAbsolutePath() + File.separator + "module1"); + + loadProjectDefinition("multi-module-with-unexisting-basedir"); + } + + @Test + public void shouldFailIfUnexistingModuleFile() throws IOException { + thrown.expect(RunnerException.class); + thrown.expectMessage("The properties file of the module 'module1' does not exist: " + + TestUtils.getResource(this.getClass(), "multi-module-with-unexisting-file").getAbsolutePath() + File.separator + "any-folder" + + File.separator + "any-file.properties"); + + loadProjectDefinition("multi-module-with-unexisting-file"); + } + + @Test + public void shouldExtractModuleProperties() { + Properties props = new Properties(); + props.setProperty("sources", "src/main/java"); + props.setProperty("tests", "src/test/java"); + props.setProperty("foo.sources", "src/main/java"); + props.setProperty("foobar.tests", "src/test/java"); + props.setProperty("foobar.binaries", "target/classes"); + + Properties moduleProps = SonarProjectBuilder.extractModuleProperties("bar", props); + assertThat(moduleProps.size()).isEqualTo(0); + + moduleProps = SonarProjectBuilder.extractModuleProperties("foo", props); + assertThat(moduleProps.size()).isEqualTo(1); + assertThat(moduleProps.get("sources")).isEqualTo("src/main/java"); + + moduleProps = SonarProjectBuilder.extractModuleProperties("foobar", props); + assertThat(moduleProps.size()).isEqualTo(2); + assertThat(moduleProps.get("tests")).isEqualTo("src/test/java"); + assertThat(moduleProps.get("binaries")).isEqualTo("target/classes"); + } + + @Test + public void shouldFailIfMandatoryPropertiesAreNotPresent() { + Properties props = new Properties(); + props.setProperty("sources", "src/main/java"); + props.setProperty("tests", "src/test/java"); + + thrown.expect(RunnerException.class); + thrown.expectMessage("You must define the following mandatory properties for 'foo': sonar.projectKey, sonar.projectName"); + + SonarProjectBuilder.checkMandatoryProperties("foo", props, new String[] {"sonar.projectKey", "sonar.projectName", "sources"}); + } + + @Test + public void shouldNotFailIfMandatoryPropertiesArePresent() { + Properties props = new Properties(); + props.setProperty("sources", "src/main/java"); + props.setProperty("tests", "src/test/java"); + + SonarProjectBuilder.checkMandatoryProperties("foo", props, new String[] {"sources"}); + + // No exception should be thrown + } + + @Test + public void shouldFilterFiles() throws Exception { + File baseDir = TestUtils.getResource(this.getClass(), "shouldFilterFiles"); + assertThat(SonarProjectBuilder.getLibraries(baseDir, "in*.txt").length).isEqualTo(1); + assertThat(SonarProjectBuilder.getLibraries(baseDir, "*.txt").length).isEqualTo(2); + assertThat(SonarProjectBuilder.getLibraries(baseDir.getParentFile(), "shouldFilterFiles/in*.txt").length).isEqualTo(1); + assertThat(SonarProjectBuilder.getLibraries(baseDir.getParentFile(), "shouldFilterFiles/*.txt").length).isEqualTo(2); + } + + @Test + public void shouldWorkWithAbsolutePath() throws Exception { + File baseDir = new File("not-exists"); + String absolutePattern = TestUtils.getResource(this.getClass(), "shouldFilterFiles").getAbsolutePath() + "/in*.txt"; + assertThat(SonarProjectBuilder.getLibraries(baseDir.getParentFile(), absolutePattern).length).isEqualTo(1); + } + + @Test + public void shouldThrowExceptionWhenNoFilesMatchingPattern() throws Exception { + File baseDir = TestUtils.getResource(this.getClass(), "shouldFilterFiles"); + + thrown.expect(RunnerException.class); + thrown.expectMessage("No files matching pattern \"*.jar\" in directory"); + + SonarProjectBuilder.getLibraries(baseDir, "*.jar"); + } + + @Test + public void shouldGetList() { + Properties props = new Properties(); + + props.put("prop", " foo , bar , \n\ntoto,tutu"); + assertThat(SonarProjectBuilder.getListFromProperty(props, "prop")).containsOnly("foo", "bar", "toto", "tutu"); + } + + @Test + public void shouldGetListFromFile() throws IOException { + String filePath = "shouldGetList/foo.properties"; + Properties props = loadPropsFromFile(filePath); + + assertThat(SonarProjectBuilder.getListFromProperty(props, "prop")).containsOnly("foo", "bar", "toto", "tutu"); + } + + @Test + public void shouldGetRelativeFile() { + Properties props = new Properties(); + props.put("path", "shouldGetFile/foo.properties"); + + assertThat(SonarProjectBuilder.getFileFromProperty(props, "path", TestUtils.getResource(this.getClass(), "/"))) + .isEqualTo(TestUtils.getResource("org/sonar/runner/model/SonarProjectBuilderTest/shouldGetFile/foo.properties")); + } + + @Test + public void shouldGetAbsoluteFile() { + File file = TestUtils.getResource("org/sonar/runner/model/SonarProjectBuilderTest/shouldGetFile/foo.properties"); + + Properties props = new Properties(); + props.put("path", file.getAbsolutePath()); + + assertThat(SonarProjectBuilder.getFileFromProperty(props, "path", TestUtils.getResource(this.getClass(), "/"))) + .isEqualTo(file); + } + + @Test + public void shouldMergeParentProperties() { + Properties parentProps = new Properties(); + parentProps.setProperty("toBeMergeProps", "fooParent"); + parentProps.setProperty("existingChildProp", "barParent"); + parentProps.setProperty("sonar.modules", "mod1,mod2"); + parentProps.setProperty("sonar.projectDescription", "Desc fomr Parent"); + + Properties childProps = new Properties(); + childProps.setProperty("existingChildProp", "barChild"); + childProps.setProperty("otherProp", "tutuChild"); + + SonarProjectBuilder.mergeParentProperties(childProps, parentProps); + + assertThat(childProps.size()).isEqualTo(3); + assertThat(childProps.getProperty("toBeMergeProps")).isEqualTo("fooParent"); + assertThat(childProps.getProperty("existingChildProp")).isEqualTo("barChild"); + assertThat(childProps.getProperty("otherProp")).isEqualTo("tutuChild"); + assertThat(childProps.getProperty("sonar.modules")).isNull(); + assertThat(childProps.getProperty("sonar.projectDescription")).isNull(); + } + + private ProjectDefinition loadProjectDefinition(String projectFolder) throws FileNotFoundException, IOException { + Properties props = loadPropsFromFile(projectFolder + "/sonar-project.properties"); + ProjectDefinition projectDefinition = SonarProjectBuilder.create(TestUtils.getResource(this.getClass(), projectFolder), props) + .generateProjectDefinition(); + return projectDefinition; + } + + private Properties loadPropsFromFile(String filePath) throws FileNotFoundException, IOException { + Properties props = new Properties(); + FileInputStream fileInputStream = null; + try { + fileInputStream = new FileInputStream(TestUtils.getResource(this.getClass(), filePath)); + props.load(fileInputStream); + } finally { + IOUtils.closeQuietly(fileInputStream); + } + return props; + } + + @Test + public void shouldInitWorkDir() { + SonarProjectBuilder builder = SonarProjectBuilder.create(null, new Properties()); + File baseDir = new File("target/tmp/baseDir"); + + File workDir = builder.initWorkDir(baseDir); + + assertThat(workDir).isEqualTo(new File(baseDir, ".sonar")); + } + + @Test + public void shouldInitWorkDirWithCustomRelativeFolder() { + Properties properties = new Properties(); + properties.put("sonar.working.directory", ".foo"); + SonarProjectBuilder builder = SonarProjectBuilder.create(null, properties); + File baseDir = new File("target/tmp/baseDir"); + + File workDir = builder.initWorkDir(baseDir); + + assertThat(workDir).isEqualTo(new File(baseDir, ".foo")); + } + + @Test + public void shouldInitWorkDirWithCustomAbsoluteFolder() { + Properties properties = new Properties(); + properties.put("sonar.working.directory", new File("src").getAbsolutePath()); + SonarProjectBuilder builder = SonarProjectBuilder.create(null, properties); + File baseDir = new File("target/tmp/baseDir"); + + File workDir = builder.initWorkDir(baseDir); + + assertThat(workDir).isEqualTo(new File("src").getAbsoluteFile()); + } + +} diff --git a/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/multi-module-with-file/any-folder/any-file.properties b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/multi-module-with-file/any-folder/any-file.properties new file mode 100644 index 0000000..460d349 --- /dev/null +++ b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/multi-module-with-file/any-folder/any-file.properties @@ -0,0 +1,2 @@ +sonar.projectKey=com.foo.project.module1 +sonar.projectName=Foo Module 1 diff --git a/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/multi-module-with-file/any-folder/sources/Fake.java b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/multi-module-with-file/any-folder/sources/Fake.java new file mode 100644 index 0000000..5967658 --- /dev/null +++ b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/multi-module-with-file/any-folder/sources/Fake.java @@ -0,0 +1 @@ +Fake
\ No newline at end of file diff --git a/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/multi-module-with-file/sonar-project.properties b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/multi-module-with-file/sonar-project.properties new file mode 100644 index 0000000..4c655a7 --- /dev/null +++ b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/multi-module-with-file/sonar-project.properties @@ -0,0 +1,14 @@ +sonar.projectKey=com.foo.project +sonar.projectName=Foo Project +sonar.projectVersion=1.0-SNAPSHOT +sonar.projectDescription=Description of Foo Project + +sources=sources +tests=tests +binaries=target/classes + +sonar.modules=module1 + +module1.file=any-folder/any-file.properties +module1.sonar.projectKey=com.foo.project.module1 +module1.sonar.projectName=Foo Module 1 diff --git a/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/multi-module-with-path/modules/module1/sources/Fake.java b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/multi-module-with-path/modules/module1/sources/Fake.java new file mode 100644 index 0000000..5967658 --- /dev/null +++ b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/multi-module-with-path/modules/module1/sources/Fake.java @@ -0,0 +1 @@ +Fake
\ No newline at end of file diff --git a/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/multi-module-with-path/sonar-project.properties b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/multi-module-with-path/sonar-project.properties new file mode 100644 index 0000000..202de2e --- /dev/null +++ b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/multi-module-with-path/sonar-project.properties @@ -0,0 +1,14 @@ +sonar.projectKey=com.foo.project +sonar.projectName=Foo Project +sonar.projectVersion=1.0-SNAPSHOT +sonar.projectDescription=Description of Foo Project + +sources=sources +tests=tests +binaries=target/classes + +sonar.modules=module1 + +module1.path=modules/module1 +module1.sonar.projectKey=com.foo.project.module1 +module1.sonar.projectName=Foo Module 1 diff --git a/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/multi-module-with-unexisting-basedir/sonar-project.properties b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/multi-module-with-unexisting-basedir/sonar-project.properties new file mode 100644 index 0000000..7249f0a --- /dev/null +++ b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/multi-module-with-unexisting-basedir/sonar-project.properties @@ -0,0 +1,13 @@ +sonar.projectKey=com.foo.project +sonar.projectName=Foo Project +sonar.projectVersion=1.0-SNAPSHOT +sonar.projectDescription=Description of Foo Project + +sources=sources +tests=tests +binaries=target/classes + +sonar.modules=module1 + +module1.sonar.projectKey=com.foo.project.module1 +module1.sonar.projectName=Foo Module 1 diff --git a/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/multi-module-with-unexisting-file/sonar-project.properties b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/multi-module-with-unexisting-file/sonar-project.properties new file mode 100644 index 0000000..4c655a7 --- /dev/null +++ b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/multi-module-with-unexisting-file/sonar-project.properties @@ -0,0 +1,14 @@ +sonar.projectKey=com.foo.project +sonar.projectName=Foo Project +sonar.projectVersion=1.0-SNAPSHOT +sonar.projectDescription=Description of Foo Project + +sources=sources +tests=tests +binaries=target/classes + +sonar.modules=module1 + +module1.file=any-folder/any-file.properties +module1.sonar.projectKey=com.foo.project.module1 +module1.sonar.projectName=Foo Module 1 diff --git a/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/multi-module/module1/sources/Fake.java b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/multi-module/module1/sources/Fake.java new file mode 100644 index 0000000..5967658 --- /dev/null +++ b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/multi-module/module1/sources/Fake.java @@ -0,0 +1 @@ +Fake
\ No newline at end of file diff --git a/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/multi-module/module2/src/Fake.java b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/multi-module/module2/src/Fake.java new file mode 100644 index 0000000..5967658 --- /dev/null +++ b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/multi-module/module2/src/Fake.java @@ -0,0 +1 @@ +Fake
\ No newline at end of file diff --git a/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/multi-module/sonar-project.properties b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/multi-module/sonar-project.properties new file mode 100644 index 0000000..96eb03d --- /dev/null +++ b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/multi-module/sonar-project.properties @@ -0,0 +1,20 @@ +sonar.projectKey=com.foo.project +sonar.projectName=Foo Project +sonar.projectVersion=1.0-SNAPSHOT +sonar.projectDescription=Description of Foo Project + +sources=sources +tests=tests +binaries=target/classes + +sonar.modules=module1,\ + module2 + +module1.sonar.projectKey=com.foo.project.module1 +module1.sonar.projectName=Foo Module 1 + +module2.sonar.projectKey=com.foo.project.module2 +module2.sonar.projectName=Foo Module 2 +# redefine some properties +module2.sonar.projectDescription=Description of Module 2 +module2.sources=src diff --git a/src/test/resources/org/sonar/runner/LauncherTest/shouldFilterFiles/exclude.txt b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/shouldFilterFiles/exclude.txt index e69de29..e69de29 100644 --- a/src/test/resources/org/sonar/runner/LauncherTest/shouldFilterFiles/exclude.txt +++ b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/shouldFilterFiles/exclude.txt diff --git a/src/test/resources/org/sonar/runner/LauncherTest/shouldFilterFiles/include.txt b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/shouldFilterFiles/include.txt index e69de29..e69de29 100644 --- a/src/test/resources/org/sonar/runner/LauncherTest/shouldFilterFiles/include.txt +++ b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/shouldFilterFiles/include.txt diff --git a/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/shouldGetFile/foo.properties b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/shouldGetFile/foo.properties new file mode 100644 index 0000000..8fbb104 --- /dev/null +++ b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/shouldGetFile/foo.properties @@ -0,0 +1,4 @@ +prop= foo, bar, \ +toto,\ +\ +tutu,
\ No newline at end of file diff --git a/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/shouldGetList/foo.properties b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/shouldGetList/foo.properties new file mode 100644 index 0000000..8fbb104 --- /dev/null +++ b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/shouldGetList/foo.properties @@ -0,0 +1,4 @@ +prop= foo, bar, \ +toto,\ +\ +tutu,
\ No newline at end of file diff --git a/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/simple-project/libs/lib1.txt b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/simple-project/libs/lib1.txt new file mode 100644 index 0000000..81d4e95 --- /dev/null +++ b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/simple-project/libs/lib1.txt @@ -0,0 +1 @@ +lib1
\ No newline at end of file diff --git a/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/simple-project/libs/lib2.txt b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/simple-project/libs/lib2.txt new file mode 100644 index 0000000..7dacac0 --- /dev/null +++ b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/simple-project/libs/lib2.txt @@ -0,0 +1 @@ +lib2
\ No newline at end of file diff --git a/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/simple-project/sonar-project.properties b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/simple-project/sonar-project.properties new file mode 100644 index 0000000..81bdf16 --- /dev/null +++ b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/simple-project/sonar-project.properties @@ -0,0 +1,9 @@ +sonar.projectKey=com.foo.project +sonar.projectName=Foo Project +sonar.projectVersion=1.0-SNAPSHOT +sonar.projectDescription=Description of Foo Project + +sources=sources +tests=tests +binaries=target/classes +libraries=libs/*.txt diff --git a/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/simple-project/sources/Fake.java b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/simple-project/sources/Fake.java new file mode 100644 index 0000000..5967658 --- /dev/null +++ b/src/test/resources/org/sonar/runner/model/SonarProjectBuilderTest/simple-project/sources/Fake.java @@ -0,0 +1 @@ +Fake
\ No newline at end of file |