extensions.add(ReferenceAnalysis.class);
// time machine
+ extensions.add(TimeMachineConfiguration.class);
extensions.add(TendencyDecorator.class);
extensions.add(VariationDecorator.class);
extensions.add(ViolationTrackingDecorator.class);
import org.sonar.api.resources.Scopes;
import org.sonar.api.utils.KeyValueFormat;
import org.sonar.batch.components.PastSnapshot;
-import org.sonar.batch.components.TimeMachineConfiguration;
import org.sonar.core.NotDryRun;
import java.util.Arrays;
import org.sonar.api.rules.RulePriority;
import org.sonar.api.rules.Violation;
import org.sonar.batch.components.PastSnapshot;
-import org.sonar.batch.components.TimeMachineConfiguration;
import org.sonar.core.NotDryRun;
import java.util.*;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
import org.sonar.api.resources.Scopes;
-import org.sonar.batch.components.TimeMachineConfiguration;
import org.sonar.core.NotDryRun;
import java.util.List;
--- /dev/null
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 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.plugins.core.timemachine;
+
+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.BatchExtension;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.database.DatabaseSession;
+import org.sonar.api.database.model.Snapshot;
+import org.sonar.api.resources.Project;
+import org.sonar.api.resources.Qualifiers;
+import org.sonar.api.utils.Logs;
+import org.sonar.batch.components.PastSnapshot;
+import org.sonar.batch.components.PastSnapshotFinder;
+
+import javax.persistence.Query;
+import java.util.Collections;
+import java.util.List;
+
+public class TimeMachineConfiguration implements BatchExtension {
+
+ private static final int NUMBER_OF_VARIATION_SNAPSHOTS = 5;
+
+ private Project project;
+ private final Configuration configuration;
+ private List<PastSnapshot> projectPastSnapshots;
+ private DatabaseSession session;
+
+ public TimeMachineConfiguration(DatabaseSession session, Project project, Configuration configuration, PastSnapshotFinder pastSnapshotFinder) {
+ this.session = session;
+ this.project = project;
+ this.configuration = configuration;
+ initPastSnapshots(pastSnapshotFinder);
+ }
+
+ private void initPastSnapshots(PastSnapshotFinder pastSnapshotFinder) {
+ Snapshot projectSnapshot = buildProjectSnapshot();
+
+ projectPastSnapshots = Lists.newLinkedList();
+ if (projectSnapshot != null) {
+ for (int index = 1; index <= NUMBER_OF_VARIATION_SNAPSHOTS; index++) {
+ PastSnapshot pastSnapshot = pastSnapshotFinder.find(projectSnapshot, configuration, index);
+ if (pastSnapshot != null) {
+ log(pastSnapshot);
+ projectPastSnapshots.add(pastSnapshot);
+ }
+ }
+ }
+ }
+
+ private Snapshot buildProjectSnapshot() {
+ Query query = session.createNativeQuery("select p.id from projects p where p.kee=:resourceKey and p.qualifier<>:lib and p.enabled=:enabled");
+ query.setParameter("resourceKey", project.getKey());
+ query.setParameter("lib", Qualifiers.LIBRARY);
+ query.setParameter("enabled", Boolean.TRUE);
+
+ Snapshot snapshot = null;
+ Number projectId = session.getSingleResult(query, null);
+ if (projectId != null) {
+ snapshot = new Snapshot();
+ snapshot.setResourceId(projectId.intValue());
+ snapshot.setCreatedAt(project.getAnalysisDate());
+ }
+ return snapshot;
+ }
+
+ private void log(PastSnapshot pastSnapshot) {
+ String qualifier = pastSnapshot.getQualifier();
+ // hack to avoid too many logs when the views plugin is installed
+ if (StringUtils.equals(Qualifiers.VIEW, qualifier) || StringUtils.equals(Qualifiers.SUBVIEW, qualifier)) {
+ LoggerFactory.getLogger(getClass()).debug(pastSnapshot.toString());
+ } else {
+ Logs.INFO.info(pastSnapshot.toString());
+ }
+ }
+
+ public boolean skipTendencies() {
+ return configuration.getBoolean(CoreProperties.SKIP_TENDENCIES_PROPERTY, CoreProperties.SKIP_TENDENCIES_DEFAULT_VALUE);
+ }
+
+ public int getTendencyPeriodInDays() {
+ return configuration.getInt(CoreProperties.CORE_TENDENCY_DEPTH_PROPERTY, CoreProperties.CORE_TENDENCY_DEPTH_DEFAULT_VALUE);
+ }
+
+ public List<PastSnapshot> getProjectPastSnapshots() {
+ return projectPastSnapshots;
+ }
+
+ public boolean isFileVariationEnabled() {
+ return configuration.getBoolean("sonar.enableFileVariation", Boolean.FALSE);
+ }
+}
import org.sonar.api.resources.Resource;
import org.sonar.api.resources.ResourceUtils;
import org.sonar.batch.components.PastSnapshot;
-import org.sonar.batch.components.TimeMachineConfiguration;
import org.sonar.core.NotDryRun;
import java.util.List;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.lang.StringUtils;
+import org.sonar.api.CoreProperties;
import org.sonar.api.batch.*;
import org.sonar.api.measures.*;
import org.sonar.api.resources.Project;
+import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.Resource;
import org.sonar.api.resources.Scopes;
import org.sonar.batch.components.PastMeasuresLoader;
import org.sonar.batch.components.PastSnapshot;
-import org.sonar.batch.components.TimeMachineConfiguration;
-import org.sonar.core.NotDryRun;
import java.util.Collection;
import java.util.List;
import java.util.Map;
-@NotDryRun
@DependedUpon(DecoratorBarriers.END_OF_TIME_MACHINE)
public class VariationDecorator implements Decorator {
private List<PastSnapshot> projectPastSnapshots;
private MetricFinder metricFinder;
private PastMeasuresLoader pastMeasuresLoader;
+ private final boolean enabledFileVariation;
public VariationDecorator(PastMeasuresLoader pastMeasuresLoader, MetricFinder metricFinder, TimeMachineConfiguration configuration) {
- this(pastMeasuresLoader, metricFinder, configuration.getProjectPastSnapshots());
+ this(pastMeasuresLoader, metricFinder, configuration.getProjectPastSnapshots(), configuration.isFileVariationEnabled());
}
- public VariationDecorator(PastMeasuresLoader pastMeasuresLoader, MetricFinder metricFinder, List<PastSnapshot> projectPastSnapshots) {
+
+ VariationDecorator(PastMeasuresLoader pastMeasuresLoader, MetricFinder metricFinder, List<PastSnapshot> projectPastSnapshots, boolean enabledFileVariation) {
this.pastMeasuresLoader = pastMeasuresLoader;
this.projectPastSnapshots = projectPastSnapshots;
this.metricFinder = metricFinder;
+ this.enabledFileVariation = enabledFileVariation;
}
public boolean shouldExecuteOnProject(Project project) {
}
public void decorate(Resource resource, DecoratorContext context) {
- if (shouldCalculateVariations(resource)) {
- for (PastSnapshot projectPastSnapshot : projectPastSnapshots) {
- calculateVariation(resource, context, projectPastSnapshot);
+ for (PastSnapshot projectPastSnapshot : projectPastSnapshots) {
+ if (shouldComputeVariation(projectPastSnapshot.getMode(), resource)) {
+ computeVariation(resource, context, projectPastSnapshot);
}
}
}
- static boolean shouldCalculateVariations(Resource resource) {
+ boolean shouldComputeVariation(String variationMode, Resource resource) {
+ if (Scopes.FILE.equals(resource.getScope()) && !Qualifiers.UNIT_TEST_FILE.equals(resource.getQualifier())) {
+ return enabledFileVariation && StringUtils.equals(variationMode, CoreProperties.TIMEMACHINE_MODE_PREVIOUS_ANALYSIS);
+ }
+
// measures on files are currently purged, so past measures are not available on files
return StringUtils.equals(Scopes.PROJECT, resource.getScope()) || StringUtils.equals(Scopes.DIRECTORY, resource.getScope());
}
- private void calculateVariation(Resource resource, DecoratorContext context, PastSnapshot pastSnapshot) {
+ private void computeVariation(Resource resource, DecoratorContext context, PastSnapshot pastSnapshot) {
List<Object[]> pastMeasures = pastMeasuresLoader.getPastMeasures(resource, pastSnapshot);
compareWithPastMeasures(context, pastSnapshot.getIndex(), pastMeasures);
}
import org.sonar.api.rules.RulePriority;
import org.sonar.api.rules.Violation;
import org.sonar.batch.components.PastSnapshot;
-import org.sonar.batch.components.TimeMachineConfiguration;
import java.util.Arrays;
import java.util.Date;
import org.sonar.api.measures.MetricFinder;
import org.sonar.api.resources.JavaPackage;
import org.sonar.api.resources.Project;
-import org.sonar.batch.components.TimeMachineConfiguration;
import java.text.ParseException;
import java.text.SimpleDateFormat;
}
private TimeMachineConfiguration newConf() {
- return new TimeMachineConfiguration(new PropertiesConfiguration());
+ TimeMachineConfiguration configuration = mock(TimeMachineConfiguration.class);
+ when(configuration.getTendencyPeriodInDays()).thenReturn(30);
+ return configuration;
}
@Test
import org.sonar.api.database.model.Snapshot;
import org.sonar.api.utils.DateUtils;
import org.sonar.batch.components.PastSnapshot;
-import org.sonar.batch.components.TimeMachineConfiguration;
import org.sonar.jpa.test.AbstractDbUnitTestCase;
import java.text.ParseException;
package org.sonar.plugins.core.timemachine;
import org.apache.commons.configuration.PropertiesConfiguration;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
import org.junit.Test;
import org.sonar.api.CoreProperties;
import org.sonar.api.database.model.Snapshot;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.batch.components.PastSnapshot;
+import org.sonar.api.resources.Project;
import org.sonar.batch.components.PastSnapshotFinder;
-import org.sonar.batch.components.TimeMachineConfiguration;
import org.sonar.jpa.test.AbstractDbUnitTestCase;
-import java.text.ParseException;
-import java.util.Date;
-
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.*;
public class TimeMachineConfigurationTest extends AbstractDbUnitTestCase {
public void shouldSkipTendencies() {
PropertiesConfiguration conf = new PropertiesConfiguration();
conf.setProperty(CoreProperties.SKIP_TENDENCIES_PROPERTY, true);
- assertThat(new TimeMachineConfiguration(conf).skipTendencies(), is(true));
+ assertThat(new TimeMachineConfiguration(getSession(), new Project("my:project"), conf, mock(PastSnapshotFinder.class)).skipTendencies(), is(true));
}
@Test
public void shouldNotSkipTendenciesByDefault() {
PropertiesConfiguration conf = new PropertiesConfiguration();
- assertThat(new TimeMachineConfiguration(conf).skipTendencies(), is(false));
+ assertThat(new TimeMachineConfiguration(getSession(), new Project("my:project"), conf, mock(PastSnapshotFinder.class)).skipTendencies(), is(false));
}
@Test
- public void shouldInitPastSnapshots() throws ParseException {
+ public void shouldInitPastSnapshots() {
+ setupData("shared");
PropertiesConfiguration conf = new PropertiesConfiguration();
PastSnapshotFinder pastSnapshotFinder = mock(PastSnapshotFinder.class);
- when(pastSnapshotFinder.find(null, conf, 1)).thenReturn(new PastSnapshot("days", new Date(), newSnapshot("2010-10-15")));
- when(pastSnapshotFinder.find(null, conf, 3)).thenReturn(new PastSnapshot("days", new Date(), newSnapshot("2010-10-13")));
- TimeMachineConfiguration timeMachineConfiguration = new TimeMachineConfiguration(conf, pastSnapshotFinder, null);
+ new TimeMachineConfiguration(getSession(), new Project("my:project"), conf, pastSnapshotFinder);
- verify(pastSnapshotFinder).find(null, conf, 1);
- verify(pastSnapshotFinder).find(null, conf, 2);
- verify(pastSnapshotFinder).find(null, conf, 3);
+ verify(pastSnapshotFinder).find(argThat(new BaseMatcher<Snapshot>() {
+ public boolean matches(Object o) {
+ return ((Snapshot) o).getResourceId() == 2 /* see database in shared.xml */;
+ }
- assertThat(timeMachineConfiguration.getProjectPastSnapshots().size(), is(2));
+ public void describeTo(Description description) {
+ }
+ }), eq(conf), eq(1));
}
- private Snapshot newSnapshot(String date) throws ParseException {
- return new Snapshot().setCreatedAt(DateUtils.parseDate(date));
+ @Test
+ public void shouldNotInitPastSnapshotsIfFirstAnalysis() {
+ setupData("shared");
+ PropertiesConfiguration conf = new PropertiesConfiguration();
+ PastSnapshotFinder pastSnapshotFinder = mock(PastSnapshotFinder.class);
+
+ new TimeMachineConfiguration(getSession(), new Project("new:project"), conf, pastSnapshotFinder);
+
+ verifyZeroInteractions(pastSnapshotFinder);
}
}
import org.junit.Test;
import org.mockito.Matchers;
+import org.sonar.api.CoreProperties;
import org.sonar.api.batch.DecoratorContext;
import org.sonar.api.database.model.MeasureModel;
-import org.sonar.api.database.model.Snapshot;
import org.sonar.api.measures.Measure;
import org.sonar.api.measures.MeasuresFilter;
import org.sonar.api.measures.Metric;
public static final Metric COVERAGE = new Metric("coverage").setId(COVERAGE_ID);
@Test
- public void shouldNotCalculateVariationsOnFiles() {
- assertThat(VariationDecorator.shouldCalculateVariations(new Project("foo")), is(true));
- assertThat(VariationDecorator.shouldCalculateVariations(new JavaPackage("org.foo")), is(true));
- assertThat(VariationDecorator.shouldCalculateVariations(new Directory("org/foo")), is(true));
-
- assertThat(VariationDecorator.shouldCalculateVariations(new JavaFile("org.foo.Bar")), is(false));
- assertThat(VariationDecorator.shouldCalculateVariations(new JavaFile("org.foo.Bar", true)), is(false));
- assertThat(VariationDecorator.shouldCalculateVariations(new File("org/foo/Bar.php")), is(false));
+ public void shouldComputeVariations() {
+ TimeMachineConfiguration conf = mock(TimeMachineConfiguration.class);
+ when(conf.isFileVariationEnabled()).thenReturn(false);
+ VariationDecorator decorator = new VariationDecorator(mock(PastMeasuresLoader.class), mock(MetricFinder.class), conf);
+
+ assertThat(decorator.shouldComputeVariation(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_ANALYSIS, new Project("foo")), is(true));
+ assertThat(decorator.shouldComputeVariation(CoreProperties.TIMEMACHINE_MODE_DATE, new Project("foo")), is(true));
+ }
+
+ @Test
+ public void shouldNotComputeFileVariations() {
+ TimeMachineConfiguration conf = mock(TimeMachineConfiguration.class);
+ when(conf.isFileVariationEnabled()).thenReturn(false);
+ VariationDecorator decorator = new VariationDecorator(mock(PastMeasuresLoader.class), mock(MetricFinder.class), conf);
+
+ assertThat(decorator.shouldComputeVariation(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_ANALYSIS, new JavaFile("org.foo.Bar")), is(false));
+ assertThat(decorator.shouldComputeVariation(CoreProperties.TIMEMACHINE_MODE_DATE, new JavaFile("org.foo.Bar")), is(false));
+ assertThat(decorator.shouldComputeVariation(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_ANALYSIS, new File("org/foo/Bar.php")), is(false));
+ assertThat(decorator.shouldComputeVariation(CoreProperties.TIMEMACHINE_MODE_DATE, new File("org/foo/Bar.php")), is(false));
+ }
+
+ @Test
+ public void shouldComputeFileVariationsIfExplictlyEnabled() {
+ TimeMachineConfiguration conf = mock(TimeMachineConfiguration.class);
+ when(conf.isFileVariationEnabled()).thenReturn(true);
+ VariationDecorator decorator = new VariationDecorator(mock(PastMeasuresLoader.class), mock(MetricFinder.class), conf);
+
+ // only for variation with reference analysis
+ assertThat(decorator.shouldComputeVariation(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_ANALYSIS, new JavaFile("org.foo.Bar")), is(true));
+ assertThat(decorator.shouldComputeVariation(CoreProperties.TIMEMACHINE_MODE_DATE, new JavaFile("org.foo.Bar")), is(false));
+ assertThat(decorator.shouldComputeVariation(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_ANALYSIS, new File("org/foo/Bar.php")), is(true));
+ assertThat(decorator.shouldComputeVariation(CoreProperties.TIMEMACHINE_MODE_DATE, new File("org/foo/Bar.php")), is(false));
+
+ // no side-effect on other resources
+ assertThat(decorator.shouldComputeVariation(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_ANALYSIS, new Project("foo")), is(true));
}
@Test
Measure currentCoverage = newMeasure(COVERAGE, 80.0);
when(context.getMeasures(Matchers.<MeasuresFilter>anyObject())).thenReturn(Arrays.asList(currentNcloc, currentCoverage));
- VariationDecorator decorator = new VariationDecorator(pastMeasuresLoader, mock(MetricFinder.class),
- Arrays.asList(pastSnapshot1, pastSnapshot3));
+ VariationDecorator decorator = new VariationDecorator(pastMeasuresLoader, mock(MetricFinder.class), Arrays.asList(pastSnapshot1, pastSnapshot3), false);
decorator.decorate(javaPackage, context);
// context updated for each variation : 2 times for ncloc and 1 time for coverage
--- /dev/null
+<dataset>
+
+ <projects long_name="[null]" id="1" scope="PRJ" kee="my:project" qualifier="LIB" name="my project as lib"
+ root_id="[null]" description="[null]" enabled="true" profile_id="[null]" language="java" copy_resource_id="[null]"/>
+
+ <projects long_name="[null]" id="2" scope="PRJ" kee="my:project" qualifier="TRK" name="my project"
+ root_id="[null]" description="[null]" enabled="true" profile_id="[null]" language="java" copy_resource_id="[null]"/>
+
+ <projects long_name="[null]" id="3" scope="DIR" kee="my:project:path/to/dir" qualifier="TRK" name="my dir"
+ root_id="2" description="[null]" enabled="true" profile_id="[null]" language="java" copy_resource_id="[null]"/>
+
+</dataset>
import org.sonar.api.rules.DefaultRulesManager;
import org.sonar.api.utils.SonarException;
import org.sonar.batch.*;
-import org.sonar.batch.components.TimeMachineConfiguration;
import org.sonar.batch.events.EventBus;
import org.sonar.batch.index.DefaultIndex;
import org.sonar.batch.index.DefaultResourcePersister;
if (!dryRun) {
// the Snapshot component will be removed when asynchronous measures are improved (required for AsynchronousMeasureSensor)
addComponent(getComponent(DefaultResourcePersister.class).getSnapshot(project));
- addComponent(TimeMachineConfiguration.class);
}
addComponent(org.sonar.api.database.daos.MeasuresDao.class);
addComponent(ProfilesDao.class);
import org.apache.commons.lang.ObjectUtils;
import org.sonar.api.BatchExtension;
import org.sonar.api.database.DatabaseSession;
+import org.sonar.api.database.model.ResourceModel;
import org.sonar.api.database.model.Snapshot;
import org.sonar.api.measures.Metric;
import org.sonar.api.measures.MetricFinder;
+import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.Resource;
import java.util.Collection;
}
public List<Object[]> getPastMeasures(Resource resource, PastSnapshot projectPastSnapshot) {
- if (isPersisted(resource) && projectPastSnapshot != null && projectPastSnapshot.getProjectSnapshot()!=null) {
- return getPastMeasures(resource.getId(), projectPastSnapshot.getProjectSnapshot());
+ if (projectPastSnapshot != null && projectPastSnapshot.getProjectSnapshot()!=null) {
+ return getPastMeasures(resource.getEffectiveKey(), projectPastSnapshot.getProjectSnapshot());
}
return Collections.emptyList();
}
- public List<Object[]> getPastMeasures(int resourceId, Snapshot projectSnapshot) {
+ public List<Object[]> getPastMeasures(String resourceKey, Snapshot projectPastSnapshot) {
String sql = "select m.metric_id, m.characteristic_id, m.value from project_measures m, snapshots s" +
" where m.snapshot_id=s.id and m.metric_id in (:metricIds) and m.rule_id is null and m.rule_priority is null " +
- " and (s.root_snapshot_id=:rootSnapshotId or s.id=:rootSnapshotId) and s.project_id=:resourceId and s.status=:status";
+ " and (s.root_snapshot_id=:rootSnapshotId or s.id=:rootSnapshotId) and s.status=:status and s.project_id=(select p.id from projects p where p.kee=:resourceKey and p.qualifier<>:lib)";
return session.createNativeQuery(sql)
.setParameter("metricIds", metricByIds.keySet())
- .setParameter("rootSnapshotId", ObjectUtils.defaultIfNull(projectSnapshot.getRootId(), projectSnapshot.getId()))
- .setParameter("resourceId", resourceId)
+ .setParameter("rootSnapshotId", ObjectUtils.defaultIfNull(projectPastSnapshot.getRootId(), projectPastSnapshot.getId()))
+ .setParameter("resourceKey", resourceKey)
+ .setParameter("lib", Qualifiers.LIBRARY)
.setParameter("status", Snapshot.STATUS_PROCESSED)
.getResultList();
}
- private boolean isPersisted(Resource resource) {
- return resource.getId() != null;
- }
-
public static int getMetricId(Object[] row) {
// can be BigDecimal on Oracle
return ((Number)row[0]).intValue();
@Override
public String toString() {
- if (StringUtils.equals(mode, PastSnapshotFinderByVersion.MODE)) {
+ if (StringUtils.equals(mode, CoreProperties.TIMEMACHINE_MODE_VERSION)) {
String label = String.format("Compare to version %s", modeParameter);
if (getTargetDate() != null) {
label += String.format(" (%s)", DateUtils.formatDate(getTargetDate()));
}
return label;
}
- if (StringUtils.equals(mode, PastSnapshotFinderByDays.MODE)) {
+ if (StringUtils.equals(mode, CoreProperties.TIMEMACHINE_MODE_DAYS)) {
String label = String.format("Compare over %s days (%s", modeParameter, DateUtils.formatDate(getTargetDate()));
if (isRelatedToSnapshot()) {
label += ", analysis of " + getDate();
}
return label;
}
- if (StringUtils.equals(mode, PastSnapshotFinderByDate.MODE)) {
+ if (StringUtils.equals(mode, CoreProperties.TIMEMACHINE_MODE_DATE)) {
String label = "Compare to date " + DateUtils.formatDate(getTargetDate());
if (isRelatedToSnapshot()) {
label += String.format(" (analysis of %s)", DateUtils.formatDate(getDate()));
return conf.getString(CoreProperties.TIMEMACHINE_PERIOD_PREFIX + index, defaultValue);
}
+ public PastSnapshot findPreviousAnalysis(Snapshot projectSnapshot) {
+ return finderByPreviousAnalysis.findByPreviousAnalysis(projectSnapshot);
+ }
+
public PastSnapshot find(Snapshot projectSnapshot, int index, String property) {
if (StringUtils.isBlank(property)) {
return null;
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;
public class PastSnapshotFinderByDate implements BatchExtension {
- public static final String MODE = "date";
-
private DatabaseSession session;
public PastSnapshotFinderByDate(DatabaseSession session) {
snapshot = findSnapshot(projectSnapshot, date);
}
SimpleDateFormat format = new SimpleDateFormat(DateUtils.DATE_FORMAT);
- return new PastSnapshot(MODE, date, snapshot).setModeParameter(format.format(date));
+ return new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_DATE, date, snapshot).setModeParameter(format.format(date));
}
import org.apache.commons.lang.time.DateUtils;
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;
public class PastSnapshotFinderByDays implements BatchExtension {
- public static final String MODE = "days";
-
private DatabaseSession session;
public PastSnapshotFinderByDays(DatabaseSession session) {
.getResultList();
Snapshot snapshot = getNearestToTarget(snapshots, targetDate);
- return new PastSnapshot(MODE, targetDate, snapshot).setModeParameter(String.valueOf(days));
+ return new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_DAYS, targetDate, snapshot).setModeParameter(String.valueOf(days));
}
static Snapshot getNearestToTarget(List<Snapshot> snapshots, Date currentDate, int distanceInDays) {
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;
public class PastSnapshotFinderByVersion implements BatchExtension {
- public static final String MODE = "version";
-
private DatabaseSession session;
public PastSnapshotFinderByVersion(DatabaseSession session) {
.getResultList();
if (snapshots.isEmpty()) {
- return new PastSnapshot(MODE);
+ return new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_VERSION);
}
Snapshot snapshot = snapshots.get(0);
Date targetDate = snapshot.getCreatedAt();
- return new PastSnapshot(MODE, targetDate, snapshot).setModeParameter(version);
+ return new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_VERSION, targetDate, snapshot).setModeParameter(version);
}
}
+++ /dev/null
-/*
- * Sonar, open source software quality management tool.
- * Copyright (C) 2008-2011 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 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.BatchExtension;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.database.model.Snapshot;
-import org.sonar.api.resources.Qualifiers;
-import org.sonar.api.utils.Logs;
-
-import java.util.Collections;
-import java.util.List;
-
-public class TimeMachineConfiguration implements BatchExtension {
-
- private static final int NUMBER_OF_VARIATION_SNAPSHOTS = 5;
-
- private final Configuration configuration;
- private List<PastSnapshot> projectPastSnapshots;
-
- public TimeMachineConfiguration(Configuration configuration, PastSnapshotFinder pastSnapshotFinder, Snapshot projectSnapshot) {
- this.configuration = configuration;
- initPastSnapshots(pastSnapshotFinder, projectSnapshot);
- }
-
- private void initPastSnapshots(PastSnapshotFinder pastSnapshotFinder, Snapshot projectSnapshot) {
- projectPastSnapshots = Lists.newLinkedList();
- for (int index = 1; index <= NUMBER_OF_VARIATION_SNAPSHOTS; index++) {
- PastSnapshot pastSnapshot = pastSnapshotFinder.find(projectSnapshot, configuration, index);
- if (pastSnapshot != null) {
- log(pastSnapshot);
- projectPastSnapshots.add(pastSnapshot);
- }
- }
- }
-
- private void log(PastSnapshot pastSnapshot) {
- String qualifier = pastSnapshot.getQualifier();
- // hack to avoid too many logs when the views plugin is installed
- if (StringUtils.equals(Qualifiers.VIEW, qualifier) || StringUtils.equals(Qualifiers.SUBVIEW, qualifier)) {
- LoggerFactory.getLogger(getClass()).debug(pastSnapshot.toString());
- } else {
- Logs.INFO.info(pastSnapshot.toString());
- }
- }
-
- public TimeMachineConfiguration(Configuration configuration) {
- this.configuration = configuration;
- this.projectPastSnapshots = Collections.emptyList();
- }
-
-
- public boolean skipTendencies() {
- return configuration.getBoolean(CoreProperties.SKIP_TENDENCIES_PROPERTY, CoreProperties.SKIP_TENDENCIES_DEFAULT_VALUE);
- }
-
- public int getTendencyPeriodInDays() {
- return configuration.getInt(CoreProperties.CORE_TENDENCY_DEPTH_PROPERTY, CoreProperties.CORE_TENDENCY_DEPTH_DEFAULT_VALUE);
- }
-
- public List<PastSnapshot> getProjectPastSnapshots() {
- return projectPastSnapshots;
- }
-}
package org.sonar.batch.components;
import org.junit.Test;
-import org.sonar.api.database.model.MeasureModel;
import org.sonar.api.database.model.Snapshot;
import org.sonar.api.measures.Metric;
-import org.sonar.batch.components.PastMeasuresLoader;
import org.sonar.jpa.test.AbstractDbUnitTestCase;
import java.util.Arrays;
public class PastMeasuresLoaderTest extends AbstractDbUnitTestCase {
private static final int PROJECT_SNAPSHOT_ID = 1000;
- private static final int PROJECT_ID = 1;
- private static final int FILE_ID = 3;
+ private static final String PROJECT_KEY = "project";
+ private static final String FILE_KEY = "project:org.foo.Bar";
@Test
public void shouldGetPastResourceMeasures() {
Snapshot projectSnapshot = getSession().getSingleResult(Snapshot.class, "id", PROJECT_SNAPSHOT_ID);
PastMeasuresLoader loader = new PastMeasuresLoader(getSession(), metrics);
- List<Object[]> measures = loader.getPastMeasures(FILE_ID, projectSnapshot);
+ List<Object[]> measures = loader.getPastMeasures(FILE_KEY, projectSnapshot);
assertThat(measures.size(), is(2));
Object[] pastMeasure = measures.get(0);
Snapshot projectSnapshot = getSession().getSingleResult(Snapshot.class, "id", PROJECT_SNAPSHOT_ID);
PastMeasuresLoader loader = new PastMeasuresLoader(getSession(), metrics);
- List<Object[]> measures = loader.getPastMeasures(PROJECT_ID, projectSnapshot);
+ List<Object[]> measures = loader.getPastMeasures(PROJECT_KEY, projectSnapshot);
assertThat(measures.size(), is(2));
Object[] pastMeasure = measures.get(0);
@Test
public void testToStringForVersion() {
- PastSnapshot pastSnapshot = new PastSnapshot(PastSnapshotFinderByVersion.MODE, new Date()).setModeParameter("2.3");
+ PastSnapshot pastSnapshot = new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_VERSION, new Date()).setModeParameter("2.3");
assertThat(pastSnapshot.toString(), startsWith("Compare to version 2.3"));
}
@Test
public void testToStringForVersionWithoutDate() {
- PastSnapshot pastSnapshot = new PastSnapshot(PastSnapshotFinderByVersion.MODE).setModeParameter("2.3");
+ PastSnapshot pastSnapshot = new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_VERSION).setModeParameter("2.3");
assertThat(pastSnapshot.toString(), equalTo("Compare to version 2.3"));
}
@Test
public void testToStringForNumberOfDays() {
- PastSnapshot pastSnapshot = new PastSnapshot(PastSnapshotFinderByDays.MODE, new Date()).setModeParameter("30");
+ PastSnapshot pastSnapshot = new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_DAYS, new Date()).setModeParameter("30");
assertThat(pastSnapshot.toString(), startsWith("Compare over 30 days ("));
}
@Test
public void testToStringForNumberOfDaysWithSnapshot() {
- PastSnapshot pastSnapshot = new PastSnapshot(PastSnapshotFinderByDays.MODE, new Date(), new Snapshot().setCreatedAt(new Date())).setModeParameter("30");
+ PastSnapshot pastSnapshot = new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_DAYS, new Date(), new Snapshot().setCreatedAt(new Date())).setModeParameter("30");
assertThat(pastSnapshot.toString(), startsWith("Compare over 30 days ("));
}
@Test
public void testToStringForDate() {
- PastSnapshot pastSnapshot = new PastSnapshot(PastSnapshotFinderByDate.MODE, new Date());
+ PastSnapshot pastSnapshot = new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_DATE, new Date());
assertThat(pastSnapshot.toString(), startsWith("Compare to date "));
}
@Test
public void testToStringForDateWithSnapshot() {
- PastSnapshot pastSnapshot = new PastSnapshot(PastSnapshotFinderByDate.MODE, new Date(), new Snapshot().setCreatedAt(new Date()));
+ PastSnapshot pastSnapshot = new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_DATE, new Date(), new Snapshot().setCreatedAt(new Date()));
assertThat(pastSnapshot.toString(), startsWith("Compare to date "));
}
/* Time machine periods */
String TIMEMACHINE_PERIOD_PREFIX = "sonar.timemachine.period";
String TIMEMACHINE_MODE_PREVIOUS_ANALYSIS = "previous_analysis";
+ String TIMEMACHINE_MODE_DATE = "date";
+ String TIMEMACHINE_MODE_VERSION = "version";
+ String TIMEMACHINE_MODE_DAYS = "days";
String TIMEMACHINE_DEFAULT_PERIOD_1 = TIMEMACHINE_MODE_PREVIOUS_ANALYSIS;
String TIMEMACHINE_DEFAULT_PERIOD_2 = "5";
String TIMEMACHINE_DEFAULT_PERIOD_3 = "30";
public Project(String key) {
setKey(key);
+ setEffectiveKey(key);
}
public Project(String key, String branch, String name) {
setKey(key);
this.name = name;
}
+ setEffectiveKey(getKey());
this.branch = branch;
}
return parent;
}
+
+
/**
* For internal use only.
*/
assertEquals(project1.hashCode(), project2.hashCode());
}
+ @Test
+ public void effectiveKeyShouldEqualKey() {
+ assertThat(new Project("my:project").getEffectiveKey(), is("my:project"));
+ }
+
@Test
public void createFromMavenIds() {
Project project = Project.createFromMavenIds("my", "artifact");