aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-scanner-engine/src/main/java/org/sonar/scanner
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/main/java/org/sonar/scanner
parent4db8bd9ecf0584443a2e5a9c369970e6ee85f48f (diff)
downloadsonarqube-bbff7949d06677e808d7c6f2cf4fd7cfc1f1a079.tar.gz
sonarqube-bbff7949d06677e808d7c6f2cf4fd7cfc1f1a079.zip
SONAR-11587 Rework issue exclusions
Diffstat (limited to 'sonar-scanner-engine/src/main/java/org/sonar/scanner')
-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
17 files changed, 194 insertions, 345 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);