]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-2218 compute coverage on new/changed code
authorsimonbrandhof <simon.brandhof@gmail.com>
Mon, 28 Feb 2011 17:05:03 +0000 (18:05 +0100)
committersimonbrandhof <simon.brandhof@gmail.com>
Mon, 28 Feb 2011 17:05:03 +0000 (18:05 +0100)
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/AbstractCoverageDecorator.java
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/BranchCoverageDecorator.java
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/CoverageDecorator.java
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/LineCoverageDecorator.java
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewCoverageAggregator.java
plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/BranchCoverageDecoratorTest.java
plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/NewCoverageAggregatorTest.java [new file with mode: 0644]
sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java

index b548de52143e34d6108342650dcb8db5634b8951..d5a6e95c047d3c513008bc96722a84550c67ccf8 100644 (file)
@@ -22,11 +22,15 @@ package org.sonar.plugins.core.sensors;
 import org.sonar.api.batch.Decorator;
 import org.sonar.api.batch.DecoratorContext;
 import org.sonar.api.batch.DependedUpon;
+import org.sonar.api.measures.Measure;
 import org.sonar.api.measures.Metric;
 import org.sonar.api.resources.Project;
 import org.sonar.api.resources.Resource;
 import org.sonar.api.resources.ResourceUtils;
 
+import java.util.Arrays;
+import java.util.Collection;
+
 public abstract class AbstractCoverageDecorator implements Decorator {
 
   public boolean shouldExecuteOnProject(Project project) {
@@ -34,36 +38,60 @@ public abstract class AbstractCoverageDecorator implements Decorator {
   }
 
   @DependedUpon
-  public Metric generatesCoverage() {
-    return getTargetMetric();
+  public Collection<Metric> generatedMetrics() {
+    return Arrays.asList(getGeneratedMetric(), getGeneratedMetricForNewCode());
   }
 
   public void decorate(final Resource resource, final DecoratorContext context) {
     if (shouldDecorate(resource, context)) {
-      saveLineCoverage(context);
+      computeMeasure(context);
+      computeMeasureForNewCode(context);
     }
   }
 
   protected boolean shouldDecorate(final Resource resource, final DecoratorContext context) {
-    return context.getMeasure(getTargetMetric()) == null && !ResourceUtils.isUnitTestClass(resource);
+    return context.getMeasure(getGeneratedMetric()) == null && !ResourceUtils.isUnitTestClass(resource);
+  }
+
+  private void computeMeasure(DecoratorContext context) {
+    Long elements = countElements(context);
+    if (elements != null && elements > 0L) {
+      Long coveredElements = countCoveredElements(context);
+      context.saveMeasure(getGeneratedMetric(), calculateCoverage(coveredElements, elements));
+    }
   }
 
-  private void saveLineCoverage(DecoratorContext context) {
-    Double elements = countElements(context);
-    Double coveredElements = countCoveredElements(context);
+  private void computeMeasureForNewCode(DecoratorContext context) {
+    Measure measure = new Measure(getGeneratedMetricForNewCode());
+    boolean hasValue = false;
+    /* TODO remove this magic number */
+    for (int periodIndex = 1; periodIndex <= 5; periodIndex++) {
+      Long elements = countElementsForNewCode(context, periodIndex);
 
-    if (elements != null && elements > 0.0 && coveredElements != null) {
-      context.saveMeasure(getTargetMetric(), calculateCoverage(coveredElements, elements));
+      if (elements != null && elements > 0L) {
+        long coveredElements = countCoveredElementsForNewCode(context, periodIndex);
+        measure.setVariation(periodIndex, calculateCoverage(coveredElements, elements));
+        hasValue = true;
+      }
+    }
+    if (hasValue) {
+      context.saveMeasure(measure);
     }
   }
 
-  private double calculateCoverage(final Double coveredLines, final Double lines) {
+  private double calculateCoverage(final long coveredLines, final long lines) {
     return (100.0 * coveredLines) / lines;
   }
 
-  protected abstract Metric getTargetMetric();
+  protected abstract Metric getGeneratedMetric();
+
+  protected abstract Long countElements(DecoratorContext context);
+
+  protected abstract long countCoveredElements(DecoratorContext context);
+
+  protected abstract Metric getGeneratedMetricForNewCode();
 
-  protected abstract Double countCoveredElements(DecoratorContext context);
+  protected abstract Long countElementsForNewCode(DecoratorContext context, int periodIndex);
 
-  protected abstract Double countElements(DecoratorContext context);
+  protected abstract long countCoveredElementsForNewCode(DecoratorContext context, int periodIndex);
 }
index ce4c61bd11ab749deda0f7f1a0079cec6553404e..d9f3cc76ef0f82c4a1872ae7da2d27f6559a9683 100644 (file)
@@ -28,27 +28,45 @@ import org.sonar.api.measures.Metric;
 import java.util.Arrays;
 import java.util.List;
 
-public class BranchCoverageDecorator extends AbstractCoverageDecorator {
+public final class BranchCoverageDecorator extends AbstractCoverageDecorator {
+
+  @DependsUpon
+  public List<Metric> dependsUponMetrics() {
+    return Arrays.asList(CoreMetrics.UNCOVERED_CONDITIONS, CoreMetrics.CONDITIONS_TO_COVER,
+        CoreMetrics.NEW_UNCOVERED_CONDITIONS, CoreMetrics.NEW_CONDITIONS_TO_COVER);
+  }
 
   @Override
-  protected Metric getTargetMetric() {
+  protected Metric getGeneratedMetric() {
     return CoreMetrics.BRANCH_COVERAGE;
   }
 
-  @DependsUpon
-  public List<Metric> dependsUponMetrics() {
-    return Arrays.asList(CoreMetrics.UNCOVERED_CONDITIONS, CoreMetrics.CONDITIONS_TO_COVER);
+  @Override
+  protected Long countElements(DecoratorContext context) {
+    return MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.CONDITIONS_TO_COVER), 0L);
   }
 
   @Override
-  protected Double countCoveredElements(DecoratorContext context) {
-    double uncoveredConditions = MeasureUtils.getValue(context.getMeasure(CoreMetrics.UNCOVERED_CONDITIONS), 0.0);
-    double conditions = MeasureUtils.getValue(context.getMeasure(CoreMetrics.CONDITIONS_TO_COVER), 0.0);
+  protected long countCoveredElements(DecoratorContext context) {
+    long uncoveredConditions = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.UNCOVERED_CONDITIONS), 0L);
+    long conditions = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.CONDITIONS_TO_COVER), 0L);
     return conditions - uncoveredConditions;
   }
 
   @Override
-  protected Double countElements(DecoratorContext context) {
-    return MeasureUtils.getValue(context.getMeasure(CoreMetrics.CONDITIONS_TO_COVER), 0.0);
+  protected Metric getGeneratedMetricForNewCode() {
+    return CoreMetrics.NEW_BRANCH_COVERAGE;
+  }
+
+  @Override
+  protected Long countElementsForNewCode(DecoratorContext context, int periodIndex) {
+    return MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_CONDITIONS_TO_COVER), periodIndex);
+  }
+
+  @Override
+  protected long countCoveredElementsForNewCode(DecoratorContext context, int periodIndex) {
+    long uncoveredConditions = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_UNCOVERED_CONDITIONS), periodIndex, 0L);
+    long conditions = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_CONDITIONS_TO_COVER), periodIndex, 0L);
+    return conditions - uncoveredConditions;
   }
 }
index 4342742a87eb027c55114b6acea889316a033116..0944f8dabcd0336e147cc98e9065467d9d138eb0 100644 (file)
 package org.sonar.plugins.core.sensors;
 
 import org.sonar.api.batch.DecoratorContext;
+import org.sonar.api.batch.DependedUpon;
 import org.sonar.api.batch.DependsUpon;
 import org.sonar.api.measures.CoreMetrics;
 import org.sonar.api.measures.MeasureUtils;
 import org.sonar.api.measures.Metric;
 
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.List;
 
-public class CoverageDecorator extends AbstractCoverageDecorator {
+public final class CoverageDecorator extends AbstractCoverageDecorator {
+
+  @DependsUpon
+  public Collection<Metric> usedMetrics() {
+    return Arrays.asList(CoreMetrics.LINES_TO_COVER, CoreMetrics.UNCOVERED_LINES, CoreMetrics.NEW_LINES_TO_COVER,
+        CoreMetrics.NEW_UNCOVERED_LINES, CoreMetrics.CONDITIONS_TO_COVER, CoreMetrics.UNCOVERED_CONDITIONS,
+        CoreMetrics.NEW_CONDITIONS_TO_COVER, CoreMetrics.NEW_UNCOVERED_CONDITIONS);
+  }
 
   @Override
-  protected Metric getTargetMetric() {
+  protected Metric getGeneratedMetric() {
     return CoreMetrics.COVERAGE;
   }
 
-  @DependsUpon
-  public List<Metric> dependsUponMetrics() {
-    return Arrays.asList(CoreMetrics.LINES_TO_COVER, CoreMetrics.UNCOVERED_LINES, CoreMetrics.CONDITIONS_TO_COVER, CoreMetrics.UNCOVERED_CONDITIONS);
+  @Override
+  protected Long countElements(DecoratorContext context) {
+    long lines = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.LINES_TO_COVER), 0L);
+    long conditions = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.CONDITIONS_TO_COVER), 0L);
+    return lines + conditions;
   }
 
   @Override
-  protected Double countCoveredElements(DecoratorContext context) {
-    double uncoveredLines = MeasureUtils.getValue(context.getMeasure(CoreMetrics.UNCOVERED_LINES), 0.0);
-    double lines = MeasureUtils.getValue(context.getMeasure(CoreMetrics.LINES_TO_COVER), 0.0);
-    double uncoveredConditions = MeasureUtils.getValue(context.getMeasure(CoreMetrics.UNCOVERED_CONDITIONS), 0.0);
-    double conditions = MeasureUtils.getValue(context.getMeasure(CoreMetrics.CONDITIONS_TO_COVER), 0.0);
+  protected long countCoveredElements(DecoratorContext context) {
+    long uncoveredLines = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.UNCOVERED_LINES), 0L);
+    long lines = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.LINES_TO_COVER), 0L);
+    long uncoveredConditions = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.UNCOVERED_CONDITIONS), 0L);
+    long conditions = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.CONDITIONS_TO_COVER), 0L);
     return lines + conditions - uncoveredConditions - uncoveredLines;
   }
 
+
+
   @Override
-  protected Double countElements(DecoratorContext context) {
-    double lines = MeasureUtils.getValue(context.getMeasure(CoreMetrics.LINES_TO_COVER), 0.0);
-    double conditions = MeasureUtils.getValue(context.getMeasure(CoreMetrics.CONDITIONS_TO_COVER), 0.0);
-    return lines + conditions;
+  protected Metric getGeneratedMetricForNewCode() {
+    return CoreMetrics.NEW_COVERAGE;
+  }
+
+  @Override
+  protected Long countElementsForNewCode(DecoratorContext context, int periodIndex) {
+    Long newLinesToCover = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_LINES_TO_COVER), periodIndex);
+    if (newLinesToCover!=null) {
+      long newConditionsToCover = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_CONDITIONS_TO_COVER), periodIndex, 0L);
+      return newLinesToCover + newConditionsToCover;
+    }
+    return null;
+  }
+
+  @Override
+  protected long countCoveredElementsForNewCode(DecoratorContext context, int periodIndex) {
+    long newLines = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_LINES_TO_COVER), periodIndex, 0L);
+    long newUncoveredLines = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_UNCOVERED_LINES), periodIndex, 0L);
+    long newUncoveredConditions = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_UNCOVERED_CONDITIONS), periodIndex, 0L);
+    long newConditions = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_CONDITIONS_TO_COVER), periodIndex, 0L);
+    return newLines + newConditions - newUncoveredConditions - newUncoveredLines;
   }
 }
\ No newline at end of file
index 5d8ed7bd57ac853d786589e2c45f3faf22206894..d702f6b3c12e0c5be3ae1d49396bedb24c3231b0 100644 (file)
@@ -28,27 +28,46 @@ import org.sonar.api.measures.Metric;
 import java.util.Arrays;
 import java.util.List;
 
-public class LineCoverageDecorator extends AbstractCoverageDecorator {
+public final class LineCoverageDecorator extends AbstractCoverageDecorator {
+
+  @DependsUpon
+  public List<Metric> dependsUponMetrics() {
+    return Arrays.asList(CoreMetrics.UNCOVERED_LINES, CoreMetrics.LINES_TO_COVER, CoreMetrics.NEW_UNCOVERED_LINES,
+        CoreMetrics.NEW_LINES_TO_COVER);
+  }
 
   @Override
-  protected Metric getTargetMetric() {
+  protected Metric getGeneratedMetric() {
     return CoreMetrics.LINE_COVERAGE;
   }
 
-  @DependsUpon
-  public List<Metric> dependsUponMetrics() {
-    return Arrays.asList(CoreMetrics.UNCOVERED_LINES, CoreMetrics.LINES_TO_COVER);
+  @Override
+  protected Long countElements(DecoratorContext context) {
+    return MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.LINES_TO_COVER), 0L);
   }
 
   @Override
-  protected Double countCoveredElements(DecoratorContext context) {
-    double uncoveredLines = MeasureUtils.getValue(context.getMeasure(CoreMetrics.UNCOVERED_LINES), 0.0);
-    double lines = MeasureUtils.getValue(context.getMeasure(CoreMetrics.LINES_TO_COVER), 0.0);
+  protected long countCoveredElements(DecoratorContext context) {
+    long uncoveredLines = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.UNCOVERED_LINES), 0L);
+    long lines = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.LINES_TO_COVER), 0L);
     return lines - uncoveredLines;
   }
 
+
   @Override
-  protected Double countElements(DecoratorContext context) {
-    return MeasureUtils.getValue(context.getMeasure(CoreMetrics.LINES_TO_COVER), 0.0);
+  protected Metric getGeneratedMetricForNewCode() {
+    return CoreMetrics.NEW_LINE_COVERAGE;
+  }
+
+  @Override
+  protected Long countElementsForNewCode(DecoratorContext context, int periodIndex) {
+    return MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_LINES_TO_COVER), periodIndex);
+  }
+
+  @Override
+  protected long countCoveredElementsForNewCode(DecoratorContext context, int periodIndex) {
+    long uncoveredLines = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_UNCOVERED_LINES), periodIndex, 0L);
+    long lines = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_LINES_TO_COVER), periodIndex, 0L);
+    return lines - uncoveredLines;
   }
 }
index f4d560971611e179da535dcc4f7692b98ac289e6..0104f20faa5753c2f2314c91d8f12614ab79b9ac 100644 (file)
@@ -56,7 +56,7 @@ public final class NewCoverageAggregator implements Decorator {
     }
   }
 
-  private void aggregate(DecoratorContext context, Metric metric, int maxPeriods) {
+  void aggregate(DecoratorContext context, Metric metric, int maxPeriods) {
     int[] variations = {0,0,0,0,0};
     boolean[] hasValues = {false,false,false,false,false};
     for (Measure child : context.getChildrenMeasures(metric)) {
@@ -80,7 +80,7 @@ public final class NewCoverageAggregator implements Decorator {
     }
   }
 
-  private boolean shouldDecorate(Resource resource) {
+  boolean shouldDecorate(Resource resource) {
     return Scopes.isHigherThan(resource, Scopes.FILE);
   }
 }
index e98980ba776df6ad47057e354048724c40d1ae3b..2c529e87a96c591b29fa07114c3f8f5c57d35ca4 100644 (file)
@@ -31,7 +31,7 @@ import org.sonar.api.resources.Project;
 public class BranchCoverageDecoratorTest {
 
   @Test
-  public void noBranchCoverageIfMissingConditions() {
+  public void shouldNotSaveBranchCoverageIfMissingConditions() {
     Project resource = mock(Project.class);
     when(resource.getScope()).thenReturn(Project.SCOPE_SET);
     when(resource.getQualifier()).thenReturn(Project.QUALIFIER_SUBVIEW);
@@ -43,7 +43,7 @@ public class BranchCoverageDecoratorTest {
   }
 
   @Test
-  public void branchCoverage() {
+  public void shouldSaveBranchCoverage() {
     Project resource = mock(Project.class);
     when(resource.getScope()).thenReturn(Project.SCOPE_SET);
     when(resource.getQualifier()).thenReturn(Project.QUALIFIER_PROJECT);
diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/NewCoverageAggregatorTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/NewCoverageAggregatorTest.java
new file mode 100644 (file)
index 0000000..e5d7ea4
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * 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 org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.junit.Test;
+import org.mockito.Matchers;
+import org.sonar.api.batch.DecoratorContext;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.measures.Measure;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import static org.mockito.Mockito.*;
+
+public class NewCoverageAggregatorTest {
+
+  @Test
+  public void shouldNotSaveDataWhenNoMeasures() {
+    NewCoverageAggregator aggregator = new NewCoverageAggregator();
+    DecoratorContext context = mock(DecoratorContext.class);
+    when(context.getChildrenMeasures(CoreMetrics.NEW_LINES_TO_COVER)).thenReturn(Collections.<Measure>emptyList());
+
+    aggregator.aggregate(context, CoreMetrics.NEW_LINES_TO_COVER, 3);
+
+    verify(context, never()).saveMeasure(Matchers.<Measure>anyObject());
+  }
+
+  @Test
+  public void shouldNotsetZeroWhenNoValueOnPeriod() {
+    NewCoverageAggregator aggregator = new NewCoverageAggregator();
+    DecoratorContext context = mock(DecoratorContext.class);
+    when(context.getChildrenMeasures(CoreMetrics.NEW_LINES_TO_COVER)).thenReturn(Arrays.asList(newMeasure(null, 3.0, 2.0), newMeasure(null, 13.0, null)));
+
+    aggregator.aggregate(context, CoreMetrics.NEW_LINES_TO_COVER, 3);
+
+    verify(context).saveMeasure(argThat(new BaseMatcher<Measure>() {
+      public boolean matches(Object o) {
+        Measure m = (Measure)o;
+        return m.getVariation1()==null;
+      }
+
+      public void describeTo(Description description) {
+
+      }
+    }));
+  }
+
+
+  @Test
+  public void shouldSumValues() {
+    NewCoverageAggregator aggregator = new NewCoverageAggregator();
+    DecoratorContext context = mock(DecoratorContext.class);
+    when(context.getChildrenMeasures(CoreMetrics.NEW_LINES_TO_COVER)).thenReturn(Arrays.asList(newMeasure(null, 3.0, 2.0), newMeasure(null, 13.0, null)));
+
+    aggregator.aggregate(context, CoreMetrics.NEW_LINES_TO_COVER, 3);
+
+    verify(context).saveMeasure(argThat(new BaseMatcher<Measure>() {
+      public boolean matches(Object o) {
+        Measure m = (Measure)o;
+        return m.getVariation2()==16.0 && m.getVariation3()==2.0;
+      }
+
+      public void describeTo(Description description) {
+
+      }
+    }));
+  }
+
+
+  private Measure newMeasure(Double variation1, Double variation2, Double variation3) {
+    return new Measure(CoreMetrics.NEW_LINES_TO_COVER)
+        .setVariation1(variation1)
+        .setVariation2(variation2)
+        .setVariation3(variation3);
+  }
+}
index b33487af40f4815eeeb497d818455d3bc722db9a..80f9451ec421bfb5956ebde07b75f56291de03ad 100644 (file)
@@ -107,6 +107,57 @@ public final class CoreMetrics {
   public static final Metric PUBLIC_API = new Metric(PUBLIC_API_KEY, "Public API", "Public API", Metric.ValueType.INT,
       Metric.DIRECTION_WORST, false, DOMAIN_SIZE).setFormula(new SumChildValuesFormula(false));
 
+
+
+
+
+
+  //--------------------------------------------------------------------------------------------------------------------
+  //
+  // DOCUMENTATION
+  //
+  //--------------------------------------------------------------------------------------------------------------------
+
+  public static final String COMMENT_LINES_KEY = "comment_lines";
+  public static final Metric COMMENT_LINES = new Metric(COMMENT_LINES_KEY, "Comment lines", "Number of comment lines",
+      Metric.ValueType.INT, Metric.DIRECTION_BETTER, false, DOMAIN_DOCUMENTATION).setFormula(new SumChildValuesFormula(false));
+
+  public static final String COMMENT_LINES_DENSITY_KEY = "comment_lines_density";
+  public static final Metric COMMENT_LINES_DENSITY = new Metric(COMMENT_LINES_DENSITY_KEY, "Comments (%)",
+      "Comments balanced by ncloc + comment lines", Metric.ValueType.PERCENT, Metric.DIRECTION_BETTER, true, DOMAIN_DOCUMENTATION);
+
+  public static final String COMMENT_BLANK_LINES_KEY = "comment_blank_lines";
+  public static final Metric COMMENT_BLANK_LINES = new Metric(COMMENT_BLANK_LINES_KEY, "Blank comments",
+      "Comments that do not contain comments", Metric.ValueType.INT, Metric.DIRECTION_WORST, false, CoreMetrics.DOMAIN_DOCUMENTATION)
+      .setFormula(new SumChildValuesFormula(false)).setBestValue(0.0).setOptimizedBestValue(true);
+
+  public static final String PUBLIC_DOCUMENTED_API_DENSITY_KEY = "public_documented_api_density";
+  public static final Metric PUBLIC_DOCUMENTED_API_DENSITY = new Metric(PUBLIC_DOCUMENTED_API_DENSITY_KEY, "Public documented API (%)",
+      "Public documented classes and methods balanced by ncloc", Metric.ValueType.PERCENT, Metric.DIRECTION_BETTER, true,
+      DOMAIN_DOCUMENTATION).setWorstValue(0.0).setBestValue(100.0).setOptimizedBestValue(true);
+
+  public static final String PUBLIC_UNDOCUMENTED_API_KEY = "public_undocumented_api";
+  public static final Metric PUBLIC_UNDOCUMENTED_API = new Metric(PUBLIC_UNDOCUMENTED_API_KEY, "Public undocumented API",
+      "Public undocumented classes, methods and variables", Metric.ValueType.INT, Metric.DIRECTION_WORST, true, DOMAIN_DOCUMENTATION)
+      .setBestValue(0.0).setDirection(Metric.DIRECTION_WORST).setOptimizedBestValue(true).setFormula(
+          new SumChildValuesFormula(false));
+
+  public static final String COMMENTED_OUT_CODE_LINES_KEY = "commented_out_code_lines";
+  public static final Metric COMMENTED_OUT_CODE_LINES = new Metric(COMMENTED_OUT_CODE_LINES_KEY, "Commented LOCs",
+      "Commented lines of code", Metric.ValueType.INT, Metric.DIRECTION_WORST, true, DOMAIN_DOCUMENTATION).setFormula(
+      new SumChildValuesFormula(false)).setBestValue(0.0).setOptimizedBestValue(true);
+
+
+  
+
+
+
+  //--------------------------------------------------------------------------------------------------------------------
+  //
+  // COMPLEXITY
+  //
+  //--------------------------------------------------------------------------------------------------------------------
+
   public static final String COMPLEXITY_KEY = "complexity";
   public static final Metric COMPLEXITY = new Metric(COMPLEXITY_KEY, "Complexity", "Cyclomatic complexity", Metric.ValueType.INT,
       Metric.DIRECTION_WORST, false, DOMAIN_COMPLEXITY).setFormula(new SumChildValuesFormula(false));
@@ -150,37 +201,12 @@ public final class CoreMetrics {
       "Paragraph distribution /complexity", "Paragraph distribution /complexity", Metric.ValueType.DISTRIB, Metric.DIRECTION_NONE, true,
       DOMAIN_COMPLEXITY).setFormula(new SumChildDistributionFormula().setMinimumScopeToPersist(Scopes.DIRECTORY));
 
-  public static final String COMMENT_LINES_KEY = "comment_lines";
-  public static final Metric COMMENT_LINES = new Metric(COMMENT_LINES_KEY, "Comment lines", "Number of comment lines",
-      Metric.ValueType.INT, Metric.DIRECTION_BETTER, false, DOMAIN_DOCUMENTATION).setFormula(new SumChildValuesFormula(false));
-
-  public static final String COMMENT_LINES_DENSITY_KEY = "comment_lines_density";
-  public static final Metric COMMENT_LINES_DENSITY = new Metric(COMMENT_LINES_DENSITY_KEY, "Comments (%)",
-      "Comments balanced by ncloc + comment lines", Metric.ValueType.PERCENT, Metric.DIRECTION_BETTER, true, DOMAIN_DOCUMENTATION);
-
-  public static final String COMMENT_BLANK_LINES_KEY = "comment_blank_lines";
-  public static final Metric COMMENT_BLANK_LINES = new Metric(COMMENT_BLANK_LINES_KEY, "Blank comments",
-      "Comments that do not contain comments", Metric.ValueType.INT, Metric.DIRECTION_WORST, false, CoreMetrics.DOMAIN_DOCUMENTATION)
-      .setFormula(new SumChildValuesFormula(false)).setBestValue(0.0).setOptimizedBestValue(true);
-
-  public static final String PUBLIC_DOCUMENTED_API_DENSITY_KEY = "public_documented_api_density";
-  public static final Metric PUBLIC_DOCUMENTED_API_DENSITY = new Metric(PUBLIC_DOCUMENTED_API_DENSITY_KEY, "Public documented API (%)",
-      "Public documented classes and methods balanced by ncloc", Metric.ValueType.PERCENT, Metric.DIRECTION_BETTER, true,
-      DOMAIN_DOCUMENTATION).setWorstValue(0.0).setBestValue(100.0).setOptimizedBestValue(true);
-
-  public static final String PUBLIC_UNDOCUMENTED_API_KEY = "public_undocumented_api";
-  public static final Metric PUBLIC_UNDOCUMENTED_API = new Metric(PUBLIC_UNDOCUMENTED_API_KEY, "Public undocumented API",
-      "Public undocumented classes, methods and variables", Metric.ValueType.INT, Metric.DIRECTION_WORST, true, DOMAIN_DOCUMENTATION)
-      .setBestValue(0.0).setDirection(Metric.DIRECTION_WORST).setOptimizedBestValue(true).setFormula(
-          new SumChildValuesFormula(false));
-
-  public static final String COMMENTED_OUT_CODE_LINES_KEY = "commented_out_code_lines";
-  public static final Metric COMMENTED_OUT_CODE_LINES = new Metric(COMMENTED_OUT_CODE_LINES_KEY, "Commented LOCs",
-      "Commented lines of code", Metric.ValueType.INT, Metric.DIRECTION_WORST, true, DOMAIN_DOCUMENTATION).setFormula(
-      new SumChildValuesFormula(false)).setBestValue(0.0).setOptimizedBestValue(true);
-
 
+  //--------------------------------------------------------------------------------------------------------------------
+  //
   // UNIT TESTS
+  //
+  //--------------------------------------------------------------------------------------------------------------------
 
   public static final String TESTS_KEY = "tests";
   public static final Metric TESTS = new Metric(TESTS_KEY, "Unit tests", "Number of unit tests", Metric.ValueType.INT,
@@ -217,8 +243,26 @@ public final class CoreMetrics {
       Metric.DIRECTION_WORST, false, DOMAIN_TESTS);
 
   public static final String COVERAGE_KEY = "coverage";
-  public static final Metric COVERAGE = new Metric(COVERAGE_KEY, "Coverage", "Coverage by unit tests", Metric.ValueType.PERCENT,
-      Metric.DIRECTION_BETTER, true, DOMAIN_TESTS).setWorstValue(0.0).setBestValue(100.0);
+  public static final Metric COVERAGE = new Metric.Builder(COVERAGE_KEY, Metric.ValueType.PERCENT)
+      .setName("Coverage")
+      .setDescription("Coverage by unit tests")
+      .setDirection(Metric.DIRECTION_BETTER)
+      .setQualitative(true)
+      .setDomain(DOMAIN_TESTS)
+      .setWorstValue(0.0)
+      .setBestValue(100.0)
+      .create();
+
+  public static final String NEW_COVERAGE_KEY = "new_coverage";
+  public static final Metric NEW_COVERAGE = new Metric.Builder(NEW_COVERAGE_KEY, Metric.ValueType.PERCENT)
+      .setName("New coverage")
+      .setDescription("Coverage of new/changed code")
+      .setDirection(Metric.DIRECTION_BETTER)
+      .setQualitative(true)
+      .setDomain(DOMAIN_TESTS)
+      .setWorstValue(0.0)
+      .setBestValue(100.0)
+      .create();
 
   public static final String LINES_TO_COVER_KEY = "lines_to_cover";
   public static final Metric LINES_TO_COVER = new Metric(LINES_TO_COVER_KEY, "Lines to cover", "Lines to cover", Metric.ValueType.INT,
@@ -253,8 +297,24 @@ public final class CoreMetrics {
       .create();
 
   public static final String LINE_COVERAGE_KEY = "line_coverage";
-  public static final Metric LINE_COVERAGE = new Metric(LINE_COVERAGE_KEY, "Line coverage", "Line coverage", Metric.ValueType.PERCENT,
-      Metric.DIRECTION_BETTER, true, DOMAIN_TESTS);
+  public static final Metric LINE_COVERAGE = new Metric.Builder(LINE_COVERAGE_KEY, Metric.ValueType.PERCENT)
+      .setName("Line coverage")
+      .setDescription("Line coverage")
+      .setDirection(Metric.DIRECTION_BETTER)
+      .setQualitative(true)
+      .setDomain(DOMAIN_TESTS)
+      .create();
+
+  public static final String NEW_LINE_COVERAGE_KEY = "new_line_coverage";
+  public static final Metric NEW_LINE_COVERAGE = new Metric.Builder(NEW_LINE_COVERAGE_KEY, Metric.ValueType.PERCENT)
+      .setName("New line coverage")
+      .setDescription("Line coverage of added/changed code")
+      .setDirection(Metric.DIRECTION_BETTER)
+      .setQualitative(true)
+      .setWorstValue(0.0)
+      .setBestValue(100.0)
+      .setDomain(DOMAIN_TESTS)
+      .create();
 
   public static final String COVERAGE_LINE_HITS_DATA_KEY = "coverage_line_hits_data";
   public static final Metric COVERAGE_LINE_HITS_DATA = new Metric.Builder(COVERAGE_LINE_HITS_DATA_KEY, Metric.ValueType.DATA)
@@ -308,6 +368,17 @@ public final class CoreMetrics {
       .setBestValue(100.0)
       .create();
 
+  public static final String NEW_BRANCH_COVERAGE_KEY = "new_branch_coverage";
+  public static final Metric NEW_BRANCH_COVERAGE = new Metric.Builder(NEW_BRANCH_COVERAGE_KEY, Metric.ValueType.PERCENT)
+      .setName("NEw branch coverage")
+      .setDescription("Branch coverage of new/changed code")
+      .setDirection(Metric.DIRECTION_BETTER)
+      .setQualitative(true)
+      .setDomain(DOMAIN_TESTS)
+      .setWorstValue(0.0)
+      .setBestValue(100.0)
+      .create();
+
   @Deprecated
   public static final String BRANCH_COVERAGE_HITS_DATA_KEY = "branch_coverage_hits_data";
 
@@ -339,6 +410,12 @@ public final class CoreMetrics {
       .create();
 
 
+  //--------------------------------------------------------------------------------------------------------------------
+  //
+  // DUPLICATIONS
+  //
+  //--------------------------------------------------------------------------------------------------------------------
+
   public static final String DUPLICATED_LINES_KEY = "duplicated_lines";
   public static final Metric DUPLICATED_LINES = new Metric(DUPLICATED_LINES_KEY, "Duplicated lines", "Duplicated lines",
       Metric.ValueType.INT, Metric.DIRECTION_WORST, false, DOMAIN_DUPLICATION).setBestValue(0.0).setOptimizedBestValue(true);
@@ -360,7 +437,12 @@ public final class CoreMetrics {
   public static final Metric DUPLICATIONS_DATA = new Metric(DUPLICATIONS_DATA_KEY, "Duplications details", "Duplications details",
       Metric.ValueType.DATA, Metric.DIRECTION_NONE, false, DOMAIN_DUPLICATION);
 
-  /* coding rules */
+
+  //--------------------------------------------------------------------------------------------------------------------
+  //
+  // CODING RULES
+  //
+  //--------------------------------------------------------------------------------------------------------------------
   /**
    * @deprecated since 2.5 See http://jira.codehaus.org/browse/SONAR-2007
    */
@@ -483,7 +565,11 @@ public final class CoreMetrics {
       Metric.ValueType.INT, Metric.DIRECTION_WORST, true, DOMAIN_RULES).setHidden(true).setBestValue(0.0).setOptimizedBestValue(true);
 
 
+  //--------------------------------------------------------------------------------------------------------------------
+  //
   // DESIGN
+  //
+  //--------------------------------------------------------------------------------------------------------------------
 
   public static final String ABSTRACTNESS_KEY = "abstractness";
   public static final Metric ABSTRACTNESS = new Metric(ABSTRACTNESS_KEY, "Abstractness", "Abstractness", Metric.ValueType.PERCENT,
@@ -582,25 +668,12 @@ public final class CoreMetrics {
       Metric.ValueType.INT, Metric.DIRECTION_BETTER, false, DOMAIN_DESIGN).setHidden(true);
 
 
-  // Alerts
-  public static final String ALERT_STATUS_KEY = "alert_status";
-  public static final Metric ALERT_STATUS = new Metric.Builder(ALERT_STATUS_KEY, Metric.ValueType.LEVEL)
-      .setName("Alert")
-      .setDescription("Alert")
-      .setDirection(Metric.DIRECTION_BETTER)
-      .setQualitative(true)
-      .setDomain(DOMAIN_GENERAL)
-      .create();
-
-
-  /* quality profile */
-  public static final String PROFILE_KEY = "profile";
-  public static final Metric PROFILE = new Metric(PROFILE_KEY, "Profile", "Selected quality profile", Metric.ValueType.DATA,
-      Metric.DIRECTION_NONE, false, DOMAIN_GENERAL);
-
-
+  //--------------------------------------------------------------------------------------------------------------------
+  //
   // SCM
   // These metrics are computed by the SCM Activity plugin, since version 1.2.
+  //
+  //--------------------------------------------------------------------------------------------------------------------
 
   public static final String SCM_COMMITS_KEY = "commits";
   public static final Metric SCM_COMMITS = new Metric.Builder(SCM_COMMITS_KEY, Metric.ValueType.INT)
@@ -635,6 +708,27 @@ public final class CoreMetrics {
       .setDomain(DOMAIN_SCM)
       .create();
 
+
+  //--------------------------------------------------------------------------------------------------------------------
+  //
+  // OTHERS
+  //
+  //--------------------------------------------------------------------------------------------------------------------
+  public static final String ALERT_STATUS_KEY = "alert_status";
+  public static final Metric ALERT_STATUS = new Metric.Builder(ALERT_STATUS_KEY, Metric.ValueType.LEVEL)
+      .setName("Alert")
+      .setDescription("Alert")
+      .setDirection(Metric.DIRECTION_BETTER)
+      .setQualitative(true)
+      .setDomain(DOMAIN_GENERAL)
+      .create();
+
+
+  public static final String PROFILE_KEY = "profile";
+  public static final Metric PROFILE = new Metric(PROFILE_KEY, "Profile", "Selected quality profile", Metric.ValueType.DATA,
+      Metric.DIRECTION_NONE, false, DOMAIN_GENERAL);
+
+
   public static List<Metric> metrics = Lists.newLinkedList();
 
   public static List<Metric> getMetrics() {