diff options
author | Julien HENRY <julien.henry@sonarsource.com> | 2015-03-26 14:09:31 +0100 |
---|---|---|
committer | Teryk Bellahsene <teryk.bellahsene@sonarsource.com> | 2015-03-26 17:32:20 +0100 |
commit | 6f5449b6daa0f588c2e18bf5e04e1dbe5b2688b1 (patch) | |
tree | fc9986467f08ae2afad9f8825b1de80fd0a0c2af | |
parent | a83dfe19c1da637994148d538e116d4edf22ed98 (diff) | |
download | sonarqube-6f5449b6daa0f588c2e18bf5e04e1dbe5b2688b1.tar.gz sonarqube-6f5449b6daa0f588c2e18bf5e04e1dbe5b2688b1.zip |
SONAR-6317 Feed SCM in compute report - batch side
43 files changed, 505 insertions, 940 deletions
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/AbstractNewCoverageFileAnalyzer.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/AbstractNewCoverageFileAnalyzer.java index 1ade50dfc61..1ac4c1a4f3a 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/AbstractNewCoverageFileAnalyzer.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/AbstractNewCoverageFileAnalyzer.java @@ -19,15 +19,10 @@ */ package org.sonar.plugins.core.timemachine; -import org.sonar.batch.components.Period; - -import org.sonar.batch.components.TimeMachineConfiguration; -import org.sonar.api.batch.RequiresDB; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import org.apache.commons.lang.ObjectUtils; import org.sonar.api.batch.*; -import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.Measure; import org.sonar.api.measures.Metric; import org.sonar.api.resources.Project; @@ -35,6 +30,13 @@ import org.sonar.api.resources.Qualifiers; import org.sonar.api.resources.Resource; import org.sonar.api.resources.Scopes; import org.sonar.api.utils.KeyValueFormat; +import org.sonar.batch.components.Period; +import org.sonar.batch.components.TimeMachineConfiguration; +import org.sonar.batch.index.ResourceCache; +import org.sonar.batch.protocol.output.BatchReport.Scm; +import org.sonar.batch.protocol.output.BatchReport.Scm.Changeset; +import org.sonar.batch.protocol.output.BatchReportReader; +import org.sonar.batch.report.PublishReportJob; import javax.annotation.Nullable; @@ -50,16 +52,20 @@ import java.util.Map; @DependedUpon(DecoratorBarriers.END_OF_TIME_MACHINE) public abstract class AbstractNewCoverageFileAnalyzer implements Decorator { - private List<PeriodStruct> structs; + private final List<PeriodStruct> structs; + private final PublishReportJob publishReportJob; + private final ResourceCache resourceCache; - public AbstractNewCoverageFileAnalyzer(TimeMachineConfiguration timeMachineConfiguration) { - structs = Lists.newArrayList(); + public AbstractNewCoverageFileAnalyzer(TimeMachineConfiguration timeMachineConfiguration, PublishReportJob publishReportJob, ResourceCache resourceCache) { + this(Lists.<PeriodStruct>newArrayList(), publishReportJob, resourceCache); for (Period period : timeMachineConfiguration.periods()) { structs.add(new PeriodStruct(period.getIndex(), period.getDate())); } } - AbstractNewCoverageFileAnalyzer(List<PeriodStruct> structs) { + AbstractNewCoverageFileAnalyzer(List<PeriodStruct> structs, PublishReportJob publishReportJob, ResourceCache resourceCache) { + this.resourceCache = resourceCache; + this.publishReportJob = publishReportJob; this.structs = structs; } @@ -89,8 +95,7 @@ public abstract class AbstractNewCoverageFileAnalyzer implements Decorator { @DependsUpon public List<Metric> dependsOnMetrics() { - return Arrays.asList(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE, - getCoverageLineHitsDataMetric(), getConditionsByLineMetric(), getCoveredConditionsByLineMetric()); + return Arrays.asList(getCoverageLineHitsDataMetric(), getConditionsByLineMetric(), getCoveredConditionsByLineMetric()); } @DependedUpon @@ -112,11 +117,11 @@ public abstract class AbstractNewCoverageFileAnalyzer implements Decorator { } private boolean parse(DecoratorContext context) { - Measure lastCommits = context.getMeasure(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE); + BatchReportReader reader = new BatchReportReader(publishReportJob.getReportDir()); + Scm componentScm = reader.readComponentScm(resourceCache.get(context.getResource()).batchId()); Measure hitsByLineMeasure = context.getMeasure(getCoverageLineHitsDataMetric()); - if (lastCommits != null && lastCommits.hasData() && hitsByLineMeasure != null && hitsByLineMeasure.hasData()) { - Map<Integer, Date> datesByLine = KeyValueFormat.parseIntDateTime(lastCommits.getData()); + if (componentScm != null && hitsByLineMeasure != null && hitsByLineMeasure.hasData()) { Map<Integer, Integer> hitsByLine = parseCountByLine(hitsByLineMeasure); Map<Integer, Integer> conditionsByLine = parseCountByLine(context.getMeasure(getConditionsByLineMetric())); Map<Integer, Integer> coveredConditionsByLine = parseCountByLine(context.getMeasure(getCoveredConditionsByLineMetric())); @@ -128,7 +133,8 @@ public abstract class AbstractNewCoverageFileAnalyzer implements Decorator { int hits = entry.getValue(); int conditions = (Integer) ObjectUtils.defaultIfNull(conditionsByLine.get(lineId), 0); int coveredConditions = (Integer) ObjectUtils.defaultIfNull(coveredConditionsByLine.get(lineId), 0); - Date date = datesByLine.get(lineId); + Changeset changeset = componentScm.getChangeset(componentScm.getChangesetIndexByLine(lineId - 1)); + Date date = changeset.hasDate() ? new Date(changeset.getDate()) : null; for (PeriodStruct struct : structs) { struct.analyze(date, hits, conditions, coveredConditions); } diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewCoverageFileAnalyzer.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewCoverageFileAnalyzer.java index 352070ccc68..38aac00f0ea 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewCoverageFileAnalyzer.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewCoverageFileAnalyzer.java @@ -19,21 +19,22 @@ */ package org.sonar.plugins.core.timemachine; -import org.sonar.batch.components.TimeMachineConfiguration; - import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.Metric; +import org.sonar.batch.components.TimeMachineConfiguration; +import org.sonar.batch.index.ResourceCache; +import org.sonar.batch.report.PublishReportJob; import java.util.List; public class NewCoverageFileAnalyzer extends AbstractNewCoverageFileAnalyzer { - public NewCoverageFileAnalyzer(TimeMachineConfiguration timeMachineConfiguration) { - super(timeMachineConfiguration); + public NewCoverageFileAnalyzer(TimeMachineConfiguration timeMachineConfiguration, PublishReportJob publishReportJob, ResourceCache resourceCache) { + super(timeMachineConfiguration, publishReportJob, resourceCache); } - NewCoverageFileAnalyzer(List<PeriodStruct> structs) { - super(structs); + NewCoverageFileAnalyzer(List<PeriodStruct> structs, PublishReportJob publishReportJob, ResourceCache resourceCache) { + super(structs, publishReportJob, resourceCache); } @Override diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewItCoverageFileAnalyzer.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewItCoverageFileAnalyzer.java index 2dbcf8416a4..48222f59ce2 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewItCoverageFileAnalyzer.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewItCoverageFileAnalyzer.java @@ -19,15 +19,16 @@ */ package org.sonar.plugins.core.timemachine; -import org.sonar.batch.components.TimeMachineConfiguration; - import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.Metric; +import org.sonar.batch.components.TimeMachineConfiguration; +import org.sonar.batch.index.ResourceCache; +import org.sonar.batch.report.PublishReportJob; public class NewItCoverageFileAnalyzer extends AbstractNewCoverageFileAnalyzer { - public NewItCoverageFileAnalyzer(TimeMachineConfiguration timeMachineConfiguration) { - super(timeMachineConfiguration); + public NewItCoverageFileAnalyzer(TimeMachineConfiguration timeMachineConfiguration, PublishReportJob publishReportJob, ResourceCache resourceCache) { + super(timeMachineConfiguration, publishReportJob, resourceCache); } @Override diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewOverallCoverageFileAnalyzer.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewOverallCoverageFileAnalyzer.java index b57db6dbe0e..75a1a83686c 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewOverallCoverageFileAnalyzer.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewOverallCoverageFileAnalyzer.java @@ -19,15 +19,16 @@ */ package org.sonar.plugins.core.timemachine; -import org.sonar.batch.components.TimeMachineConfiguration; - import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.Metric; +import org.sonar.batch.components.TimeMachineConfiguration; +import org.sonar.batch.index.ResourceCache; +import org.sonar.batch.report.PublishReportJob; public class NewOverallCoverageFileAnalyzer extends AbstractNewCoverageFileAnalyzer { - public NewOverallCoverageFileAnalyzer(TimeMachineConfiguration timeMachineConfiguration) { - super(timeMachineConfiguration); + public NewOverallCoverageFileAnalyzer(TimeMachineConfiguration timeMachineConfiguration, PublishReportJob publishReportJob, ResourceCache resourceCache) { + super(timeMachineConfiguration, publishReportJob, resourceCache); } @Override diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/NewCoverageFileAnalyzerTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/NewCoverageFileAnalyzerTest.java index 8ef3f98c1bb..af6d25828a6 100644 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/NewCoverageFileAnalyzerTest.java +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/NewCoverageFileAnalyzerTest.java @@ -19,13 +19,23 @@ */ package org.sonar.plugins.core.timemachine; +import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TemporaryFolder; import org.mockito.ArgumentMatcher; import org.sonar.api.batch.DecoratorContext; import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.Measure; import org.sonar.api.measures.Metric; +import org.sonar.api.resources.File; +import org.sonar.api.resources.Resource; import org.sonar.api.utils.DateUtils; +import org.sonar.batch.index.ResourceCache; +import org.sonar.batch.protocol.output.BatchReport.Scm; +import org.sonar.batch.protocol.output.BatchReport.Scm.Changeset; +import org.sonar.batch.protocol.output.BatchReportWriter; +import org.sonar.batch.report.PublishReportJob; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -35,28 +45,57 @@ import java.util.List; import static org.mockito.Matchers.any; import static org.mockito.Matchers.argThat; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; public class NewCoverageFileAnalyzerTest { + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + + private DecoratorContext context; + private NewCoverageFileAnalyzer decorator; + private BatchReportWriter writer; + + @Before + public void prepare() throws Exception { + context = mock(DecoratorContext.class); + Resource f = File.create("src/Foo.java").setEffectiveKey("foo:src/Foo.java"); + when(context.getResource()).thenReturn(f); + ResourceCache cache = new ResourceCache(); + cache.add(f, null); + List<AbstractNewCoverageFileAnalyzer.PeriodStruct> structs = Arrays.asList( + new AbstractNewCoverageFileAnalyzer.PeriodStruct(1, newDate("2009-12-25")), + new AbstractNewCoverageFileAnalyzer.PeriodStruct(3, newDate("2011-02-18"))); + PublishReportJob publishReportJob = mock(PublishReportJob.class); + java.io.File reportBaseDir = temp.newFolder(); + when(publishReportJob.getReportDir()).thenReturn(reportBaseDir); + writer = new BatchReportWriter(reportBaseDir); + decorator = new NewCoverageFileAnalyzer(structs, publishReportJob, cache); + + } + @Test public void shouldDoNothingIfNoScmData() throws ParseException { - DecoratorContext context = mock(DecoratorContext.class); when(context.getMeasure(CoreMetrics.COVERAGE_LINE_HITS_DATA)) .thenReturn(new Measure(CoreMetrics.COVERAGE_LINE_HITS_DATA, "1=10")); - NewCoverageFileAnalyzer decorator = newDecorator(); decorator.doDecorate(context); verify(context, never()).saveMeasure(any(Measure.class)); } @Test public void shouldDoNothingIfNoCoverageData() throws ParseException { - DecoratorContext context = mock(DecoratorContext.class); - when(context.getMeasure(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE)) - .thenReturn(new Measure(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE, "10=2008-05-18T00:00:00+0000")); + writer.writeComponentScm(Scm.newBuilder() + .setComponentRef(1) + .addChangeset(Changeset.newBuilder() + .setDate(DateUtils.parseDateTime("2008-05-18T00:00:00+0000").getTime()) + .build()) + .addChangesetIndexByLine(0) + .build()); - NewCoverageFileAnalyzer decorator = newDecorator(); decorator.doDecorate(context); verify(context, never()).saveMeasure(any(Measure.class)); @@ -64,13 +103,31 @@ public class NewCoverageFileAnalyzerTest { @Test public void shouldGetNewLines() throws ParseException { - DecoratorContext context = mock(DecoratorContext.class); when(context.getMeasure(CoreMetrics.COVERAGE_LINE_HITS_DATA)).thenReturn( new Measure(CoreMetrics.COVERAGE_LINE_HITS_DATA, "10=2;11=3")); - when(context.getMeasure(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE)).thenReturn( - new Measure(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE, "10=2007-01-15T00:00:00+0000;11=2011-01-01T00:00:00+0000")); + writer.writeComponentScm(Scm.newBuilder() + .setComponentRef(1) + .addChangeset(Changeset.newBuilder() + .build()) + .addChangeset(Changeset.newBuilder() + .setDate(DateUtils.parseDateTime("2007-01-15T00:00:00+0000").getTime()) + .build()) + .addChangeset(Changeset.newBuilder() + .setDate(DateUtils.parseDateTime("2011-01-01T00:00:00+0000").getTime()) + .build()) + .addChangesetIndexByLine(0) + .addChangesetIndexByLine(0) + .addChangesetIndexByLine(0) + .addChangesetIndexByLine(0) + .addChangesetIndexByLine(0) + .addChangesetIndexByLine(0) + .addChangesetIndexByLine(0) + .addChangesetIndexByLine(0) + .addChangesetIndexByLine(0) + .addChangesetIndexByLine(1) + .addChangesetIndexByLine(2) + .build()); - NewCoverageFileAnalyzer decorator = newDecorator(); decorator.doDecorate(context); // line 11 has been updated after date1 (2009-12-25). This line is covered. @@ -92,17 +149,35 @@ public class NewCoverageFileAnalyzerTest { @Test public void shouldGetNewConditions() throws ParseException { - DecoratorContext context = mock(DecoratorContext.class); when(context.getMeasure(CoreMetrics.COVERAGE_LINE_HITS_DATA)).thenReturn( new Measure(CoreMetrics.COVERAGE_LINE_HITS_DATA, "10=2;11=3")); when(context.getMeasure(CoreMetrics.CONDITIONS_BY_LINE)).thenReturn( new Measure(CoreMetrics.CONDITIONS_BY_LINE, "11=4")); when(context.getMeasure(CoreMetrics.COVERED_CONDITIONS_BY_LINE)).thenReturn( new Measure(CoreMetrics.COVERED_CONDITIONS_BY_LINE, "11=1")); - when(context.getMeasure(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE)).thenReturn( - new Measure(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE, "10=2007-01-15T00:00:00+0000;11=2011-01-01T00:00:00+0000")); + writer.writeComponentScm(Scm.newBuilder() + .setComponentRef(1) + .addChangeset(Changeset.newBuilder() + .build()) + .addChangeset(Changeset.newBuilder() + .setDate(DateUtils.parseDateTime("2007-01-15T00:00:00+0000").getTime()) + .build()) + .addChangeset(Changeset.newBuilder() + .setDate(DateUtils.parseDateTime("2011-01-01T00:00:00+0000").getTime()) + .build()) + .addChangesetIndexByLine(0) + .addChangesetIndexByLine(0) + .addChangesetIndexByLine(0) + .addChangesetIndexByLine(0) + .addChangesetIndexByLine(0) + .addChangesetIndexByLine(0) + .addChangesetIndexByLine(0) + .addChangesetIndexByLine(0) + .addChangesetIndexByLine(0) + .addChangesetIndexByLine(1) + .addChangesetIndexByLine(2) + .build()); - NewCoverageFileAnalyzer decorator = newDecorator(); decorator.doDecorate(context); // line 11 has been updated after date1 (2009-12-25). This line has 1 covered condition amongst 4 @@ -124,17 +199,35 @@ public class NewCoverageFileAnalyzerTest { @Test public void shouldNotGetNewConditionsWhenNewLineHasNoConditions() throws ParseException { - DecoratorContext context = mock(DecoratorContext.class); when(context.getMeasure(CoreMetrics.COVERAGE_LINE_HITS_DATA)).thenReturn( new Measure(CoreMetrics.COVERAGE_LINE_HITS_DATA, "10=2;11=3")); when(context.getMeasure(CoreMetrics.CONDITIONS_BY_LINE)).thenReturn( new Measure(CoreMetrics.CONDITIONS_BY_LINE, "10=1")); when(context.getMeasure(CoreMetrics.COVERED_CONDITIONS_BY_LINE)).thenReturn( new Measure(CoreMetrics.COVERED_CONDITIONS_BY_LINE, "10=1")); - when(context.getMeasure(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE)).thenReturn( - new Measure(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE, "10=2007-01-15T00:00:00+0000;11=2011-01-01T00:00:00+0000")); + writer.writeComponentScm(Scm.newBuilder() + .setComponentRef(1) + .addChangeset(Changeset.newBuilder() + .build()) + .addChangeset(Changeset.newBuilder() + .setDate(DateUtils.parseDateTime("2007-01-15T00:00:00+0000").getTime()) + .build()) + .addChangeset(Changeset.newBuilder() + .setDate(DateUtils.parseDateTime("2011-01-01T00:00:00+0000").getTime()) + .build()) + .addChangesetIndexByLine(0) + .addChangesetIndexByLine(0) + .addChangesetIndexByLine(0) + .addChangesetIndexByLine(0) + .addChangesetIndexByLine(0) + .addChangesetIndexByLine(0) + .addChangesetIndexByLine(0) + .addChangesetIndexByLine(0) + .addChangesetIndexByLine(0) + .addChangesetIndexByLine(1) + .addChangesetIndexByLine(2) + .build()); - NewCoverageFileAnalyzer decorator = newDecorator(); decorator.doDecorate(context); // line 11 has been updated after date1 (2009-12-25) but it has no conditions @@ -144,22 +237,24 @@ public class NewCoverageFileAnalyzerTest { @Test public void shouldLeaveNullValueWhenNothingHasChanged() throws Exception { - String lastCommitDatesByLine = "1=2008-08-02T13:56:37+0200;" + - "2=2008-08-02T13:56:37+0200;" + - "3=2008-08-02T13:56:37+0200;" + - "4=2008-08-02T13:56:37+0200"; - DecoratorContext context = mock(DecoratorContext.class); when(context.getMeasure(CoreMetrics.COVERAGE_LINE_HITS_DATA)).thenReturn( new Measure(CoreMetrics.COVERAGE_LINE_HITS_DATA, "2=1;3=1")); when(context.getMeasure(CoreMetrics.CONDITIONS_BY_LINE)).thenReturn( new Measure(CoreMetrics.CONDITIONS_BY_LINE, "2=1")); when(context.getMeasure(CoreMetrics.COVERED_CONDITIONS_BY_LINE)).thenReturn( new Measure(CoreMetrics.COVERED_CONDITIONS_BY_LINE, "2=1")); - when(context.getMeasure(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE)).thenReturn( - new Measure(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE, lastCommitDatesByLine)); + writer.writeComponentScm(Scm.newBuilder() + .setComponentRef(1) + .addChangeset(Changeset.newBuilder() + .setDate(DateUtils.parseDateTime("2008-08-02T13:56:37+0200").getTime()) + .build()) + .addChangesetIndexByLine(0) + .addChangesetIndexByLine(0) + .addChangesetIndexByLine(0) + .addChangesetIndexByLine(0) + .build()); - NewCoverageFileAnalyzer decorator = newDecorator(); decorator.doDecorate(context); verify(context).saveMeasure(argThat(new VariationMatcher(CoreMetrics.NEW_LINES_TO_COVER, 1, null))); @@ -197,13 +292,6 @@ public class NewCoverageFileAnalyzerTest { } } - private NewCoverageFileAnalyzer newDecorator() throws ParseException { - List<AbstractNewCoverageFileAnalyzer.PeriodStruct> structs = Arrays.asList( - new AbstractNewCoverageFileAnalyzer.PeriodStruct(1, newDate("2009-12-25")), - new AbstractNewCoverageFileAnalyzer.PeriodStruct(3, newDate("2011-02-18"))); - return new NewCoverageFileAnalyzer(structs); - } - private Date newDate(String s) throws ParseException { return new SimpleDateFormat(DateUtils.DATE_FORMAT).parse(s); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/batch/ProjectRepositoryLoader.java b/server/sonar-server/src/main/java/org/sonar/server/batch/ProjectRepositoryLoader.java index 0ebebdac72a..baac3ce42b2 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/batch/ProjectRepositoryLoader.java +++ b/server/sonar-server/src/main/java/org/sonar/server/batch/ProjectRepositoryLoader.java @@ -289,7 +289,8 @@ public class ProjectRepositoryLoader implements ServerComponent { } for (FilePathWithHashDto file : dbClient.componentDao().selectEnabledDescendantFiles(session, moduleKey)) { - FileData fileData = new FileData(file.getSrcHash(), false, null, null, null); + // TODO should query E/S to know if blame is missing on this file + FileData fileData = new FileData(file.getSrcHash(), true); ref.addFileData(moduleKeysByUuid.get(file.getModuleUuid()), file.getPath(), fileData); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/SourceLinesCache.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/SourceLinesCache.java index daec5fb60e4..b49e8abf5f4 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/SourceLinesCache.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/SourceLinesCache.java @@ -21,6 +21,8 @@ package org.sonar.server.computation.issue; import org.apache.commons.lang.StringUtils; import org.sonar.batch.protocol.output.BatchReport; +import org.sonar.batch.protocol.output.BatchReport.Scm.Changeset; +import org.sonar.batch.protocol.output.BatchReport.Scm.Changeset.Builder; import org.sonar.batch.protocol.output.BatchReportReader; import org.sonar.server.source.index.SourceLineDoc; import org.sonar.server.source.index.SourceLineIndex; @@ -28,6 +30,7 @@ import org.sonar.server.source.index.SourceLineIndex; import javax.annotation.CheckForNull; import javax.annotation.Nullable; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -120,17 +123,29 @@ public class SourceLinesCache { BatchReport.Scm.Builder scmBuilder = BatchReport.Scm.newBuilder() .setComponentRef(currentFileReportRef); for (SourceLineDoc sourceLine : lines) { - if (changesetByRevision.get(sourceLine.scmRevision()) == null) { - BatchReport.Scm.Changeset changeset = BatchReport.Scm.Changeset.newBuilder() - .setAuthor(sourceLine.scmAuthor()) - .setDate(sourceLine.scmDate().getTime()) - .setRevision(sourceLine.scmRevision()) - .build(); + String scmRevision = sourceLine.scmRevision(); + if (scmRevision == null || changesetByRevision.get(scmRevision) == null) { + Builder changeSetBuilder = BatchReport.Scm.Changeset.newBuilder(); + String scmAuthor = sourceLine.scmAuthor(); + if (scmAuthor != null) { + changeSetBuilder.setAuthor(scmAuthor); + } + Date scmDate = sourceLine.scmDate(); + if (scmDate != null) { + changeSetBuilder.setDate(scmDate.getTime()); + } + if (scmRevision != null) { + changeSetBuilder.setRevision(scmRevision); + } + + Changeset changeset = changeSetBuilder.build(); scmBuilder.addChangeset(changeset); scmBuilder.addChangesetIndexByLine(scmBuilder.getChangesetCount() - 1); - changesetByRevision.put(sourceLine.scmRevision(), changeset); + if (scmRevision != null) { + changesetByRevision.put(scmRevision, changeset); + } } else { - scmBuilder.addChangesetIndexByLine(scmBuilder.getChangesetList().indexOf(changesetByRevision.get(sourceLine.scmRevision()))); + scmBuilder.addChangesetIndexByLine(scmBuilder.getChangesetList().indexOf(changesetByRevision.get(scmRevision))); } } return scmBuilder.build(); diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java index 195e297eb8f..b3137965343 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java @@ -599,10 +599,8 @@ class ServerComponents { pico.addSingleton(ShowAction.class); pico.addSingleton(LinesAction.class); pico.addSingleton(HashAction.class); - pico.addSingleton(ScmWriter.class); pico.addSingleton(RawAction.class); pico.addSingleton(IndexAction.class); - pico.addSingleton(ScmAction.class); pico.addSingleton(SourceLineIndexDefinition.class); pico.addSingleton(SourceLineIndex.class); pico.addSingleton(SourceLineIndexer.class); diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/SourceService.java b/server/sonar-server/src/main/java/org/sonar/server/source/SourceService.java index ed80adb8f94..581df02b837 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/source/SourceService.java +++ b/server/sonar-server/src/main/java/org/sonar/server/source/SourceService.java @@ -23,18 +23,12 @@ package org.sonar.server.source; import org.apache.commons.lang.ObjectUtils; import org.elasticsearch.common.collect.Lists; import org.sonar.api.ServerComponent; -import org.sonar.api.measures.CoreMetrics; -import org.sonar.api.web.UserRole; -import org.sonar.core.measure.db.MeasureDto; -import org.sonar.core.persistence.DbSession; -import org.sonar.core.persistence.MyBatis; import org.sonar.server.db.DbClient; import org.sonar.server.source.index.SourceLineDoc; import org.sonar.server.source.index.SourceLineIndex; -import org.sonar.server.user.UserSession; -import javax.annotation.CheckForNull; import javax.annotation.Nullable; + import java.util.List; public class SourceService implements ServerComponent { @@ -74,34 +68,4 @@ public class SourceService implements ServerComponent { } return lines; } - - @CheckForNull - public String getScmAuthorData(String fileKey) { - checkPermission(fileKey); - return findDataFromComponent(fileKey, CoreMetrics.SCM_AUTHORS_BY_LINE_KEY); - } - - @CheckForNull - public String getScmDateData(String fileKey) { - checkPermission(fileKey); - return findDataFromComponent(fileKey, CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE_KEY); - } - - private void checkPermission(String fileKey) { - UserSession.get().checkComponentPermission(UserRole.CODEVIEWER, fileKey); - } - - @CheckForNull - private String findDataFromComponent(String fileKey, String metricKey) { - DbSession session = dbClient.openSession(false); - try { - MeasureDto data = dbClient.measureDao().findByComponentKeyAndMetricKey(session, fileKey, metricKey); - if (data != null) { - return data.getData(); - } - return null; - } finally { - MyBatis.closeQuietly(session); - } - } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/ws/ScmAction.java b/server/sonar-server/src/main/java/org/sonar/server/source/ws/ScmAction.java deleted file mode 100644 index f214b680a10..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/source/ws/ScmAction.java +++ /dev/null @@ -1,92 +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.server.source.ws; - -import com.google.common.io.Resources; -import org.apache.commons.lang.ObjectUtils; -import org.sonar.api.server.ws.Request; -import org.sonar.api.server.ws.RequestHandler; -import org.sonar.api.server.ws.Response; -import org.sonar.api.server.ws.WebService; -import org.sonar.api.utils.text.JsonWriter; -import org.sonar.server.source.SourceService; - -public class ScmAction implements RequestHandler { - - private final SourceService service; - private final ScmWriter scmWriter; - - public ScmAction(SourceService service, ScmWriter scmWriter) { - this.service = service; - this.scmWriter = scmWriter; - } - - void define(WebService.NewController controller) { - WebService.NewAction action = controller.createAction("scm") - .setDescription("Get SCM information of source files. Require See Source Code permission on file's project<br/>" + - "Each element of the result array is composed of:" + - "<ol>" + - "<li>Line number</li>" + - "<li>Author of the commit</li>" + - "<li>Date of the commit</li>" + - "</ol>") - .setSince("4.4") - .setResponseExample(Resources.getResource(getClass(), "example-scm.json")) - .setHandler(this); - - action - .createParam("key") - .setRequired(true) - .setDescription("File key") - .setExampleValue("my_project:/src/foo/Bar.php"); - - action - .createParam("from") - .setDescription("First line to return. Starts at 1") - .setExampleValue("10") - .setDefaultValue("1"); - - action - .createParam("to") - .setDescription("Last line to return (inclusive)") - .setExampleValue("20"); - - action - .createParam("commits_by_line") - .setDescription("Group lines by SCM commit if value is false, else display commits for each line, even if two " + - "consecutive lines relate to the same commit.") - .setBooleanPossibleValues() - .setDefaultValue("false"); - } - - @Override - public void handle(Request request, Response response) { - String fileKey = request.mandatoryParam("key"); - - String authors = service.getScmAuthorData(fileKey); - String dates = service.getScmDateData(fileKey); - - JsonWriter json = response.newJsonWriter().beginObject(); - int from = Math.max(request.mandatoryParamAsInt("from"), 1); - int to = (Integer) ObjectUtils.defaultIfNull(request.paramAsInt("to"), Integer.MAX_VALUE); - scmWriter.write(authors, dates, from, to, request.mandatoryParamAsBoolean("commits_by_line"), json); - json.endObject().close(); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/ws/ScmWriter.java b/server/sonar-server/src/main/java/org/sonar/server/source/ws/ScmWriter.java deleted file mode 100644 index b95300fea51..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/source/ws/ScmWriter.java +++ /dev/null @@ -1,67 +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.server.source.ws; - -import org.sonar.api.ServerComponent; -import org.sonar.api.utils.DateUtils; -import org.sonar.api.utils.KeyValueFormat; -import org.sonar.api.utils.text.JsonWriter; - -import javax.annotation.Nullable; - -import java.util.Map; - -public class ScmWriter implements ServerComponent { - - public void write(@Nullable String authorsData, @Nullable String datesData, int from, int to, boolean showCommitsByLine, JsonWriter json) { - json.name("scm").beginArray(); - if (authorsData != null) { - Map<Integer, String> authors = KeyValueFormat.parseIntString(authorsData); - Map<Integer, String> dates = KeyValueFormat.parseIntString(datesData); - - String previousAuthor = null; - String previousDate = null; - boolean started = false; - for (Map.Entry<Integer, String> entry : authors.entrySet()) { - Integer line = entry.getKey(); - String author = entry.getValue(); - String date = dates.get(line); - String formattedDate = DateUtils.formatDate(DateUtils.parseDateTime(date)); - if (line >= from && line <= to) { - if (!started || showCommitsByLine || !isSameCommit(date, previousDate, author, previousAuthor)) { - json.beginArray(); - json.value(line); - json.value(author); - json.value(formattedDate); - json.endArray(); - started = true; - } - } - previousAuthor = author; - previousDate = date; - } - } - json.endArray(); - } - - private boolean isSameCommit(String date, String previousDate, String author, String previousAuthor) { - return author.equals(previousAuthor) && date.equals(previousDate); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/ws/SourcesWs.java b/server/sonar-server/src/main/java/org/sonar/server/source/ws/SourcesWs.java index f7dc54420fb..f87834b8714 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/source/ws/SourcesWs.java +++ b/server/sonar-server/src/main/java/org/sonar/server/source/ws/SourcesWs.java @@ -27,15 +27,13 @@ public class SourcesWs implements WebService { private final ShowAction showAction; private final LinesAction linesAction; private final RawAction rawAction; - private final ScmAction scmAction; private final HashAction hashAction; private final IndexAction indexAction; - public SourcesWs(ShowAction showAction, RawAction rawAction, ScmAction scmAction, LinesAction linesAction, HashAction hashAction, IndexAction indexAction) { + public SourcesWs(ShowAction showAction, RawAction rawAction, LinesAction linesAction, HashAction hashAction, IndexAction indexAction) { this.showAction = showAction; this.linesAction = linesAction; this.rawAction = rawAction; - this.scmAction = scmAction; this.hashAction = hashAction; this.indexAction = indexAction; } @@ -48,7 +46,6 @@ public class SourcesWs implements WebService { showAction.define(controller); linesAction.define(controller); rawAction.define(controller); - scmAction.define(controller); hashAction.define(controller); indexAction.define(controller); controller.done(); diff --git a/server/sonar-server/src/test/java/org/sonar/server/source/SourceServiceTest.java b/server/sonar-server/src/test/java/org/sonar/server/source/SourceServiceTest.java index 468f6cdd89b..100348abe6c 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/source/SourceServiceTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/source/SourceServiceTest.java @@ -25,11 +25,9 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; -import org.sonar.api.measures.CoreMetrics; import org.sonar.api.web.UserRole; import org.sonar.core.persistence.DbSession; import org.sonar.server.db.DbClient; -import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.measure.persistence.MeasureDao; import org.sonar.server.source.index.SourceLineDoc; import org.sonar.server.source.index.SourceLineIndex; @@ -39,10 +37,9 @@ import java.util.Arrays; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) public class SourceServiceTest { @@ -93,45 +90,6 @@ public class SourceServiceTest { } @Test - public void get_scm_author_data() throws Exception { - service.getScmAuthorData(COMPONENT_UUID); - verify(measureDao).findByComponentKeyAndMetricKey(session, COMPONENT_UUID, CoreMetrics.SCM_AUTHORS_BY_LINE_KEY); - } - - @Test - public void fail_to_get_scm_author_data_if_no_permission() throws Exception { - MockUserSession.set().setLogin("johh"); - try { - service.getScmAuthorData(COMPONENT_UUID); - fail(); - } catch (Exception e) { - assertThat(e).isInstanceOf(ForbiddenException.class); - } - verifyZeroInteractions(measureDao); - } - - @Test - public void not_get_scm_author_data_if_no_data() throws Exception { - MockUserSession.set().addComponentPermission(UserRole.CODEVIEWER, PROJECT_KEY, COMPONENT_UUID); - when(measureDao.findByComponentKeyAndMetricKey(eq(session), anyString(), anyString())).thenReturn(null); - assertThat(service.getScmAuthorData(COMPONENT_UUID)).isNull(); - } - - @Test - public void get_scm_date_data() throws Exception { - MockUserSession.set().addComponentPermission(UserRole.CODEVIEWER, PROJECT_KEY, COMPONENT_UUID); - service.getScmDateData(COMPONENT_UUID); - verify(measureDao).findByComponentKeyAndMetricKey(session, COMPONENT_UUID, CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE_KEY); - } - - @Test - public void not_get_scm_date_data_if_no_data() throws Exception { - MockUserSession.set().addComponentPermission(UserRole.CODEVIEWER, PROJECT_KEY, COMPONENT_UUID); - when(measureDao.findByComponentKeyAndMetricKey(eq(session), anyString(), anyString())).thenReturn(null); - assertThat(service.getScmDateData(COMPONENT_UUID)).isNull(); - } - - @Test public void getLinesAsTxt() throws Exception { MockUserSession.set().addComponentPermission(UserRole.CODEVIEWER, PROJECT_KEY, COMPONENT_UUID); when(sourceLineIndex.getLines(COMPONENT_UUID, 1, Integer.MAX_VALUE)).thenReturn( diff --git a/server/sonar-server/src/test/java/org/sonar/server/source/ws/HashActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/source/ws/HashActionTest.java index 65616c6f3c7..5d74342ae99 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/source/ws/HashActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/source/ws/HashActionTest.java @@ -67,7 +67,6 @@ public class HashActionTest { new SourcesWs( mock(ShowAction.class), mock(RawAction.class), - mock(ScmAction.class), mock(LinesAction.class), new HashAction(dbClient), mock(IndexAction.class) diff --git a/server/sonar-server/src/test/java/org/sonar/server/source/ws/IndexActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/source/ws/IndexActionTest.java index 079666645dd..efcb5258229 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/source/ws/IndexActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/source/ws/IndexActionTest.java @@ -66,7 +66,7 @@ public class IndexActionTest { public void setUp() throws Exception { when(dbClient.componentDao()).thenReturn(componentDao); when(dbClient.openSession(false)).thenReturn(session); - tester = new WsTester(new SourcesWs(mock(ShowAction.class), mock(RawAction.class), mock(ScmAction.class), mock(LinesAction.class), + tester = new WsTester(new SourcesWs(mock(ShowAction.class), mock(RawAction.class), mock(LinesAction.class), mock(HashAction.class), new IndexAction(dbClient, sourceService))); } @@ -116,7 +116,7 @@ public class IndexActionTest { WsTester.TestRequest request = tester.newGetRequest("api/sources", "index").setParam("resource", fileKey); try { request.execute(); - } catch(NotFoundException nfe) { + } catch (NotFoundException nfe) { verify(session).close(); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/source/ws/LinesActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/source/ws/LinesActionTest.java index bcd67c877c1..91e73188d66 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/source/ws/LinesActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/source/ws/LinesActionTest.java @@ -72,18 +72,17 @@ public class LinesActionTest { new SourcesWs( mock(ShowAction.class), mock(RawAction.class), - mock(ScmAction.class), new LinesAction(sourceLineIndex, htmlSourceDecorator, componentService), mock(HashAction.class), mock(IndexAction.class) ) - ); + ); when(htmlSourceDecorator.getDecoratedSourceAsHtml(anyString(), anyString(), anyString())).thenAnswer(new Answer<String>() { @Override public String answer(InvocationOnMock invocation) throws Throwable { return "<span class=\"" + invocation.getArguments()[1] + " sym-" + invocation.getArguments()[2] + "\">" + StringEscapeUtils.escapeHtml((String) invocation.getArguments()[0]) + - "</span>"; + "</span>"; } }); } @@ -155,7 +154,7 @@ public class LinesActionTest { line1, line2, line3 - )); + )); String componentKey = "componentKey"; when(componentService.getByUuid(componentUuid)).thenReturn(new ComponentDto().setKey(componentKey).setProjectUuid(projectUuid)); @@ -213,7 +212,7 @@ public class LinesActionTest { .setItCoveredConditions(null) .setDuplications(null) .setUpdateDate(new Date()) - )); + )); WsTester.TestRequest request = tester .newGetRequest("api/sources", "lines") .setParam("uuid", fileUuid) diff --git a/server/sonar-server/src/test/java/org/sonar/server/source/ws/RawActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/source/ws/RawActionTest.java index ed2f15ef01e..28de2fb6f67 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/source/ws/RawActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/source/ws/RawActionTest.java @@ -65,7 +65,7 @@ public class RawActionTest { public void setUp() throws Exception { when(dbClient.componentDao()).thenReturn(componentDao); when(dbClient.openSession(false)).thenReturn(session); - tester = new WsTester(new SourcesWs(mock(ShowAction.class), new RawAction(dbClient, sourceService), mock(ScmAction.class), mock(LinesAction.class), + tester = new WsTester(new SourcesWs(mock(ShowAction.class), new RawAction(dbClient, sourceService), mock(LinesAction.class), mock(HashAction.class), mock(IndexAction.class))); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/source/ws/ScmActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/source/ws/ScmActionTest.java deleted file mode 100644 index 97ccb21efa6..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/source/ws/ScmActionTest.java +++ /dev/null @@ -1,83 +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.server.source.ws; - -import org.junit.Test; -import org.sonar.api.utils.text.JsonWriter; -import org.sonar.server.source.SourceService; -import org.sonar.server.ws.WsTester; - -import static org.mockito.Matchers.any; -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 ScmActionTest { - - SourceService sourceService = mock(SourceService.class); - ScmWriter scmWriter = mock(ScmWriter.class); - WsTester tester = new WsTester(new SourcesWs(mock(ShowAction.class), mock(RawAction.class), new ScmAction(sourceService, scmWriter), mock(LinesAction.class), - mock(HashAction.class), mock(IndexAction.class))); - - @Test - public void get_scm() throws Exception { - String fileKey = "src/Foo.java"; - when(sourceService.getScmAuthorData(fileKey)).thenReturn("1=julien"); - when(sourceService.getScmDateData(fileKey)).thenReturn("1=2013-01-01"); - - WsTester.TestRequest request = tester.newGetRequest("api/sources", "scm").setParam("key", fileKey); - request.execute(); - verify(scmWriter).write(eq("1=julien"), eq("1=2013-01-01"), eq(1), eq(Integer.MAX_VALUE), eq(false), any(JsonWriter.class)); - } - - @Test - public void do_not_group_lines_by_commit() throws Exception { - String fileKey = "src/Foo.java"; - when(sourceService.getScmAuthorData(fileKey)).thenReturn("1=julien"); - when(sourceService.getScmDateData(fileKey)).thenReturn("1=2013-01-01"); - - WsTester.TestRequest request = tester.newGetRequest("api/sources", "scm").setParam("key", fileKey).setParam("commits_by_line", "true"); - request.execute(); - verify(scmWriter).write(eq("1=julien"), eq("1=2013-01-01"), eq(1), eq(Integer.MAX_VALUE), eq(true), any(JsonWriter.class)); - } - - @Test - public void range_of_lines() throws Exception { - String fileKey = "src/Foo.java"; - when(sourceService.getScmAuthorData(fileKey)).thenReturn("1=julien"); - when(sourceService.getScmDateData(fileKey)).thenReturn("1=2013-01-01"); - - WsTester.TestRequest request = tester.newGetRequest("api/sources", "scm").setParam("key", fileKey).setParam("from", "3").setParam("to", "20"); - request.execute(); - verify(scmWriter).write(eq("1=julien"), eq("1=2013-01-01"), eq(3), eq(20), eq(false), any(JsonWriter.class)); - } - - @Test - public void accept_negative_from_line() throws Exception { - String fileKey = "src/Foo.java"; - when(sourceService.getScmAuthorData(fileKey)).thenReturn("1=julien"); - when(sourceService.getScmDateData(fileKey)).thenReturn("1=2013-01-01"); - - WsTester.TestRequest request = tester.newGetRequest("api/sources", "scm").setParam("key", fileKey).setParam("from", "-3").setParam("to", "20"); - request.execute(); - verify(scmWriter).write(eq("1=julien"), eq("1=2013-01-01"), eq(1), eq(20), eq(false), any(JsonWriter.class)); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/source/ws/ScmWriterTest.java b/server/sonar-server/src/test/java/org/sonar/server/source/ws/ScmWriterTest.java deleted file mode 100644 index cf05251cf34..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/source/ws/ScmWriterTest.java +++ /dev/null @@ -1,73 +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.server.source.ws; - -import org.junit.Test; -import org.sonar.api.utils.text.JsonWriter; -import org.sonar.test.JsonAssert; - -import java.io.StringWriter; - -public class ScmWriterTest { - - ScmWriter writer = new ScmWriter(); - - @Test - public void write_authors_and_dates() throws Exception { - // same commit on lines 1 and 2 - test("1=julien;2=julien;3=simon;", "1=2013-03-13T16:22:31+0100;2=2013-03-13T16:22:31+0100;3=2014-01-01T16:22:31+0100;", 1, Integer.MAX_VALUE, true, - "{\"scm\": [[1, \"julien\", \"2013-03-13\"], [2, \"julien\", \"2013-03-13\"], [3, \"simon\", \"2014-01-01\"]]}"); - } - - @Test - public void filter_by_range_of_lines() throws Exception { - String authors = "1=julien;2=simon;"; - String dates = "1=2013-03-13T16:22:31+0100;2=2014-01-01T16:22:31+0100;"; - - test(authors, dates, 2, 200, true, "{\"scm\": [[2, \"simon\", \"2014-01-01\"]]}"); - test(authors, dates, 3, 5, true, "{\"scm\": []}"); - test(authors, dates, -2, 1, true, "{\"scm\": [[1, \"julien\", \"2013-03-13\"]]}"); - } - - @Test - public void group_by_commits() throws Exception { - // lines 1 and 2 are the same commit, but not 3 (different date) - String authors = "1=julien;2=julien;3=julien;4=simon;"; - String dates = "1=2013-03-13T16:22:31+0100;2=2013-03-13T16:22:31+0100;3=2013-03-14T16:22:31+0100;4=2014-01-01T16:22:31+0100"; - - test(authors, dates, 1, Integer.MAX_VALUE, false, - "{\"scm\": [[1, \"julien\", \"2013-03-13\"], [3, \"julien\", \"2013-03-14\"], [4, \"simon\", \"2014-01-01\"]]}"); - - test(authors, dates, 2, 4, false, - "{\"scm\": [[2, \"julien\", \"2013-03-13\"], [3, \"julien\", \"2013-03-14\"], [4, \"simon\", \"2014-01-01\"]]}"); - - test(authors, dates, 1, 2, false, "{\"scm\": [[1, \"julien\", \"2013-03-13\"]]}"); - test(authors, dates, 10, 20, false, "{\"scm\": []}"); - } - - private void test(String authors, String dates, int from, int to, boolean group, String expected) { - StringWriter output = new StringWriter(); - JsonWriter jsonWriter = JsonWriter.of(output); - jsonWriter.beginObject(); - writer.write(authors, dates, from, to, group, jsonWriter); - jsonWriter.endObject(); - JsonAssert.assertJson(output.toString()).isSimilarTo(expected); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/source/ws/ShowActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/source/ws/ShowActionTest.java index c3471efa0bb..4763f2f91f6 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/source/ws/ShowActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/source/ws/ShowActionTest.java @@ -65,7 +65,7 @@ public class ShowActionTest { public void setUp() throws Exception { when(dbClient.componentDao()).thenReturn(componentDao); when(dbClient.openSession(false)).thenReturn(session); - tester = new WsTester(new SourcesWs(new ShowAction(sourceService, dbClient), mock(RawAction.class), new ScmAction(sourceService, mock(ScmWriter.class)), + tester = new WsTester(new SourcesWs(new ShowAction(sourceService, dbClient), mock(RawAction.class), mock(LinesAction.class), mock(HashAction.class), mock(IndexAction.class))); diff --git a/server/sonar-server/src/test/java/org/sonar/server/source/ws/SourcesWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/source/ws/SourcesWsTest.java index f56d738f99e..491d42912e6 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/source/ws/SourcesWsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/source/ws/SourcesWsTest.java @@ -36,11 +36,10 @@ public class SourcesWsTest { ShowAction showAction = new ShowAction(mock(SourceService.class), mock(DbClient.class)); RawAction rawAction = new RawAction(mock(DbClient.class), mock(SourceService.class)); - ScmAction scmAction = new ScmAction(mock(SourceService.class), new ScmWriter()); LinesAction linesAction = new LinesAction(mock(SourceLineIndex.class), mock(HtmlSourceDecorator.class), mock(ComponentService.class)); HashAction hashAction = new HashAction(mock(DbClient.class)); IndexAction indexAction = new IndexAction(mock(DbClient.class), mock(SourceService.class)); - WsTester tester = new WsTester(new SourcesWs(showAction, rawAction, scmAction, linesAction, hashAction, indexAction)); + WsTester tester = new WsTester(new SourcesWs(showAction, rawAction, linesAction, hashAction, indexAction)); @Test public void define_ws() throws Exception { @@ -48,7 +47,7 @@ public class SourcesWsTest { assertThat(controller).isNotNull(); assertThat(controller.since()).isEqualTo("4.2"); assertThat(controller.description()).isNotEmpty(); - assertThat(controller.actions()).hasSize(6); + assertThat(controller.actions()).hasSize(5); WebService.Action show = controller.action("show"); assertThat(show).isNotNull(); @@ -66,14 +65,6 @@ public class SourcesWsTest { assertThat(raw.responseExampleAsString()).isNotEmpty(); assertThat(raw.params()).hasSize(1); - WebService.Action scm = controller.action("scm"); - assertThat(scm).isNotNull(); - assertThat(scm.handler()).isSameAs(scmAction); - assertThat(scm.since()).isEqualTo("4.4"); - assertThat(scm.isInternal()).isFalse(); - assertThat(scm.responseExampleAsString()).isNotEmpty(); - assertThat(scm.params()).hasSize(4); - WebService.Action lines = controller.action("lines"); assertThat(lines).isNotNull(); assertThat(lines.handler()).isSameAs(linesAction); diff --git a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/input/FileData.java b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/input/FileData.java index d68bcbd3c61..28b8083c0e2 100644 --- a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/input/FileData.java +++ b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/input/FileData.java @@ -26,16 +26,10 @@ public class FileData { private final String hash; private final boolean needBlame; - private final String scmLastCommitDatetimesByLine; - private final String scmRevisionsByLine; - private final String scmAuthorsByLine; - public FileData(@Nullable String hash, boolean needBlame, @Nullable String scmLastCommitDatetimesByLine, @Nullable String scmRevisionsByLine, @Nullable String scmAuthorsByLine) { + public FileData(@Nullable String hash, boolean needBlame) { this.hash = hash; this.needBlame = needBlame; - this.scmLastCommitDatetimesByLine = scmLastCommitDatetimesByLine; - this.scmRevisionsByLine = scmRevisionsByLine; - this.scmAuthorsByLine = scmAuthorsByLine; } @CheckForNull @@ -47,19 +41,4 @@ public class FileData { return needBlame; } - @CheckForNull - public String scmLastCommitDatetimesByLine() { - return scmLastCommitDatetimesByLine; - } - - @CheckForNull - public String scmRevisionsByLine() { - return scmRevisionsByLine; - } - - @CheckForNull - public String scmAuthorsByLine() { - return scmAuthorsByLine; - } - } diff --git a/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/input/ProjectRepositoriesTest.java b/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/input/ProjectRepositoriesTest.java index b86b2938f15..91a1b171df6 100644 --- a/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/input/ProjectRepositoriesTest.java +++ b/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/input/ProjectRepositoriesTest.java @@ -50,8 +50,8 @@ public class ProjectRepositoriesTest { ref.addActiveRule(activeRule); ref.setLastAnalysisDate(DATE_FORMAT.parse("2014-05-18T15:50:45+0100")); ref.setTimestamp(10); - ref.addFileData("foo", "src/main/java/Foo.java", new FileData("xyz", true, "1=12345,2=3456", "1=345,2=345", "1=henryju,2=gaudin")); - ref.addFileData("foo", "src/main/java/Foo2.java", new FileData("xyz", false, "1=12345,2=3456", "1=345,2=345", "1=henryju,2=gaudin")); + ref.addFileData("foo", "src/main/java/Foo.java", new FileData("xyz", true)); + ref.addFileData("foo", "src/main/java/Foo2.java", new FileData("xyz", false)); JsonAssert.assertJson(ref.toJson()) .isSimilarTo(getClass().getResource("ProjectRepositoriesTest/testToJson.json")); @@ -89,9 +89,6 @@ public class ProjectRepositoriesTest { assertThat(ref.fileData("foo", "src/main/java/Foo.java").hash()).isEqualTo("xyz"); assertThat(ref.fileData("foo", "src/main/java/Foo.java").needBlame()).isTrue(); - assertThat(ref.fileData("foo", "src/main/java/Foo.java").scmAuthorsByLine()).isEqualTo("1=henryju,2=gaudin"); - assertThat(ref.fileData("foo", "src/main/java/Foo.java").scmLastCommitDatetimesByLine()).isEqualTo("1=12345,2=3456"); - assertThat(ref.fileData("foo", "src/main/java/Foo.java").scmRevisionsByLine()).isEqualTo("1=345,2=345"); assertThat(ref.lastAnalysisDate().getTime()).isEqualTo(DATE_FORMAT.parse("2014-10-31T00:00:00+0100").getTime()); } diff --git a/sonar-batch-protocol/src/test/resources/org/sonar/batch/protocol/input/ProjectRepositoriesTest/testToJson.json b/sonar-batch-protocol/src/test/resources/org/sonar/batch/protocol/input/ProjectRepositoriesTest/testToJson.json index 7b5e29c3695..d728bdc4414 100644 --- a/sonar-batch-protocol/src/test/resources/org/sonar/batch/protocol/input/ProjectRepositoriesTest/testToJson.json +++ b/sonar-batch-protocol/src/test/resources/org/sonar/batch/protocol/input/ProjectRepositoriesTest/testToJson.json @@ -32,16 +32,10 @@ "src/main/java/Foo.java": { "hash": "xyz", "needBlame": true, - "scmLastCommitDatetimesByLine": "1\u003d12345,2\u003d3456", - "scmRevisionsByLine": "1\u003d345,2\u003d345", - "scmAuthorsByLine": "1\u003dhenryju,2\u003dgaudin" }, "src/main/java/Foo2.java": { "hash": "xyz", "needBlame": false, - "scmLastCommitDatetimesByLine": "1\u003d12345,2\u003d3456", - "scmRevisionsByLine": "1\u003d345,2\u003d345", - "scmAuthorsByLine": "1\u003dhenryju,2\u003dgaudin" } } }, diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java index ff223b4b9f4..33f6246ea8c 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java +++ b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java @@ -70,11 +70,7 @@ public class DefaultIndex extends SonarIndex { CoreMetrics.FILE_FEEDBACK_EDGES, CoreMetrics.FILE_TANGLE_INDEX, CoreMetrics.FILE_TANGLES, - // Computed by ScmSensor - CoreMetrics.SCM_AUTHORS_BY_LINE, - CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE, - CoreMetrics.SCM_REVISIONS_BY_LINE, - // Computed by core duplication plugin + // Computed by CpdSensor CoreMetrics.DUPLICATIONS_DATA, CoreMetrics.DUPLICATION_LINES_DATA, CoreMetrics.DUPLICATED_FILES, diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/ResourceCache.java b/sonar-batch/src/main/java/org/sonar/batch/index/ResourceCache.java index 4a97a6c8ab8..3b1ec2fe187 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/index/ResourceCache.java +++ b/sonar-batch/src/main/java/org/sonar/batch/index/ResourceCache.java @@ -23,6 +23,8 @@ import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.google.common.collect.Maps; import org.sonar.api.BatchComponent; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.resources.Library; import org.sonar.api.resources.Resource; @@ -54,6 +56,10 @@ public class ResourceCache implements BatchComponent { } } + public BatchResource get(InputFile inputFile) { + return resources.get(((DefaultInputFile) inputFile).key()); + } + public BatchResource add(Resource resource, @Nullable Resource parentResource) { String componentKey = resource.getEffectiveKey(); Preconditions.checkState(!Strings.isNullOrEmpty(componentKey), "Missing resource effective key"); diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/SourceDataFactory.java b/sonar-batch/src/main/java/org/sonar/batch/index/SourceDataFactory.java index 2aa0b854e01..d2197170309 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/index/SourceDataFactory.java +++ b/sonar-batch/src/main/java/org/sonar/batch/index/SourceDataFactory.java @@ -30,10 +30,13 @@ import org.sonar.api.batch.sensor.highlighting.internal.SyntaxHighlightingRule; import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.Measure; import org.sonar.api.source.Symbol; -import org.sonar.api.utils.DateUtils; import org.sonar.api.utils.KeyValueFormat; import org.sonar.batch.duplication.DuplicationCache; import org.sonar.batch.highlighting.SyntaxHighlightingData; +import org.sonar.batch.protocol.output.BatchReport.Scm; +import org.sonar.batch.protocol.output.BatchReport.Scm.Changeset; +import org.sonar.batch.protocol.output.BatchReportReader; +import org.sonar.batch.report.PublishReportJob; import org.sonar.batch.scan.filesystem.InputFileMetadata; import org.sonar.batch.scan.measure.MeasureCache; import org.sonar.batch.source.CodeColorizers; @@ -41,6 +44,7 @@ import org.sonar.batch.symbol.SymbolData; import org.sonar.core.source.SnapshotDataTypes; import org.sonar.core.source.db.FileSourceDto; import org.sonar.server.source.db.FileSourceDb; +import org.sonar.server.source.db.FileSourceDb.Data.Builder; import java.io.IOException; import java.util.*; @@ -57,18 +61,24 @@ public class SourceDataFactory implements BatchComponent { private final ComponentDataCache componentDataCache; private final DuplicationCache duplicationCache; private final CodeColorizers codeColorizers; + private final PublishReportJob publishReportJob; + + private final ResourceCache resourceCache; public SourceDataFactory(MeasureCache measureCache, ComponentDataCache componentDataCache, - DuplicationCache duplicationCache, CodeColorizers codeColorizers) { + DuplicationCache duplicationCache, CodeColorizers codeColorizers, PublishReportJob publishReportJob, ResourceCache resourceCache) { this.measureCache = measureCache; this.componentDataCache = componentDataCache; this.duplicationCache = duplicationCache; this.codeColorizers = codeColorizers; + this.publishReportJob = publishReportJob; + this.resourceCache = resourceCache; } public byte[] consolidateData(DefaultInputFile inputFile, InputFileMetadata metadata) throws IOException { FileSourceDb.Data.Builder dataBuilder = createForSource(inputFile); applyLineMeasures(inputFile, dataBuilder); + applyScm(inputFile, dataBuilder); applyDuplications(inputFile.key(), dataBuilder); applyHighlighting(inputFile, metadata, dataBuilder); applySymbolReferences(inputFile, metadata, dataBuilder); @@ -90,25 +100,30 @@ public class SourceDataFactory implements BatchComponent { return result; } - void applyLineMeasures(DefaultInputFile file, FileSourceDb.Data.Builder dataBuilder) { - applyLineMeasure(file.key(), CoreMetrics.SCM_AUTHORS_BY_LINE_KEY, dataBuilder, new MeasureOperation() { - @Override - public void apply(String value, FileSourceDb.Line.Builder lineBuilder) { - lineBuilder.setScmAuthor(value); - } - }); - applyLineMeasure(file.key(), CoreMetrics.SCM_REVISIONS_BY_LINE_KEY, dataBuilder, new MeasureOperation() { - @Override - public void apply(String value, FileSourceDb.Line.Builder lineBuilder) { - lineBuilder.setScmRevision(value); - } - }); - applyLineMeasure(file.key(), CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE_KEY, dataBuilder, new MeasureOperation() { - @Override - public void apply(String value, FileSourceDb.Line.Builder lineBuilder) { - lineBuilder.setScmDate(DateUtils.parseDateTimeQuietly(value).getTime()); + void applyScm(DefaultInputFile inputFile, Builder dataBuilder) { + BatchReportReader reader = new BatchReportReader(publishReportJob.getReportDir()); + Scm componentScm = reader.readComponentScm(resourceCache.get(inputFile).batchId()); + if (componentScm != null) { + for (int i = 0; i < componentScm.getChangesetIndexByLineCount(); i++) { + int index = componentScm.getChangesetIndexByLine(i); + Changeset changeset = componentScm.getChangeset(index); + if (i < dataBuilder.getLinesCount()) { + FileSourceDb.Line.Builder lineBuilder = dataBuilder.getLinesBuilder(i); + if (changeset.hasAuthor()) { + lineBuilder.setScmAuthor(changeset.getAuthor()); + } + if (changeset.hasRevision()) { + lineBuilder.setScmRevision(changeset.getRevision()); + } + if (changeset.hasDate()) { + lineBuilder.setScmDate(changeset.getDate()); + } + } } - }); + } + } + + void applyLineMeasures(DefaultInputFile file, FileSourceDb.Data.Builder dataBuilder) { applyLineMeasure(file.key(), CoreMetrics.COVERAGE_LINE_HITS_DATA_KEY, dataBuilder, new MeasureOperation() { @Override public void apply(String value, FileSourceDb.Line.Builder lineBuilder) { @@ -167,17 +182,16 @@ public class SourceDataFactory implements BatchComponent { void applyLineMeasure(String inputFileKey, String metricKey, FileSourceDb.Data.Builder to, MeasureOperation op) { Iterable<Measure> measures = measureCache.byMetric(inputFileKey, metricKey); - if (measures != null) { - for (Measure measure : measures) { - Map<Integer, String> lineMeasures = KeyValueFormat.parseIntString((String) measure.value()); - for (Map.Entry<Integer, String> lineMeasure : lineMeasures.entrySet()) { - int lineIdx = lineMeasure.getKey(); - if (lineIdx <= to.getLinesCount()) { - String value = lineMeasure.getValue(); - if (StringUtils.isNotEmpty(value)) { - FileSourceDb.Line.Builder lineBuilder = to.getLinesBuilder(lineIdx - 1); - op.apply(value, lineBuilder); - } + if (measures.iterator().hasNext()) { + Measure measure = measures.iterator().next(); + Map<Integer, String> lineMeasures = KeyValueFormat.parseIntString((String) measure.value()); + for (Map.Entry<Integer, String> lineMeasure : lineMeasures.entrySet()) { + int lineIdx = lineMeasure.getKey(); + if (lineIdx <= to.getLinesCount()) { + String value = lineMeasure.getValue(); + if (StringUtils.isNotEmpty(value)) { + FileSourceDb.Line.Builder lineBuilder = to.getLinesBuilder(lineIdx - 1); + op.apply(value, lineBuilder); } } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java index ed0142bcace..6200c172993 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java +++ b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java @@ -36,6 +36,7 @@ import org.sonar.batch.bootstrapper.EnvironmentInformation; import org.sonar.batch.issue.tracking.ServerLineHashesLoader; import org.sonar.batch.protocol.input.*; import org.sonar.batch.protocol.input.BatchInput.ServerIssue; +import org.sonar.batch.report.PublishReportJob; import org.sonar.batch.repository.GlobalRepositoriesLoader; import org.sonar.batch.repository.ProjectRepositoriesLoader; import org.sonar.batch.repository.ServerIssuesLoader; @@ -61,6 +62,7 @@ public class BatchMediumTester { public static BatchMediumTesterBuilder builder() { BatchMediumTesterBuilder builder = new BatchMediumTesterBuilder().registerCoreMetrics(); builder.bootstrapProperties.put(MEDIUM_TEST_ENABLED, "true"); + builder.bootstrapProperties.put(PublishReportJob.KEEP_REPORT_PROP_KEY, "true"); builder.bootstrapProperties.put(CoreProperties.WORKING_DIRECTORY, Files.createTempDir().getAbsolutePath()); return builder; } 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 3a70259bede..9fe5d4bbd8b 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 @@ -22,13 +22,16 @@ package org.sonar.batch.report; import com.github.kevinsawicki.http.HttpRequest; import com.google.common.annotations.VisibleForTesting; import org.apache.commons.io.FileUtils; +import org.codehaus.plexus.personality.plexus.lifecycle.phase.Startable; +import org.codehaus.plexus.personality.plexus.lifecycle.phase.StartingException; +import org.codehaus.plexus.personality.plexus.lifecycle.phase.StoppingException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.BatchComponent; import org.sonar.api.CoreProperties; +import org.sonar.api.batch.bootstrap.ProjectReactor; import org.sonar.api.config.Settings; import org.sonar.api.platform.Server; -import org.sonar.api.resources.Project; import org.sonar.api.utils.TempFolder; import org.sonar.api.utils.ZipUtils; import org.sonar.batch.bootstrap.DefaultAnalysisMode; @@ -40,33 +43,55 @@ import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; -public class PublishReportJob implements BatchComponent { +public class PublishReportJob implements BatchComponent, Startable { private static final Logger LOG = LoggerFactory.getLogger(PublishReportJob.class); + public static final String KEEP_REPORT_PROP_KEY = "sonar.batch.keepReport"; private final ServerClient serverClient; private final Server server; private final Settings settings; - private final Project project; + private final ProjectReactor projectReactor; private final DefaultAnalysisMode analysisMode; private final TempFolder temp; private ReportPublisher[] publishers; + private File reportDir; + private BatchReportWriter writer; + public PublishReportJob(Settings settings, ServerClient serverClient, Server server, - Project project, DefaultAnalysisMode analysisMode, TempFolder temp, ReportPublisher[] publishers) { + ProjectReactor projectReactor, DefaultAnalysisMode analysisMode, TempFolder temp, ReportPublisher[] publishers) { this.serverClient = serverClient; this.server = server; - this.project = project; + this.projectReactor = projectReactor; this.settings = settings; this.analysisMode = analysisMode; this.temp = temp; this.publishers = publishers; } - public PublishReportJob(Settings settings, ServerClient serverClient, Server server, - Project project, DefaultAnalysisMode analysisMode, TempFolder temp) { - this(settings, serverClient, server, project, analysisMode, temp, new ReportPublisher[0]); + @Override + public void start() throws StartingException { + reportDir = new File(projectReactor.getRoot().getWorkDir(), "batch-report"); + writer = new BatchReportWriter(reportDir); + } + + @Override + public void stop() throws StoppingException { + if (!settings.getBoolean(KEEP_REPORT_PROP_KEY)) { + FileUtils.deleteQuietly(reportDir); + } else { + LOG.info("Batch report generated in " + reportDir); + } + } + + public File getReportDir() { + return reportDir; + } + + public BatchReportWriter getWriter() { + return writer; } public void execute() { @@ -83,8 +108,6 @@ public class PublishReportJob implements BatchComponent { private File prepareReport() { try { long startTime = System.currentTimeMillis(); - File reportDir = temp.newDir("batch-report"); - BatchReportWriter writer = new BatchReportWriter(reportDir); for (ReportPublisher publisher : publishers) { publisher.publish(writer); } @@ -94,7 +117,6 @@ public class PublishReportJob implements BatchComponent { startTime = System.currentTimeMillis(); File reportZip = temp.newFile("batch-report", ".zip"); ZipUtils.zipDir(reportDir, reportZip); - FileUtils.deleteDirectory(reportDir); stopTime = System.currentTimeMillis(); LOG.info("Analysis reports compressed in " + (stopTime - startTime) + "ms, zip size=" + FileUtils.byteCountToDisplaySize(FileUtils.sizeOf(reportZip))); return reportZip; @@ -109,7 +131,8 @@ public class PublishReportJob implements BatchComponent { long startTime = System.currentTimeMillis(); URL url; try { - url = new URL(serverClient.getURL() + "/api/computation/submit_report?projectKey=" + project.getEffectiveKey()); + String effectiveKey = projectReactor.getRoot().getKeyWithBranch(); + url = new URL(serverClient.getURL() + "/api/computation/submit_report?projectKey=" + effectiveKey); } catch (MalformedURLException e) { throw new IllegalArgumentException("Invalid URL", e); } @@ -148,7 +171,8 @@ public class PublishReportJob implements BatchComponent { if (!baseUrl.endsWith("/")) { baseUrl += "/"; } - String url = baseUrl + "dashboard/index/" + project.getKey(); + String effectiveKey = projectReactor.getRoot().getKeyWithBranch(); + String url = baseUrl + "dashboard/index/" + effectiveKey; logger.info("ANALYSIS SUCCESSFUL, you can browse {}", url); logger.info("Note that you will be able to access the updated dashboard once the server has processed the submitted analysis report."); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectScmRepositoryLoader.java b/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectScmRepositoryLoader.java deleted file mode 100644 index a5ee07dd685..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectScmRepositoryLoader.java +++ /dev/null @@ -1,155 +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.repository; - -import com.google.common.collect.Maps; -import org.sonar.api.BatchComponent; -import org.sonar.api.batch.RequiresDB; -import org.sonar.api.batch.bootstrap.ProjectDefinition; -import org.sonar.api.batch.bootstrap.ProjectReactor; -import org.sonar.api.database.DatabaseSession; -import org.sonar.api.database.model.MeasureModel; -import org.sonar.api.database.model.ResourceModel; -import org.sonar.api.database.model.Snapshot; -import org.sonar.api.measures.CoreMetrics; -import org.sonar.api.measures.Metric; -import org.sonar.api.resources.Qualifiers; -import org.sonar.batch.protocol.input.FileData; -import org.sonar.batch.protocol.input.ProjectRepositories; - -import javax.annotation.CheckForNull; -import javax.persistence.NoResultException; -import javax.persistence.Query; - -import java.util.Arrays; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import static org.sonar.api.utils.DateUtils.longToDate; - -/** - * Waiting for SCM measure copy to be handled in computation stack we need to get previous measures from DB - */ -@RequiresDB -public class ProjectScmRepositoryLoader implements BatchComponent { - - private final DatabaseSession session; - private final ProjectReactor reactor; - private final ProjectRepositories ref; - - public ProjectScmRepositoryLoader(DatabaseSession session, ProjectReactor reactor, ProjectRepositories ref) { - this.session = session; - this.reactor = reactor; - this.ref = ref; - } - - public void complete() { - for (ProjectDefinition module : reactor.getProjects()) { - - for (Entry<String, FileData> fileDataByPaths : ref.fileDataByPath(module.getKeyWithBranch()).entrySet()) { - String path = fileDataByPaths.getKey(); - FileData fileData = fileDataByPaths.getValue(); - String lastCommits = null; - String revisions = null; - String authors = null; - List<Object[]> measuresByKey = query(module.getKeyWithBranch() + ":" + path, CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE_KEY, CoreMetrics.SCM_REVISIONS_BY_LINE_KEY, - CoreMetrics.SCM_AUTHORS_BY_LINE_KEY); - for (Object[] measureByKey : measuresByKey) { - if (measureByKey[0].equals(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE_KEY)) { - lastCommits = ((MeasureModel) measureByKey[1]).getData(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE); - } else if (measureByKey[0].equals(CoreMetrics.SCM_REVISIONS_BY_LINE_KEY)) { - revisions = ((MeasureModel) measureByKey[1]).getData(CoreMetrics.SCM_REVISIONS_BY_LINE); - } else if (measureByKey[0].equals(CoreMetrics.SCM_AUTHORS_BY_LINE_KEY)) { - authors = ((MeasureModel) measureByKey[1]).getData(CoreMetrics.SCM_AUTHORS_BY_LINE); - } - } - ref.addFileData(module.getKeyWithBranch(), path, new FileData(fileData.hash(), authors == null, lastCommits, revisions, authors)); - } - } - ref.setLastAnalysisDate(lastSnapshotCreationDate(reactor.getRoot().getKeyWithBranch())); - } - - private List<Object[]> query(String resourceKey, String... metricKeys) { - StringBuilder sb = new StringBuilder(); - Map<String, Object> params = Maps.newHashMap(); - - sb.append("SELECT met.key, m"); - sb.append(" FROM ") - .append(MeasureModel.class.getSimpleName()) - .append(" m, ") - .append(Metric.class.getSimpleName()) - .append(" met, ") - .append(ResourceModel.class.getSimpleName()) - .append(" r, ") - .append(Snapshot.class.getSimpleName()) - .append(" s WHERE met.id=m.metricId AND m.snapshotId=s.id AND s.resourceId=r.id AND r.key=:kee AND s.status=:status AND s.qualifier<>:lib"); - params.put("kee", resourceKey); - params.put("status", Snapshot.STATUS_PROCESSED); - params.put("lib", Qualifiers.LIBRARY); - - sb.append(" AND m.characteristicId IS NULL"); - sb.append(" AND m.personId IS NULL"); - sb.append(" AND m.ruleId IS NULL AND m.rulePriority IS NULL"); - if (metricKeys.length > 0) { - sb.append(" AND met.key IN (:metricKeys) "); - params.put("metricKeys", Arrays.asList(metricKeys)); - } - sb.append(" AND s.last=true "); - sb.append(" ORDER BY s.createdAt "); - - Query jpaQuery = session.createQuery(sb.toString()); - - for (Map.Entry<String, Object> entry : params.entrySet()) { - jpaQuery.setParameter(entry.getKey(), entry.getValue()); - } - return jpaQuery.getResultList(); - } - - @CheckForNull - Date lastSnapshotCreationDate(String resourceKey) { - StringBuilder sb = new StringBuilder(); - Map<String, Object> params = Maps.newHashMap(); - - sb.append("SELECT s.buildDate"); - sb.append(" FROM ") - .append(ResourceModel.class.getSimpleName()) - .append(" r, ") - .append(Snapshot.class.getSimpleName()) - .append(" s WHERE s.resourceId=r.id AND r.key=:kee AND s.status=:status AND s.qualifier<>:lib"); - params.put("kee", resourceKey); - params.put("status", Snapshot.STATUS_PROCESSED); - params.put("lib", Qualifiers.LIBRARY); - - sb.append(" AND s.last=true "); - - Query jpaQuery = session.createQuery(sb.toString()); - - for (Map.Entry<String, Object> entry : params.entrySet()) { - jpaQuery.setParameter(entry.getKey(), entry.getValue()); - } - try { - return longToDate((Long) jpaQuery.getSingleResult()); - } catch (NoResultException e) { - return null; - } - } -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectReactorReady.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectReactorReady.java index 45b4700e795..85ea965e514 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectReactorReady.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectReactorReady.java @@ -22,7 +22,6 @@ package org.sonar.batch.scan; import org.sonar.api.batch.bootstrap.ProjectBuilder; import org.sonar.api.batch.bootstrap.ProjectReactor; import org.sonar.api.batch.bootstrap.internal.ProjectBuilderContext; -import org.sonar.batch.repository.ProjectScmRepositoryLoader; import javax.annotation.Nullable; @@ -43,27 +42,16 @@ public class ProjectReactorReady { private final ProjectBuilder[] projectBuilders; private final ProjectExclusions exclusions; private final ProjectReactorValidator validator; - private final ProjectScmRepositoryLoader projectScmRepositoryLoader; - public ProjectReactorReady(ProjectExclusions exclusions, ProjectReactor reactor, @Nullable ProjectBuilder[] projectBuilders, ProjectReactorValidator validator, - @Nullable ProjectScmRepositoryLoader projectScmRepositoryLoader) { + public ProjectReactorReady(ProjectExclusions exclusions, ProjectReactor reactor, @Nullable ProjectBuilder[] projectBuilders, ProjectReactorValidator validator) { this.exclusions = exclusions; this.reactor = reactor; this.projectBuilders = projectBuilders; this.validator = validator; - this.projectScmRepositoryLoader = projectScmRepositoryLoader; - } - - public ProjectReactorReady(ProjectExclusions exclusions, ProjectReactor reactor, @Nullable ProjectBuilder[] projectBuilders, ProjectReactorValidator validator) { - this(exclusions, reactor, projectBuilders, validator, null); - } - - public ProjectReactorReady(ProjectExclusions exclusions, ProjectReactor reactor, ProjectReactorValidator validator, ProjectScmRepositoryLoader projectScmRepositoryLoader) { - this(exclusions, reactor, new ProjectBuilder[0], validator, projectScmRepositoryLoader); } public ProjectReactorReady(ProjectExclusions exclusions, ProjectReactor reactor, ProjectReactorValidator validator) { - this(exclusions, reactor, new ProjectBuilder[0], validator, null); + this(exclusions, reactor, new ProjectBuilder[0], validator); } public void start() { @@ -80,10 +68,5 @@ public class ProjectReactorReady { // 3 Validate final reactor validator.validate(reactor); - // 4 Complete missing SCM information from project repositories - if (projectScmRepositoryLoader != null) { - projectScmRepositoryLoader.complete(); - } - } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java index ffa93f69285..aaa63f0d328 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java @@ -51,9 +51,8 @@ import org.sonar.batch.mediumtest.ScanTaskObservers; import org.sonar.batch.phases.GraphPersister; import org.sonar.batch.profiling.PhasesSumUpTimeProfiler; import org.sonar.batch.qualitygate.QualityGateProvider; -import org.sonar.batch.report.EventCache; +import org.sonar.batch.report.*; import org.sonar.batch.repository.ProjectRepositoriesProvider; -import org.sonar.batch.repository.ProjectScmRepositoryLoader; import org.sonar.batch.repository.language.DefaultLanguagesRepository; import org.sonar.batch.rule.ActiveRulesProvider; import org.sonar.batch.rule.RulesProvider; @@ -187,6 +186,12 @@ public class ProjectScanContainer extends ComponentContainer { ProjectSettings.class, + // Report + PublishReportJob.class, + ComponentsPublisher.class, + IssuesPublisher.class, + MeasuresPublisher.class, + ScanTaskObservers.class); } @@ -196,8 +201,6 @@ public class ProjectScanContainer extends ComponentContainer { SourcePersister.class, ResourceKeyMigration.class, - ProjectScmRepositoryLoader.class, - // Users DefaultUserFinder.class, diff --git a/sonar-batch/src/main/java/org/sonar/batch/scm/DefaultBlameOutput.java b/sonar-batch/src/main/java/org/sonar/batch/scm/DefaultBlameOutput.java index b95ba5d2178..4323e5cff92 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scm/DefaultBlameOutput.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scm/DefaultBlameOutput.java @@ -20,25 +20,25 @@ package org.sonar.batch.scm; import com.google.common.base.Preconditions; +import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.scm.BlameCommand.BlameOutput; import org.sonar.api.batch.scm.BlameLine; -import org.sonar.api.batch.sensor.SensorContext; -import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.Metric; import org.sonar.api.measures.PropertiesBuilder; -import org.sonar.api.utils.DateUtils; +import org.sonar.batch.index.BatchResource; +import org.sonar.batch.index.ResourceCache; +import org.sonar.batch.protocol.output.BatchReport; +import org.sonar.batch.protocol.output.BatchReport.Scm.Builder; +import org.sonar.batch.protocol.output.BatchReportWriter; import org.sonar.batch.util.ProgressReport; import javax.annotation.Nullable; import java.text.Normalizer; -import java.util.Date; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; @@ -49,14 +49,16 @@ class DefaultBlameOutput implements BlameOutput { private static final Pattern NON_ASCII_CHARS = Pattern.compile("[^\\x00-\\x7F]"); private static final Pattern ACCENT_CODES = Pattern.compile("\\p{InCombiningDiacriticalMarks}+"); - private final SensorContext context; + private final BatchReportWriter writer; + private final ResourceCache componentCache; private final Set<InputFile> allFilesToBlame = new HashSet<InputFile>(); private ProgressReport progressReport; private int count; private int total; - DefaultBlameOutput(SensorContext context, List<InputFile> filesToBlame) { - this.context = context; + DefaultBlameOutput(BatchReportWriter writer, ResourceCache componentCache, List<InputFile> filesToBlame) { + this.writer = writer; + this.componentCache = componentCache; this.allFilesToBlame.addAll(filesToBlame); count = 0; total = filesToBlame.size(); @@ -75,24 +77,45 @@ class DefaultBlameOutput implements BlameOutput { return; } - PropertiesBuilder<Integer, String> authors = propertiesBuilder(CoreMetrics.SCM_AUTHORS_BY_LINE); - PropertiesBuilder<Integer, String> dates = propertiesBuilder(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE); - PropertiesBuilder<Integer, String> revisions = propertiesBuilder(CoreMetrics.SCM_REVISIONS_BY_LINE); + BatchResource batchComponent = componentCache.get(file); + Builder scmBuilder = BatchReport.Scm.newBuilder(); + scmBuilder.setComponentRef(batchComponent.batchId()); + Map<String, Integer> changesetsIdByRevision = new HashMap<>(); - int lineNumber = 1; for (BlameLine line : lines) { - authors.add(lineNumber, normalizeString(line.author())); - Date date = line.date(); - dates.add(lineNumber, date != null ? DateUtils.formatDateTime(date) : ""); - revisions.add(lineNumber, line.revision()); - lineNumber++; + if (StringUtils.isNotBlank(line.revision())) { + Integer changesetId = changesetsIdByRevision.get(line.revision()); + if (changesetId == null) { + addChangeset(scmBuilder, line); + changesetId = scmBuilder.getChangesetCount() - 1; + changesetsIdByRevision.put(line.revision(), changesetId); + } + scmBuilder.addChangesetIndexByLine(changesetId); + } else { + addChangeset(scmBuilder, line); + } } - ScmSensor.saveMeasures(context, file, authors.buildData(), dates.buildData(), revisions.buildData()); + writer.writeComponentScm(scmBuilder.build()); allFilesToBlame.remove(file); count++; progressReport.message(count + "/" + total + " files analyzed, last one was " + file.absolutePath()); } + private void addChangeset(Builder scmBuilder, BlameLine line) { + BatchReport.Scm.Changeset.Builder changesetBuilder = BatchReport.Scm.Changeset.newBuilder(); + if (StringUtils.isNotBlank(line.revision())) { + changesetBuilder.setRevision(line.revision()); + } + if (StringUtils.isNotBlank(line.author())) { + changesetBuilder.setAuthor(normalizeString(line.author())); + } + Date date = line.date(); + if (date != null) { + changesetBuilder.setDate(date.getTime()); + } + scmBuilder.addChangeset(changesetBuilder.build()); + } + private String normalizeString(@Nullable String inputString) { if (inputString == null) { return ""; diff --git a/sonar-batch/src/main/java/org/sonar/batch/scm/ScmSensor.java b/sonar-batch/src/main/java/org/sonar/batch/scm/ScmSensor.java index 09b74bc6a6a..700098ab142 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scm/ScmSensor.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scm/ScmSensor.java @@ -30,10 +30,10 @@ import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.sensor.Sensor; import org.sonar.api.batch.sensor.SensorContext; import org.sonar.api.batch.sensor.SensorDescriptor; -import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; -import org.sonar.api.measures.CoreMetrics; +import org.sonar.batch.index.ResourceCache; import org.sonar.batch.protocol.input.FileData; import org.sonar.batch.protocol.input.ProjectRepositories; +import org.sonar.batch.report.PublishReportJob; import org.sonar.batch.scan.filesystem.InputFileMetadata; import org.sonar.batch.scan.filesystem.InputPathCache; @@ -49,14 +49,19 @@ public final class ScmSensor implements Sensor { private final FileSystem fs; private final ProjectRepositories projectReferentials; private final InputPathCache inputPathCache; + private final ResourceCache resourceCache; + private final PublishReportJob publishReportJob; public ScmSensor(ProjectDefinition projectDefinition, ScmConfiguration configuration, - ProjectRepositories projectReferentials, FileSystem fs, InputPathCache inputPathCache) { + ProjectRepositories projectReferentials, FileSystem fs, InputPathCache inputPathCache, ResourceCache resourceCache, + PublishReportJob publishReportJob) { this.projectDefinition = projectDefinition; this.configuration = configuration; this.projectReferentials = projectReferentials; this.fs = fs; this.inputPathCache = inputPathCache; + this.resourceCache = resourceCache; + this.publishReportJob = publishReportJob; } @Override @@ -66,9 +71,9 @@ public final class ScmSensor implements Sensor { } @Override - public void execute(final SensorContext context) { + public void execute(SensorContext context) { if (configuration.isDisabled()) { - LOG.info("SCM Sensor is disabled"); + LOG.info("SCM Publisher is disabled"); return; } if (configuration.provider() == null) { @@ -76,51 +81,32 @@ public final class ScmSensor implements Sensor { return; } - List<InputFile> filesToBlame = collectFilesToBlame(context); + List<InputFile> filesToBlame = collectFilesToBlame(); if (!filesToBlame.isEmpty()) { String key = configuration.provider().key(); LOG.info("SCM provider for this project is: " + key); - DefaultBlameOutput output = new DefaultBlameOutput(context, filesToBlame); + DefaultBlameOutput output = new DefaultBlameOutput(publishReportJob.getWriter(), resourceCache, filesToBlame); configuration.provider().blameCommand().blame(new DefaultBlameInput(fs, filesToBlame), output); output.finish(); } } - private List<InputFile> collectFilesToBlame(final SensorContext context) { + private List<InputFile> collectFilesToBlame() { if (configuration.forceReloadAll()) { LOG.warn("Forced reloading of SCM data for all files."); } List<InputFile> filesToBlame = new LinkedList<InputFile>(); - for (InputFile f : fs.inputFiles(fs.predicates().all())) { - if (!configuration.forceReloadAll()) { - copyPreviousMeasuresForUnmodifiedFiles(context, filesToBlame, f); - } else { - filesToBlame.add(f); - } - } - return filesToBlame; - } - - private void copyPreviousMeasuresForUnmodifiedFiles(final SensorContext context, List<InputFile> filesToBlame, InputFile f) { - FileData fileData = projectReferentials.fileData(projectDefinition.getKeyWithBranch(), f.relativePath()); - - if (f.status() == Status.SAME && fileData != null) { - if (fileData.needBlame()) { + for (InputFile f : inputPathCache.allFiles()) { + if (configuration.forceReloadAll()) { addIfNotEmpty(filesToBlame, (DefaultInputFile) f); } else { - // Copy previous measures - String scmAuthorsByLine = fileData.scmAuthorsByLine(); - String scmLastCommitDatetimesByLine = fileData.scmLastCommitDatetimesByLine(); - String scmRevisionsByLine = fileData.scmRevisionsByLine(); - if (scmAuthorsByLine != null - && scmLastCommitDatetimesByLine != null - && scmRevisionsByLine != null) { - saveMeasures(context, f, scmAuthorsByLine, scmLastCommitDatetimesByLine, scmRevisionsByLine); + FileData fileData = projectReferentials.fileData(projectDefinition.getKeyWithBranch(), f.relativePath()); + if (f.status() != Status.SAME || fileData == null || fileData.needBlame()) { + addIfNotEmpty(filesToBlame, (DefaultInputFile) f); } } - } else { - addIfNotEmpty(filesToBlame, (DefaultInputFile) f); } + return filesToBlame; } private void addIfNotEmpty(List<InputFile> filesToBlame, DefaultInputFile f) { @@ -130,24 +116,4 @@ public final class ScmSensor implements Sensor { } } - static void saveMeasures(SensorContext context, InputFile f, String scmAuthorsByLine, String scmLastCommitDatetimesByLine, String scmRevisionsByLine) { - ((DefaultMeasure<String>) context.<String>newMeasure() - .onFile(f) - .forMetric(CoreMetrics.SCM_AUTHORS_BY_LINE) - .withValue(scmAuthorsByLine)) - .setFromCore() - .save(); - ((DefaultMeasure<String>) context.<String>newMeasure() - .onFile(f) - .forMetric(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE) - .withValue(scmLastCommitDatetimesByLine)) - .setFromCore() - .save(); - ((DefaultMeasure<String>) context.<String>newMeasure() - .onFile(f) - .forMetric(CoreMetrics.SCM_REVISIONS_BY_LINE) - .withValue(scmRevisionsByLine)) - .setFromCore() - .save(); - } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/SourceDataFactoryTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/SourceDataFactoryTest.java index f55cd36f09f..a37bef0da56 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/index/SourceDataFactoryTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/index/SourceDataFactoryTest.java @@ -38,6 +38,10 @@ import org.sonar.api.source.Symbol; import org.sonar.batch.duplication.DuplicationCache; import org.sonar.batch.highlighting.SyntaxHighlightingData; import org.sonar.batch.highlighting.SyntaxHighlightingDataBuilder; +import org.sonar.batch.protocol.output.BatchReport.Scm; +import org.sonar.batch.protocol.output.BatchReport.Scm.Changeset; +import org.sonar.batch.protocol.output.BatchReportWriter; +import org.sonar.batch.report.PublishReportJob; import org.sonar.batch.scan.filesystem.InputFileMetadata; import org.sonar.batch.scan.measure.MeasureCache; import org.sonar.batch.source.CodeColorizers; @@ -59,17 +63,25 @@ public class SourceDataFactoryTest { @Rule public TemporaryFolder temp = new TemporaryFolder(); - MeasureCache measureCache = mock(MeasureCache.class); - ComponentDataCache componentDataCache = mock(ComponentDataCache.class); - DuplicationCache duplicationCache = mock(DuplicationCache.class); - CodeColorizers colorizers = mock(CodeColorizers.class); - DefaultInputFile inputFile; - InputFileMetadata metadata; - SourceDataFactory sut = new SourceDataFactory(measureCache, componentDataCache, duplicationCache, colorizers); - FileSourceDb.Data.Builder output; + private MeasureCache measureCache = mock(MeasureCache.class); + private ComponentDataCache componentDataCache = mock(ComponentDataCache.class); + private DuplicationCache duplicationCache = mock(DuplicationCache.class); + private CodeColorizers colorizers = mock(CodeColorizers.class); + private DefaultInputFile inputFile; + private InputFileMetadata metadata; + private SourceDataFactory sut; + private FileSourceDb.Data.Builder output; + private File reportDir; @Before public void setUp() throws Exception { + PublishReportJob publishReportJob = mock(PublishReportJob.class); + reportDir = temp.newFolder(); + when(publishReportJob.getReportDir()).thenReturn(reportDir); + ResourceCache resourceCache = new ResourceCache(); + resourceCache.add(org.sonar.api.resources.File.create("src/Foo.java").setEffectiveKey("module_key:src/Foo.java"), null); + when(measureCache.byMetric(anyString(), anyString())).thenReturn(Collections.<Measure>emptyList()); + sut = new SourceDataFactory(measureCache, componentDataCache, duplicationCache, colorizers, publishReportJob, resourceCache); // generate a file with 3 lines File baseDir = temp.newFolder(); DefaultFileSystem fs = new DefaultFileSystem(baseDir.toPath()); @@ -137,10 +149,39 @@ public class SourceDataFactoryTest { } @Test + public void applyScm() throws Exception { + BatchReportWriter writer = new BatchReportWriter(reportDir); + writer.writeComponentScm(Scm.newBuilder().setComponentRef(1) + .addChangeset(Changeset.newBuilder() + .setRevision("ABC") + .setAuthor("him") + .setDate(123456L) + .build()) + .addChangeset(Changeset.newBuilder() + .build()) + .addChangesetIndexByLine(0) + .addChangesetIndexByLine(1) + .addChangesetIndexByLine(0) + // This should never happens but here there is 4 data but inputfile has only 3 lines + .addChangesetIndexByLine(1) + .build()); + + sut.applyScm(inputFile, output); + + FileSourceDb.Data data = output.build(); + assertThat(data.getLines(0).getScmRevision()).isEqualTo("ABC"); + assertThat(data.getLines(0).getScmAuthor()).isEqualTo("him"); + + assertThat(data.getLines(1).hasScmRevision()).isFalse(); + assertThat(data.getLines(1).hasScmAuthor()).isFalse(); + + assertThat(data.getLines(2).getScmRevision()).isEqualTo("ABC"); + assertThat(data.getLines(2).getScmAuthor()).isEqualTo("him"); + + } + + @Test public void applyLineMeasures() throws Exception { - setupLineMeasure(CoreMetrics.SCM_AUTHORS_BY_LINE, "1=him;2=her"); - setupLineMeasure(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE, "1=2014-10-11T16:44:02+0100;2=2014-10-12T16:44:02+0100;3=2014-10-13T16:44:02+0100"); - setupLineMeasure(CoreMetrics.SCM_REVISIONS_BY_LINE, "1=ABC;2=234;3=345"); setupLineMeasure(CoreMetrics.COVERAGE_LINE_HITS_DATA, "1=10;3=4"); setupLineMeasure(CoreMetrics.CONDITIONS_BY_LINE, "1=10;3=4"); setupLineMeasure(CoreMetrics.CONDITIONS_BY_LINE, "1=10;3=4"); @@ -157,15 +198,11 @@ public class SourceDataFactoryTest { FileSourceDb.Data data = output.build(); assertThat(data.getLines(0).getUtLineHits()).isEqualTo(10); assertThat(data.getLines(0).getItLineHits()).isEqualTo(11); - assertThat(data.getLines(0).getScmRevision()).isEqualTo("ABC"); - assertThat(data.getLines(0).getScmAuthor()).isEqualTo("him"); assertThat(data.getLines(1).hasUtLineHits()).isFalse(); assertThat(data.getLines(1).getItLineHits()).isEqualTo(4); - assertThat(data.getLines(1).getScmAuthor()).isEqualTo("her"); assertThat(data.getLines(2).getUtLineHits()).isEqualTo(4); - assertThat(data.getLines(2).hasScmAuthor()).isFalse(); } private void setupLineMeasure(Metric metric, String dataPerLine) { diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/preview/IncrementalModeMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/preview/IncrementalModeMediumTest.java index ffc8451d9cb..6bffe47ace2 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/preview/IncrementalModeMediumTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/preview/IncrementalModeMediumTest.java @@ -67,7 +67,7 @@ public class IncrementalModeMediumTest { .activateRule(new ActiveRule("xoo", "OneIssuePerLine", null, "One issue per line", "MAJOR", null, "xoo")) .activateRule(new ActiveRule("manual", "MyManualIssue", null, "My manual issue", "MAJOR", null, null)) .setPreviousAnalysisDate(new Date()) - .addFileData("sample", "src/sample.xoo", new FileData(DigestUtils.md5Hex(SAMPLE_CONTENT), false, null, null, null)) + .addFileData("sample", "src/sample.xoo", new FileData(DigestUtils.md5Hex(SAMPLE_CONTENT), false)) .mockLineHashes("sample:src/sample.xoo", new String[] {DigestUtils.md5Hex("Samplecontent"), DigestUtils.md5Hex("oldcode"), DigestUtils.md5Hex("4"), DigestUtils.md5Hex("lines")}) // Remote open issue => will be tracked and not new diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/scm/ScmMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/scm/ScmMediumTest.java index 61cbf327eb6..7c80e0db6dd 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/scm/ScmMediumTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/scm/ScmMediumTest.java @@ -28,13 +28,14 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; -import org.sonar.api.batch.fs.internal.DefaultInputFile; -import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; -import org.sonar.api.measures.CoreMetrics; import org.sonar.batch.mediumtest.BatchMediumTester; import org.sonar.batch.mediumtest.BatchMediumTester.TaskBuilder; import org.sonar.batch.mediumtest.TaskResult; import org.sonar.batch.protocol.input.FileData; +import org.sonar.batch.protocol.output.BatchReport.Component; +import org.sonar.batch.protocol.output.BatchReport.Scm; +import org.sonar.batch.protocol.output.BatchReport.Scm.Changeset; +import org.sonar.batch.protocol.output.BatchReportReader; import org.sonar.xoo.XooPlugin; import java.io.File; @@ -55,7 +56,7 @@ public class ScmMediumTest { public BatchMediumTester tester = BatchMediumTester.builder() .registerPlugin("xoo", new XooPlugin()) .addDefaultQProfile("xoo", "Sonar Way") - .addFileData("com.foo.project", "src/sample2.xoo", new FileData(DigestUtils.md5Hex(SAMPLE_XOO_CONTENT), false, "1=;2=", "1=;2=", "1=;2=")) + .addFileData("com.foo.project", "src/sample2.xoo", new FileData(DigestUtils.md5Hex(SAMPLE_XOO_CONTENT), false)) .build(); @Before @@ -86,17 +87,35 @@ public class ScmMediumTest { .build()) .start(); - assertThat(result.measures()).hasSize(5); + Scm fileScm = getScm(baseDir, 0); - assertThat(result.measures()).contains(new DefaultMeasure<Integer>() - .forMetric(CoreMetrics.LINES) - .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo")) - .withValue(5)); + assertThat(fileScm.getChangesetIndexByLineList()).hasSize(5); - assertThat(result.measures()).contains(new DefaultMeasure<String>() - .forMetric(CoreMetrics.SCM_AUTHORS_BY_LINE) - .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo")) - .withValue("1=;2=julien;3=julien;4=julien;5=simon")); + Changeset changesetLine1 = fileScm.getChangeset(fileScm.getChangesetIndexByLine(0)); + assertThat(changesetLine1.hasAuthor()).isFalse(); + + Changeset changesetLine2 = fileScm.getChangeset(fileScm.getChangesetIndexByLine(1)); + assertThat(changesetLine2.getAuthor()).isEqualTo("julien"); + + Changeset changesetLine3 = fileScm.getChangeset(fileScm.getChangesetIndexByLine(2)); + assertThat(changesetLine3.getAuthor()).isEqualTo("julien"); + + Changeset changesetLine4 = fileScm.getChangeset(fileScm.getChangesetIndexByLine(3)); + assertThat(changesetLine4.getAuthor()).isEqualTo("julien"); + + Changeset changesetLine5 = fileScm.getChangeset(fileScm.getChangesetIndexByLine(4)); + assertThat(changesetLine5.getAuthor()).isEqualTo("simon"); + } + + private Scm getScm(File baseDir, int fileId) { + File reportDir = new File(baseDir, ".sonar/batch-report"); + BatchReportReader reader = new BatchReportReader(reportDir); + + Component project = reader.readComponent(reader.readMetadata().getRootComponentRef()); + Component dir = reader.readComponent(project.getChildRef(0)); + Component file = reader.readComponent(dir.getChildRef(fileId)); + Scm fileScm = reader.readComponentScm(file.getRef()); + return fileScm; } @Test @@ -120,17 +139,14 @@ public class ScmMediumTest { .build()) .start(); - // lines + qprofile - assertThat(result.measures()).hasSize(2); + Scm fileScm = getScm(baseDir, 0); + + assertThat(fileScm).isNull(); - assertThat(result.measures()).contains(new DefaultMeasure<Integer>() - .forMetric(CoreMetrics.LINES) - .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo")) - .withValue(1)); } @Test - public void dontFailIfMissingFile() throws IOException { + public void sample2_dont_need_blame() throws IOException { File baseDir = prepareProject(); File xooFile = new File(baseDir, "src/sample2.xoo"); @@ -148,14 +164,26 @@ public class ScmMediumTest { .put("sonar.scm.provider", "xoo") .build()) .start(); + + Scm file1Scm = getScm(baseDir, 0); + assertThat(file1Scm).isNotNull(); + + Scm file2Scm = getScm(baseDir, 1); + assertThat(file2Scm).isNull(); } @Test - public void copyPreviousMeasuresOrForceReload() throws IOException { + public void forceReload() throws IOException { File baseDir = prepareProject(); File xooFileNoScm = new File(baseDir, "src/sample2.xoo"); FileUtils.write(xooFileNoScm, SAMPLE_XOO_CONTENT); + File xooScmFile = new File(baseDir, "src/sample2.xoo.scm"); + FileUtils.write(xooScmFile, + // revision,author,dateTime + "1,foo,2013-01-04\n" + + "1,bar,2013-01-04\n" + ); TaskBuilder taskBuilder = tester.newTask() .properties(ImmutableMap.<String, String>builder() @@ -167,38 +195,17 @@ public class ScmMediumTest { .put("sonar.projectDescription", "Description of Foo Project") .put("sonar.sources", "src") .put("sonar.scm.provider", "xoo") + // Force reload + .put("sonar.scm.forceReloadAll", "true") .build()); - TaskResult result = taskBuilder.start(); - - assertThat(result.measures()).hasSize(1 + 2 * 4); + taskBuilder.start(); - assertThat(result.measures()).contains(new DefaultMeasure<Integer>() - .forMetric(CoreMetrics.LINES) - .onFile(new DefaultInputFile("com.foo.project", "src/sample2.xoo")) - .withValue(2)); + Scm file1Scm = getScm(baseDir, 0); + assertThat(file1Scm).isNotNull(); - assertThat(result.measures()).contains(new DefaultMeasure<String>() - .forMetric(CoreMetrics.SCM_AUTHORS_BY_LINE) - .onFile(new DefaultInputFile("com.foo.project", "src/sample2.xoo")) - .withValue("1=;2=")); - - // Force reload - File xooScmFile = new File(baseDir, "src/sample2.xoo.scm"); - FileUtils.write(xooScmFile, - // revision,author,dateTime - "1,foo,2013-01-04\n" + - "1,bar,2013-01-04\n" - ); - - result = taskBuilder - .property("sonar.scm.forceReloadAll", "true") - .start(); - - assertThat(result.measures()).contains(new DefaultMeasure<String>() - .forMetric(CoreMetrics.SCM_AUTHORS_BY_LINE) - .onFile(new DefaultInputFile("com.foo.project", "src/sample2.xoo")) - .withValue("1=foo;2=bar")); + Scm file2Scm = getScm(baseDir, 1); + assertThat(file2Scm).isNotNull(); } @Test @@ -206,7 +213,7 @@ public class ScmMediumTest { File baseDir = prepareProject(); - TaskResult result = tester.newTask() + tester.newTask() .properties(ImmutableMap.<String, String>builder() .put("sonar.task", "scan") .put("sonar.projectBaseDir", baseDir.getAbsolutePath()) @@ -219,17 +226,8 @@ public class ScmMediumTest { .build()) .start(); - assertThat(result.measures()).hasSize(5); - - assertThat(result.measures()).contains(new DefaultMeasure<Integer>() - .forMetric(CoreMetrics.LINES) - .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo")) - .withValue(5)); - - assertThat(result.measures()).contains(new DefaultMeasure<String>() - .forMetric(CoreMetrics.SCM_AUTHORS_BY_LINE) - .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo")) - .withValue("1=;2=julien;3=julien;4=julien;5=simon")); + Scm file1Scm = getScm(baseDir, 0); + assertThat(file1Scm).isNotNull(); } @Test @@ -238,7 +236,7 @@ public class ScmMediumTest { File baseDir = prepareProject(); new File(baseDir, ".xoo").createNewFile(); - TaskResult result = tester.newTask() + tester.newTask() .properties(ImmutableMap.<String, String>builder() .put("sonar.task", "scan") .put("sonar.projectBaseDir", baseDir.getAbsolutePath()) @@ -250,17 +248,8 @@ public class ScmMediumTest { .build()) .start(); - assertThat(result.measures()).hasSize(5); - - assertThat(result.measures()).contains(new DefaultMeasure<Integer>() - .forMetric(CoreMetrics.LINES) - .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo")) - .withValue(5)); - - assertThat(result.measures()).contains(new DefaultMeasure<String>() - .forMetric(CoreMetrics.SCM_AUTHORS_BY_LINE) - .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo")) - .withValue("1=;2=julien;3=julien;4=julien;5=simon")); + Scm file1Scm = getScm(baseDir, 0); + assertThat(file1Scm).isNotNull(); } private File prepareProject() throws IOException { @@ -274,10 +263,10 @@ public class ScmMediumTest { FileUtils.write(xooScmFile1, // revision,author,dateTime "1,,2013-01-04\n" + - "1,julien,2013-01-04\n" + - "2,julien,2013-02-03\n" + - "2,julien,2013-02-03\n" + - "3,simon,2013-03-04\n" + "2,julien,2013-01-04\n" + + "3,julien,2013-02-03\n" + + "3,julien,2013-02-03\n" + + "4,simon,2013-03-04\n" ); return baseDir; diff --git a/sonar-batch/src/test/java/org/sonar/batch/qualitygate/QualityGateVerifierTest.java b/sonar-batch/src/test/java/org/sonar/batch/qualitygate/QualityGateVerifierTest.java index 26447e6e792..ca89fe8ccae 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/qualitygate/QualityGateVerifierTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/qualitygate/QualityGateVerifierTest.java @@ -344,12 +344,12 @@ public class QualityGateVerifierTest { @Test(expected = NotImplementedException.class) public void shouldNotAllowPeriodVariationAlertOnStringMetric() { - Measure measure = new Measure(CoreMetrics.SCM_AUTHORS_BY_LINE, 100d); + Measure measure = new Measure(CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION, 100d); measure.setVariation1(50d); - when(context.getMeasure(CoreMetrics.SCM_AUTHORS_BY_LINE)).thenReturn(measure); + when(context.getMeasure(CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION)).thenReturn(measure); ArrayList<ResolvedCondition> conditions = Lists.newArrayList( - mockCondition(CoreMetrics.SCM_AUTHORS_BY_LINE, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "30", 1) + mockCondition(CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "30", 1) ); when(qualityGate.conditions()).thenReturn(conditions); diff --git a/sonar-batch/src/test/java/org/sonar/batch/report/PublishReportJobTest.java b/sonar-batch/src/test/java/org/sonar/batch/report/PublishReportJobTest.java index 2da52bd2f3d..a636a5386df 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/report/PublishReportJobTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/report/PublishReportJobTest.java @@ -23,16 +23,19 @@ import org.junit.Before; import org.junit.Test; import org.slf4j.Logger; import org.sonar.api.CoreProperties; +import org.sonar.api.batch.bootstrap.ProjectDefinition; +import org.sonar.api.batch.bootstrap.ProjectReactor; import org.sonar.api.config.Settings; import org.sonar.api.platform.Server; -import org.sonar.api.resources.Project; import org.sonar.api.utils.TempFolder; import org.sonar.batch.bootstrap.DefaultAnalysisMode; import org.sonar.batch.bootstrap.ServerClient; import org.sonar.batch.index.ResourceCache; import org.sonar.jpa.test.AbstractDbUnitTestCase; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; public class PublishReportJobTest extends AbstractDbUnitTestCase { @@ -40,17 +43,20 @@ public class PublishReportJobTest extends AbstractDbUnitTestCase { ResourceCache resourceCache = mock(ResourceCache.class); + private ProjectReactor reactor; + @Before public void setUp() { mode = mock(DefaultAnalysisMode.class); + reactor = mock(ProjectReactor.class); + when(reactor.getRoot()).thenReturn(ProjectDefinition.create().setKey("struts")); } @Test public void should_log_successful_analysis() throws Exception { Settings settings = new Settings(); settings.setProperty(CoreProperties.SERVER_BASE_URL, "http://myserver/"); - Project project = new Project("struts"); - PublishReportJob job = new PublishReportJob(settings, mock(ServerClient.class), mock(Server.class), project, mode, mock(TempFolder.class)); + PublishReportJob job = new PublishReportJob(settings, mock(ServerClient.class), mock(Server.class), reactor, mode, mock(TempFolder.class), new ReportPublisher[0]); Logger logger = mock(Logger.class); job.logSuccess(logger); @@ -63,8 +69,7 @@ public class PublishReportJobTest extends AbstractDbUnitTestCase { public void should_log_successful_preview_analysis() throws Exception { Settings settings = new Settings(); when(mode.isPreview()).thenReturn(true); - Project project = new Project("struts"); - PublishReportJob job = new PublishReportJob(settings, mock(ServerClient.class), mock(Server.class), project, mode, mock(TempFolder.class)); + PublishReportJob job = new PublishReportJob(settings, mock(ServerClient.class), mock(Server.class), reactor, mode, mock(TempFolder.class), new ReportPublisher[0]); Logger logger = mock(Logger.class); job.logSuccess(logger); diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/ProjectReactorReadyTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/ProjectReactorReadyTest.java index 8ab69d7fec7..63f2377e67e 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/scan/ProjectReactorReadyTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/scan/ProjectReactorReadyTest.java @@ -22,7 +22,6 @@ package org.sonar.batch.scan; import org.junit.Test; import org.sonar.api.batch.bootstrap.ProjectBuilder; import org.sonar.api.batch.bootstrap.ProjectReactor; -import org.sonar.batch.repository.ProjectScmRepositoryLoader; import static org.mockito.Mockito.mock; @@ -31,14 +30,13 @@ public class ProjectReactorReadyTest { public void should_do_nothing() { // it's only a barrier ProjectReactorReady barrier = new ProjectReactorReady(mock(ProjectExclusions.class), mock(ProjectReactor.class), - new ProjectBuilder[] {mock(ProjectBuilder.class)}, mock(ProjectReactorValidator.class), mock(ProjectScmRepositoryLoader.class)); + new ProjectBuilder[] {mock(ProjectBuilder.class)}, mock(ProjectReactorValidator.class)); barrier.start(); } @Test public void project_builders_should_be_optional() { - ProjectReactorReady barrier = new ProjectReactorReady(mock(ProjectExclusions.class), mock(ProjectReactor.class), mock(ProjectReactorValidator.class), - mock(ProjectScmRepositoryLoader.class)); + ProjectReactorReady barrier = new ProjectReactorReady(mock(ProjectExclusions.class), mock(ProjectReactor.class), mock(ProjectReactorValidator.class)); barrier.start(); } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/StatusDetectionTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/StatusDetectionTest.java index 261ff3b8a2c..cc5feed7883 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/StatusDetectionTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/StatusDetectionTest.java @@ -30,8 +30,8 @@ public class StatusDetectionTest { @Test public void detect_status() throws Exception { ProjectRepositories ref = new ProjectRepositories(); - ref.addFileData("foo", "src/Foo.java", new FileData("ABCDE", true, null, null, null)); - ref.addFileData("foo", "src/Bar.java", new FileData("FGHIJ", true, null, null, null)); + ref.addFileData("foo", "src/Foo.java", new FileData("ABCDE", true)); + ref.addFileData("foo", "src/Bar.java", new FileData("FGHIJ", true)); StatusDetection statusDetection = new StatusDetection(ref); assertThat(statusDetection.status("foo", "src/Foo.java", "ABCDE")).isEqualTo(InputFile.Status.SAME); diff --git a/sonar-batch/src/test/java/org/sonar/batch/scm/DefaultBlameOutputTest.java b/sonar-batch/src/test/java/org/sonar/batch/scm/DefaultBlameOutputTest.java index 3b5632ccb7e..a92b20382dd 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/scm/DefaultBlameOutputTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/scm/DefaultBlameOutputTest.java @@ -37,7 +37,7 @@ public class DefaultBlameOutputTest { public void shouldNotFailIfNotSameNumberOfLines() { InputFile file = new DefaultInputFile("foo", "src/main/java/Foo.java").setLines(10); - new DefaultBlameOutput(null, Arrays.asList(file)).blameResult(file, Arrays.asList(new BlameLine().revision("1").author("guy"))); + new DefaultBlameOutput(null, null, Arrays.asList(file)).blameResult(file, Arrays.asList(new BlameLine().revision("1").author("guy"))); } @Test @@ -47,7 +47,7 @@ public class DefaultBlameOutputTest { thrown.expect(IllegalArgumentException.class); thrown.expectMessage("It was not expected to blame file src/main/java/Foo.java"); - new DefaultBlameOutput(null, Arrays.<InputFile>asList(new DefaultInputFile("foo", "src/main/java/Foo2.java"))) + new DefaultBlameOutput(null, null, Arrays.<InputFile>asList(new DefaultInputFile("foo", "src/main/java/Foo2.java"))) .blameResult(file, Arrays.asList(new BlameLine().revision("1").author("guy"))); } diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/resources/CoreMetricsTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/resources/CoreMetricsTest.java index c5db06856fe..0dcbda870b1 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/resources/CoreMetricsTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/resources/CoreMetricsTest.java @@ -32,7 +32,7 @@ public class CoreMetricsTest { @Test public void read_metrics_from_class_reflection() { List<Metric> metrics = CoreMetrics.getMetrics(); - assertThat(metrics).hasSize(142); + assertThat(metrics.size()).isGreaterThan(100); assertThat(metrics).contains(CoreMetrics.NCLOC, CoreMetrics.DIRECTORIES); } |