]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-7957 New metric « New Lines of Code » 1144/head
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Fri, 12 Aug 2016 15:53:09 +0000 (17:53 +0200)
committerTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Sat, 13 Aug 2016 10:08:39 +0000 (12:08 +0200)
it/it-tests/src/test/java/it/dbCleaner/PurgeTest.java
server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/NewLinesMeasureStep.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/ReportComputationSteps.java
server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ReportNewLinesMeasureStepTest.java [new file with mode: 0644]
sonar-core/src/main/resources/org/sonar/l10n/core.properties
sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java
sonar-plugin-api/src/test/java/org/sonar/api/resources/CoreMetricsTest.java

index 73cade69b6f5eca3a84e12903dad8db91019df66..3891af3855fc4b9bf6897dce4403ebc1072c00c8 100644 (file)
@@ -115,10 +115,10 @@ public class PurgeTest {
     // must be a different date, else a single snapshot is kept per day
     scan(PROJECT_SAMPLE_PATH, DateFormatUtils.ISO_DATE_FORMAT.format(today));
 
-    int newMeasuresOnTrk = 55;
-    int newMeasuresOnBrc = 286;
-    int newMeasuresOnDir = 44;
-    int newMeasuresOnFil = 0;
+    int newMeasuresOnTrk = 56;
+    int newMeasuresOnBrc = 292;
+    int newMeasuresOnDir = 48;
+    int newMeasuresOnFil = 4;
 
     assertMeasuresCountForQualifier("TRK", measuresOnTrk + newMeasuresOnTrk);
     assertMeasuresCountForQualifier("BRC", measuresOnBrc + newMeasuresOnBrc);
@@ -129,7 +129,7 @@ public class PurgeTest {
     collector.checkThat(
       "Wrong number of measure of new_ metrics",
       count("project_measures, metrics where metrics.id = project_measures.metric_id and metrics.name like 'new_%'"),
-      equalTo(121));
+      equalTo(136));
 
     // added measures relate to project and new_* metrics
     expectedMeasures += newMeasuresOnTrk + newMeasuresOnBrc + newMeasuresOnDir + newMeasuresOnFil;
@@ -256,8 +256,9 @@ public class PurgeTest {
 
     scan(PROJECT_SAMPLE_PATH, "2012-02-02");
 
-    assertThat(count(COUNT_FILE_MEASURES)).isEqualTo(fileMeasures);
-    assertThat(count(COUNT_DIR_MEASURES)).isLessThan(2 * dirMeasures); // second analysis as NEW_* metrics
+    // second analysis with new_* metrics
+    assertThat(count(COUNT_FILE_MEASURES)).isLessThan(2 * fileMeasures);
+    assertThat(count(COUNT_DIR_MEASURES)).isLessThan(2 * dirMeasures);
   }
 
   /**
@@ -274,8 +275,9 @@ public class PurgeTest {
 
     scan(PROJECT_SAMPLE_PATH, "2012-02-02");
 
-    assertThat(count(COUNT_FILE_MEASURES)).isEqualTo(fileMeasures);
-    assertThat(count(COUNT_DIR_MEASURES)).isGreaterThan(2 * dirMeasures); // second analysis as NEW_* metrics
+    // second analysis as NEW_* metrics
+    assertThat(count(COUNT_FILE_MEASURES)).isLessThan( 2 * fileMeasures);
+    assertThat(count(COUNT_DIR_MEASURES)).isGreaterThan(2 * dirMeasures);
   }
 
   /**
@@ -359,8 +361,8 @@ public class PurgeTest {
   private void logMeasures(String title, String qualifier) {
     String sql = "SELECT m.name as metricName, pm.value as value, pm.text_value as textValue, pm.variation_value_1, pm.variation_value_2, pm.variation_value_3 "
       +
-      "FROM project_measures pm, snapshots s, metrics m " +
-      "WHERE pm.snapshot_id=s.id and pm.metric_id=m.id and s.qualifier='"
+      "FROM project_measures pm, projects p, metrics m " +
+      "WHERE pm.component_uuid=p.uuid and pm.metric_id=m.id and p.qualifier='"
       + qualifier + "'";
     List<Map<String, String>> rows = orchestrator.getDatabase().executeSql(sql);
 
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/NewLinesMeasureStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/NewLinesMeasureStep.java
new file mode 100644 (file)
index 0000000..f05bad7
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.computation.task.projectanalysis.step;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import java.util.Map;
+import org.sonar.api.utils.KeyValueFormat;
+import org.sonar.core.util.stream.Collectors;
+import org.sonar.server.computation.task.projectanalysis.component.Component;
+import org.sonar.server.computation.task.projectanalysis.component.PathAwareCrawler;
+import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolder;
+import org.sonar.server.computation.task.projectanalysis.formula.Counter;
+import org.sonar.server.computation.task.projectanalysis.formula.CounterInitializationContext;
+import org.sonar.server.computation.task.projectanalysis.formula.CreateMeasureContext;
+import org.sonar.server.computation.task.projectanalysis.formula.Formula;
+import org.sonar.server.computation.task.projectanalysis.formula.FormulaExecutorComponentVisitor;
+import org.sonar.server.computation.task.projectanalysis.formula.counter.IntVariationValue;
+import org.sonar.server.computation.task.projectanalysis.measure.Measure;
+import org.sonar.server.computation.task.projectanalysis.measure.MeasureRepository;
+import org.sonar.server.computation.task.projectanalysis.measure.MeasureVariations;
+import org.sonar.server.computation.task.projectanalysis.metric.Metric;
+import org.sonar.server.computation.task.projectanalysis.metric.MetricRepository;
+import org.sonar.server.computation.task.projectanalysis.period.Period;
+import org.sonar.server.computation.task.projectanalysis.period.PeriodsHolder;
+import org.sonar.server.computation.task.projectanalysis.scm.Changeset;
+import org.sonar.server.computation.task.projectanalysis.scm.ScmInfo;
+import org.sonar.server.computation.task.projectanalysis.scm.ScmInfoRepository;
+import org.sonar.server.computation.task.step.ComputationStep;
+
+import static org.sonar.api.measures.CoreMetrics.NCLOC_DATA_KEY;
+import static org.sonar.api.measures.CoreMetrics.NEW_NCLOC_KEY;
+import static org.sonar.api.utils.KeyValueFormat.newIntegerConverter;
+
+/**
+ * Computes new lines of code measure on files and then aggregates them on higher components.
+ */
+public class NewLinesMeasureStep implements ComputationStep {
+
+  private final TreeRootHolder treeRootHolder;
+  private final PeriodsHolder periodsHolder;
+  private final MetricRepository metricRepository;
+  private final MeasureRepository measureRepository;
+  private final ScmInfoRepository scmInfoRepository;
+
+  public NewLinesMeasureStep(TreeRootHolder treeRootHolder, PeriodsHolder periodsHolder, MetricRepository metricRepository, MeasureRepository measureRepository,
+    ScmInfoRepository scmInfoRepository) {
+    this.treeRootHolder = treeRootHolder;
+    this.periodsHolder = periodsHolder;
+    this.metricRepository = metricRepository;
+    this.measureRepository = measureRepository;
+    this.scmInfoRepository = scmInfoRepository;
+  }
+
+  @Override
+  public String getDescription() {
+    return "Compute new lines of code";
+  }
+
+  @Override
+  public void execute() {
+    new PathAwareCrawler<>(
+      FormulaExecutorComponentVisitor.newBuilder(metricRepository, measureRepository)
+        .withVariationSupport(periodsHolder)
+        .buildFor(ImmutableList.of(new NewLinesFormula(measureRepository, scmInfoRepository, metricRepository.getByKey(NCLOC_DATA_KEY)))))
+          .visit(treeRootHolder.getRoot());
+  }
+
+  private static class NewLinesCounter implements Counter<NewLinesCounter> {
+    private final MeasureRepository measureRepository;
+    private final ScmInfoRepository scmInfoRepository;
+    private final Metric nclocDataMetric;
+
+    private final IntVariationValue.Array newLines = IntVariationValue.newArray();
+
+    private NewLinesCounter(MeasureRepository measureRepository, ScmInfoRepository scmInfoRepository, Metric nclocDataMetric) {
+      this.measureRepository = measureRepository;
+      this.scmInfoRepository = scmInfoRepository;
+      this.nclocDataMetric = nclocDataMetric;
+    }
+
+    @Override
+    public void aggregate(NewLinesCounter counter) {
+      this.newLines.incrementAll(counter.newLines);
+    }
+
+    @Override
+    public void initialize(CounterInitializationContext context) {
+      context.getPeriods().forEach(period -> newLines.increment(period, 0));
+
+      Component leak = context.getLeaf();
+      if (leak.getType() != Component.Type.FILE) {
+        return;
+      }
+
+      Optional<ScmInfo> optionalScmInfo = scmInfoRepository.getScmInfo(leak);
+      Optional<Measure> nclocData = measureRepository.getRawMeasure(leak, nclocDataMetric);
+
+      if (!nclocData.isPresent() || !optionalScmInfo.isPresent()) {
+        return;
+      }
+
+      ScmInfo scmInfo = optionalScmInfo.get();
+
+      nclocLineNumbers(nclocData.get()).stream()
+        .map(scmInfo::getChangesetForLine)
+        .forEach(changeset -> context.getPeriods().stream()
+          .filter(period -> isLineInPeriod(changeset, period))
+          .forEach(period -> newLines.increment(period, 1)));
+    }
+
+    /**
+     * NCLOC_DATA contains Key-value pairs, where key - is a line number, and value - is an indicator of whether line
+     * contains code (1) or not (0).
+     *
+     * This method parses the value of the NCLOC_DATA measure and return the line numbers which contain code.
+     */
+    private static List<Integer> nclocLineNumbers(Measure nclocDataMeasure) {
+      Map<Integer, Integer> parsedNclocData = KeyValueFormat.parse(nclocDataMeasure.getData(), newIntegerConverter(), newIntegerConverter());
+      return parsedNclocData.entrySet()
+        .stream()
+        .filter(entry -> entry.getValue() == 1)
+        .map(Map.Entry::getKey)
+        .collect(Collectors.toList());
+    }
+
+    private static boolean isLineInPeriod(Changeset changeset, Period period) {
+      return changeset.getDate() > period.getSnapshotDate();
+    }
+  }
+
+  private static final class NewLinesFormula implements Formula<NewLinesCounter> {
+    private final MeasureRepository measureRepository;
+    private final ScmInfoRepository scmInfoRepository;
+    private final Metric nclocDataMetric;
+
+    private NewLinesFormula(MeasureRepository measureRepository, ScmInfoRepository scmInfoRepository, Metric nclocDataMetric) {
+      this.measureRepository = measureRepository;
+      this.scmInfoRepository = scmInfoRepository;
+      this.nclocDataMetric = nclocDataMetric;
+    }
+
+    @Override
+    public NewLinesCounter createNewCounter() {
+      return new NewLinesCounter(measureRepository, scmInfoRepository, nclocDataMetric);
+    }
+
+    @Override
+    public Optional<Measure> createMeasure(NewLinesCounter counter, CreateMeasureContext context) {
+      String metricKey = context.getMetric().getKey();
+      if (NEW_NCLOC_KEY.equals(metricKey)) {
+        Optional<MeasureVariations> newLines = counter.newLines.toMeasureVariations();
+        return newLines.isPresent()
+          ? Optional.of(Measure.newMeasureBuilder().setVariations(newLines.get()).createNoValue())
+          : Optional.absent();
+      }
+
+      throw new IllegalArgumentException("Unsupported metric " + context.getMetric());
+    }
+
+    @Override
+    public String[] getOutputMetricKeys() {
+      return new String[] {NEW_NCLOC_KEY};
+    }
+  }
+}
index 7785c691bd2a865508c83efa10727226719d5b81..e9038735573480d949d1b3c0f2e1bd0a2ce27085 100644 (file)
@@ -59,6 +59,7 @@ public class ReportComputationSteps extends AbstractComputationSteps {
 
     // data computation
     SizeMeasuresStep.class,
+    NewLinesMeasureStep.class,
     NewCoverageMeasuresStep.class,
     CoverageMeasuresStep.class,
     CommentMeasuresStep.class,
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ReportNewLinesMeasureStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ReportNewLinesMeasureStepTest.java
new file mode 100644 (file)
index 0000000..a9adc37
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.computation.task.projectanalysis.step;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.utils.KeyValueFormat;
+import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolderRule;
+import org.sonar.server.computation.task.projectanalysis.measure.Measure;
+import org.sonar.server.computation.task.projectanalysis.measure.MeasureRepositoryRule;
+import org.sonar.server.computation.task.projectanalysis.measure.MeasureVariations;
+import org.sonar.server.computation.task.projectanalysis.metric.MetricRepositoryRule;
+import org.sonar.server.computation.task.projectanalysis.period.Period;
+import org.sonar.server.computation.task.projectanalysis.period.PeriodsHolderRule;
+import org.sonar.server.computation.task.projectanalysis.scm.Changeset;
+import org.sonar.server.computation.task.projectanalysis.scm.ScmInfoRepositoryRule;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.api.measures.CoreMetrics.NCLOC_DATA;
+import static org.sonar.api.measures.CoreMetrics.NCLOC_DATA_KEY;
+import static org.sonar.api.measures.CoreMetrics.NEW_NCLOC;
+import static org.sonar.api.measures.CoreMetrics.NEW_NCLOC_KEY;
+import static org.sonar.api.utils.DateUtils.parseDate;
+import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.DIRECTORY;
+import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.FILE;
+import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.MODULE;
+import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.PROJECT;
+import static org.sonar.server.computation.task.projectanalysis.component.ReportComponent.builder;
+
+public class ReportNewLinesMeasureStepTest {
+  private static final int ROOT_REF = 1;
+  private static final int MODULE_REF = 12;
+  private static final int SUB_MODULE_1_REF = 123;
+  private static final int SUB_MODULE_2_REF = 126;
+  private static final int DIRECTORY_REF = 1234;
+  private static final int DIRECTORY_2_REF = 1235;
+  private static final int FILE_1_REF = 12341;
+  private static final int FILE_2_REF = 12342;
+  private static final int FILE_3_REF = 1261;
+  private static final int FILE_4_REF = 1262;
+
+  @Rule
+  public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule()
+    .setRoot(
+      builder(PROJECT, ROOT_REF)
+        .addChildren(
+          builder(MODULE, MODULE_REF)
+            .addChildren(
+              builder(MODULE, SUB_MODULE_1_REF)
+                .addChildren(
+                  builder(DIRECTORY, DIRECTORY_REF)
+                    .addChildren(
+                      builder(FILE, FILE_1_REF).build(),
+                      builder(FILE, FILE_2_REF).build())
+                    .build(),
+                  builder(DIRECTORY, DIRECTORY_2_REF).build())
+                .build(),
+              builder(MODULE, SUB_MODULE_2_REF)
+                .addChildren(
+                  builder(FILE, FILE_3_REF).build(),
+                  builder(FILE, FILE_4_REF).build())
+                .build())
+            .build())
+        .build());
+  @Rule
+  public PeriodsHolderRule periodsHolder = new PeriodsHolderRule().setPeriods(
+    new Period(2, "mode_p_1", null, parseDate("2009-12-25").getTime(), "u1"),
+    new Period(5, "mode_p_5", null, parseDate("2011-02-18").getTime(), "u2"));
+  @Rule
+  public ScmInfoRepositoryRule scmInfoRepository = new ScmInfoRepositoryRule();
+  @Rule
+  public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
+    .add(NEW_NCLOC)
+    .add(NCLOC_DATA);
+  @Rule
+  public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
+
+  NewLinesMeasureStep underTest = new NewLinesMeasureStep(treeRootHolder, periodsHolder, metricRepository, measureRepository, scmInfoRepository);
+
+  @Test
+  public void compute_new_ncloc() {
+    setChangesets(FILE_1_REF, FILE_2_REF, FILE_3_REF, FILE_4_REF);
+    setNclocsExcept(FILE_1_REF, 2, 4, 6);
+    setNclocsExcept(FILE_2_REF);
+    setNclocsExcept(FILE_3_REF, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
+    setNclocsExcept(FILE_4_REF, 1, 2);
+
+    underTest.execute();
+
+    assertRawMeasureValue(FILE_1_REF, NEW_NCLOC_KEY, 12 - 1 - 3);
+    assertRawMeasureValue(FILE_2_REF, NEW_NCLOC_KEY, 12 - 1);
+    assertRawMeasureValue(FILE_3_REF, NEW_NCLOC_KEY, 0);
+    assertRawMeasureValue(FILE_4_REF, NEW_NCLOC_KEY, 12 - 1 - 2);
+    assertRawMeasureValue(DIRECTORY_REF, NEW_NCLOC_KEY, 19);
+    assertRawMeasureValue(DIRECTORY_2_REF, NEW_NCLOC_KEY, 0);
+    assertRawMeasureValue(SUB_MODULE_1_REF, NEW_NCLOC_KEY, 19);
+    assertRawMeasureValue(SUB_MODULE_2_REF, NEW_NCLOC_KEY, 9);
+    assertRawMeasureValue(MODULE_REF, NEW_NCLOC_KEY, 28);
+    assertRawMeasureValue(ROOT_REF, NEW_NCLOC_KEY, 28);
+  }
+
+  @Test
+  public void compute_with_no_changeset() {
+    setNclocsExcept(FILE_1_REF);
+
+    underTest.execute();
+
+    assertNoRawMeasureValue();
+  }
+
+  @Test
+  public void compute_with_no_ncloc_data() {
+    underTest.execute();
+
+    assertNoRawMeasureValue();
+  }
+
+  private void assertNoRawMeasureValue() {
+    assertRawMeasureValue(FILE_1_REF, NEW_NCLOC_KEY, 0);
+    assertRawMeasureValue(FILE_2_REF, NEW_NCLOC_KEY, 0);
+    assertRawMeasureValue(FILE_3_REF, NEW_NCLOC_KEY, 0);
+    assertRawMeasureValue(FILE_4_REF, NEW_NCLOC_KEY, 0);
+    assertRawMeasureValue(DIRECTORY_REF, NEW_NCLOC_KEY, 0);
+    assertRawMeasureValue(DIRECTORY_2_REF, NEW_NCLOC_KEY, 0);
+    assertRawMeasureValue(SUB_MODULE_1_REF, NEW_NCLOC_KEY, 0);
+    assertRawMeasureValue(SUB_MODULE_2_REF, NEW_NCLOC_KEY, 0);
+    assertRawMeasureValue(MODULE_REF, NEW_NCLOC_KEY, 0);
+    assertRawMeasureValue(ROOT_REF, NEW_NCLOC_KEY, 0);
+  }
+
+  private void assertRawMeasureValue(int componentRef, String metricKey, double period2Value) {
+    assertRawMeasureValue(componentRef, metricKey, period2Value, 0d);
+  }
+
+  private void assertRawMeasureValue(int componentRef, String metricKey, double period2Value, double period5Value) {
+    MeasureVariations variations = measureRepository.getAddedRawMeasure(componentRef, metricKey).get().getVariations();
+    assertThat(variations.getVariation2()).isEqualTo(period2Value);
+    assertThat(variations.getVariation5()).isEqualTo(period5Value);
+  }
+
+  private void setNclocsExcept(int componentRef, Integer... lineNumbersNotLineOfCode) {
+    List<Integer> notLocNumbers = Arrays.asList(lineNumbersNotLineOfCode);
+    Map<Integer, Integer> nclocData = IntStream.rangeClosed(1, 12)
+      .filter(lineNumber -> !notLocNumbers.contains(lineNumber))
+      .boxed()
+      .collect(Collectors.toMap(Function.identity(), lineNumber -> 1));
+    measureRepository.addRawMeasure(componentRef, NCLOC_DATA_KEY, Measure.newMeasureBuilder().create(KeyValueFormat.format(nclocData)));
+  }
+
+  private void setChangesets(int... componentRefs) {
+    Arrays.stream(componentRefs)
+      .forEach(componentRef -> scmInfoRepository.setScmInfo(componentRef,
+        Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build(),
+        Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build(),
+        // line 3 is older, part of no period
+        Changeset.newChangesetBuilder().setDate(parseDate("2007-01-15").getTime()).setRevision("rev-2").build(),
+        Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build(),
+        Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build(),
+        Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build(),
+        Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build(),
+        Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build(),
+        Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build(),
+        Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build(),
+        Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build(),
+        Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build()));
+  }
+
+}
index 2fe6894a9fb92880e65b6dd90d4ef807063e4b12..dd6158fd3e292b38d50ba0e12be87212a9b3c291 100644 (file)
@@ -2455,7 +2455,7 @@ metric.major_violations.name=Major Issues
 metric.minor_violations.description=Minor issues
 metric.minor_violations.name=Minor Issues
 metric.ncloc.abbreviation=LOC
-metric.ncloc.description=Non Commenting Lines of Code
+metric.ncloc.description=Non commenting lines of code
 metric.ncloc.name=Lines of Code
 metric.ncloc_language_distribution.description=Non Commenting Lines of Code Distributed By Language
 metric.ncloc_language_distribution.name=Lines of Code Per Language
@@ -2501,6 +2501,8 @@ metric.new_major_violations.description=New Major issues
 metric.new_major_violations.name=New Major Issues
 metric.new_minor_violations.description=New Minor issues
 metric.new_minor_violations.name=New Minor Issues
+metric.new_ncloc.name=New Lines of Code
+metric.new_ncloc.description=New non commenting lines of code
 metric.new_overall_branch_coverage.description=Condition coverage of new/changed code by all tests
 metric.new_overall_branch_coverage.name=Overall Condition Coverage on New Code
 metric.new_overall_conditions_to_cover.description=New conditions to cover by all tests
index a576efb753021aa5b7ca8b1b221baca397783f0a..58bce43ac4b57c6b220bcbde53c64df6c512f9b9 100644 (file)
@@ -123,12 +123,27 @@ public final class CoreMetrics {
 
   public static final String NCLOC_KEY = "ncloc";
   public static final Metric<Integer> NCLOC = new Metric.Builder(NCLOC_KEY, "Lines of Code", Metric.ValueType.INT)
-    .setDescription("Non Commenting Lines of Code")
+    .setDescription("Non commenting lines of code")
     .setDirection(Metric.DIRECTION_WORST)
     .setQualitative(false)
     .setDomain(DOMAIN_SIZE)
     .create();
 
+  /**
+   * @since 6.1
+   */
+  public static final String NEW_NCLOC_KEY = "new_ncloc";
+  /**
+   * @since 6.1
+   */
+  public static final Metric<Integer> NEW_NCLOC = new Metric.Builder(NEW_NCLOC_KEY, "New Lines of Code", Metric.ValueType.INT)
+    .setDescription("New non commenting lines of code")
+    .setDirection(Metric.DIRECTION_WORST)
+    .setQualitative(false)
+    .setDomain(DOMAIN_SIZE)
+    .setDeleteHistoricalData(true)
+    .create();
+
   /**
    * @since 4.4
    */
@@ -1314,7 +1329,13 @@ public final class CoreMetrics {
     .setOptimizedBestValue(true)
     .create();
 
+  /**
+   * @since 6.1
+   */
   public static final String NEW_LINES_DUPLICATED_KEY = "new_duplicated_lines";
+  /**
+   * @since 6.1
+   */
   public static final Metric<Integer> NEW_LINES_DUPLICATED = new Metric.Builder(NEW_LINES_DUPLICATED_KEY, "New Duplicated Lines", Metric.ValueType.INT)
     .setDescription("New duplicated lines")
     .setDirection(Metric.DIRECTION_WORST)
@@ -1334,7 +1355,13 @@ public final class CoreMetrics {
     .setOptimizedBestValue(true)
     .create();
 
+  /**
+   * @since 6.1
+    */
   public static final String NEW_BLOCKS_DUPLICATED_KEY = "new_duplicated_blocks";
+  /**
+   * @since 6.1
+   */
   public static final Metric<Integer> NEW_BLOCKS_DUPLICATED = new Metric.Builder(NEW_BLOCKS_DUPLICATED_KEY, "Duplicated Blocks on New Code", Metric.ValueType.INT)
     .setDescription("Duplicated blocks on new code")
     .setDirection(Metric.DIRECTION_WORST)
index e82d793431a4a51765a59c8a535ff24819e6646a..854cef24431c0d0bfa2ce21a70c46e7b88d61c9d 100644 (file)
  */
 package org.sonar.api.resources;
 
+import java.util.List;
 import org.junit.Test;
 import org.sonar.api.measures.CoreMetrics;
 import org.sonar.api.measures.Metric;
 
-import java.util.List;
-
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class CoreMetricsTest {