diff options
author | Simon Brandhof <simon.brandhof@gmail.com> | 2011-06-21 15:12:11 +0200 |
---|---|---|
committer | Simon Brandhof <simon.brandhof@gmail.com> | 2011-06-21 15:13:48 +0200 |
commit | 02fdeba8d5cea42b17f0e24bc1d0bdebd9c0d29b (patch) | |
tree | 56b6d7bb26a1b842577c75968269ad3ae9e976ef | |
parent | 09b9a9586fe2a3a82d79ea2e7c5f1cbe742c8ac5 (diff) | |
download | sonarqube-02fdeba8d5cea42b17f0e24bc1d0bdebd9c0d29b.tar.gz sonarqube-02fdeba8d5cea42b17f0e24bc1d0bdebd9c0d29b.zip |
SONAR-2505 support measure variations
25 files changed, 182 insertions, 99 deletions
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java index c14be8d3310..f3b72b9e0c1 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java @@ -217,6 +217,7 @@ public class CorePlugin extends SonarPlugin { extensions.add(ReferenceAnalysis.class); // time machine + extensions.add(TimeMachineConfiguration.class); extensions.add(TendencyDecorator.class); extensions.add(VariationDecorator.class); extensions.add(ViolationTrackingDecorator.class); diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewCoverageFileAnalyzer.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewCoverageFileAnalyzer.java index d44ffd056e1..666d89082b5 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewCoverageFileAnalyzer.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewCoverageFileAnalyzer.java @@ -32,7 +32,6 @@ import org.sonar.api.resources.Resource; 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; diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewViolationsDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewViolationsDecorator.java index 86a150e28cd..4e00eb4c99f 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewViolationsDecorator.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewViolationsDecorator.java @@ -31,7 +31,6 @@ import org.sonar.api.rules.Rule; 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.*; diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/TendencyDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/TendencyDecorator.java index ade65afb788..5a52622f9ec 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/TendencyDecorator.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/TendencyDecorator.java @@ -31,7 +31,6 @@ import org.sonar.api.measures.MetricFinder; 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; diff --git a/sonar-batch/src/main/java/org/sonar/batch/components/TimeMachineConfiguration.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/TimeMachineConfiguration.java index ff317f2b01a..0ef49a93ea6 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/components/TimeMachineConfiguration.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/TimeMachineConfiguration.java @@ -17,7 +17,7 @@ * 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; +package org.sonar.plugins.core.timemachine; import com.google.common.collect.Lists; import org.apache.commons.configuration.Configuration; @@ -25,10 +25,15 @@ 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; @@ -36,25 +41,49 @@ 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(Configuration configuration, PastSnapshotFinder pastSnapshotFinder, Snapshot projectSnapshot) { + public TimeMachineConfiguration(DatabaseSession session, Project project, Configuration configuration, PastSnapshotFinder pastSnapshotFinder) { + this.session = session; + this.project = project; this.configuration = configuration; - initPastSnapshots(pastSnapshotFinder, projectSnapshot); + initPastSnapshots(pastSnapshotFinder); } - private void initPastSnapshots(PastSnapshotFinder pastSnapshotFinder, Snapshot projectSnapshot) { + private void initPastSnapshots(PastSnapshotFinder pastSnapshotFinder) { + Snapshot projectSnapshot = buildProjectSnapshot(); + 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); + 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 @@ -65,12 +94,6 @@ public class TimeMachineConfiguration implements BatchExtension { } } - 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); } @@ -82,4 +105,8 @@ public class TimeMachineConfiguration implements BatchExtension { public List<PastSnapshot> getProjectPastSnapshots() { return projectPastSnapshots; } + + public boolean isFileVariationEnabled() { + return configuration.getBoolean("sonar.enableFileVariation", Boolean.FALSE); + } } diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/TimeMachineConfigurationPersister.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/TimeMachineConfigurationPersister.java index 889a9010d78..6021e9ef78c 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/TimeMachineConfigurationPersister.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/TimeMachineConfigurationPersister.java @@ -27,7 +27,6 @@ import org.sonar.api.resources.Project; 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; diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/VariationDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/VariationDecorator.java index 1fe3ec56cc1..5299904a13b 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/VariationDecorator.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/VariationDecorator.java @@ -22,36 +22,38 @@ package org.sonar.plugins.core.timemachine; 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) { @@ -64,19 +66,23 @@ public class VariationDecorator implements Decorator { } 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); } diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/NewViolationsDecoratorTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/NewViolationsDecoratorTest.java index 22a239811b3..b027004067b 100644 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/NewViolationsDecoratorTest.java +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/NewViolationsDecoratorTest.java @@ -38,7 +38,6 @@ import org.sonar.api.rules.Rule; 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; diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/TendencyDecoratorTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/TendencyDecoratorTest.java index 9fd3336ab0c..5999463ec21 100644 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/TendencyDecoratorTest.java +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/TendencyDecoratorTest.java @@ -29,7 +29,6 @@ import org.sonar.api.measures.Measure; 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; @@ -61,7 +60,9 @@ public class TendencyDecoratorTest { } private TimeMachineConfiguration newConf() { - return new TimeMachineConfiguration(new PropertiesConfiguration()); + TimeMachineConfiguration configuration = mock(TimeMachineConfiguration.class); + when(configuration.getTendencyPeriodInDays()).thenReturn(30); + return configuration; } @Test diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/TimeMachineConfigurationPersisterTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/TimeMachineConfigurationPersisterTest.java index afc51cf8969..21dcfefffec 100644 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/TimeMachineConfigurationPersisterTest.java +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/TimeMachineConfigurationPersisterTest.java @@ -23,7 +23,6 @@ import org.junit.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; diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/TimeMachineConfigurationTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/TimeMachineConfigurationTest.java index f1444bd6acc..dda4f1a77b8 100644 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/TimeMachineConfigurationTest.java +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/TimeMachineConfigurationTest.java @@ -20,20 +20,19 @@ 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 { @@ -42,32 +41,41 @@ 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); } } diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/VariationDecoratorTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/VariationDecoratorTest.java index ad4fd12459e..27c2fff471b 100644 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/VariationDecoratorTest.java +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/VariationDecoratorTest.java @@ -21,9 +21,9 @@ package org.sonar.plugins.core.timemachine; 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; @@ -50,14 +50,41 @@ public class VariationDecoratorTest extends AbstractDbUnitTestCase { 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 @@ -83,8 +110,7 @@ public class VariationDecoratorTest extends AbstractDbUnitTestCase { 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 diff --git a/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/timemachine/TimeMachineConfigurationTest/shared.xml b/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/timemachine/TimeMachineConfigurationTest/shared.xml new file mode 100644 index 00000000000..5e53bd405e7 --- /dev/null +++ b/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/timemachine/TimeMachineConfigurationTest/shared.xml @@ -0,0 +1,12 @@ +<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> diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectModule.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectModule.java index 59d3dff04f9..ee7c07ebb3f 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectModule.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectModule.java @@ -31,7 +31,6 @@ import org.sonar.api.resources.ProjectFileSystem; 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; @@ -78,7 +77,6 @@ public class ProjectModule extends Module { 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); diff --git a/sonar-batch/src/main/java/org/sonar/batch/components/PastMeasuresLoader.java b/sonar-batch/src/main/java/org/sonar/batch/components/PastMeasuresLoader.java index 11683350a8b..c4dd2a56dc0 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/components/PastMeasuresLoader.java +++ b/sonar-batch/src/main/java/org/sonar/batch/components/PastMeasuresLoader.java @@ -23,9 +23,11 @@ import com.google.common.collect.Maps; 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; @@ -57,28 +59,25 @@ public class PastMeasuresLoader implements BatchExtension { } 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(); diff --git a/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshot.java b/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshot.java index 843304af53b..881559f14ed 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshot.java +++ b/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshot.java @@ -99,14 +99,14 @@ public class PastSnapshot { @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(); @@ -121,7 +121,7 @@ public class PastSnapshot { } 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())); diff --git a/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinder.java b/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinder.java index dd59bb2009d..ec0ef5d2191 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinder.java +++ b/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinder.java @@ -69,6 +69,10 @@ public class PastSnapshotFinder implements BatchExtension { 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; diff --git a/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByDate.java b/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByDate.java index 4340ac6c4b3..d605b7cabf9 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByDate.java +++ b/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByDate.java @@ -20,6 +20,7 @@ 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; @@ -31,8 +32,6 @@ import java.util.List; public class PastSnapshotFinderByDate implements BatchExtension { - public static final String MODE = "date"; - private DatabaseSession session; public PastSnapshotFinderByDate(DatabaseSession session) { @@ -45,7 +44,7 @@ public class PastSnapshotFinderByDate implements BatchExtension { 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)); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByDays.java b/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByDays.java index b3763107e9c..548d339e31a 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByDays.java +++ b/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByDays.java @@ -21,6 +21,7 @@ package org.sonar.batch.components; 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; @@ -30,8 +31,6 @@ import java.util.List; public class PastSnapshotFinderByDays implements BatchExtension { - public static final String MODE = "days"; - private DatabaseSession session; public PastSnapshotFinderByDays(DatabaseSession session) { @@ -49,7 +48,7 @@ public class PastSnapshotFinderByDays implements BatchExtension { .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) { diff --git a/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByVersion.java b/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByVersion.java index c4cc272c5db..c5de66950d6 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByVersion.java +++ b/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByVersion.java @@ -20,6 +20,7 @@ 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; @@ -29,8 +30,6 @@ import java.util.List; public class PastSnapshotFinderByVersion implements BatchExtension { - public static final String MODE = "version"; - private DatabaseSession session; public PastSnapshotFinderByVersion(DatabaseSession session) { @@ -48,11 +47,11 @@ public class PastSnapshotFinderByVersion implements BatchExtension { .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); } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/components/PastMeasuresLoaderTest.java b/sonar-batch/src/test/java/org/sonar/batch/components/PastMeasuresLoaderTest.java index 74e19b28ddf..40c253e78b3 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/components/PastMeasuresLoaderTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/components/PastMeasuresLoaderTest.java @@ -20,10 +20,8 @@ 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; @@ -38,8 +36,8 @@ import static org.junit.internal.matchers.IsCollectionContaining.hasItems; 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() { @@ -49,7 +47,7 @@ public class PastMeasuresLoaderTest extends AbstractDbUnitTestCase { 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); @@ -71,7 +69,7 @@ public class PastMeasuresLoaderTest extends AbstractDbUnitTestCase { 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); diff --git a/sonar-batch/src/test/java/org/sonar/batch/components/PastSnapshotTest.java b/sonar-batch/src/test/java/org/sonar/batch/components/PastSnapshotTest.java index 8bd305e85e2..d403bd0b7a0 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/components/PastSnapshotTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/components/PastSnapshotTest.java @@ -33,37 +33,37 @@ public class PastSnapshotTest { @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 ")); } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java b/sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java index 49fa07f4c95..e19a5a3f13b 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java @@ -159,6 +159,9 @@ public interface CoreProperties { /* 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"; diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/resources/Project.java b/sonar-plugin-api/src/main/java/org/sonar/api/resources/Project.java index a689a25bb53..dda4c228c52 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/resources/Project.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/resources/Project.java @@ -111,6 +111,7 @@ public class Project extends Resource { public Project(String key) { setKey(key); + setEffectiveKey(key); } public Project(String key, String branch, String name) { @@ -121,6 +122,7 @@ public class Project extends Resource { setKey(key); this.name = name; } + setEffectiveKey(getKey()); this.branch = branch; } @@ -305,6 +307,8 @@ public class Project extends Resource { return parent; } + + /** * For internal use only. */ diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/resources/ProjectTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/resources/ProjectTest.java index d52bbd6a746..8df12c56673 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/resources/ProjectTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/resources/ProjectTest.java @@ -38,6 +38,11 @@ public class ProjectTest { } @Test + public void effectiveKeyShouldEqualKey() { + assertThat(new Project("my:project").getEffectiveKey(), is("my:project")); + } + + @Test public void createFromMavenIds() { Project project = Project.createFromMavenIds("my", "artifact"); assertThat(project.getKey(), is("my:artifact")); |