]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6317 Feed SCM in compute report - batch side 164/head
authorJulien HENRY <julien.henry@sonarsource.com>
Thu, 26 Mar 2015 13:09:31 +0000 (14:09 +0100)
committerTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Thu, 26 Mar 2015 16:32:20 +0000 (17:32 +0100)
43 files changed:
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/AbstractNewCoverageFileAnalyzer.java
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewCoverageFileAnalyzer.java
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewItCoverageFileAnalyzer.java
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewOverallCoverageFileAnalyzer.java
plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/NewCoverageFileAnalyzerTest.java
server/sonar-server/src/main/java/org/sonar/server/batch/ProjectRepositoryLoader.java
server/sonar-server/src/main/java/org/sonar/server/computation/issue/SourceLinesCache.java
server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
server/sonar-server/src/main/java/org/sonar/server/source/SourceService.java
server/sonar-server/src/main/java/org/sonar/server/source/ws/ScmAction.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/source/ws/ScmWriter.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/source/ws/SourcesWs.java
server/sonar-server/src/test/java/org/sonar/server/source/SourceServiceTest.java
server/sonar-server/src/test/java/org/sonar/server/source/ws/HashActionTest.java
server/sonar-server/src/test/java/org/sonar/server/source/ws/IndexActionTest.java
server/sonar-server/src/test/java/org/sonar/server/source/ws/LinesActionTest.java
server/sonar-server/src/test/java/org/sonar/server/source/ws/RawActionTest.java
server/sonar-server/src/test/java/org/sonar/server/source/ws/ScmActionTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/source/ws/ScmWriterTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/source/ws/ShowActionTest.java
server/sonar-server/src/test/java/org/sonar/server/source/ws/SourcesWsTest.java
sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/input/FileData.java
sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/input/ProjectRepositoriesTest.java
sonar-batch-protocol/src/test/resources/org/sonar/batch/protocol/input/ProjectRepositoriesTest/testToJson.json
sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java
sonar-batch/src/main/java/org/sonar/batch/index/ResourceCache.java
sonar-batch/src/main/java/org/sonar/batch/index/SourceDataFactory.java
sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java
sonar-batch/src/main/java/org/sonar/batch/report/PublishReportJob.java
sonar-batch/src/main/java/org/sonar/batch/repository/ProjectScmRepositoryLoader.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/scan/ProjectReactorReady.java
sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
sonar-batch/src/main/java/org/sonar/batch/scm/DefaultBlameOutput.java
sonar-batch/src/main/java/org/sonar/batch/scm/ScmSensor.java
sonar-batch/src/test/java/org/sonar/batch/index/SourceDataFactoryTest.java
sonar-batch/src/test/java/org/sonar/batch/mediumtest/preview/IncrementalModeMediumTest.java
sonar-batch/src/test/java/org/sonar/batch/mediumtest/scm/ScmMediumTest.java
sonar-batch/src/test/java/org/sonar/batch/qualitygate/QualityGateVerifierTest.java
sonar-batch/src/test/java/org/sonar/batch/report/PublishReportJobTest.java
sonar-batch/src/test/java/org/sonar/batch/scan/ProjectReactorReadyTest.java
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/StatusDetectionTest.java
sonar-batch/src/test/java/org/sonar/batch/scm/DefaultBlameOutputTest.java
sonar-plugin-api/src/test/java/org/sonar/api/resources/CoreMetricsTest.java

index 1ade50dfc61130aeb6f4be7340f8f52b268a0335..1ac4c1a4f3a264c82a9cb535dffb641f82d18028 100644 (file)
  */
 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);
         }
index 352070ccc686b9beee689d6f61b2432a19fd7554..38aac00f0eaf78180752dff44f48bee387a521df 100644 (file)
  */
 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
index 2dbcf8416a440decd43669169e07f1a01c1cb793..48222f59ce2ab6b87de708df79f4b1ac01c43273 100644 (file)
  */
 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
index b57db6dbe0ead58e72b23e0392c6d0d395ae74f1..75a1a83686c7d7611f4156efd64a312b6a75e0f6 100644 (file)
  */
 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
index 8ef3f98c1bb7171bbd748f92afe77a6a93d5ee17..af6d25828a6a1e091a845f9c1232885ce8202496 100644 (file)
  */
 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);
   }
index 0ebebdac72af8f79220c6d3c66a884053c3a28d3..baac3ce42b21bca1b7416aa57bbc1efdb0a609c8 100644 (file)
@@ -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);
     }
   }
index daec5fb60e40c3f840d7441dbab82543e0ecf497..b49e8abf5f4cf07beadc2d9b358fd37d19d58694 100644 (file)
@@ -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();
index 195e297eb8fc2981f936b6ae0e24af75236959bf..b313796534305c3c9bdcccd780add004475e5800 100644 (file)
@@ -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);
index ed80adb8f940745eb8f6dbc67bb25f4c1da80c33..581df02b8374e356a24d644d0f300a1bec4e3dc6 100644 (file)
@@ -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 (file)
index f214b68..0000000
+++ /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 (file)
index b95300f..0000000
+++ /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);
-  }
-}
index f7dc54420fbcadcfc6fddff4cec49eea32ff1445..f87834b8714b81551171be8ff8aeb14a8495690e 100644 (file)
@@ -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();
index 468f6cdd89b7abebe0ababac63de99728887d48c..100348abe6c59d8fbd9029ae033caf0ade57b5b6 100644 (file)
@@ -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 {
@@ -92,45 +89,6 @@ public class SourceServiceTest {
     verify(sourceDecorator).getDecoratedSourceAsHtml("source2", "highlight2", "symbols2");
   }
 
-  @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);
index 65616c6f3c7dec18d5ed1835286e5cab5193573d..5d74342ae998fcf9cb4f20dc839244b956ed38e2 100644 (file)
@@ -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)
index 079666645dd6bd018e101b00b633c793995ee59a..efcb52582293d0087a49225032beee44671b5b96 100644 (file)
@@ -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();
     }
   }
index bcd67c877c109c6e2665b8fa173a0fb886f074f3..91e73188d66fbc81cc1aa996efeb98947c05e8ba 100644 (file)
@@ -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)
index ed2f15ef01e9a3a897e392c67c2057bf9dfa335b..28de2fb6f675bd471eea4433325ece9f7b5fecb3 100644 (file)
@@ -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 (file)
index 97ccb21..0000000
+++ /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 (file)
index cf05251..0000000
+++ /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);
-  }
-}
index c3471efa0bb89dfec79d54476513c6860857df0b..4763f2f91f6fd50155d77d147fc0b81bc5adfb45 100644 (file)
@@ -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)));
index f56d738f99e178ce9a47204ca99f802974d64a0f..491d42912e68ef6e01c8f8fcbc331c84506169b0 100644 (file)
@@ -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);
index d68bcbd3c61abbaf207c1321e078461436f1a781..28b8083c0e264fba023959aeb563c84cd108569c 100644 (file)
@@ -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;
-  }
-
 }
index b86b2938f15b5cd2cdf787359aeaad451c278f18..91a1b171df6031f465e847cd247bac7fcc282536 100644 (file)
@@ -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());
   }
index 7b5e29c3695e8cceb0c3657844aa9463ab6ad379..d728bdc441479d8d649a47577e04e14834b7f42f 100644 (file)
       "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"
       }
     }
   },
index ff223b4b9f45ecf78add9e6fdebe0e6bab14ce56..33f6246ea8cd1532192a3f6cfac73ec06e813d44 100644 (file)
@@ -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,
index 4a97a6c8ab82b64981171ce8e8c9a0eff5c56167..3b1ec2fe1872dbb461a09895135c36ed9e5bba5f 100644 (file)
@@ -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");
index 2aa0b854e01af03f345e72712b9b168e95bc4b97..d2197170309156af6cf45bac74e49f5848ea11bb 100644 (file)
@@ -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);
           }
         }
       }
index ed0142bcace5f7516467dc11c4db2514fff73eb0..6200c172993f8dcdd19ca0ae59149fcf32efeedf 100644 (file)
@@ -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;
   }
index 3a70259bede30e1c7fc6d417c6535eaee5e369e2..9fe5d4bbd8bab29e31818a0d8165b441f88cebd2 100644 (file)
@@ -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 (file)
index a5ee07d..0000000
+++ /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;
-    }
-  }
-}
index 45b4700e795e797c005a96052afb43293bc5fc1d..85ea965e514d61a4a2f97f6637adccf0abe012d2 100644 (file)
@@ -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();
-    }
-
   }
 }
index ffa93f692855595f730616371d6005aec52c301d..aaa63f0d3286e1782adb072fb33798d0b35871da 100644 (file)
@@ -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,
 
index b95ba5d2178d76497fe1fdc08721ff908a343458..4323e5cff92c59792c29e4b498418c7e941e1ade 100644 (file)
 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 "";
index 09b74bc6a6a0aed999d8878a75dd77c14383390f..700098ab142e9122b9bae405dd9cf36ad5040098 100644 (file)
@@ -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();
-  }
 }
index f55cd36f09fb96beeb235beefd1673012784cbf8..a37bef0da563e3098ae904b17fa478b6a8d167e1 100644 (file)
@@ -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());
@@ -136,11 +148,40 @@ public class SourceDataFactoryTest {
     assertThat(data.getLinesCount()).isEqualTo(3);
   }
 
+  @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) {
index ffc8451d9cb51ea14ff240fc72f8b99ea028b4d4..6bffe47ace29cc90c9127a94da75a9eba5999137 100644 (file)
@@ -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
index 61cbf327eb6315ec779ae108c2e2558c5643dd2c..7c80e0db6ddaa22879594e4a2650d7b1ffdb6d33 100644 (file)
@@ -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;
index 26447e6e792098d57d07383fdea72cc8e3377f8d..ca89fe8ccaebe52ceb897b10bf453d98a9e54f85 100644 (file)
@@ -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);
 
index 2da52bd2f3db05b4ec8b496f9c24840ddf53684b..a636a5386dfded6e34120445800707c8b9e14ca0 100644 (file)
@@ -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);
index 8ab69d7fec78bbb618dd529eadf3833a77aba101..63f2377e67e1ae1626570d2033bc4200a0a1d17a 100644 (file)
@@ -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();
   }
 }
index 261ff3b8a2c9b1912665d33b9d919ae407ecfc1e..cc5feed7883e2a31e46a99fba7d28d0c6dd76cb0 100644 (file)
@@ -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);
index 3b5632ccb7e8064623f14429ccdcc0bd2809dc7d..a92b20382dd50370c5f426080639489f75bb2fb2 100644 (file)
@@ -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")));
   }
 
index c5db06856fe657c62c6a27e4ab41604e3a9fec66..0dcbda870b1843230926898bbcf71e7eb5b161c0 100644 (file)
@@ -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);
   }