aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Brandhof <simon.brandhof@gmail.com>2013-05-28 14:08:36 +0200
committerSimon Brandhof <simon.brandhof@gmail.com>2013-05-28 14:08:44 +0200
commit0eddfffce1b680964cc0917cc0bdc5d505a7a167 (patch)
tree479dd529846ebd49699f559349cc2e77e3db74aa
parent4c203b53eefd8fdef5d114f1720fbfaf5b84fb1d (diff)
downloadsonarqube-0eddfffce1b680964cc0917cc0bdc5d505a7a167.tar.gz
sonarqube-0eddfffce1b680964cc0917cc0bdc5d505a7a167.zip
SONAR-4316 implement IssueFilter and support ViolationFilter
-rw-r--r--plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java1
-rw-r--r--plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/CountOpenIssuesDecorator.java2
-rw-r--r--plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTracking.java2
-rw-r--r--plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTrackingDecorator.java19
-rw-r--r--plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/IssueTrackingDecoratorTest.java10
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/ViolationFilters.java8
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/Bucket.java10
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java73
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/ResourceCache.java48
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/issue/DeprecatedViolations.java63
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/issue/IssueFilters.java (renamed from plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueFilters.java)24
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/issue/ScanIssues.java41
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java6
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java1
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/index/BucketTest.java15
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java69
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/index/ResourceCacheTest.java68
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/index/SnapshotCacheTest.java3
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/issue/DeprecatedViolationsTest.java88
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/issue/IssueFiltersTest.java (renamed from plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/IssueFiltersTest.java)37
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/issue/ScanIssuesTest.java67
-rw-r--r--sonar-core/src/main/java/org/sonar/core/issue/DefaultIssue.java2
-rw-r--r--sonar-core/src/main/java/org/sonar/core/issue/db/IssueDto.java4
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/database/model/Snapshot.java3
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/resources/Resource.java4
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/rules/Violation.java2
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/rules/ViolationFilter.java2
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/violations/ViolationQuery.java2
28 files changed, 449 insertions, 225 deletions
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java
index 741f1176f1a..8421f36b4b8 100644
--- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java
+++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java
@@ -389,7 +389,6 @@ public final class CorePlugin extends SonarPlugin {
IssueTrackingDecorator.class,
IssueTracking.class,
IssueHandlers.class,
- IssueFilters.class,
CountOpenIssuesDecorator.class,
CountFalsePositivesDecorator.class,
WeightedIssuesDecorator.class,
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/CountOpenIssuesDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/CountOpenIssuesDecorator.java
index 62251e4ef13..9c0b9725d32 100644
--- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/CountOpenIssuesDecorator.java
+++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/CountOpenIssuesDecorator.java
@@ -274,7 +274,7 @@ public class CountOpenIssuesDecorator implements Decorator {
}
private boolean isAfter(Issue issue, @Nullable Date date) {
- return date == null || issue.creationDate() != null && issue.creationDate().after(date);
+ return date == null || (issue.creationDate() != null && issue.creationDate().after(date));
}
private boolean shouldSaveNewMetrics(DecoratorContext context) {
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTracking.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTracking.java
index a95d9713606..ed33a132279 100644
--- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTracking.java
+++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTracking.java
@@ -295,7 +295,7 @@ public class IssueTracking implements BatchExtension {
}
private boolean isSameChecksum(DefaultIssue newIssue, IssueDto pastIssue) {
- return Objects.equal(pastIssue.getChecksum(), newIssue.getChecksum());
+ return Objects.equal(pastIssue.getChecksum(), newIssue.checksum());
}
private boolean isSameLine(DefaultIssue newIssue, IssueDto pastIssue) {
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTrackingDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTrackingDecorator.java
index 8e071fba49e..3e7be468505 100644
--- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTrackingDecorator.java
+++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTrackingDecorator.java
@@ -31,8 +31,6 @@ import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
import org.sonar.api.resources.ResourceUtils;
import org.sonar.api.rules.ActiveRule;
-import org.sonar.api.rules.Rule;
-import org.sonar.api.rules.RuleFinder;
import org.sonar.api.utils.KeyValueFormat;
import org.sonar.batch.issue.IssueCache;
import org.sonar.core.issue.DefaultIssue;
@@ -42,16 +40,14 @@ import org.sonar.core.issue.db.IssueDto;
import org.sonar.core.issue.workflow.IssueWorkflow;
import java.util.Collection;
-import java.util.Map;
@DependsUpon({DecoratorBarriers.END_OF_VIOLATIONS_GENERATION, DecoratorBarriers.START_VIOLATION_TRACKING})
-@DependedUpon({DecoratorBarriers.END_OF_VIOLATION_TRACKING,DecoratorBarriers.END_OF_ISSUES_UPDATES})
+@DependedUpon({DecoratorBarriers.END_OF_VIOLATION_TRACKING, DecoratorBarriers.END_OF_ISSUES_UPDATES})
public class IssueTrackingDecorator implements Decorator {
private final IssueCache issueCache;
private final InitialOpenIssuesStack initialOpenIssues;
private final IssueTracking tracking;
- private final IssueFilters filters;
private final IssueHandlers handlers;
private final IssueWorkflow workflow;
private final IssueUpdater updater;
@@ -60,14 +56,13 @@ public class IssueTrackingDecorator implements Decorator {
private final RulesProfile rulesProfile;
public IssueTrackingDecorator(IssueCache issueCache, InitialOpenIssuesStack initialOpenIssues, IssueTracking tracking,
- IssueFilters filters, IssueHandlers handlers, IssueWorkflow workflow,
+ IssueHandlers handlers, IssueWorkflow workflow,
IssueUpdater updater,
Project project, ResourcePerspectives perspectives,
RulesProfile rulesProfile) {
this.issueCache = issueCache;
this.initialOpenIssues = initialOpenIssues;
this.tracking = tracking;
- this.filters = filters;
this.handlers = handlers;
this.workflow = workflow;
this.updater = updater;
@@ -93,9 +88,7 @@ public class IssueTrackingDecorator implements Decorator {
Collection<DefaultIssue> issues = Lists.newArrayList();
for (Issue issue : issueCache.byComponent(resource.getEffectiveKey())) {
issueCache.remove(issue);
- if (filters.accept(issue)) {
- issues.add((DefaultIssue) issue);
- }
+ issues.add((DefaultIssue) issue);
}
// issues = all the issues created by rule engines during this module scan and not excluded by filters
@@ -143,7 +136,7 @@ public class IssueTrackingDecorator implements Decorator {
issue.setAssignee(ref.getAssignee());
issue.setAuthorLogin(ref.getAuthorLogin());
if (ref.getIssueAttributes() != null) {
- issue.setAttributes(KeyValueFormat.parse(ref.getIssueAttributes()));
+ issue.setAttributes(KeyValueFormat.parse(ref.getIssueAttributes()));
}
// fields to update with current values
@@ -168,7 +161,7 @@ public class IssueTrackingDecorator implements Decorator {
ActiveRule activeRule = rulesProfile.getActiveRule(unmatchedDto.getRuleRepo(), unmatchedDto.getRule());
boolean manualIssue = !Strings.isNullOrEmpty(unmatched.reporter());
- boolean onDisabledRule = (activeRule==null);
+ boolean onDisabledRule = (activeRule == null);
unmatched.setNew(false);
unmatched.setEndOfLife(!manualIssue);
@@ -183,7 +176,7 @@ public class IssueTrackingDecorator implements Decorator {
ActiveRule activeRule = rulesProfile.getActiveRule(deadDto.getRuleRepo(), deadDto.getRule());
dead.setNew(false);
dead.setEndOfLife(true);
- dead.setOnDisabledRule(activeRule==null);
+ dead.setOnDisabledRule(activeRule == null);
issues.add(dead);
}
}
diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/IssueTrackingDecoratorTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/IssueTrackingDecoratorTest.java
index bc062f6a0ce..79178d74f49 100644
--- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/IssueTrackingDecoratorTest.java
+++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/IssueTrackingDecoratorTest.java
@@ -28,7 +28,6 @@ import org.sonar.api.profiles.RulesProfile;
import org.sonar.api.resources.File;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
-import org.sonar.api.rules.RuleFinder;
import org.sonar.batch.issue.IssueCache;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.IssueChangeContext;
@@ -49,7 +48,6 @@ public class IssueTrackingDecoratorTest extends AbstractDaoTestCase {
IssueCache issueCache = mock(IssueCache.class);
InitialOpenIssuesStack initialOpenIssues = mock(InitialOpenIssuesStack.class);
IssueTracking tracking = mock(IssueTracking.class, RETURNS_MOCKS);
- IssueFilters filters = mock(IssueFilters.class);
IssueHandlers handlers = mock(IssueHandlers.class);
IssueWorkflow workflow = mock(IssueWorkflow.class);
IssueUpdater updater = mock(IssueUpdater.class);
@@ -64,7 +62,7 @@ public class IssueTrackingDecoratorTest extends AbstractDaoTestCase {
issueCache,
initialOpenIssues,
tracking,
- filters, handlers,
+ handlers,
workflow,
updater,
mock(Project.class),
@@ -90,7 +88,7 @@ public class IssueTrackingDecoratorTest extends AbstractDaoTestCase {
public void should_not_be_executed_on_classes_not_methods() throws Exception {
DecoratorContext context = mock(DecoratorContext.class);
decorator.decorate(JavaClass.create("org.foo.Bar"), context);
- verifyZeroInteractions(context, issueCache, tracking, filters, handlers, workflow);
+ verifyZeroInteractions(context, issueCache, tracking, handlers, workflow);
}
@Test
@@ -100,14 +98,12 @@ public class IssueTrackingDecoratorTest extends AbstractDaoTestCase {
// INPUT : one issue, no open issues during previous scan, no filtering
when(issueCache.byComponent("struts:Action.java")).thenReturn(Arrays.asList(issue));
- when(filters.accept(issue)).thenReturn(true);
List<IssueDto> dbIssues = Collections.emptyList();
when(initialOpenIssues.selectAndRemove(123)).thenReturn(dbIssues);
decorator.doDecorate(file);
// Apply filters, track, apply transitions, notify extensions then update cache
- verify(filters).accept(issue);
verify(tracking).track(eq(file), eq(dbIssues), argThat(new ArgumentMatcher<Collection<DefaultIssue>>() {
@Override
public boolean matches(Object o) {
@@ -128,7 +124,6 @@ public class IssueTrackingDecoratorTest extends AbstractDaoTestCase {
// INPUT : one issue, one open issue during previous scan, no filtering
when(issueCache.byComponent("struts:Action.java")).thenReturn(Arrays.asList(openIssue));
- when(filters.accept(openIssue)).thenReturn(true);
IssueDto unmatchedIssue = new IssueDto().setKee("ABCDE").setResolution("OPEN").setStatus("OPEN").setRuleKey_unit_test_only("squid", "AvoidCycle");
IssueTrackingResult trackingResult = new IssueTrackingResult();
@@ -156,7 +151,6 @@ public class IssueTrackingDecoratorTest extends AbstractDaoTestCase {
Project project = new Project("struts");
DefaultIssue openIssue = new DefaultIssue();
when(issueCache.byComponent("struts")).thenReturn(Arrays.asList(openIssue));
- when(filters.accept(openIssue)).thenReturn(true);
IssueDto deadIssue = new IssueDto().setKee("ABCDE").setResolution("OPEN").setStatus("OPEN").setRuleKey_unit_test_only("squid", "AvoidCycle");
when(initialOpenIssues.getAllIssues()).thenReturn(Arrays.asList(deadIssue));
diff --git a/sonar-batch/src/main/java/org/sonar/batch/ViolationFilters.java b/sonar-batch/src/main/java/org/sonar/batch/ViolationFilters.java
index d6edcfc5092..3df35ee05b6 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/ViolationFilters.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/ViolationFilters.java
@@ -31,15 +31,15 @@ public class ViolationFilters {
private ViolationFilter[] filters;
public ViolationFilters(ViolationFilter[] filters) {
- this.filters = (filters==null ? new ViolationFilter[0] : filters);
+ this.filters = filters;
}
public ViolationFilters() {
- this(null);
+ this(new ViolationFilter[0]);
}
- public ViolationFilter[] getFilters() {
- return filters;
+ public boolean isEmpty() {
+ return filters.length==0;
}
/**
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/Bucket.java b/sonar-batch/src/main/java/org/sonar/batch/index/Bucket.java
index 50e43abb197..6c253dd7e19 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/Bucket.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/Bucket.java
@@ -37,7 +37,6 @@ public final class Bucket {
private Resource resource;
private ListMultimap<String, Measure> measuresByMetric = ArrayListMultimap.create();
- private List<Violation> violations = Lists.newLinkedList();
private Bucket parent;
private List<Bucket> children;
@@ -80,14 +79,6 @@ public final class Bucket {
return parent;
}
- public void addViolation(Violation violation) {
- violations.add(violation);
- }
-
- public List<Violation> getViolations() {
- return violations;
- }
-
public void addMeasure(Measure measure) {
List<Measure> metricMeasures = measuresByMetric.get(measure.getMetric().getKey());
@@ -109,7 +100,6 @@ public final class Bucket {
public void clear() {
measuresByMetric = null;
- violations = null;
children = null;
if (parent != null) {
parent.removeChild(this);
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java
index 3a51f38ff0d..cef707b9799 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java
@@ -32,19 +32,16 @@ import org.sonar.api.database.model.ResourceModel;
import org.sonar.api.database.model.Snapshot;
import org.sonar.api.design.Dependency;
import org.sonar.api.measures.*;
-import org.sonar.api.profiles.RulesProfile;
import org.sonar.api.resources.*;
-import org.sonar.api.rules.ActiveRule;
import org.sonar.api.rules.Rule;
-import org.sonar.api.rules.RuleFinder;
import org.sonar.api.rules.Violation;
import org.sonar.api.utils.SonarException;
import org.sonar.api.violations.ViolationQuery;
import org.sonar.batch.DefaultResourceCreationLock;
import org.sonar.batch.ProjectTree;
import org.sonar.batch.ResourceFilters;
-import org.sonar.batch.ViolationFilters;
import org.sonar.batch.issue.DeprecatedViolations;
+import org.sonar.batch.issue.ScanIssues;
import org.sonar.core.component.ScanGraph;
import java.util.*;
@@ -53,16 +50,14 @@ public class DefaultIndex extends SonarIndex {
private static final Logger LOG = LoggerFactory.getLogger(DefaultIndex.class);
- private RulesProfile profile;
private PersistenceManager persistence;
private DefaultResourceCreationLock lock;
private MetricFinder metricFinder;
- private RuleFinder ruleFinder;
- private ScanGraph graph;
- private SnapshotCache snapshotCache;
+ private final ScanGraph graph;
+ private final SnapshotCache snapshotCache;
+ private final ResourceCache resourceCache;
// filters
- private ViolationFilters violationFilters;
private ResourceFilters resourceFilters;
// caches
@@ -73,17 +68,18 @@ public class DefaultIndex extends SonarIndex {
private Map<Resource, Map<Resource, Dependency>> incomingDependenciesByResource = Maps.newHashMap();
private ProjectTree projectTree;
private final DeprecatedViolations deprecatedViolations;
+ private ScanIssues scanIssues;
public DefaultIndex(PersistenceManager persistence, DefaultResourceCreationLock lock, ProjectTree projectTree, MetricFinder metricFinder,
- RuleFinder ruleFinder, ScanGraph graph, DeprecatedViolations deprecatedViolations, SnapshotCache snapshotCache) {
+ ScanGraph graph, SnapshotCache snapshotCache, ResourceCache resourceCache, DeprecatedViolations deprecatedViolations) {
this.persistence = persistence;
this.lock = lock;
this.projectTree = projectTree;
this.metricFinder = metricFinder;
- this.ruleFinder = ruleFinder;
this.graph = graph;
- this.deprecatedViolations = deprecatedViolations;
this.snapshotCache = snapshotCache;
+ this.resourceCache = resourceCache;
+ this.deprecatedViolations = deprecatedViolations;
}
public void start() {
@@ -116,13 +112,12 @@ public class DefaultIndex extends SonarIndex {
return currentProject;
}
- public void setCurrentProject(Project project, ResourceFilters resourceFilters, ViolationFilters violationFilters, RulesProfile profile) {
+ public void setCurrentProject(Project project, ResourceFilters resourceFilters, ScanIssues scanIssues) {
this.currentProject = project;
- // the following components depend on the current project, so they need to be reloaded.
+ // the following components depend on the current module, so they need to be reloaded.
this.resourceFilters = resourceFilters;
- this.violationFilters = violationFilters;
- this.profile = profile;
+ this.scanIssues = scanIssues;
}
/**
@@ -321,10 +316,13 @@ public class DefaultIndex extends SonarIndex {
return Collections.emptyList();
}
+ List<Violation> violations = deprecatedViolations.get(bucket.getResource().getEffectiveKey());
+ if (violationQuery.getSwitchMode() == ViolationQuery.SwitchMode.BOTH) {
+ return violations;
+ }
List<Violation> filteredViolations = Lists.newArrayList();
- ViolationQuery.SwitchMode mode = violationQuery.getSwitchMode();
- for (Violation violation : bucket.getViolations()) {
- if (isFiltered(violation, mode)) {
+ for (Violation violation : violations) {
+ if (isFiltered(violation, violationQuery.getSwitchMode())) {
filteredViolations.add(violation);
}
}
@@ -352,47 +350,13 @@ public class DefaultIndex extends SonarIndex {
return;
}
- if (rule.getId() == null) {
- Rule persistedRule = ruleFinder.findByKey(rule.getRepositoryKey(), rule.getKey());
- if (persistedRule == null) {
- LOG.warn("Rule does not exist. Ignoring violation {}", violation);
- return;
- }
- violation.setRule(persistedRule);
- }
-
Bucket bucket = checkIndexed(resource);
if (bucket == null || bucket.isExcluded()) {
return;
}
violation.setResource(bucket.getResource());
- if (addViolation(violation, bucket, force)) {
- deprecatedViolations.add(violation, currentProject.getAnalysisDate());
- }
- }
-
- private boolean addViolation(Violation violation, Bucket bucket, boolean force) {
- boolean isIgnored = !force && violationFilters != null && violationFilters.isIgnored(violation);
- if (isIgnored) {
- return false;
- }
-
- // TODO this code is not the responsibility of this index. It should be moved somewhere else.
- if (!violation.isManual()) {
- ActiveRule activeRule = profile.getActiveRule(violation.getRule());
- if (activeRule != null) {
- violation.setSeverity(activeRule.getSeverity());
- } else if (currentProject.getReuseExistingRulesConfig()) {
- violation.setSeverity(violation.getRule().getSeverity());
- } else {
- LoggerFactory.getLogger(getClass()).debug("Rule is not activated, ignoring violation {}", violation);
- return false;
- }
- }
-
- bucket.addViolation(violation);
- return true;
+ scanIssues.initAndAddViolation(violation);
}
@@ -569,6 +533,7 @@ public class DefaultIndex extends SonarIndex {
if (ResourceUtils.isPersistable(resource) && !Qualifiers.LIBRARY.equals(resource.getQualifier())) {
graph.addComponent(resource, snapshot);
snapshotCache.put(resource.getEffectiveKey(), snapshot);
+ resourceCache.add(resource);
}
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/ResourceCache.java b/sonar-batch/src/main/java/org/sonar/batch/index/ResourceCache.java
new file mode 100644
index 00000000000..a6879fd751f
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/ResourceCache.java
@@ -0,0 +1,48 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.batch.index;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+import com.google.common.collect.Maps;
+import org.sonar.api.BatchComponent;
+import org.sonar.api.resources.Resource;
+
+import java.util.Map;
+
+/**
+ * @since 3.6
+ */
+public class ResourceCache implements BatchComponent {
+ // resource by component key
+ private final Map<String, Resource> resources = Maps.newHashMap();
+
+ public Resource get(String componentKey) {
+ return resources.get(componentKey);
+ }
+
+ public ResourceCache add(Resource resource) {
+ String componentKey = resource.getEffectiveKey();
+ Preconditions.checkState(!Strings.isNullOrEmpty(componentKey), "Missing resource effective key");
+ Preconditions.checkState(!resources.containsKey(componentKey), "Resource is already registered: " + componentKey);
+ resources.put(componentKey, resource);
+ return this;
+ }
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/DeprecatedViolations.java b/sonar-batch/src/main/java/org/sonar/batch/issue/DeprecatedViolations.java
index adb81f8967b..936165eae69 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/issue/DeprecatedViolations.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/issue/DeprecatedViolations.java
@@ -19,43 +19,58 @@
*/
package org.sonar.batch.issue;
+import com.google.common.collect.Lists;
import org.sonar.api.BatchComponent;
+import org.sonar.api.issue.Issue;
import org.sonar.api.resources.Resource;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.Severity;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RuleFinder;
+import org.sonar.api.rules.RulePriority;
import org.sonar.api.rules.Violation;
+import org.sonar.batch.index.ResourceCache;
import org.sonar.core.issue.DefaultIssue;
-import org.sonar.core.issue.DefaultIssueBuilder;
import java.util.Collection;
-import java.util.Date;
+import java.util.List;
+/**
+ * Bridge with violations, that have been deprecated in 3.6.
+ * @since 3.6
+ */
public class DeprecatedViolations implements BatchComponent {
- private final IssueCache cache;
-
- public DeprecatedViolations(IssueCache cache) {
- this.cache = cache;
- }
+ private final IssueCache issueCache;
+ private final RuleFinder ruleFinder;
+ private final ResourceCache resourceCache;
- public void add(Violation violation, Date creationDate) {
- DefaultIssue issue = toIssue(violation, creationDate);
- cache.put(issue);
+ public DeprecatedViolations(IssueCache issueCache, RuleFinder ruleFinder, ResourceCache resourceCache) {
+ this.issueCache = issueCache;
+ this.ruleFinder = ruleFinder;
+ this.resourceCache = resourceCache;
}
- public Collection<Violation> get(Resource resource) {
- throw new UnsupportedOperationException("TODO");
+ public List<Violation> get(String componentKey) {
+ Collection<DefaultIssue> issues = issueCache.byComponent(componentKey);
+ List<Violation> violations = Lists.newArrayList();
+ for (DefaultIssue issue : issues) {
+ violations.add(toViolation(issue));
+ }
+ return violations;
}
- DefaultIssue toIssue(Violation violation, Date creationDate) {
- return (DefaultIssue) new DefaultIssueBuilder()
- .createdDate(creationDate)
- .componentKey(violation.getResource().getEffectiveKey())
- .ruleKey(RuleKey.of(violation.getRule().getRepositoryKey(), violation.getRule().getKey()))
- .effortToFix(violation.getCost())
- .line(violation.getLineId())
- .message(violation.getMessage())
- .severity(violation.getSeverity() != null ? violation.getSeverity().name() : Severity.MAJOR)
- .build();
+ public Violation toViolation(DefaultIssue issue) {
+ Rule rule = ruleFinder.findByKey(issue.ruleKey());
+ Resource resource = resourceCache.get(issue.componentKey());
+ Violation violation = new Violation(rule, resource);
+ violation.setNew(issue.isNew());
+ violation.setChecksum(issue.checksum());
+ violation.setMessage(issue.message());
+ violation.setCost(issue.effortToFix());
+ violation.setLineId(issue.line());
+ violation.setCreatedAt(issue.creationDate());
+ violation.setManual(issue.reporter() != null);
+ violation.setSeverity(RulePriority.valueOf(issue.severity()));
+ violation.setSwitchedOff(Issue.RESOLUTION_FALSE_POSITIVE.equals(issue.resolution()));
+ return violation;
}
}
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueFilters.java b/sonar-batch/src/main/java/org/sonar/batch/issue/IssueFilters.java
index 7b52e845618..0488c432aed 100644
--- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueFilters.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/issue/IssueFilters.java
@@ -17,29 +17,43 @@
* 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.plugins.core.issue;
+package org.sonar.batch.issue;
import org.sonar.api.BatchExtension;
import org.sonar.api.issue.Issue;
import org.sonar.api.issue.IssueFilter;
+import org.sonar.api.rules.Violation;
+import org.sonar.batch.ViolationFilters;
+import org.sonar.core.issue.DefaultIssue;
+
+import javax.annotation.Nullable;
public class IssueFilters implements BatchExtension {
+
+ private final ViolationFilters deprecatedFilters;
+ private final DeprecatedViolations deprecatedViolations;
private final IssueFilter[] filters;
- public IssueFilters(IssueFilter[] filters) {
+ public IssueFilters(ViolationFilters deprecatedFilters, DeprecatedViolations deprecatedViolations, IssueFilter[] filters) {
+ this.deprecatedFilters = deprecatedFilters;
+ this.deprecatedViolations = deprecatedViolations;
this.filters = filters;
}
- public IssueFilters() {
- this(new IssueFilter[0]);
+ public IssueFilters(ViolationFilters deprecatedFilters, DeprecatedViolations deprecatedViolations) {
+ this(deprecatedFilters, deprecatedViolations, new IssueFilter[0]);
}
- public boolean accept(Issue issue) {
+ public boolean accept(DefaultIssue issue, @Nullable Violation violation) {
for (IssueFilter filter : filters) {
if (!filter.accept(issue)) {
return false;
}
}
+ if (!deprecatedFilters.isEmpty()) {
+ Violation v = (violation != null ? violation : deprecatedViolations.toViolation(issue));
+ return !deprecatedFilters.isIgnored(v);
+ }
return true;
}
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/ScanIssues.java b/sonar-batch/src/main/java/org/sonar/batch/issue/ScanIssues.java
index ab06a7f9cca..4d0e5863023 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/issue/ScanIssues.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/issue/ScanIssues.java
@@ -22,25 +22,54 @@ package org.sonar.batch.issue;
import org.sonar.api.BatchComponent;
import org.sonar.api.profiles.RulesProfile;
import org.sonar.api.resources.Project;
+import org.sonar.api.rule.RuleKey;
import org.sonar.api.rules.ActiveRule;
+import org.sonar.api.rules.Violation;
import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.DefaultIssueBuilder;
+
+import javax.annotation.Nullable;
/**
- * Central component to manage issues
+ * Initialize the issues raised during scan.
*/
public class ScanIssues implements BatchComponent {
private final RulesProfile qProfile;
private final IssueCache cache;
private final Project project;
+ private final IssueFilters filters;
- public ScanIssues(RulesProfile qProfile, IssueCache cache, Project project) {
+ public ScanIssues(RulesProfile qProfile, IssueCache cache, Project project, IssueFilters filters) {
this.qProfile = qProfile;
this.cache = cache;
this.project = project;
+ this.filters = filters;
}
public boolean initAndAddIssue(DefaultIssue issue) {
+ return initAndAddIssue(issue, null);
+ }
+
+ public boolean initAndAddViolation(Violation violation) {
+ DefaultIssue issue = newIssue(violation);
+ return initAndAddIssue(issue, violation);
+ }
+
+ private DefaultIssue newIssue(Violation violation) {
+ return (DefaultIssue) new DefaultIssueBuilder()
+ .componentKey(violation.getResource().getEffectiveKey())
+ .ruleKey(RuleKey.of(violation.getRule().getRepositoryKey(), violation.getRule().getKey()))
+ .effortToFix(violation.getCost())
+ .line(violation.getLineId())
+ .message(violation.getMessage())
+ .severity(violation.getSeverity() != null ? violation.getSeverity().name() : null)
+ .build();
+ }
+
+ private boolean initAndAddIssue(DefaultIssue issue, @Nullable Violation violation) {
+ // TODO fail fast : if rule does not exist
+
ActiveRule activeRule = qProfile.getActiveRule(issue.ruleKey().repository(), issue.ruleKey().rule());
if (activeRule == null || activeRule.getRule() == null) {
// rule does not exist or is not enabled -> ignore the issue
@@ -52,8 +81,12 @@ public class ScanIssues implements BatchComponent {
if (issue.severity() == null) {
issue.setSeverity(activeRule.getSeverity().name());
}
- cache.put(issue);
- return true;
+
+ if (filters.accept(issue, violation)) {
+ cache.put(issue);
+ return true;
+ }
+ return false;
}
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java
index c40edc06c85..23a087ce155 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java
@@ -25,7 +25,6 @@ import org.sonar.api.BatchExtension;
import org.sonar.api.batch.InstantiationStrategy;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.platform.ComponentContainer;
-import org.sonar.api.profiles.RulesProfile;
import org.sonar.api.resources.Languages;
import org.sonar.api.resources.Project;
import org.sonar.api.scan.filesystem.FileExclusions;
@@ -40,6 +39,7 @@ import org.sonar.batch.events.EventBus;
import org.sonar.batch.index.DefaultIndex;
import org.sonar.batch.index.ResourcePersister;
import org.sonar.batch.issue.IssuableFactory;
+import org.sonar.batch.issue.IssueFilters;
import org.sonar.batch.issue.ScanIssues;
import org.sonar.batch.phases.PhaseExecutor;
import org.sonar.batch.phases.PhasesTimeProfiler;
@@ -103,6 +103,7 @@ public class ModuleScanContainer extends ComponentContainer {
BatchExtensionDictionnary.class,
DefaultTimeMachine.class,
ViolationFilters.class,
+ IssueFilters.class,
ResourceFilters.class,
DeprecatedJsonReport.class,
JsonReport.class,
@@ -136,8 +137,7 @@ public class ModuleScanContainer extends ComponentContainer {
DefaultIndex index = getComponentByType(DefaultIndex.class);
index.setCurrentProject(module,
getComponentByType(ResourceFilters.class),
- getComponentByType(ViolationFilters.class),
- getComponentByType(RulesProfile.class));
+ getComponentByType(ScanIssues.class));
getComponentByType(PhaseExecutor.class).execute(module);
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
index ae0bab858c4..857ffb174ab 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
@@ -89,6 +89,7 @@ public class ProjectScanContainer extends ComponentContainer {
LastSnapshots.class,
Caches.class,
SnapshotCache.class,
+ ResourceCache.class,
ComponentDataCache.class,
ComponentDataPersister.class,
diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/BucketTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/BucketTest.java
index a61acdcbd09..89f0ddd43a8 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/index/BucketTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/index/BucketTest.java
@@ -36,9 +36,9 @@ import static org.junit.internal.matchers.IsCollectionContaining.hasItem;
public class BucketTest {
- private JavaPackage javaPackage = new JavaPackage("org.foo");
- private JavaFile javaFile = new JavaFile("org.foo.Bar");
- private Metric ncloc = new Metric("ncloc");
+ JavaPackage javaPackage = new JavaPackage("org.foo");
+ JavaFile javaFile = new JavaFile("org.foo.Bar");
+ Metric ncloc = new Metric("ncloc");
@Test
public void shouldManageRelationships() {
@@ -52,15 +52,6 @@ public class BucketTest {
}
@Test
- public void shouldCacheViolations() {
- Bucket fileBucket = new Bucket(javaFile);
- Violation violation = Violation.create(Rule.create("checkstyle", "rule1", "Rule one"), javaFile);
- fileBucket.addViolation(violation);
- assertThat(fileBucket.getViolations().size(), is(1));
- assertThat(fileBucket.getViolations(), hasItem(violation));
- }
-
- @Test
public void shouldAddNewMeasure() {
Bucket fileBucket = new Bucket(javaFile);
Measure measure = new Measure(ncloc).setValue(1200.0);
diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java
index c23a85bdd2f..598b73750ae 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java
@@ -20,7 +20,6 @@
package org.sonar.batch.index;
import org.apache.commons.lang.StringUtils;
-import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
import org.sonar.api.batch.ResourceFilter;
@@ -30,15 +29,7 @@ import org.sonar.api.measures.Measure;
import org.sonar.api.measures.MeasuresFilters;
import org.sonar.api.measures.MetricFinder;
import org.sonar.api.profiles.RulesProfile;
-import org.sonar.api.resources.Directory;
-import org.sonar.api.resources.File;
-import org.sonar.api.resources.Java;
-import org.sonar.api.resources.JavaPackage;
-import org.sonar.api.resources.Language;
-import org.sonar.api.resources.Library;
-import org.sonar.api.resources.Project;
-import org.sonar.api.resources.Qualifiers;
-import org.sonar.api.resources.Resource;
+import org.sonar.api.resources.*;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RuleFinder;
import org.sonar.api.rules.Violation;
@@ -47,12 +38,10 @@ import org.sonar.api.violations.ViolationQuery;
import org.sonar.batch.DefaultResourceCreationLock;
import org.sonar.batch.ProjectTree;
import org.sonar.batch.ResourceFilters;
-import org.sonar.batch.ViolationFilters;
import org.sonar.batch.issue.DeprecatedViolations;
+import org.sonar.batch.issue.ScanIssues;
import org.sonar.core.component.ScanGraph;
-import java.util.List;
-
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
@@ -73,7 +62,8 @@ public class DefaultIndexTest {
when(metricFinder.findByKey("ncloc")).thenReturn(CoreMetrics.NCLOC);
ruleFinder = mock(RuleFinder.class);
- index = new DefaultIndex(mock(PersistenceManager.class), lock, mock(ProjectTree.class), metricFinder, ruleFinder, mock(ScanGraph.class), mock(DeprecatedViolations.class), mock(SnapshotCache.class));
+ index = new DefaultIndex(mock(PersistenceManager.class), lock, mock(ProjectTree.class), metricFinder, mock(ScanGraph.class),
+ mock(SnapshotCache.class), mock(ResourceCache.class), mock(DeprecatedViolations.class));
Project project = new Project("project");
ResourceFilter filter = new ResourceFilter() {
@@ -86,7 +76,7 @@ public class DefaultIndexTest {
rule = Rule.create("repoKey", "ruleKey", "Rule");
rule.setId(1);
rulesProfile.activateRule(rule, null);
- index.setCurrentProject(project, new ResourceFilters(new ResourceFilter[]{filter}), new ViolationFilters(), rulesProfile);
+ index.setCurrentProject(project, new ResourceFilters(new ResourceFilter[]{filter}), mock(ScanIssues.class));
index.doStart(project);
}
@@ -214,25 +204,6 @@ public class DefaultIndexTest {
* See https://jira.codehaus.org/browse/SONAR-3583
*/
@Test
- public void should_support_violations_with_missing_rule_id() {
- Rule ruleWithoutId = Rule.create("repoKey", "ruleKey", "Rule");
- Rule ruleWithId = Rule.create("repoKey", "ruleKey", "Rule");
- ruleWithId.setId(123);
- when(ruleFinder.findByKey("repoKey", "ruleKey")).thenReturn(ruleWithId);
-
- File file = new File("org/foo/Bar.java");
- Violation violation = Violation.create(ruleWithoutId, file);
- index.addViolation(violation);
-
- List<Violation> violations = index.getViolations(file);
- assertThat(violations.size(), is(1));
- assertThat(violations.get(0).getRule().getId(), Matchers.is(123));
- }
-
- /**
- * See https://jira.codehaus.org/browse/SONAR-3583
- */
- @Test
public void should_ignore_violation_on_unknown_rules() {
Rule ruleWithoutID = Rule.create("repoKey", "ruleKey", "Rule");
@@ -243,36 +214,6 @@ public class DefaultIndexTest {
assertThat(index.getViolations(file).size(), is(0));
}
- @Test
- public void testGetViolations() {
- File file = new File("org/foo/Bar.java");
- Violation violation1 = Violation.create(rule, file);
- index.addViolation(violation1);
- Violation violation2 = Violation.create(rule, file);
- violation2.setSwitchedOff(true);
- index.addViolation(violation2);
- Violation violation3 = Violation.create(rule, file);
- violation3.setSwitchedOff(true);
- index.addViolation(violation3);
-
- assertThat(index.getViolations(file).size(), is(1));
- }
-
- @Test
- public void testGetViolationsWithQuery() {
- File file = new File("org/foo/Bar.java");
- Violation violation1 = Violation.create(rule, file);
- index.addViolation(violation1);
- Violation violation2 = Violation.create(rule, file);
- violation2.setSwitchedOff(true);
- index.addViolation(violation2);
- Violation violation3 = Violation.create(rule, file);
- violation3.setSwitchedOff(true);
- index.addViolation(violation3);
-
- assertThat(index.getViolations(ViolationQuery.create().forResource(file).setSwitchedOff(true)).size(), is(2));
- }
-
@Test(expected = IllegalArgumentException.class)
public void testGetViolationsWithQueryWithNoResource() {
index.getViolations(ViolationQuery.create());
diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/ResourceCacheTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/ResourceCacheTest.java
new file mode 100644
index 00000000000..ad16edcb02f
--- /dev/null
+++ b/sonar-batch/src/test/java/org/sonar/batch/index/ResourceCacheTest.java
@@ -0,0 +1,68 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.batch.index;
+
+import org.junit.Test;
+import org.sonar.api.resources.JavaFile;
+import org.sonar.api.resources.Resource;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
+
+public class ResourceCacheTest {
+ @Test
+ public void should_cache_resource() throws Exception {
+ ResourceCache cache = new ResourceCache();
+ String componentKey = "struts:org.struts.Action";
+ Resource resource = new JavaFile("org.struts.Action").setEffectiveKey(componentKey);
+ cache.add(resource);
+
+ assertThat(cache.get(componentKey)).isSameAs(resource);
+ assertThat(cache.get("other")).isNull();
+ }
+
+ @Test
+ public void should_fail_if_add_twice() throws Exception {
+ ResourceCache cache = new ResourceCache();
+ String componentKey = "struts:org.struts.Action";
+ Resource resource = new JavaFile("org.struts.Action").setEffectiveKey(componentKey);
+ cache.add(resource);
+ try {
+ cache.add(resource);
+ fail();
+ } catch (IllegalStateException e) {
+ // success
+ assertThat(e).hasMessage("Resource is already registered: struts:org.struts.Action");
+ }
+ }
+
+ @Test
+ public void should_fail_if_missing_component_key() throws Exception {
+ ResourceCache cache = new ResourceCache();
+ Resource resource = new JavaFile("org.struts.Action").setEffectiveKey(null);
+ try {
+ cache.add(resource);
+ fail();
+ } catch (IllegalStateException e) {
+ // success
+ assertThat(e).hasMessage("Missing resource effective key");
+ }
+ }
+}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/SnapshotCacheTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/SnapshotCacheTest.java
index 81776a93518..29df021f0c8 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/index/SnapshotCacheTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/index/SnapshotCacheTest.java
@@ -28,7 +28,7 @@ import static org.mockito.Mockito.mock;
public class SnapshotCacheTest {
- private Snapshot snapshot = mock(Snapshot.class);
+ Snapshot snapshot = mock(Snapshot.class);
@Test
public void should_cache_snapshots() throws Exception {
@@ -49,6 +49,7 @@ public class SnapshotCacheTest {
fail();
} catch (IllegalStateException e) {
// success
+ assertThat(e).hasMessage("Component is already registered: org.apache.struts:struts-core");
}
}
}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/issue/DeprecatedViolationsTest.java b/sonar-batch/src/test/java/org/sonar/batch/issue/DeprecatedViolationsTest.java
new file mode 100644
index 00000000000..bff9ae4e2d0
--- /dev/null
+++ b/sonar-batch/src/test/java/org/sonar/batch/issue/DeprecatedViolationsTest.java
@@ -0,0 +1,88 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.batch.issue;
+
+import org.junit.Test;
+import org.sonar.api.resources.JavaFile;
+import org.sonar.api.resources.Project;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.Severity;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RuleFinder;
+import org.sonar.api.rules.RulePriority;
+import org.sonar.api.rules.Violation;
+import org.sonar.batch.index.ResourceCache;
+import org.sonar.core.issue.DefaultIssue;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class DeprecatedViolationsTest {
+
+ IssueCache issueCache = mock(IssueCache.class);
+ RuleFinder ruleFinder = mock(RuleFinder.class);
+ ResourceCache resourceCache = mock(ResourceCache.class);
+ DeprecatedViolations deprecatedViolations = new DeprecatedViolations(issueCache, ruleFinder, resourceCache);
+
+ @Test
+ public void test_toViolation() throws Exception {
+ RuleKey ruleKey = RuleKey.of("squid", "AvoidCycles");
+ when(ruleFinder.findByKey(ruleKey)).thenReturn(new Rule("squid", "AvoidCycles"));
+ when(resourceCache.get("org.apache:struts")).thenReturn(new Project("org.apache:struts"));
+
+ DefaultIssue issue = newIssue(ruleKey);
+
+ Violation violation = deprecatedViolations.toViolation(issue);
+ assertThat(violation.getLineId()).isEqualTo(42);
+ assertThat(violation.getSeverity()).isEqualTo(RulePriority.BLOCKER);
+ assertThat(violation.isManual()).isTrue();
+ assertThat(violation.getRule().getRepositoryKey()).isEqualTo("squid");
+ assertThat(violation.getRule().getKey()).isEqualTo("AvoidCycles");
+ assertThat(violation.getResource()).isNotNull();
+ }
+
+ private DefaultIssue newIssue(RuleKey ruleKey) {
+ DefaultIssue issue = new DefaultIssue();
+ issue.setKey("ABCDE");
+ issue.setRuleKey(ruleKey);
+ issue.setComponentKey("org.apache:struts");
+ issue.setLine(42);
+ issue.setEffortToFix(3.14);
+ issue.setReporter("leon");
+ issue.setSeverity(Severity.BLOCKER);
+ return issue;
+ }
+
+ @Test
+ public void test_get() throws Exception {
+ RuleKey ruleKey = RuleKey.of("squid", "AvoidCycles");
+ when(ruleFinder.findByKey(ruleKey)).thenReturn(new Rule("squid", "AvoidCycles"));
+ when(resourceCache.get("org.apache:struts")).thenReturn(new Project("org.apache:struts"));
+ when(issueCache.byComponent("org.apache:struts")).thenReturn(Arrays.asList(newIssue(ruleKey)));
+
+ List<Violation> violations = deprecatedViolations.get("org.apache:struts");
+
+ assertThat(violations).hasSize(1);
+ }
+}
diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/IssueFiltersTest.java b/sonar-batch/src/test/java/org/sonar/batch/issue/IssueFiltersTest.java
index d6dbe9cec3d..731c78d536f 100644
--- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/IssueFiltersTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/issue/IssueFiltersTest.java
@@ -17,11 +17,13 @@
* 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.plugins.core.issue;
+package org.sonar.batch.issue;
import org.junit.Test;
import org.sonar.api.issue.Issue;
import org.sonar.api.issue.IssueFilter;
+import org.sonar.api.rules.Violation;
+import org.sonar.batch.ViolationFilters;
import org.sonar.core.issue.DefaultIssue;
import static org.fest.assertions.Assertions.assertThat;
@@ -30,27 +32,42 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class IssueFiltersTest {
+
+ DeprecatedViolations deprecatedViolations = mock(DeprecatedViolations.class);
+ ViolationFilters deprecatedFilters = mock(ViolationFilters.class);
+
@Test
- public void test_accept() throws Exception {
+ public void accept() throws Exception {
IssueFilter ok = mock(IssueFilter.class);
when(ok.accept(any(Issue.class))).thenReturn(true);
IssueFilter ko = mock(IssueFilter.class);
when(ko.accept(any(Issue.class))).thenReturn(false);
- IssueFilters filters = new IssueFilters(new IssueFilter[]{ok, ko});
- assertThat(filters.accept(new DefaultIssue())).isFalse();
+ when(deprecatedFilters.isEmpty()).thenReturn(true);
+ IssueFilters filters = new IssueFilters(deprecatedFilters, deprecatedViolations, new IssueFilter[]{ok, ko});
+ assertThat(filters.accept(new DefaultIssue(), null)).isFalse();
- filters = new IssueFilters(new IssueFilter[]{ok});
- assertThat(filters.accept(new DefaultIssue())).isTrue();
+ filters = new IssueFilters(deprecatedFilters, deprecatedViolations, new IssueFilter[]{ok});
+ assertThat(filters.accept(new DefaultIssue(), null)).isTrue();
- filters = new IssueFilters(new IssueFilter[]{ko});
- assertThat(filters.accept(new DefaultIssue())).isFalse();
+ filters = new IssueFilters(deprecatedFilters, deprecatedViolations, new IssueFilter[]{ko});
+ assertThat(filters.accept(new DefaultIssue(), null)).isFalse();
}
@Test
public void should_always_accept_if_no_filters() {
- IssueFilters filters = new IssueFilters();
- assertThat(filters.accept(new DefaultIssue())).isTrue();
+ when(deprecatedFilters.isEmpty()).thenReturn(true);
+ IssueFilters filters = new IssueFilters(deprecatedFilters, deprecatedViolations);
+ assertThat(filters.accept(new DefaultIssue(), null)).isTrue();
+ }
+
+ @Test
+ public void should_check_deprecated_violation_filters() throws Exception {
+ when(deprecatedFilters.isEmpty()).thenReturn(false);
+ when(deprecatedFilters.isIgnored(any(Violation.class))).thenReturn(true);
+ IssueFilters filters = new IssueFilters(deprecatedFilters, deprecatedViolations, new IssueFilter[0]);
+ assertThat(filters.accept(new DefaultIssue(), null)).isFalse();
+
}
}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/issue/ScanIssuesTest.java b/sonar-batch/src/test/java/org/sonar/batch/issue/ScanIssuesTest.java
index 730a0508faf..a41a12657a8 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/issue/ScanIssuesTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/issue/ScanIssuesTest.java
@@ -22,12 +22,15 @@ package org.sonar.batch.issue;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.sonar.api.profiles.RulesProfile;
+import org.sonar.api.resources.JavaFile;
import org.sonar.api.resources.Project;
+import org.sonar.api.resources.Resource;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity;
import org.sonar.api.rules.ActiveRule;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RulePriority;
+import org.sonar.api.rules.Violation;
import org.sonar.core.issue.DefaultIssue;
import java.util.Date;
@@ -40,7 +43,8 @@ public class ScanIssuesTest {
IssueCache cache = mock(IssueCache.class);
RulesProfile qProfile = mock(RulesProfile.class);
Project project = mock(Project.class);
- ScanIssues scanIssues = new ScanIssues(qProfile, cache, project);
+ IssueFilters filters = mock(IssueFilters.class);
+ ScanIssues scanIssues = new ScanIssues(qProfile, cache, project, filters);
@Test
public void should_ignore_null_active_rule() throws Exception {
@@ -68,11 +72,11 @@ public class ScanIssuesTest {
@Test
public void should_add_issue_to_cache() throws Exception {
- Rule rule = Rule.create("repoKey", "ruleKey");
+ Rule rule = Rule.create("squid", "AvoidCycle");
ActiveRule activeRule = mock(ActiveRule.class);
when(activeRule.getRule()).thenReturn(rule);
when(activeRule.getSeverity()).thenReturn(RulePriority.INFO);
- when(qProfile.getActiveRule(anyString(), anyString())).thenReturn(activeRule);
+ when(qProfile.getActiveRule("squid", "AvoidCycle")).thenReturn(activeRule);
Date analysisDate = new Date();
when(project.getAnalysisDate()).thenReturn(analysisDate);
@@ -81,6 +85,8 @@ public class ScanIssuesTest {
.setKey("ABCDE")
.setRuleKey(RuleKey.of("squid", "AvoidCycle"))
.setSeverity(Severity.CRITICAL);
+ when(filters.accept(issue, null)).thenReturn(true);
+
boolean added = scanIssues.initAndAddIssue(issue);
assertThat(added).isTrue();
@@ -92,16 +98,17 @@ public class ScanIssuesTest {
@Test
public void should_use_severity_from_active_rule_if_no_severity() throws Exception {
- Rule rule = Rule.create("repoKey", "ruleKey");
+ Rule rule = Rule.create("squid", "AvoidCycle");
ActiveRule activeRule = mock(ActiveRule.class);
when(activeRule.getRule()).thenReturn(rule);
when(activeRule.getSeverity()).thenReturn(RulePriority.INFO);
- when(qProfile.getActiveRule(anyString(), anyString())).thenReturn(activeRule);
+ when(qProfile.getActiveRule("squid", "AvoidCycle")).thenReturn(activeRule);
Date analysisDate = new Date();
when(project.getAnalysisDate()).thenReturn(analysisDate);
DefaultIssue issue = new DefaultIssue().setRuleKey(RuleKey.of("squid", "AvoidCycle")).setSeverity(null);
+ when(filters.accept(issue, null)).thenReturn(true);
scanIssues.initAndAddIssue(issue);
ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
@@ -109,4 +116,54 @@ public class ScanIssuesTest {
assertThat(argument.getValue().severity()).isEqualTo(Severity.INFO);
assertThat(argument.getValue().creationDate()).isEqualTo(analysisDate);
}
+
+ @Test
+ public void should_add_deprecated_violation() throws Exception {
+ Rule rule = Rule.create("squid", "AvoidCycle");
+ Resource resource = new JavaFile("org.struts.Action").setEffectiveKey("struts:org.struts.Action");
+ Violation violation = new Violation(rule, resource);
+ violation.setLineId(42);
+ violation.setSeverity(RulePriority.CRITICAL);
+ violation.setMessage("the message");
+
+ ActiveRule activeRule = mock(ActiveRule.class);
+ when(activeRule.getRule()).thenReturn(rule);
+ when(activeRule.getSeverity()).thenReturn(RulePriority.INFO);
+ when(qProfile.getActiveRule("squid", "AvoidCycle")).thenReturn(activeRule);
+ when(filters.accept(any(DefaultIssue.class), eq(violation))).thenReturn(true);
+
+ boolean added = scanIssues.initAndAddViolation(violation);
+ assertThat(added).isTrue();
+
+ ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
+ verify(cache).put(argument.capture());
+ DefaultIssue issue = argument.getValue();
+ assertThat(issue.severity()).isEqualTo(Severity.CRITICAL);
+ assertThat(issue.line()).isEqualTo(42);
+ assertThat(issue.message()).isEqualTo("the message");
+ assertThat(issue.key()).isNotEmpty();
+ assertThat(issue.ruleKey().toString()).isEqualTo("squid:AvoidCycle");
+ assertThat(issue.componentKey().toString()).isEqualTo("struts:org.struts.Action");
+ }
+
+ @Test
+ public void should_filter_issue() throws Exception {
+ Rule rule = Rule.create("squid", "AvoidCycle");
+ ActiveRule activeRule = mock(ActiveRule.class);
+ when(activeRule.getRule()).thenReturn(rule);
+ when(activeRule.getSeverity()).thenReturn(RulePriority.INFO);
+ when(qProfile.getActiveRule("squid", "AvoidCycle")).thenReturn(activeRule);
+
+ DefaultIssue issue = new DefaultIssue()
+ .setKey("ABCDE")
+ .setRuleKey(RuleKey.of("squid", "AvoidCycle"))
+ .setSeverity(Severity.CRITICAL);
+
+ when(filters.accept(issue, null)).thenReturn(false);
+
+ boolean added = scanIssues.initAndAddIssue(issue);
+
+ assertThat(added).isFalse();
+ verifyZeroInteractions(cache);
+ }
}
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssue.java b/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssue.java
index 56fb83bebe4..d573da495d6 100644
--- a/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssue.java
+++ b/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssue.java
@@ -241,7 +241,7 @@ public class DefaultIssue implements Issue {
@CheckForNull
- public String getChecksum() {
+ public String checksum() {
return checksum;
}
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/db/IssueDto.java b/sonar-core/src/main/java/org/sonar/core/issue/db/IssueDto.java
index 0d1390fd5cd..84d6677376e 100644
--- a/sonar-core/src/main/java/org/sonar/core/issue/db/IssueDto.java
+++ b/sonar-core/src/main/java/org/sonar/core/issue/db/IssueDto.java
@@ -343,7 +343,7 @@ public final class IssueDto {
.setResolution(issue.resolution())
.setStatus(issue.status())
.setSeverity(issue.severity())
- .setChecksum(issue.getChecksum())
+ .setChecksum(issue.checksum())
.setManualSeverity(issue.manualSeverity())
.setReporter(issue.reporter())
.setAssignee(issue.assignee())
@@ -371,7 +371,7 @@ public final class IssueDto {
.setResolution(issue.resolution())
.setStatus(issue.status())
.setSeverity(issue.severity())
- .setChecksum(issue.getChecksum())
+ .setChecksum(issue.checksum())
.setManualSeverity(issue.manualSeverity())
.setReporter(issue.reporter())
.setAssignee(issue.assignee())
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/database/model/Snapshot.java b/sonar-plugin-api/src/main/java/org/sonar/api/database/model/Snapshot.java
index 8f5cbd8aaf8..de5390d3a2a 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/database/model/Snapshot.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/database/model/Snapshot.java
@@ -32,6 +32,7 @@ import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
+import java.io.Serializable;
import java.util.Date;
/**
@@ -39,7 +40,7 @@ import java.util.Date;
*/
@Entity
@Table(name = "snapshots")
-public class Snapshot extends BaseIdentifiable {
+public class Snapshot extends BaseIdentifiable implements Serializable {
/**
* This status is set on the snapshot at the beginning of the batch
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/resources/Resource.java b/sonar-plugin-api/src/main/java/org/sonar/api/resources/Resource.java
index 95dcdd084d2..c6e22cdd408 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/resources/Resource.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/resources/Resource.java
@@ -19,12 +19,14 @@
*/
package org.sonar.api.resources;
+import java.io.Serializable;
+
/**
* The interface to implement to create a resource in Sonar
*
* @since 1.10
*/
-public abstract class Resource<P extends Resource> {
+public abstract class Resource<P extends Resource> implements Serializable {
/**
* @deprecated since 2.6. Use Scopes.PROJECT.
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/rules/Violation.java b/sonar-plugin-api/src/main/java/org/sonar/api/rules/Violation.java
index 906aea24aad..d1091b62cf9 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/rules/Violation.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/rules/Violation.java
@@ -27,7 +27,9 @@ import java.util.Date;
/**
* A class that represents a violation. A violation happens when a resource does not respect a defined rule.
+ * @deprecated in 3.6. Replaced by {@link org.sonar.api.issue.Issue}.
*/
+@Deprecated
public class Violation {
private Resource resource;
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/rules/ViolationFilter.java b/sonar-plugin-api/src/main/java/org/sonar/api/rules/ViolationFilter.java
index 71e8cecf495..612e8eb054d 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/rules/ViolationFilter.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/rules/ViolationFilter.java
@@ -27,8 +27,10 @@ import org.sonar.api.batch.DependedUpon;
* Filter violations to save. For example, ignore a violation if it occurs on a line of code commented with //NOSONAR
*
* @since 1.12
+ * @deprecated in 3.6. Replaced by {@link org.sonar.api.issue.IssueFilter}.
*/
@DependedUpon(value = DecoratorBarriers.START_VIOLATIONS_GENERATION)
+@Deprecated
public interface ViolationFilter extends BatchExtension {
/**
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/violations/ViolationQuery.java b/sonar-plugin-api/src/main/java/org/sonar/api/violations/ViolationQuery.java
index 70ca8ee5f13..470e3929648 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/violations/ViolationQuery.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/violations/ViolationQuery.java
@@ -25,7 +25,9 @@ import org.sonar.api.resources.Resource;
* Class that allows to query the Sonar index about violations.
*
* @since 2.8
+ * @deprecated in 3.6 for the merge of violations and reviews into issues.
*/
+@Deprecated
public final class ViolationQuery {
public static enum SwitchMode {