package org.sonar.plugins.core;
import com.google.common.collect.ImmutableList;
-import org.sonar.api.*;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.Extension;
+import org.sonar.api.Properties;
+import org.sonar.api.Property;
+import org.sonar.api.PropertyType;
+import org.sonar.api.SonarPlugin;
import org.sonar.api.checks.NoSonarFilter;
import org.sonar.api.resources.Java;
import org.sonar.plugins.core.batch.ExcludedResourceFilter;
import org.sonar.plugins.core.charts.DistributionBarChart;
import org.sonar.plugins.core.charts.XradarChart;
import org.sonar.plugins.core.colorizers.JavaColorizerFormat;
-import org.sonar.plugins.core.dashboards.*;
+import org.sonar.plugins.core.dashboards.DefaultDashboard;
+import org.sonar.plugins.core.dashboards.HotspotsDashboard;
+import org.sonar.plugins.core.dashboards.MyFavouritesDashboard;
+import org.sonar.plugins.core.dashboards.ProjectsDashboard;
+import org.sonar.plugins.core.dashboards.ReviewsDashboard;
+import org.sonar.plugins.core.dashboards.TimeMachineDashboard;
+import org.sonar.plugins.core.dashboards.TreemapDashboard;
import org.sonar.plugins.core.filters.MyFavouritesFilter;
import org.sonar.plugins.core.filters.ProjectFilter;
import org.sonar.plugins.core.filters.TreeMapFilter;
import org.sonar.plugins.core.security.ApplyProjectRolesDecorator;
-import org.sonar.plugins.core.security.DefaultResourcePermissions;
-import org.sonar.plugins.core.sensors.*;
+import org.sonar.plugins.core.sensors.BranchCoverageDecorator;
+import org.sonar.plugins.core.sensors.CheckAlertThresholds;
+import org.sonar.plugins.core.sensors.CommentDensityDecorator;
+import org.sonar.plugins.core.sensors.CoverageDecorator;
+import org.sonar.plugins.core.sensors.DirectoriesDecorator;
+import org.sonar.plugins.core.sensors.FilesDecorator;
+import org.sonar.plugins.core.sensors.GenerateAlertEvents;
+import org.sonar.plugins.core.sensors.ItBranchCoverageDecorator;
+import org.sonar.plugins.core.sensors.ItCoverageDecorator;
+import org.sonar.plugins.core.sensors.ItLineCoverageDecorator;
+import org.sonar.plugins.core.sensors.LineCoverageDecorator;
+import org.sonar.plugins.core.sensors.ManualMeasureDecorator;
+import org.sonar.plugins.core.sensors.ManualViolationInjector;
+import org.sonar.plugins.core.sensors.ProfileEventsSensor;
+import org.sonar.plugins.core.sensors.ProfileSensor;
+import org.sonar.plugins.core.sensors.ProjectLinksSensor;
+import org.sonar.plugins.core.sensors.ReviewNotifications;
+import org.sonar.plugins.core.sensors.ReviewWorkflowDecorator;
+import org.sonar.plugins.core.sensors.ReviewsMeasuresDecorator;
+import org.sonar.plugins.core.sensors.UnitTestDecorator;
+import org.sonar.plugins.core.sensors.VersionEventsSensor;
+import org.sonar.plugins.core.sensors.ViolationSeverityUpdater;
+import org.sonar.plugins.core.sensors.ViolationsDecorator;
+import org.sonar.plugins.core.sensors.ViolationsDensityDecorator;
+import org.sonar.plugins.core.sensors.WeightedViolationsDecorator;
import org.sonar.plugins.core.testdetailsviewer.TestsViewerDefinition;
-import org.sonar.plugins.core.timemachine.*;
+import org.sonar.plugins.core.timemachine.NewCoverageAggregator;
+import org.sonar.plugins.core.timemachine.NewCoverageFileAnalyzer;
+import org.sonar.plugins.core.timemachine.NewItCoverageFileAnalyzer;
+import org.sonar.plugins.core.timemachine.NewViolationsDecorator;
+import org.sonar.plugins.core.timemachine.ReferenceAnalysis;
+import org.sonar.plugins.core.timemachine.TendencyDecorator;
+import org.sonar.plugins.core.timemachine.TimeMachineConfigurationPersister;
+import org.sonar.plugins.core.timemachine.VariationDecorator;
+import org.sonar.plugins.core.timemachine.ViolationPersisterDecorator;
+import org.sonar.plugins.core.timemachine.ViolationTrackingDecorator;
import org.sonar.plugins.core.web.Lcom4Viewer;
-import org.sonar.plugins.core.widgets.*;
+import org.sonar.plugins.core.widgets.AlertsWidget;
+import org.sonar.plugins.core.widgets.CommentsDuplicationsWidget;
+import org.sonar.plugins.core.widgets.ComplexityWidget;
+import org.sonar.plugins.core.widgets.CoverageWidget;
+import org.sonar.plugins.core.widgets.CustomMeasuresWidget;
+import org.sonar.plugins.core.widgets.DescriptionWidget;
+import org.sonar.plugins.core.widgets.EventsWidget;
+import org.sonar.plugins.core.widgets.FilterWidget;
+import org.sonar.plugins.core.widgets.HotspotMetricWidget;
+import org.sonar.plugins.core.widgets.HotspotMostViolatedResourcesWidget;
+import org.sonar.plugins.core.widgets.HotspotMostViolatedRulesWidget;
+import org.sonar.plugins.core.widgets.ItCoverageWidget;
+import org.sonar.plugins.core.widgets.RulesWidget;
+import org.sonar.plugins.core.widgets.SizeWidget;
+import org.sonar.plugins.core.widgets.TimeMachineWidget;
+import org.sonar.plugins.core.widgets.TimelineWidget;
+import org.sonar.plugins.core.widgets.TreemapWidget;
import org.sonar.plugins.core.widgets.actionPlans.ActionPlansWidget;
-import org.sonar.plugins.core.widgets.reviews.*;
+import org.sonar.plugins.core.widgets.reviews.FalsePositiveReviewsWidget;
+import org.sonar.plugins.core.widgets.reviews.MyReviewsWidget;
+import org.sonar.plugins.core.widgets.reviews.PlannedReviewsWidget;
+import org.sonar.plugins.core.widgets.reviews.ProjectReviewsWidget;
+import org.sonar.plugins.core.widgets.reviews.ReviewsMetricsWidget;
+import org.sonar.plugins.core.widgets.reviews.ReviewsPerDeveloperWidget;
+import org.sonar.plugins.core.widgets.reviews.UnplannedReviewsWidget;
import java.util.List;
name = "Period 1",
description = "Period used to compare measures and track new violations. Values are : <ul class='bullet'><li>Number of days before " +
"analysis, for example 5.</li><li>A custom date. Format is yyyy-MM-dd, for example 2010-12-25</li><li>'previous_analysis' to " +
- "compare to previous analysis</li></ul>" + "<p>When specifying a number of days or a date, the snapshot selected for comparison is " +
+ "compare to previous analysis</li><li>'previous_version' to compare to the previous version in the project history</li></ul>" +
+ "<p>When specifying a number of days or a date, the snapshot selected for comparison is " +
" the first one available inside the corresponding time range. </p>" +
"<p>Changing this property only takes effect after subsequent project inspections.<p/>",
project = false,
name = "Period 4",
description = "Period used to compare measures and track new violations. This property is specific to the project. Values are : " +
"<ul class='bullet'><li>Number of days before analysis, for example 5.</li><li>A custom date. Format is yyyy-MM-dd, " +
- "for example 2010-12-25</li><li>'previous_analysis' to compare to previous analysis</li><li>A version, for example 1.2</li></ul>" +
+ "for example 2010-12-25</li><li>'previous_analysis' to compare to previous analysis</li>" +
+ "<li>'previous_version' to compare to the previous version in the project history</li><li>A version, for example 1.2</li></ul>" +
"<p>When specifying a number of days or a date, the snapshot selected for comparison is the first one available inside the corresponding time range. </p>" +
"<p>Changing this property only takes effect after subsequent project inspections.<p/>",
project = true,
@SuppressWarnings("unchecked")
public List<Class<? extends Extension>> getExtensions() {
return ImmutableList.of(
- DefaultResourceTypes.class,
- UserManagedMetrics.class,
- ProjectFileSystemLogger.class,
+ DefaultResourceTypes.class,
+ UserManagedMetrics.class,
+ ProjectFileSystemLogger.class,
- // maven
- MavenInitializer.class,
+ // maven
+ MavenInitializer.class,
- // languages
- Java.class,
+ // languages
+ Java.class,
- // pages
- TestsViewerDefinition.class,
- Lcom4Viewer.class,
+ // pages
+ TestsViewerDefinition.class,
+ Lcom4Viewer.class,
- // filters
- ProjectFilter.class,
- TreeMapFilter.class,
- MyFavouritesFilter.class,
+ // filters
+ ProjectFilter.class,
+ TreeMapFilter.class,
+ MyFavouritesFilter.class,
- // widgets
- AlertsWidget.class,
- CoverageWidget.class,
- ItCoverageWidget.class,
- CommentsDuplicationsWidget.class,
- DescriptionWidget.class,
- ComplexityWidget.class,
- RulesWidget.class,
- SizeWidget.class,
- EventsWidget.class,
- CustomMeasuresWidget.class,
- TimelineWidget.class,
- TimeMachineWidget.class,
- HotspotMetricWidget.class,
- HotspotMostViolatedResourcesWidget.class,
- HotspotMostViolatedRulesWidget.class,
- MyReviewsWidget.class,
- ProjectReviewsWidget.class,
- FalsePositiveReviewsWidget.class,
- ReviewsPerDeveloperWidget.class,
- PlannedReviewsWidget.class,
- UnplannedReviewsWidget.class,
- ActionPlansWidget.class,
- ReviewsMetricsWidget.class,
- TreemapWidget.class,
- FilterWidget.class,
+ // widgets
+ AlertsWidget.class,
+ CoverageWidget.class,
+ ItCoverageWidget.class,
+ CommentsDuplicationsWidget.class,
+ DescriptionWidget.class,
+ ComplexityWidget.class,
+ RulesWidget.class,
+ SizeWidget.class,
+ EventsWidget.class,
+ CustomMeasuresWidget.class,
+ TimelineWidget.class,
+ TimeMachineWidget.class,
+ HotspotMetricWidget.class,
+ HotspotMostViolatedResourcesWidget.class,
+ HotspotMostViolatedRulesWidget.class,
+ MyReviewsWidget.class,
+ ProjectReviewsWidget.class,
+ FalsePositiveReviewsWidget.class,
+ ReviewsPerDeveloperWidget.class,
+ PlannedReviewsWidget.class,
+ UnplannedReviewsWidget.class,
+ ActionPlansWidget.class,
+ ReviewsMetricsWidget.class,
+ TreemapWidget.class,
+ FilterWidget.class,
- // dashboards
- DefaultDashboard.class,
- HotspotsDashboard.class,
- ReviewsDashboard.class,
- TimeMachineDashboard.class,
- ProjectsDashboard.class,
- TreemapDashboard.class,
- MyFavouritesDashboard.class,
+ // dashboards
+ DefaultDashboard.class,
+ HotspotsDashboard.class,
+ ReviewsDashboard.class,
+ TimeMachineDashboard.class,
+ ProjectsDashboard.class,
+ TreemapDashboard.class,
+ MyFavouritesDashboard.class,
- // chart
- XradarChart.class,
- DistributionBarChart.class,
- DistributionAreaChart.class,
+ // chart
+ XradarChart.class,
+ DistributionBarChart.class,
+ DistributionAreaChart.class,
- // colorizers
- JavaColorizerFormat.class,
+ // colorizers
+ JavaColorizerFormat.class,
- // batch
- ProfileSensor.class,
- ProfileEventsSensor.class,
- ProjectLinksSensor.class,
- UnitTestDecorator.class,
- VersionEventsSensor.class,
- CheckAlertThresholds.class,
- GenerateAlertEvents.class,
- ViolationsDecorator.class,
- WeightedViolationsDecorator.class,
- ViolationsDensityDecorator.class,
- LineCoverageDecorator.class,
- CoverageDecorator.class,
- BranchCoverageDecorator.class,
- ItLineCoverageDecorator.class,
- ItCoverageDecorator.class,
- ItBranchCoverageDecorator.class,
- DefaultResourcePermissions.class,
- ApplyProjectRolesDecorator.class,
- ExcludedResourceFilter.class,
- CommentDensityDecorator.class,
- NoSonarFilter.class,
- DirectoriesDecorator.class,
- FilesDecorator.class,
- ReviewNotifications.class,
- ReviewWorkflowDecorator.class,
- ReferenceAnalysis.class,
- ManualMeasureDecorator.class,
- ManualViolationInjector.class,
- ViolationSeverityUpdater.class,
- IndexProjectPostJob.class,
- ReviewsMeasuresDecorator.class,
+ // batch
+ ProfileSensor.class,
+ ProfileEventsSensor.class,
+ ProjectLinksSensor.class,
+ UnitTestDecorator.class,
+ VersionEventsSensor.class,
+ CheckAlertThresholds.class,
+ GenerateAlertEvents.class,
+ ViolationsDecorator.class,
+ WeightedViolationsDecorator.class,
+ ViolationsDensityDecorator.class,
+ LineCoverageDecorator.class,
+ CoverageDecorator.class,
+ BranchCoverageDecorator.class,
+ ItLineCoverageDecorator.class,
+ ItCoverageDecorator.class,
+ ItBranchCoverageDecorator.class,
+ DefaultResourcePermissions.class,
+ ApplyProjectRolesDecorator.class,
+ ExcludedResourceFilter.class,
+ CommentDensityDecorator.class,
+ NoSonarFilter.class,
+ DirectoriesDecorator.class,
+ FilesDecorator.class,
+ ReviewNotifications.class,
+ ReviewWorkflowDecorator.class,
+ ReferenceAnalysis.class,
+ ManualMeasureDecorator.class,
+ ManualViolationInjector.class,
+ ViolationSeverityUpdater.class,
+ IndexProjectPostJob.class,
+ ReviewsMeasuresDecorator.class,
- // time machine
- TendencyDecorator.class,
- VariationDecorator.class,
- ViolationTrackingDecorator.class,
- ViolationPersisterDecorator.class,
- NewViolationsDecorator.class,
- TimeMachineConfigurationPersister.class,
- NewCoverageFileAnalyzer.class,
- NewItCoverageFileAnalyzer.class,
- NewCoverageAggregator.class);
+ // time machine
+ TendencyDecorator.class,
+ VariationDecorator.class,
+ ViolationTrackingDecorator.class,
+ ViolationPersisterDecorator.class,
+ NewViolationsDecorator.class,
+ TimeMachineConfigurationPersister.class,
+ NewCoverageFileAnalyzer.class,
+ NewItCoverageFileAnalyzer.class,
+ NewCoverageAggregator.class);
}
}
added_since=Added since {0}
added_since_previous_analysis=Added since previous analysis
added_since_previous_analysis_detailed=Added since previous analysis ({0})
+added_since_previous_version=Added since previous version
+added_since_previous_version_detailed=Added since previous version ({0})
added_since_version=Added since version {0}
alerts_feed=Alerts feed
all_violations=All violations
default_severity=Default severity
default_sort_on=Default sort on
delta_since_previous_analysis=Δ since previous analysis
+delta_since_previous_version=Δ since previous version
delta_over_x_days=Δ over {0} days
delta_since=Δ since {0}
delta_since_version=Δ since version {0}
since_previous_analysis_detailed=since previous analysis ({0})
since_version=since version {0}
since_version_detailed=since version {0} ({1})
+since_previous_version=since previous version
+since_previous_version_detailed=since previous version ({0})
time_changes=Time changes
#------------------------------------------------------------------------------
import org.sonar.batch.DefaultResourceCreationLock;
import org.sonar.batch.ProjectConfigurator;
import org.sonar.batch.ProjectTree;
-import org.sonar.batch.components.*;
-import org.sonar.batch.index.*;
+import org.sonar.batch.components.PastMeasuresLoader;
+import org.sonar.batch.components.PastSnapshotFinder;
+import org.sonar.batch.components.PastSnapshotFinderByDate;
+import org.sonar.batch.components.PastSnapshotFinderByDays;
+import org.sonar.batch.components.PastSnapshotFinderByPreviousAnalysis;
+import org.sonar.batch.components.PastSnapshotFinderByPreviousVersion;
+import org.sonar.batch.components.PastSnapshotFinderByVersion;
+import org.sonar.batch.index.DefaultIndex;
+import org.sonar.batch.index.DefaultPersistenceManager;
+import org.sonar.batch.index.DefaultResourcePersister;
+import org.sonar.batch.index.DependencyPersister;
+import org.sonar.batch.index.EventPersister;
+import org.sonar.batch.index.LinkPersister;
+import org.sonar.batch.index.MeasurePersister;
+import org.sonar.batch.index.MemoryOptimizer;
+import org.sonar.batch.index.ReadOnlyPersistenceManager;
+import org.sonar.batch.index.SourcePersister;
import org.sonar.core.metric.CacheMetricFinder;
import org.sonar.core.notification.DefaultNotificationManager;
import org.sonar.core.rule.CacheRuleFinder;
addCoreSingleton(PastSnapshotFinderByDays.class);
addCoreSingleton(PastSnapshotFinderByPreviousAnalysis.class);
addCoreSingleton(PastSnapshotFinderByVersion.class);
+ addCoreSingleton(PastSnapshotFinderByPreviousVersion.class);
addCoreSingleton(PastMeasuresLoader.class);
addCoreSingleton(PastSnapshotFinder.class);
addCoreSingleton(DefaultNotificationManager.class);
}
return label;
}
+ if (StringUtils.equals(mode, CoreProperties.TIMEMACHINE_MODE_PREVIOUS_VERSION)) {
+ String label = "Compare to previous version";
+ if (isRelatedToSnapshot()) {
+ label += String.format(" (%s)", DateUtils.formatDate(getDate()));
+ }
+ return label;
+ }
if (StringUtils.equals(mode, CoreProperties.TIMEMACHINE_MODE_DATE)) {
String label = "Compare to date " + DateUtils.formatDate(getTargetDate());
if (isRelatedToSnapshot()) {
private PastSnapshotFinderByVersion finderByVersion;
private PastSnapshotFinderByDate finderByDate;
private PastSnapshotFinderByPreviousAnalysis finderByPreviousAnalysis;
+ private PastSnapshotFinderByPreviousVersion finderByPreviousVersion;
public PastSnapshotFinder(PastSnapshotFinderByDays finderByDays, PastSnapshotFinderByVersion finderByVersion,
- PastSnapshotFinderByDate finderByDate, PastSnapshotFinderByPreviousAnalysis finderByPreviousAnalysis) {
+ PastSnapshotFinderByDate finderByDate, PastSnapshotFinderByPreviousAnalysis finderByPreviousAnalysis,
+ PastSnapshotFinderByPreviousVersion finderByPreviousVersion) {
this.finderByDays = finderByDays;
this.finderByVersion = finderByVersion;
this.finderByDate = finderByDate;
this.finderByPreviousAnalysis = finderByPreviousAnalysis;
+ this.finderByPreviousVersion = finderByPreviousVersion;
}
public PastSnapshot find(Snapshot projectSnapshot, Configuration conf, int index) {
if (result == null) {
result = findByPreviousAnalysis(projectSnapshot, property);
if (result == null) {
- result = findByVersion(projectSnapshot, property);
+ result = findByPreviousVersion(projectSnapshot, property);
+ if (result == null) {
+ result = findByVersion(projectSnapshot, property);
+ }
}
}
}
return pastSnapshot;
}
+ private PastSnapshot findByPreviousVersion(Snapshot projectSnapshot, String property) {
+ PastSnapshot pastSnapshot = null;
+ if (StringUtils.equals(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_VERSION, property)) {
+ pastSnapshot = finderByPreviousVersion.findByPreviousVersion(projectSnapshot);
+ }
+ return pastSnapshot;
+ }
+
private PastSnapshot findByDate(Snapshot projectSnapshot, String property) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
try {
--- /dev/null
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.batch.components;
+
+import org.sonar.api.BatchExtension;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.database.DatabaseSession;
+import org.sonar.api.database.model.Snapshot;
+import org.sonar.api.resources.Qualifiers;
+
+import java.util.Date;
+import java.util.List;
+
+public class PastSnapshotFinderByPreviousVersion implements BatchExtension {
+
+ private final DatabaseSession session;
+
+ public PastSnapshotFinderByPreviousVersion(DatabaseSession session) {
+ this.session = session;
+ }
+
+ PastSnapshot findByPreviousVersion(Snapshot projectSnapshot) {
+ String hql = "from " + Snapshot.class.getSimpleName() +
+ " where version!=:version AND version!='' AND resourceId=:resourceId AND status=:status AND qualifier<>:lib order by createdAt desc";
+ List<Snapshot> snapshots = session.createQuery(hql)
+ .setParameter("version", projectSnapshot.getVersion())
+ .setParameter("resourceId", projectSnapshot.getResourceId())
+ .setParameter("status", Snapshot.STATUS_PROCESSED)
+ .setParameter("lib", Qualifiers.LIBRARY)
+ .setMaxResults(1)
+ .getResultList();
+
+ PastSnapshot result;
+ if (snapshots.isEmpty()) {
+ result = new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_VERSION);
+ } else {
+ Snapshot snapshot = snapshots.get(0);
+ Date targetDate = snapshot.getCreatedAt();
+ result = new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_VERSION, targetDate, snapshot).setModeParameter(snapshot.getVersion());
+ }
+ return result;
+ }
+
+}
*/
package org.sonar.batch.components;
-import java.util.Date;
-import java.util.List;
-
-import javax.persistence.Query;
-
+import com.google.common.collect.Lists;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.lang.StringUtils;
import org.slf4j.LoggerFactory;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.utils.Logs;
-import com.google.common.collect.Lists;
+import javax.persistence.Query;
+
+import java.util.Date;
+import java.util.List;
public class TimeMachineConfiguration implements BatchExtension {
snapshot.setResourceId(projectId.intValue());
snapshot.setCreatedAt(project.getAnalysisDate());
snapshot.setBuildDate(new Date());
+ snapshot.setVersion(project.getAnalysisVersion());
}
return snapshot;
}
--- /dev/null
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.batch.components;
+
+import org.junit.Test;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.database.model.Snapshot;
+import org.sonar.jpa.test.AbstractDbUnitTestCase;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class PastSnapshotFinderByPreviousVersionTest extends AbstractDbUnitTestCase {
+
+ @Test
+ public void shouldFindByPreviousVersion() {
+ setupData("shared");
+ PastSnapshotFinderByPreviousVersion finder = new PastSnapshotFinderByPreviousVersion(getSession());
+
+ Snapshot currentProjectSnapshot = getSession().getSingleResult(Snapshot.class, "id", 1010);
+ PastSnapshot foundSnapshot = finder.findByPreviousVersion(currentProjectSnapshot);
+ assertThat(foundSnapshot.getProjectSnapshotId()).isEqualTo(1009);
+ assertThat(foundSnapshot.getMode()).isEqualTo(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_VERSION);
+ assertThat(foundSnapshot.getModeParameter()).isEqualTo("1.1");
+
+ // and test also another version to verify that unprocessed snapshots are ignored
+ currentProjectSnapshot = getSession().getSingleResult(Snapshot.class, "id", 1009);
+ assertThat(finder.findByPreviousVersion(currentProjectSnapshot).getProjectSnapshotId()).isEqualTo(1003);
+ }
+
+}
assertThat(finder.findByVersion(currentProjectSnapshot, "1.1").getProjectSnapshotId()).isEqualTo(1009);
}
- /**
- * Revert SONAR-3407
- */
- @Test
- public void doNotFailIfUnknownVersion() {
- setupData("shared");
-
- Snapshot currentProjectSnapshot = getSession().getSingleResult(Snapshot.class, "id", 1010);
- PastSnapshotFinderByVersion finder = new PastSnapshotFinderByVersion(getSession());
-
- PastSnapshot pastSnapshot = finder.findByVersion(currentProjectSnapshot, "0.1.2");
- assertThat(pastSnapshot).isNotNull();
- assertThat(pastSnapshot.getDate()).isNull();
- }
}
*/
package org.sonar.batch.components;
+import org.apache.commons.configuration.BaseConfiguration;
+import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentMatcher;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import org.sonar.api.CoreProperties;
import org.sonar.api.database.model.Snapshot;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.argThat;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class PastSnapshotFinderTest {
+ @Mock
private PastSnapshotFinderByDays finderByDays;
+ @Mock
private PastSnapshotFinderByDate finderByDate;
+ @Mock
private PastSnapshotFinderByVersion finderByVersion;
+ @Mock
private PastSnapshotFinderByPreviousAnalysis finderByPreviousAnalysis;
+ @Mock
+ private PastSnapshotFinderByPreviousVersion finderByPreviousVersion;
+
private PastSnapshotFinder finder;
@Before
public void initFinders() {
- finderByDays = mock(PastSnapshotFinderByDays.class);
- finderByDate = mock(PastSnapshotFinderByDate.class);
- finderByVersion = mock(PastSnapshotFinderByVersion.class);
- finderByPreviousAnalysis = mock(PastSnapshotFinderByPreviousAnalysis.class);
- finder = new PastSnapshotFinder(finderByDays, finderByVersion, finderByDate, finderByPreviousAnalysis);
+ MockitoAnnotations.initMocks(this);
+
+ finder = new PastSnapshotFinder(finderByDays, finderByVersion, finderByDate, finderByPreviousAnalysis, finderByPreviousVersion);
+ }
+
+ @Test
+ public void shouldFind() {
+ Configuration conf = new BaseConfiguration();
+ conf.addProperty("sonar.timemachine.period5", "1.2");
+
+ when(finderByVersion.findByVersion(null, "1.2")).thenReturn(new PastSnapshot("version", new Date(), new Snapshot()));
+
+ PastSnapshot variationSnapshot = finder.find(null, conf, 5);
+
+ verify(finderByVersion).findByVersion(null, "1.2");
+ assertThat(variationSnapshot.getIndex(), is(5));
+ assertThat(variationSnapshot.getMode(), is("version"));
+ assertThat(variationSnapshot.getProjectSnapshot(), not(nullValue()));
}
@Test
assertNull(variationSnapshot);
}
+ @Test
+ public void shouldFindByPreviousVersion() throws ParseException {
+ final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
+ final Date date = format.parse("2010-05-18");
+ Snapshot snapshot = new Snapshot();
+ snapshot.setCreatedAt(date);
+ when(finderByPreviousVersion.findByPreviousVersion(null)).thenReturn(new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_VERSION, date, snapshot));
+
+ PastSnapshot variationSnapshot = finder.find(null, 2, CoreProperties.TIMEMACHINE_MODE_PREVIOUS_VERSION);
+
+ verify(finderByPreviousVersion).findByPreviousVersion(null);
+ assertThat(variationSnapshot.getIndex(), is(2));
+ assertThat(variationSnapshot.getMode(), is(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_VERSION));
+ assertThat(variationSnapshot.getProjectSnapshot(), not(nullValue()));
+ }
+
@Test
public void shouldFindByVersion() {
when(finderByVersion.findByVersion(null, "1.2")).thenReturn(new PastSnapshot("version", new Date(), new Snapshot()));
--- /dev/null
+<dataset>
+
+ <projects long_name="[null]" id="1" scope="PRJ" qualifier="TRK" kee="project" name="project"
+ root_id="[null]"
+ description="[null]"
+ enabled="true" language="java" copy_resource_id="[null]" person_id="[null]"/>
+
+
+ <!-- version 1.1-SNAPSHOT -->
+ <snapshots purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]" id="1000"
+ project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
+ scope="PRJ" qualifier="TRK" created_at="2008-11-01 13:58:00.00" build_date="2008-11-01 13:58:00.00" version="1.1-SNAPSHOT" path=""
+ status="P" islast="false" depth="0" />
+
+
+ <!-- version 1.1-SNAPSHOT -->
+ <snapshots purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]" id="1003"
+ project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
+ scope="PRJ" qualifier="TRK" created_at="2008-11-02 13:58:00.00" build_date="2008-11-02 13:58:00.00" version="1.1-SNAPSHOT" path=""
+ status="P" islast="true" depth="0" />
+
+
+ <!-- unprocessed version 1.1 (to ignore) -->
+ <snapshots purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]" id="1006"
+ project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
+ scope="PRJ" qualifier="TRK" created_at="2008-11-03 13:58:00.00" build_date="2008-11-03 13:58:00.00" version="1.1" path=""
+ status="U" islast="false" depth="0" />
+
+
+ <!-- version 1.1 -->
+ <snapshots purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]" id="1009"
+ project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
+ scope="PRJ" qualifier="TRK" created_at="2008-11-04 13:58:00.00" build_date="2008-11-04 13:58:00.00" version="1.1" path=""
+ status="P" islast="false" depth="0" />
+
+ <!-- current analysis -->
+ <snapshots purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]" id="1010"
+ project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
+ scope="PRJ" qualifier="TRK" created_at="2008-11-05 13:58:00.00" build_date="2008-11-05 13:58:00.00" version="1.2-SNAPSHOT" path=""
+ status="U" islast="false" depth="0" />
+
+</dataset>
\ No newline at end of file
*/
String ENCRYPTION_SECRET_KEY_PATH = "sonar.secretKeyPath";
-
/**
* @since 2.11
*/
*/
String CATEGORY_DIFFERENTIAL_VIEWS = "differentialViews";
-
/* Global settings */
String SONAR_HOME = "SONAR_HOME";
String PROJECT_BRANCH_PROPERTY = "sonar.branch";
String TIMEMACHINE_MODE_DATE = "date";
String TIMEMACHINE_MODE_VERSION = "version";
String TIMEMACHINE_MODE_DAYS = "days";
+ String TIMEMACHINE_MODE_PREVIOUS_VERSION = "previous_version";
String TIMEMACHINE_DEFAULT_PERIOD_1 = TIMEMACHINE_MODE_PREVIOUS_ANALYSIS;
String TIMEMACHINE_DEFAULT_PERIOD_2 = "5";
String TIMEMACHINE_DEFAULT_PERIOD_3 = "30";
else
label = message('since_previous_analysis')
end
+ elsif mode=='previous_version'
+ unless mode_param.nil?
+ label = message('since_previous_version_detailed', :params => mode_param.to_s)
+ else
+ label = message('since_previous_version')
+ end
elsif mode=='date'
label = message('since_x', :params => date.strftime("%Y %b %d").to_s)
end
include WidgetPropertiesHelper
include MetricsHelper
include FiltersHelper
-
def dashboard_action(action_name, opts={})
if @resource
{ :action => action_name, :did => @dashboard.id, :id => @resource.id }.merge!(opts)
end
def formatted_value(measure, default='')
- measure ? measure.formatted_value : default
+ measure ? measure.formatted_value : default
end
def measure(metric_key)
- @snapshot.measure(metric_key)
+ @snapshot.measure(metric_key)
end
def period_select_options(snapshot, index)
- label=period_label(snapshot, index)
- if label
- selected=(params[:period]==index.to_s ? 'selected' : '')
- "<option value='#{index}' #{selected}>Δ #{label}</option>"
- else
- nil
- end
+ label=period_label(snapshot, index)
+ if label
+ selected=(params[:period]==index.to_s ? 'selected' : '')
+ "<option value='#{index}' #{selected}>Δ #{label}</option>"
+ else
+ nil
+ end
end
def violation_period_select_options(snapshot, index)
- return nil if snapshot.nil? || snapshot.project_snapshot.nil?
- mode=snapshot.project_snapshot.send "period#{index}_mode"
- mode_param=snapshot.project_snapshot.send "period#{index}_param"
- date=snapshot.project_snapshot.send "period#{index}_date"
-
- if mode
- if mode=='days'
- label = message('added_over_x_days', :params => mode_param.to_s)
- elsif mode=='version'
- label = message('added_since_version', :params => mode_param.to_s)
- elsif mode=='previous_analysis'
- if !date.nil?
- label = message('added_since_previous_analysis_detailed', :params => date.strftime("%Y %b. %d").to_s)
- else
- label = message('added_since_previous_analysis')
- end
- elsif mode=='date'
- label = message('added_since', :params => date.strftime("%Y %b %d").to_s)
- end
- if label
- selected=(params[:period]==index.to_s ? 'selected' : '')
- "<option value='#{index}' #{selected}>#{label}</option>"
- end
- else
- nil
- end
+ return nil if snapshot.nil? || snapshot.project_snapshot.nil?
+ mode=snapshot.project_snapshot.send "period#{index}_mode"
+ mode_param=snapshot.project_snapshot.send "period#{index}_param"
+ date=snapshot.project_snapshot.send "period#{index}_date"
+
+ if mode
+ if mode=='days'
+ label = message('added_over_x_days', :params => mode_param.to_s)
+ elsif mode=='version'
+ label = message('added_since_version', :params => mode_param.to_s)
+ elsif mode=='previous_analysis'
+ if !date.nil?
+ label = message('added_since_previous_analysis_detailed', :params => date.strftime("%Y %b. %d").to_s)
+ else
+ label = message('added_since_previous_analysis')
+ end
+ elsif mode=='previous_version'
+ unless mode_param.nil?
+ label = message('added_since_previous_version_detailed', :params => mode_param.to_s)
+ else
+ label = message('added_since_previous_version')
+ end
+ elsif mode=='date'
+ label = message('added_since', :params => date.strftime("%Y %b %d").to_s)
+ end
+ if label
+ selected=(params[:period]==index.to_s ? 'selected' : '')
+ "<option value='#{index}' #{selected}>#{label}</option>"
+ end
+ else
+ nil
+ end
end
def measure_or_variation_value(measure)
- if measure
- @period_index ? measure.variation(@period_index) : measure.value
- else
- nil
- end
+ if measure
+ @period_index ? measure.variation(@period_index) : measure.value
+ else
+ nil
+ end
end
def switch_to_widget_resource(widget)
def period_name(property)
if property=='previous_analysis'
message('delta_since_previous_analysis')
+ elsif property=='previous_version'
+ message('delta_since_previous_version')
elsif property =~ /^[\d]+(\.[\d]+){0,1}$/
# is integer
message('delta_over_x_days', :params => property)