From: Julien HENRY Date: Thu, 8 Jan 2015 14:53:13 +0000 (+0100) Subject: SONAR-5945 Change format of batch report X-Git-Tag: latest-silver-master-#65~283 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=f55d531dec9879f047463e60d916f3b6f7921737;p=sonarqube.git SONAR-5945 Change format of batch report --- 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/1/issues-1.json b/server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/report-folder/1/issues-1.json new file mode 100644 index 00000000000..fa3eec4d9f7 --- /dev/null +++ b/server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/report-folder/1/issues-1.json @@ -0,0 +1,182 @@ +[ + { + "isNew": false, + "key": "key", + "manualSeverity": false, + "assignee": "Assignee", + "attributes": "attributes", + "authorLogin": "login", + "isChanged": true, + "ruleKey": "ruleKey", + "ruleRepo": "local", + "severity": "INFO", + "message": "message", + "line": 25, + "effortToFix": 30, + "debtInMinutes": 25, + "status": "NEW", + "resolution": "Non Solved", + "reporter": "reporter", + "assignee": "assignee", + "checkSum": "checkSum", + "attributes": "toto=25", + "authorLogin": "author", + "actionPlanKey": "actionPlanKey", + "creationDate": "2014-12-19T00:03:14+0100", + "updateDate": "2014-12-19T00:03:14+0100", + "closeDate": "2014-12-19T00:03:14+0100", + "currentChange": "coucou,c'est,nous", + "isChange": false, + "selectAt": 564897564 + }, + { + "isNew": false, + "key": "key", + "manualSeverity": false, + "assignee": "Assignee", + "attributes": "attributes", + "authorLogin": "login", + "isChanged": true, + "ruleKey": "ruleKey", + "ruleRepo": "local", + "severity": "INFO", + "message": "message", + "line": 25, + "effortToFix": 30, + "debtInMinutes": 25, + "status": "NEW", + "resolution": "Non Solved", + "reporter": "reporter", + "assignee": "assignee", + "checkSum": "checkSum", + "attributes": "toto=25", + "authorLogin": "author", + "actionPlanKey": "actionPlanKey", + "creationDate": "2014-12-19T00:03:14+0100", + "updateDate": "2014-12-19T00:03:14+0100", + "closeDate": "2014-12-19T00:03:14+0100", + "currentChange": "coucou,c'est,nous", + "isChange": false, + "selectAt": 564897564 + }, + { + "isNew": false, + "key": "key", + "manualSeverity": false, + "assignee": "Assignee", + "attributes": "attributes", + "authorLogin": "login", + "isChanged": true, + "ruleKey": "ruleKey", + "ruleRepo": "local", + "severity": "INFO", + "message": "message", + "line": 25, + "effortToFix": 30, + "debtInMinutes": 25, + "status": "NEW", + "resolution": "Non Solved", + "reporter": "reporter", + "assignee": "assignee", + "checkSum": "checkSum", + "attributes": "toto=25", + "authorLogin": "author", + "actionPlanKey": "actionPlanKey", + "creationDate": "2014-12-19T00:03:14+0100", + "updateDate": "2014-12-19T00:03:14+0100", + "closeDate": "2014-12-19T00:03:14+0100", + "currentChange": "coucou,c'est,nous", + "isChange": false, + "selectAt": 564897564 + }, + { + "isNew": false, + "key": "key", + "manualSeverity": false, + "assignee": "Assignee", + "attributes": "attributes", + "authorLogin": "login", + "isChanged": true, + "ruleKey": "ruleKey", + "ruleRepo": "local", + "severity": "INFO", + "message": "message", + "line": 25, + "effortToFix": 30, + "debtInMinutes": 25, + "status": "NEW", + "resolution": "Non Solved", + "reporter": "reporter", + "assignee": "assignee", + "checkSum": "checkSum", + "attributes": "toto=25", + "authorLogin": "author", + "actionPlanKey": "actionPlanKey", + "creationDate": "2014-12-19T00:03:14+0100", + "updateDate": "2014-12-19T00:03:14+0100", + "closeDate": "2014-12-19T00:03:14+0100", + "currentChange": "coucou,c'est,nous", + "isChange": false, + "selectAt": 564897564 + }, + { + "isNew": false, + "key": "key", + "manualSeverity": false, + "assignee": "Assignee", + "attributes": "attributes", + "authorLogin": "login", + "isChanged": true, + "ruleKey": "ruleKey", + "ruleRepo": "local", + "severity": "INFO", + "message": "message", + "line": 25, + "effortToFix": 30, + "debtInMinutes": 25, + "status": "NEW", + "resolution": "Non Solved", + "reporter": "reporter", + "assignee": "assignee", + "checkSum": "checkSum", + "attributes": "toto=25", + "authorLogin": "author", + "actionPlanKey": "actionPlanKey", + "creationDate": "2014-12-19T00:03:14+0100", + "updateDate": "2014-12-19T00:03:14+0100", + "closeDate": "2014-12-19T00:03:14+0100", + "currentChange": "coucou,c'est,nous", + "isChange": false, + "selectAt": 564897564 + }, + { + "isNew": false, + "key": "key", + "manualSeverity": false, + "assignee": "Assignee", + "attributes": "attributes", + "authorLogin": "login", + "isChanged": true, + "ruleKey": "ruleKey", + "ruleRepo": "local", + "severity": "INFO", + "message": "message", + "line": 25, + "effortToFix": 30, + "debtInMinutes": 25, + "status": "NEW", + "resolution": "Non Solved", + "reporter": "reporter", + "assignee": "assignee", + "checkSum": "checkSum", + "attributes": "toto=25", + "authorLogin": "author", + "actionPlanKey": "actionPlanKey", + "creationDate": "2014-12-19T00:03:14+0100", + "updateDate": "2014-12-19T00:03:14+0100", + "closeDate": "2014-12-19T00:03:14+0100", + "currentChange": "coucou,c'est,nous", + "isChange": false, + "selectAt": 564897564 + } +] \ No newline at end of file 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/issues.json deleted file mode 100644 index fa3eec4d9f7..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/report-folder/issues.json +++ /dev/null @@ -1,182 +0,0 @@ -[ - { - "isNew": false, - "key": "key", - "manualSeverity": false, - "assignee": "Assignee", - "attributes": "attributes", - "authorLogin": "login", - "isChanged": true, - "ruleKey": "ruleKey", - "ruleRepo": "local", - "severity": "INFO", - "message": "message", - "line": 25, - "effortToFix": 30, - "debtInMinutes": 25, - "status": "NEW", - "resolution": "Non Solved", - "reporter": "reporter", - "assignee": "assignee", - "checkSum": "checkSum", - "attributes": "toto=25", - "authorLogin": "author", - "actionPlanKey": "actionPlanKey", - "creationDate": "2014-12-19T00:03:14+0100", - "updateDate": "2014-12-19T00:03:14+0100", - "closeDate": "2014-12-19T00:03:14+0100", - "currentChange": "coucou,c'est,nous", - "isChange": false, - "selectAt": 564897564 - }, - { - "isNew": false, - "key": "key", - "manualSeverity": false, - "assignee": "Assignee", - "attributes": "attributes", - "authorLogin": "login", - "isChanged": true, - "ruleKey": "ruleKey", - "ruleRepo": "local", - "severity": "INFO", - "message": "message", - "line": 25, - "effortToFix": 30, - "debtInMinutes": 25, - "status": "NEW", - "resolution": "Non Solved", - "reporter": "reporter", - "assignee": "assignee", - "checkSum": "checkSum", - "attributes": "toto=25", - "authorLogin": "author", - "actionPlanKey": "actionPlanKey", - "creationDate": "2014-12-19T00:03:14+0100", - "updateDate": "2014-12-19T00:03:14+0100", - "closeDate": "2014-12-19T00:03:14+0100", - "currentChange": "coucou,c'est,nous", - "isChange": false, - "selectAt": 564897564 - }, - { - "isNew": false, - "key": "key", - "manualSeverity": false, - "assignee": "Assignee", - "attributes": "attributes", - "authorLogin": "login", - "isChanged": true, - "ruleKey": "ruleKey", - "ruleRepo": "local", - "severity": "INFO", - "message": "message", - "line": 25, - "effortToFix": 30, - "debtInMinutes": 25, - "status": "NEW", - "resolution": "Non Solved", - "reporter": "reporter", - "assignee": "assignee", - "checkSum": "checkSum", - "attributes": "toto=25", - "authorLogin": "author", - "actionPlanKey": "actionPlanKey", - "creationDate": "2014-12-19T00:03:14+0100", - "updateDate": "2014-12-19T00:03:14+0100", - "closeDate": "2014-12-19T00:03:14+0100", - "currentChange": "coucou,c'est,nous", - "isChange": false, - "selectAt": 564897564 - }, - { - "isNew": false, - "key": "key", - "manualSeverity": false, - "assignee": "Assignee", - "attributes": "attributes", - "authorLogin": "login", - "isChanged": true, - "ruleKey": "ruleKey", - "ruleRepo": "local", - "severity": "INFO", - "message": "message", - "line": 25, - "effortToFix": 30, - "debtInMinutes": 25, - "status": "NEW", - "resolution": "Non Solved", - "reporter": "reporter", - "assignee": "assignee", - "checkSum": "checkSum", - "attributes": "toto=25", - "authorLogin": "author", - "actionPlanKey": "actionPlanKey", - "creationDate": "2014-12-19T00:03:14+0100", - "updateDate": "2014-12-19T00:03:14+0100", - "closeDate": "2014-12-19T00:03:14+0100", - "currentChange": "coucou,c'est,nous", - "isChange": false, - "selectAt": 564897564 - }, - { - "isNew": false, - "key": "key", - "manualSeverity": false, - "assignee": "Assignee", - "attributes": "attributes", - "authorLogin": "login", - "isChanged": true, - "ruleKey": "ruleKey", - "ruleRepo": "local", - "severity": "INFO", - "message": "message", - "line": 25, - "effortToFix": 30, - "debtInMinutes": 25, - "status": "NEW", - "resolution": "Non Solved", - "reporter": "reporter", - "assignee": "assignee", - "checkSum": "checkSum", - "attributes": "toto=25", - "authorLogin": "author", - "actionPlanKey": "actionPlanKey", - "creationDate": "2014-12-19T00:03:14+0100", - "updateDate": "2014-12-19T00:03:14+0100", - "closeDate": "2014-12-19T00:03:14+0100", - "currentChange": "coucou,c'est,nous", - "isChange": false, - "selectAt": 564897564 - }, - { - "isNew": false, - "key": "key", - "manualSeverity": false, - "assignee": "Assignee", - "attributes": "attributes", - "authorLogin": "login", - "isChanged": true, - "ruleKey": "ruleKey", - "ruleRepo": "local", - "severity": "INFO", - "message": "message", - "line": 25, - "effortToFix": 30, - "debtInMinutes": 25, - "status": "NEW", - "resolution": "Non Solved", - "reporter": "reporter", - "assignee": "assignee", - "checkSum": "checkSum", - "attributes": "toto=25", - "authorLogin": "author", - "actionPlanKey": "actionPlanKey", - "creationDate": "2014-12-19T00:03:14+0100", - "updateDate": "2014-12-19T00:03:14+0100", - "closeDate": "2014-12-19T00:03:14+0100", - "currentChange": "coucou,c'est,nous", - "isChange": false, - "selectAt": 564897564 - } -] \ No newline at end of file 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/component/ReportComponent.java b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/component/ReportComponent.java new file mode 100644 index 00000000000..37b64b87e47 --- /dev/null +++ b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/component/ReportComponent.java @@ -0,0 +1,144 @@ +/* + * 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.component; + +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; + +import java.util.ArrayList; +import java.util.Collection; + +public class ReportComponent { + + public enum Type { + PRJ, + MOD, + DIR, + FIL, + VIEW, + SUBVIEW + } + + private long batchId; + private int id; + private int snapshotId; + private String path; + private String name; + private Type type; + // Only for files + private Boolean isTest; + private String languageKey; + + private Collection children = new ArrayList(); + + public ReportComponent setBatchId(long batchId) { + this.batchId = batchId; + return this; + } + + public long batchId() { + return batchId; + } + + public ReportComponent setId(int id) { + this.id = id; + return this; + } + + public int id() { + return id; + } + + public ReportComponent setSnapshotId(int snapshotId) { + this.snapshotId = snapshotId; + return this; + } + + public int snapshotId() { + return snapshotId; + } + + public ReportComponent setPath(String path) { + this.path = path; + return this; + } + + public String path() { + return path; + } + + public ReportComponent setName(@Nullable String name) { + this.name = name; + return this; + } + + /** + * @return null for files and directories since it is the same as the path + */ + @CheckForNull + public String name() { + return name; + } + + public ReportComponent setType(Type type) { + this.type = type; + return this; + } + + public Type type() { + return type; + } + + public ReportComponent setTest(@Nullable Boolean isTest) { + this.isTest = isTest; + return this; + } + + /** + * @return null when not a file + */ + @CheckForNull + public Boolean isTest() { + return isTest; + } + + public ReportComponent setLanguageKey(@Nullable String languageKey) { + this.languageKey = languageKey; + return this; + } + + /** + * @return null when not a file + */ + @CheckForNull + public String languageKey() { + return languageKey; + } + + public ReportComponent addChild(ReportComponent child) { + this.children.add(child); + return this; + } + + public Collection children() { + return children; + } + +} diff --git a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/component/ReportComponents.java b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/component/ReportComponents.java new file mode 100644 index 00000000000..5ee00eee71c --- /dev/null +++ b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/component/ReportComponents.java @@ -0,0 +1,57 @@ +/* + * 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.component; + +import org.sonar.batch.protocol.GsonHelper; + +import java.util.Date; + +public class ReportComponents { + + private Date analysisDate; + + private ReportComponent root; + + public void setAnalysisDate(Date analysisDate) { + this.analysisDate = analysisDate; + } + + public Date analysisDate() { + return analysisDate; + } + + public ReportComponents setRoot(ReportComponent r) { + this.root = r; + return this; + } + + public ReportComponent root() { + return root; + } + + public String toJson() { + return GsonHelper.create().toJson(this); + } + + public static ReportComponents fromJson(String json) { + return GsonHelper.create().fromJson(json, ReportComponents.class); + } + +} diff --git a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/component/package-info.java b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/component/package-info.java new file mode 100644 index 00000000000..7e8017af61e --- /dev/null +++ b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/component/package-info.java @@ -0,0 +1,24 @@ +/* + * 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. + */ +@ParametersAreNonnullByDefault +package org.sonar.batch.protocol.output.component; + +import javax.annotation.ParametersAreNonnullByDefault; + 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/resource/ReportComponent.java deleted file mode 100644 index e9ff00c57ac..00000000000 --- a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/resource/ReportComponent.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * 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.resource; - -import javax.annotation.CheckForNull; -import javax.annotation.Nullable; - -import java.util.ArrayList; -import java.util.Collection; - -public class ReportComponent { - - public enum Type { - PRJ, - MOD, - DIR, - FIL, - VIEW, - SUBVIEW - } - - private long batchId; - private int id; - private int snapshotId; - private String path; - private String name; - private Type type; - // Only for files - private Boolean isTest; - private String languageKey; - - private Collection children = new ArrayList(); - - public ReportComponent setBatchId(long batchId) { - this.batchId = batchId; - return this; - } - - public long batchId() { - return batchId; - } - - public ReportComponent setId(int id) { - this.id = id; - return this; - } - - public int id() { - return id; - } - - public ReportComponent setSnapshotId(int snapshotId) { - this.snapshotId = snapshotId; - return this; - } - - public int snapshotId() { - return snapshotId; - } - - public ReportComponent setPath(String path) { - this.path = path; - return this; - } - - public String path() { - return path; - } - - public ReportComponent setName(@Nullable String name) { - this.name = name; - return this; - } - - /** - * @return null for files and directories since it is the same as the path - */ - @CheckForNull - public String name() { - return name; - } - - public ReportComponent setType(Type type) { - this.type = type; - return this; - } - - public Type type() { - return type; - } - - public ReportComponent setTest(@Nullable Boolean isTest) { - this.isTest = isTest; - return this; - } - - /** - * @return null when not a file - */ - @CheckForNull - public Boolean isTest() { - return isTest; - } - - public ReportComponent setLanguageKey(@Nullable String languageKey) { - this.languageKey = languageKey; - return this; - } - - /** - * @return null when not a file - */ - @CheckForNull - public String languageKey() { - return languageKey; - } - - public ReportComponent addChild(ReportComponent child) { - this.children.add(child); - return this; - } - - public Collection children() { - return children; - } - -} 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/resource/ReportComponents.java deleted file mode 100644 index 5e7b0fb6fdf..00000000000 --- a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/resource/ReportComponents.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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.resource; - -import org.sonar.batch.protocol.GsonHelper; - -import java.util.Date; - -public class ReportComponents { - - private Date analysisDate; - - private ReportComponent root; - - public void setAnalysisDate(Date analysisDate) { - this.analysisDate = analysisDate; - } - - public Date analysisDate() { - return analysisDate; - } - - public ReportComponents setRoot(ReportComponent r) { - this.root = r; - return this; - } - - public ReportComponent root() { - return root; - } - - public String toJson() { - return GsonHelper.create().toJson(this); - } - - public static ReportComponents fromJson(String json) { - return GsonHelper.create().fromJson(json, ReportComponents.class); - } - -} 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/resource/package-info.java deleted file mode 100644 index 5e45e2dee7a..00000000000 --- a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/resource/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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. - */ -@ParametersAreNonnullByDefault -package org.sonar.batch.protocol.output.resource; - -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/component/ReportComponentsTest.java b/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/component/ReportComponentsTest.java new file mode 100644 index 00000000000..f97cf26b28e --- /dev/null +++ b/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/component/ReportComponentsTest.java @@ -0,0 +1,98 @@ +/* + * 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.component; + +import org.apache.commons.io.IOUtils; +import org.junit.Test; +import org.skyscreamer.jsonassert.JSONAssert; +import org.sonar.batch.protocol.output.component.ReportComponent.Type; + +import java.text.SimpleDateFormat; +import java.util.Date; + +import static org.fest.assertions.Assertions.assertThat; + +public class ReportComponentsTest { + + @Test + public void to_json() throws Exception { + ReportComponents res = new ReportComponents(); + Date d = new SimpleDateFormat("dd/MM/yyyy").parse("12/12/2012"); + res.setAnalysisDate(d); + ReportComponent root = new ReportComponent() + .setBatchId(1) + .setId(11) + .setName("Root project") + .setSnapshotId(111) + .setType(Type.PRJ); + ReportComponent module = new ReportComponent() + .setBatchId(2) + .setId(22) + .setName("Module") + .setSnapshotId(222) + .setPath("module1") + .setType(Type.MOD); + root.addChild(module); + ReportComponent dir = new ReportComponent() + .setBatchId(3) + .setId(33) + .setName("src") + .setSnapshotId(333) + .setPath("src") + .setType(Type.DIR); + module.addChild(dir); + ReportComponent file = new ReportComponent() + .setBatchId(4) + .setId(44) + .setName("Foo.java") + .setSnapshotId(444) + .setPath("Foo.java") + .setType(Type.FIL) + .setTest(true) + .setLanguageKey("java"); + dir.addChild(file); + res.setRoot(root); + + JSONAssert + .assertEquals( + IOUtils.toString(this.getClass().getResourceAsStream("ReportComponentsTest/expected.json"), "UTF-8"), + res.toJson(), true); + } + + @Test + public void from_json() throws Exception { + ReportComponents res = ReportComponents + .fromJson( + 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(); + assertThat(root.batchId()).isEqualTo(1); + assertThat(root.id()).isEqualTo(11); + assertThat(root.name()).isEqualTo("Root project"); + assertThat(root.snapshotId()).isEqualTo(111); + assertThat(root.path()).isNull(); + assertThat(root.type()).isEqualTo(Type.PRJ); + assertThat(root.children()).hasSize(1); + assertThat(root.isTest()).isNull(); + assertThat(root.languageKey()).isNull(); + + } +} 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/resource/ReportComponentsTest.java deleted file mode 100644 index b3b989aa8f8..00000000000 --- a/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/resource/ReportComponentsTest.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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.resource; - -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 java.text.SimpleDateFormat; -import java.util.Date; - -import static org.fest.assertions.Assertions.assertThat; - -public class ReportComponentsTest { - - @Test - public void to_json() throws Exception { - ReportComponents res = new ReportComponents(); - Date d = new SimpleDateFormat("dd/MM/yyyy").parse("12/12/2012"); - res.setAnalysisDate(d); - ReportComponent root = new ReportComponent() - .setBatchId(1) - .setId(11) - .setName("Root project") - .setSnapshotId(111) - .setType(Type.PRJ); - ReportComponent module = new ReportComponent() - .setBatchId(2) - .setId(22) - .setName("Module") - .setSnapshotId(222) - .setPath("module1") - .setType(Type.MOD); - root.addChild(module); - ReportComponent dir = new ReportComponent() - .setBatchId(3) - .setId(33) - .setName("src") - .setSnapshotId(333) - .setPath("src") - .setType(Type.DIR); - module.addChild(dir); - ReportComponent file = new ReportComponent() - .setBatchId(4) - .setId(44) - .setName("Foo.java") - .setSnapshotId(444) - .setPath("Foo.java") - .setType(Type.FIL) - .setTest(true) - .setLanguageKey("java"); - dir.addChild(file); - res.setRoot(root); - - JSONAssert - .assertEquals( - IOUtils.toString(this.getClass().getResourceAsStream("ReportResourceTest/expected.json"), "UTF-8"), - res.toJson(), true); - } - - @Test - public void from_json() throws Exception { - ReportComponents res = ReportComponents - .fromJson( - IOUtils.toString(this.getClass().getResourceAsStream("ReportResourceTest/expected.json"), "UTF-8")); - - assertThat(res.analysisDate()).isEqualTo(new SimpleDateFormat("dd/MM/yyyy").parse("12/12/2012")); - ReportComponent root = res.root(); - assertThat(root.batchId()).isEqualTo(1); - assertThat(root.id()).isEqualTo(11); - assertThat(root.name()).isEqualTo("Root project"); - assertThat(root.snapshotId()).isEqualTo(111); - assertThat(root.path()).isNull(); - assertThat(root.type()).isEqualTo(Type.PRJ); - assertThat(root.children()).hasSize(1); - assertThat(root.isTest()).isNull(); - assertThat(root.languageKey()).isNull(); - - } -} diff --git a/sonar-batch-protocol/src/test/resources/org/sonar/batch/protocol/output/component/ReportComponentsTest/expected.json b/sonar-batch-protocol/src/test/resources/org/sonar/batch/protocol/output/component/ReportComponentsTest/expected.json new file mode 100644 index 00000000000..581bbc5ea23 --- /dev/null +++ b/sonar-batch-protocol/src/test/resources/org/sonar/batch/protocol/output/component/ReportComponentsTest/expected.json @@ -0,0 +1,43 @@ +{ + "analysisDate": "2012-12-12T00:00:00+0100", + "root": { + "batchId": 1, + "id": 11, + "snapshotId": 111, + "name": "Root project", + "type": "PRJ", + "children": [ + { + "batchId": 2, + "id": 22, + "snapshotId": 222, + "path": "module1", + "name": "Module", + "type": "MOD", + "children": [ + { + "batchId": 3, + "id": 33, + "snapshotId": 333, + "path": "src", + "name": "src", + "type": "DIR", + "children": [ + { + "batchId": 4, + "id": 44, + "snapshotId": 444, + "path": "Foo.java", + "name": "Foo.java", + "type": "FIL", + "languageKey": "java", + "isTest": true, + "children": [] + } + ] + } + ] + } + ] + } +} \ No newline at end of file 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/resource/ReportResourceTest/expected.json deleted file mode 100644 index 581bbc5ea23..00000000000 --- a/sonar-batch-protocol/src/test/resources/org/sonar/batch/protocol/output/resource/ReportResourceTest/expected.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "analysisDate": "2012-12-12T00:00:00+0100", - "root": { - "batchId": 1, - "id": 11, - "snapshotId": 111, - "name": "Root project", - "type": "PRJ", - "children": [ - { - "batchId": 2, - "id": 22, - "snapshotId": 222, - "path": "module1", - "name": "Module", - "type": "MOD", - "children": [ - { - "batchId": 3, - "id": 33, - "snapshotId": 333, - "path": "src", - "name": "src", - "type": "DIR", - "children": [ - { - "batchId": 4, - "id": 44, - "snapshotId": 444, - "path": "Foo.java", - "name": "Foo.java", - "type": "FIL", - "languageKey": "java", - "isTest": true, - "children": [] - } - ] - } - ] - } - ] - } -} \ No newline at end of file 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(