From 062c27d9de4d892209dc05087ae3dc68e0b93cb4 Mon Sep 17 00:00:00 2001 From: Teryk Bellahsene Date: Fri, 12 Aug 2016 17:53:09 +0200 Subject: [PATCH] =?utf8?q?SONAR-7957=20New=20metric=20=C2=AB=20New=20Lines?= =?utf8?q?=20of=20Code=20=C2=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- .../src/test/java/it/dbCleaner/PurgeTest.java | 24 ++- .../step/NewLinesMeasureStep.java | 185 +++++++++++++++++ .../step/ReportComputationSteps.java | 1 + .../step/ReportNewLinesMeasureStepTest.java | 192 ++++++++++++++++++ .../resources/org/sonar/l10n/core.properties | 4 +- .../org/sonar/api/measures/CoreMetrics.java | 29 ++- .../sonar/api/resources/CoreMetricsTest.java | 3 +- 7 files changed, 423 insertions(+), 15 deletions(-) create mode 100644 server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/NewLinesMeasureStep.java create mode 100644 server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ReportNewLinesMeasureStepTest.java diff --git a/it/it-tests/src/test/java/it/dbCleaner/PurgeTest.java b/it/it-tests/src/test/java/it/dbCleaner/PurgeTest.java index 73cade69b6f..3891af3855f 100644 --- a/it/it-tests/src/test/java/it/dbCleaner/PurgeTest.java +++ b/it/it-tests/src/test/java/it/dbCleaner/PurgeTest.java @@ -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> 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 index 00000000000..f05bad753f9 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/NewLinesMeasureStep.java @@ -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 { + 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 optionalScmInfo = scmInfoRepository.getScmInfo(leak); + Optional 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 nclocLineNumbers(Measure nclocDataMeasure) { + Map 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 { + 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 createMeasure(NewLinesCounter counter, CreateMeasureContext context) { + String metricKey = context.getMetric().getKey(); + if (NEW_NCLOC_KEY.equals(metricKey)) { + Optional 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}; + } + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/ReportComputationSteps.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/ReportComputationSteps.java index 7785c691bd2..e9038735573 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/ReportComputationSteps.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/ReportComputationSteps.java @@ -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 index 00000000000..a9adc37aa05 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ReportNewLinesMeasureStepTest.java @@ -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 notLocNumbers = Arrays.asList(lineNumbersNotLineOfCode); + Map 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())); + } + +} diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index 2fe6894a9fb..dd6158fd3e2 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -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 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 a576efb7530..58bce43ac4b 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 @@ -123,12 +123,27 @@ public final class CoreMetrics { public static final String NCLOC_KEY = "ncloc"; public static final Metric 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 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 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 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) diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/resources/CoreMetricsTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/resources/CoreMetricsTest.java index e82d793431a..854cef24431 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/resources/CoreMetricsTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/resources/CoreMetricsTest.java @@ -19,12 +19,11 @@ */ 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 { -- 2.39.5