From f55d531dec9879f047463e60d916f3b6f7921737 Mon Sep 17 00:00:00 2001 From: Julien HENRY Date: Thu, 8 Jan 2015 15:53:13 +0100 Subject: [PATCH] SONAR-5945 Change format of batch report --- .../computation/AnalysisReportService.java | 63 ++----- .../computation/ComputeEngineContext.java | 17 +- .../computation/step/CleanReportStep.java | 2 +- .../AnalysisReportServiceTest.java | 28 ++- .../ComputeEngineIssueStorageTest.java | 3 +- .../computation/step/CleanReportStepTest.java | 13 +- .../{issues.json => 1/issues-1.json} | 0 sonar-batch-protocol/pom.xml | 4 + .../batch/protocol/output/ReportHelper.java | 163 ++++++++++++++++++ .../ReportComponent.java | 2 +- .../ReportComponents.java | 2 +- .../{resource => component}/package-info.java | 2 +- .../protocol/output/ReportHelperTest.java | 55 ++++++ .../ReportComponentsTest.java | 8 +- .../ReportComponentsTest}/expected.json | 0 .../batch/report/ComponentsPublisher.java | 13 +- .../sonar/batch/report/IssuesPublisher.java | 33 ++-- .../sonar/batch/report/PublishReportJob.java | 4 +- .../sonar/batch/report/ReportPublisher.java | 5 +- .../batch/report/ComponentsPublisherTest.java | 7 +- 20 files changed, 323 insertions(+), 101 deletions(-) rename server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/report-folder/{issues.json => 1/issues-1.json} (100%) create mode 100644 sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/ReportHelper.java rename sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/{resource => component}/ReportComponent.java (98%) rename sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/{resource => component}/ReportComponents.java (96%) rename sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/{resource => component}/package-info.java (95%) create mode 100644 sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/ReportHelperTest.java rename sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/{resource => component}/ReportComponentsTest.java (93%) rename sonar-batch-protocol/src/test/resources/org/sonar/batch/protocol/output/{resource/ReportResourceTest => component/ReportComponentsTest}/expected.json (100%) diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/AnalysisReportService.java b/server/sonar-server/src/main/java/org/sonar/server/computation/AnalysisReportService.java index 14e6a66458b..3a3c1056fed 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/AnalysisReportService.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/AnalysisReportService.java @@ -20,11 +20,13 @@ package org.sonar.server.computation; +import org.sonar.batch.protocol.output.component.ReportComponent; + import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Function; +import com.google.common.collect.Iterables; import com.google.gson.Gson; -import com.google.gson.stream.JsonReader; import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.ServerComponent; @@ -34,9 +36,8 @@ import org.sonar.api.rule.RuleKey; import org.sonar.api.utils.Duration; import org.sonar.api.utils.KeyValueFormat; import org.sonar.batch.protocol.GsonHelper; +import org.sonar.batch.protocol.output.ReportHelper; import org.sonar.batch.protocol.output.issue.ReportIssue; -import org.sonar.batch.protocol.output.resource.ReportComponent; -import org.sonar.batch.protocol.output.resource.ReportComponents; import org.sonar.core.computation.db.AnalysisReportDto; import org.sonar.core.issue.db.IssueStorage; import org.sonar.core.persistence.DbSession; @@ -44,10 +45,9 @@ import org.sonar.server.db.DbClient; import javax.annotation.Nullable; -import java.io.*; -import java.util.ArrayList; +import java.io.File; +import java.io.IOException; import java.util.Date; -import java.util.List; public class AnalysisReportService implements ServerComponent { private static final Logger LOG = LoggerFactory.getLogger(AnalysisReportService.class); @@ -64,22 +64,13 @@ public class AnalysisReportService implements ServerComponent { public void digest(DbSession session, ComputeEngineContext context) { decompress(session, context); - loadResources(context); + loadComponents(context); saveIssues(context); } @VisibleForTesting - void loadResources(ComputeEngineContext context) { - File file = new File(context.getReportDirectory(), "components.json"); - - try (InputStream resourcesStream = new FileInputStream(file)) { - String json = IOUtils.toString(resourcesStream); - ReportComponents reportComponents = ReportComponents.fromJson(json); - context.addResources(reportComponents); - } catch (IOException e) { - throw new IllegalStateException("Failed to read issues", e); - } - + void loadComponents(ComputeEngineContext context) { + context.addResources(context.getReportHelper().getComponents()); } @VisibleForTesting @@ -87,40 +78,24 @@ public class AnalysisReportService implements ServerComponent { AnalysisReportDto report = context.getReportDto(); File decompressedDirectory = dbClient.analysisReportDao().getDecompressedReport(session, report.getId()); - context.setReportDirectory(decompressedDirectory); + context.setReportHelper(ReportHelper.create(decompressedDirectory)); } @VisibleForTesting - void saveIssues(ComputeEngineContext context) { + void saveIssues(final ComputeEngineContext context) { IssueStorage issueStorage = issueStorageFactory.newComputeEngineIssueStorage(context.getProject()); - File issuesFile = new File(context.getReportDirectory(), "issues.json"); - List issues = new ArrayList<>(MAX_ISSUES_SIZE); - - try (InputStream issuesStream = new FileInputStream(issuesFile); - JsonReader reader = new JsonReader(new InputStreamReader(issuesStream))) { - reader.beginArray(); - while (reader.hasNext()) { - ReportIssue reportIssue = gson.fromJson(reader, ReportIssue.class); - DefaultIssue defaultIssue = toIssue(context, reportIssue); - issues.add(defaultIssue); - if (shouldPersistIssues(issues, reader)) { - issueStorage.save(issues); - issues.clear(); + for (ReportComponent component : context.getComponents().values()) { + Iterable reportIssues = context.getReportHelper().getIssues(component.batchId()); + issueStorage.save(Iterables.transform(reportIssues, new Function() { + @Override + public DefaultIssue apply(ReportIssue input) { + return toIssue(context, input); } - } - - reader.endArray(); - reader.close(); - } catch (IOException e) { - throw new IllegalStateException("Failed to read issues", e); + })); } } - private boolean shouldPersistIssues(List issues, JsonReader reader) throws IOException { - return issues.size() == MAX_ISSUES_SIZE || !reader.hasNext(); - } - private DefaultIssue toIssue(ComputeEngineContext context, ReportIssue issue) { DefaultIssue defaultIssue = new DefaultIssue(); defaultIssue.setKey(issue.key()); diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ComputeEngineContext.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ComputeEngineContext.java index 09aa16566fa..af2da0157c8 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/ComputeEngineContext.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/ComputeEngineContext.java @@ -20,16 +20,17 @@ package org.sonar.server.computation; +import org.sonar.batch.protocol.output.component.ReportComponent; +import org.sonar.batch.protocol.output.component.ReportComponents; + import com.google.common.annotations.VisibleForTesting; -import org.sonar.batch.protocol.output.resource.ReportComponent; -import org.sonar.batch.protocol.output.resource.ReportComponents; +import org.sonar.batch.protocol.output.ReportHelper; import org.sonar.core.component.ComponentDto; import org.sonar.core.computation.db.AnalysisReportDto; import javax.annotation.CheckForNull; import javax.annotation.Nullable; -import java.io.File; import java.util.Date; import java.util.HashMap; import java.util.Map; @@ -38,7 +39,7 @@ public class ComputeEngineContext { private final AnalysisReportDto reportDto; private final ComponentDto project; - private File reportDirectory; + private ReportHelper reportHelper; private Map components = new HashMap<>(); private Date analysisDate; @@ -55,12 +56,12 @@ public class ComputeEngineContext { return project; } - public File getReportDirectory() { - return reportDirectory; + public ReportHelper getReportHelper() { + return reportHelper; } - public void setReportDirectory(@Nullable File reportDirectory) { - this.reportDirectory = reportDirectory; + public void setReportHelper(@Nullable ReportHelper reportHelper) { + this.reportHelper = reportHelper; } public void addResources(ReportComponents reportComponents) { diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/CleanReportStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/CleanReportStep.java index 8bf6be6c020..b88abbb4e1b 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/CleanReportStep.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/CleanReportStep.java @@ -33,7 +33,7 @@ public class CleanReportStep implements ComputationStep { @Override public void execute(DbSession session, ComputeEngineContext context) { - reportService.deleteDirectory(context.getReportDirectory()); + reportService.deleteDirectory(context.getReportHelper().reportRootDir()); } @Override diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/AnalysisReportServiceTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/AnalysisReportServiceTest.java index 483f2367100..db4fccfbdc8 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/AnalysisReportServiceTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/AnalysisReportServiceTest.java @@ -20,13 +20,18 @@ package org.sonar.server.computation; +import org.sonar.batch.protocol.output.component.ReportComponent; +import org.sonar.batch.protocol.output.component.ReportComponents; + import com.google.common.collect.Lists; import org.apache.commons.io.FileUtils; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TemporaryFolder; import org.sonar.api.issue.internal.DefaultIssue; import org.sonar.api.rules.RuleFinder; -import org.sonar.batch.protocol.output.resource.ReportComponent; +import org.sonar.batch.protocol.output.ReportHelper; import org.sonar.core.component.ComponentDto; import org.sonar.core.computation.db.AnalysisReportDto; import org.sonar.core.issue.db.IssueStorage; @@ -40,9 +45,16 @@ import java.util.List; import static org.fest.assertions.Assertions.assertThat; import static org.mockito.Matchers.any; -import static org.mockito.Mockito.*; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; public class AnalysisReportServiceTest { + + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + private AnalysisReportService sut; private IssueStorage issueStorage; @@ -64,6 +76,8 @@ public class AnalysisReportServiceTest { AnalysisReportDto report = AnalysisReportDto.newForTests(123L); ComputeEngineContext context = new ComputeEngineContext(report, mock(ComponentDto.class)); + when(dao.getDecompressedReport(any(DbSession.class), eq(123L))).thenReturn(temp.newFile()); + sut.decompress(mock(DbSession.class), context); verify(dao).getDecompressedReport(any(DbSession.class), eq(123L)); @@ -87,11 +101,11 @@ public class AnalysisReportServiceTest { } @Test - public void load_resources() throws Exception { + public void load_components() throws Exception { ComputeEngineContext context = new ComputeEngineContext(mock(AnalysisReportDto.class), mock(ComponentDto.class)); - context.setReportDirectory(new File(getClass().getResource("/org/sonar/server/computation/AnalysisReportServiceTest/report-folder").getFile())); + context.setReportHelper(ReportHelper.create(new File(getClass().getResource("/org/sonar/server/computation/AnalysisReportServiceTest/report-folder").getFile()))); - sut.loadResources(context); + sut.loadComponents(context); assertThat(context.getComponents()).hasSize(4); } @@ -99,7 +113,9 @@ public class AnalysisReportServiceTest { @Test public void save_issues() throws Exception { ComputeEngineContext context = new FakeComputeEngineContext(); - context.setReportDirectory(new File(getClass().getResource("/org/sonar/server/computation/AnalysisReportServiceTest/report-folder").getFile())); + context.setReportHelper(ReportHelper.create(new File(getClass().getResource("/org/sonar/server/computation/AnalysisReportServiceTest/report-folder").getFile()))); + + context.addResources(new ReportComponents().setRoot(new ReportComponent().setBatchId(1))); sut.saveIssues(context); diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ComputeEngineIssueStorageTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ComputeEngineIssueStorageTest.java index 23ad7910b25..933ff910566 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/ComputeEngineIssueStorageTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/ComputeEngineIssueStorageTest.java @@ -20,6 +20,8 @@ package org.sonar.server.computation; +import org.sonar.batch.protocol.output.component.ReportComponent; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -33,7 +35,6 @@ import org.sonar.api.rules.RuleQuery; import org.sonar.api.utils.DateUtils; import org.sonar.api.utils.Duration; import org.sonar.api.utils.System2; -import org.sonar.batch.protocol.output.resource.ReportComponent; import org.sonar.core.component.ComponentDto; import org.sonar.core.persistence.AbstractDaoTestCase; import org.sonar.core.persistence.DbSession; diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/CleanReportStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/CleanReportStepTest.java index dc7b8881b41..59e9ae30fbb 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/CleanReportStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/CleanReportStepTest.java @@ -20,7 +20,10 @@ package org.sonar.server.computation.step; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.sonar.batch.protocol.output.ReportHelper; import org.sonar.core.persistence.DbSession; import org.sonar.server.computation.AnalysisReportService; import org.sonar.server.computation.ComputeEngineContext; @@ -30,8 +33,13 @@ import java.io.File; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; public class CleanReportStepTest { + + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + CleanReportStep sut; @Test @@ -39,7 +47,10 @@ public class CleanReportStepTest { AnalysisReportService service = mock(AnalysisReportService.class); sut = new CleanReportStep(service); - sut.execute(mock(DbSession.class), mock(ComputeEngineContext.class)); + ComputeEngineContext context = mock(ComputeEngineContext.class); + when(context.getReportHelper()).thenReturn(ReportHelper.create(temp.newFolder())); + + sut.execute(mock(DbSession.class), context); verify(service).deleteDirectory(any(File.class)); } diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/report-folder/issues.json b/server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/report-folder/1/issues-1.json similarity index 100% rename from server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/report-folder/issues.json rename to server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/report-folder/1/issues-1.json diff --git a/sonar-batch-protocol/pom.xml b/sonar-batch-protocol/pom.xml index 3584c2d52d3..a221b25fbe6 100644 --- a/sonar-batch-protocol/pom.xml +++ b/sonar-batch-protocol/pom.xml @@ -22,6 +22,10 @@ jsr305 provided + + commons-io + commons-io + diff --git a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/ReportHelper.java b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/ReportHelper.java new file mode 100644 index 00000000000..f407a4a3f01 --- /dev/null +++ b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/ReportHelper.java @@ -0,0 +1,163 @@ +/* + * 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.protocol.output; + +import org.sonar.batch.protocol.output.component.ReportComponents; + +import com.google.gson.Gson; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.sonar.batch.protocol.GsonHelper; +import org.sonar.batch.protocol.output.issue.ReportIssue; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.util.Iterator; + +public class ReportHelper { + + private static final String COMPONENTS_JSON = "components.json"; + private final File reportRootDir; + private final Gson gson = GsonHelper.create(); + + private ReportHelper(File reportRootDir) { + this.reportRootDir = reportRootDir; + } + + public static ReportHelper create(File workDirectory) { + if (!workDirectory.exists() && !workDirectory.mkdirs()) { + throw new IllegalStateException("Unable to create directory " + workDirectory); + } + return new ReportHelper(workDirectory); + } + + public File reportRootDir() { + return reportRootDir; + } + + public void saveComponents(ReportComponents components) { + File resourcesFile = new File(reportRootDir, COMPONENTS_JSON); + try { + FileUtils.write(resourcesFile, components.toJson()); + } catch (IOException e) { + throw new IllegalStateException("Unable to write components", e); + } + } + + public void saveIssues(long componentBatchId, Iterable issues) { + Gson gson = GsonHelper.create(); + File issuesFile = getIssuesFile(componentBatchId); + try (OutputStreamWriter out = new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(issuesFile)), "UTF-8")) { + + JsonWriter writer = new JsonWriter(out); + writer.setIndent(" "); + writer.beginArray(); + for (ReportIssue reportIssue : issues) { + gson.toJson(reportIssue, ReportIssue.class, writer); + } + writer.endArray(); + writer.close(); + } catch (IOException e) { + throw new IllegalStateException("Unable to save issues", e); + } + } + + private File getIssuesFile(long componentBatchId) { + return new File(getComponentFolder(componentBatchId), "issues-" + componentBatchId + ".json"); + } + + private File getComponentFolder(long componentBatchId) { + File folder = new File(reportRootDir, Long.toString(componentBatchId)); + if (!folder.exists() && !folder.mkdir()) { + throw new IllegalStateException("Unable to create directory " + folder); + } + return folder; + } + + public ReportComponents getComponents() { + File file = new File(reportRootDir, COMPONENTS_JSON); + + try (InputStream resourcesStream = new FileInputStream(file)) { + String json = IOUtils.toString(resourcesStream); + return ReportComponents.fromJson(json); + } catch (IOException e) { + throw new IllegalStateException("Failed to read issues", e); + } + } + + public Iterable getIssues(final long componentBatchId) { + + return new Iterable() { + @Override + public Iterator iterator() { + return new ReportIssueIterator(getIssuesFile(componentBatchId)); + } + }; + } + + private final class ReportIssueIterator implements Iterator { + + private JsonReader reader; + + public ReportIssueIterator(File issuesFile) { + try { + reader = new JsonReader(new InputStreamReader(new BufferedInputStream(new FileInputStream(issuesFile)))); + reader.beginArray(); + } catch (IOException e) { + throw new IllegalStateException("Unable to read " + issuesFile, e); + } + } + + @Override + public boolean hasNext() { + try { + if (reader.hasNext()) { + return true; + } + reader.endArray(); + reader.close(); + return false; + } catch (IOException e) { + IOUtils.closeQuietly(reader); + throw new IllegalStateException("Unable to iterate over JSON file ", e); + } + } + + @Override + public ReportIssue next() { + return gson.fromJson(reader, ReportIssue.class); + } + + @Override + public void remove() { + throw new UnsupportedOperationException("remove"); + } + } + +} diff --git a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/resource/ReportComponent.java b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/component/ReportComponent.java similarity index 98% rename from sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/resource/ReportComponent.java rename to sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/component/ReportComponent.java index e9ff00c57ac..37b64b87e47 100644 --- a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/resource/ReportComponent.java +++ b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/component/ReportComponent.java @@ -17,7 +17,7 @@ * 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.protocol.output.resource; +package org.sonar.batch.protocol.output.component; import javax.annotation.CheckForNull; import javax.annotation.Nullable; diff --git a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/resource/ReportComponents.java b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/component/ReportComponents.java similarity index 96% rename from sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/resource/ReportComponents.java rename to sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/component/ReportComponents.java index 5e7b0fb6fdf..5ee00eee71c 100644 --- a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/resource/ReportComponents.java +++ b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/component/ReportComponents.java @@ -17,7 +17,7 @@ * 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.protocol.output.resource; +package org.sonar.batch.protocol.output.component; import org.sonar.batch.protocol.GsonHelper; diff --git a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/resource/package-info.java b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/component/package-info.java similarity index 95% rename from sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/resource/package-info.java rename to sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/component/package-info.java index 5e45e2dee7a..7e8017af61e 100644 --- a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/resource/package-info.java +++ b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/component/package-info.java @@ -18,7 +18,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @ParametersAreNonnullByDefault -package org.sonar.batch.protocol.output.resource; +package org.sonar.batch.protocol.output.component; import javax.annotation.ParametersAreNonnullByDefault; diff --git a/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/ReportHelperTest.java b/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/ReportHelperTest.java new file mode 100644 index 00000000000..2cfc9ef745f --- /dev/null +++ b/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/ReportHelperTest.java @@ -0,0 +1,55 @@ +/* + * 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.protocol.output; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.sonar.batch.protocol.output.component.ReportComponent; +import org.sonar.batch.protocol.output.component.ReportComponents; +import org.sonar.batch.protocol.output.issue.ReportIssue; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; + +import static org.fest.assertions.Assertions.assertThat; + +public class ReportHelperTest { + + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + + @Test + public void createAndRead() throws IOException { + ReportHelper helper = ReportHelper.create(temp.newFolder()); + + helper.saveComponents(new ReportComponents().setRoot(new ReportComponent().setBatchId(1L))); + + helper.saveIssues(1L, Arrays.asList(new ReportIssue().setRuleKey("foo", "bar"))); + + assertThat(new File(helper.reportRootDir(), "components.json")).exists(); + assertThat(new File(helper.reportRootDir(), "1/issues-1.json")).exists(); + + assertThat(helper.getComponents().root().batchId()).isEqualTo(1L); + assertThat(helper.getIssues(1L)).hasSize(1); + } + +} diff --git a/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/resource/ReportComponentsTest.java b/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/component/ReportComponentsTest.java similarity index 93% rename from sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/resource/ReportComponentsTest.java rename to sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/component/ReportComponentsTest.java index b3b989aa8f8..f97cf26b28e 100644 --- a/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/resource/ReportComponentsTest.java +++ b/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/component/ReportComponentsTest.java @@ -17,12 +17,12 @@ * 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.protocol.output.resource; +package org.sonar.batch.protocol.output.component; import org.apache.commons.io.IOUtils; import org.junit.Test; import org.skyscreamer.jsonassert.JSONAssert; -import org.sonar.batch.protocol.output.resource.ReportComponent.Type; +import org.sonar.batch.protocol.output.component.ReportComponent.Type; import java.text.SimpleDateFormat; import java.util.Date; @@ -72,7 +72,7 @@ public class ReportComponentsTest { JSONAssert .assertEquals( - IOUtils.toString(this.getClass().getResourceAsStream("ReportResourceTest/expected.json"), "UTF-8"), + IOUtils.toString(this.getClass().getResourceAsStream("ReportComponentsTest/expected.json"), "UTF-8"), res.toJson(), true); } @@ -80,7 +80,7 @@ public class ReportComponentsTest { public void from_json() throws Exception { ReportComponents res = ReportComponents .fromJson( - IOUtils.toString(this.getClass().getResourceAsStream("ReportResourceTest/expected.json"), "UTF-8")); + IOUtils.toString(this.getClass().getResourceAsStream("ReportComponentsTest/expected.json"), "UTF-8")); assertThat(res.analysisDate()).isEqualTo(new SimpleDateFormat("dd/MM/yyyy").parse("12/12/2012")); ReportComponent root = res.root(); diff --git a/sonar-batch-protocol/src/test/resources/org/sonar/batch/protocol/output/resource/ReportResourceTest/expected.json b/sonar-batch-protocol/src/test/resources/org/sonar/batch/protocol/output/component/ReportComponentsTest/expected.json similarity index 100% rename from sonar-batch-protocol/src/test/resources/org/sonar/batch/protocol/output/resource/ReportResourceTest/expected.json rename to sonar-batch-protocol/src/test/resources/org/sonar/batch/protocol/output/component/ReportComponentsTest/expected.json 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 8e617830527..2117266659a 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 @@ -19,7 +19,9 @@ */ package org.sonar.batch.report; -import org.apache.commons.io.FileUtils; +import org.sonar.batch.protocol.output.component.ReportComponent; +import org.sonar.batch.protocol.output.component.ReportComponents; + import org.sonar.api.batch.bootstrap.ProjectReactor; import org.sonar.api.resources.Language; import org.sonar.api.resources.Project; @@ -27,12 +29,10 @@ import org.sonar.api.resources.Resource; import org.sonar.api.resources.ResourceUtils; import org.sonar.batch.index.BatchResource; import org.sonar.batch.index.ResourceCache; -import org.sonar.batch.protocol.output.resource.ReportComponent; -import org.sonar.batch.protocol.output.resource.ReportComponents; +import org.sonar.batch.protocol.output.ReportHelper; import javax.annotation.CheckForNull; -import java.io.File; import java.io.IOException; public class ComponentsPublisher implements ReportPublisher { @@ -46,13 +46,12 @@ public class ComponentsPublisher implements ReportPublisher { } @Override - public void export(File reportDir) throws IOException { + public void export(ReportHelper reportHelper) throws IOException { ReportComponents components = new ReportComponents(); BatchResource rootProject = resourceCache.get(reactor.getRoot().getKeyWithBranch()); components.setRoot(buildResourceForReport(rootProject)); components.setAnalysisDate(((Project) rootProject.resource()).getAnalysisDate()); - File resourcesFile = new File(reportDir, "components.json"); - FileUtils.write(resourcesFile, components.toJson()); + reportHelper.saveComponents(components); } private ReportComponent buildResourceForReport(BatchResource batchResource) { 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 290820d11bc..5399b1ac149 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 @@ -19,23 +19,18 @@ */ package org.sonar.batch.report; -import com.google.gson.Gson; -import com.google.gson.stream.JsonWriter; +import com.google.common.base.Function; +import com.google.common.collect.Iterables; import org.sonar.api.issue.internal.DefaultIssue; import org.sonar.api.issue.internal.FieldDiffs; import org.sonar.api.utils.KeyValueFormat; import org.sonar.batch.index.BatchResource; import org.sonar.batch.index.ResourceCache; import org.sonar.batch.issue.IssueCache; -import org.sonar.batch.protocol.GsonHelper; +import org.sonar.batch.protocol.output.ReportHelper; import org.sonar.batch.protocol.output.issue.ReportIssue; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; public class IssuesPublisher implements ReportPublisher { @@ -48,20 +43,16 @@ public class IssuesPublisher implements ReportPublisher { } @Override - public void export(File reportDir) throws IOException { - Gson gson = GsonHelper.create(); - File issuesFile = new File(reportDir, "issues.json"); - OutputStream out = new BufferedOutputStream(new FileOutputStream(issuesFile)); - - JsonWriter writer = new JsonWriter(new OutputStreamWriter(out, "UTF-8")); - writer.setIndent(" "); - writer.beginArray(); - for (DefaultIssue issue : issueCache.all()) { - ReportIssue reportIssue = toReportIssue(issue); - gson.toJson(reportIssue, ReportIssue.class, writer); + public void export(ReportHelper reportHelper) throws IOException { + for (BatchResource resource : resourceCache.all()) { + Iterable issues = issueCache.byComponent(resource.resource().getEffectiveKey()); + reportHelper.saveIssues(resource.batchId(), Iterables.transform(issues, new Function() { + @Override + public ReportIssue apply(DefaultIssue input) { + return toReportIssue(input); + } + })); } - writer.endArray(); - writer.close(); } private ReportIssue toReportIssue(DefaultIssue issue) { diff --git a/sonar-batch/src/main/java/org/sonar/batch/report/PublishReportJob.java b/sonar-batch/src/main/java/org/sonar/batch/report/PublishReportJob.java index 6f2242a2ca7..22aa61b0d1a 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/report/PublishReportJob.java +++ b/sonar-batch/src/main/java/org/sonar/batch/report/PublishReportJob.java @@ -34,6 +34,7 @@ import org.sonar.api.utils.ZipUtils; import org.sonar.batch.bootstrap.AnalysisMode; import org.sonar.batch.bootstrap.ServerClient; import org.sonar.batch.index.ResourceCache; +import org.sonar.batch.protocol.output.ReportHelper; import java.io.File; import java.io.IOException; @@ -83,8 +84,9 @@ public class PublishReportJob implements BatchComponent { private File prepareReport() { try { File reportDir = temp.newDir("batch-report"); + ReportHelper reportHelper = ReportHelper.create(reportDir); for (ReportPublisher publisher : publishers) { - publisher.export(reportDir); + publisher.export(reportHelper); } File reportZip = temp.newFile("batch-report", ".zip"); diff --git a/sonar-batch/src/main/java/org/sonar/batch/report/ReportPublisher.java b/sonar-batch/src/main/java/org/sonar/batch/report/ReportPublisher.java index c9d42f0a849..32f93f64f10 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/report/ReportPublisher.java +++ b/sonar-batch/src/main/java/org/sonar/batch/report/ReportPublisher.java @@ -19,11 +19,12 @@ */ package org.sonar.batch.report; -import java.io.File; +import org.sonar.batch.protocol.output.ReportHelper; + import java.io.IOException; public interface ReportPublisher { - void export(File reportDir) throws IOException; + void export(ReportHelper reportHelper) throws IOException; } diff --git a/sonar-batch/src/test/java/org/sonar/batch/report/ComponentsPublisherTest.java b/sonar-batch/src/test/java/org/sonar/batch/report/ComponentsPublisherTest.java index 8c2722d11bc..b9c0cebea72 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/report/ComponentsPublisherTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/report/ComponentsPublisherTest.java @@ -35,6 +35,7 @@ import org.sonar.api.resources.Project; import org.sonar.api.resources.Qualifiers; import org.sonar.api.resources.Scopes; import org.sonar.batch.index.ResourceCache; +import org.sonar.batch.protocol.output.ReportHelper; import java.io.File; import java.text.SimpleDateFormat; @@ -75,7 +76,8 @@ public class ComponentsPublisherTest { resourceCache.add(testFile, dir2).setSnapshot(new Snapshot().setId(16)); File exportDir = temp.newFolder(); - publisher.export(exportDir); + ReportHelper helper = ReportHelper.create(exportDir); + publisher.export(helper); JSONAssert .assertEquals( @@ -100,7 +102,8 @@ public class ComponentsPublisherTest { resourceCache.add(mainFile, view).setSnapshot(new Snapshot().setId(12)); File exportDir = temp.newFolder(); - publisher.export(exportDir); + ReportHelper helper = ReportHelper.create(exportDir); + publisher.export(helper); JSONAssert .assertEquals( -- 2.39.5