import org.sonar.api.CoreProperties;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.PathPattern;
+import org.sonar.api.notifications.AnalysisWarnings;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
+import static java.lang.String.format;
+import static org.sonar.api.CoreProperties.PROJECT_TESTS_EXCLUSIONS_PROPERTY;
+import static org.sonar.api.CoreProperties.PROJECT_TESTS_INCLUSIONS_PROPERTY;
+import static org.sonar.api.CoreProperties.PROJECT_TEST_EXCLUSIONS_PROPERTY;
+import static org.sonar.api.CoreProperties.PROJECT_TEST_INCLUSIONS_PROPERTY;
+
public abstract class AbstractExclusionFilters {
private static final Logger LOG = Loggers.get(AbstractExclusionFilters.class);
+ private static final String WARNING_ALIAS_PROPERTY_USAGE = "Use of %s detected. While being taken into account, the only supported property is %s." +
+ " Consider updating your configuration.";
+
+ private static final String WARNING_LEGACY_AND_ALIAS_PROPERTIES_USAGE =
+ "Use of %s and %s at the same time. %s is taken into account. Consider updating your configuration";
+
+ private final AnalysisWarnings analysisWarnings;
private final String[] sourceInclusions;
private final String[] testInclusions;
private final String[] sourceExclusions;
private PathPattern[] testInclusionsPattern;
private PathPattern[] testExclusionsPattern;
- protected AbstractExclusionFilters(Function<String, String[]> configProvider) {
+ protected AbstractExclusionFilters(AnalysisWarnings analysisWarnings, Function<String, String[]> configProvider) {
+ this.analysisWarnings = analysisWarnings;
this.sourceInclusions = inclusions(configProvider, CoreProperties.PROJECT_INCLUSIONS_PROPERTY);
- this.testInclusions = inclusions(configProvider, CoreProperties.PROJECT_TEST_INCLUSIONS_PROPERTY);
this.sourceExclusions = exclusions(configProvider, CoreProperties.GLOBAL_EXCLUSIONS_PROPERTY, CoreProperties.PROJECT_EXCLUSIONS_PROPERTY);
- this.testExclusions = exclusions(configProvider, CoreProperties.GLOBAL_TEST_EXCLUSIONS_PROPERTY, CoreProperties.PROJECT_TEST_EXCLUSIONS_PROPERTY);
+
+ String[] testInclusionsFromLegacy = inclusions(configProvider, PROJECT_TEST_INCLUSIONS_PROPERTY);
+ String[] testInclusionsFromAlias = inclusions(configProvider, PROJECT_TESTS_INCLUSIONS_PROPERTY);
+ this.testInclusions = keepInclusionTestBetweenLegacyAndAliasProperties(testInclusionsFromLegacy, testInclusionsFromAlias);
+ String[] testExclusionsFromLegacy = exclusions(configProvider, CoreProperties.GLOBAL_TEST_EXCLUSIONS_PROPERTY, PROJECT_TEST_EXCLUSIONS_PROPERTY);
+ String[] testExclusionsFromAlias = exclusions(configProvider, CoreProperties.GLOBAL_TEST_EXCLUSIONS_PROPERTY, PROJECT_TESTS_EXCLUSIONS_PROPERTY);
+ this.testExclusions = keepExclusionTestBetweenLegacyAndAliasProperties(testExclusionsFromLegacy, testExclusionsFromAlias);
+
this.mainInclusionsPattern = prepareMainInclusions(sourceInclusions);
- this.mainExclusionsPattern = prepareMainExclusions(sourceExclusions, testInclusions);
- this.testInclusionsPattern = prepareTestInclusions(testInclusions);
- this.testExclusionsPattern = prepareTestExclusions(testExclusions);
+ this.mainExclusionsPattern = prepareMainExclusions(sourceExclusions, this.testInclusions);
+ this.testInclusionsPattern = prepareTestInclusions(this.testInclusions);
+ this.testExclusionsPattern = prepareTestExclusions(this.testExclusions);
+ }
+
+ private String[] keepExclusionTestBetweenLegacyAndAliasProperties(String[] fromLegacyProperty, String[] fromAliasProperty) {
+ if (fromAliasProperty.length == 0) {
+ return fromLegacyProperty;
+ }
+ if (fromLegacyProperty.length == 0) {
+ logWarningForAliasUsage(PROJECT_TEST_EXCLUSIONS_PROPERTY, PROJECT_TESTS_EXCLUSIONS_PROPERTY);
+ return fromAliasProperty;
+ }
+ logWarningForLegacyAndAliasUsage(PROJECT_TEST_EXCLUSIONS_PROPERTY, PROJECT_TESTS_EXCLUSIONS_PROPERTY);
+ return fromLegacyProperty;
+ }
+
+ private String[] keepInclusionTestBetweenLegacyAndAliasProperties(String[] fromLegacyProperty, String[] fromAliasProperty) {
+ if (fromAliasProperty.length == 0) {
+ return fromLegacyProperty;
+ }
+ if (fromLegacyProperty.length == 0) {
+ logWarningForAliasUsage(PROJECT_TEST_INCLUSIONS_PROPERTY, PROJECT_TESTS_INCLUSIONS_PROPERTY);
+ return fromAliasProperty;
+ }
+ logWarningForLegacyAndAliasUsage(PROJECT_TEST_INCLUSIONS_PROPERTY, PROJECT_TESTS_INCLUSIONS_PROPERTY);
+ return fromLegacyProperty;
+ }
+
+ private void logWarningForAliasUsage(String legacyProperty, String aliasProperty) {
+ logWarning(format(WARNING_ALIAS_PROPERTY_USAGE, aliasProperty, legacyProperty));
+ }
+
+ private void logWarningForLegacyAndAliasUsage(String legacyProperty, String aliasProperty) {
+ logWarning(format(WARNING_LEGACY_AND_ALIAS_PROPERTIES_USAGE, legacyProperty, aliasProperty, legacyProperty));
+ }
+
+ private void logWarning(String warning) {
+ LOG.warn(warning);
+ analysisWarnings.addUnique(warning);
}
public void log(String indent) {
/**
* <p>Checks if the file should be excluded as a parent directory of excluded files and subdirectories.</p>
- *
+ *
* @param absolutePath The full path of the file.
* @param relativePath The relative path of the file.
- * @param baseDir The base directory of the project.
- * @param type The file type.
+ * @param baseDir The base directory of the project.
+ * @param type The file type.
* @return True if the file should be excluded, false otherwise.
*/
public boolean isExcludedAsParentDirectoryOfExcludedChildren(Path absolutePath, Path relativePath, Path baseDir, InputFile.Type type) {
*/
package org.sonar.scanner.scan.filesystem;
+import org.sonar.api.notifications.AnalysisWarnings;
import org.sonar.scanner.scan.ModuleConfiguration;
public class ModuleExclusionFilters extends AbstractExclusionFilters {
- public ModuleExclusionFilters(ModuleConfiguration moduleConfiguration) {
- super(moduleConfiguration::getStringArray);
+
+ public ModuleExclusionFilters(ModuleConfiguration moduleConfiguration, AnalysisWarnings analysisWarnings) {
+ super(analysisWarnings, moduleConfiguration::getStringArray);
}
}
package org.sonar.scanner.scan.filesystem;
import org.sonar.api.config.Configuration;
+import org.sonar.api.notifications.AnalysisWarnings;
public class ProjectExclusionFilters extends AbstractExclusionFilters {
- public ProjectExclusionFilters(Configuration projectConfig) {
- super(projectConfig::getStringArray);
+ public ProjectExclusionFilters(Configuration projectConfig, AnalysisWarnings analysisWarnings) {
+ super(analysisWarnings, projectConfig::getStringArray);
}
}
import org.sonar.api.batch.fs.InputFile.Type;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.scm.IgnoreCommand;
+import org.sonar.api.notifications.AnalysisWarnings;
import org.sonar.api.scan.filesystem.PathResolver;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
private final FileIndexer fileIndexer;
private final IgnoreCommand ignoreCommand;
private final boolean useScmExclusion;
+ private final AnalysisWarnings analysisWarnings;
private ProgressReport progressReport;
public ProjectFileIndexer(InputComponentStore componentStore, ProjectExclusionFilters exclusionFilters,
SonarGlobalPropertiesFilter sonarGlobalPropertiesFilter, InputModuleHierarchy inputModuleHierarchy,
GlobalConfiguration globalConfig, GlobalServerSettings globalServerSettings, ProjectServerSettings projectServerSettings,
- FileIndexer fileIndexer, ProjectCoverageAndDuplicationExclusions projectCoverageAndDuplicationExclusions, ScmConfiguration scmConfiguration) {
+ FileIndexer fileIndexer, ProjectCoverageAndDuplicationExclusions projectCoverageAndDuplicationExclusions, ScmConfiguration scmConfiguration,
+ AnalysisWarnings analysisWarnings) {
this.componentStore = componentStore;
this.sonarGlobalPropertiesFilter = sonarGlobalPropertiesFilter;
this.inputModuleHierarchy = inputModuleHierarchy;
this.projectExclusionFilters = exclusionFilters;
this.projectCoverageAndDuplicationExclusions = projectCoverageAndDuplicationExclusions;
this.scmConfiguration = scmConfiguration;
+ this.analysisWarnings = analysisWarnings;
this.ignoreCommand = loadIgnoreCommand();
this.useScmExclusion = ignoreCommand != null;
}
private void index(DefaultInputModule module, ExclusionCounter exclusionCounter) {
// Emulate creation of module level settings
ModuleConfiguration moduleConfig = new ModuleConfigurationProvider(sonarGlobalPropertiesFilter).provide(globalConfig, module, globalServerSettings, projectServerSettings);
- ModuleExclusionFilters moduleExclusionFilters = new ModuleExclusionFilters(moduleConfig);
+ ModuleExclusionFilters moduleExclusionFilters = new ModuleExclusionFilters(moduleConfig, analysisWarnings);
ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions = new ModuleCoverageAndDuplicationExclusions(moduleConfig);
if (componentStore.allModules().size() > 1) {
LOG.info("Indexing files of module '{}'", module.getName());
private static void logPaths(String label, Path baseDir, List<Path> paths) {
if (!paths.isEmpty()) {
StringBuilder sb = new StringBuilder(label);
- for (Iterator<Path> it = paths.iterator(); it.hasNext();) {
+ for (Iterator<Path> it = paths.iterator(); it.hasNext(); ) {
Path file = it.next();
Optional<String> relativePathToBaseDir = PathResolver.relativize(baseDir, file);
if (!relativePathToBaseDir.isPresent()) {
* <p>Exclusions patterns are checked both at project and module level.</p>
*
* @param moduleExclusionFilters The exclusion filters.
- * @param realAbsoluteFile The path to be checked.
- * @param projectBaseDir The project base directory.
- * @param moduleBaseDir The module base directory.
- * @param type The input file type.
+ * @param realAbsoluteFile The path to be checked.
+ * @param projectBaseDir The project base directory.
+ * @param moduleBaseDir The module base directory.
+ * @param type The input file type.
* @return True if path is an excluded directory, false otherwise.
*/
private static boolean isExcludedDirectory(ModuleExclusionFilters moduleExclusionFilters, Path realAbsoluteFile, Path projectBaseDir, Path moduleBaseDir,
* </p>
*
* @param file a reference to the file
- * @param exc the I/O exception that prevented the file from being visited
- *
+ * @param exc the I/O exception that prevented the file from being visited
* @throws IOException
*/
@Override
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * 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 02110-1301, USA.
+ */
+package org.sonar.scanner.scan.filesystem;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.fs.IndexedFile;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.internal.DefaultIndexedFile;
+import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.notifications.AnalysisWarnings;
+import org.sonar.api.utils.log.LogTester;
+import org.sonar.api.utils.log.LoggerLevel;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.sonar.api.CoreProperties.PROJECT_TESTS_EXCLUSIONS_PROPERTY;
+import static org.sonar.api.CoreProperties.PROJECT_TESTS_INCLUSIONS_PROPERTY;
+import static org.sonar.api.CoreProperties.PROJECT_TEST_EXCLUSIONS_PROPERTY;
+import static org.sonar.api.CoreProperties.PROJECT_TEST_INCLUSIONS_PROPERTY;
+
+public class AbstractExclusionFiltersTest {
+
+ @Rule
+ public LogTester logTester = new LogTester();
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ private AnalysisWarnings analysisWarnings;
+ private Path moduleBaseDir;
+ private MapSettings settings;
+
+ @Before
+ public void setUp() throws IOException {
+ settings = new MapSettings();
+ moduleBaseDir = temp.newFolder().toPath();
+ this.analysisWarnings = mock(AnalysisWarnings.class);
+ }
+
+ @Test
+ public void should_handleAliasForTestInclusionsProperty() {
+ settings.setProperty(PROJECT_TESTS_INCLUSIONS_PROPERTY, "**/*Dao.java");
+ AbstractExclusionFilters filter = new AbstractExclusionFilters(analysisWarnings, settings.asConfig()::getStringArray) {
+ };
+
+ IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "test/main/java/com/mycompany/FooDao.java", null);
+ assertThat(filter.isIncluded(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.TEST)).isTrue();
+
+ indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "test/main/java/com/mycompany/Foo.java", null);
+ assertThat(filter.isIncluded(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.TEST)).isFalse();
+
+ String expectedWarn = "Use of sonar.tests.inclusions detected. " +
+ "While being taken into account, the only supported property is sonar.test.inclusions. Consider updating your configuration.";
+ assertThat( logTester.logs(LoggerLevel.WARN) ).hasSize(1)
+ .contains(expectedWarn);
+ verify(analysisWarnings).addUnique(expectedWarn);
+ }
+
+ @Test
+ public void should_handleAliasForTestExclusionsProperty() {
+ settings.setProperty(PROJECT_TESTS_EXCLUSIONS_PROPERTY, "**/*Dao.java");
+ AbstractExclusionFilters filter = new AbstractExclusionFilters(analysisWarnings, settings.asConfig()::getStringArray) {
+ };
+
+ IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "test/main/java/com/mycompany/FooDao.java", null);
+ assertThat(filter.isExcluded(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.TEST)).isTrue();
+
+ indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "test/main/java/com/mycompany/Foo.java", null);
+ assertThat(filter.isExcluded(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.TEST)).isFalse();
+
+ String expectedWarn = "Use of sonar.tests.exclusions detected. " +
+ "While being taken into account, the only supported property is sonar.test.exclusions. Consider updating your configuration.";
+ assertThat( logTester.logs(LoggerLevel.WARN) ).hasSize(1)
+ .contains(expectedWarn);
+ verify(analysisWarnings).addUnique(expectedWarn);
+ }
+
+ @Test
+ public void should_keepLegacyValue_when_legacyAndAliasPropertiesAreUsedForTestInclusions(){
+ settings.setProperty(PROJECT_TESTS_INCLUSIONS_PROPERTY, "**/*Dao.java");
+ settings.setProperty(PROJECT_TEST_INCLUSIONS_PROPERTY,"**/*Dto.java");
+ AbstractExclusionFilters filter = new AbstractExclusionFilters(analysisWarnings, settings.asConfig()::getStringArray) {
+ };
+
+ IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "test/main/java/com/mycompany/FooDao.java", null);
+ assertThat(filter.isIncluded(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.TEST)).isFalse();
+
+ indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "test/main/java/com/mycompany/FooDto.java", null);
+ assertThat(filter.isIncluded(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.TEST)).isTrue();
+
+ String expectedWarn = "Use of sonar.test.inclusions and sonar.tests.inclusions at the same time. sonar.test.inclusions is taken into account. Consider updating your configuration";
+ assertThat( logTester.logs(LoggerLevel.WARN) ).hasSize(1)
+ .contains(expectedWarn);
+ verify(analysisWarnings).addUnique(expectedWarn);
+ }
+
+ @Test
+ public void should_keepLegacyValue_when_legacyAndAliasPropertiesAreUsedForTestExclusions(){
+ settings.setProperty(PROJECT_TESTS_EXCLUSIONS_PROPERTY, "**/*Dao.java");
+ settings.setProperty(PROJECT_TEST_EXCLUSIONS_PROPERTY,"**/*Dto.java");
+ AbstractExclusionFilters filter = new AbstractExclusionFilters(analysisWarnings, settings.asConfig()::getStringArray) {
+ };
+
+ IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "test/main/java/com/mycompany/FooDao.java", null);
+ assertThat(filter.isExcluded(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.TEST)).isFalse();
+
+ indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "test/main/java/com/mycompany/FooDto.java", null);
+ assertThat(filter.isExcluded(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.TEST)).isTrue();
+
+ String expectedWarn = "Use of sonar.test.exclusions and sonar.tests.exclusions at the same time. sonar.test.exclusions is taken into account. Consider updating your configuration";
+ assertThat( logTester.logs(LoggerLevel.WARN) ).hasSize(1)
+ .contains(expectedWarn);
+ verify(analysisWarnings).addUnique(expectedWarn);
+ }
+}
\ No newline at end of file
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultIndexedFile;
import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.notifications.AnalysisWarnings;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
public class ProjectExclusionFiltersTest {
@Test
public void no_inclusions_nor_exclusions() {
- ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig());
+ ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig(), mock(AnalysisWarnings.class));
IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDao.java", null);
assertThat(filter.isExcluded(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse();
@Test
public void match_inclusion() {
settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "**/*Dao.java");
- ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig());
+ ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig(), mock(AnalysisWarnings.class));
IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDao.java", null);
assertThat(filter.isIncluded(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue();
@Test
public void match_at_least_one_inclusion() {
settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "**/*Dao.java,**/*Dto.java");
- ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig());
+ ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig(),mock(AnalysisWarnings.class));
IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/Foo.java", null);
assertThat(filter.isIncluded(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse();
settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "src/main/java/**/*");
settings.setProperty(CoreProperties.PROJECT_TEST_INCLUSIONS_PROPERTY, "src/test/java/**/*");
settings.setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, "**/*Dao.java");
- ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig());
+ ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig(),mock(AnalysisWarnings.class));
IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDao.java", null);
assertThat(filter.isExcluded(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue();
settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "src/main/java/**/*");
settings.setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, "file:" + excludedFile.getAbsolutePath());
- ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig());
+ ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig(),mock(AnalysisWarnings.class));
IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/org/bar/Foo.java", null);
assertThat(filter.isExcluded(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse();