From 4e10bd0c5beb97e398e80747d26f6b85f8a9f930 Mon Sep 17 00:00:00 2001 From: Godin Date: Tue, 30 Nov 2010 23:34:59 +0000 Subject: [PATCH] SONAR-1450: Add first implementation of NewViolationsDecorator --- .../org/sonar/plugins/core/CorePlugin.java | 3 + .../timemachine/NewViolationsDecorator.java | 73 ++++++++++++++++ .../timemachine/TimeMachineConfiguration.java | 13 +-- .../NewViolationsDecoratorTest.java | 42 ++++++++++ .../org/sonar/api/measures/CoreMetrics.java | 4 + .../java/org/sonar/api/measures/Measure.java | 83 ++++++++++--------- .../java/org/sonar/api/rules/Violation.java | 3 +- 7 files changed, 173 insertions(+), 48 deletions(-) create mode 100644 plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewViolationsDecorator.java create mode 100644 plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/NewViolationsDecoratorTest.java 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 a3495af0c0b..f1e767eec96 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 @@ -19,6 +19,8 @@ */ package org.sonar.plugins.core; +import org.sonar.plugins.core.timemachine.NewViolationsDecorator; + import com.google.common.collect.Lists; import org.sonar.api.CoreProperties; import org.sonar.api.Plugin; @@ -196,6 +198,7 @@ public class CorePlugin implements Plugin { extensions.add(TendencyDecorator.class); extensions.add(PeriodLocator.class); extensions.add(VariationDecorator.class); + extensions.add(NewViolationsDecorator.class); extensions.add(TimeMachineConfiguration.class); return extensions; 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 new file mode 100644 index 00000000000..4e6dc6276f7 --- /dev/null +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewViolationsDecorator.java @@ -0,0 +1,73 @@ +package org.sonar.plugins.core.timemachine; + +import org.apache.commons.lang.time.DateUtils; +import org.sonar.api.batch.Decorator; +import org.sonar.api.batch.DecoratorBarriers; +import org.sonar.api.batch.DecoratorContext; +import org.sonar.api.batch.DependedUpon; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.api.measures.Measure; +import org.sonar.api.resources.Project; +import org.sonar.api.resources.Resource; +import org.sonar.api.rules.Violation; + +import java.util.Date; + +@DependedUpon(DecoratorBarriers.END_OF_VIOLATIONS_GENERATION) +public class NewViolationsDecorator implements Decorator { + + private TimeMachineConfiguration timeMachineConfiguration; + + public NewViolationsDecorator(TimeMachineConfiguration timeMachineConfiguration) { + this.timeMachineConfiguration = timeMachineConfiguration; + } + + public boolean shouldExecuteOnProject(Project project) { + return true; + } + + public void decorate(Resource resource, DecoratorContext context) { + Measure measure = new Measure(CoreMetrics.NEW_VIOLATIONS); + for (int index = 0; index < 3; index++) { + int days = timeMachineConfiguration.getDiffPeriodInDays(index); + setDiffValue(measure, index, calculate(context, days)); + } + context.saveMeasure(measure); + } + + int calculate(DecoratorContext context, int days) { + Date targetDate = getTargetDate(context.getProject(), days); + int newViolations = 0; + for (Violation violation : context.getViolations()) { + if (!violation.getCreatedAt().before(targetDate)) { + newViolations++; + } + } + return newViolations; + } + + private Date getTargetDate(Project project, int distanceInDays) { + return DateUtils.addDays(project.getAnalysisDate(), -distanceInDays); + } + + private void setDiffValue(Measure measure, int index, double value) { + switch (index) { + case 0: + measure.setDiffValue1(value); + break; + case 1: + measure.setDiffValue2(value); + break; + case 2: + measure.setDiffValue2(value); + break; + default: + break; + } + } + + @Override + public String toString() { + return getClass().toString(); + } +} diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/TimeMachineConfiguration.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/TimeMachineConfiguration.java index 0a4efdff2d1..4e219294a09 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/TimeMachineConfiguration.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/TimeMachineConfiguration.java @@ -42,12 +42,13 @@ public final class TimeMachineConfiguration implements BatchExtension { return configuration.getInt(CoreProperties.CORE_TENDENCY_DEPTH_PROPERTY, CoreProperties.CORE_TENDENCY_DEPTH_DEFAULT_VALUE); } - Snapshot getProjectSnapshotForDiffValues(int index) { + Integer getDiffPeriodInDays(int index) { String property = configuration.getString("sonar.timemachine.diff" + index); - Snapshot projectSnapshot = null; - if (property!=null) { - projectSnapshot = periodLocator.locate(Integer.valueOf(property)); - } - return projectSnapshot; + return property == null ? null : Integer.valueOf(property); + } + + Snapshot getProjectSnapshotForDiffValues(int index) { + Integer days = getDiffPeriodInDays(index); + return days == null ? null : periodLocator.locate(days); } } 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 new file mode 100644 index 00000000000..b4c82280518 --- /dev/null +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/NewViolationsDecoratorTest.java @@ -0,0 +1,42 @@ +package org.sonar.plugins.core.timemachine; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.apache.commons.lang.time.DateUtils; +import org.junit.Before; +import org.junit.Test; +import org.sonar.api.batch.DecoratorContext; +import org.sonar.api.resources.Project; +import org.sonar.api.rules.Violation; + +import java.util.Arrays; +import java.util.Date; + +public class NewViolationsDecoratorTest { + + private NewViolationsDecorator decorator; + + @Before + public void setUp() { + decorator = new NewViolationsDecorator(null); + } + + @Test + public void test() { + DecoratorContext context = mock(DecoratorContext.class); + Date date1 = new Date(); + Date date2 = DateUtils.addDays(date1, -20); + Project project = new Project("project"); + project.setAnalysisDate(date1); + Violation violation1 = new Violation(null).setCreatedAt(date1); + Violation violation2 = new Violation(null).setCreatedAt(date2); + when(context.getViolations()).thenReturn(Arrays.asList(violation1, violation2)); + when(context.getProject()).thenReturn(project); + + assertThat(decorator.calculate(context, 10), is(1)); + assertThat(decorator.calculate(context, 30), is(2)); + } +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java b/sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java index 8ddffc1ee22..cf6cacfb657 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java @@ -297,6 +297,10 @@ public final class CoreMetrics { public static final Metric VIOLATIONS = new Metric(VIOLATIONS_KEY, "Violations", "Violations", Metric.ValueType.INT, Metric.DIRECTION_WORST, false, DOMAIN_RULES).setBestValue(0.0).setOptimizedBestValue(true); + public static final String NEW_VIOLATIONS_KEY = "new_violations"; + public static final Metric NEW_VIOLATIONS = new Metric(NEW_VIOLATIONS_KEY, "New Violations", "New Violations", Metric.ValueType.INT, + Metric.DIRECTION_WORST, false, DOMAIN_RULES); + public static final String BLOCKER_VIOLATIONS_KEY = "blocker_violations"; public static final Metric BLOCKER_VIOLATIONS = new Metric(BLOCKER_VIOLATIONS_KEY, "Blocker violations", "Blocker violations", Metric.ValueType.INT, Metric.DIRECTION_WORST, false, DOMAIN_RULES).setBestValue(0.0).setOptimizedBestValue(true); diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/measures/Measure.java b/sonar-plugin-api/src/main/java/org/sonar/api/measures/Measure.java index 5ff3e96c5ae..7bd623d98e1 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/measures/Measure.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/measures/Measure.java @@ -28,8 +28,7 @@ import java.util.Date; /** * A class to handle measures. - *

- * + * * @since 1.10 */ public class Measure { @@ -61,7 +60,7 @@ public class Measure { /** * Creates a measure with a metric - * + * * @param metric the metric */ public Measure(Metric metric) { @@ -71,9 +70,9 @@ public class Measure { /** * Creates a measure with a metric and a value - * + * * @param metric the metric - * @param value its value + * @param value its value */ public Measure(Metric metric, Double value) { this.metric = metric; @@ -83,9 +82,9 @@ public class Measure { /** * Creates a measure with a metric, a value and a precision for the value - * - * @param metric the metric - * @param value its value + * + * @param metric the metric + * @param value its value * @param precision the value precision */ public Measure(Metric metric, Double value, int precision) { @@ -96,10 +95,10 @@ public class Measure { /** * Creates a measure with a metric, a value and a data field - * + * * @param metric the metric - * @param value the value - * @param data the data field + * @param value the value + * @param data the data field */ public Measure(Metric metric, Double value, String data) { this.metric = metric; @@ -110,9 +109,9 @@ public class Measure { /** * * Creates a measure with a metric and a data field - * + * * @param metric the metric - * @param data the data field + * @param data the data field */ public Measure(Metric metric, String data) { this.metric = metric; @@ -122,9 +121,9 @@ public class Measure { /** * Creates a measure with a metric and an alert level - * + * * @param metric the metric - * @param level the alert level + * @param level the alert level */ public Measure(Metric metric, Metric.Level level) { this.metric = metric; @@ -141,20 +140,23 @@ public class Measure { } /** - * Gets the persistence mode of the measure. Default persistence mode is FULL, - * except when instantiating the measure with a String parameter. + * Gets the persistence mode of the measure. Default persistence mode is FULL, except when instantiating the measure with a String + * parameter. */ public PersistenceMode getPersistenceMode() { return persistenceMode; } /** - *

Sets the persistence mode of a measure.

- *

WARNING : Being able to reuse measures saved in memory is only possible within the same tree. - * In a multi-module project for example, a measure save in memory at the module level will not be accessible by - * the root project. In that case, database should be used. + *

+ * Sets the persistence mode of a measure. *

- * + *

+ * WARNING : Being able to reuse measures saved in memory is only possible within the same tree. In a multi-module project for + * example, a measure save in memory at the module level will not be accessible by the root project. In that case, database should be + * used. + *

+ * * @param mode the mode * @return the measure object instance */ @@ -176,7 +178,7 @@ public class Measure { /** * Set the underlying metric - * + * * @param metric the metric * @return the measure object instance */ @@ -205,7 +207,7 @@ public class Measure { /** * Sets the date of the measure - Used only in TimeMachine queries - * + * * @param date the date * @return the measure object instance */ @@ -233,7 +235,7 @@ public class Measure { /** * Sets the measure value with the default precision of 1 - * + * * @param v the measure value * @return the measure object instance */ @@ -243,7 +245,7 @@ public class Measure { /** * Sets the measure value as an int - * + * * @param i the value * @return the measure object instance */ @@ -258,8 +260,8 @@ public class Measure { /** * Sets the measure value with a given precision - * - * @param v the measure value + * + * @param v the measure value * @param precision the measure value precision * @return the measure object instance */ @@ -289,7 +291,7 @@ public class Measure { /** * Sets the data field of the measure. - * + * * @param s the data * @return the measure object instance */ @@ -303,7 +305,7 @@ public class Measure { /** * Sets an alert level as the data field - * + * * @param level the alert level * @return the measure object instance */ @@ -325,7 +327,7 @@ public class Measure { /** * Sets the measure description - * + * * @param description the description * @return the measure object instance */ @@ -343,7 +345,7 @@ public class Measure { /** * Set the alert status of the measure - * + * * @param status the status * @return the measure object instance */ @@ -361,7 +363,7 @@ public class Measure { /** * Sets the text associated to the alert on the measure - * + * * @param alertText the text * @return the measure object instance */ @@ -372,7 +374,7 @@ public class Measure { /** * Gets the measure tendency - * + * * @return the tendency */ public Integer getTendency() { @@ -381,7 +383,7 @@ public class Measure { /** * Sets the tendency for the measure - * + * * @param tendency the tendency * @return the measure object instance */ @@ -399,7 +401,7 @@ public class Measure { /** * Sets the measure id - Internal use only - * + * * @param id the id * @return the measure object instance */ @@ -417,7 +419,7 @@ public class Measure { /** * Sets the first differential value of the measure - * + * * @param diff1 the diff * @return the measure object instance */ @@ -435,7 +437,7 @@ public class Measure { /** * Sets the second differential value of the measure - * + * * @param diff2 the diff * @return the measure object instance */ @@ -453,7 +455,7 @@ public class Measure { /** * Sets the third differential value of the measure - * + * * @param diff3 the diff * @return the measure object instance */ @@ -471,7 +473,7 @@ public class Measure { /** * Sets the URL of the measure - * + * * @param url the url * @return the measure object instance */ @@ -489,7 +491,6 @@ public class Measure { return this; } - @Override public boolean equals(Object o) { if (this == o) { diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/rules/Violation.java b/sonar-plugin-api/src/main/java/org/sonar/api/rules/Violation.java index 8230154d966..6b8eaa7fe3e 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/rules/Violation.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/rules/Violation.java @@ -161,8 +161,9 @@ public class Violation { /** * @since 2.5 */ - public void setCreatedAt(Date createdAt) { + public Violation setCreatedAt(Date createdAt) { this.createdAt = createdAt; + return this; } @Override -- 2.39.5