aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-scanner-engine/src
diff options
context:
space:
mode:
authorJulien HENRY <julien.henry@sonarsource.com>2018-12-14 19:35:50 +0100
committersonartech <sonartech@sonarsource.com>2019-01-16 09:43:10 +0100
commitbbff7949d06677e808d7c6f2cf4fd7cfc1f1a079 (patch)
tree2333a2f05764d9e00833fda00c142d776b2d1387 /sonar-scanner-engine/src
parent4db8bd9ecf0584443a2e5a9c369970e6ee85f48f (diff)
downloadsonarqube-bbff7949d06677e808d7c6f2cf4fd7cfc1f1a079.tar.gz
sonarqube-bbff7949d06677e808d7c6f2cf4fd7cfc1f1a079.zip
SONAR-11587 Rework issue exclusions
Diffstat (limited to 'sonar-scanner-engine/src')
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/DefaultFilterableIssue.java13
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssueFilters.java5
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssuePublisher.java2
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilter.java55
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilter.java51
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/AbstractPatternInitializer.java16
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssueExclusionPatternInitializer.java14
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssueInclusionPatternInitializer.java4
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssuePattern.java90
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/PatternDecoder.java100
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/PatternMatcher.java62
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsLoader.java44
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScanner.java32
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectReactorBuilder.java42
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java3
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java4
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/MetadataGenerator.java2
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/DefaultFilterableIssueTest.java12
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/IssuePublisherTest.java10
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilterTest.java66
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilterTest.java43
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssueExclusionPatternInitializerTest.java9
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssuePatternTest.java61
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/PatternDecoderTest.java56
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/PatternMatcherTest.java111
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsLoaderTest.java69
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest.java77
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/FileSystemMediumTest.java8
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/issues/IssuesMediumTest.java249
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ProjectReactorBuilderTest.java10
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/MetadataGeneratorTest.java6
31 files changed, 589 insertions, 737 deletions
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/DefaultFilterableIssue.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/DefaultFilterableIssue.java
index eaf4e0f1edb..bb92a02f31c 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/DefaultFilterableIssue.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/DefaultFilterableIssue.java
@@ -23,6 +23,7 @@ import java.util.Date;
import javax.annotation.concurrent.ThreadSafe;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
+import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.fs.TextRange;
import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.api.batch.fs.internal.DefaultTextPointer;
@@ -35,20 +36,20 @@ import org.sonar.scanner.protocol.output.ScannerReport.Issue;
@ThreadSafe
public class DefaultFilterableIssue implements FilterableIssue {
private final Issue rawIssue;
+ private final InputComponent component;
private final ProjectAnalysisInfo projectAnalysisInfo;
- private final String componentKey;
private DefaultInputProject project;
- public DefaultFilterableIssue(DefaultInputProject project, ProjectAnalysisInfo projectAnalysisInfo, Issue rawIssue, String componentKey) {
+ public DefaultFilterableIssue(DefaultInputProject project, ProjectAnalysisInfo projectAnalysisInfo, Issue rawIssue, InputComponent component) {
this.project = project;
this.projectAnalysisInfo = projectAnalysisInfo;
this.rawIssue = rawIssue;
- this.componentKey = componentKey;
+ this.component = component;
}
@Override
public String componentKey() {
- return componentKey;
+ return component.key();
}
@Override
@@ -98,6 +99,10 @@ public class DefaultFilterableIssue implements FilterableIssue {
return project.key();
}
+ public InputComponent getComponent() {
+ return component;
+ }
+
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssueFilters.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssueFilters.java
index 92a8f758249..b4ade123839 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssueFilters.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssueFilters.java
@@ -19,6 +19,7 @@
*/
package org.sonar.scanner.issue;
+import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.api.scan.issue.filter.FilterableIssue;
import org.sonar.api.scan.issue.filter.IssueFilter;
@@ -45,8 +46,8 @@ public class IssueFilters {
this(project, projectAnalysisInfo, new IssueFilter[0]);
}
- public boolean accept(String componentKey, ScannerReport.Issue rawIssue) {
- FilterableIssue fIssue = new DefaultFilterableIssue(project, projectAnalysisInfo, rawIssue, componentKey);
+ public boolean accept(InputComponent component, ScannerReport.Issue rawIssue) {
+ FilterableIssue fIssue = new DefaultFilterableIssue(project, projectAnalysisInfo, rawIssue, component);
return filterChain.accept(fIssue);
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssuePublisher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssuePublisher.java
index ca0a8cc0764..f8a652553ea 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssuePublisher.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssuePublisher.java
@@ -70,7 +70,7 @@ public class IssuePublisher {
ScannerReport.Issue rawIssue = createReportIssue(issue, inputComponent.scannerId(), activeRule.severity());
- if (filters.accept(inputComponent.key(), rawIssue)) {
+ if (filters.accept(inputComponent, rawIssue)) {
write(inputComponent.scannerId(), rawIssue);
return true;
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilter.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilter.java
index 3f5b74f2390..0cf870ea06b 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilter.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilter.java
@@ -22,31 +22,31 @@ package org.sonar.scanner.issue.ignore;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-
-import javax.annotation.CheckForNull;
import javax.annotation.concurrent.ThreadSafe;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.sonar.api.batch.fs.InputComponent;
-import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.notifications.AnalysisWarnings;
import org.sonar.api.scan.issue.filter.FilterableIssue;
import org.sonar.api.scan.issue.filter.IssueFilter;
import org.sonar.api.scan.issue.filter.IssueFilterChain;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.scanner.issue.DefaultFilterableIssue;
import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer;
import org.sonar.scanner.issue.ignore.pattern.IssuePattern;
-import org.sonar.scanner.scan.filesystem.InputComponentStore;
@ThreadSafe
public class EnforceIssuesFilter implements IssueFilter {
- private static final Logger LOG = LoggerFactory.getLogger(EnforceIssuesFilter.class);
+ private static final Logger LOG = Loggers.get(EnforceIssuesFilter.class);
private final List<IssuePattern> multicriteriaPatterns;
- private final InputComponentStore componentStore;
+ private final AnalysisWarnings analysisWarnings;
+
+ private boolean warnDeprecatedIssuePatternAlreadyLogged;
- public EnforceIssuesFilter(IssueInclusionPatternInitializer patternInitializer, InputComponentStore componentStore) {
+ public EnforceIssuesFilter(IssueInclusionPatternInitializer patternInitializer, AnalysisWarnings analysisWarnings) {
this.multicriteriaPatterns = Collections.unmodifiableList(new ArrayList<>(patternInitializer.getMulticriteriaPatterns()));
- this.componentStore = componentStore;
+ this.analysisWarnings = analysisWarnings;
}
@Override
@@ -56,12 +56,22 @@ public class EnforceIssuesFilter implements IssueFilter {
IssuePattern matchingPattern = null;
for (IssuePattern pattern : multicriteriaPatterns) {
- if (pattern.getRulePattern().match(issue.ruleKey().toString())) {
+ if (pattern.matchRule(issue.ruleKey())) {
atLeastOneRuleMatched = true;
- String relativePath = getRelativePath(issue.componentKey());
- if (relativePath != null && pattern.getResourcePattern().match(relativePath)) {
- atLeastOnePatternFullyMatched = true;
- matchingPattern = pattern;
+ InputComponent component = ((DefaultFilterableIssue) issue).getComponent();
+ if (component.isFile()) {
+ DefaultInputFile file = (DefaultInputFile) component;
+ if (pattern.matchFile(file.getProjectRelativePath())) {
+ atLeastOnePatternFullyMatched = true;
+ matchingPattern = pattern;
+ } else if (pattern.matchFile(file.getModuleRelativePath())) {
+ warnOnceDeprecatedIssuePattern(
+ "Specifying module-relative paths at project level in property '" + IssueInclusionPatternInitializer.CONFIG_KEY + "' is deprecated. " +
+ "To continue matching files like '" + file.getProjectRelativePath() + "', update this property so that patterns refer to project-relative paths.");
+
+ atLeastOnePatternFullyMatched = true;
+ matchingPattern = pattern;
+ }
}
}
}
@@ -76,13 +86,12 @@ public class EnforceIssuesFilter implements IssueFilter {
}
}
- @CheckForNull
- private String getRelativePath(String componentKey) {
- InputComponent component = componentStore.getByKey(componentKey);
- if (component == null || !component.isFile()) {
- return null;
+ private void warnOnceDeprecatedIssuePattern(String msg) {
+ if (!warnDeprecatedIssuePatternAlreadyLogged) {
+ LOG.warn(msg);
+ analysisWarnings.addUnique(msg);
+ warnDeprecatedIssuePatternAlreadyLogged = true;
}
- InputFile inputPath = (InputFile) component;
- return inputPath.relativePath();
}
+
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilter.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilter.java
index 723d7eecc4d..666b1732dea 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilter.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilter.java
@@ -19,42 +19,55 @@
*/
package org.sonar.scanner.issue.ignore;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
+import org.sonar.api.batch.fs.InputComponent;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.scan.issue.filter.FilterableIssue;
import org.sonar.api.scan.issue.filter.IssueFilter;
import org.sonar.api.scan.issue.filter.IssueFilterChain;
-import org.sonar.scanner.issue.ignore.pattern.IssuePattern;
-import org.sonar.scanner.issue.ignore.pattern.PatternMatcher;
+import org.sonar.api.utils.WildcardPattern;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.scanner.issue.DefaultFilterableIssue;
public class IgnoreIssuesFilter implements IssueFilter {
- private PatternMatcher patternMatcher;
+ private Multimap<InputComponent, WildcardPattern> rulePatternByComponent = LinkedHashMultimap.create();
- private static final Logger LOG = LoggerFactory.getLogger(IgnoreIssuesFilter.class);
-
- public IgnoreIssuesFilter(PatternMatcher patternMatcher) {
- this.patternMatcher = patternMatcher;
- }
+ private static final Logger LOG = Loggers.get(IgnoreIssuesFilter.class);
@Override
public boolean accept(FilterableIssue issue, IssueFilterChain chain) {
- if (hasMatchFor(issue)) {
+ InputComponent component = ((DefaultFilterableIssue) issue).getComponent();
+ if (component.isFile() && ((DefaultInputFile) component).isIgnoreAllIssues()) {
+ return false;
+ }
+ if (component.isFile() && ((DefaultInputFile) component).isIgnoreAllIssuesOnLine(issue.line())) {
+ return false;
+ }
+ if (hasRuleMatchFor(component, issue)) {
return false;
}
return chain.accept(issue);
}
- private boolean hasMatchFor(FilterableIssue issue) {
- IssuePattern pattern = patternMatcher.getMatchingPattern(issue.componentKey(), issue.ruleKey(), issue.line());
- if (pattern != null) {
- logExclusion(issue, pattern);
- return true;
+ public void addRuleExclusionPatternForComponent(DefaultInputFile inputFile, WildcardPattern rulePattern) {
+ if ("*".equals(rulePattern.toString())) {
+ inputFile.setIgnoreAllIssues(true);
+ } else {
+ rulePatternByComponent.put(inputFile, rulePattern);
}
- return false;
}
- private static void logExclusion(FilterableIssue issue, IssuePattern pattern) {
- LOG.debug("Issue {} ignored by exclusion pattern {}", issue, pattern);
+ private boolean hasRuleMatchFor(InputComponent component, FilterableIssue issue) {
+ for (WildcardPattern pattern : rulePatternByComponent.get(component)) {
+ if (pattern.match(issue.ruleKey().toString())) {
+ LOG.debug("Issue {} ignored by exclusion pattern {}", issue, pattern);
+ return true;
+ }
+ }
+ return false;
+
}
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/AbstractPatternInitializer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/AbstractPatternInitializer.java
index 51058404811..4b85daf89e4 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/AbstractPatternInitializer.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/AbstractPatternInitializer.java
@@ -22,9 +22,9 @@ package org.sonar.scanner.issue.ignore.pattern;
import com.google.common.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.List;
-import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.config.Configuration;
+import org.sonar.api.utils.MessageException;
import static com.google.common.base.MoreObjects.firstNonNull;
@@ -59,13 +59,15 @@ public abstract class AbstractPatternInitializer {
multicriteriaPatterns = new ArrayList<>();
for (String id : settings.getStringArray(getMulticriteriaConfigurationKey())) {
String propPrefix = getMulticriteriaConfigurationKey() + "." + id + ".";
- String resourceKeyPattern = settings.get(propPrefix + "resourceKey").orElse(null);
+ String filePathPattern = settings.get(propPrefix + "resourceKey").orElse(null);
+ if (StringUtils.isBlank(filePathPattern)) {
+ throw MessageException.of("Issue exclusions are misconfigured. File pattern is mandatory for each entry of '" + getMulticriteriaConfigurationKey() + "'");
+ }
String ruleKeyPattern = settings.get(propPrefix + "ruleKey").orElse(null);
- String lineRange = "*";
- String[] fields = new String[] {resourceKeyPattern, ruleKeyPattern, lineRange};
- PatternDecoder.checkRegularLineConstraints(StringUtils.join(fields, ","), fields);
- Set<LineRange> rangeOfLines = PatternDecoder.decodeRangeOfLines(firstNonNull(lineRange, "*"));
- IssuePattern pattern = new IssuePattern(firstNonNull(resourceKeyPattern, "*"), firstNonNull(ruleKeyPattern, "*"), rangeOfLines);
+ if (StringUtils.isBlank(ruleKeyPattern)) {
+ throw MessageException.of("Issue exclusions are misconfigured. Rule key pattern is mandatory for each entry of '" + getMulticriteriaConfigurationKey() + "'");
+ }
+ IssuePattern pattern = new IssuePattern(firstNonNull(filePathPattern, "*"), firstNonNull(ruleKeyPattern, "*"));
multicriteriaPatterns.add(pattern);
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssueExclusionPatternInitializer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssueExclusionPatternInitializer.java
index 01e0ab76b06..16c3163cbf7 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssueExclusionPatternInitializer.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssueExclusionPatternInitializer.java
@@ -24,12 +24,14 @@ import java.util.Collections;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.config.Configuration;
+import org.sonar.api.utils.MessageException;
import org.sonar.core.config.IssueExclusionProperties;
import static com.google.common.base.Strings.nullToEmpty;
public class IssueExclusionPatternInitializer extends AbstractPatternInitializer {
+ public static final String CONFIG_KEY = IssueExclusionProperties.EXCLUSION_KEY_PREFIX + ".multicriteria";
private List<BlockIssuePattern> blockPatterns;
private List<String> allFilePatterns;
@@ -40,7 +42,7 @@ public class IssueExclusionPatternInitializer extends AbstractPatternInitializer
@Override
protected String getMulticriteriaConfigurationKey() {
- return IssueExclusionProperties.EXCLUSION_KEY_PREFIX + ".multicriteria";
+ return CONFIG_KEY;
}
@Override
@@ -54,9 +56,11 @@ public class IssueExclusionPatternInitializer extends AbstractPatternInitializer
for (String id : getSettings().getStringArray(IssueExclusionProperties.PATTERNS_BLOCK_KEY)) {
String propPrefix = IssueExclusionProperties.PATTERNS_BLOCK_KEY + "." + id + ".";
String beginBlockRegexp = getSettings().get(propPrefix + IssueExclusionProperties.BEGIN_BLOCK_REGEXP).orElse(null);
+ if (StringUtils.isBlank(beginBlockRegexp)) {
+ throw MessageException.of("Issue exclusions are misconfigured. Start block regexp is mandatory for each entry of '" + IssueExclusionProperties.PATTERNS_BLOCK_KEY + "'");
+ }
String endBlockRegexp = getSettings().get(propPrefix + IssueExclusionProperties.END_BLOCK_REGEXP).orElse(null);
- String[] fields = new String[] {beginBlockRegexp, endBlockRegexp};
- PatternDecoder.checkDoubleRegexpLineConstraints(StringUtils.join(fields, ","), fields);
+ // As per configuration help, missing second field means: from start regexp to EOF
BlockIssuePattern pattern = new BlockIssuePattern(nullToEmpty(beginBlockRegexp), nullToEmpty(endBlockRegexp));
blockPatterns.add(pattern);
}
@@ -67,7 +71,9 @@ public class IssueExclusionPatternInitializer extends AbstractPatternInitializer
for (String id : getSettings().getStringArray(IssueExclusionProperties.PATTERNS_ALLFILE_KEY)) {
String propPrefix = IssueExclusionProperties.PATTERNS_ALLFILE_KEY + "." + id + ".";
String allFileRegexp = getSettings().get(propPrefix + IssueExclusionProperties.FILE_REGEXP).orElse(null);
- PatternDecoder.checkWholeFileRegexp(allFileRegexp);
+ if (StringUtils.isBlank(allFileRegexp)) {
+ throw MessageException.of("Issue exclusions are misconfigured. Remove blank entries from '" + IssueExclusionProperties.PATTERNS_ALLFILE_KEY + "'");
+ }
allFilePatterns.add(nullToEmpty(allFileRegexp));
}
allFilePatterns = Collections.unmodifiableList(allFilePatterns);
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssueInclusionPatternInitializer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssueInclusionPatternInitializer.java
index 0fa72da96db..30987808e9d 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssueInclusionPatternInitializer.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssueInclusionPatternInitializer.java
@@ -24,12 +24,14 @@ import org.sonar.core.config.IssueExclusionProperties;
public class IssueInclusionPatternInitializer extends AbstractPatternInitializer {
+ public static final String CONFIG_KEY = IssueExclusionProperties.INCLUSION_KEY_PREFIX + ".multicriteria";
+
public IssueInclusionPatternInitializer(Configuration settings) {
super(settings);
}
@Override
protected String getMulticriteriaConfigurationKey() {
- return IssueExclusionProperties.INCLUSION_KEY_PREFIX + ".multicriteria";
+ return CONFIG_KEY;
}
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssuePattern.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssuePattern.java
index 4e76159ab72..9be0fd7c75e 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssuePattern.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssuePattern.java
@@ -19,108 +19,32 @@
*/
package org.sonar.scanner.issue.ignore.pattern;
-import java.util.Collections;
-import java.util.LinkedHashSet;
-import java.util.Set;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
-import org.apache.commons.lang.builder.ToStringBuilder;
-import org.apache.commons.lang.builder.ToStringStyle;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.WildcardPattern;
@Immutable
public class IssuePattern {
- private final WildcardPattern resourcePattern;
+ private final WildcardPattern filePattern;
private final WildcardPattern rulePattern;
- private final Set<Integer> lines;
- private final Set<LineRange> lineRanges;
- private final boolean checkLines;
- public IssuePattern(String resourcePattern, String rulePattern) {
- this(resourcePattern, rulePattern, Collections.emptySet());
- }
-
- public IssuePattern(String resourcePattern, String rulePattern, Set<LineRange> lineRanges) {
- this.resourcePattern = WildcardPattern.create(resourcePattern);
+ public IssuePattern(String filePattern, String rulePattern) {
+ this.filePattern = WildcardPattern.create(filePattern);
this.rulePattern = WildcardPattern.create(rulePattern);
- this.checkLines = !lineRanges.isEmpty();
- Set<Integer> modifiableLines = new LinkedHashSet<>();
- Set<LineRange> modifiableLineRanges = new LinkedHashSet<>();
-
- for (LineRange range : lineRanges) {
- if (range.from() == range.to()) {
- modifiableLines.add(range.from());
- } else {
- modifiableLineRanges.add(range);
- }
- }
-
- this.lines = Collections.unmodifiableSet(modifiableLines);
- this.lineRanges = Collections.unmodifiableSet(modifiableLineRanges);
- }
-
- public WildcardPattern getResourcePattern() {
- return resourcePattern;
}
public WildcardPattern getRulePattern() {
return rulePattern;
}
- boolean isCheckLines() {
- return checkLines;
- }
-
- Set<Integer> getAllLines() {
- Set<Integer> allLines = new LinkedHashSet<>(lines);
- for (LineRange lineRange : lineRanges) {
- allLines.addAll(lineRange.toLines());
- }
- return allLines;
+ public boolean matchRule(RuleKey rule) {
+ return rulePattern.match(rule.toString());
}
- public boolean match(@Nullable String componentKey, RuleKey ruleKey, @Nullable Integer line) {
- if (checkLines) {
- if (line == null) {
- return false;
- } else {
- return matchResource(componentKey) && matchRule(ruleKey) && matchLine(line);
- }
- }
- return matchResource(componentKey) && matchRule(ruleKey);
+ public boolean matchFile(@Nullable String filePath) {
+ return filePath != null && filePattern.match(filePath);
}
- boolean matchLine(int lineId) {
- if (lines.contains(lineId)) {
- return true;
- }
-
- for (LineRange range : lineRanges) {
- if (range.in(lineId)) {
- return true;
- }
- }
-
- return false;
- }
-
- boolean matchRule(RuleKey rule) {
- String key = new StringBuilder().append(rule.repository()).append(':').append(rule.rule()).toString();
- return rulePattern.match(key);
- }
-
- public boolean matchResource(@Nullable String resource) {
- return resource != null && resourcePattern.match(resource);
- }
-
- public IssuePattern forResource(String resource) {
- return new IssuePattern(resource, rulePattern.toString(), lineRanges);
- }
-
- @Override
- public String toString() {
- return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
- }
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/PatternDecoder.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/PatternDecoder.java
deleted file mode 100644
index bb301e3f57b..00000000000
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/PatternDecoder.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 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.issue.ignore.pattern;
-
-import com.google.common.annotations.VisibleForTesting;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-import org.apache.commons.lang.StringUtils;
-
-public class PatternDecoder {
- private static final String LINE_RANGE_REGEXP = "\\[((\\d+|\\d+-\\d+),?)*\\]";
- private static final String CONFIG_FORMAT_ERROR_PREFIX = "Exclusions > Issues : Invalid format. ";
-
- private PatternDecoder() {
- // static only
- }
-
- static void checkRegularLineConstraints(String line, String[] fields) {
- if (!isResource(fields[0])) {
- throw new IllegalStateException(CONFIG_FORMAT_ERROR_PREFIX + "The first field does not define a resource pattern: " + line);
- }
- if (!isRule(fields[1])) {
- throw new IllegalStateException(CONFIG_FORMAT_ERROR_PREFIX + "The second field does not define a rule pattern: " + line);
- }
- if (!isLinesRange(fields[2])) {
- throw new IllegalStateException(CONFIG_FORMAT_ERROR_PREFIX + "The third field does not define a range of lines: " + line);
- }
- }
-
- static void checkDoubleRegexpLineConstraints(String line, String[] fields) {
- if (!isRegexp(fields[0])) {
- throw new IllegalStateException(CONFIG_FORMAT_ERROR_PREFIX + "The first field does not define a regular expression: " + line);
- }
- // As per configuration help, missing second field means: from start regexp to EOF
- }
-
- static void checkWholeFileRegexp(String regexp) {
- if (!isRegexp(regexp)) {
- throw new IllegalStateException(CONFIG_FORMAT_ERROR_PREFIX + "The field does not define a regular expression: " + regexp);
- }
- }
-
- public static Set<LineRange> decodeRangeOfLines(String field) {
- if (StringUtils.equals(field, "*")) {
- return Collections.emptySet();
- } else {
- Set<LineRange> lineRanges = new HashSet<>();
-
- String s = StringUtils.substringBetween(StringUtils.trim(field), "[", "]");
- String[] parts = StringUtils.split(s, ',');
- for (String part : parts) {
- if (StringUtils.contains(part, '-')) {
- String[] range = StringUtils.split(part, '-');
- lineRanges.add(new LineRange(Integer.valueOf(range[0]), Integer.valueOf(range[1])));
- } else {
- lineRanges.add(new LineRange(Integer.valueOf(part), Integer.valueOf(part)));
- }
- }
- return lineRanges;
- }
- }
-
- @VisibleForTesting
- static boolean isLinesRange(String field) {
- return StringUtils.equals(field, "*") || java.util.regex.Pattern.matches(LINE_RANGE_REGEXP, field);
- }
-
- @VisibleForTesting
- static boolean isResource(String field) {
- return StringUtils.isNotBlank(field);
- }
-
- @VisibleForTesting
- static boolean isRule(String field) {
- return StringUtils.isNotBlank(field);
- }
-
- @VisibleForTesting
- static boolean isRegexp(String field) {
- return StringUtils.isNotBlank(field);
- }
-}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/PatternMatcher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/PatternMatcher.java
deleted file mode 100644
index a9be53e5aa0..00000000000
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/PatternMatcher.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 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.issue.ignore.pattern;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.LinkedHashMultimap;
-import com.google.common.collect.Multimap;
-import java.util.Collection;
-import java.util.Set;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import org.sonar.api.rule.RuleKey;
-
-public class PatternMatcher {
-
- private Multimap<String, IssuePattern> excludePatternByComponent = LinkedHashMultimap.create();
-
- @CheckForNull
- public IssuePattern getMatchingPattern(String componentKey, RuleKey ruleKey, @Nullable Integer line) {
- for (IssuePattern pattern : getPatternsForComponent(componentKey)) {
- if (pattern.match(componentKey, ruleKey, line)) {
- return pattern;
- }
- }
- return null;
- }
-
- @VisibleForTesting
- public Collection<IssuePattern> getPatternsForComponent(String componentKey) {
- return excludePatternByComponent.get(componentKey);
- }
-
- public void addPatternForComponent(String componentKey, IssuePattern pattern) {
- excludePatternByComponent.put(componentKey, pattern.forResource(componentKey));
- }
-
- public void addPatternToExcludeResource(String componentKey) {
- addPatternForComponent(componentKey, new IssuePattern(componentKey, "*"));
- }
-
- public void addPatternToExcludeLines(String componentKey, Set<LineRange> lineRanges) {
- addPatternForComponent(componentKey, new IssuePattern(componentKey, "*", lineRanges));
- }
-
-}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsLoader.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsLoader.java
index 7a3591af10c..6e639385b09 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsLoader.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsLoader.java
@@ -23,22 +23,31 @@ import java.util.ArrayList;
import java.util.List;
import javax.annotation.CheckForNull;
import org.apache.commons.lang.StringUtils;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.charhandler.CharHandler;
+import org.sonar.api.notifications.AnalysisWarnings;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.scanner.issue.ignore.IgnoreIssuesFilter;
import org.sonar.scanner.issue.ignore.pattern.BlockIssuePattern;
import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
import org.sonar.scanner.issue.ignore.pattern.IssuePattern;
-import org.sonar.scanner.issue.ignore.pattern.PatternMatcher;
public final class IssueExclusionsLoader {
+ private static final Logger LOG = Loggers.get(IssueExclusionsLoader.class);
+
private final List<java.util.regex.Pattern> allFilePatterns;
private final List<DoubleRegexpMatcher> blockMatchers;
- private final PatternMatcher patternMatcher;
+ private final IgnoreIssuesFilter ignoreIssuesFilter;
+ private final AnalysisWarnings analysisWarnings;
private final IssueExclusionPatternInitializer patternsInitializer;
private final boolean enableCharHandler;
+ private boolean warnDeprecatedIssuePatternAlreadyLogged;
- public IssueExclusionsLoader(IssueExclusionPatternInitializer patternsInitializer, PatternMatcher patternMatcher) {
+ public IssueExclusionsLoader(IssueExclusionPatternInitializer patternsInitializer, IgnoreIssuesFilter ignoreIssuesFilter, AnalysisWarnings analysisWarnings) {
this.patternsInitializer = patternsInitializer;
- this.patternMatcher = patternMatcher;
+ this.ignoreIssuesFilter = ignoreIssuesFilter;
+ this.analysisWarnings = analysisWarnings;
this.allFilePatterns = new ArrayList<>();
this.blockMatchers = new ArrayList<>();
@@ -53,22 +62,31 @@ public final class IssueExclusionsLoader {
enableCharHandler = !allFilePatterns.isEmpty() || !blockMatchers.isEmpty();
}
- public boolean shouldExecute() {
- return patternsInitializer.hasMulticriteriaPatterns();
- }
-
- public void addMulticriteriaPatterns(String relativePath, String componentKey) {
+ public void addMulticriteriaPatterns(DefaultInputFile inputFile) {
for (IssuePattern pattern : patternsInitializer.getMulticriteriaPatterns()) {
- if (pattern.matchResource(relativePath)) {
- patternMatcher.addPatternForComponent(componentKey, pattern);
+ if (pattern.matchFile(inputFile.getProjectRelativePath())) {
+ ignoreIssuesFilter.addRuleExclusionPatternForComponent(inputFile, pattern.getRulePattern());
+ } else if (pattern.matchFile(inputFile.getModuleRelativePath())) {
+ warnOnceDeprecatedIssuePattern(
+ "Specifying module-relative paths at project level in property '" + IssueExclusionPatternInitializer.CONFIG_KEY + "' is deprecated. " +
+ "To continue matching files like '" + inputFile.getProjectRelativePath() + "', update this property so that patterns refer to project-relative paths.");
+ ignoreIssuesFilter.addRuleExclusionPatternForComponent(inputFile, pattern.getRulePattern());
}
}
}
+ private void warnOnceDeprecatedIssuePattern(String msg) {
+ if (!warnDeprecatedIssuePatternAlreadyLogged) {
+ LOG.warn(msg);
+ analysisWarnings.addUnique(msg);
+ warnDeprecatedIssuePatternAlreadyLogged = true;
+ }
+ }
+
@CheckForNull
- public CharHandler createCharHandlerFor(String componentKey) {
+ public CharHandler createCharHandlerFor(DefaultInputFile inputFile) {
if (enableCharHandler) {
- return new IssueExclusionsRegexpScanner(componentKey, allFilePatterns, blockMatchers, patternMatcher);
+ return new IssueExclusionsRegexpScanner(inputFile, allFilePatterns, blockMatchers);
}
return null;
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScanner.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScanner.java
index 5daf24c6075..a08ba55a593 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScanner.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScanner.java
@@ -24,12 +24,12 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
-import org.apache.commons.lang.StringUtils;
+import java.util.stream.Collectors;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.charhandler.CharHandler;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.scanner.issue.ignore.pattern.LineRange;
-import org.sonar.scanner.issue.ignore.pattern.PatternMatcher;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader.DoubleRegexpMatcher;
public class IssueExclusionsRegexpScanner extends CharHandler {
@@ -38,8 +38,7 @@ public class IssueExclusionsRegexpScanner extends CharHandler {
private final StringBuilder sb = new StringBuilder();
private final List<Pattern> allFilePatterns;
private final List<DoubleRegexpMatcher> blockMatchers;
- private final String componentKey;
- private final PatternMatcher patternMatcher;
+ private final DefaultInputFile inputFile;
private int lineIndex = 1;
private List<LineExclusion> lineExclusions = new ArrayList<>();
@@ -47,22 +46,26 @@ public class IssueExclusionsRegexpScanner extends CharHandler {
private int fileLength = 0;
private DoubleRegexpMatcher currentMatcher;
- IssueExclusionsRegexpScanner(String componentKey, List<Pattern> allFilePatterns, List<DoubleRegexpMatcher> blockMatchers, PatternMatcher patternMatcher) {
+ IssueExclusionsRegexpScanner(DefaultInputFile inputFile, List<Pattern> allFilePatterns, List<DoubleRegexpMatcher> blockMatchers) {
this.allFilePatterns = allFilePatterns;
this.blockMatchers = blockMatchers;
- this.patternMatcher = patternMatcher;
- this.componentKey = componentKey;
- String relativePath = StringUtils.substringAfterLast(componentKey, ":");
- LOG.info("'{}' generating issue exclusions", relativePath);
+ this.inputFile = inputFile;
+ LOG.debug("Evaluate issue exclusions for '{}'", inputFile.getProjectRelativePath());
}
@Override
public void handleIgnoreEoL(char c) {
+ if (inputFile.isIgnoreAllIssues()) {
+ return;
+ }
sb.append(c);
}
@Override
public void newLine() {
+ if (inputFile.isIgnoreAllIssues()) {
+ return;
+ }
processLine(sb.toString());
sb.setLength(0);
lineIndex++;
@@ -70,6 +73,9 @@ public class IssueExclusionsRegexpScanner extends CharHandler {
@Override
public void eof() {
+ if (inputFile.isIgnoreAllIssues()) {
+ return;
+ }
processLine(sb.toString());
if (currentMatcher != null && !currentMatcher.hasSecondPattern()) {
@@ -81,8 +87,8 @@ public class IssueExclusionsRegexpScanner extends CharHandler {
fileLength = lineIndex;
if (!lineExclusions.isEmpty()) {
Set<LineRange> lineRanges = convertLineExclusionsToLineRanges();
- LOG.debug("- Line exclusions found: {}", lineRanges);
- patternMatcher.addPatternToExcludeLines(componentKey, lineRanges);
+ LOG.debug(" - Line exclusions found: {}", lineRanges.stream().map(LineRange::toString).collect(Collectors.joining(",")));
+ inputFile.addIgnoreIssuesOnLineRanges(lineRanges.stream().map(r -> new int[] {r.from(), r.to()}).collect(Collectors.toList()));
}
}
@@ -94,9 +100,9 @@ public class IssueExclusionsRegexpScanner extends CharHandler {
// first check the single regexp patterns that can be used to totally exclude a file
for (Pattern pattern : allFilePatterns) {
if (pattern.matcher(line).find()) {
- patternMatcher.addPatternToExcludeResource(componentKey);
// nothing more to do on this file
- LOG.debug("- Exclusion pattern '{}': every issue in this file will be ignored.", pattern);
+ LOG.debug(" - Exclusion pattern '{}': all issues in this file will be ignored.", pattern);
+ inputFile.setIgnoreAllIssues(true);
return;
}
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectReactorBuilder.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectReactorBuilder.java
index 38d0d60733f..7dceaf350a0 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectReactorBuilder.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectReactorBuilder.java
@@ -20,17 +20,18 @@
package org.sonar.scanner.scan;
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.Lists;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.MessageFormat;
import java.util.Arrays;
+import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.stream.Stream;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.apache.commons.lang.ArrayUtils;
@@ -38,16 +39,21 @@ import org.apache.commons.lang.StringUtils;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.bootstrap.ProjectReactor;
+import org.sonar.api.notifications.AnalysisWarnings;
import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler;
+import org.sonar.core.config.IssueExclusionProperties;
import org.sonar.scanner.bootstrap.ScannerProperties;
+import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
+import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer;
import org.sonar.scanner.util.ScannerUtils;
+import static java.util.Arrays.asList;
+import static java.util.stream.Collectors.toList;
import static org.sonar.api.config.internal.MultivalueProperty.parseAsCsv;
-
/**
* Class that creates a project definition based on a set of properties.
*/
@@ -95,17 +101,23 @@ public class ProjectReactorBuilder {
*/
private static final String[] MANDATORY_PROPERTIES_FOR_CHILD = {MODULE_KEY_PROPERTY};
+ private static final Collection<String> UNSUPPORTED_PROPS_FOR_MODULES = asList(IssueExclusionPatternInitializer.CONFIG_KEY, IssueInclusionPatternInitializer.CONFIG_KEY,
+ IssueExclusionProperties.PATTERNS_BLOCK_KEY, IssueExclusionProperties.PATTERNS_ALLFILE_KEY);
+
/**
* 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(PROPERTY_PROJECT_BASEDIR, CoreProperties.WORKING_DIRECTORY, PROPERTY_MODULES,
- CoreProperties.PROJECT_DESCRIPTION_PROPERTY);
+ private static final List<String> NON_HERITED_PROPERTIES_FOR_CHILD = Stream.concat(Stream.of(PROPERTY_PROJECT_BASEDIR, CoreProperties.WORKING_DIRECTORY, PROPERTY_MODULES,
+ CoreProperties.PROJECT_DESCRIPTION_PROPERTY), UNSUPPORTED_PROPS_FOR_MODULES.stream()).collect(toList());
private final ScannerProperties scannerProps;
+ private final AnalysisWarnings analysisWarnings;
private File rootProjectWorkDir;
+ private boolean warnExclusionsAlreadyLogged;
- public ProjectReactorBuilder(ScannerProperties props) {
+ public ProjectReactorBuilder(ScannerProperties props, AnalysisWarnings analysisWarnings) {
this.scannerProps = props;
+ this.analysisWarnings = analysisWarnings;
}
public ProjectReactor execute() {
@@ -121,7 +133,7 @@ public class ProjectReactorBuilder {
}
private static void extractPropertiesByModule(Map<String, Map<String, String>> propertiesByModuleIdPath, String currentModuleId, String currentModuleIdPath,
- Map<String, String> parentProperties) {
+ Map<String, String> parentProperties) {
if (propertiesByModuleIdPath.containsKey(currentModuleIdPath)) {
throw MessageException.of(String.format("Two modules have the same id: '%s'. Each module must have a unique id.", currentModuleId));
}
@@ -170,6 +182,7 @@ public class ProjectReactorBuilder {
workDir = initRootProjectWorkDir(baseDir, moduleProperties);
} else {
workDir = initModuleWorkDir(baseDir, moduleProperties);
+ checkUnsupportedIssueExclusions(moduleProperties);
}
return ProjectDefinition.create().setProperties(moduleProperties)
@@ -178,6 +191,23 @@ public class ProjectReactorBuilder {
.setBuildDir(initModuleBuildDir(baseDir, moduleProperties));
}
+ private void checkUnsupportedIssueExclusions(Map<String, String> moduleProperties) {
+ UNSUPPORTED_PROPS_FOR_MODULES.stream().forEach(p -> {
+ if (moduleProperties.containsKey(p)) {
+ warnOnceUnsupportedIssueExclusions(
+ "Specifying issue exclusions at module level is not supported anymore. Configure the property '" + p + "' and any other issue exclusions at project level.");
+ }
+ });
+ }
+
+ private void warnOnceUnsupportedIssueExclusions(String msg) {
+ if (!warnExclusionsAlreadyLogged) {
+ LOG.warn(msg);
+ analysisWarnings.addUnique(msg);
+ warnExclusionsAlreadyLogged = true;
+ }
+ }
+
@VisibleForTesting
protected File initRootProjectWorkDir(File baseDir, Map<String, String> rootProperties) {
String workDir = rootProperties.get(CoreProperties.WORKING_DIRECTORY);
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java
index b3d656a55c3..6171c2793de 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java
@@ -47,7 +47,6 @@ import org.sonar.scanner.bootstrap.MetricProvider;
import org.sonar.scanner.bootstrap.PostJobExtensionDictionnary;
import org.sonar.scanner.cpd.CpdExecutor;
import org.sonar.scanner.cpd.CpdSettings;
-import org.sonar.scanner.cpd.JavaCpdBlockIndexerSensor;
import org.sonar.scanner.cpd.index.SonarCpdBlockIndex;
import org.sonar.scanner.deprecated.test.TestPlanBuilder;
import org.sonar.scanner.deprecated.test.TestableBuilder;
@@ -59,7 +58,6 @@ import org.sonar.scanner.issue.ignore.EnforceIssuesFilter;
import org.sonar.scanner.issue.ignore.IgnoreIssuesFilter;
import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer;
-import org.sonar.scanner.issue.ignore.pattern.PatternMatcher;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
import org.sonar.scanner.issue.tracking.DefaultServerLineHashesLoader;
import org.sonar.scanner.issue.tracking.IssueTransition;
@@ -230,7 +228,6 @@ public class ProjectScanContainer extends ComponentContainer {
// issue exclusions
IssueInclusionPatternInitializer.class,
IssueExclusionPatternInitializer.class,
- PatternMatcher.class,
IssueExclusionsLoader.class,
EnforceIssuesFilter.class,
IgnoreIssuesFilter.class,
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 cd9767328a2..aba73c172a4 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
@@ -134,9 +134,7 @@ public class FileIndexer {
}
checkIfAlreadyIndexed(inputFile);
componentStore.put(module.key(), inputFile);
- if (issueExclusionsLoader.shouldExecute()) {
- issueExclusionsLoader.addMulticriteriaPatterns(inputFile.getProjectRelativePath(), inputFile.key());
- }
+ issueExclusionsLoader.addMulticriteriaPatterns(inputFile);
LOG.debug("'{}' indexed {}with language '{}'", projectRelativePath, type == Type.TEST ? "as test " : "", inputFile.language());
evaluateCoverageExclusions(moduleCoverageExclusions, inputFile);
if (properties.preloadFileMetadata()) {
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/MetadataGenerator.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/MetadataGenerator.java
index a603edbe6de..cf7833e18fc 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/MetadataGenerator.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/MetadataGenerator.java
@@ -64,7 +64,7 @@ public class MetadataGenerator {
}
InputStream is = charsetDetector.inputStream();
inputFile.setCharset(charset);
- Metadata metadata = fileMetadata.readMetadata(is, charset, inputFile.absolutePath(), exclusionsScanner.createCharHandlerFor(inputFile.key()));
+ Metadata metadata = fileMetadata.readMetadata(is, charset, inputFile.absolutePath(), exclusionsScanner.createCharHandlerFor(inputFile));
inputFile.setMetadata(metadata);
inputFile.setStatus(statusDetection.status(moduleKeyWithBranch, inputFile, metadata.hash()));
LOG.debug("'{}' generated metadata{} with charset '{}'", inputFile, inputFile.type() == Type.TEST ? " as test " : "", charset);
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/DefaultFilterableIssueTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/DefaultFilterableIssueTest.java
index 9b379f021a2..240624f63c3 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/DefaultFilterableIssueTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/DefaultFilterableIssueTest.java
@@ -22,6 +22,7 @@ package org.sonar.scanner.issue;
import java.util.Date;
import org.junit.Before;
import org.junit.Test;
+import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.scanner.ProjectAnalysisInfo;
import org.sonar.scanner.protocol.Constants.Severity;
@@ -36,14 +37,15 @@ public class DefaultFilterableIssueTest {
private DefaultFilterableIssue issue;
private DefaultInputProject mockedProject;
private ProjectAnalysisInfo projectAnalysisInfo;
- private String componentKey;
+ private InputComponent component;
private Issue rawIssue;
@Before
public void setUp() {
mockedProject = mock(DefaultInputProject.class);
projectAnalysisInfo = mock(ProjectAnalysisInfo.class);
- componentKey = "component";
+ component = mock(InputComponent.class);
+ when(component.key()).thenReturn("foo");
}
private Issue createIssue() {
@@ -68,12 +70,12 @@ public class DefaultFilterableIssueTest {
@Test
public void testRoundTrip() {
rawIssue = createIssue();
- issue = new DefaultFilterableIssue(mockedProject, projectAnalysisInfo, rawIssue, componentKey);
+ issue = new DefaultFilterableIssue(mockedProject, projectAnalysisInfo, rawIssue, component);
when(projectAnalysisInfo.analysisDate()).thenReturn(new Date(10_000));
when(mockedProject.key()).thenReturn("projectKey");
- assertThat(issue.componentKey()).isEqualTo(componentKey);
+ assertThat(issue.componentKey()).isEqualTo(component.key());
assertThat(issue.creationDate()).isEqualTo(new Date(10_000));
assertThat(issue.line()).isEqualTo(30);
assertThat(issue.textRange().start().line()).isEqualTo(30);
@@ -88,7 +90,7 @@ public class DefaultFilterableIssueTest {
@Test
public void nullValues() {
rawIssue = createIssueWithoutFields();
- issue = new DefaultFilterableIssue(mockedProject, projectAnalysisInfo, rawIssue, componentKey);
+ issue = new DefaultFilterableIssue(mockedProject, projectAnalysisInfo, rawIssue, component);
assertThat(issue.line()).isNull();
assertThat(issue.gap()).isNull();
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/IssuePublisherTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/IssuePublisherTest.java
index 2c472af2ea0..3e371c728fc 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/IssuePublisherTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/IssuePublisherTest.java
@@ -31,6 +31,7 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
+import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
@@ -48,7 +49,6 @@ import org.sonar.scanner.report.ReportPublisher;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.mock;
@@ -130,7 +130,7 @@ public class IssuePublisherTest {
.forRule(SQUID_RULE_KEY)
.overrideSeverity(org.sonar.api.batch.rule.Severity.CRITICAL);
- when(filters.accept(anyString(), any(ScannerReport.Issue.class))).thenReturn(true);
+ when(filters.accept(any(InputComponent.class), any(ScannerReport.Issue.class))).thenReturn(true);
boolean added = moduleIssues.initAndAddIssue(issue);
@@ -171,7 +171,7 @@ public class IssuePublisherTest {
DefaultIssue issue = new DefaultIssue(project)
.at(new DefaultIssueLocation().on(file).at(file.selectLine(3)).message("Foo"))
.forRule(SQUID_RULE_KEY);
- when(filters.accept(anyString(), any(ScannerReport.Issue.class))).thenReturn(true);
+ when(filters.accept(any(InputComponent.class), any(ScannerReport.Issue.class))).thenReturn(true);
moduleIssues.initAndAddIssue(issue);
ArgumentCaptor<ScannerReport.Issue> argument = ArgumentCaptor.forClass(ScannerReport.Issue.class);
@@ -193,7 +193,7 @@ public class IssuePublisherTest {
.at(new DefaultIssueLocation().on(file).at(file.selectLine(3)).message(""))
.forRule(SQUID_RULE_KEY);
- when(filters.accept(anyString(), any(ScannerReport.Issue.class))).thenReturn(false);
+ when(filters.accept(any(InputComponent.class), any(ScannerReport.Issue.class))).thenReturn(false);
boolean added = moduleIssues.initAndAddIssue(issue);
@@ -240,7 +240,7 @@ public class IssuePublisherTest {
.at(new DefaultIssueLocation().on(file).at(file.selectLine(3)).message(""))
.forRule(NOSONAR_RULE_KEY);
- when(filters.accept(anyString(), any(ScannerReport.Issue.class))).thenReturn(true);
+ when(filters.accept(any(InputComponent.class), any(ScannerReport.Issue.class))).thenReturn(true);
boolean added = moduleIssues.initAndAddIssue(issue);
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilterTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilterTest.java
index f5c1f1baecf..80ce4f25eb2 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilterTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilterTest.java
@@ -20,17 +20,19 @@
package org.sonar.scanner.issue.ignore;
import com.google.common.collect.ImmutableList;
+import java.io.IOException;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
+import org.sonar.api.notifications.AnalysisWarnings;
import org.sonar.api.rule.RuleKey;
-import org.sonar.api.scan.issue.filter.FilterableIssue;
import org.sonar.api.scan.issue.filter.IssueFilterChain;
-import org.sonar.api.utils.WildcardPattern;
+import org.sonar.scanner.issue.DefaultFilterableIssue;
import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer;
import org.sonar.scanner.issue.ignore.pattern.IssuePattern;
-import org.sonar.scanner.scan.filesystem.InputComponentStore;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
@@ -40,24 +42,25 @@ import static org.mockito.Mockito.when;
public class EnforceIssuesFilterTest {
+ @Rule
+ public TemporaryFolder tempFolder = new TemporaryFolder();
+
private IssueInclusionPatternInitializer exclusionPatternInitializer;
- private InputComponentStore inputComponentStore;
private EnforceIssuesFilter ignoreFilter;
- private FilterableIssue issue;
+ private DefaultFilterableIssue issue;
private IssueFilterChain chain;
@Before
public void init() {
- inputComponentStore = mock(InputComponentStore.class);
exclusionPatternInitializer = mock(IssueInclusionPatternInitializer.class);
- issue = mock(FilterableIssue.class);
+ issue = mock(DefaultFilterableIssue.class);
chain = mock(IssueFilterChain.class);
when(chain.accept(issue)).thenReturn(true);
}
@Test
public void shouldPassToChainIfNoConfiguredPatterns() {
- ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, inputComponentStore);
+ ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, mock(AnalysisWarnings.class));
assertThat(ignoreFilter.accept(issue, chain)).isTrue();
verify(chain).accept(issue);
}
@@ -70,12 +73,10 @@ public class EnforceIssuesFilterTest {
when(issue.ruleKey()).thenReturn(ruleKey);
IssuePattern matching = mock(IssuePattern.class);
- WildcardPattern rulePattern = mock(WildcardPattern.class);
- when(matching.getRulePattern()).thenReturn(rulePattern);
- when(rulePattern.match(rule)).thenReturn(false);
+ when(matching.matchRule(ruleKey)).thenReturn(false);
when(exclusionPatternInitializer.getMulticriteriaPatterns()).thenReturn(ImmutableList.of(matching));
- ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, inputComponentStore);
+ ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, mock(AnalysisWarnings.class));
assertThat(ignoreFilter.accept(issue, chain)).isTrue();
verify(chain).accept(issue);
}
@@ -84,23 +85,17 @@ public class EnforceIssuesFilterTest {
public void shouldAcceptIssueIfFullyMatched() {
String rule = "rule";
String path = "org/sonar/api/Issue.java";
- String componentKey = "org.sonar.api.Issue";
RuleKey ruleKey = mock(RuleKey.class);
when(ruleKey.toString()).thenReturn(rule);
when(issue.ruleKey()).thenReturn(ruleKey);
- when(issue.componentKey()).thenReturn(componentKey);
IssuePattern matching = mock(IssuePattern.class);
- WildcardPattern rulePattern = mock(WildcardPattern.class);
- when(matching.getRulePattern()).thenReturn(rulePattern);
- when(rulePattern.match(rule)).thenReturn(true);
- WildcardPattern pathPattern = mock(WildcardPattern.class);
- when(matching.getResourcePattern()).thenReturn(pathPattern);
- when(pathPattern.match(path)).thenReturn(true);
+ when(matching.matchRule(ruleKey)).thenReturn(true);
+ when(matching.matchFile(path)).thenReturn(true);
when(exclusionPatternInitializer.getMulticriteriaPatterns()).thenReturn(ImmutableList.of(matching));
- when(inputComponentStore.getByKey(componentKey)).thenReturn(createComponentWithPath(path));
+ when(issue.getComponent()).thenReturn(createComponentWithPath(path));
- ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, inputComponentStore);
+ ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, mock(AnalysisWarnings.class));
assertThat(ignoreFilter.accept(issue, chain)).isTrue();
verifyZeroInteractions(chain);
}
@@ -120,41 +115,32 @@ public class EnforceIssuesFilterTest {
when(issue.componentKey()).thenReturn(componentKey);
IssuePattern matching = mock(IssuePattern.class);
- WildcardPattern rulePattern = mock(WildcardPattern.class);
- when(matching.getRulePattern()).thenReturn(rulePattern);
- when(rulePattern.match(rule)).thenReturn(true);
- WildcardPattern pathPattern = mock(WildcardPattern.class);
- when(matching.getResourcePattern()).thenReturn(pathPattern);
- when(pathPattern.match(path)).thenReturn(false);
+ when(matching.matchRule(ruleKey)).thenReturn(true);
+ when(matching.matchFile(path)).thenReturn(false);
when(exclusionPatternInitializer.getMulticriteriaPatterns()).thenReturn(ImmutableList.of(matching));
- when(inputComponentStore.getByKey(componentKey)).thenReturn(createComponentWithPath(path));
+ when(issue.getComponent()).thenReturn(createComponentWithPath(path));
- ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, inputComponentStore);
+ ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, mock(AnalysisWarnings.class));
assertThat(ignoreFilter.accept(issue, chain)).isFalse();
verifyZeroInteractions(chain);
}
@Test
- public void shouldRefuseIssueIfRuleMatchesAndPathUnknown() {
+ public void shouldRefuseIssueIfRuleMatchesAndNotFile() throws IOException {
String rule = "rule";
String path = "org/sonar/api/Issue.java";
String componentKey = "org.sonar.api.Issue";
RuleKey ruleKey = mock(RuleKey.class);
when(ruleKey.toString()).thenReturn(rule);
when(issue.ruleKey()).thenReturn(ruleKey);
- when(issue.componentKey()).thenReturn(componentKey);
IssuePattern matching = mock(IssuePattern.class);
- WildcardPattern rulePattern = mock(WildcardPattern.class);
- when(matching.getRulePattern()).thenReturn(rulePattern);
- when(rulePattern.match(rule)).thenReturn(true);
- WildcardPattern pathPattern = mock(WildcardPattern.class);
- when(matching.getResourcePattern()).thenReturn(pathPattern);
- when(pathPattern.match(path)).thenReturn(false);
+ when(matching.matchRule(ruleKey)).thenReturn(true);
+ when(matching.matchFile(path)).thenReturn(true);
when(exclusionPatternInitializer.getMulticriteriaPatterns()).thenReturn(ImmutableList.of(matching));
- when(inputComponentStore.getByKey(componentKey)).thenReturn(null);
+ when(issue.getComponent()).thenReturn(TestInputFileBuilder.newDefaultInputProject("foo", tempFolder.newFolder()));
- ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, inputComponentStore);
+ ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, mock(AnalysisWarnings.class));
assertThat(ignoreFilter.accept(issue, chain)).isFalse();
verifyZeroInteractions(chain);
}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilterTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilterTest.java
index 5f987c98e3a..8a9df4a744a 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilterTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilterTest.java
@@ -19,42 +19,57 @@
*/
package org.sonar.scanner.issue.ignore;
+import org.junit.Before;
import org.junit.Test;
-import org.mockito.Mockito;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.rule.RuleKey;
-import org.sonar.api.scan.issue.filter.FilterableIssue;
import org.sonar.api.scan.issue.filter.IssueFilterChain;
-import org.sonar.scanner.issue.ignore.pattern.IssuePattern;
-import org.sonar.scanner.issue.ignore.pattern.PatternMatcher;
+import org.sonar.api.utils.WildcardPattern;
+import org.sonar.scanner.issue.DefaultFilterableIssue;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class IgnoreIssuesFilterTest {
- private PatternMatcher exclusionPatternMatcher = mock(PatternMatcher.class);
- private FilterableIssue issue = mock(FilterableIssue.class, Mockito.RETURNS_DEEP_STUBS);
+ private DefaultFilterableIssue issue = mock(DefaultFilterableIssue.class);
private IssueFilterChain chain = mock(IssueFilterChain.class);
- private IgnoreIssuesFilter underTest = new IgnoreIssuesFilter(exclusionPatternMatcher);
+ private IgnoreIssuesFilter underTest = new IgnoreIssuesFilter();
+ private DefaultInputFile component;
+ private RuleKey ruleKey = RuleKey.of("foo", "bar");
+
+ @Before
+ public void prepare() {
+ component = mock(DefaultInputFile.class);
+ when(issue.getComponent()).thenReturn(component);
+ when(issue.ruleKey()).thenReturn(ruleKey);
+ }
@Test
public void shouldPassToChainIfMatcherHasNoPatternForIssue() {
- when(exclusionPatternMatcher.getMatchingPattern(anyString(), any(RuleKey.class), any(Integer.class)))
- .thenReturn(null);
when(chain.accept(issue)).thenReturn(true);
assertThat(underTest.accept(issue, chain)).isTrue();
+ verify(chain).accept(any());
}
@Test
- public void shouldRejectIfPatternMatches() {
- IssuePattern pattern = mock(IssuePattern.class);
- when(exclusionPatternMatcher.getMatchingPattern(anyString(), any(RuleKey.class), any(Integer.class)))
- .thenReturn(pattern);
+ public void shouldRejectIfRulePatternMatches() {
+ WildcardPattern pattern = mock(WildcardPattern.class);
+ when(pattern.match(ruleKey.toString())).thenReturn(true);
+ underTest.addRuleExclusionPatternForComponent(component, pattern);
assertThat(underTest.accept(issue, chain)).isFalse();
}
+ @Test
+ public void shouldAcceptIfRulePatternDoesNotMatch() {
+ WildcardPattern pattern = mock(WildcardPattern.class);
+ when(pattern.match(ruleKey.toString())).thenReturn(false);
+ underTest.addRuleExclusionPatternForComponent(component, pattern);
+
+ assertThat(underTest.accept(issue, chain)).isFalse();
+ }
}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssueExclusionPatternInitializerTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssueExclusionPatternInitializerTest.java
index 0a0f394e210..50096cc117f 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssueExclusionPatternInitializerTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssueExclusionPatternInitializerTest.java
@@ -23,6 +23,7 @@ import org.junit.Before;
import org.junit.Test;
import org.sonar.api.config.PropertyDefinitions;
import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.utils.MessageException;
import org.sonar.core.config.IssueExclusionProperties;
import static org.assertj.core.api.Assertions.assertThat;
@@ -43,7 +44,7 @@ public class IssueExclusionPatternInitializerTest {
assertThat(patternsInitializer.getMulticriteriaPatterns().size()).isEqualTo(0);
}
- @Test(expected = IllegalStateException.class)
+ @Test(expected = MessageException.class)
public void shouldLogInvalidResourceKey() {
settings.setProperty("sonar.issue.ignore" + ".multicriteria", "1");
settings.setProperty("sonar.issue.ignore" + ".multicriteria" + ".1." + "resourceKey", "");
@@ -51,7 +52,7 @@ public class IssueExclusionPatternInitializerTest {
patternsInitializer = new IssueExclusionPatternInitializer(settings.asConfig());
}
- @Test(expected = IllegalStateException.class)
+ @Test(expected = MessageException.class)
public void shouldLogInvalidRuleKey() {
settings.setProperty("sonar.issue.ignore" + ".multicriteria", "1");
settings.setProperty("sonar.issue.ignore" + ".multicriteria" + ".1." + "resourceKey", "*");
@@ -78,7 +79,7 @@ public class IssueExclusionPatternInitializerTest {
assertThat(patternsInitializer.getAllFilePatterns().size()).isEqualTo(0);
}
- @Test(expected = IllegalStateException.class)
+ @Test(expected = MessageException.class)
public void shouldLogInvalidStartBlockPattern() {
settings.setProperty(IssueExclusionProperties.PATTERNS_BLOCK_KEY, "1");
settings.setProperty(IssueExclusionProperties.PATTERNS_BLOCK_KEY + ".1." + IssueExclusionProperties.BEGIN_BLOCK_REGEXP, "");
@@ -101,7 +102,7 @@ public class IssueExclusionPatternInitializerTest {
assertThat(patternsInitializer.getAllFilePatterns().size()).isEqualTo(2);
}
- @Test(expected = IllegalStateException.class)
+ @Test(expected = MessageException.class)
public void shouldLogInvalidAllFilePattern() {
settings.setProperty(IssueExclusionProperties.PATTERNS_ALLFILE_KEY, "1");
settings.setProperty(IssueExclusionProperties.PATTERNS_ALLFILE_KEY + ".1." + IssueExclusionProperties.FILE_REGEXP, "");
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssuePatternTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssuePatternTest.java
index ee3ca739f7d..ffb26cffeb8 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssuePatternTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssuePatternTest.java
@@ -19,9 +19,6 @@
*/
package org.sonar.scanner.issue.ignore.pattern;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
import org.junit.Test;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rules.Rule;
@@ -31,35 +28,19 @@ import static org.assertj.core.api.Assertions.assertThat;
public class IssuePatternTest {
@Test
- public void shouldMatchLines() {
- Set<LineRange> lineRanges = new HashSet<>();
- lineRanges.add(new LineRange(12));
- lineRanges.add(new LineRange(15));
- lineRanges.add(new LineRange(20, 25));
-
- IssuePattern pattern = new IssuePattern("*", "*", lineRanges);
-
- assertThat(pattern.matchLine(3)).isFalse();
- assertThat(pattern.matchLine(12)).isTrue();
- assertThat(pattern.matchLine(14)).isFalse();
- assertThat(pattern.matchLine(21)).isTrue();
- assertThat(pattern.matchLine(6599)).isFalse();
- }
-
- @Test
public void shouldMatchJavaFile() {
- String javaFile = "org.foo.Bar";
- assertThat(new IssuePattern("org.foo.Bar", "*").matchResource(javaFile)).isTrue();
- assertThat(new IssuePattern("org.foo.*", "*").matchResource(javaFile)).isTrue();
- assertThat(new IssuePattern("*Bar", "*").matchResource(javaFile)).isTrue();
- assertThat(new IssuePattern("*", "*").matchResource(javaFile)).isTrue();
- assertThat(new IssuePattern("org.*.?ar", "*").matchResource(javaFile)).isTrue();
-
- assertThat(new IssuePattern("org.other.Hello", "*").matchResource(javaFile)).isFalse();
- assertThat(new IssuePattern("org.foo.Hello", "*").matchResource(javaFile)).isFalse();
- assertThat(new IssuePattern("org.*.??ar", "*").matchResource(javaFile)).isFalse();
- assertThat(new IssuePattern("org.*.??ar", "*").matchResource(null)).isFalse();
- assertThat(new IssuePattern("org.*.??ar", "*").matchResource("plop")).isFalse();
+ String javaFile = "org/foo/Bar.java";
+ assertThat(new IssuePattern("org/foo/Bar.java", "*").matchFile(javaFile)).isTrue();
+ assertThat(new IssuePattern("org/foo/*", "*").matchFile(javaFile)).isTrue();
+ assertThat(new IssuePattern("**Bar.java", "*").matchFile(javaFile)).isTrue();
+ assertThat(new IssuePattern("**", "*").matchFile(javaFile)).isTrue();
+ assertThat(new IssuePattern("org/*/?ar.java", "*").matchFile(javaFile)).isTrue();
+
+ assertThat(new IssuePattern("org/other/Hello.java", "*").matchFile(javaFile)).isFalse();
+ assertThat(new IssuePattern("org/foo/Hello.java", "*").matchFile(javaFile)).isFalse();
+ assertThat(new IssuePattern("org/*/??ar.java", "*").matchFile(javaFile)).isFalse();
+ assertThat(new IssuePattern("org/*/??ar.java", "*").matchFile(null)).isFalse();
+ assertThat(new IssuePattern("org/*/??ar.java", "*").matchFile("plop")).isFalse();
}
@Test
@@ -76,22 +57,4 @@ public class IssuePatternTest {
assertThat(new IssuePattern("*", "*:Foo*IllegalRegexp").matchRule(rule)).isFalse();
}
- @Test
- public void shouldMatchViolation() {
- Rule rule = Rule.create("checkstyle", "IllegalRegexp", "");
- String javaFile = "org.foo.Bar";
-
- IssuePattern pattern = new IssuePattern("*", "*", Collections.singleton(new LineRange(12)));
-
- assertThat(pattern.match(javaFile, rule.ruleKey(), null)).isFalse();
- assertThat(pattern.match(javaFile, rule.ruleKey(), 12)).isTrue();
- assertThat(pattern.match(null, rule.ruleKey(), null)).isFalse();
- }
-
- @Test
- public void shouldPrintPatternToString() {
- IssuePattern pattern = new IssuePattern("*", "checkstyle:*");
-
- assertThat(pattern.toString()).isEqualTo("IssuePattern[resourcePattern=*,rulePattern=checkstyle:*,lines=[],lineRanges=[],checkLines=false]");
- }
}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/PatternDecoderTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/PatternDecoderTest.java
deleted file mode 100644
index 2b4f50eb3ac..00000000000
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/PatternDecoderTest.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 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.issue.ignore.pattern;
-
-import org.junit.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class PatternDecoderTest {
- @Test
- public void shouldCheckFormatOfResource() {
- assertThat(PatternDecoder.isResource("")).isFalse();
- assertThat(PatternDecoder.isResource("*")).isTrue();
- assertThat(PatternDecoder.isResource("com.foo.*")).isTrue();
- }
-
- @Test
- public void shouldCheckFormatOfRule() {
- assertThat(PatternDecoder.isRule("")).isFalse();
- assertThat(PatternDecoder.isRule("*")).isTrue();
- assertThat(PatternDecoder.isRule("com.foo.*")).isTrue();
- }
-
- @Test
- public void shouldCheckFormatOfLinesRange() {
- assertThat(PatternDecoder.isLinesRange("")).isFalse();
- assertThat(PatternDecoder.isLinesRange(" ")).isFalse();
- assertThat(PatternDecoder.isLinesRange("12")).isFalse();
- assertThat(PatternDecoder.isLinesRange("12,212")).isFalse();
-
- assertThat(PatternDecoder.isLinesRange("*")).isTrue();
- assertThat(PatternDecoder.isLinesRange("[]")).isTrue();
- assertThat(PatternDecoder.isLinesRange("[13]")).isTrue();
- assertThat(PatternDecoder.isLinesRange("[13,24]")).isTrue();
- assertThat(PatternDecoder.isLinesRange("[13,24,25-500]")).isTrue();
- assertThat(PatternDecoder.isLinesRange("[24-65]")).isTrue();
- assertThat(PatternDecoder.isLinesRange("[13,24-65,84-89,122]")).isTrue();
- }
-}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/PatternMatcherTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/PatternMatcherTest.java
deleted file mode 100644
index 92797410b02..00000000000
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/PatternMatcherTest.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 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.issue.ignore.pattern;
-
-import com.google.common.collect.Sets;
-import java.util.Collections;
-import java.util.Set;
-import javax.annotation.Nullable;
-import org.junit.Before;
-import org.junit.Test;
-import org.sonar.api.rules.Rule;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class PatternMatcherTest {
-
- public static final Rule CHECKSTYLE_RULE = Rule.create("checkstyle", "MagicNumber", "");
- public static final String JAVA_FILE = "org.foo.Hello";
-
- private PatternMatcher patternMatcher;
-
- @Before
- public void setUp() {
- patternMatcher = new PatternMatcher();
- }
-
- @Test
- public void shouldReturnExtraPatternForResource() {
- String file = "foo";
- patternMatcher.addPatternToExcludeResource(file);
-
- IssuePattern extraPattern = patternMatcher.getPatternsForComponent(file).iterator().next();
- assertThat(extraPattern.matchResource(file)).isTrue();
- assertThat(extraPattern.isCheckLines()).isFalse();
- }
-
- @Test
- public void shouldReturnExtraPatternForLinesOfResource() {
- String file = "foo";
- Set<LineRange> lineRanges = Sets.newHashSet();
- lineRanges.add(new LineRange(25, 28));
- patternMatcher.addPatternToExcludeLines(file, lineRanges);
-
- IssuePattern extraPattern = patternMatcher.getPatternsForComponent(file).iterator().next();
- assertThat(extraPattern.matchResource(file)).isTrue();
- assertThat(extraPattern.getAllLines()).isEqualTo(Sets.newHashSet(25, 26, 27, 28));
- }
-
- @Test
- public void shouldHaveNoMatcherIfNoneDefined() {
- assertThat(patternMatcher.getMatchingPattern(JAVA_FILE, CHECKSTYLE_RULE.ruleKey(), null)).isNull();
- }
-
- @Test
- public void shouldMatchWithStandardPatterns() {
- patternMatcher.addPatternForComponent(JAVA_FILE, createPattern("org.foo.Hello", "checkstyle:MagicNumber", createRanges(15, 200)));
-
- assertThat(patternMatcher.getMatchingPattern(JAVA_FILE, CHECKSTYLE_RULE.ruleKey(), 150)).isNotNull();
- }
-
- @Test
- public void shouldNotMatchWithStandardPatterns() {
- patternMatcher.addPatternForComponent(JAVA_FILE, createPattern("org.foo.Hello", "checkstyle:MagicNumber", createRanges(15, 200)));
-
- assertThat(patternMatcher.getMatchingPattern(JAVA_FILE, CHECKSTYLE_RULE.ruleKey(), 5)).isNull();
- }
-
- @Test
- public void shouldMatchWithExtraPattern() {
- patternMatcher.addPatternForComponent(JAVA_FILE, createPattern("org.foo.Hello", "*", createRanges(15, 200)));
-
- assertThat(patternMatcher.getMatchingPattern(JAVA_FILE, CHECKSTYLE_RULE.ruleKey(), 150)).isNotNull();
- }
-
- @Test
- public void shouldNotMatchWithExtraPattern() {
- patternMatcher.addPatternForComponent(JAVA_FILE, createPattern("org.foo.Hello", "*", createRanges(15, 200)));
-
- assertThat(patternMatcher.getMatchingPattern(JAVA_FILE, CHECKSTYLE_RULE.ruleKey(), 5)).isNull();
- }
-
- private IssuePattern createPattern(String resourcePattern, String rulePattern, @Nullable Set<LineRange> lineRanges) {
- if (lineRanges != null) {
- return new IssuePattern(resourcePattern, rulePattern, lineRanges);
- } else {
- return new IssuePattern(resourcePattern, rulePattern);
- }
- }
-
- private Set<LineRange> createRanges(int from, int to) {
- return Collections.singleton(new LineRange(from, to));
- }
-
-}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsLoaderTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsLoaderTest.java
index baa433cef82..b52ad14b4af 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsLoaderTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsLoaderTest.java
@@ -19,7 +19,6 @@
*/
package org.sonar.scanner.issue.ignore.scanner;
-import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import org.junit.Before;
@@ -28,9 +27,12 @@ import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
+import org.sonar.api.notifications.AnalysisWarnings;
+import org.sonar.scanner.issue.ignore.IgnoreIssuesFilter;
import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
import org.sonar.scanner.issue.ignore.pattern.IssuePattern;
-import org.sonar.scanner.issue.ignore.pattern.PatternMatcher;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
@@ -46,15 +48,15 @@ public class IssueExclusionsLoaderTest {
@Mock
private IssueExclusionPatternInitializer exclusionPatternInitializer;
- private PatternMatcher patternMatcher;
+ private IgnoreIssuesFilter ignoreIssuesFilter;
private IssueExclusionsLoader scanner;
@Before
public void before() throws Exception {
- patternMatcher = new PatternMatcher();
+ ignoreIssuesFilter = mock(IgnoreIssuesFilter.class);
MockitoAnnotations.initMocks(this);
- scanner = new IssueExclusionsLoader(exclusionPatternInitializer, patternMatcher);
+ scanner = new IssueExclusionsLoader(exclusionPatternInitializer, ignoreIssuesFilter, mock(AnalysisWarnings.class));
}
@Test
@@ -64,54 +66,31 @@ public class IssueExclusionsLoaderTest {
@Test
public void createComputer() {
- assertThat(scanner.createCharHandlerFor("src/main/java/Foo.java")).isNull();
+ assertThat(scanner.createCharHandlerFor(TestInputFileBuilder.create("foo", "src/main/java/Foo.java").build())).isNull();
when(exclusionPatternInitializer.getAllFilePatterns()).thenReturn(Collections.singletonList("pattern"));
- scanner = new IssueExclusionsLoader(exclusionPatternInitializer, patternMatcher);
- assertThat(scanner.createCharHandlerFor("src/main/java/Foo.java")).isNotNull();
-
+ scanner = new IssueExclusionsLoader(exclusionPatternInitializer, ignoreIssuesFilter, mock(AnalysisWarnings.class));
+ assertThat(scanner.createCharHandlerFor(TestInputFileBuilder.create("foo", "src/main/java/Foo.java").build())).isNotNull();
}
@Test
- public void shouldHavePatternsBasedOnMulticriteriaPattern() {
- IssuePattern pattern1 = new IssuePattern("org/foo/Bar.java", "*");
- IssuePattern pattern2 = new IssuePattern("org/foo/Hello.java", "checkstyle:MagicNumber");
+ public void populateRuleExclusionPatterns() {
+ IssuePattern pattern1 = new IssuePattern("org/foo/Bar*.java", "*");
+ IssuePattern pattern2 = new IssuePattern("org/foo/Hell?.java", "checkstyle:MagicNumber");
when(exclusionPatternInitializer.getMulticriteriaPatterns()).thenReturn(Arrays.asList(new IssuePattern[] {pattern1, pattern2}));
- IssueExclusionsLoader loader = new IssueExclusionsLoader(exclusionPatternInitializer, patternMatcher);
- loader.addMulticriteriaPatterns("org/foo/Bar.java", "org.foo.Bar");
- loader.addMulticriteriaPatterns("org/foo/Baz.java", "org.foo.Baz");
- loader.addMulticriteriaPatterns("org/foo/Hello.java", "org.foo.Hello");
-
- assertThat(patternMatcher.getPatternsForComponent("org.foo.Bar")).hasSize(1);
- assertThat(patternMatcher.getPatternsForComponent("org.foo.Baz")).hasSize(0);
- assertThat(patternMatcher.getPatternsForComponent("org.foo.Hello")).hasSize(1);
- }
-
- @Test
- public void shouldAnalyzeProject() throws IOException {
- IssuePattern pattern = new IssuePattern("**", "*");
- when(exclusionPatternInitializer.getMulticriteriaPatterns()).thenReturn(Collections.singletonList(pattern));
- when(exclusionPatternInitializer.hasMulticriteriaPatterns()).thenReturn(true);
-
- PatternMatcher patternMatcher = mock(PatternMatcher.class);
- IssueExclusionsLoader loader = new IssueExclusionsLoader(exclusionPatternInitializer, patternMatcher);
- assertThat(loader.shouldExecute()).isTrue();
- loader.addMulticriteriaPatterns("src/main/java/Foo.java", "polop:src/main/java/Foo.java");
- loader.addMulticriteriaPatterns("src/test/java/FooTest.java", "polop:src/test/java/FooTest.java");
-
- verify(patternMatcher).addPatternForComponent("polop:src/main/java/Foo.java", pattern);
- verify(patternMatcher).addPatternForComponent("polop:src/test/java/FooTest.java", pattern);
- verifyNoMoreInteractions(patternMatcher);
+ IssueExclusionsLoader loader = new IssueExclusionsLoader(exclusionPatternInitializer, ignoreIssuesFilter, mock(AnalysisWarnings.class));
+ DefaultInputFile file1 = TestInputFileBuilder.create("foo", "org/foo/Bar.java").build();
+ loader.addMulticriteriaPatterns(file1);
+ DefaultInputFile file2 = TestInputFileBuilder.create("foo", "org/foo/Baz.java").build();
+ loader.addMulticriteriaPatterns(file2);
+ DefaultInputFile file3 = TestInputFileBuilder.create("foo", "org/foo/Hello.java").build();
+ loader.addMulticriteriaPatterns(file3);
+
+ verify(ignoreIssuesFilter).addRuleExclusionPatternForComponent(file1, pattern1.getRulePattern());
+ verify(ignoreIssuesFilter).addRuleExclusionPatternForComponent(file3, pattern2.getRulePattern());
+ verifyNoMoreInteractions(ignoreIssuesFilter);
}
- @Test
- public void shouldExecute() {
- when(exclusionPatternInitializer.hasMulticriteriaPatterns()).thenReturn(true);
- assertThat(scanner.shouldExecute()).isTrue();
-
- when(exclusionPatternInitializer.hasMulticriteriaPatterns()).thenReturn(false);
- assertThat(scanner.shouldExecute()).isFalse();
- }
}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest.java
index f47fdebe959..ab54b184c7d 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest.java
@@ -27,32 +27,27 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collections;
-import java.util.HashSet;
import java.util.List;
-import java.util.Set;
import java.util.regex.Pattern;
+import java.util.stream.IntStream;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.FileMetadata;
+import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
-import org.sonar.scanner.issue.ignore.pattern.LineRange;
-import org.sonar.scanner.issue.ignore.pattern.PatternMatcher;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader.DoubleRegexpMatcher;
import static java.nio.charset.StandardCharsets.UTF_8;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
public class IssueExclusionsRegexpScannerTest {
- private String javaFile;
+ private DefaultInputFile javaFile;
@Mock
private IssueExclusionPatternInitializer patternsInitializer;
- @Mock
- private PatternMatcher patternMatcher;
private List<Pattern> allFilePatterns;
private List<DoubleRegexpMatcher> blockPatterns;
@@ -69,8 +64,8 @@ public class IssueExclusionsRegexpScannerTest {
});
allFilePatterns = Collections.singletonList(Pattern.compile("@SONAR-IGNORE-ALL"));
- javaFile = "org.sonar.test.MyFile";
- regexpScanner = new IssueExclusionsRegexpScanner(javaFile, allFilePatterns, blockPatterns, patternMatcher);
+ javaFile = TestInputFileBuilder.create("foo", "src/Foo.java").build();
+ regexpScanner = new IssueExclusionsRegexpScanner(javaFile, allFilePatterns, blockPatterns);
}
@Test
@@ -78,8 +73,7 @@ public class IssueExclusionsRegexpScannerTest {
Path filePath = getResource("file-with-single-regexp-last-line.txt");
fileMetadata.readMetadata(Files.newInputStream(filePath), UTF_8, filePath.toString(), regexpScanner);
- verify(patternMatcher, times(1)).addPatternToExcludeResource(javaFile);
- verifyNoMoreInteractions(patternMatcher);
+ assertThat(javaFile.isIgnoreAllIssues()).isTrue();
}
@Test
@@ -87,39 +81,34 @@ public class IssueExclusionsRegexpScannerTest {
Path filePath = getResource("file-with-no-regexp.txt");
fileMetadata.readMetadata(Files.newInputStream(filePath), UTF_8, filePath.toString(), regexpScanner);
- verifyNoMoreInteractions(patternMatcher);
+ assertThat(javaFile.isIgnoreAllIssues()).isFalse();
}
@Test
- public void shouldAddPatternToExcludeFile() throws Exception {
+ public void shouldExcludeAllIssues() throws Exception {
Path filePath = getResource("file-with-single-regexp.txt");
fileMetadata.readMetadata(Files.newInputStream(filePath), UTF_8, filePath.toString(), regexpScanner);
- verify(patternMatcher, times(1)).addPatternToExcludeResource(javaFile);
- verifyNoMoreInteractions(patternMatcher);
+ assertThat(javaFile.isIgnoreAllIssues()).isTrue();
}
@Test
- public void shouldAddPatternToExcludeFileEvenIfAlsoDoubleRegexps() throws Exception {
+ public void shouldExcludeAllIssuesEvenIfAlsoDoubleRegexps() throws Exception {
Path filePath = getResource("file-with-single-regexp-and-double-regexp.txt");
fileMetadata.readMetadata(Files.newInputStream(filePath), UTF_8, filePath.toString(), regexpScanner);
- Set<LineRange> lineRanges = new HashSet<>();
- lineRanges.add(new LineRange(5, 26));
- verify(patternMatcher, times(1)).addPatternToExcludeResource(javaFile);
- verify(patternMatcher, times(1)).addPatternToExcludeLines(javaFile, lineRanges);
- verifyNoMoreInteractions(patternMatcher);
+ assertThat(javaFile.isIgnoreAllIssues()).isTrue();
}
@Test
- public void shouldAddPatternToExcludeLines() throws Exception {
+ public void shouldExcludeLines() throws Exception {
Path filePath = getResource("file-with-double-regexp.txt");
fileMetadata.readMetadata(Files.newInputStream(filePath), UTF_8, filePath.toString(), regexpScanner);
- Set<LineRange> lineRanges = new HashSet<>();
- lineRanges.add(new LineRange(21, 25));
- verify(patternMatcher, times(1)).addPatternToExcludeLines(javaFile, lineRanges);
- verifyNoMoreInteractions(patternMatcher);
+ assertThat(javaFile.isIgnoreAllIssues()).isFalse();
+ assertThat(IntStream.rangeClosed(1, 20).noneMatch(javaFile::isIgnoreAllIssuesOnLine)).isTrue();
+ assertThat(IntStream.rangeClosed(21, 25).allMatch(javaFile::isIgnoreAllIssuesOnLine)).isTrue();
+ assertThat(IntStream.rangeClosed(26, 34).noneMatch(javaFile::isIgnoreAllIssuesOnLine)).isTrue();
}
@Test
@@ -127,10 +116,9 @@ public class IssueExclusionsRegexpScannerTest {
Path filePath = getResource("file-with-double-regexp-unfinished.txt");
fileMetadata.readMetadata(Files.newInputStream(filePath), UTF_8, filePath.toString(), regexpScanner);
- Set<LineRange> lineRanges = new HashSet<>();
- lineRanges.add(new LineRange(21, 34));
- verify(patternMatcher, times(1)).addPatternToExcludeLines(javaFile, lineRanges);
- verifyNoMoreInteractions(patternMatcher);
+ assertThat(javaFile.isIgnoreAllIssues()).isFalse();
+ assertThat(IntStream.rangeClosed(1, 20).noneMatch(javaFile::isIgnoreAllIssuesOnLine)).isTrue();
+ assertThat(IntStream.rangeClosed(21, 34).allMatch(javaFile::isIgnoreAllIssuesOnLine)).isTrue();
}
@Test
@@ -138,11 +126,11 @@ public class IssueExclusionsRegexpScannerTest {
Path filePath = getResource("file-with-double-regexp-twice.txt");
fileMetadata.readMetadata(Files.newInputStream(filePath), UTF_8, filePath.toString(), regexpScanner);
- Set<LineRange> lineRanges = new HashSet<>();
- lineRanges.add(new LineRange(21, 25));
- lineRanges.add(new LineRange(29, 33));
- verify(patternMatcher, times(1)).addPatternToExcludeLines(javaFile, lineRanges);
- verifyNoMoreInteractions(patternMatcher);
+ assertThat(javaFile.isIgnoreAllIssues()).isFalse();
+ assertThat(IntStream.rangeClosed(1, 20).noneMatch(javaFile::isIgnoreAllIssuesOnLine)).isTrue();
+ assertThat(IntStream.rangeClosed(21, 25).allMatch(javaFile::isIgnoreAllIssuesOnLine)).isTrue();
+ assertThat(IntStream.rangeClosed(26, 28).noneMatch(javaFile::isIgnoreAllIssuesOnLine)).isTrue();
+ assertThat(IntStream.rangeClosed(29, 33).allMatch(javaFile::isIgnoreAllIssuesOnLine)).isTrue();
}
@Test
@@ -150,10 +138,8 @@ public class IssueExclusionsRegexpScannerTest {
Path filePath = getResource("file-with-double-regexp-wrong-order.txt");
fileMetadata.readMetadata(Files.newInputStream(filePath), UTF_8, filePath.toString(), regexpScanner);
- Set<LineRange> lineRanges = new HashSet<>();
- lineRanges.add(new LineRange(25, 35));
- verify(patternMatcher, times(1)).addPatternToExcludeLines(javaFile, lineRanges);
- verifyNoMoreInteractions(patternMatcher);
+ assertThat(IntStream.rangeClosed(1, 24).noneMatch(javaFile::isIgnoreAllIssuesOnLine)).isTrue();
+ assertThat(IntStream.rangeClosed(25, 35).allMatch(javaFile::isIgnoreAllIssuesOnLine)).isTrue();
}
@Test
@@ -161,10 +147,9 @@ public class IssueExclusionsRegexpScannerTest {
Path filePath = getResource("file-with-double-regexp-mess.txt");
fileMetadata.readMetadata(Files.newInputStream(filePath), UTF_8, filePath.toString(), regexpScanner);
- Set<LineRange> lineRanges = new HashSet<>();
- lineRanges.add(new LineRange(21, 29));
- verify(patternMatcher, times(1)).addPatternToExcludeLines(javaFile, lineRanges);
- verifyNoMoreInteractions(patternMatcher);
+ assertThat(IntStream.rangeClosed(1, 20).noneMatch(javaFile::isIgnoreAllIssuesOnLine)).isTrue();
+ assertThat(IntStream.rangeClosed(21, 29).allMatch(javaFile::isIgnoreAllIssuesOnLine)).isTrue();
+ assertThat(IntStream.rangeClosed(30, 37).noneMatch(javaFile::isIgnoreAllIssuesOnLine)).isTrue();
}
private Path getResource(String fileName) throws URISyntaxException {
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 e2103e18828..293ef226b5f 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
@@ -328,8 +328,8 @@ public class FileSystemMediumTest {
.execute();
assertThat(logTester.logs()).containsOnlyOnce("'src" + File.separator + "myfile.binary' indexed with language 'null'");
- assertThat(logTester.logs()).doesNotContain("'src/myfile.binary' generating issue exclusions");
- assertThat(logTester.logs()).containsOnlyOnce("'src/sample.xoo' generating issue exclusions");
+ assertThat(logTester.logs()).doesNotContain("Evaluate issue exclusions for 'src/myfile.binary'");
+ assertThat(logTester.logs()).containsOnlyOnce("Evaluate issue exclusions for 'src/sample.xoo'");
}
@Test
@@ -354,8 +354,8 @@ public class FileSystemMediumTest {
.build())
.execute();
- assertThat(logTester.logs()).containsOnlyOnce("- Exclusion pattern 'pattern': every issue in this file will be ignored.");
- assertThat(logTester.logs()).containsOnlyOnce("'src/myfile.binary' generating issue exclusions");
+ assertThat(logTester.logs()).containsSequence("Evaluate issue exclusions for 'src/sample.xoo'",
+ " - Exclusion pattern 'pattern': all issues in this file will be ignored.");
}
@Test
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/issues/IssuesMediumTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/issues/IssuesMediumTest.java
index 5a066cdc700..3fd82bf4afb 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/issues/IssuesMediumTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/issues/IssuesMediumTest.java
@@ -22,16 +22,22 @@ package org.sonar.scanner.mediumtest.issues;
import com.google.common.collect.ImmutableMap;
import java.io.File;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.utils.log.LogTester;
+import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.scanner.mediumtest.ScannerMediumTester;
import org.sonar.scanner.mediumtest.AnalysisResult;
import org.sonar.scanner.protocol.output.ScannerReport.ExternalIssue;
import org.sonar.scanner.protocol.output.ScannerReport.Issue;
+import org.sonar.scanner.rule.LoadedActiveRule;
import org.sonar.xoo.XooPlugin;
+import org.sonar.xoo.rule.HasTagSensor;
import org.sonar.xoo.rule.OneExternalIssuePerLineSensor;
import org.sonar.xoo.rule.XooRulesDefinition;
@@ -44,6 +50,9 @@ public class IssuesMediumTest {
public TemporaryFolder temp = new TemporaryFolder();
@Rule
+ public LogTester logTester = new LogTester();
+
+ @Rule
public ScannerMediumTester tester = new ScannerMediumTester()
.registerPlugin("xoo", new XooPlugin())
.addDefaultQProfile("xoo", "Sonar Way")
@@ -113,7 +122,7 @@ public class IssuesMediumTest {
}
@Test
- public void testIssueExclusion() throws Exception {
+ public void testIssueExclusionByRegexp() throws Exception {
File projectDir = new File("test-resources/mediumtest/xoo/sample");
File tmpDir = temp.newFolder();
FileUtils.copyDirectory(projectDir, tmpDir);
@@ -129,23 +138,249 @@ public class IssuesMediumTest {
}
@Test
- public void testIssueDetails() throws IOException {
+ public void testIssueExclusionByBlock() throws Exception {
+ File baseDir = temp.newFolder();
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ File xooFile = new File(srcDir, "sample.xoo");
+ FileUtils.write(xooFile, "1\nSONAR-OFF 2\n3\n4\n5\nSONAR-ON 6\n7\n8\n9\n10", StandardCharsets.UTF_8);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .build())
+ .property("sonar.issue.ignore.block", "1")
+ .property("sonar.issue.ignore.block.1.beginBlockRegexp", "SON.*-OFF")
+ .property("sonar.issue.ignore.block.1.endBlockRegexp", "SON.*-ON")
+ .execute();
+ List<Issue> issues = result.issuesFor(result.inputFile("src/sample.xoo"));
+ assertThat(issues).hasSize(5);
+ assertThat(issues)
+ .extracting("textRange.startLine")
+ .containsExactlyInAnyOrder(1, 7, 8, 9, 10);
+ }
+
+ @Test
+ public void testIssueExclusionByIgnoreMultiCriteria() throws Exception {
+ File baseDir = temp.newFolder();
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ activateTODORule();
+
+ File xooFile1 = new File(srcDir, "sample1.xoo");
+ FileUtils.write(xooFile1, "1\n2\n3 TODO\n4\n5\n6 TODO\n7\n8\n9\n10", StandardCharsets.UTF_8);
+ File xooFile11 = new File(srcDir, "sample11.xoo");
+ FileUtils.write(xooFile11, "1\n2\n3 TODO\n4\n5\n6 TODO\n7\n8\n9\n10", StandardCharsets.UTF_8);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .build())
+ .property("sonar.issue.ignore.multicriteria", "1,2")
+ .property("sonar.issue.ignore.multicriteria.1.ruleKey", "xoo:HasTag")
+ .property("sonar.issue.ignore.multicriteria.1.resourceKey", "src/sample11.xoo")
+ .property("sonar.issue.ignore.multicriteria.2.ruleKey", "xoo:One*")
+ .property("sonar.issue.ignore.multicriteria.2.resourceKey", "src/sample?.xoo")
+ .execute();
+
+ List<Issue> issues = result.issuesFor(result.inputFile("src/sample1.xoo"));
+ assertThat(issues).hasSize(2);
+
+ issues = result.issuesFor(result.inputFile("src/sample11.xoo"));
+ assertThat(issues).hasSize(10);
+ }
+
+ @Test
+ public void warn_user_for_outdated_IssueExclusionByIgnoreMultiCriteria() throws Exception {
+ 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, "1\n2\n3\n4\n5\n6 TODO\n7\n8\n9\n10", StandardCharsets.UTF_8);
+ File xooFileB = new File(srcDirB, "sampleB.xoo");
+ FileUtils.write(xooFileB, "1\n2\n3\n4\n5\n6 TODO\n7\n8\n9\n10", StandardCharsets.UTF_8);
+
+ tester
+ .addProjectServerSettings("sonar.issue.ignore.multicriteria", "1")
+ .addProjectServerSettings("sonar.issue.ignore.multicriteria.1.ruleKey", "*")
+ .addProjectServerSettings("sonar.issue.ignore.multicriteria.1.resourceKey", "src/sampleA.xoo");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.modules", "moduleA,moduleB")
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ assertThat(logTester.logs(LoggerLevel.WARN)).contains("Specifying module-relative paths at project level in property 'sonar.issue.ignore.multicriteria' is deprecated. To continue matching files like 'moduleA/src/sampleA.xoo', update this property so that patterns refer to project-relative paths.");
+
+ List<Issue> issues = result.issuesFor(result.inputFile("moduleA/src/sampleA.xoo"));
+ assertThat(issues).hasSize(0);
+
+ issues = result.issuesFor(result.inputFile("moduleB/src/sampleB.xoo"));
+ assertThat(issues).hasSize(10);
+ }
+
+ @Test
+ public void warn_user_for_unsupported_module_level_IssueExclusion() throws Exception {
+ 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, "1\n2\n3\n4\n5\n6 TODO\n7\n8\n9\n10", StandardCharsets.UTF_8);
+ File xooFileB = new File(srcDirB, "sampleB.xoo");
+ FileUtils.write(xooFileB, "1\n2\n3\n4\n5\n6 TODO\n7\n8\n9\n10", StandardCharsets.UTF_8);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.modules", "moduleA,moduleB")
+ .put("sonar.sources", "src")
+ .put("sonar.scm.disabled", "true")
+ .put("sonar.issue.ignore.multicriteria", "1")
+ .put("sonar.issue.ignore.multicriteria.1.ruleKey", "*")
+ .put("sonar.issue.ignore.multicriteria.1.resourceKey", "*")
+ .build())
+ .execute();
+
+ assertThat(logTester.logs(LoggerLevel.WARN)).isEmpty();
+
+ result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.modules", "moduleA,moduleB")
+ .put("sonar.sources", "src")
+ .put("sonar.scm.disabled", "true")
+ .put("moduleA.sonar.issue.ignore.multicriteria", "1")
+ .put("moduleA.sonar.issue.ignore.multicriteria.1.ruleKey", "*")
+ .put("moduleA.sonar.issue.ignore.multicriteria.1.resourceKey", "*")
+ .build())
+ .execute();
+
+ assertThat(logTester.logs(LoggerLevel.WARN)).containsOnly("Specifying issue exclusions at module level is not supported anymore. Configure the property 'sonar.issue.ignore.multicriteria' and any other issue exclusions at project level.");
+
+ List<Issue> issues = result.issuesFor(result.inputFile("moduleA/src/sampleA.xoo"));
+ assertThat(issues).hasSize(10);
+
+ issues = result.issuesFor(result.inputFile("moduleB/src/sampleB.xoo"));
+ assertThat(issues).hasSize(10);
+ }
+
+ @Test
+ public void testIssueExclusionByEnforceMultiCriteria() throws Exception {
+ File baseDir = temp.newFolder();
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ activateTODORule();
+
+ File xooFile1 = new File(srcDir, "sample1.xoo");
+ FileUtils.write(xooFile1, "1\n2\n3 TODO\n4\n5\n6 TODO\n7\n8\n9\n10", StandardCharsets.UTF_8);
+ File xooFile11 = new File(srcDir, "sample11.xoo");
+ FileUtils.write(xooFile11, "1\n2\n3 TODO\n4\n5\n6 TODO\n7\n8\n9\n10", StandardCharsets.UTF_8);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .build())
+ .property("sonar.issue.enforce.multicriteria", "1,2")
+ .property("sonar.issue.enforce.multicriteria.1.ruleKey", "xoo:HasTag")
+ .property("sonar.issue.enforce.multicriteria.1.resourceKey", "src/sample11.xoo")
+ .property("sonar.issue.enforce.multicriteria.2.ruleKey", "xoo:One*")
+ .property("sonar.issue.enforce.multicriteria.2.resourceKey", "src/sample?.xoo")
+ .execute();
+
+ List<Issue> issues = result.issuesFor(result.inputFile("src/sample1.xoo"));
+ assertThat(issues).hasSize(10);
+
+ issues = result.issuesFor(result.inputFile("src/sample11.xoo"));
+ assertThat(issues).hasSize(2);
+ }
+
+ @Test
+ public void warn_user_for_outdated_IssueExclusionByEnforceMultiCriteria() throws Exception {
+ 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, "1\n2\n3\n4\n5\n6 TODO\n7\n8\n9\n10", StandardCharsets.UTF_8);
+ File xooFileB = new File(srcDirB, "sampleB.xoo");
+ FileUtils.write(xooFileB, "1\n2\n3\n4\n5\n6 TODO\n7\n8\n9\n10", StandardCharsets.UTF_8);
+
+ tester
+ .addProjectServerSettings("sonar.issue.enforce.multicriteria", "1")
+ .addProjectServerSettings("sonar.issue.enforce.multicriteria.1.ruleKey", "*")
+ .addProjectServerSettings("sonar.issue.enforce.multicriteria.1.resourceKey", "src/sampleA.xoo");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.modules", "moduleA,moduleB")
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ assertThat(logTester.logs(LoggerLevel.WARN)).contains("Specifying module-relative paths at project level in property 'sonar.issue.enforce.multicriteria' is deprecated. To continue matching files like 'moduleA/src/sampleA.xoo', update this property so that patterns refer to project-relative paths.");
+
+ List<Issue> issues = result.issuesFor(result.inputFile("moduleA/src/sampleA.xoo"));
+ assertThat(issues).hasSize(10);
+
+ issues = result.issuesFor(result.inputFile("moduleB/src/sampleB.xoo"));
+ assertThat(issues).hasSize(0);
+ }
+
+ private void activateTODORule() {
+ LoadedActiveRule r = new LoadedActiveRule();
+ r.setRuleKey(RuleKey.of("xoo", HasTagSensor.RULE_KEY));
+ r.setName("TODO");
+ r.setLanguage("xoo");
+ r.setSeverity("MAJOR");
+ r.setParams(ImmutableMap.of("tag", "TODO"));
+ tester.activateRule(r);
+ }
+
+ @Test
+ public void testIssueDetails() throws IOException {
File baseDir = temp.newFolder();
File srcDir = new File(baseDir, "src");
srcDir.mkdir();
File xooFile = new File(srcDir, "sample.xoo");
- FileUtils.write(xooFile, "1\n2\n3\n4\n5\n6\n7\n8\n9\n10");
+ FileUtils.write(xooFile, "1\n2\n3\n4\n5\n6\n7\n8\n9\n10", StandardCharsets.UTF_8);
AnalysisResult result = tester.newAnalysis()
.properties(ImmutableMap.<String, String>builder()
- .put("sonar.task", "scan")
.put("sonar.projectBaseDir", baseDir.getAbsolutePath())
.put("sonar.projectKey", "com.foo.project")
- .put("sonar.projectName", "Foo Project")
- .put("sonar.projectVersion", "1.0-SNAPSHOT")
- .put("sonar.projectDescription", "Description of Foo Project")
.put("sonar.sources", "src")
.build())
.execute();
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ProjectReactorBuilderTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ProjectReactorBuilderTest.java
index 1db1cd92e04..ead72172d9c 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ProjectReactorBuilderTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ProjectReactorBuilderTest.java
@@ -35,11 +35,13 @@ import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.bootstrap.ProjectReactor;
+import org.sonar.api.notifications.AnalysisWarnings;
import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.log.LogTester;
import org.sonar.scanner.bootstrap.ScannerProperties;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
public class ProjectReactorBuilderTest {
@@ -399,7 +401,7 @@ public class ProjectReactorBuilderTest {
@Test
public void shouldInitRootWorkDir() {
- ProjectReactorBuilder builder = new ProjectReactorBuilder(new ScannerProperties(Maps.<String, String>newHashMap()));
+ ProjectReactorBuilder builder = new ProjectReactorBuilder(new ScannerProperties(Maps.<String, String>newHashMap()), mock(AnalysisWarnings.class));
File baseDir = new File("target/tmp/baseDir");
File workDir = builder.initRootProjectWorkDir(baseDir, Maps.<String, String>newHashMap());
@@ -411,7 +413,7 @@ public class ProjectReactorBuilderTest {
public void shouldInitWorkDirWithCustomRelativeFolder() {
Map<String, String> props = Maps.<String, String>newHashMap();
props.put("sonar.working.directory", ".foo");
- ProjectReactorBuilder builder = new ProjectReactorBuilder(new ScannerProperties(props));
+ ProjectReactorBuilder builder = new ProjectReactorBuilder(new ScannerProperties(props), mock(AnalysisWarnings.class));
File baseDir = new File("target/tmp/baseDir");
File workDir = builder.initRootProjectWorkDir(baseDir, props);
@@ -423,7 +425,7 @@ public class ProjectReactorBuilderTest {
public void shouldInitRootWorkDirWithCustomAbsoluteFolder() {
Map<String, String> props = Maps.<String, String>newHashMap();
props.put("sonar.working.directory", new File("src").getAbsolutePath());
- ProjectReactorBuilder builder = new ProjectReactorBuilder(new ScannerProperties(props));
+ ProjectReactorBuilder builder = new ProjectReactorBuilder(new ScannerProperties(props), mock(AnalysisWarnings.class));
File baseDir = new File("target/tmp/baseDir");
File workDir = builder.initRootProjectWorkDir(baseDir, props);
@@ -482,7 +484,7 @@ public class ProjectReactorBuilderTest {
private ProjectDefinition loadProjectDefinition(String projectFolder) {
Map<String, String> props = loadProps(projectFolder);
ScannerProperties bootstrapProps = new ScannerProperties(props);
- ProjectReactor projectReactor = new ProjectReactorBuilder(bootstrapProps).execute();
+ ProjectReactor projectReactor = new ProjectReactorBuilder(bootstrapProps, mock(AnalysisWarnings.class)).execute();
return projectReactor.getRoot();
}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/MetadataGeneratorTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/MetadataGeneratorTest.java
index b46d174783b..cc4b6bf2485 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/MetadataGeneratorTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/MetadataGeneratorTest.java
@@ -35,9 +35,10 @@ import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.FileMetadata;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
+import org.sonar.api.notifications.AnalysisWarnings;
import org.sonar.api.utils.PathUtils;
+import org.sonar.scanner.issue.ignore.IgnoreIssuesFilter;
import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
-import org.sonar.scanner.issue.ignore.pattern.PatternMatcher;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
import static org.apache.commons.codec.digest.DigestUtils.md5Hex;
@@ -61,7 +62,8 @@ public class MetadataGeneratorTest {
public void setUp() throws IOException {
MockitoAnnotations.initMocks(this);
metadata = new FileMetadata();
- IssueExclusionsLoader issueExclusionsLoader = new IssueExclusionsLoader(mock(IssueExclusionPatternInitializer.class), mock(PatternMatcher.class));
+ IssueExclusionsLoader issueExclusionsLoader = new IssueExclusionsLoader(mock(IssueExclusionPatternInitializer.class), mock(IgnoreIssuesFilter.class),
+ mock(AnalysisWarnings.class));
generator = new MetadataGenerator(statusDetection, metadata, issueExclusionsLoader);
}