summaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorSimon Brandhof <simon.brandhof@sonarsource.com>2015-09-01 23:14:19 +0200
committerSimon Brandhof <simon.brandhof@sonarsource.com>2015-09-04 15:14:35 +0200
commit2f92fe93b2d7bb37ca31357fbcccbffeda02d039 (patch)
tree31263f9abb13737c2ff6cd863ba9937e953a9897 /server
parentd156cfffc2efd849f85bbbfc3d8f0870697ec7b1 (diff)
downloadsonarqube-2f92fe93b2d7bb37ca31357fbcccbffeda02d039.tar.gz
sonarqube-2f92fe93b2d7bb37ca31357fbcccbffeda02d039.zip
SONAR-6824 add metric last_commit_date
Diffstat (limited to 'server')
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/container/ReportComputeEngineContainerPopulator.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/metric/Metric.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/source/LastCommitVisitor.java138
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistNumberOfDaysSinceLastCommitStep.java137
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/ReportComputationSteps.java1
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/source/ws/ShowAction.java2
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/source/LastCommitVisitorTest.java220
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistNumberOfDaysSinceLastCommitStepTest.java132
8 files changed, 362 insertions, 272 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/container/ReportComputeEngineContainerPopulator.java b/server/sonar-server/src/main/java/org/sonar/server/computation/container/ReportComputeEngineContainerPopulator.java
index 7c1e502aff4..0756e92821c 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/container/ReportComputeEngineContainerPopulator.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/container/ReportComputeEngineContainerPopulator.java
@@ -77,6 +77,7 @@ import org.sonar.server.computation.qualitygate.EvaluationResultTextConverterImp
import org.sonar.server.computation.qualitygate.QualityGateHolderImpl;
import org.sonar.server.computation.qualitygate.QualityGateServiceImpl;
import org.sonar.server.computation.qualityprofile.ActiveRulesHolderImpl;
+import org.sonar.server.computation.source.LastCommitVisitor;
import org.sonar.server.computation.sqale.SqaleMeasuresVisitor;
import org.sonar.server.computation.sqale.SqaleRatingSettings;
import org.sonar.server.computation.step.ComputationSteps;
@@ -168,6 +169,7 @@ public final class ReportComputeEngineContainerPopulator implements ContainerPop
IntegrateIssuesVisitor.class,
CloseIssuesOnRemovedComponentsVisitor.class,
SqaleMeasuresVisitor.class,
+ LastCommitVisitor.class,
MeasureComputersVisitor.class,
UpdateConflictResolver.class,
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/metric/Metric.java b/server/sonar-server/src/main/java/org/sonar/server/computation/metric/Metric.java
index 5446495665b..ee6771b6cfe 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/metric/Metric.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/metric/Metric.java
@@ -51,7 +51,7 @@ public interface Metric {
enum MetricType {
INT(Measure.ValueType.INT),
- MILLISEC(Measure.ValueType.INT),
+ MILLISEC(Measure.ValueType.LONG),
RATING(Measure.ValueType.INT),
WORK_DUR(Measure.ValueType.LONG),
FLOAT(Measure.ValueType.DOUBLE),
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/source/LastCommitVisitor.java b/server/sonar-server/src/main/java/org/sonar/server/computation/source/LastCommitVisitor.java
new file mode 100644
index 00000000000..63a137871c5
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/source/LastCommitVisitor.java
@@ -0,0 +1,138 @@
+/*
+ * 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.computation.source;
+
+import com.google.common.base.Optional;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.batch.protocol.output.BatchReport;
+import org.sonar.server.computation.batch.BatchReportReader;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.CrawlerDepthLimit;
+import org.sonar.server.computation.component.PathAwareVisitorAdapter;
+import org.sonar.server.computation.measure.Measure;
+import org.sonar.server.computation.measure.MeasureRepository;
+import org.sonar.server.computation.metric.Metric;
+import org.sonar.server.computation.metric.MetricRepository;
+
+import static org.sonar.server.computation.component.ComponentVisitor.Order.POST_ORDER;
+
+public class LastCommitVisitor extends PathAwareVisitorAdapter<LastCommitVisitor.LastCommit> {
+
+ private final BatchReportReader reportReader;
+ private final MeasureRepository measureRepository;
+ private final Metric lastCommitDateMetric;
+
+ public LastCommitVisitor(BatchReportReader reportReader, MetricRepository metricRepository,
+ MeasureRepository measureRepository) {
+ super(CrawlerDepthLimit.LEAVES, POST_ORDER, new SimpleStackElementFactory<LastCommit>() {
+ @Override
+ public LastCommit createForAny(Component component) {
+ return new LastCommit();
+ }
+
+ /** Stack item is not used at ProjectView level, saves on instantiating useless objects */
+ @Override
+ public LastCommit createForProjectView(Component projectView) {
+ return null;
+ }
+ });
+ this.reportReader = reportReader;
+ this.measureRepository = measureRepository;
+ this.lastCommitDateMetric = metricRepository.getByKey(CoreMetrics.LAST_COMMIT_DATE_KEY);
+ }
+
+ @Override
+ public void visitProject(Component project, Path<LastCommit> path) {
+ saveAndAggregate(project, path);
+ }
+
+ @Override
+ public void visitDirectory(Component directory, Path<LastCommit> path) {
+ saveAndAggregate(directory, path);
+ }
+
+ @Override
+ public void visitModule(Component module, Path<LastCommit> path) {
+ saveAndAggregate(module, path);
+ }
+
+ @Override
+ public void visitFile(Component file, Path<LastCommit> path) {
+ // load SCM blame information from report. It can be absent when the file was not touched
+ // since previous analysis (optimization to decrease execution of blame commands). In this case
+ // the date is loaded from database, as it did not change from previous analysis.
+ BatchReport.Changesets changesets = reportReader.readChangesets(file.getReportAttributes().getRef());
+ if (changesets == null) {
+ Optional<Measure> baseMeasure = measureRepository.getBaseMeasure(file, lastCommitDateMetric);
+ if (baseMeasure.isPresent()) {
+ path.current().addDate(baseMeasure.get().getLongValue());
+ }
+ } else {
+ for (BatchReport.Changesets.Changeset changeset : changesets.getChangesetList()) {
+ if (changeset.hasDate()) {
+ path.current().addDate(changeset.getDate());
+ }
+ }
+ }
+ saveAndAggregate(file, path);
+ }
+
+ @Override
+ public void visitView(Component view, Path<LastCommit> path) {
+ saveAndAggregate(view, path);
+ }
+
+ @Override
+ public void visitSubView(Component subView, Path<LastCommit> path) {
+ saveAndAggregate(subView, path);
+ }
+
+ @Override
+ public void visitProjectView(Component projectView, Path<LastCommit> path) {
+ if (!path.isRoot()) {
+ Optional<Measure> rawMeasure = measureRepository.getRawMeasure(projectView, lastCommitDateMetric);
+ if (rawMeasure.isPresent()) {
+ path.parent().addDate(rawMeasure.get().getLongValue());
+ }
+ }
+ }
+
+ private void saveAndAggregate(Component component, Path<LastCommit> path) {
+ long maxDate = path.current().getDate();
+ if (maxDate > 0L) {
+ measureRepository.add(component, lastCommitDateMetric, Measure.newMeasureBuilder().create(maxDate));
+ if (!path.isRoot()) {
+ path.parent().addDate(maxDate);
+ }
+ }
+ }
+
+ public static final class LastCommit {
+ private long date = 0;
+
+ public void addDate(long l) {
+ this.date = Math.max(this.date, l);
+ }
+
+ public long getDate() {
+ return date;
+ }
+ }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistNumberOfDaysSinceLastCommitStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistNumberOfDaysSinceLastCommitStep.java
deleted file mode 100644
index e28c529d121..00000000000
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistNumberOfDaysSinceLastCommitStep.java
+++ /dev/null
@@ -1,137 +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.computation.step;
-
-import java.util.Date;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.utils.System2;
-import org.sonar.batch.protocol.output.BatchReport;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.db.MyBatis;
-import org.sonar.db.measure.MeasureDto;
-import org.sonar.server.computation.batch.BatchReportReader;
-import org.sonar.server.computation.component.Component;
-import org.sonar.server.computation.component.CrawlerDepthLimit;
-import org.sonar.server.computation.component.DbIdsRepository;
-import org.sonar.server.computation.component.DepthTraversalTypeAwareCrawler;
-import org.sonar.server.computation.component.TreeRootHolder;
-import org.sonar.server.computation.component.TypeAwareVisitorAdapter;
-import org.sonar.server.computation.metric.MetricRepository;
-import org.sonar.server.source.index.SourceLineIndex;
-
-import static com.google.common.base.Objects.firstNonNull;
-import static org.sonar.server.computation.component.ComponentVisitor.Order.PRE_ORDER;
-
-public class PersistNumberOfDaysSinceLastCommitStep implements ComputationStep {
-
- private static final long MILLISECONDS_PER_DAY = 1000 * 60 * 60 * 24L;
-
- private final DbClient dbClient;
- private final SourceLineIndex sourceLineIndex;
- private final MetricRepository metricRepository;
- private final System2 system;
- private final TreeRootHolder treeRootHolder;
- private final BatchReportReader reportReader;
- private final DbIdsRepository dbIdsRepository;
-
- public PersistNumberOfDaysSinceLastCommitStep(System2 system, DbClient dbClient, SourceLineIndex sourceLineIndex, MetricRepository metricRepository,
- TreeRootHolder treeRootHolder, BatchReportReader reportReader, DbIdsRepository dbIdsRepository) {
- this.dbClient = dbClient;
- this.sourceLineIndex = sourceLineIndex;
- this.metricRepository = metricRepository;
- this.system = system;
- this.treeRootHolder = treeRootHolder;
- this.reportReader = reportReader;
- this.dbIdsRepository = dbIdsRepository;
- }
-
- @Override
- public String getDescription() {
- return "Compute and persist the number of days since last commit";
- }
-
- @Override
- public void execute() {
- NumberOfDaysSinceLastCommitVisitor visitor = new NumberOfDaysSinceLastCommitVisitor();
- Component project = treeRootHolder.getRoot();
- new DepthTraversalTypeAwareCrawler(visitor).visit(project);
-
- long lastCommitTimestamp = visitor.lastCommitTimestampFromReport;
- if (lastCommitTimestamp == 0L) {
- Long lastCommitFromIndex = lastCommitFromIndex(treeRootHolder.getRoot().getUuid());
- lastCommitTimestamp = firstNonNull(lastCommitFromIndex, lastCommitTimestamp);
- }
-
- if (lastCommitTimestamp != 0L) {
- persistNumberOfDaysSinceLastCommit(lastCommitTimestamp, dbIdsRepository.getSnapshotId(project));
- }
- }
-
- @CheckForNull
- private Long lastCommitFromIndex(String projectUuid) {
- Date lastCommitDate = sourceLineIndex.lastCommitDateOnProject(projectUuid);
- return lastCommitDate == null ? null : lastCommitDate.getTime();
- }
-
- private void persistNumberOfDaysSinceLastCommit(long lastCommitTimestamp, long projectSnapshotId) {
- long numberOfDaysSinceLastCommit = (system.now() - lastCommitTimestamp) / MILLISECONDS_PER_DAY;
- DbSession dbSession = dbClient.openSession(true);
- try {
- dbClient.measureDao().insert(dbSession, new MeasureDto()
- .setValue((double) numberOfDaysSinceLastCommit)
- .setMetricId(metricRepository.getByKey(CoreMetrics.DAYS_SINCE_LAST_COMMIT_KEY).getId())
- .setSnapshotId(projectSnapshotId));
- dbSession.commit();
- } finally {
- MyBatis.closeQuietly(dbSession);
- }
- }
-
- private class NumberOfDaysSinceLastCommitVisitor extends TypeAwareVisitorAdapter {
-
- private long lastCommitTimestampFromReport = 0L;
-
- private NumberOfDaysSinceLastCommitVisitor() {
- super(CrawlerDepthLimit.FILE, PRE_ORDER);
- }
-
- @Override
- public void visitFile(Component component) {
- BatchReport.Changesets scm = reportReader.readChangesets(component.getReportAttributes().getRef());
- processScm(scm);
- }
-
- private void processScm(@Nullable BatchReport.Changesets scm) {
- if (scm == null) {
- return;
- }
-
- for (BatchReport.Changesets.Changeset changeset : scm.getChangesetList()) {
- if (changeset.hasDate() && changeset.getDate() > lastCommitTimestampFromReport) {
- lastCommitTimestampFromReport = changeset.getDate();
- }
- }
- }
- }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/ReportComputationSteps.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/ReportComputationSteps.java
index d65b2d96add..2a784b5c1b7 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/ReportComputationSteps.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/ReportComputationSteps.java
@@ -81,7 +81,6 @@ public class ReportComputationSteps implements ComputationSteps {
// Persist data
PersistComponentsStep.class,
PersistSnapshotsStep.class,
- PersistNumberOfDaysSinceLastCommitStep.class,
PersistMeasuresStep.class,
PersistIssuesStep.class,
PersistProjectLinksStep.class,
diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/ws/ShowAction.java b/server/sonar-server/src/main/java/org/sonar/server/source/ws/ShowAction.java
index 278d4c8b350..2d9a12109a4 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/source/ws/ShowAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/source/ws/ShowAction.java
@@ -106,7 +106,7 @@ public class ShowAction implements SourcesWsAction {
for (int i = 0; i < lines.size(); i++) {
String line = lines.get(i);
json.beginArray();
- json.value(1L * i + from);
+ json.value((long) i + from);
json.value(line);
json.endArray();
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/source/LastCommitVisitorTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/source/LastCommitVisitorTest.java
new file mode 100644
index 00000000000..93dfebdfa92
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/source/LastCommitVisitorTest.java
@@ -0,0 +1,220 @@
+/*
+ * 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.computation.source;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.batch.protocol.output.BatchReport;
+import org.sonar.server.computation.batch.BatchReportReaderRule;
+import org.sonar.server.computation.batch.TreeRootHolderRule;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.ComponentVisitor;
+import org.sonar.server.computation.component.FileAttributes;
+import org.sonar.server.computation.component.ReportComponent;
+import org.sonar.server.computation.component.ViewsComponent;
+import org.sonar.server.computation.component.VisitorsCrawler;
+import org.sonar.server.computation.measure.Measure;
+import org.sonar.server.computation.measure.MeasureRepositoryRule;
+import org.sonar.server.computation.metric.MetricRepositoryRule;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.api.measures.CoreMetrics.LAST_COMMIT_DATE_KEY;
+import static org.sonar.server.computation.component.Component.Type.DIRECTORY;
+import static org.sonar.server.computation.component.Component.Type.FILE;
+import static org.sonar.server.computation.component.Component.Type.MODULE;
+import static org.sonar.server.computation.component.Component.Type.PROJECT;
+import static org.sonar.server.computation.component.Component.Type.PROJECT_VIEW;
+import static org.sonar.server.computation.component.Component.Type.SUBVIEW;
+import static org.sonar.server.computation.component.Component.Type.VIEW;
+import static org.sonar.server.computation.component.ViewsComponent.builder;
+import static org.sonar.server.computation.measure.Measure.newMeasureBuilder;
+
+public class LastCommitVisitorTest {
+
+ public static final int FILE_REF = 1;
+
+ @Rule
+ public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
+
+ @Rule
+ public BatchReportReaderRule reportReader = new BatchReportReaderRule();
+
+ @Rule
+ public MetricRepositoryRule metricRepository = new MetricRepositoryRule().add(CoreMetrics.LAST_COMMIT_DATE);
+
+ @Rule
+ public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
+
+ @Test
+ public void aggregate_date_of_last_commit_to_directories_and_project() throws Exception {
+ // simulate the output of visitFile()
+ LastCommitVisitor visitor = new LastCommitVisitor(reportReader, metricRepository, measureRepository) {
+ @Override
+ public void visitFile(Component file, Path<LastCommit> path) {
+ path.parent().addDate(file.getReportAttributes().getRef() * 1_000_000_000L);
+ }
+ };
+
+ // project with 1 module, 2 directories and 3 files
+ ReportComponent project = ReportComponent.builder(PROJECT, 1)
+ .addChildren(
+ ReportComponent.builder(MODULE, 11)
+ .addChildren(
+ ReportComponent.builder(DIRECTORY, 111)
+ .addChildren(
+ createFileComponent(1111),
+ createFileComponent(1112))
+ .build(),
+ ReportComponent.builder(DIRECTORY, 112)
+ .addChildren(
+ createFileComponent(1121))
+ .build())
+ .build())
+ .build();
+ treeRootHolder.setRoot(project);
+
+ VisitorsCrawler underTest = new VisitorsCrawler(Lists.<ComponentVisitor>newArrayList(visitor));
+ underTest.visit(project);
+
+ // directories
+ assertDate(111, 1_112_000_000_000L);
+ assertDate(112, 1_121_000_000_000L);
+
+ // module = most recent commit date of directories
+ assertDate(11, 1_121_000_000_000L);
+
+ // project
+ assertDate(1, 1_121_000_000_000L);
+ }
+
+ @Test
+ public void aggregate_date_of_last_commit_to_views() throws Exception {
+ // view with 3 nested sub-views and 3 projects
+ ViewsComponent view = ViewsComponent.builder(VIEW, 1)
+ .addChildren(
+ builder(SUBVIEW, 11)
+ .addChildren(
+ builder(SUBVIEW, 111)
+ .addChildren(
+ builder(PROJECT_VIEW, 1111).build(),
+ builder(PROJECT_VIEW, 1112).build())
+ .build(),
+ builder(SUBVIEW, 112)
+ .addChildren(
+ builder(PROJECT_VIEW, 1121).build())
+ .build())
+ .build())
+ .build();
+ treeRootHolder.setRoot(view);
+
+ // the second project has the most recent commit date
+ measureRepository.addRawMeasure(1111, CoreMetrics.LAST_COMMIT_DATE_KEY, newMeasureBuilder().create(1_500_000_000_000L));
+ measureRepository.addRawMeasure(1112, CoreMetrics.LAST_COMMIT_DATE_KEY, newMeasureBuilder().create(1_700_000_000_000L));
+ measureRepository.addRawMeasure(1121, CoreMetrics.LAST_COMMIT_DATE_KEY, newMeasureBuilder().create(1_600_000_000_000L));
+
+ VisitorsCrawler underTest = new VisitorsCrawler(Lists.<ComponentVisitor>newArrayList(new LastCommitVisitor(reportReader, metricRepository, measureRepository)));
+ underTest.visit(view);
+
+ // second level of sub-views
+ assertDate(111, 1_700_000_000_000L);
+ assertDate(112, 1_600_000_000_000L);
+
+ // first level of sub-views
+ assertDate(11, 1_700_000_000_000L);
+
+ // view
+ assertDate(1, 1_700_000_000_000L);
+ }
+
+ @Test
+ public void compute_date_of_file_from_blame_info_of_report() throws Exception {
+ VisitorsCrawler underTest = new VisitorsCrawler(Lists.<ComponentVisitor>newArrayList(new LastCommitVisitor(reportReader, metricRepository, measureRepository)));
+
+ BatchReport.Changesets changesets = BatchReport.Changesets.newBuilder()
+ .setComponentRef(FILE_REF)
+ .addChangeset(BatchReport.Changesets.Changeset.newBuilder()
+ .setAuthor("john")
+ .setDate(1_500_000_000_000L)
+ .setRevision("rev-1")
+ .build())
+ .addChangeset(BatchReport.Changesets.Changeset.newBuilder()
+ .setAuthor("tom")
+ // this is the most recent change
+ .setDate(1_600_000_000_000L)
+ .setRevision("rev-2")
+ .build())
+ .addChangeset(BatchReport.Changesets.Changeset.newBuilder()
+ .setAuthor("john")
+ .setDate(1_500_000_000_000L)
+ .setRevision("rev-1")
+ .build())
+ .addChangesetIndexByLine(0)
+ .build();
+ reportReader.putChangesets(changesets);
+ ReportComponent file = createFileComponent(FILE_REF);
+ treeRootHolder.setRoot(file);
+
+ underTest.visit(file);
+
+ assertDate(FILE_REF, 1_600_000_000_000L);
+ }
+
+ private void assertDate(int componentRef, long expectedDate) {
+ Optional<Measure> measure = measureRepository.getAddedRawMeasure(componentRef, LAST_COMMIT_DATE_KEY);
+ assertThat(measure.isPresent()).isTrue();
+ assertThat(measure.get().getLongValue()).isEqualTo(expectedDate);
+ }
+
+ /**
+ * When the file was not changed since previous analysis, than the report may not contain
+ * the SCM blame information. In this case the date of last commit is loaded
+ * from the base measure of previous analysis, directly from database
+ */
+ @Test
+ public void reuse_date_of_previous_analysis_if_blame_info_is_not_in_report() throws Exception {
+ VisitorsCrawler underTest = new VisitorsCrawler(Lists.<ComponentVisitor>newArrayList(new LastCommitVisitor(reportReader, metricRepository, measureRepository)));
+ ReportComponent file = createFileComponent(FILE_REF);
+ treeRootHolder.setRoot(file);
+ measureRepository.addBaseMeasure(FILE_REF, LAST_COMMIT_DATE_KEY, newMeasureBuilder().create(1_500_000_000L));
+
+ underTest.visit(file);
+
+ assertDate(FILE_REF, 1_500_000_000L);
+ }
+
+ @Test
+ public void date_is_not_computed_on_file_if_blame_is_not_in_report_nor_in_previous_analysis() throws Exception {
+ VisitorsCrawler underTest = new VisitorsCrawler(Lists.<ComponentVisitor>newArrayList(new LastCommitVisitor(reportReader, metricRepository, measureRepository)));
+ ReportComponent file = createFileComponent(FILE_REF);
+ treeRootHolder.setRoot(file);
+
+ underTest.visit(file);
+
+ Optional<Measure> measure = measureRepository.getAddedRawMeasure(FILE_REF, LAST_COMMIT_DATE_KEY);
+ assertThat(measure.isPresent()).isFalse();
+ }
+
+ private ReportComponent createFileComponent(int fileRef) {
+ return ReportComponent.builder(FILE, fileRef).setFileAttributes(new FileAttributes(false, "js")).build();
+ }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistNumberOfDaysSinceLastCommitStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistNumberOfDaysSinceLastCommitStepTest.java
deleted file mode 100644
index 37487ea77aa..00000000000
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistNumberOfDaysSinceLastCommitStepTest.java
+++ /dev/null
@@ -1,132 +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.computation.step;
-
-import java.util.Date;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.config.Settings;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.api.utils.System2;
-import org.sonar.batch.protocol.output.BatchReport;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbTester;
-import org.sonar.server.computation.batch.BatchReportReaderRule;
-import org.sonar.server.computation.batch.TreeRootHolderRule;
-import org.sonar.server.computation.component.Component;
-import org.sonar.server.computation.component.DbIdsRepositoryImpl;
-import org.sonar.server.computation.component.ReportComponent;
-import org.sonar.server.computation.language.LanguageRepository;
-import org.sonar.server.computation.metric.Metric;
-import org.sonar.server.computation.metric.MetricImpl;
-import org.sonar.server.computation.metric.MetricRepository;
-import org.sonar.server.source.index.SourceLineIndex;
-
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class PersistNumberOfDaysSinceLastCommitStepTest extends BaseStepTest {
-
- @Rule
- public DbTester db = DbTester.create(System2.INSTANCE);
-
- @Rule
- public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
-
- @Rule
- public BatchReportReaderRule reportReader = new BatchReportReaderRule();
-
- DbIdsRepositoryImpl dbIdsRepository = new DbIdsRepositoryImpl();
-
- PersistNumberOfDaysSinceLastCommitStep underTest;
-
- DbClient dbClient = db.getDbClient();
- SourceLineIndex sourceLineIndex;
- MetricRepository metricRepository;
- Settings projectSettings;
- LanguageRepository languageRepository;
-
- @Before
- public void setUp() {
- db.truncateTables();
- sourceLineIndex = mock(SourceLineIndex.class);
- metricRepository = mock(MetricRepository.class);
- projectSettings = new Settings();
- languageRepository = mock(LanguageRepository.class);
- when(metricRepository.getByKey(anyString())).thenReturn(new MetricImpl(10, "key", "name", Metric.MetricType.STRING));
-
- underTest = new PersistNumberOfDaysSinceLastCommitStep(System2.INSTANCE, dbClient, sourceLineIndex, metricRepository, treeRootHolder, reportReader, dbIdsRepository);
- }
-
- @Override
- protected ComputationStep step() {
- return underTest;
- }
-
- @Test
- public void persist_number_of_days_since_last_commit_from_report() {
- long threeDaysAgo = DateUtils.addDays(new Date(), -3).getTime();
- initProject();
- reportReader.putChangesets(
- BatchReport.Changesets.newBuilder()
- .setComponentRef(2)
- .addChangeset(
- BatchReport.Changesets.Changeset.newBuilder()
- .setDate(threeDaysAgo)
- )
- .build()
- );
-
- underTest.execute();
-
- db.assertDbUnit(getClass(), "insert-from-report-result.xml", new String[]{"id"}, "project_measures");
- }
-
- @Test
- public void persist_number_of_days_since_last_commit_from_index() {
- Date sixDaysAgo = DateUtils.addDays(new Date(), -6);
- when(sourceLineIndex.lastCommitDateOnProject("project-uuid")).thenReturn(sixDaysAgo);
- initProject();
-
- underTest.execute();
-
- db.assertDbUnit(getClass(), "insert-from-index-result.xml", new String[]{"id"}, "project_measures");
- }
-
- @Test
- public void no_scm_information_in_report_and_index() {
- initProject();
-
- underTest.execute();
-
- db.assertDbUnit(getClass(), "empty.xml");
- }
-
- private void initProject() {
- Component project = ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("project-uuid").addChildren(
- ReportComponent.builder(Component.Type.FILE, 2).setUuid("file-uuid").build())
- .build();
- treeRootHolder.setRoot(project);
- dbIdsRepository.setSnapshotId(project, 1000);
- }
-}