import java.util.LinkedHashMap;
import java.util.Map;
-import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.rule.RuleKey;
/**
return this;
}
- public ActiveRules build() {
+ public DefaultActiveRules build() {
return new DefaultActiveRules(map.values());
}
}
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
import javax.annotation.concurrent.Immutable;
import org.sonar.api.batch.rule.ActiveRule;
import org.sonar.api.rule.RuleKey;
private final long createdAt;
private final long updatedAt;
private final String qProfileKey;
+ private final Set<RuleKey> deprecatedKeys;
public DefaultActiveRule(NewActiveRule newActiveRule) {
this.severity = newActiveRule.severity;
this.createdAt = newActiveRule.createdAt;
this.updatedAt = newActiveRule.updatedAt;
this.qProfileKey = newActiveRule.qProfileKey;
+ this.deprecatedKeys = Collections.unmodifiableSet(new HashSet<>(newActiveRule.deprecatedKeys));
}
@Override
public String qpKey() {
return qProfileKey;
}
+
+ public Set<RuleKey> getDeprecatedKeys() {
+ // already immutable
+ return deprecatedKeys;
+ }
}
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.concurrent.Immutable;
import org.sonar.api.batch.rule.ActiveRule;
import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.rule.RuleKey;
+import org.sonar.api.utils.WildcardPattern;
+
+import static java.util.Collections.emptySet;
@Immutable
public class DefaultActiveRules implements ActiveRules {
+ private final Map<RuleKey, Set<String>> deprecatedRuleKeysByRuleKey = new LinkedHashMap<>();
private final Map<String, List<ActiveRule>> activeRulesByRepository = new HashMap<>();
private final Map<String, Map<String, ActiveRule>> activeRulesByRepositoryAndKey = new HashMap<>();
private final Map<String, Map<String, ActiveRule>> activeRulesByRepositoryAndInternalKey = new HashMap<>();
if (internalKey != null) {
activeRulesByRepositoryAndInternalKey.computeIfAbsent(repo, r -> new HashMap<>()).put(internalKey, ar);
}
+
+ deprecatedRuleKeysByRuleKey.put(ar.ruleKey(), ar.getDeprecatedKeys().stream().map(RuleKey::toString).collect(Collectors.toSet()));
}
}
+ public Set<String> getDeprecatedRuleKeys(RuleKey ruleKey) {
+ return deprecatedRuleKeysByRuleKey.getOrDefault(ruleKey, emptySet());
+ }
+
+ public boolean matchesDeprecatedKeys(RuleKey ruleKey, WildcardPattern rulePattern) {
+ return getDeprecatedRuleKeys(ruleKey).contains(rulePattern.toString());
+ }
+
@Override
public ActiveRule find(RuleKey ruleKey) {
return activeRulesByRepositoryAndKey.getOrDefault(ruleKey.repository(), Collections.emptyMap())
package org.sonar.api.batch.rule.internal;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import org.apache.commons.lang.StringUtils;
final String language;
final String templateRuleKey;
final String qProfileKey;
+ final Set<RuleKey> deprecatedKeys;
NewActiveRule(Builder builder) {
this.ruleKey = builder.ruleKey;
this.language = builder.language;
this.templateRuleKey = builder.templateRuleKey;
this.qProfileKey = builder.qProfileKey;
+ this.deprecatedKeys = builder.deprecatedKeys;
}
public RuleKey ruleKey() {
private String language;
private String templateRuleKey;
private String qProfileKey;
+ private Set<RuleKey> deprecatedKeys = new HashSet<>();
public Builder setRuleKey(RuleKey ruleKey) {
this.ruleKey = ruleKey;
return this;
}
+ public Builder setDeprecatedKeys(Set<RuleKey> deprecatedKeys) {
+ this.deprecatedKeys = deprecatedKeys;
+ return this;
+ }
+
public NewActiveRule build() {
return new NewActiveRule(this);
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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.api.batch.rule.internal;
+
+import com.google.common.collect.ImmutableSet;
+import java.util.Collections;
+import org.junit.Test;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.utils.WildcardPattern;
+
+import static java.util.Collections.singleton;
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class DefaultActiveRulesTest {
+ private final RuleKey ruleKey = RuleKey.of("repo", "rule");
+
+ @Test
+ public void empty_returns_nothing() {
+ DefaultActiveRules underTest = new DefaultActiveRules(Collections.emptyList());
+
+ assertThat(underTest.getDeprecatedRuleKeys(ruleKey)).isEmpty();
+ assertThat(underTest.matchesDeprecatedKeys(ruleKey, WildcardPattern.create("**"))).isFalse();
+ }
+
+ @Test
+ public void finds_match() {
+ DefaultActiveRules underTest = new DefaultActiveRules(ImmutableSet.of(new NewActiveRule.Builder()
+ .setRuleKey(ruleKey)
+ .setDeprecatedKeys(singleton(RuleKey.of("oldrepo", "oldrule")))
+ .build()));
+
+ assertThat(underTest.getDeprecatedRuleKeys(ruleKey)).containsOnly("oldrepo:oldrule");
+ assertThat(underTest.matchesDeprecatedKeys(ruleKey, WildcardPattern.create("oldrepo:oldrule"))).isTrue();
+ }
+
+ @Test
+ public void finds_match_with_multiple_deprecated_keys() {
+ DefaultActiveRules underTest = new DefaultActiveRules(ImmutableSet.of(new NewActiveRule.Builder()
+ .setRuleKey(ruleKey)
+ .setDeprecatedKeys(ImmutableSet.of(RuleKey.of("oldrepo", "oldrule"), (RuleKey.of("oldrepo2", "oldrule2"))))
+ .build()));
+
+ assertThat(underTest.getDeprecatedRuleKeys(ruleKey)).containsOnly("oldrepo:oldrule", "oldrepo2:oldrule2");
+ assertThat(underTest.matchesDeprecatedKeys(ruleKey, WildcardPattern.create("oldrepo:oldrule"))).isTrue();
+ }
+}
import java.util.ArrayList;
import java.util.Collections;
+import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Set;
import javax.annotation.concurrent.ThreadSafe;
import org.sonar.api.batch.fs.InputComponent;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.rule.internal.DefaultActiveRules;
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.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.api.batch.fs.internal.DefaultInputFile;
import org.sonar.scanner.issue.DefaultFilterableIssue;
import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer;
import org.sonar.scanner.issue.ignore.pattern.IssuePattern;
private final List<IssuePattern> multicriteriaPatterns;
private final AnalysisWarnings analysisWarnings;
+ private final DefaultActiveRules activeRules;
+ private final Set<RuleKey> warnedDeprecatedRuleKeys = new LinkedHashSet<>();
private boolean warnDeprecatedIssuePatternAlreadyLogged;
- public EnforceIssuesFilter(IssueInclusionPatternInitializer patternInitializer, AnalysisWarnings analysisWarnings) {
+ public EnforceIssuesFilter(IssueInclusionPatternInitializer patternInitializer, AnalysisWarnings analysisWarnings, DefaultActiveRules activeRules) {
this.multicriteriaPatterns = Collections.unmodifiableList(new ArrayList<>(patternInitializer.getMulticriteriaPatterns()));
this.analysisWarnings = analysisWarnings;
+ this.activeRules = activeRules;
}
@Override
IssuePattern matchingPattern = null;
for (IssuePattern pattern : multicriteriaPatterns) {
- if (pattern.matchRule(issue.ruleKey())) {
+ if (ruleMatches(pattern, issue.ruleKey())) {
atLeastOneRuleMatched = true;
InputComponent component = ((DefaultFilterableIssue) issue).getComponent();
if (component.isFile()) {
if (atLeastOneRuleMatched) {
if (atLeastOnePatternFullyMatched) {
- LOG.debug("Issue {} enforced by pattern {}", issue, matchingPattern);
+ LOG.debug("Issue '{}' enforced by pattern '{}'", issue, matchingPattern);
}
return atLeastOnePatternFullyMatched;
} else {
}
}
+ private boolean ruleMatches(IssuePattern pattern, RuleKey ruleKey) {
+ if (activeRules.matchesDeprecatedKeys(ruleKey, pattern.getRulePattern())) {
+ String msg = String.format("The issue multicriteria pattern '%s' matches a rule key that has been changed. The pattern should be updated to '%s'",
+ pattern.getRulePattern(), ruleKey);
+ analysisWarnings.addUnique(msg);
+ if (warnedDeprecatedRuleKeys.add(ruleKey)) {
+ LOG.warn(msg);
+ }
+ return true;
+ }
+ return pattern.matchRule(ruleKey);
+ }
+
private void warnOnceDeprecatedIssuePattern(String msg) {
if (!warnDeprecatedIssuePatternAlreadyLogged) {
LOG.warn(msg);
import java.util.Collections;
import java.util.HashMap;
+import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.rule.internal.DefaultActiveRules;
+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.IssueFilter;
import org.sonar.api.scan.issue.filter.IssueFilterChain;
public class IgnoreIssuesFilter implements IssueFilter {
- private Map<InputComponent, List<WildcardPattern>> rulePatternByComponent = new HashMap<>();
-
+ private final DefaultActiveRules activeRules;
+ private final AnalysisWarnings analysisWarnings;
+ private final Map<InputComponent, List<WildcardPattern>> rulePatternByComponent = new HashMap<>();
+ private final Set<RuleKey> warnedDeprecatedRuleKeys = new LinkedHashSet<>();
private static final Logger LOG = Loggers.get(IgnoreIssuesFilter.class);
+ public IgnoreIssuesFilter(DefaultActiveRules activeRules, AnalysisWarnings analysisWarnings) {
+ this.activeRules = activeRules;
+ this.analysisWarnings = analysisWarnings;
+ }
+
@Override
public boolean accept(FilterableIssue issue, IssueFilterChain chain) {
InputComponent component = ((DefaultFilterableIssue) issue).getComponent();
private boolean hasRuleMatchFor(InputComponent component, FilterableIssue issue) {
for (WildcardPattern pattern : rulePatternByComponent.getOrDefault(component, Collections.emptyList())) {
if (pattern.match(issue.ruleKey().toString())) {
- LOG.debug("Issue {} ignored by exclusion pattern {}", issue, pattern);
+ LOG.debug("Issue '{}' ignored by exclusion pattern '{}'", issue, pattern);
+ return true;
+ }
+
+ RuleKey ruleKey = issue.ruleKey();
+ if (activeRules.matchesDeprecatedKeys(ruleKey, pattern)) {
+ String msg = String.format("The issue multicriteria pattern '%s' matches a rule key that has been changed. The pattern should be updated to '%s'", pattern, ruleKey);
+ analysisWarnings.addUnique(msg);
+ if (warnedDeprecatedRuleKeys.add(ruleKey)) {
+ LOG.warn(msg);
+ }
+ LOG.debug("Issue '{}' ignored by exclusion pattern '{}' matching a deprecated rule key", issue, pattern);
return true;
}
}
import org.sonar.api.utils.MessageException;
public abstract class AbstractPatternInitializer {
- private Configuration settings;
+ private final Configuration settings;
private List<IssuePattern> multicriteriaPatterns;
protected AbstractPatternInitializer(Configuration config) {
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(filePathPattern != null ? filePathPattern : "*", ruleKeyPattern != null ? ruleKeyPattern : "*");
+ IssuePattern pattern = new IssuePattern(filePathPattern, ruleKeyPattern);
multicriteriaPatterns.add(pattern);
}
*/
package org.sonar.scanner.issue.ignore.pattern;
+import com.google.common.base.MoreObjects;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import org.sonar.api.rule.RuleKey;
return filePath != null && filePattern.match(filePath);
}
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("filePattern", filePattern)
+ .add("rulePattern", rulePattern)
+ .toString();
+ }
+
}
import java.util.Map;
import java.util.Set;
import org.picocontainer.injectors.ProviderAdapter;
-import org.sonar.api.batch.rule.ActiveRules;
-import org.sonar.api.batch.rule.internal.ActiveRulesBuilder;
import org.sonar.api.batch.rule.LoadedActiveRule;
+import org.sonar.api.batch.rule.internal.ActiveRulesBuilder;
+import org.sonar.api.batch.rule.internal.DefaultActiveRules;
import org.sonar.api.batch.rule.internal.NewActiveRule;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.log.Logger;
public class ActiveRulesProvider extends ProviderAdapter {
private static final Logger LOG = Loggers.get(ActiveRulesProvider.class);
private static final String LOG_MSG = "Load active rules";
- private ActiveRules singleton = null;
+ private DefaultActiveRules singleton = null;
- public ActiveRules provide(ActiveRulesLoader loader, QualityProfiles qProfiles) {
+ public DefaultActiveRules provide(ActiveRulesLoader loader, QualityProfiles qProfiles) {
if (singleton == null) {
Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
singleton = load(loader, qProfiles);
return singleton;
}
- private static ActiveRules load(ActiveRulesLoader loader, QualityProfiles qProfiles) {
+ private static DefaultActiveRules load(ActiveRulesLoader loader, QualityProfiles qProfiles) {
Collection<String> qProfileKeys = getKeys(qProfiles);
Set<RuleKey> loadedRulesKey = new HashSet<>();
for (LoadedActiveRule r : qProfileRules) {
if (!loadedRulesKey.contains(r.getRuleKey())) {
loadedRulesKey.add(r.getRuleKey());
- builder.addRule(transform(r, qProfileKey));
+ builder.addRule(transform(r, qProfileKey, r.getDeprecatedKeys()));
}
}
}
return builder.build();
}
- private static NewActiveRule transform(LoadedActiveRule activeRule, String qProfileKey) {
+ private static NewActiveRule transform(LoadedActiveRule activeRule, String qProfileKey, Set<RuleKey> deprecatedKeys) {
NewActiveRule.Builder builder = new NewActiveRule.Builder();
builder
.setRuleKey(activeRule.getRuleKey())
.setLanguage(activeRule.getLanguage())
.setInternalKey(activeRule.getInternalKey())
.setTemplateRuleKey(activeRule.getTemplateRuleKey())
- .setQProfileKey(qProfileKey);
+ .setQProfileKey(qProfileKey)
+ .setDeprecatedKeys(deprecatedKeys);
// load parameters
if (activeRule.getParams() != null) {
for (Map.Entry<String, String> params : activeRule.getParams().entrySet()) {
package org.sonar.scanner.issue.ignore;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
import java.io.IOException;
import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
+import org.sonar.api.batch.rule.internal.DefaultActiveRules;
+import org.sonar.api.batch.rule.internal.NewActiveRule;
import org.sonar.api.notifications.AnalysisWarnings;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.scan.issue.filter.IssueFilterChain;
import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer;
import org.sonar.scanner.issue.ignore.pattern.IssuePattern;
+import static java.util.Collections.singleton;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
public class EnforceIssuesFilterTest {
@Rule
public TemporaryFolder tempFolder = new TemporaryFolder();
- private IssueInclusionPatternInitializer exclusionPatternInitializer;
+ private final IssueInclusionPatternInitializer exclusionPatternInitializer = mock(IssueInclusionPatternInitializer.class);
+ private final DefaultFilterableIssue issue = mock(DefaultFilterableIssue.class);
+ private final IssueFilterChain chain = mock(IssueFilterChain.class);
+ private final AnalysisWarnings analysisWarnings = mock(AnalysisWarnings.class);
private EnforceIssuesFilter ignoreFilter;
- private DefaultFilterableIssue issue;
- private IssueFilterChain chain;
@Before
public void init() {
- exclusionPatternInitializer = mock(IssueInclusionPatternInitializer.class);
- issue = mock(DefaultFilterableIssue.class);
- chain = mock(IssueFilterChain.class);
when(chain.accept(issue)).thenReturn(true);
}
@Test
public void shouldPassToChainIfNoConfiguredPatterns() {
- ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, mock(AnalysisWarnings.class));
+ DefaultActiveRules activeRules = new DefaultActiveRules(ImmutableSet.of());
+ ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, analysisWarnings, activeRules);
assertThat(ignoreFilter.accept(issue, chain)).isTrue();
verify(chain).accept(issue);
}
@Test
public void shouldPassToChainIfRuleDoesNotMatch() {
- String rule = "rule";
- RuleKey ruleKey = mock(RuleKey.class);
- when(ruleKey.toString()).thenReturn(rule);
+ DefaultActiveRules activeRules = new DefaultActiveRules(ImmutableSet.of());
+ RuleKey ruleKey = RuleKey.of("repo", "rule");
when(issue.ruleKey()).thenReturn(ruleKey);
- IssuePattern matching = mock(IssuePattern.class);
- when(matching.matchRule(ruleKey)).thenReturn(false);
+ IssuePattern matching = new IssuePattern("**", "unknown");
when(exclusionPatternInitializer.getMulticriteriaPatterns()).thenReturn(ImmutableList.of(matching));
- ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, mock(AnalysisWarnings.class));
+ ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, analysisWarnings, activeRules);
assertThat(ignoreFilter.accept(issue, chain)).isTrue();
verify(chain).accept(issue);
}
@Test
public void shouldAcceptIssueIfFullyMatched() {
- String rule = "rule";
+ DefaultActiveRules activeRules = new DefaultActiveRules(ImmutableSet.of());
String path = "org/sonar/api/Issue.java";
- RuleKey ruleKey = mock(RuleKey.class);
- when(ruleKey.toString()).thenReturn(rule);
+ RuleKey ruleKey = RuleKey.of("repo", "rule");
when(issue.ruleKey()).thenReturn(ruleKey);
- IssuePattern matching = mock(IssuePattern.class);
- when(matching.matchRule(ruleKey)).thenReturn(true);
- when(matching.matchFile(path)).thenReturn(true);
+ IssuePattern matching = new IssuePattern(path, ruleKey.toString());
when(exclusionPatternInitializer.getMulticriteriaPatterns()).thenReturn(ImmutableList.of(matching));
when(issue.getComponent()).thenReturn(createComponentWithPath(path));
- ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, mock(AnalysisWarnings.class));
+ ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, analysisWarnings, activeRules);
assertThat(ignoreFilter.accept(issue, chain)).isTrue();
- verifyZeroInteractions(chain);
+ verifyNoInteractions(chain);
+ }
+
+ @Test
+ public void shouldAcceptIssueIfMatchesDeprecatedRuleKey() {
+ RuleKey ruleKey = RuleKey.of("repo", "rule");
+ DefaultActiveRules activeRules = new DefaultActiveRules(ImmutableSet.of(new NewActiveRule.Builder()
+ .setRuleKey(ruleKey)
+ .setDeprecatedKeys(singleton(RuleKey.of("repo2", "deprecated")))
+ .build()));
+ String path = "org/sonar/api/Issue.java";
+ when(issue.ruleKey()).thenReturn(ruleKey);
+
+ IssuePattern matching = new IssuePattern("org/**", "repo2:deprecated");
+ when(exclusionPatternInitializer.getMulticriteriaPatterns()).thenReturn(ImmutableList.of(matching));
+ when(issue.getComponent()).thenReturn(createComponentWithPath(path));
+
+ ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, analysisWarnings, activeRules);
+ assertThat(ignoreFilter.accept(issue, chain)).isTrue();
+ verify(analysisWarnings)
+ .addUnique("The issue multicriteria pattern 'repo2:deprecated' matches a rule key that has been changed. The pattern should be updated to 'repo:rule'");
+ verifyNoInteractions(chain);
}
private InputComponent createComponentWithPath(String path) {
@Test
public void shouldRefuseIssueIfRuleMatchesButNotPath() {
- String rule = "rule";
+ DefaultActiveRules activeRules = new DefaultActiveRules(ImmutableSet.of());
String path = "org/sonar/api/Issue.java";
String componentKey = "org.sonar.api.Issue";
- RuleKey ruleKey = mock(RuleKey.class);
- when(ruleKey.toString()).thenReturn(rule);
+ RuleKey ruleKey = RuleKey.of("repo", "rule");
when(issue.ruleKey()).thenReturn(ruleKey);
when(issue.componentKey()).thenReturn(componentKey);
- IssuePattern matching = mock(IssuePattern.class);
- when(matching.matchRule(ruleKey)).thenReturn(true);
- when(matching.matchFile(path)).thenReturn(false);
+ IssuePattern matching = new IssuePattern("no match", "repo:rule");
when(exclusionPatternInitializer.getMulticriteriaPatterns()).thenReturn(ImmutableList.of(matching));
when(issue.getComponent()).thenReturn(createComponentWithPath(path));
- ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, mock(AnalysisWarnings.class));
+ ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, analysisWarnings, activeRules);
assertThat(ignoreFilter.accept(issue, chain)).isFalse();
- verifyZeroInteractions(chain);
+ verifyNoInteractions(chain, analysisWarnings);
}
@Test
public void shouldRefuseIssueIfRuleMatchesAndNotFile() throws IOException {
- String rule = "rule";
+ DefaultActiveRules activeRules = new DefaultActiveRules(ImmutableSet.of());
String path = "org/sonar/api/Issue.java";
- String componentKey = "org.sonar.api.Issue";
- RuleKey ruleKey = mock(RuleKey.class);
- when(ruleKey.toString()).thenReturn(rule);
+ RuleKey ruleKey = RuleKey.of("repo", "key");
when(issue.ruleKey()).thenReturn(ruleKey);
- IssuePattern matching = mock(IssuePattern.class);
- when(matching.matchRule(ruleKey)).thenReturn(true);
- when(matching.matchFile(path)).thenReturn(true);
+ IssuePattern matching = new IssuePattern(path, ruleKey.toString());
when(exclusionPatternInitializer.getMulticriteriaPatterns()).thenReturn(ImmutableList.of(matching));
when(issue.getComponent()).thenReturn(TestInputFileBuilder.newDefaultInputProject("foo", tempFolder.newFolder()));
- ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, mock(AnalysisWarnings.class));
+ ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, analysisWarnings, activeRules);
assertThat(ignoreFilter.accept(issue, chain)).isFalse();
- verifyZeroInteractions(chain);
+ verifyNoInteractions(chain, analysisWarnings);
}
}
*/
package org.sonar.scanner.issue.ignore;
+import com.google.common.collect.ImmutableSet;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.rule.internal.DefaultActiveRules;
+import org.sonar.api.batch.rule.internal.NewActiveRule;
+import org.sonar.api.notifications.AnalysisWarnings;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.scan.issue.filter.IssueFilterChain;
import org.sonar.api.utils.WildcardPattern;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.utils.log.LogTester;
import org.sonar.scanner.issue.DefaultFilterableIssue;
+import static java.util.Collections.singleton;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
public class IgnoreIssuesFilterTest {
+ @Rule
+ public LogTester logTester = new LogTester();
+
+ private final DefaultFilterableIssue issue = mock(DefaultFilterableIssue.class);
+ private final IssueFilterChain chain = mock(IssueFilterChain.class);
+ private final AnalysisWarnings analysisWarnings = mock(AnalysisWarnings.class);
+ private final RuleKey ruleKey = RuleKey.of("foo", "bar");
- private DefaultFilterableIssue issue = mock(DefaultFilterableIssue.class);
- private IssueFilterChain chain = mock(IssueFilterChain.class);
- private IgnoreIssuesFilter underTest = new IgnoreIssuesFilter();
private DefaultInputFile component;
- private RuleKey ruleKey = RuleKey.of("foo", "bar");
@Before
public void prepare() {
@Test
public void shouldPassToChainIfMatcherHasNoPatternForIssue() {
+ DefaultActiveRules activeRules = new DefaultActiveRules(ImmutableSet.of());
+ IgnoreIssuesFilter underTest = new IgnoreIssuesFilter(activeRules, analysisWarnings);
+
when(chain.accept(issue)).thenReturn(true);
assertThat(underTest.accept(issue, chain)).isTrue();
verify(chain).accept(any());
@Test
public void shouldRejectIfRulePatternMatches() {
+ DefaultActiveRules activeRules = new DefaultActiveRules(ImmutableSet.of());
+ IgnoreIssuesFilter underTest = new IgnoreIssuesFilter(activeRules, analysisWarnings);
+
WildcardPattern pattern = mock(WildcardPattern.class);
when(pattern.match(ruleKey.toString())).thenReturn(true);
underTest.addRuleExclusionPatternForComponent(component, pattern);
assertThat(underTest.accept(issue, chain)).isFalse();
+ verifyNoInteractions(analysisWarnings);
+ }
+
+ @Test
+ public void shouldRejectIfRulePatternMatchesDeprecatedRule() {
+ DefaultActiveRules activeRules = new DefaultActiveRules(ImmutableSet.of(new NewActiveRule.Builder()
+ .setRuleKey(ruleKey)
+ .setDeprecatedKeys(singleton(RuleKey.of("repo", "rule")))
+ .build()));
+ IgnoreIssuesFilter underTest = new IgnoreIssuesFilter(activeRules, analysisWarnings);
+
+ WildcardPattern pattern = WildcardPattern.create("repo:rule");
+ underTest.addRuleExclusionPatternForComponent(component, pattern);
+ assertThat(underTest.accept(issue, chain)).isFalse();
+
+ verify(analysisWarnings).addUnique("The issue multicriteria pattern 'repo:rule' matches a rule key that has been changed. The pattern should be updated to 'foo:bar'");
+ assertThat(logTester.logs())
+ .contains("The issue multicriteria pattern 'repo:rule' matches a rule key that has been changed. The pattern should be updated to 'foo:bar'");
}
@Test
public void shouldAcceptIfRulePatternDoesNotMatch() {
+ DefaultActiveRules activeRules = new DefaultActiveRules(ImmutableSet.of());
+ IgnoreIssuesFilter underTest = new IgnoreIssuesFilter(activeRules, analysisWarnings);
+
WildcardPattern pattern = mock(WildcardPattern.class);
when(pattern.match(ruleKey.toString())).thenReturn(false);
underTest.addRuleExclusionPatternForComponent(component, pattern);
assertThat(new IssuePattern("*", "*:Foo*IllegalRegexp").matchRule(rule)).isFalse();
}
+ @Test
+ public void toString_should_include_all_fields() {
+ assertThat(new IssuePattern("*", "*:Foo*IllegalRegexp").toString()).isEqualTo("IssuePattern{filePattern=*, rulePattern=*:Foo*IllegalRegexp}");
+ }
+
}
import org.sonarqube.ws.Qualityprofiles.SearchWsResponse.QualityProfile;
import org.sonarqube.ws.Rules.ListResponse.Rule;
+import static java.util.Collections.emptySet;
+
/**
* Main utility class for writing scanner medium tests.
*/
r.setTemplateRuleKey(templateRuleKey);
r.setLanguage(language);
r.setSeverity(severity);
+ r.setDeprecatedKeys(emptySet());
activeRules.addActiveRule(r);
return this;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.rule.LoadedActiveRule;
import org.sonar.api.rule.RuleKey;
-import org.sonar.scanner.mediumtest.ScannerMediumTester;
import org.sonar.scanner.mediumtest.AnalysisResult;
+import org.sonar.scanner.mediumtest.ScannerMediumTester;
import org.sonar.scanner.protocol.output.ScannerReport.Issue;
-import org.sonar.api.batch.rule.LoadedActiveRule;
import org.sonar.xoo.XooPlugin;
import org.sonar.xoo.rule.XooRulesDefinition;
+import static java.util.Collections.emptySet;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
r.setTemplateRuleKey(templateRuleKey);
r.setLanguage(languag);
r.setSeverity(severity);
+ r.setDeprecatedKeys(emptySet());
Map<String, String> params = new HashMap<>();
params.put(paramKey, paramValue);
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.rule.LoadedActiveRule;
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.mediumtest.ScannerMediumTester;
import org.sonar.scanner.protocol.output.ScannerReport.ExternalIssue;
import org.sonar.scanner.protocol.output.ScannerReport.Issue;
-import org.sonar.api.batch.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;
+import static java.util.Collections.emptySet;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
r.setName("TODO");
r.setLanguage("xoo");
r.setSeverity("MAJOR");
+ r.setDeprecatedKeys(emptySet()
+ );
r.setParams(ImmutableMap.of("tag", "TODO"));
tester.activateRule(r);
}
import java.util.LinkedList;
import java.util.List;
import org.assertj.core.groups.Tuple;
-import org.junit.Before;
import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.batch.rule.LoadedActiveRule;
+import org.sonar.api.batch.rule.internal.DefaultActiveRules;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.DateUtils;
import org.sonarqube.ws.Qualityprofiles.SearchWsResponse.QualityProfile;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
public class ActiveRulesProviderTest {
- private ActiveRulesProvider provider;
-
- @Mock
- private DefaultActiveRulesLoader loader;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- provider = new ActiveRulesProvider();
- }
+ private final ActiveRulesProvider provider = new ActiveRulesProvider();
+ private final DefaultActiveRulesLoader loader = mock(DefaultActiveRulesLoader.class);
@Test
public void testCombinationOfRules() {
when(loader.load(eq("qp3"))).thenReturn(qp3Rules);
QualityProfiles profiles = mockProfiles("qp1", "qp2", "qp3");
- ActiveRules activeRules = provider.provide(loader, profiles);
+ DefaultActiveRules activeRules = provider.provide(loader, profiles);
assertThat(activeRules.findAll()).hasSize(3);
assertThat(activeRules.findAll()).extracting("ruleKey").containsOnly(
verify(loader).load(eq("qp1"));
verify(loader).load(eq("qp2"));
verify(loader).load(eq("qp3"));
+
+ assertThat(activeRules.getDeprecatedRuleKeys(RuleKey.of("rule1", "rule1"))).containsOnly("rule1old:rule1old");
verifyNoMoreInteractions(loader);
}