From: Julien HENRY Date: Thu, 3 Jan 2019 16:36:03 +0000 (+0100) Subject: SONAR-11508 Rework inclusion/exclusion to restore support of module overrides X-Git-Tag: 7.6~48 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=2e7846d8c26cc62798f03f72cd6becaf0ec5217e;p=sonarqube.git SONAR-11508 Rework inclusion/exclusion to restore support of module overrides --- diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/AbstractExclusionFilters.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/AbstractExclusionFilters.java index 89809081735..0a74fad2261 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/AbstractExclusionFilters.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/AbstractExclusionFilters.java @@ -91,38 +91,6 @@ public abstract class AbstractExclusionFilters { } } - public boolean accept(Path absolutePath, Path relativePath, InputFile.Type type) { - PathPattern[] inclusionPatterns; - PathPattern[] exclusionPatterns; - if (InputFile.Type.MAIN == type) { - inclusionPatterns = mainInclusionsPattern; - exclusionPatterns = mainExclusionsPattern; - } else if (InputFile.Type.TEST == type) { - inclusionPatterns = testInclusionsPattern; - exclusionPatterns = testExclusionsPattern; - } else { - throw new IllegalArgumentException("Unknown file type: " + type); - } - - if (inclusionPatterns.length > 0) { - boolean matchInclusion = false; - for (PathPattern pattern : inclusionPatterns) { - matchInclusion |= pattern.match(absolutePath, relativePath); - } - if (!matchInclusion) { - return false; - } - } - if (exclusionPatterns.length > 0) { - for (PathPattern pattern : exclusionPatterns) { - if (pattern.match(absolutePath, relativePath)) { - return false; - } - } - } - return true; - } - private static PathPattern[] prepareMainInclusions(String[] sourceInclusions) { if (sourceInclusions.length > 0) { // User defined params @@ -145,27 +113,43 @@ public abstract class AbstractExclusionFilters { return PathPattern.create(testExclusions); } - @Override - public boolean equals(Object o) { - if (this == o) { + public String[] getInclusionsConfig(InputFile.Type type) { + return type == InputFile.Type.MAIN ? sourceInclusions : testInclusions; + } + + public String[] getExclusionsConfig(InputFile.Type type) { + return type == InputFile.Type.MAIN ? sourceExclusions : testExclusions; + } + + public boolean isIncluded(Path absolutePath, Path relativePath, InputFile.Type type) { + PathPattern[] inclusionPatterns = InputFile.Type.MAIN == type ? mainInclusionsPattern : testInclusionsPattern; + + if (inclusionPatterns.length == 0) { return true; } - if (!(o instanceof AbstractExclusionFilters)) { - return false; + + for (PathPattern pattern : inclusionPatterns) { + if (pattern.match(absolutePath, relativePath)) { + return true; + } } - AbstractExclusionFilters that = (AbstractExclusionFilters) o; - return Arrays.equals(sourceInclusions, that.sourceInclusions) && - Arrays.equals(testInclusions, that.testInclusions) && - Arrays.equals(sourceExclusions, that.sourceExclusions) && - Arrays.equals(testExclusions, that.testExclusions); + + return false; } - @Override - public int hashCode() { - int result = Arrays.hashCode(sourceInclusions); - result = 31 * result + Arrays.hashCode(testInclusions); - result = 31 * result + Arrays.hashCode(sourceExclusions); - result = 31 * result + Arrays.hashCode(testExclusions); - return result; + public boolean isExcluded(Path absolutePath, Path relativePath, InputFile.Type type) { + PathPattern[] exclusionPatterns = InputFile.Type.MAIN == type ? mainExclusionsPattern : testExclusionsPattern; + + if (exclusionPatterns.length == 0) { + return false; + } + + for (PathPattern pattern : exclusionPatterns) { + if (pattern.match(absolutePath, relativePath)) { + return true; + } + } + + return false; } } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java index 60798fe990b..2464a6350c7 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java @@ -24,6 +24,8 @@ import java.nio.file.LinkOption; import java.nio.file.Path; import java.util.Arrays; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BooleanSupplier; +import org.apache.commons.io.FilenameUtils; import org.sonar.api.CoreProperties; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.InputFile.Type; @@ -60,14 +62,15 @@ public class FileIndexer { private final SensorStrategy sensorStrategy; private final LanguageDetection langDetection; + private boolean warnInclusionsAlreadyLogged; private boolean warnExclusionsAlreadyLogged; private boolean warnCoverageExclusionsAlreadyLogged; private boolean warnDuplicationExclusionsAlreadyLogged; public FileIndexer(DefaultInputProject project, ScannerComponentIdGenerator scannerComponentIdGenerator, InputComponentStore componentStore, - ProjectExclusionFilters projectExclusionFilters, ProjectCoverageAndDuplicationExclusions projectCoverageAndDuplicationExclusions, IssueExclusionsLoader issueExclusionsLoader, - MetadataGenerator metadataGenerator, SensorStrategy sensorStrategy, LanguageDetection languageDetection, AnalysisWarnings analysisWarnings, ScanProperties properties, - InputFileFilter[] filters) { + ProjectExclusionFilters projectExclusionFilters, ProjectCoverageAndDuplicationExclusions projectCoverageAndDuplicationExclusions, IssueExclusionsLoader issueExclusionsLoader, + MetadataGenerator metadataGenerator, SensorStrategy sensorStrategy, LanguageDetection languageDetection, AnalysisWarnings analysisWarnings, ScanProperties properties, + InputFileFilter[] filters) { this.project = project; this.scannerComponentIdGenerator = scannerComponentIdGenerator; this.componentStore = componentStore; @@ -83,17 +86,19 @@ public class FileIndexer { } public FileIndexer(DefaultInputProject project, ScannerComponentIdGenerator scannerComponentIdGenerator, InputComponentStore componentStore, - ProjectExclusionFilters projectExclusionFilters, ProjectCoverageAndDuplicationExclusions projectCoverageAndDuplicationExclusions, IssueExclusionsLoader issueExclusionsLoader, - MetadataGenerator metadataGenerator, SensorStrategy sensorStrategy, LanguageDetection languageDetection, AnalysisWarnings analysisWarnings, ScanProperties properties) { - this(project, scannerComponentIdGenerator, componentStore, projectExclusionFilters, projectCoverageAndDuplicationExclusions, issueExclusionsLoader, metadataGenerator, sensorStrategy, + ProjectExclusionFilters projectExclusionFilters, ProjectCoverageAndDuplicationExclusions projectCoverageAndDuplicationExclusions, IssueExclusionsLoader issueExclusionsLoader, + MetadataGenerator metadataGenerator, SensorStrategy sensorStrategy, LanguageDetection languageDetection, AnalysisWarnings analysisWarnings, ScanProperties properties) { + this(project, scannerComponentIdGenerator, componentStore, projectExclusionFilters, projectCoverageAndDuplicationExclusions, issueExclusionsLoader, metadataGenerator, + sensorStrategy, languageDetection, analysisWarnings, properties, new InputFileFilter[0]); } - public void indexFile(DefaultInputModule module, ModuleExclusionFilters moduleExclusionFilters, ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions, Path sourceFile, - InputFile.Type type, ProgressReport progressReport, - AtomicInteger excludedByPatternsCount) + void indexFile(DefaultInputModule module, ModuleExclusionFilters moduleExclusionFilters, ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions, + Path sourceFile, + InputFile.Type type, ProgressReport progressReport, + AtomicInteger excludedByPatternsCount) throws IOException { // get case of real file without resolving link Path realAbsoluteFile = sourceFile.toRealPath(LinkOption.NOFOLLOW_LINKS).toAbsolutePath().normalize(); @@ -103,17 +108,13 @@ public class FileIndexer { } Path projectRelativePath = project.getBaseDir().relativize(realAbsoluteFile); Path moduleRelativePath = module.getBaseDir().relativize(realAbsoluteFile); - if (!projectExclusionFilters.accept(realAbsoluteFile, projectRelativePath, type)) { + boolean included = evaluateInclusionsFilters(moduleExclusionFilters, realAbsoluteFile, projectRelativePath, moduleRelativePath, type); + if (!included) { excludedByPatternsCount.incrementAndGet(); return; } - if (!moduleExclusionFilters.accept(realAbsoluteFile, moduleRelativePath, type)) { - if (projectExclusionFilters.equals(moduleExclusionFilters)) { - warnOnceDeprecatedExclusion( - "Specifying module-relative paths at project level in the files exclusions/inclusions properties is deprecated. " + - "To continue matching files like '" + projectRelativePath + "', " + - "update these properties so that patterns refer to project-relative paths."); - } + boolean excluded = evaluateExclusionsFilters(moduleExclusionFilters, realAbsoluteFile, projectRelativePath, moduleRelativePath, type); + if (excluded) { excludedByPatternsCount.incrementAndGet(); return; } @@ -146,6 +147,42 @@ public class FileIndexer { progressReport.message(count + " " + pluralizeFiles(count) + " indexed... (last one was " + inputFile.getProjectRelativePath() + ")"); } + private boolean evaluateInclusionsFilters(ModuleExclusionFilters moduleExclusionFilters, Path realAbsoluteFile, Path projectRelativePath, Path moduleRelativePath, + InputFile.Type type) { + if (!Arrays.equals(moduleExclusionFilters.getInclusionsConfig(type), projectExclusionFilters.getInclusionsConfig(type))) { + // Module specific configuration + return moduleExclusionFilters.isIncluded(realAbsoluteFile, moduleRelativePath, type); + } + boolean includedByProjectConfiguration = projectExclusionFilters.isIncluded(realAbsoluteFile, projectRelativePath, type); + if (includedByProjectConfiguration) { + return true; + } else if (moduleExclusionFilters.isIncluded(realAbsoluteFile, moduleRelativePath, type)) { + warnOnce( + type == Type.MAIN ? CoreProperties.PROJECT_INCLUSIONS_PROPERTY : CoreProperties.PROJECT_TEST_INCLUSIONS_PROPERTY, + FilenameUtils.normalize(projectRelativePath.toString(), true), () -> warnInclusionsAlreadyLogged, () -> warnInclusionsAlreadyLogged = true); + return true; + } + return false; + } + + private boolean evaluateExclusionsFilters(ModuleExclusionFilters moduleExclusionFilters, Path realAbsoluteFile, Path projectRelativePath, Path moduleRelativePath, + InputFile.Type type) { + if (!Arrays.equals(moduleExclusionFilters.getExclusionsConfig(type), projectExclusionFilters.getExclusionsConfig(type))) { + // Module specific configuration + return moduleExclusionFilters.isExcluded(realAbsoluteFile, moduleRelativePath, type); + } + boolean includedByProjectConfiguration = projectExclusionFilters.isExcluded(realAbsoluteFile, projectRelativePath, type); + if (includedByProjectConfiguration) { + return true; + } else if (moduleExclusionFilters.isExcluded(realAbsoluteFile, moduleRelativePath, type)) { + warnOnce( + type == Type.MAIN ? CoreProperties.PROJECT_EXCLUSIONS_PROPERTY : CoreProperties.PROJECT_TEST_EXCLUSIONS_PROPERTY, + FilenameUtils.normalize(projectRelativePath.toString(), true), () -> warnExclusionsAlreadyLogged, () -> warnExclusionsAlreadyLogged = true); + return true; + } + return false; + } + private void checkIfAlreadyIndexed(DefaultInputFile inputFile) { if (componentStore.inputFile(inputFile.getProjectRelativePath()) != null) { throw MessageException.of("File " + inputFile + " can't be indexed twice. Please check that inclusion/exclusion patterns produce " @@ -154,58 +191,60 @@ public class FileIndexer { } private void evaluateCoverageExclusions(ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions, DefaultInputFile inputFile) { + boolean excludedForCoverage = isExcludedForCoverage(moduleCoverageAndDuplicationExclusions, inputFile); + inputFile.setExcludedForCoverage(excludedForCoverage); + if (excludedForCoverage) { + LOG.debug("File {} excluded for coverage", inputFile); + } + } + + private boolean isExcludedForCoverage(ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions, DefaultInputFile inputFile) { + if (!Arrays.equals(moduleCoverageAndDuplicationExclusions.getCoverageExclusionConfig(), projectCoverageAndDuplicationExclusions.getCoverageExclusionConfig())) { + // Module specific configuration + return moduleCoverageAndDuplicationExclusions.isExcludedForCoverage(inputFile); + } boolean excludedByProjectConfiguration = projectCoverageAndDuplicationExclusions.isExcludedForCoverage(inputFile); if (excludedByProjectConfiguration) { - inputFile.setExcludedForCoverage(true); - LOG.debug("File {} excluded for coverage", inputFile); + return true; } else if (moduleCoverageAndDuplicationExclusions.isExcludedForCoverage(inputFile)) { - inputFile.setExcludedForCoverage(true); - if (Arrays.equals(moduleCoverageAndDuplicationExclusions.getCoverageExclusionConfig(), projectCoverageAndDuplicationExclusions.getCoverageExclusionConfig())) { - warnOnceDeprecatedCoverageExclusion( - "Specifying module-relative paths at project level in the property '" + CoreProperties.PROJECT_COVERAGE_EXCLUSIONS_PROPERTY + "' is deprecated. " + - "To continue matching files like '" + inputFile + "', update this property so that patterns refer to project-relative paths."); - } - LOG.debug("File {} excluded for coverage", inputFile); + warnOnce(CoreProperties.PROJECT_COVERAGE_EXCLUSIONS_PROPERTY, inputFile.getProjectRelativePath(), () -> warnCoverageExclusionsAlreadyLogged, + () -> warnCoverageExclusionsAlreadyLogged = true); + return true; } + return false; } private void evaluateDuplicationExclusions(ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions, DefaultInputFile inputFile) { - boolean excludedByProjectConfiguration = projectCoverageAndDuplicationExclusions.isExcludedForDuplication(inputFile); - if (excludedByProjectConfiguration) { - inputFile.setExcludedForDuplication(true); - LOG.debug("File {} excluded for duplication", inputFile); - } else if (moduleCoverageAndDuplicationExclusions.isExcludedForDuplication(inputFile)) { - inputFile.setExcludedForDuplication(true); - if (Arrays.equals(moduleCoverageAndDuplicationExclusions.getDuplicationExclusionConfig(), projectCoverageAndDuplicationExclusions.getDuplicationExclusionConfig())) { - warnOnceDeprecatedDuplicationExclusion( - "Specifying module-relative paths at project level in the property '" + CoreProperties.CPD_EXCLUSIONS + "' is deprecated. " + - "To continue matching files like '" + inputFile + "', update this property so that patterns refer to project-relative paths."); - } + boolean excludedForDuplications = isExcludedForDuplications(moduleCoverageAndDuplicationExclusions, inputFile); + inputFile.setExcludedForDuplication(excludedForDuplications); + if (excludedForDuplications) { LOG.debug("File {} excluded for duplication", inputFile); } } - private void warnOnceDeprecatedExclusion(String msg) { - if (!warnExclusionsAlreadyLogged) { - LOG.warn(msg); - analysisWarnings.addUnique(msg); - warnExclusionsAlreadyLogged = true; + private boolean isExcludedForDuplications(ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions, DefaultInputFile inputFile) { + if (!Arrays.equals(moduleCoverageAndDuplicationExclusions.getDuplicationExclusionConfig(), projectCoverageAndDuplicationExclusions.getDuplicationExclusionConfig())) { + // Module specific configuration + return moduleCoverageAndDuplicationExclusions.isExcludedForDuplication(inputFile); } - } - - private void warnOnceDeprecatedCoverageExclusion(String msg) { - if (!warnCoverageExclusionsAlreadyLogged) { - LOG.warn(msg); - analysisWarnings.addUnique(msg); - warnCoverageExclusionsAlreadyLogged = true; + boolean excludedByProjectConfiguration = projectCoverageAndDuplicationExclusions.isExcludedForDuplication(inputFile); + if (excludedByProjectConfiguration) { + return true; + } else if (moduleCoverageAndDuplicationExclusions.isExcludedForDuplication(inputFile)) { + warnOnce(CoreProperties.CPD_EXCLUSIONS, inputFile.getProjectRelativePath(), () -> warnDuplicationExclusionsAlreadyLogged, + () -> warnDuplicationExclusionsAlreadyLogged = true); + return true; } + return false; } - private void warnOnceDeprecatedDuplicationExclusion(String msg) { - if (!warnDuplicationExclusionsAlreadyLogged) { + private void warnOnce(String propKey, String filePath, BooleanSupplier alreadyLoggedGetter, Runnable markAsLogged) { + if (!alreadyLoggedGetter.getAsBoolean()) { + String msg = "Specifying module-relative paths at project level in the property '" + propKey + "' is deprecated. " + + "To continue matching files like '" + filePath + "', update this property so that patterns refer to project-relative paths."; LOG.warn(msg); analysisWarnings.addUnique(msg); - warnDuplicationExclusionsAlreadyLogged = true; + markAsLogged.run(); } } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ProjectFileIndexer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ProjectFileIndexer.java index a0372a6d633..83d1382ec3e 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ProjectFileIndexer.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ProjectFileIndexer.java @@ -84,8 +84,8 @@ public class ProjectFileIndexer { int totalIndexed = componentStore.inputFiles().size(); progressReport.stop(totalIndexed + " " + pluralizeFiles(totalIndexed) + " indexed"); - if (projectExclusionFilters.hasPattern()) { - int excludedFileCount = excludedByPatternsCount.get(); + int excludedFileCount = excludedByPatternsCount.get(); + if (projectExclusionFilters.hasPattern() || excludedFileCount > 0) { LOG.info("{} {} ignored because of inclusion/exclusion patterns", excludedFileCount, pluralizeFiles(excludedFileCount)); } } @@ -139,8 +139,8 @@ public class ProjectFileIndexer { return count == 1 ? "file" : "files"; } - private void indexFiles(DefaultInputModule module, ModuleExclusionFilters moduleExclusionFilters, ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions, List sources, - Type type, AtomicInteger excludedByPatternsCount) { + private void indexFiles(DefaultInputModule module, ModuleExclusionFilters moduleExclusionFilters, ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions, + List sources, Type type, AtomicInteger excludedByPatternsCount) { try { for (Path dirOrFile : sources) { if (dirOrFile.toFile().isDirectory()) { @@ -154,8 +154,8 @@ public class ProjectFileIndexer { } } - private void indexDirectory(DefaultInputModule module, ModuleExclusionFilters moduleExclusionFilters, ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions, Path dirToIndex, - Type type, AtomicInteger excludedByPatternsCount) + private void indexDirectory(DefaultInputModule module, ModuleExclusionFilters moduleExclusionFilters, + ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions, Path dirToIndex, Type type, AtomicInteger excludedByPatternsCount) throws IOException { Files.walkFileTree(dirToIndex.normalize(), Collections.singleton(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE, new IndexFileVisitor(module, moduleExclusionFilters, moduleCoverageAndDuplicationExclusions, type, excludedByPatternsCount)); @@ -168,8 +168,9 @@ public class ProjectFileIndexer { private final Type type; private final AtomicInteger excludedByPatternsCount; - IndexFileVisitor(DefaultInputModule module, ModuleExclusionFilters moduleExclusionFilters, ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions, Type type, - AtomicInteger excludedByPatternsCount) { + IndexFileVisitor(DefaultInputModule module, ModuleExclusionFilters moduleExclusionFilters, ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions, + Type type, + AtomicInteger excludedByPatternsCount) { this.module = module; this.moduleExclusionFilters = moduleExclusionFilters; this.moduleCoverageAndDuplicationExclusions = moduleCoverageAndDuplicationExclusions; diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/coverage/CoverageMediumTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/coverage/CoverageMediumTest.java index 6b622327bcc..0b6744565de 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/coverage/CoverageMediumTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/coverage/CoverageMediumTest.java @@ -196,6 +196,45 @@ public class CoverageMediumTest { "To continue matching files like 'moduleA/src/sampleA.xoo', update this property so that patterns refer to project-relative paths."); } + @Test + public void module_level_exclusions_override_parent_for_multi_module_project() throws IOException { + + File baseDir = temp.getRoot(); + File baseDirModuleA = new File(baseDir, "moduleA"); + File baseDirModuleB = new File(baseDir, "moduleB"); + File srcDirA = new File(baseDirModuleA, "src"); + srcDirA.mkdirs(); + File srcDirB = new File(baseDirModuleB, "src"); + srcDirB.mkdirs(); + + File xooFileA = new File(srcDirA, "sampleA.xoo"); + File xooUtCoverageFileA = new File(srcDirA, "sampleA.xoo.coverage"); + FileUtils.write(xooFileA, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8); + FileUtils.write(xooUtCoverageFileA, "2:2:2:1\n3:1", StandardCharsets.UTF_8); + + File xooFileB = new File(srcDirB, "sampleB.xoo"); + File xooUtCoverageFileB = new File(srcDirB, "sampleB.xoo.coverage"); + FileUtils.write(xooFileB, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8); + FileUtils.write(xooUtCoverageFileB, "2:2:2:1\n3:1", StandardCharsets.UTF_8); + + AnalysisResult result = tester.newAnalysis() + .properties(ImmutableMap.builder() + .put("sonar.projectBaseDir", baseDir.getAbsolutePath()) + .put("sonar.projectKey", "com.foo.project") + .put("sonar.sources", "src") + .put("sonar.modules", "moduleA,moduleB") + .put("sonar.coverage.exclusions", "**/*.xoo") + .put("moduleA.sonar.coverage.exclusions", "**/*.nothing") + .build()) + .execute(); + + InputFile fileA = result.inputFile("moduleA/src/sampleA.xoo"); + assertThat(result.coverageFor(fileA, 2)).isNotNull(); + + InputFile fileB = result.inputFile("moduleB/src/sampleB.xoo"); + assertThat(result.coverageFor(fileB, 2)).isNull(); + } + @Test public void warn_user_for_outdated_server_side_exclusions_for_multi_module_project() throws IOException { diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/cpd/CpdMediumTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/cpd/CpdMediumTest.java index d8900cfa569..eaea6f109ea 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/cpd/CpdMediumTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/cpd/CpdMediumTest.java @@ -353,6 +353,52 @@ public class CpdMediumTest { "To continue matching files like 'moduleA/src/sampleA.xoo', update this property so that patterns refer to project-relative paths."); } + @Test + public void module_level_exclusions_override_parent_for_multi_module_project() throws IOException { + + String duplicatedStuff = "Sample xoo\ncontent\n" + + "foo\nbar\ntoto\ntiti\n" + + "foo\nbar\ntoto\ntiti\n" + + "bar\ntoto\ntiti\n" + + "foo\nbar\ntoto\ntiti"; + + File baseDir = temp.getRoot(); + File baseDirModuleA = new File(baseDir, "moduleA"); + File baseDirModuleB = new File(baseDir, "moduleB"); + File srcDirA = new File(baseDirModuleA, "src"); + srcDirA.mkdirs(); + File srcDirB = new File(baseDirModuleB, "src"); + srcDirB.mkdirs(); + + File xooFileA = new File(srcDirA, "sampleA.xoo"); + FileUtils.write(xooFileA, duplicatedStuff, StandardCharsets.UTF_8); + + File xooFileB = new File(srcDirB, "sampleB.xoo"); + FileUtils.write(xooFileB, duplicatedStuff, StandardCharsets.UTF_8); + + AnalysisResult result = tester.newAnalysis() + .properties(ImmutableMap.builder() + .put("sonar.projectBaseDir", baseDir.getAbsolutePath()) + .put("sonar.projectKey", "com.foo.project") + .put("sonar.sources", "src") + .put("sonar.modules", "moduleA,moduleB") + .put("sonar.cpd.xoo.minimumTokens", "10") + .put("sonar.cpd.exclusions", "**/*") + .put("moduleA.sonar.cpd.exclusions", "**/*.nothing") + .put("moduleB.sonar.cpd.exclusions", "**/*.nothing") + .build()) + .execute(); + + InputFile inputFile1 = result.inputFile("moduleA/src/sampleA.xoo"); + InputFile inputFile2 = result.inputFile("moduleB/src/sampleB.xoo"); + + List duplicationGroupsFile1 = result.duplicationsFor(inputFile1); + assertThat(duplicationGroupsFile1).isNotEmpty(); + + List duplicationGroupsFile2 = result.duplicationsFor(inputFile2); + assertThat(duplicationGroupsFile2).isNotEmpty(); + } + @Test public void enableCrossProjectDuplication() throws IOException { File srcDir = new File(baseDir, "src"); diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/FileSystemMediumTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/FileSystemMediumTest.java index 293ef226b5f..1eaec75bde6 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/FileSystemMediumTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/FileSystemMediumTest.java @@ -508,6 +508,99 @@ public class FileSystemMediumTest { assertThat(result.inputFiles()).hasSize(2); } + @Test + public void test_inclusions_on_multi_modules() throws IOException { + File baseDir = temp.getRoot(); + File baseDirModuleA = new File(baseDir, "moduleA"); + File baseDirModuleB = new File(baseDir, "moduleB"); + File srcDirA = new File(baseDirModuleA, "tests"); + srcDirA.mkdirs(); + File srcDirB = new File(baseDirModuleB, "tests"); + srcDirB.mkdirs(); + + File xooFileA = new File(srcDirA, "sampleTestA.xoo"); + FileUtils.write(xooFileA, "Sample xoo\ncontent", StandardCharsets.UTF_8); + + File xooFileB = new File(srcDirB, "sampleTestB.xoo"); + FileUtils.write(xooFileB, "Sample xoo\ncontent", StandardCharsets.UTF_8); + + final ImmutableMap.Builder builder = ImmutableMap.builder() + .put("sonar.projectBaseDir", baseDir.getAbsolutePath()) + .put("sonar.projectKey", "com.foo.project") + .put("sonar.sources", "") + .put("sonar.tests", "tests") + .put("sonar.modules", "moduleA,moduleB"); + + + AnalysisResult result = tester.newAnalysis() + .properties(builder.build()) + .execute(); + + assertThat(result.inputFiles()).hasSize(2); + + InputFile fileA = result.inputFile("moduleA/tests/sampleTestA.xoo"); + assertThat(fileA).isNotNull(); + + InputFile fileB = result.inputFile("moduleB/tests/sampleTestB.xoo"); + assertThat(fileB).isNotNull(); + + result = tester.newAnalysis() + .properties(builder + .put("sonar.test.inclusions", "moduleA/tests/**") + .build()) + .execute(); + + assertThat(result.inputFiles()).hasSize(1); + + fileA = result.inputFile("moduleA/tests/sampleTestA.xoo"); + assertThat(fileA).isNotNull(); + + fileB = result.inputFile("moduleB/tests/sampleTestB.xoo"); + assertThat(fileB).isNull(); + } + + @Test + public void test_module_level_inclusions_override_parent_on_multi_modules() throws IOException { + File baseDir = temp.getRoot(); + File baseDirModuleA = new File(baseDir, "moduleA"); + File baseDirModuleB = new File(baseDir, "moduleB"); + File srcDirA = new File(baseDirModuleA, "src"); + srcDirA.mkdirs(); + File srcDirB = new File(baseDirModuleB, "src"); + srcDirB.mkdirs(); + + File xooFileA = new File(srcDirA, "sampleA.xoo"); + FileUtils.write(xooFileA, "Sample xoo\ncontent", StandardCharsets.UTF_8); + + File xooFileB = new File(srcDirB, "sampleB.xoo"); + FileUtils.write(xooFileB, "Sample xoo\ncontent", StandardCharsets.UTF_8); + + final ImmutableMap.Builder builder = ImmutableMap.builder() + .put("sonar.projectBaseDir", baseDir.getAbsolutePath()) + .put("sonar.projectKey", "com.foo.project") + .put("sonar.sources", "src") + .put("sonar.modules", "moduleA,moduleB") + .put("sonar.inclusions", "**/*.php"); + + + AnalysisResult result = tester.newAnalysis() + .properties(builder.build()) + .execute(); + + assertThat(result.inputFiles()).isEmpty(); + + result = tester.newAnalysis() + .properties(builder + .put("moduleA.sonar.inclusions", "**/*.xoo") + .build()) + .execute(); + + assertThat(result.inputFiles()).hasSize(1); + + InputFile fileA = result.inputFile("moduleA/src/sampleA.xoo"); + assertThat(fileA).isNotNull(); + } + @Test public void warn_user_for_outdated_scanner_side_inherited_exclusions_for_multi_module_project() throws IOException { File baseDir = temp.getRoot(); @@ -526,7 +619,6 @@ public class FileSystemMediumTest { AnalysisResult result = tester.newAnalysis() .properties(ImmutableMap.builder() - .put("sonar.task", "scan") .put("sonar.projectBaseDir", baseDir.getAbsolutePath()) .put("sonar.projectKey", "com.foo.project") .put("sonar.sources", "src") @@ -542,8 +634,8 @@ public class FileSystemMediumTest { assertThat(fileB).isNull(); assertThat(logTester.logs(LoggerLevel.WARN)) - .contains("Specifying module-relative paths at project level in the files exclusions/inclusions properties is deprecated. " + - "To continue matching files like 'moduleA/src/sample.xoo', update these properties so that patterns refer to project-relative paths."); + .contains("Specifying module-relative paths at project level in the property 'sonar.exclusions' is deprecated. " + + "To continue matching files like 'moduleA/src/sample.xoo', update this property so that patterns refer to project-relative paths."); } @Test @@ -566,7 +658,6 @@ public class FileSystemMediumTest { AnalysisResult result = tester.newAnalysis() .properties(ImmutableMap.builder() - .put("sonar.task", "scan") .put("sonar.projectBaseDir", baseDir.getAbsolutePath()) .put("sonar.projectKey", "com.foo.project") .put("sonar.sources", "src") @@ -581,8 +672,8 @@ public class FileSystemMediumTest { assertThat(fileB).isNull(); assertThat(logTester.logs(LoggerLevel.WARN)) - .contains("Specifying module-relative paths at project level in the files exclusions/inclusions properties is deprecated. " + - "To continue matching files like 'moduleA/src/sample.xoo', update these properties so that patterns refer to project-relative paths."); + .contains("Specifying module-relative paths at project level in the property 'sonar.exclusions' is deprecated. " + + "To continue matching files like 'moduleA/src/sample.xoo', update this property so that patterns refer to project-relative paths."); } @Test diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ProjectExclusionFiltersTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ProjectExclusionFiltersTest.java index a4f0a30761d..7e6540f69f1 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ProjectExclusionFiltersTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ProjectExclusionFiltersTest.java @@ -53,8 +53,10 @@ public class ProjectExclusionFiltersTest { ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig()); IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDao.java", null); - assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue(); - assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.TEST)).isTrue(); + assertThat(filter.isExcluded(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse(); + assertThat(filter.isExcluded(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.TEST)).isFalse(); + assertThat(filter.isIncluded(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue(); + assertThat(filter.isIncluded(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.TEST)).isTrue(); } @Test @@ -63,10 +65,10 @@ public class ProjectExclusionFiltersTest { ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig()); IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDao.java", null); - assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue(); + assertThat(filter.isIncluded(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue(); indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/Foo.java", null); - assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse(); + assertThat(filter.isIncluded(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse(); } @Test @@ -75,10 +77,10 @@ public class ProjectExclusionFiltersTest { ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig()); IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/Foo.java", null); - assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse(); + assertThat(filter.isIncluded(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse(); indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDto.java", null); - assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue(); + assertThat(filter.isIncluded(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue(); } @Test @@ -89,14 +91,14 @@ public class ProjectExclusionFiltersTest { ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig()); IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDao.java", null); - assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse(); + assertThat(filter.isExcluded(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue(); indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/Foo.java", null); - assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue(); + assertThat(filter.isExcluded(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse(); // source exclusions do not apply to tests indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/test/java/com/mycompany/FooDao.java", null); - assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.TEST)).isTrue(); + assertThat(filter.isExcluded(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.TEST)).isFalse(); } @Test @@ -108,10 +110,10 @@ public class ProjectExclusionFiltersTest { ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig()); IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/org/bar/Foo.java", null); - assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue(); + assertThat(filter.isExcluded(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse(); indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/org/bar/Bar.java", null); - assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse(); + assertThat(filter.isExcluded(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue(); } @Test