From 81928180ce26c452c38d9c060e0f79cf4f3b47f7 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Wed, 1 Feb 2012 18:19:33 +0400 Subject: [PATCH] SONAR-3231 Allow to associate measure with committer --- .../core/timemachine/VariationDecorator.java | 14 ++++++++--- .../timemachine/VariationDecoratorTest.java | 14 +++++------ .../org/sonar/batch/DefaultTimeMachine.java | 10 +++++--- .../batch/components/PastMeasuresLoader.java | 13 +++++++--- .../sonar/batch/index/MeasurePersister.java | 1 + .../components/PastMeasuresLoaderTest.java | 7 ++++-- .../api/database/model/MeasureModel.java | 17 ++++++++++++- .../java/org/sonar/api/measures/Measure.java | 25 ++++++++++++++++++- .../sonar/api/measures/MeasuresFilters.java | 3 ++- .../sonar/server/filters/FilterExecutor.java | 5 +++- 10 files changed, 85 insertions(+), 24 deletions(-) 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 b3a5d258121..dab6531f557 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 @@ -98,9 +98,10 @@ public class VariationDecorator implements Decorator { // compare with past measure Integer metricId = (measure.getMetric().getId() != null ? measure.getMetric().getId() : metricFinder.findByKey(measure.getMetric().getKey()).getId()); Integer characteristicId = (measure.getCharacteristic() != null ? measure.getCharacteristic().getId() : null); + String committer = measure.getCommitter(); Integer ruleId = (measure instanceof RuleMeasure ? ((RuleMeasure)measure).getRule().getId() : null); - Object[] pastMeasure = pastMeasuresByKey.get(new MeasureKey(metricId, characteristicId, ruleId)); + Object[] pastMeasure = pastMeasuresByKey.get(new MeasureKey(metricId, characteristicId, committer, ruleId)); if (updateVariation(measure, pastMeasure, index)) { context.saveMeasure(measure); } @@ -124,17 +125,20 @@ public class VariationDecorator implements Decorator { static final class MeasureKey { int metricId; Integer characteristicId; + String committer; Integer ruleId; MeasureKey(Object[] pastFields) { metricId = PastMeasuresLoader.getMetricId(pastFields); characteristicId = PastMeasuresLoader.getCharacteristicId(pastFields); + committer = PastMeasuresLoader.getCommitter(pastFields); ruleId = PastMeasuresLoader.getRuleId(pastFields); } - MeasureKey(int metricId, Integer characteristicId, Integer ruleId) { + MeasureKey(int metricId, Integer characteristicId, String committer, Integer ruleId) { this.metricId = metricId; this.characteristicId = characteristicId; + this.committer = committer; this.ruleId = ruleId; } @@ -153,6 +157,9 @@ public class VariationDecorator implements Decorator { if (characteristicId != null ? !characteristicId.equals(that.characteristicId) : that.characteristicId != null) { return false; } + if (committer != null ? !committer.equals(that.committer) : that.committer != null) { + return false; + } if (ruleId != null ? !ruleId.equals(that.ruleId) : that.ruleId != null) { return false; } @@ -163,8 +170,9 @@ public class VariationDecorator implements Decorator { public int hashCode() { int result = metricId; result = 31 * result + (characteristicId != null ? characteristicId.hashCode() : 0); + result = 31 * result + (committer != null ? committer.hashCode() : 0); result = 31 * result + (ruleId != null ? ruleId.hashCode() : 0); return result; } } -} \ No newline at end of file +} 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 35d5e524d3c..9ac297f1d28 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 @@ -23,11 +23,9 @@ 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.measures.*; import org.sonar.api.resources.*; import org.sonar.api.rules.Rule; -import org.sonar.api.rules.RulePriority; import org.sonar.batch.components.PastMeasuresLoader; import org.sonar.batch.components.PastSnapshot; import org.sonar.batch.components.TimeMachineConfiguration; @@ -100,12 +98,12 @@ public class VariationDecoratorTest extends AbstractDbUnitTestCase { // first past analysis when(pastMeasuresLoader.getPastMeasures(javaPackage, pastSnapshot1)).thenReturn(Arrays.asList( - new Object[]{NCLOC_ID, null, null, 180.0}, - new Object[]{COVERAGE_ID, null, null, 75.0})); + new Object[] {NCLOC_ID, null, null, null, 180.0}, + new Object[] {COVERAGE_ID, null, null, null, 75.0})); // second past analysis when(pastMeasuresLoader.getPastMeasures(javaPackage, pastSnapshot3)).thenReturn(Arrays.asList( - new Object[]{NCLOC_ID, null, null, 240.0})); + new Object[] {NCLOC_ID, null, null, null, 240.0})); // current analysis DecoratorContext context = mock(DecoratorContext.class); @@ -142,9 +140,9 @@ public class VariationDecoratorTest extends AbstractDbUnitTestCase { // first past analysis when(pastMeasuresLoader.getPastMeasures(javaPackage, pastSnapshot1)).thenReturn(Arrays.asList( - new Object[]{VIOLATIONS_ID, null, null, 180.0},//total - new Object[]{VIOLATIONS_ID, null, rule1.getId(), 100.0},// rule 1 - new Object[]{VIOLATIONS_ID, null, rule2.getId(), 80.0})); // rule 2 + new Object[] {VIOLATIONS_ID, null, null, null, 180.0},// total + new Object[] {VIOLATIONS_ID, null, null, rule1.getId(), 100.0},// rule 1 + new Object[] {VIOLATIONS_ID, null, null, rule2.getId(), 80.0})); // rule 2 // current analysis DecoratorContext context = mock(DecoratorContext.class); diff --git a/sonar-batch/src/main/java/org/sonar/batch/DefaultTimeMachine.java b/sonar-batch/src/main/java/org/sonar/batch/DefaultTimeMachine.java index fce98a19737..326dfbb9b2d 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/DefaultTimeMachine.java +++ b/sonar-batch/src/main/java/org/sonar/batch/DefaultTimeMachine.java @@ -34,6 +34,7 @@ import org.sonar.api.resources.Resource; import org.sonar.batch.index.DefaultIndex; import javax.persistence.Query; + import java.util.*; public class DefaultTimeMachine implements TimeMachine { @@ -93,12 +94,14 @@ public class DefaultTimeMachine implements TimeMachine { .append(MeasureModel.class.getSimpleName()) .append(" m, ") .append(Snapshot.class.getSimpleName()) - .append(" s WHERE m.snapshotId=s.id AND s.resourceId=:resourceId AND s.status=:status AND m.characteristic IS NULL AND s.qualifier<>:lib"); + .append(" s WHERE m.snapshotId=s.id AND s.resourceId=:resourceId AND s.status=:status AND s.qualifier<>:lib"); params.put("resourceId", resource.getId()); params.put("status", Snapshot.STATUS_PROCESSED); params.put("lib", Qualifiers.LIBRARY); - sb.append(" AND m.ruleId IS NULL AND m.rulePriority IS NULL "); + sb.append(" AND m.characteristic IS NULL"); + sb.append(" AND m.committer IS NULL"); + sb.append(" AND m.ruleId IS NULL AND m.rulePriority IS NULL"); if (!metricIds.isEmpty()) { sb.append(" AND m.metricId IN (:metricIds) "); params.put("metricIds", metricIds); @@ -159,6 +162,7 @@ public class DefaultTimeMachine implements TimeMachine { measure.setVariation5(model.getVariationValue5()); measure.setUrl(model.getUrl()); measure.setCharacteristic(model.getCharacteristic()); + measure.setCommitter(model.getCommitter()); return measure; } -} \ No newline at end of file +} 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 a04a0311f0b..7b2560a3e28 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 @@ -65,7 +65,7 @@ public class PastMeasuresLoader implements BatchExtension { } public List getPastMeasures(String resourceKey, Snapshot projectPastSnapshot) { - String sql = "select m.metric_id, m.characteristic_id, m.rule_id, m.value from project_measures m, snapshots s" + + String sql = "select m.metric_id, m.characteristic_id, m.committer, m.rule_id, m.value from project_measures m, snapshots s" + " where m.snapshot_id=s.id and m.metric_id in (:metricIds) " + " 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)"; @@ -89,17 +89,22 @@ public class PastMeasuresLoader implements BatchExtension { return number != null ? number.intValue() : null; } + public static String getCommitter(Object[] row) { + return (String) row[2]; + } + public static Integer getRuleId(Object[] row) { // can be BigDecimal on Oracle - Number number = (Number) row[2]; + Number number = (Number) row[3]; return number != null ? number.intValue() : null; } public static boolean hasValue(Object[] row) { - return row[3] != null; + return row[4] != null; } public static double getValue(Object[] row) { - return ((Number) row[3]).doubleValue(); + return ((Number) row[4]).doubleValue(); } + } diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/MeasurePersister.java b/sonar-batch/src/main/java/org/sonar/batch/index/MeasurePersister.java index 1f0326c55a1..620519345f0 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/index/MeasurePersister.java +++ b/sonar-batch/src/main/java/org/sonar/batch/index/MeasurePersister.java @@ -150,6 +150,7 @@ public final class MeasurePersister { merge.setVariationValue5(measure.getVariation5()); merge.setUrl(measure.getUrl()); merge.setCharacteristic(measure.getCharacteristic()); + merge.setCommitter(measure.getCommitter()); if (measure.getValue() != null) { merge.setValue(measure.getValue().doubleValue()); } else { 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 5d56fde9600..5c4e9638507 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 @@ -27,7 +27,6 @@ import org.sonar.jpa.test.AbstractDbUnitTestCase; import java.util.Arrays; import java.util.List; -import static org.hamcrest.CoreMatchers.anyOf; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.nullValue; @@ -53,11 +52,13 @@ public class PastMeasuresLoaderTest extends AbstractDbUnitTestCase { Object[] pastMeasure = measures.get(0); assertThat(PastMeasuresLoader.getMetricId(pastMeasure), is(1)); assertThat(PastMeasuresLoader.getCharacteristicId(pastMeasure), nullValue()); + assertThat(PastMeasuresLoader.getCommitter(pastMeasure), nullValue()); assertThat(PastMeasuresLoader.getValue(pastMeasure), is(5.0)); pastMeasure = measures.get(1); assertThat(PastMeasuresLoader.getMetricId(pastMeasure), is(2)); assertThat(PastMeasuresLoader.getCharacteristicId(pastMeasure), nullValue()); + assertThat(PastMeasuresLoader.getCommitter(pastMeasure), nullValue()); assertThat(PastMeasuresLoader.getValue(pastMeasure), is(60.0)); } @@ -75,11 +76,13 @@ public class PastMeasuresLoaderTest extends AbstractDbUnitTestCase { Object[] pastMeasure = measures.get(0); assertThat(PastMeasuresLoader.getMetricId(pastMeasure), is(1)); assertThat(PastMeasuresLoader.getCharacteristicId(pastMeasure), nullValue()); + assertThat(PastMeasuresLoader.getCommitter(pastMeasure), nullValue()); assertThat(PastMeasuresLoader.getValue(pastMeasure), is(60.0)); pastMeasure = measures.get(1); assertThat(PastMeasuresLoader.getMetricId(pastMeasure), is(2)); assertThat(PastMeasuresLoader.getCharacteristicId(pastMeasure), nullValue()); + assertThat(PastMeasuresLoader.getCommitter(pastMeasure), nullValue()); assertThat(PastMeasuresLoader.getValue(pastMeasure), is(80.0)); } @@ -94,7 +97,7 @@ public class PastMeasuresLoaderTest extends AbstractDbUnitTestCase { List metrics = Arrays.asList(ncloc, complexity, data); PastMeasuresLoader loader = new PastMeasuresLoader(getSession(), metrics); - + assertThat(loader.getMetrics().size(), is(2)); assertThat(loader.getMetrics(), hasItems(ncloc, complexity)); } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/database/model/MeasureModel.java b/sonar-plugin-api/src/main/java/org/sonar/api/database/model/MeasureModel.java index 739c6dfc423..f63e730af76 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/database/model/MeasureModel.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/database/model/MeasureModel.java @@ -27,6 +27,7 @@ import org.sonar.api.qualitymodel.Characteristic; import org.sonar.api.rules.RulePriority; import javax.persistence.*; + import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -115,6 +116,9 @@ public class MeasureModel implements Cloneable { @JoinColumn(name = "characteristic_id") private Characteristic characteristic; + @Column(name = "committer", updatable = true, nullable = true, length = 100) + private String committer; + public Long getId() { return id; } @@ -122,7 +126,7 @@ public class MeasureModel implements Cloneable { public void setId(Long id) { this.id = id; } - + /** * Creates a measure based on a metric and a double value */ @@ -518,6 +522,15 @@ public class MeasureModel implements Cloneable { return this; } + public String getCommitter() { + return committer; + } + + public MeasureModel setCommitter(String committer) { + this.committer = committer; + return this; + } + @Override public Object clone() { MeasureModel clone = new MeasureModel(); @@ -539,6 +552,8 @@ public class MeasureModel implements Cloneable { clone.setMeasureDate(getMeasureDate()); clone.setUrl(getUrl()); clone.setCharacteristic(getCharacteristic()); + clone.setCommitter(getCommitter()); return clone; } + } 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 1b1c4134ecd..61497f07af3 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 @@ -19,6 +19,7 @@ */ package org.sonar.api.measures; +import com.google.common.annotations.Beta; import org.apache.commons.lang.builder.ReflectionToStringBuilder; import org.sonar.api.qualitymodel.Characteristic; @@ -52,6 +53,7 @@ public class Measure { protected Double variation1, variation2, variation3, variation4, variation5; protected String url; protected Characteristic characteristic; + protected String committer; protected PersistenceMode persistenceMode = PersistenceMode.FULL; public Measure(String metricKey) { @@ -329,7 +331,7 @@ public class Measure { this.data=null; return this; } - + /** * @return the description of the measure */ @@ -593,6 +595,23 @@ public class Measure { return this; } + /** + * @since 2.14 + */ + @Beta + public String getCommitter() { + return committer; + } + + /** + * @since 2.14 + */ + @Beta + public Measure setCommitter(String committer) { + this.committer = committer; + return this; + } + @Override public boolean equals(Object o) { if (this == o) { @@ -609,6 +628,9 @@ public class Measure { if (characteristic != null ? !characteristic.equals(measure.characteristic) : measure.characteristic != null) { return false; } + if (committer != null ? !committer.equals(measure.committer) : measure.committer != null) { + return false; + } return true; } @@ -616,6 +638,7 @@ public class Measure { public int hashCode() { int result = metricKey != null ? metricKey.hashCode() : 0; result = 31 * result + (characteristic != null ? characteristic.hashCode() : 0); + result = 31 * result + (committer != null ? committer.hashCode() : 0); return result; } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/measures/MeasuresFilters.java b/sonar-plugin-api/src/main/java/org/sonar/api/measures/MeasuresFilters.java index 9a975e48cbe..bf4e1964f15 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/measures/MeasuresFilters.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/measures/MeasuresFilters.java @@ -57,7 +57,8 @@ public final class MeasuresFilters { for (Measure measure : measures) { if (measure.getClass().equals(Measure.class) && measure.getMetricKey().equals(metricKey) && - measure.getCharacteristic() == null) { + measure.getCharacteristic() == null && + measure.getCommitter() == null) { return measure; } } diff --git a/sonar-server/src/main/java/org/sonar/server/filters/FilterExecutor.java b/sonar-server/src/main/java/org/sonar/server/filters/FilterExecutor.java index fc820ed90ca..6dba0c4fa01 100644 --- a/sonar-server/src/main/java/org/sonar/server/filters/FilterExecutor.java +++ b/sonar-server/src/main/java/org/sonar/server/filters/FilterExecutor.java @@ -147,7 +147,10 @@ public class FilterExecutor implements ServerComponent { sql.append(" ) AND "); } - sql.append(" pm.rule_id is null AND pm.rule_priority is null AND pm.characteristic_id IS NULL AND "); + sql.append(" pm.rule_id IS NULL AND pm.rule_priority IS NULL"); + sql.append(" AND pm.characteristic_id IS NULL"); + sql.append(" AND pm.committer IS NULL"); + sql.append(" AND "); } sql.append(" s.status=:status AND s.islast=:islast "); if (filter.getScopes() != null) { -- 2.39.5