From: Julien Lancelot Date: Mon, 20 Jul 2015 14:14:39 +0000 (+0200) Subject: SONAR-6679 Move computation of language ditribution measures to CE X-Git-Tag: 5.2-RC1~1051 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=refs%2Fpull%2F424%2Fhead;p=sonarqube.git SONAR-6679 Move computation of language ditribution measures to CE --- diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java index b1379fb1f6c..943746e11e5 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java @@ -60,6 +60,7 @@ public class ComputationSteps { // must be executed after the measures required for common rules (coverage, comment density, duplications) IntegrateIssuesStep.class, CoreMetricFormulaExecutorStep.class, + LanguageDistributionMeasuresStep.class, // SQALE measures depend on issues SqaleMeasuresStep.class, diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/LanguageDistributionMeasuresStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/LanguageDistributionMeasuresStep.java new file mode 100644 index 00000000000..d8b2d54f0cc --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/LanguageDistributionMeasuresStep.java @@ -0,0 +1,130 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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.step; + +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Multiset; +import com.google.common.collect.TreeMultiset; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.server.computation.component.TreeRootHolder; +import org.sonar.server.computation.formula.Counter; +import org.sonar.server.computation.formula.CreateMeasureContext; +import org.sonar.server.computation.formula.FileAggregateContext; +import org.sonar.server.computation.formula.Formula; +import org.sonar.server.computation.formula.FormulaExecutorComponentVisitor; +import org.sonar.server.computation.measure.Measure; +import org.sonar.server.computation.measure.MeasureRepository; +import org.sonar.server.computation.metric.MetricRepository; + +import static com.google.common.collect.Maps.asMap; +import static org.sonar.api.measures.CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION_KEY; +import static org.sonar.api.utils.KeyValueFormat.format; +import static org.sonar.server.computation.measure.Measure.newMeasureBuilder; + +public class LanguageDistributionMeasuresStep implements ComputationStep { + + private static final String UNKNOWN_LANGUAGE_KEY = ""; + + private static final ImmutableList FORMULAS = ImmutableList.of(new LanguageDistributionFormula()); + + private static final String[] LANGUAGE_DISTRIBUTION_FORMULA_METRICS = new String[] {NCLOC_LANGUAGE_DISTRIBUTION_KEY}; + + private final TreeRootHolder treeRootHolder; + private final MetricRepository metricRepository; + private final MeasureRepository measureRepository; + + public LanguageDistributionMeasuresStep(TreeRootHolder treeRootHolder, MetricRepository metricRepository, MeasureRepository measureRepository) { + this.treeRootHolder = treeRootHolder; + this.metricRepository = metricRepository; + this.measureRepository = measureRepository; + } + + @Override + public void execute() { + FormulaExecutorComponentVisitor.newBuilder(metricRepository, measureRepository) + .buildFor(FORMULAS) + .visit(treeRootHolder.getRoot()); + } + + private static class LanguageDistributionFormula implements Formula { + + @Override + public LanguageDistributionCounter createNewCounter() { + return new LanguageDistributionCounter(); + } + + @Override + public Optional createMeasure(LanguageDistributionCounter counter, CreateMeasureContext context) { + if (counter.multiset.isEmpty()) { + return Optional.absent(); + } + return Optional.of(newMeasureBuilder().create(format(asMap(counter.multiset.elementSet(), new LanguageToTotalCount(counter.multiset))))); + } + + @Override + public String[] getOutputMetricKeys() { + return LANGUAGE_DISTRIBUTION_FORMULA_METRICS; + } + } + + private static class LanguageToTotalCount implements Function { + + private final Multiset multiset; + + public LanguageToTotalCount(Multiset multiset) { + this.multiset = multiset; + } + + @Nullable + @Override + public Integer apply(@Nonnull String language) { + return multiset.count(language); + } + } + + private static class LanguageDistributionCounter implements Counter { + + private final Multiset multiset = TreeMultiset.create(); + + @Override + public void aggregate(LanguageDistributionCounter counter) { + multiset.addAll(counter.multiset); + } + + @Override + public void aggregate(FileAggregateContext context) { + String language = context.getFile().getFileAttributes().getLanguageKey(); + Optional ncloc = context.getMeasure(CoreMetrics.NCLOC_KEY); + if (ncloc.isPresent()) { + multiset.add(language == null ? UNKNOWN_LANGUAGE_KEY : language, ncloc.get().getIntValue()); + } + } + } + + @Override + public String getDescription() { + return "Compute language distribution measures"; + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/LanguageDistributionMeasuresTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/LanguageDistributionMeasuresTest.java new file mode 100644 index 00000000000..95205039d14 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/LanguageDistributionMeasuresTest.java @@ -0,0 +1,127 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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.step; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.sonar.server.computation.batch.TreeRootHolderRule; +import org.sonar.server.computation.component.FileAttributes; +import org.sonar.server.computation.measure.MeasureRepositoryRule; +import org.sonar.server.computation.metric.MetricRepositoryRule; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.guava.api.Assertions.assertThat; +import static org.sonar.api.measures.CoreMetrics.NCLOC; +import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY; +import static org.sonar.api.measures.CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION; +import static org.sonar.api.measures.CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION_KEY; +import static org.sonar.server.computation.component.Component.Type.DIRECTORY; +import static org.sonar.server.computation.component.Component.Type.FILE; +import static org.sonar.server.computation.component.Component.Type.MODULE; +import static org.sonar.server.computation.component.Component.Type.PROJECT; +import static org.sonar.server.computation.component.DumbComponent.builder; +import static org.sonar.server.computation.measure.Measure.newMeasureBuilder; + +public class LanguageDistributionMeasuresTest { + + private static final String XOO_LANGUAGE = "xoo"; + private static final String JAVA_LANGUAGE = "java"; + + private static final int ROOT_REF = 1; + private static final int MODULE_REF = 12; + private static final int SUB_MODULE_REF = 123; + private static final int DIRECTORY_REF = 1234; + private static final int FILE_1_REF = 12341; + private static final int FILE_2_REF = 12342; + private static final int FILE_3_REF = 12343; + private static final int FILE_4_REF = 12344; + + @Rule + public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule(); + + @Rule + public MetricRepositoryRule metricRepository = new MetricRepositoryRule() + .add(NCLOC) + .add(NCLOC_LANGUAGE_DISTRIBUTION); + + @Rule + public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository); + + ComputationStep underTest = new LanguageDistributionMeasuresStep(treeRootHolder, metricRepository, measureRepository); + + @Before + public void setUp() throws Exception { + treeRootHolder.setRoot( + builder(PROJECT, ROOT_REF) + .addChildren( + builder(MODULE, MODULE_REF) + .addChildren( + builder(MODULE, SUB_MODULE_REF) + .addChildren( + builder(DIRECTORY, DIRECTORY_REF) + .addChildren( + builder(FILE, FILE_1_REF).setFileAttributes(new FileAttributes(false, XOO_LANGUAGE)).build(), + builder(FILE, FILE_2_REF).setFileAttributes(new FileAttributes(false, XOO_LANGUAGE)).build(), + builder(FILE, FILE_3_REF).setFileAttributes(new FileAttributes(false, JAVA_LANGUAGE)).build(), + builder(FILE, FILE_4_REF).setFileAttributes(new FileAttributes(false, null)).build() + ).build() + ).build() + ).build() + ).build()); + } + + @Test + public void compute_ncloc_language_distribution() { + measureRepository.addRawMeasure(FILE_1_REF, NCLOC_KEY, newMeasureBuilder().create(10)); + measureRepository.addRawMeasure(FILE_2_REF, NCLOC_KEY, newMeasureBuilder().create(8)); + measureRepository.addRawMeasure(FILE_3_REF, NCLOC_KEY, newMeasureBuilder().create(6)); + measureRepository.addRawMeasure(FILE_4_REF, NCLOC_KEY, newMeasureBuilder().create(2)); + + underTest.execute(); + + assertThat(measureRepository.getAddedRawMeasure(FILE_1_REF, NCLOC_LANGUAGE_DISTRIBUTION_KEY).get().getStringValue()).isEqualTo("xoo=10"); + assertThat(measureRepository.getAddedRawMeasure(FILE_2_REF, NCLOC_LANGUAGE_DISTRIBUTION_KEY).get().getStringValue()).isEqualTo("xoo=8"); + assertThat(measureRepository.getAddedRawMeasure(FILE_3_REF, NCLOC_LANGUAGE_DISTRIBUTION_KEY).get().getStringValue()).isEqualTo("java=6"); + assertThat(measureRepository.getAddedRawMeasure(FILE_4_REF, NCLOC_LANGUAGE_DISTRIBUTION_KEY).get().getStringValue()).isEqualTo("=2"); + + assertThat(measureRepository.getAddedRawMeasure(DIRECTORY_REF, NCLOC_LANGUAGE_DISTRIBUTION_KEY).get().getStringValue()).isEqualTo("=2;java=6;xoo=18"); + assertThat(measureRepository.getAddedRawMeasure(SUB_MODULE_REF, NCLOC_LANGUAGE_DISTRIBUTION_KEY).get().getStringValue()).isEqualTo("=2;java=6;xoo=18"); + assertThat(measureRepository.getAddedRawMeasure(MODULE_REF, NCLOC_LANGUAGE_DISTRIBUTION_KEY).get().getStringValue()).isEqualTo("=2;java=6;xoo=18"); + assertThat(measureRepository.getAddedRawMeasure(ROOT_REF, NCLOC_LANGUAGE_DISTRIBUTION_KEY).get().getStringValue()).isEqualTo("=2;java=6;xoo=18"); + } + + @Test + public void do_not_compute_ncloc_language_distribution_when_no_ncloc() { + underTest.execute(); + + assertThat(measureRepository.getAddedRawMeasure(FILE_1_REF, NCLOC_LANGUAGE_DISTRIBUTION_KEY)).isAbsent(); + assertThat(measureRepository.getAddedRawMeasure(FILE_2_REF, NCLOC_LANGUAGE_DISTRIBUTION_KEY)).isAbsent(); + assertThat(measureRepository.getAddedRawMeasure(FILE_3_REF, NCLOC_LANGUAGE_DISTRIBUTION_KEY)).isAbsent(); + assertThat(measureRepository.getAddedRawMeasure(FILE_4_REF, NCLOC_LANGUAGE_DISTRIBUTION_KEY)).isAbsent(); + + assertThat(measureRepository.getAddedRawMeasure(DIRECTORY_REF, NCLOC_LANGUAGE_DISTRIBUTION_KEY)).isAbsent(); + assertThat(measureRepository.getAddedRawMeasure(SUB_MODULE_REF, NCLOC_LANGUAGE_DISTRIBUTION_KEY)).isAbsent(); + assertThat(measureRepository.getAddedRawMeasure(MODULE_REF, NCLOC_LANGUAGE_DISTRIBUTION_KEY)).isAbsent(); + assertThat(measureRepository.getAddedRawMeasure(ROOT_REF, NCLOC_LANGUAGE_DISTRIBUTION_KEY)).isAbsent(); + } + +} diff --git a/sonar-core/src/main/java/org/sonar/core/metric/BatchMetrics.java b/sonar-core/src/main/java/org/sonar/core/metric/BatchMetrics.java index a60671cca59..1317c90dcfc 100644 --- a/sonar-core/src/main/java/org/sonar/core/metric/BatchMetrics.java +++ b/sonar-core/src/main/java/org/sonar/core/metric/BatchMetrics.java @@ -167,7 +167,7 @@ public class BatchMetrics { private final Set metrics; - public SensorMetrics(Metrics[] metricsRepositories) { + public BatchMetrics(Metrics[] metricsRepositories) { this.metrics = ImmutableSet.copyOf(Iterables.concat(getPluginMetrics(metricsRepositories), ALLOWED_CORE_METRICS)); }