summaryrefslogtreecommitdiffstats
path: root/sonar-batch
diff options
context:
space:
mode:
authorJulien HENRY <julien.henry@sonarsource.com>2015-03-02 09:54:06 +0100
committerSimon Brandhof <simon.brandhof@sonarsource.com>2015-03-04 21:18:17 +0100
commit6108a50f766dac17b0bd45258c70ffd346d366c1 (patch)
tree4633e567282ffefcf8eb996aa9061e15cef338e5 /sonar-batch
parentae4801956efbc9eba1971d0b899267a3e8406c42 (diff)
downloadsonarqube-6108a50f766dac17b0bd45258c70ffd346d366c1.tar.gz
sonarqube-6108a50f766dac17b0bd45258c70ffd346d366c1.zip
SONAR-5945 close issues on deleted components
Diffstat (limited to 'sonar-batch')
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/issue/IssueCache.java6
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/report/ComponentsPublisher.java10
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/report/IssuesPublisher.java50
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/report/IssuesPublisherTest.java166
4 files changed, 220 insertions, 12 deletions
diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/IssueCache.java b/sonar-batch/src/main/java/org/sonar/batch/issue/IssueCache.java
index f804fc62efd..f0c1cfb1fbd 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/issue/IssueCache.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/issue/IssueCache.java
@@ -24,6 +24,8 @@ import org.sonar.api.issue.internal.DefaultIssue;
import org.sonar.batch.index.Cache;
import org.sonar.batch.index.Caches;
+import java.util.Collection;
+
/**
* Shared issues among all project modules
*/
@@ -44,6 +46,10 @@ public class IssueCache implements BatchComponent {
return cache.values();
}
+ public Collection<Object> componentKeys() {
+ return cache.keySet();
+ }
+
public IssueCache put(DefaultIssue issue) {
cache.put(issue.componentKey(), issue.key(), issue);
return this;
diff --git a/sonar-batch/src/main/java/org/sonar/batch/report/ComponentsPublisher.java b/sonar-batch/src/main/java/org/sonar/batch/report/ComponentsPublisher.java
index 0a7d97d9ad6..7850f6e2db4 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/report/ComponentsPublisher.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/report/ComponentsPublisher.java
@@ -21,7 +21,6 @@ package org.sonar.batch.report;
import org.sonar.api.batch.bootstrap.ProjectReactor;
import org.sonar.api.resources.Language;
-import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
import org.sonar.api.resources.ResourceUtils;
import org.sonar.batch.index.BatchResource;
@@ -48,15 +47,6 @@ public class ComponentsPublisher implements ReportPublisher {
@Override
public void publish(BatchOutputWriter writer) {
BatchResource rootProject = resourceCache.get(reactor.getRoot().getKeyWithBranch());
- BatchReport.Metadata.Builder builder = BatchReport.Metadata.newBuilder()
- .setAnalysisDate(((Project) rootProject.resource()).getAnalysisDate().getTime())
- .setProjectKey(((Project) rootProject.resource()).key())
- .setRootComponentRef(rootProject.batchId());
- Integer sid = rootProject.snapshotId();
- if (sid != null) {
- builder.setSnapshotId(sid);
- }
- writer.writeMetadata(builder.build());
recursiveWriteComponent(rootProject, writer);
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/report/IssuesPublisher.java b/sonar-batch/src/main/java/org/sonar/batch/report/IssuesPublisher.java
index 8be01240274..fd7bd13b814 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/report/IssuesPublisher.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/report/IssuesPublisher.java
@@ -21,8 +21,10 @@ package org.sonar.batch.report;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
+import org.sonar.api.batch.bootstrap.ProjectReactor;
import org.sonar.api.issue.internal.DefaultIssue;
import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.api.resources.Project;
import org.sonar.api.utils.KeyValueFormat;
import org.sonar.batch.index.BatchResource;
import org.sonar.batch.index.ResourceCache;
@@ -33,29 +35,73 @@ import org.sonar.batch.protocol.output.BatchReport;
import javax.annotation.Nullable;
+import java.util.Collection;
import java.util.Date;
+import java.util.Iterator;
public class IssuesPublisher implements ReportPublisher {
private final ResourceCache resourceCache;
private final IssueCache issueCache;
+ private final ProjectReactor reactor;
- public IssuesPublisher(ResourceCache resourceCache, IssueCache issueCache) {
+ public IssuesPublisher(ProjectReactor reactor, ResourceCache resourceCache, IssueCache issueCache) {
+ this.reactor = reactor;
this.resourceCache = resourceCache;
this.issueCache = issueCache;
}
@Override
public void publish(BatchOutputWriter writer) {
+ Collection<Object> deletedComponentKeys = issueCache.componentKeys();
for (BatchResource resource : resourceCache.all()) {
- Iterable<DefaultIssue> issues = issueCache.byComponent(resource.resource().getEffectiveKey());
+ String componentKey = resource.resource().getEffectiveKey();
+ Iterable<DefaultIssue> issues = issueCache.byComponent(componentKey);
writer.writeComponentIssues(resource.batchId(), Iterables.transform(issues, new Function<DefaultIssue, BatchReport.Issue>() {
@Override
public BatchReport.Issue apply(DefaultIssue input) {
return toReportIssue(input);
}
}));
+ deletedComponentKeys.remove(componentKey);
}
+
+ int count = exportIssuesOfDeletedComponents(deletedComponentKeys, writer);
+
+ exportMetadata(writer, count);
+ }
+
+ private void exportMetadata(BatchOutputWriter writer, int count) {
+ BatchResource rootProject = resourceCache.get(reactor.getRoot().getKeyWithBranch());
+ BatchReport.Metadata.Builder builder = BatchReport.Metadata.newBuilder()
+ .setAnalysisDate(((Project) rootProject.resource()).getAnalysisDate().getTime())
+ .setProjectKey(((Project) rootProject.resource()).key())
+ .setRootComponentRef(rootProject.batchId())
+ .setDeletedComponentsCount(count);
+ Integer sid = rootProject.snapshotId();
+ if (sid != null) {
+ builder.setSnapshotId(sid);
+ }
+ writer.writeMetadata(builder.build());
+ }
+
+ private int exportIssuesOfDeletedComponents(Collection<Object> deletedComponentKeys, BatchOutputWriter writer) {
+ int deletedComponentCount = 0;
+ for (Object componentKey : deletedComponentKeys) {
+ deletedComponentCount++;
+ Iterable<DefaultIssue> issues = issueCache.byComponent(componentKey.toString());
+ Iterator<DefaultIssue> iterator = issues.iterator();
+ if (iterator.hasNext()) {
+ String componentUuid = iterator.next().componentUuid();
+ writer.writeDeletedComponentIssues(deletedComponentCount, componentUuid, Iterables.transform(issues, new Function<DefaultIssue, BatchReport.Issue>() {
+ @Override
+ public BatchReport.Issue apply(DefaultIssue input) {
+ return toReportIssue(input);
+ }
+ }));
+ }
+ }
+ return deletedComponentCount;
}
private BatchReport.Issue toReportIssue(DefaultIssue issue) {
diff --git a/sonar-batch/src/test/java/org/sonar/batch/report/IssuesPublisherTest.java b/sonar-batch/src/test/java/org/sonar/batch/report/IssuesPublisherTest.java
new file mode 100644
index 00000000000..2674e1ddc78
--- /dev/null
+++ b/sonar-batch/src/test/java/org/sonar/batch/report/IssuesPublisherTest.java
@@ -0,0 +1,166 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 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.report;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.bootstrap.ProjectDefinition;
+import org.sonar.api.batch.bootstrap.ProjectReactor;
+import org.sonar.api.database.model.Snapshot;
+import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.api.resources.Project;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.utils.Duration;
+import org.sonar.batch.index.ResourceCache;
+import org.sonar.batch.issue.IssueCache;
+import org.sonar.batch.protocol.output.BatchOutputWriter;
+import org.sonar.batch.protocol.output.BatchReport.Metadata;
+import org.sonar.batch.protocol.output.BatchReportReader;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class IssuesPublisherTest {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ private IssueCache issueCache;
+ private IssuesPublisher publisher;
+
+ @Before
+ public void prepare() {
+ ProjectDefinition root = ProjectDefinition.create().setKey("foo");
+ Project p = new Project("foo").setAnalysisDate(new Date(1234567L));
+ ResourceCache resourceCache = new ResourceCache();
+ org.sonar.api.resources.Resource sampleFile = org.sonar.api.resources.File.create("src/Foo.php").setEffectiveKey("foo:src/Foo.php");
+ resourceCache.add(p, null).setSnapshot(new Snapshot().setId(2));
+ resourceCache.add(sampleFile, null);
+ issueCache = mock(IssueCache.class);
+ when(issueCache.byComponent(anyString())).thenReturn(Collections.<DefaultIssue>emptyList());
+ publisher = new IssuesPublisher(new ProjectReactor(root), resourceCache, issueCache);
+ }
+
+ @Test
+ public void publishIssuesAndMetadata() throws Exception {
+
+ DefaultIssue issue1 = new DefaultIssue();
+ issue1.setKey("uuid");
+ issue1.setSeverity("MAJOR");
+ issue1.setRuleKey(RuleKey.of("repo", "rule"));
+ DefaultIssue issue2 = new DefaultIssue();
+ issue2.setKey("uuid2");
+ issue2.setSeverity("MAJOR");
+ issue2.setRuleKey(RuleKey.of("repo", "rule"));
+ issue2.setLine(2);
+ issue2.setMessage("msg");
+ issue2.setEffortToFix(2d);
+ issue2.setDebt(Duration.create(2));
+ issue2.setResolution("FIXED");
+ issue2.setStatus("RESOLVED");
+ issue2.setChecksum("checksum");
+ issue2.setReporter("reporter");
+ issue2.setAssignee("assignee");
+ issue2.setActionPlanKey("action");
+ issue2.setAuthorLogin("author");
+ issue2.setCurrentChange(new FieldDiffs().setUserLogin("foo"));
+ issue2.setCreationDate(new Date());
+ issue2.setUpdateDate(new Date());
+ issue2.setCloseDate(new Date());
+ issue2.setSelectedAt(1234L);
+ when(issueCache.byComponent("foo:src/Foo.php")).thenReturn(Arrays.asList(issue1, issue2));
+
+ File outputDir = temp.newFolder();
+ BatchOutputWriter writer = new BatchOutputWriter(outputDir);
+
+ publisher.publish(writer);
+
+ BatchReportReader reader = new BatchReportReader(outputDir);
+ Metadata metadata = reader.readMetadata();
+ assertThat(metadata.getAnalysisDate()).isEqualTo(1234567L);
+ assertThat(metadata.getProjectKey()).isEqualTo("foo");
+ assertThat(metadata.getDeletedComponentsCount()).isEqualTo(0);
+ assertThat(metadata.getSnapshotId()).isEqualTo(2);
+
+ assertThat(reader.readComponentIssues(1)).hasSize(0);
+ assertThat(reader.readComponentIssues(2)).hasSize(2);
+
+ }
+
+ @Test
+ public void publishIssuesOfDeletedComponents() throws Exception {
+
+ DefaultIssue issue1 = new DefaultIssue();
+ issue1.setKey("uuid");
+ issue1.setComponentUuid("deletedUuid");
+ issue1.setSeverity("MAJOR");
+ issue1.setRuleKey(RuleKey.of("repo", "rule"));
+ DefaultIssue issue2 = new DefaultIssue();
+ issue2.setKey("uuid2");
+ issue2.setComponentUuid("deletedUuid");
+ issue2.setSeverity("MAJOR");
+ issue2.setRuleKey(RuleKey.of("repo", "rule"));
+ issue2.setLine(2);
+ issue2.setMessage("msg");
+ issue2.setEffortToFix(2d);
+ issue2.setDebt(Duration.create(2));
+ issue2.setResolution("FIXED");
+ issue2.setStatus("RESOLVED");
+ issue2.setChecksum("checksum");
+ issue2.setReporter("reporter");
+ issue2.setAssignee("assignee");
+ issue2.setActionPlanKey("action");
+ issue2.setAuthorLogin("author");
+ issue2.setCurrentChange(new FieldDiffs().setUserLogin("foo"));
+ issue2.setCreationDate(new Date());
+ issue2.setUpdateDate(new Date());
+ issue2.setCloseDate(new Date());
+ issue2.setSelectedAt(1234L);
+
+ when(issueCache.byComponent("foo:deleted.php")).thenReturn(Arrays.asList(issue1, issue2));
+
+ when(issueCache.componentKeys()).thenReturn(Arrays.<Object>asList("foo:deleted.php"));
+
+ File outputDir = temp.newFolder();
+ BatchOutputWriter writer = new BatchOutputWriter(outputDir);
+
+ publisher.publish(writer);
+
+ BatchReportReader reader = new BatchReportReader(outputDir);
+ Metadata metadata = reader.readMetadata();
+ assertThat(metadata.getDeletedComponentsCount()).isEqualTo(1);
+
+ assertThat(reader.readComponentIssues(1)).hasSize(0);
+ assertThat(reader.readComponentIssues(2)).hasSize(0);
+ assertThat(reader.readDeletedComponentIssues(1).getComponentUuid()).isEqualTo("deletedUuid");
+ assertThat(reader.readDeletedComponentIssues(1).getListList()).hasSize(2);
+
+ }
+}