From: Julien HENRY Date: Wed, 14 Jan 2015 16:14:00 +0000 (+0100) Subject: SONAR-5931 Publish new measure API X-Git-Tag: latest-silver-master-#65~211 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=12c4a20acb61ff6f516c7e7bb8996db606b263ab;p=sonarqube.git SONAR-5931 Publish new measure API --- diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java index 68275cb247a..fb1eb26c69d 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java @@ -52,7 +52,6 @@ import org.sonar.plugins.core.security.ApplyProjectRolesDecorator; import org.sonar.plugins.core.sensors.BranchCoverageDecorator; import org.sonar.plugins.core.sensors.CommentDensityDecorator; import org.sonar.plugins.core.sensors.CoverageDecorator; -import org.sonar.plugins.core.sensors.CoverageMeasurementFilter; import org.sonar.plugins.core.sensors.DirectoriesDecorator; import org.sonar.plugins.core.sensors.FileHashSensor; import org.sonar.plugins.core.sensors.FilesDecorator; @@ -369,7 +368,6 @@ public final class CorePlugin extends SonarPlugin { OverallLineCoverageDecorator.class, OverallCoverageDecorator.class, OverallBranchCoverageDecorator.class, - CoverageMeasurementFilter.class, ApplyProjectRolesDecorator.class, CommentDensityDecorator.class, DirectoriesDecorator.class, diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/BranchCoverageDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/BranchCoverageDecorator.java index 951c1d383a1..529883fc749 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/BranchCoverageDecorator.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/BranchCoverageDecorator.java @@ -19,20 +19,19 @@ */ package org.sonar.plugins.core.sensors; -import com.google.common.collect.ImmutableList; import org.sonar.api.batch.DecoratorContext; 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 org.sonar.batch.sensor.coverage.CoverageConstants; -import java.util.List; +import java.util.Collection; public final class BranchCoverageDecorator extends AbstractCoverageDecorator { @DependsUpon - public List dependsUponMetrics() { - return ImmutableList.of(CoreMetrics.UNCOVERED_CONDITIONS, CoreMetrics.CONDITIONS_TO_COVER, - CoreMetrics.NEW_UNCOVERED_CONDITIONS, CoreMetrics.NEW_CONDITIONS_TO_COVER); + public Collection dependsUponMetrics() { + return CoverageConstants.BRANCH_COVERAGE_METRICS; } @Override diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/CoverageDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/CoverageDecorator.java index 2d37d02dec9..46b02d4e0f8 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/CoverageDecorator.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/CoverageDecorator.java @@ -19,21 +19,19 @@ */ package org.sonar.plugins.core.sensors; -import com.google.common.collect.ImmutableList; import org.sonar.api.batch.DecoratorContext; 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 org.sonar.batch.sensor.coverage.CoverageConstants; import java.util.Collection; public final class CoverageDecorator extends AbstractCoverageDecorator { @DependsUpon public Collection usedMetrics() { - return ImmutableList.of(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); + return CoverageConstants.COVERAGE_METRICS; } @Override diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/CoverageMeasurementFilter.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/CoverageMeasurementFilter.java deleted file mode 100644 index e236c6298ed..00000000000 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/CoverageMeasurementFilter.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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.plugins.core.sensors; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableList.Builder; -import com.google.common.collect.ImmutableSet; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.sonar.api.CoreProperties; -import org.sonar.api.config.Settings; -import org.sonar.api.measures.Measure; -import org.sonar.api.measures.Metric; -import org.sonar.api.resources.Resource; -import org.sonar.api.utils.WildcardPattern; -import org.sonar.core.measure.MeasurementFilter; - -import java.util.Collection; -import java.util.Iterator; - -public class CoverageMeasurementFilter implements MeasurementFilter { - - private static final Logger LOG = LoggerFactory.getLogger(CoverageMeasurementFilter.class); - - private final Settings settings; - private final ImmutableSet coverageMetrics; - private Collection resourcePatterns; - - public CoverageMeasurementFilter(Settings settings, - CoverageDecorator coverageDecorator, - LineCoverageDecorator lineCoverageDecorator, - BranchCoverageDecorator branchCoverageDecorator) { - this.settings = settings; - this.coverageMetrics = ImmutableSet.builder() - .addAll(coverageDecorator.generatedMetrics()) - .addAll(coverageDecorator.usedMetrics()) - .addAll(lineCoverageDecorator.generatedMetrics()) - .addAll(lineCoverageDecorator.dependsUponMetrics()) - .addAll(branchCoverageDecorator.generatedMetrics()) - .addAll(branchCoverageDecorator.dependsUponMetrics()) - .build(); - - initPatterns(); - } - - @Override - public boolean accept(Resource resource, Measure measure) { - if (isCoverageMetric(measure.getMetric())) { - return !hasMatchingPattern(resource); - } else { - return true; - } - } - - private boolean isCoverageMetric(Metric metric) { - return this.coverageMetrics.contains(metric); - } - - private boolean hasMatchingPattern(Resource resource) { - boolean found = false; - Iterator iterator = resourcePatterns.iterator(); - while (!found && iterator.hasNext()) { - found = resource.matchFilePattern(iterator.next().toString()); - } - return found; - } - - @VisibleForTesting - final void initPatterns() { - Builder builder = ImmutableList.builder(); - for (String pattern : settings.getStringArray(CoreProperties.PROJECT_COVERAGE_EXCLUSIONS_PROPERTY)) { - builder.add(WildcardPattern.create(pattern)); - } - resourcePatterns = builder.build(); - log("Excluded sources for coverage: ", resourcePatterns); - } - - private void log(String title, Collection patterns) { - if (!patterns.isEmpty()) { - LOG.info(title); - for (WildcardPattern pattern : patterns) { - LOG.info(" " + pattern); - } - } - } -} diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/LineCoverageDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/LineCoverageDecorator.java index feaf04176cf..11ff93f0634 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/LineCoverageDecorator.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/LineCoverageDecorator.java @@ -19,20 +19,19 @@ */ package org.sonar.plugins.core.sensors; -import com.google.common.collect.ImmutableList; import org.sonar.api.batch.DecoratorContext; 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 org.sonar.batch.sensor.coverage.CoverageConstants; -import java.util.List; +import java.util.Collection; public final class LineCoverageDecorator extends AbstractCoverageDecorator { @DependsUpon - public List dependsUponMetrics() { - return ImmutableList.of(CoreMetrics.UNCOVERED_LINES, CoreMetrics.LINES_TO_COVER, CoreMetrics.NEW_UNCOVERED_LINES, - CoreMetrics.NEW_LINES_TO_COVER); + public Collection dependsUponMetrics() { + return CoverageConstants.LINE_COVERAGE_METRICS; } @Override diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/CoverageMeasurementFilterTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/CoverageMeasurementFilterTest.java deleted file mode 100644 index 85ca73d04bf..00000000000 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/CoverageMeasurementFilterTest.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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.plugins.core.sensors; - -import org.junit.Before; -import org.junit.Test; -import org.sonar.api.config.PropertyDefinitions; -import org.sonar.api.config.Settings; -import org.sonar.api.measures.CoreMetrics; -import org.sonar.api.measures.Measure; -import org.sonar.api.resources.File; -import org.sonar.api.resources.Resource; -import org.sonar.core.config.ExclusionProperties; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class CoverageMeasurementFilterTest { - - private Settings settings; - - private CoverageMeasurementFilter filter; - - @Before - public void createFilter() { - settings = new Settings(new PropertyDefinitions(ExclusionProperties.all())); - filter = new CoverageMeasurementFilter(settings, new CoverageDecorator(), new LineCoverageDecorator(), new BranchCoverageDecorator()); - } - - @Test - public void shouldNotFilterNonCoverageMetrics() { - Measure otherMeasure = mock(Measure.class); - when(otherMeasure.getMetric()).thenReturn(CoreMetrics.LINES); - assertThat(filter.accept(mock(Resource.class), otherMeasure)).isTrue(); - } - - @Test - public void shouldFilterFileBasedOnPattern() { - Resource resource = File.create("src/org/polop/File.php", "org/polop/File.php", null, false); - Measure coverageMeasure = mock(Measure.class); - when(coverageMeasure.getMetric()).thenReturn(CoreMetrics.LINES_TO_COVER); - - settings.setProperty("sonar.coverage.exclusions", "src/org/polop/*"); - filter.initPatterns(); - assertThat(filter.accept(resource, coverageMeasure)).isFalse(); - } - - @Test - public void shouldNotFilterFileBasedOnPattern() { - Resource resource = File.create("src/org/polop/File.php", "org/polop/File.php", null, false); - Measure coverageMeasure = mock(Measure.class); - when(coverageMeasure.getMetric()).thenReturn(CoreMetrics.COVERAGE); - - settings.setProperty("sonar.coverage.exclusions", "src/org/other/*"); - filter.initPatterns(); - assertThat(filter.accept(resource, coverageMeasure)).isTrue(); - } -} diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/LineCoverageDecoratorTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/LineCoverageDecoratorTest.java index 87dd7f9ae6d..e2956df1683 100644 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/LineCoverageDecoratorTest.java +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/LineCoverageDecoratorTest.java @@ -24,15 +24,12 @@ import org.junit.Test; import org.sonar.api.batch.DecoratorContext; import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.Measure; -import org.sonar.api.measures.Metric; import org.sonar.api.resources.Project; import org.sonar.api.resources.Scopes; -import java.util.List; - import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.anyDouble; -import static org.mockito.Mockito.eq; +import static org.mockito.Matchers.anyDouble; +import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -49,9 +46,8 @@ public class LineCoverageDecoratorTest { @Test public void should_depend_on_coverage_metrics() { - List metrics = decorator.dependsUponMetrics(); - - assertThat(metrics).containsOnly(CoreMetrics.UNCOVERED_LINES, CoreMetrics.LINES_TO_COVER, CoreMetrics.NEW_UNCOVERED_LINES, CoreMetrics.NEW_LINES_TO_COVER); + assertThat(decorator.dependsUponMetrics()).containsOnly(CoreMetrics.UNCOVERED_LINES, CoreMetrics.LINES_TO_COVER, CoreMetrics.NEW_UNCOVERED_LINES, + CoreMetrics.NEW_LINES_TO_COVER); } @Test diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/MeasureSensor.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/MeasureSensor.java index 471a5835639..a890b63ac9d 100644 --- a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/MeasureSensor.java +++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/MeasureSensor.java @@ -28,8 +28,7 @@ import org.sonar.api.batch.measure.MetricFinder; import org.sonar.api.batch.sensor.Sensor; import org.sonar.api.batch.sensor.SensorContext; import org.sonar.api.batch.sensor.SensorDescriptor; -import org.sonar.api.batch.sensor.measure.Measure; -import org.sonar.api.measures.CoreMetrics; +import org.sonar.api.batch.sensor.measure.NewMeasure; import org.sonar.xoo.Xoo; import java.io.File; @@ -88,7 +87,7 @@ public class MeasureSensor implements Sensor { if (metric == null) { throw new IllegalStateException("Unknow metric with key: " + metricKey); } - Measure newMeasure = context.newMeasure() + NewMeasure newMeasure = context.newMeasure() .forMetric(metric) .onFile(xooFile); if (Boolean.class.equals(metric.valueType())) { @@ -111,9 +110,7 @@ public class MeasureSensor implements Sensor { public void describe(SensorDescriptor descriptor) { descriptor .name("Xoo Measure Sensor") - .provides(CoreMetrics.LINES) - .onlyOnLanguages(Xoo.KEY) - .onOnFileType(InputFile.Type.MAIN, InputFile.Type.TEST); + .onlyOnLanguages(Xoo.KEY); } @Override diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/SymbolReferencesSensor.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/SymbolReferencesSensor.java index fbff5f75641..8d14771bab4 100644 --- a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/SymbolReferencesSensor.java +++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/SymbolReferencesSensor.java @@ -87,8 +87,7 @@ public class SymbolReferencesSensor implements Sensor { public void describe(SensorDescriptor descriptor) { descriptor .name("Xoo Symbol Reference Sensor") - .onlyOnLanguages(Xoo.KEY) - .onOnFileType(InputFile.Type.MAIN, InputFile.Type.TEST); + .onlyOnLanguages(Xoo.KEY); } @Override diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/SyntaxHighlightingSensor.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/SyntaxHighlightingSensor.java index d72b50b4089..004c186b208 100644 --- a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/SyntaxHighlightingSensor.java +++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/SyntaxHighlightingSensor.java @@ -85,8 +85,7 @@ public class SyntaxHighlightingSensor implements Sensor { public void describe(SensorDescriptor descriptor) { descriptor .name("Xoo Highlighting Sensor") - .onlyOnLanguages(Xoo.KEY) - .onOnFileType(InputFile.Type.MAIN, InputFile.Type.TEST); + .onlyOnLanguages(Xoo.KEY); } @Override diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/CreateIssueByInternalKeySensor.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/CreateIssueByInternalKeySensor.java index 04dc7be446f..886104c14a0 100644 --- a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/CreateIssueByInternalKeySensor.java +++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/CreateIssueByInternalKeySensor.java @@ -35,8 +35,7 @@ public class CreateIssueByInternalKeySensor implements Sensor { descriptor .name("CreateIssueByInternalKeySensor") .onlyOnLanguages(Xoo.KEY) - .createIssuesForRuleRepositories(XooRulesDefinition.XOO_REPOSITORY) - .onOnFileType(InputFile.Type.MAIN, InputFile.Type.TEST); + .createIssuesForRuleRepositories(XooRulesDefinition.XOO_REPOSITORY); } @Override diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneIssueOnDirPerFileSensor.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneIssueOnDirPerFileSensor.java index 548b596c300..66a31686e03 100644 --- a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneIssueOnDirPerFileSensor.java +++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneIssueOnDirPerFileSensor.java @@ -36,8 +36,7 @@ public class OneIssueOnDirPerFileSensor implements Sensor { descriptor .name("One Issue On Dir Per File") .onlyOnLanguages(Xoo.KEY) - .createIssuesForRuleRepositories(XooRulesDefinition.XOO_REPOSITORY) - .onOnFileType(InputFile.Type.MAIN, InputFile.Type.TEST); + .createIssuesForRuleRepositories(XooRulesDefinition.XOO_REPOSITORY); } @Override diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneIssuePerLineSensor.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneIssuePerLineSensor.java index 081bb1a0a2b..3e0b9f48ee5 100644 --- a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneIssuePerLineSensor.java +++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneIssuePerLineSensor.java @@ -24,7 +24,6 @@ import org.sonar.api.batch.sensor.Sensor; import org.sonar.api.batch.sensor.SensorContext; import org.sonar.api.batch.sensor.SensorDescriptor; import org.sonar.api.batch.sensor.issue.Issue.Severity; -import org.sonar.api.measures.CoreMetrics; import org.sonar.api.rule.RuleKey; import org.sonar.xoo.Xoo; @@ -38,10 +37,8 @@ public class OneIssuePerLineSensor implements Sensor { public void describe(SensorDescriptor descriptor) { descriptor .name("One Issue Per Line") - .dependsOn(CoreMetrics.LINES) .onlyOnLanguages(Xoo.KEY) - .createIssuesForRuleRepositories(XooRulesDefinition.XOO_REPOSITORY) - .onOnFileType(InputFile.Type.MAIN, InputFile.Type.TEST); + .createIssuesForRuleRepositories(XooRulesDefinition.XOO_REPOSITORY); } @Override diff --git a/sonar-batch/src/main/java/org/sonar/batch/DefaultDecoratorContext.java b/sonar-batch/src/main/java/org/sonar/batch/DefaultDecoratorContext.java index 1fa2a1b6450..3d18e06c5a9 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/DefaultDecoratorContext.java +++ b/sonar-batch/src/main/java/org/sonar/batch/DefaultDecoratorContext.java @@ -40,7 +40,7 @@ import org.sonar.api.utils.SonarException; import org.sonar.batch.duplication.DuplicationCache; import org.sonar.batch.duplication.DuplicationUtils; import org.sonar.batch.scan.measure.MeasureCache; -import org.sonar.core.measure.MeasurementFilters; +import org.sonar.batch.sensor.coverage.CoverageExclusions; import java.util.Arrays; import java.util.Collection; @@ -54,7 +54,6 @@ public class DefaultDecoratorContext implements DecoratorContext { private static final String SAVE_MEASURE_METHOD = "saveMeasure"; private SonarIndex sonarIndex; private Resource resource; - private MeasurementFilters measurementFilters; private boolean readOnly = false; private List childrenContexts; @@ -63,18 +62,19 @@ public class DefaultDecoratorContext implements DecoratorContext { private MeasureCache measureCache; private MetricFinder metricFinder; private final DuplicationCache duplicationCache; + private final CoverageExclusions coverageFilter; public DefaultDecoratorContext(Resource resource, SonarIndex index, List childrenContexts, - MeasurementFilters measurementFilters, MeasureCache measureCache, MetricFinder metricFinder, DuplicationCache duplicationCache) { + MeasureCache measureCache, MetricFinder metricFinder, DuplicationCache duplicationCache, CoverageExclusions coverageFilter) { this.sonarIndex = index; this.resource = resource; this.childrenContexts = childrenContexts; - this.measurementFilters = measurementFilters; this.measureCache = measureCache; this.metricFinder = metricFinder; this.duplicationCache = duplicationCache; + this.coverageFilter = coverageFilter; } public void init() { @@ -178,7 +178,7 @@ public class DefaultDecoratorContext implements DecoratorContext { throw new SonarException("Unknown metric: " + measure.getMetricKey()); } measure.setMetric(metric); - if (measurementFilters.accept(resource, measure)) { + if (coverageFilter.accept(resource, measure)) { List metricMeasures = measuresByMetric.get(measure.getMetricKey()); boolean add = true; diff --git a/sonar-batch/src/main/java/org/sonar/batch/DefaultSensorContext.java b/sonar-batch/src/main/java/org/sonar/batch/DefaultSensorContext.java deleted file mode 100644 index eeecd48b8bd..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/DefaultSensorContext.java +++ /dev/null @@ -1,285 +0,0 @@ -/* - * 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.batch; - -import org.apache.commons.lang.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.sonar.api.batch.Event; -import org.sonar.api.batch.SensorContext; -import org.sonar.api.batch.SonarIndex; -import org.sonar.api.batch.fs.InputDir; -import org.sonar.api.batch.fs.InputFile; -import org.sonar.api.batch.fs.InputPath; -import org.sonar.api.design.Dependency; -import org.sonar.api.measures.Measure; -import org.sonar.api.measures.MeasuresFilter; -import org.sonar.api.measures.Metric; -import org.sonar.api.resources.Directory; -import org.sonar.api.resources.File; -import org.sonar.api.resources.Project; -import org.sonar.api.resources.ProjectLink; -import org.sonar.api.resources.Qualifiers; -import org.sonar.api.resources.Resource; -import org.sonar.api.rules.Violation; -import org.sonar.api.utils.SonarException; -import org.sonar.core.measure.MeasurementFilters; - -import java.io.Serializable; -import java.util.Collection; -import java.util.Date; -import java.util.List; -import java.util.Set; - -public class DefaultSensorContext implements SensorContext { - - private static final Logger LOG = LoggerFactory.getLogger(DefaultSensorContext.class); - - private SonarIndex index; - private Project project; - private MeasurementFilters filters; - - public DefaultSensorContext(SonarIndex index, Project project, MeasurementFilters filters) { - this.index = index; - this.project = project; - this.filters = filters; - } - - public Project getProject() { - return project; - } - - @Override - public boolean index(Resource resource) { - // SONAR-5006 - if (indexedByCore(resource)) { - logWarning(); - return true; - } - return index.index(resource); - } - - private boolean indexedByCore(Resource resource) { - return StringUtils.equals(Qualifiers.DIRECTORY, resource.getQualifier()) || - StringUtils.equals(Qualifiers.FILE, resource.getQualifier()); - } - - @Override - public boolean index(Resource resource, Resource parentReference) { - // SONAR-5006 - if (indexedByCore(resource)) { - logWarning(); - return true; - } - return index.index(resource, parentReference); - } - - private void logWarning() { - if (LOG.isDebugEnabled()) { - LOG.debug("Plugins are no more responsible for indexing physical resources like directories and files. This is now handled by the platform.", new SonarException( - "Plugin should not index physical resources")); - } - } - - @Override - public boolean isExcluded(Resource reference) { - return index.isExcluded(reference); - } - - @Override - public boolean isIndexed(Resource reference, boolean acceptExcluded) { - return index.isIndexed(reference, acceptExcluded); - } - - @Override - public Resource getParent(Resource reference) { - return index.getParent(reference); - } - - @Override - public Collection getChildren(Resource reference) { - return index.getChildren(reference); - } - - @Override - public Measure getMeasure(Metric metric) { - return index.getMeasure(project, metric); - } - - @Override - public M getMeasures(MeasuresFilter filter) { - return index.getMeasures(project, filter); - } - - @Override - public Measure saveMeasure(Measure measure) { - return index.addMeasure(project, measure); - } - - @Override - public Measure saveMeasure(Metric metric, Double value) { - return index.addMeasure(project, new Measure(metric, value)); - } - - @Override - public Measure getMeasure(Resource resource, Metric metric) { - return index.getMeasure(resource, metric); - } - - @Override - public String saveResource(Resource resource) { - Resource persistedResource = index.addResource(resource); - if (persistedResource != null) { - return persistedResource.getEffectiveKey(); - } - return null; - } - - public boolean saveResource(Resource resource, Resource parentReference) { - return index.index(resource, parentReference); - } - - @Override - public Resource getResource(Resource resource) { - return index.getResource(resource); - } - - @Override - public M getMeasures(Resource resource, MeasuresFilter filter) { - return index.getMeasures(resource, filter); - } - - @Override - public Measure saveMeasure(Resource resource, Metric metric, Double value) { - return saveMeasure(resource, new Measure(metric, value)); - } - - @Override - public Measure saveMeasure(Resource resource, Measure measure) { - if (filters.accept(resource, measure)) { - return index.addMeasure(resourceOrProject(resource), measure); - } else { - return measure; - } - } - - @Override - public void saveViolation(Violation violation, boolean force) { - if (violation.getResource() == null) { - violation.setResource(resourceOrProject(violation.getResource())); - } - index.addViolation(violation, force); - } - - @Override - public void saveViolation(Violation violation) { - saveViolation(violation, false); - } - - @Override - public void saveViolations(Collection violations) { - if (violations != null) { - for (Violation violation : violations) { - saveViolation(violation); - } - } - } - - @Override - public Dependency saveDependency(Dependency dependency) { - return index.addDependency(dependency); - } - - @Override - public Set getDependencies() { - return index.getDependencies(); - } - - @Override - public Collection getIncomingDependencies(Resource to) { - return index.getIncomingEdges(resourceOrProject(to)); - } - - @Override - public Collection getOutgoingDependencies(Resource from) { - return index.getOutgoingEdges(resourceOrProject(from)); - } - - @Override - public void saveSource(Resource reference, String source) { - // useless since 4.2. - } - - @Override - public void saveLink(ProjectLink link) { - index.addLink(link); - } - - @Override - public void deleteLink(String key) { - index.deleteLink(key); - } - - @Override - public List getEvents(Resource resource) { - return index.getEvents(resource); - } - - @Override - public Event createEvent(Resource resource, String name, String description, String category, Date date) { - return index.addEvent(resource, name, description, category, date); - } - - @Override - public void deleteEvent(Event event) { - index.deleteEvent(event); - } - - private Resource resourceOrProject(Resource resource) { - if (resource == null) { - return project; - } - Resource indexedResource = getResource(resource); - return indexedResource != null ? indexedResource : resource; - } - - @Override - public Measure saveMeasure(InputFile inputFile, Metric metric, Double value) { - return saveMeasure(getResource(inputFile), metric, value); - } - - @Override - public Measure saveMeasure(InputFile inputFile, Measure measure) { - return saveMeasure(getResource(inputFile), measure); - } - - @Override - public Resource getResource(InputPath inputPath) { - Resource r; - if (inputPath instanceof InputDir) { - r = Directory.create(((InputDir) inputPath).relativePath()); - } else if (inputPath instanceof InputFile) { - r = File.create(((InputFile) inputPath).relativePath()); - } else { - throw new IllegalArgumentException("Unknow input path type: " + inputPath); - } - return getResource(r); - } -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/DeprecatedSensorContext.java b/sonar-batch/src/main/java/org/sonar/batch/DeprecatedSensorContext.java new file mode 100644 index 00000000000..35d329627f3 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/DeprecatedSensorContext.java @@ -0,0 +1,297 @@ +/* + * 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.batch; + +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.sonar.api.batch.Event; +import org.sonar.api.batch.SensorContext; +import org.sonar.api.batch.SonarIndex; +import org.sonar.api.batch.fs.FileSystem; +import org.sonar.api.batch.fs.InputDir; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.fs.InputPath; +import org.sonar.api.batch.rule.ActiveRules; +import org.sonar.api.batch.sensor.SensorStorage; +import org.sonar.api.config.Settings; +import org.sonar.api.design.Dependency; +import org.sonar.api.measures.Measure; +import org.sonar.api.measures.MeasuresFilter; +import org.sonar.api.measures.Metric; +import org.sonar.api.resources.Directory; +import org.sonar.api.resources.File; +import org.sonar.api.resources.Project; +import org.sonar.api.resources.ProjectLink; +import org.sonar.api.resources.Qualifiers; +import org.sonar.api.resources.Resource; +import org.sonar.api.rules.Violation; +import org.sonar.api.utils.SonarException; +import org.sonar.batch.duplication.BlockCache; +import org.sonar.batch.duplication.DuplicationCache; +import org.sonar.batch.index.ComponentDataCache; +import org.sonar.batch.sensor.DefaultSensorContext; +import org.sonar.batch.sensor.coverage.CoverageExclusions; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Set; + +public class DeprecatedSensorContext extends DefaultSensorContext implements SensorContext { + + private static final Logger LOG = LoggerFactory.getLogger(DeprecatedSensorContext.class); + + private final SonarIndex index; + private final Project project; + private final CoverageExclusions coverageFilter; + + public DeprecatedSensorContext(SonarIndex index, Project project, Settings settings, FileSystem fs, ActiveRules activeRules, + ComponentDataCache componentDataCache, CoverageExclusions coverageFilter, + BlockCache blockCache, DuplicationCache duplicationCache, SensorStorage sensorStorage) { + super(settings, fs, activeRules, componentDataCache, blockCache, duplicationCache, sensorStorage); + this.index = index; + this.project = project; + this.coverageFilter = coverageFilter; + } + + public Project getProject() { + return project; + } + + @Override + public boolean index(Resource resource) { + // SONAR-5006 + if (indexedByCore(resource)) { + logWarning(); + return true; + } + return index.index(resource); + } + + private boolean indexedByCore(Resource resource) { + return StringUtils.equals(Qualifiers.DIRECTORY, resource.getQualifier()) || + StringUtils.equals(Qualifiers.FILE, resource.getQualifier()); + } + + @Override + public boolean index(Resource resource, Resource parentReference) { + // SONAR-5006 + if (indexedByCore(resource)) { + logWarning(); + return true; + } + return index.index(resource, parentReference); + } + + private void logWarning() { + if (LOG.isDebugEnabled()) { + LOG.debug("Plugins are no more responsible for indexing physical resources like directories and files. This is now handled by the platform.", new SonarException( + "Plugin should not index physical resources")); + } + } + + @Override + public boolean isExcluded(Resource reference) { + return index.isExcluded(reference); + } + + @Override + public boolean isIndexed(Resource reference, boolean acceptExcluded) { + return index.isIndexed(reference, acceptExcluded); + } + + @Override + public Resource getParent(Resource reference) { + return index.getParent(reference); + } + + @Override + public Collection getChildren(Resource reference) { + return index.getChildren(reference); + } + + @Override + public Measure getMeasure(Metric metric) { + return index.getMeasure(project, metric); + } + + @Override + public M getMeasures(MeasuresFilter filter) { + return index.getMeasures(project, filter); + } + + @Override + public Measure saveMeasure(Measure measure) { + return index.addMeasure(project, measure); + } + + @Override + public Measure saveMeasure(Metric metric, Double value) { + return index.addMeasure(project, new Measure(metric, value)); + } + + @Override + public Measure getMeasure(Resource resource, Metric metric) { + return index.getMeasure(resource, metric); + } + + @Override + public String saveResource(Resource resource) { + Resource persistedResource = index.addResource(resource); + if (persistedResource != null) { + return persistedResource.getEffectiveKey(); + } + return null; + } + + public boolean saveResource(Resource resource, Resource parentReference) { + return index.index(resource, parentReference); + } + + @Override + public Resource getResource(Resource resource) { + return index.getResource(resource); + } + + @Override + public M getMeasures(Resource resource, MeasuresFilter filter) { + return index.getMeasures(resource, filter); + } + + @Override + public Measure saveMeasure(Resource resource, Metric metric, Double value) { + return saveMeasure(resource, new Measure(metric, value)); + } + + @Override + public Measure saveMeasure(Resource resource, Measure measure) { + Resource resourceOrProject = resourceOrProject(resource); + if (coverageFilter.accept(resourceOrProject, measure)) { + return index.addMeasure(resourceOrProject, measure); + } else { + return measure; + } + } + + @Override + public void saveViolation(Violation violation, boolean force) { + if (violation.getResource() == null) { + violation.setResource(resourceOrProject(violation.getResource())); + } + index.addViolation(violation, force); + } + + @Override + public void saveViolation(Violation violation) { + saveViolation(violation, false); + } + + @Override + public void saveViolations(Collection violations) { + if (violations != null) { + for (Violation violation : violations) { + saveViolation(violation); + } + } + } + + @Override + public Dependency saveDependency(Dependency dependency) { + return index.addDependency(dependency); + } + + @Override + public Set getDependencies() { + return index.getDependencies(); + } + + @Override + public Collection getIncomingDependencies(Resource to) { + return index.getIncomingEdges(resourceOrProject(to)); + } + + @Override + public Collection getOutgoingDependencies(Resource from) { + return index.getOutgoingEdges(resourceOrProject(from)); + } + + @Override + public void saveSource(Resource reference, String source) { + // useless since 4.2. + } + + @Override + public void saveLink(ProjectLink link) { + index.addLink(link); + } + + @Override + public void deleteLink(String key) { + index.deleteLink(key); + } + + @Override + public List getEvents(Resource resource) { + return index.getEvents(resource); + } + + @Override + public Event createEvent(Resource resource, String name, String description, String category, Date date) { + return index.addEvent(resource, name, description, category, date); + } + + @Override + public void deleteEvent(Event event) { + index.deleteEvent(event); + } + + private Resource resourceOrProject(Resource resource) { + if (resource == null) { + return project; + } + Resource indexedResource = getResource(resource); + return indexedResource != null ? indexedResource : resource; + } + + @Override + public Measure saveMeasure(InputFile inputFile, Metric metric, Double value) { + return saveMeasure(getResource(inputFile), metric, value); + } + + @Override + public Measure saveMeasure(InputFile inputFile, Measure measure) { + return saveMeasure(getResource(inputFile), measure); + } + + @Override + public Resource getResource(InputPath inputPath) { + Resource r; + if (inputPath instanceof InputDir) { + r = Directory.create(((InputDir) inputPath).relativePath()); + } else if (inputPath instanceof InputFile) { + r = File.create(((InputFile) inputPath).relativePath()); + } else { + throw new IllegalArgumentException("Unknow input path type: " + inputPath); + } + return getResource(r); + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchExtensionDictionnary.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchExtensionDictionnary.java index 32bebf6182e..e0a0e348514 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchExtensionDictionnary.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchExtensionDictionnary.java @@ -29,6 +29,7 @@ import org.sonar.api.platform.ComponentContainer; import org.sonar.api.resources.Project; import org.sonar.batch.scan.SensorWrapper; import org.sonar.batch.scan2.AnalyzerOptimizer; +import org.sonar.batch.sensor.DefaultSensorContext; import javax.annotation.Nullable; @@ -43,7 +44,7 @@ public class BatchExtensionDictionnary extends org.sonar.api.batch.BatchExtensio private SensorContext context; private AnalyzerOptimizer analyzerOptimizer; - public BatchExtensionDictionnary(ComponentContainer componentContainer, SensorContext context, AnalyzerOptimizer analyzerOptimizer) { + public BatchExtensionDictionnary(ComponentContainer componentContainer, DefaultSensorContext context, AnalyzerOptimizer analyzerOptimizer) { super(componentContainer); this.context = context; this.analyzerOptimizer = analyzerOptimizer; diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java index 9e3a3d1b133..64886cc1529 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java +++ b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java @@ -31,8 +31,10 @@ import org.slf4j.LoggerFactory; import org.sonar.api.batch.Event; import org.sonar.api.batch.SonarIndex; import org.sonar.api.batch.bootstrap.ProjectDefinition; +import org.sonar.api.batch.measure.Metric; import org.sonar.api.batch.measure.MetricFinder; import org.sonar.api.design.Dependency; +import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.Measure; import org.sonar.api.measures.MeasuresFilter; import org.sonar.api.measures.MeasuresFilters; @@ -51,7 +53,6 @@ import org.sonar.api.utils.SonarException; import org.sonar.batch.ProjectTree; import org.sonar.batch.issue.ModuleIssues; import org.sonar.batch.scan.measure.MeasureCache; -import org.sonar.batch.scan2.DefaultSensorContext; import org.sonar.core.component.ComponentKeys; import javax.annotation.CheckForNull; @@ -59,6 +60,7 @@ import javax.annotation.Nullable; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; @@ -72,6 +74,31 @@ public class DefaultIndex extends SonarIndex { private static final Logger LOG = LoggerFactory.getLogger(DefaultIndex.class); + private static final List INTERNAL_METRICS = Arrays.asList( + // Computed by DsmDecorator + CoreMetrics.DEPENDENCY_MATRIX, + CoreMetrics.DIRECTORY_CYCLES, + CoreMetrics.DIRECTORY_EDGES_WEIGHT, + CoreMetrics.DIRECTORY_FEEDBACK_EDGES, + CoreMetrics.DIRECTORY_TANGLE_INDEX, + CoreMetrics.DIRECTORY_TANGLES, + CoreMetrics.FILE_CYCLES, + CoreMetrics.FILE_EDGES_WEIGHT, + CoreMetrics.FILE_FEEDBACK_EDGES, + CoreMetrics.FILE_TANGLE_INDEX, + CoreMetrics.FILE_TANGLES, + // Computed by ScmActivitySensor + CoreMetrics.SCM_AUTHORS_BY_LINE, + CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE, + CoreMetrics.SCM_REVISIONS_BY_LINE, + // Computed by core duplication plugin + CoreMetrics.DUPLICATIONS_DATA, + CoreMetrics.DUPLICATION_LINES_DATA, + CoreMetrics.DUPLICATED_FILES, + CoreMetrics.DUPLICATED_LINES, + CoreMetrics.DUPLICATED_BLOCKS + ); + private final ResourceCache resourceCache; private final MetricFinder metricFinder; @@ -228,7 +255,7 @@ public class DefaultIndex extends SonarIndex { if (metric == null) { throw new SonarException("Unknown metric: " + measure.getMetricKey()); } - if (!isTechnicalProjectCopy(resource) && !measure.isFromCore() && DefaultSensorContext.INTERNAL_METRICS.contains(metric)) { + if (!isTechnicalProjectCopy(resource) && !measure.isFromCore() && INTERNAL_METRICS.contains(metric)) { LOG.debug("Metric " + metric.key() + " is an internal metric computed by SonarQube. Please update your plugin."); return measure; } diff --git a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/TaskResult.java b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/TaskResult.java index b9216a859f7..7bc120b37d6 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/TaskResult.java +++ b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/TaskResult.java @@ -19,6 +19,7 @@ */ package org.sonar.batch.mediumtest; +import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.batch.fs.InputDir; @@ -28,6 +29,7 @@ import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.sensor.dependency.Dependency; import org.sonar.api.batch.sensor.duplication.DuplicationGroup; import org.sonar.api.batch.sensor.highlighting.TypeOfText; +import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; import org.sonar.api.batch.sensor.symbol.Symbol; import org.sonar.api.batch.sensor.test.TestCaseCoverage; import org.sonar.api.batch.sensor.test.TestCaseExecution; @@ -51,6 +53,7 @@ import org.sonar.core.source.SnapshotDataTypes; import javax.annotation.CheckForNull; +import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -64,7 +67,7 @@ public class TaskResult implements org.sonar.batch.mediumtest.ScanTaskObserver { private static final Logger LOG = LoggerFactory.getLogger(TaskResult.class); private List issues = new ArrayList<>(); - private List measures = new ArrayList<>(); + private List measures = new ArrayList<>(); private Map> duplications = new HashMap<>(); private Map inputFiles = new HashMap<>(); private Map inputDirs = new HashMap<>(); @@ -81,11 +84,10 @@ public class TaskResult implements org.sonar.batch.mediumtest.ScanTaskObserver { issues.add(issue); } - for (Measure measure : container.getComponentByType(MeasureCache.class).all()) { - measures.add(measure); - } - storeFs(container); + + storeMeasures(container); + storeComponentData(container); storeDuplication(container); // storeTestCases(container); @@ -94,6 +96,24 @@ public class TaskResult implements org.sonar.batch.mediumtest.ScanTaskObserver { } + private void storeMeasures(ProjectScanContainer container) { + InputPathCache inputFileCache = container.getComponentByType(InputPathCache.class); + for (Entry measureEntry : container.getComponentByType(MeasureCache.class).entries()) { + String componentKey = measureEntry.key()[0].toString(); + InputFile file = inputFileCache.getFile(StringUtils.substringBeforeLast(componentKey, ":"), StringUtils.substringAfterLast(componentKey, ":")); + Measure oldMeasure = measureEntry.value(); + DefaultMeasure newMeasure = new DefaultMeasure<>() + .forMetric(oldMeasure.getMetric()); + if (file != null) { + newMeasure.onFile(file); + } else { + newMeasure.onProject(); + } + newMeasure.withValue(oldMeasure.value()); + measures.add(newMeasure); + } + } + private void storeCoveragePerTest(ProjectScanContainer container) { TestCaseCoverageCache testCaseCoverageCache = container.getComponentByType(TestCaseCoverageCache.class); for (Entry entry : testCaseCoverageCache.entries()) { @@ -170,7 +190,7 @@ public class TaskResult implements org.sonar.batch.mediumtest.ScanTaskObserver { return issues; } - public List measures() { + public List measures() { return measures; } diff --git a/sonar-batch/src/main/java/org/sonar/batch/phases/DecoratorsExecutor.java b/sonar-batch/src/main/java/org/sonar/batch/phases/DecoratorsExecutor.java index b867e0fc010..01ae1e452d8 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/phases/DecoratorsExecutor.java +++ b/sonar-batch/src/main/java/org/sonar/batch/phases/DecoratorsExecutor.java @@ -35,7 +35,7 @@ import org.sonar.batch.DefaultDecoratorContext; import org.sonar.batch.duplication.DuplicationCache; import org.sonar.batch.events.EventBus; import org.sonar.batch.scan.measure.MeasureCache; -import org.sonar.core.measure.MeasurementFilters; +import org.sonar.batch.sensor.coverage.CoverageExclusions; import java.util.Collection; import java.util.List; @@ -46,13 +46,13 @@ public class DecoratorsExecutor implements BatchComponent { private SonarIndex index; private EventBus eventBus; private Project project; - private MeasurementFilters measurementFilters; + private CoverageExclusions coverageFilter; private MeasureCache measureCache; private MetricFinder metricFinder; private final DuplicationCache duplicationCache; public DecoratorsExecutor(BatchExtensionDictionnary batchExtDictionnary, - Project project, SonarIndex index, EventBus eventBus, MeasurementFilters measurementFilters, MeasureCache measureCache, MetricFinder metricFinder, + Project project, SonarIndex index, EventBus eventBus, CoverageExclusions coverageFilter, MeasureCache measureCache, MetricFinder metricFinder, DuplicationCache duplicationCache) { this.measureCache = measureCache; this.metricFinder = metricFinder; @@ -61,7 +61,7 @@ public class DecoratorsExecutor implements BatchComponent { this.index = index; this.eventBus = eventBus; this.project = project; - this.measurementFilters = measurementFilters; + this.coverageFilter = coverageFilter; } public void execute() { @@ -79,7 +79,7 @@ public class DecoratorsExecutor implements BatchComponent { childrenContexts.add(childContext.end()); } - DefaultDecoratorContext context = new DefaultDecoratorContext(resource, index, childrenContexts, measurementFilters, measureCache, metricFinder, duplicationCache); + DefaultDecoratorContext context = new DefaultDecoratorContext(resource, index, childrenContexts, measureCache, metricFinder, duplicationCache, coverageFilter); context.init(); if (executeDecorators) { for (Decorator decorator : decorators) { diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java index af680789d80..98598f57f33 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java @@ -31,8 +31,8 @@ import org.sonar.api.platform.ComponentContainer; import org.sonar.api.resources.Project; import org.sonar.api.scan.filesystem.FileExclusions; import org.sonar.batch.DefaultProjectClasspath; -import org.sonar.batch.DefaultSensorContext; import org.sonar.batch.DefaultTimeMachine; +import org.sonar.batch.DeprecatedSensorContext; import org.sonar.batch.ProjectTree; import org.sonar.batch.ResourceFilters; import org.sonar.batch.bootstrap.BatchExtensionDictionnary; @@ -97,8 +97,10 @@ import org.sonar.batch.scan.filesystem.StatusDetectionFactory; import org.sonar.batch.scan.maven.MavenPluginsConfigurator; import org.sonar.batch.scan.report.JsonReport; import org.sonar.batch.scan2.AnalyzerOptimizer; +import org.sonar.batch.sensor.DefaultSensorContext; +import org.sonar.batch.sensor.DefaultSensorStorage; +import org.sonar.batch.sensor.coverage.CoverageExclusions; import org.sonar.core.component.ScanPerspectives; -import org.sonar.core.measure.MeasurementFilters; public class ModuleScanContainer extends ComponentContainer { private static final Logger LOG = LoggerFactory.getLogger(ModuleScanContainer.class); @@ -174,11 +176,12 @@ public class ModuleScanContainer extends ComponentContainer { AnalyzerOptimizer.class, DefaultSensorContext.class, - SensorContextAdapter.class, + DefaultSensorStorage.class, + DeprecatedSensorContext.class, BatchExtensionDictionnary.class, DefaultTimeMachine.class, IssueFilters.class, - MeasurementFilters.class, + CoverageExclusions.class, ResourceFilters.class, // rules diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/SensorContextAdapter.java b/sonar-batch/src/main/java/org/sonar/batch/scan/SensorContextAdapter.java deleted file mode 100644 index a8d57e8088f..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/SensorContextAdapter.java +++ /dev/null @@ -1,267 +0,0 @@ -/* - * 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.batch.scan; - -import org.sonar.api.batch.Sensor; -import org.sonar.api.batch.SonarIndex; -import org.sonar.api.batch.fs.FileSystem; -import org.sonar.api.batch.fs.InputDir; -import org.sonar.api.batch.fs.InputFile; -import org.sonar.api.batch.fs.InputPath; -import org.sonar.api.batch.measure.MetricFinder; -import org.sonar.api.batch.rule.ActiveRules; -import org.sonar.api.batch.sensor.SensorContext; -import org.sonar.api.batch.sensor.issue.Issue; -import org.sonar.api.batch.sensor.issue.Issue.Severity; -import org.sonar.api.batch.sensor.measure.Measure; -import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; -import org.sonar.api.batch.sensor.test.TestCaseCoverage; -import org.sonar.api.batch.sensor.test.TestCaseExecution; -import org.sonar.api.batch.sensor.test.internal.DefaultTestCaseExecution; -import org.sonar.api.component.ResourcePerspectives; -import org.sonar.api.config.Settings; -import org.sonar.api.design.Dependency; -import org.sonar.api.issue.Issuable; -import org.sonar.api.issue.internal.DefaultIssue; -import org.sonar.api.measures.Formula; -import org.sonar.api.measures.Metric; -import org.sonar.api.measures.PersistenceMode; -import org.sonar.api.measures.SumChildDistributionFormula; -import org.sonar.api.resources.Directory; -import org.sonar.api.resources.File; -import org.sonar.api.resources.Project; -import org.sonar.api.resources.Qualifiers; -import org.sonar.api.resources.Resource; -import org.sonar.api.resources.Scopes; -import org.sonar.api.rule.RuleKey; -import org.sonar.api.test.MutableTestCase; -import org.sonar.api.test.MutableTestPlan; -import org.sonar.api.test.MutableTestable; -import org.sonar.api.test.Testable; -import org.sonar.batch.duplication.BlockCache; -import org.sonar.batch.duplication.DuplicationCache; -import org.sonar.batch.index.ComponentDataCache; -import org.sonar.batch.scan2.BaseSensorContext; -import org.sonar.core.component.ComponentKeys; - -/** - * Implements {@link SensorContext} but forward everything to {@link org.sonar.api.batch.SensorContext} for backward compatibility. - * Will be dropped once old {@link Sensor} API is dropped. - * - */ -public class SensorContextAdapter extends BaseSensorContext { - - private static final String USES = "USES"; - private final org.sonar.api.batch.SensorContext sensorContext; - private final MetricFinder metricFinder; - private final Project project; - private final ResourcePerspectives perspectives; - private final SonarIndex sonarIndex; - - public SensorContextAdapter(org.sonar.api.batch.SensorContext sensorContext, MetricFinder metricFinder, Project project, - ResourcePerspectives perspectives, - Settings settings, FileSystem fs, ActiveRules activeRules, ComponentDataCache componentDataCache, BlockCache blockCache, - DuplicationCache duplicationCache, SonarIndex sonarIndex) { - super(settings, fs, activeRules, componentDataCache, blockCache, duplicationCache); - this.sensorContext = sensorContext; - this.metricFinder = metricFinder; - this.project = project; - this.perspectives = perspectives; - this.sonarIndex = sonarIndex; - } - - private Metric findMetricOrFail(String metricKey) { - Metric m = (Metric) metricFinder.findByKey(metricKey); - if (m == null) { - throw new IllegalStateException("Unknow metric with key: " + metricKey); - } - return m; - } - - @Override - public void store(Measure newMeasure) { - DefaultMeasure measure = (DefaultMeasure) newMeasure; - org.sonar.api.measures.Metric m = findMetricOrFail(measure.metric().key()); - org.sonar.api.measures.Measure measureToSave = new org.sonar.api.measures.Measure(m); - setValueAccordingToMetricType(newMeasure, m, measureToSave); - measureToSave.setFromCore(measure.isFromCore()); - if (newMeasure.inputFile() != null) { - Formula formula = newMeasure.metric() instanceof org.sonar.api.measures.Metric ? - ((org.sonar.api.measures.Metric) newMeasure.metric()).getFormula() : null; - if (formula instanceof SumChildDistributionFormula - && !Scopes.isHigherThanOrEquals(Scopes.FILE, ((SumChildDistributionFormula) formula).getMinimumScopeToPersist())) { - measureToSave.setPersistenceMode(PersistenceMode.MEMORY); - } - sensorContext.saveMeasure(newMeasure.inputFile(), measureToSave); - } else { - sensorContext.saveMeasure(measureToSave); - } - } - - private void setValueAccordingToMetricType(Measure measure, org.sonar.api.measures.Metric m, org.sonar.api.measures.Measure measureToSave) { - switch (m.getType()) { - case BOOL: - measureToSave.setValue(Boolean.TRUE.equals(measure.value()) ? 1.0 : 0.0); - break; - case INT: - case MILLISEC: - measureToSave.setValue(Double.valueOf((Integer) measure.value())); - break; - case FLOAT: - case PERCENT: - case RATING: - measureToSave.setValue((Double) measure.value()); - break; - case STRING: - case LEVEL: - case DATA: - case DISTRIB: - measureToSave.setData((String) measure.value()); - break; - case WORK_DUR: - measureToSave.setValue(Double.valueOf((Long) measure.value())); - break; - default: - throw new UnsupportedOperationException("Unsupported type :" + m.getType()); - } - } - - @Override - public void store(Issue issue) { - Resource r; - InputPath inputPath = issue.inputPath(); - if (inputPath != null) { - if (inputPath instanceof InputDir) { - r = Directory.create(inputPath.relativePath()); - } else { - r = File.create(inputPath.relativePath()); - } - } else { - r = project; - } - Issuable issuable = perspectives.as(Issuable.class, r); - if (issuable == null) { - return; - } - issuable.addIssue(toDefaultIssue(project.getKey(), ComponentKeys.createEffectiveKey(project, r), issue)); - } - - public static DefaultIssue toDefaultIssue(String projectKey, String componentKey, Issue issue) { - Severity overridenSeverity = issue.overridenSeverity(); - return new org.sonar.core.issue.DefaultIssueBuilder() - .componentKey(componentKey) - .projectKey(projectKey) - .ruleKey(RuleKey.of(issue.ruleKey().repository(), issue.ruleKey().rule())) - .effortToFix(issue.effortToFix()) - .line(issue.line()) - .message(issue.message()) - .severity(overridenSeverity != null ? overridenSeverity.name() : null) - .build(); - } - - @Override - public void store(TestCaseExecution testCase) { - File testRes = getTestResource(((DefaultTestCaseExecution) testCase).testFile()); - MutableTestPlan testPlan = perspectives.as(MutableTestPlan.class, testRes); - if (testPlan != null) { - testPlan - .addTestCase(testCase.name()) - .setDurationInMs(testCase.durationInMs()) - .setType(testCase.type().name()) - .setStatus(org.sonar.api.test.TestCase.Status.valueOf(testCase.status().name())) - .setMessage(testCase.message()) - .setStackTrace(testCase.stackTrace()); - } - } - - @Override - public void store(TestCaseCoverage testCaseCoverage) { - File testRes = getTestResource(testCaseCoverage.testFile()); - File mainRes = getMainResource(testCaseCoverage.coveredFile()); - Testable testAbleFile = perspectives.as(MutableTestable.class, mainRes); - if (testAbleFile != null) { - MutableTestPlan testPlan = perspectives.as(MutableTestPlan.class, testRes); - if (testPlan != null) { - for (MutableTestCase mutableTestCase : testPlan.testCasesByName(testCaseCoverage.testName())) { - mutableTestCase.setCoverageBlock(testAbleFile, testCaseCoverage.coveredLines()); - } - } else { - throw new IllegalStateException("Unable to get MutableTestPlan perspective from " + testRes); - } - } else { - throw new IllegalStateException("Unable to get MutableTestable perspective from " + mainRes); - } - } - - private File getTestResource(InputFile testFile) { - File testRes = File.create(testFile.relativePath()); - testRes.setQualifier(Qualifiers.UNIT_TEST_FILE); - // Reload - testRes = sensorContext.getResource(testRes); - if (testRes == null) { - throw new IllegalArgumentException("Provided input file is not indexed or not a test file: " + testFile); - } - return testRes; - } - - private File getMainResource(InputFile mainFile) { - File mainRes = File.create(mainFile.relativePath()); - // Reload - mainRes = sensorContext.getResource(mainRes); - if (mainRes == null) { - throw new IllegalArgumentException("Provided input file is not indexed or not a main file: " + mainRes); - } - return mainRes; - } - - private File getFile(InputFile file) { - if (file.type() == InputFile.Type.MAIN) { - return getMainResource(file); - } else { - return getTestResource(file); - } - } - - @Override - public void store(org.sonar.api.batch.sensor.dependency.Dependency dep) { - File fromResource = getFile(dep.from()); - File toResource = getFile(dep.to()); - if (sonarIndex.getEdge(fromResource, toResource) != null) { - throw new IllegalStateException("Dependency between " + dep.from() + " and " + dep.to() + " was already saved."); - } - Directory fromParent = fromResource.getParent(); - Directory toParent = toResource.getParent(); - Dependency parentDep = null; - if (!fromParent.equals(toParent)) { - parentDep = sonarIndex.getEdge(fromParent, toParent); - if (parentDep != null) { - parentDep.setWeight(parentDep.getWeight() + 1); - } else { - parentDep = new Dependency(fromParent, toParent).setUsage(USES).setWeight(1); - parentDep = sensorContext.saveDependency(parentDep); - } - } - sensorContext.saveDependency(new Dependency(fromResource, toResource) - .setUsage(USES) - .setWeight(dep.weight()) - .setParent(parentDep)); - } - -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalysisPublisher.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalysisPublisher.java deleted file mode 100644 index 621668853d3..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalysisPublisher.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * 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.batch.scan2; - -import org.apache.commons.io.Charsets; -import org.apache.commons.io.FileUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.sonar.api.batch.bootstrap.ProjectDefinition; -import org.sonar.api.batch.fs.FileSystem; -import org.sonar.api.batch.fs.InputFile; -import org.sonar.api.batch.fs.InputPath; -import org.sonar.api.batch.sensor.issue.Issue; -import org.sonar.api.batch.sensor.issue.Issue.Severity; -import org.sonar.api.batch.sensor.measure.Measure; -import org.sonar.api.config.Settings; -import org.sonar.api.utils.ZipUtils; -import org.sonar.api.utils.text.JsonWriter; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.util.Properties; - -public final class AnalysisPublisher { - - private static final Logger LOG = LoggerFactory.getLogger(AnalysisPublisher.class); - private final Settings settings; - private final FileSystem fs; - private final MeasureCache measureCache; - private final ProjectDefinition def; - private final IssueCache issueCache; - - public AnalysisPublisher(ProjectDefinition def, Settings settings, FileSystem fs, - MeasureCache measureCache, - IssueCache analyzerIssueCache) { - this.def = def; - this.settings = settings; - this.fs = fs; - this.measureCache = measureCache; - this.issueCache = analyzerIssueCache; - } - - public void execute() { - if (settings.getBoolean("sonar.skipPublish")) { - LOG.debug("Publishing of results is skipped"); - return; - } - File exportDir = prepareExportDir(); - - exportAnalysisProperties(exportDir); - - exportSourceFiles(exportDir); - - exportMeasures(exportDir); - - exportIssues(exportDir); - - createZip(exportDir); - - } - - private void createZip(File exportDir) { - File exportZip = new File(fs.workDir(), def.getKey() + "-export.zip"); - try { - ZipUtils.zipDir(exportDir, exportZip); - FileUtils.deleteDirectory(exportDir); - } catch (IOException e) { - throw unableToExport(e); - } - LOG.info("Results packaged in " + exportZip); - } - - private IllegalStateException unableToExport(IOException e) { - return new IllegalStateException("Unable to export result of analyzis", e); - } - - private void exportIssues(File exportDir) { - File issuesFile = new File(exportDir, "issues.json"); - try (Writer issueWriter = new OutputStreamWriter(new FileOutputStream(issuesFile), Charsets.UTF_8)) { - JsonWriter jsonWriter = JsonWriter.of(issueWriter); - jsonWriter - .beginObject().name("issues") - .beginArray(); - for (Issue issue : issueCache.byModule(def.getKey())) { - jsonWriter.beginObject() - .prop("repository", issue.ruleKey().repository()) - .prop("rule", issue.ruleKey().rule()); - InputPath inputPath = issue.inputPath(); - if (inputPath != null) { - jsonWriter.prop("path", inputPath.relativePath()); - } - jsonWriter.prop("message", issue.message()) - .prop("effortToFix", issue.effortToFix()) - .prop("line", issue.line()); - Severity overridenSeverity = issue.overridenSeverity(); - if (overridenSeverity != null) { - jsonWriter.prop("severity", overridenSeverity.name()); - } - jsonWriter.endObject(); - } - jsonWriter.endArray() - .endObject() - .close(); - } catch (IOException e) { - throw unableToExport(e); - } - } - - private void exportMeasures(File exportDir) { - File measuresFile = new File(exportDir, "measures.json"); - try (Writer measureWriter = new OutputStreamWriter(new FileOutputStream(measuresFile), Charsets.UTF_8)) { - JsonWriter jsonWriter = JsonWriter.of(measureWriter); - jsonWriter - .beginObject().name("measures") - .beginArray(); - for (Measure measure : measureCache.byModule(def.getKey())) { - jsonWriter.beginObject() - .prop("metricKey", measure.metric().key()); - InputFile inputFile = measure.inputFile(); - if (inputFile != null) { - jsonWriter.prop("filePath", inputFile.relativePath()); - } - jsonWriter.prop("value", String.valueOf(measure.value())) - .endObject(); - } - jsonWriter.endArray() - .endObject() - .close(); - } catch (IOException e) { - throw unableToExport(e); - } - } - - private void exportSourceFiles(File exportDir) { - File sourceDir = new File(exportDir, "sources"); - for (InputFile inputFile : fs.inputFiles(fs.predicates().all())) { - File dest = new File(sourceDir, inputFile.relativePath()); - try { - FileUtils.copyFile(inputFile.file(), dest); - } catch (IOException e) { - throw unableToExport(e); - } - } - } - - private void exportAnalysisProperties(File exportDir) { - File propsFile = new File(exportDir, "analysis.properties"); - Properties props = new Properties(); - props.putAll(settings.getProperties()); - try (Writer writer = new OutputStreamWriter(new FileOutputStream(propsFile), Charsets.UTF_8)) { - props.store(writer, "SonarQube batch"); - } catch (IOException e) { - throw unableToExport(e); - } - } - - private File prepareExportDir() { - File exportDir = new File(fs.workDir(), "export"); - try { - if (exportDir.exists()) { - FileUtils.forceDelete(exportDir); - } - FileUtils.forceMkdir(exportDir); - } catch (IOException e) { - throw unableToExport(e); - } - return exportDir; - } -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/BaseSensorContext.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/BaseSensorContext.java deleted file mode 100644 index 09b9e5b5f3e..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/scan2/BaseSensorContext.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * 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.batch.scan2; - -import com.google.common.base.Preconditions; -import org.sonar.api.batch.fs.FileSystem; -import org.sonar.api.batch.fs.InputFile; -import org.sonar.api.batch.fs.internal.DefaultInputFile; -import org.sonar.api.batch.rule.ActiveRules; -import org.sonar.api.batch.sensor.SensorContext; -import org.sonar.api.batch.sensor.SensorStorage; -import org.sonar.api.batch.sensor.dependency.Dependency; -import org.sonar.api.batch.sensor.dependency.internal.DefaultDependency; -import org.sonar.api.batch.sensor.duplication.DuplicationBuilder; -import org.sonar.api.batch.sensor.duplication.DuplicationGroup; -import org.sonar.api.batch.sensor.duplication.DuplicationTokenBuilder; -import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplicationBuilder; -import org.sonar.api.batch.sensor.highlighting.HighlightingBuilder; -import org.sonar.api.batch.sensor.issue.Issue; -import org.sonar.api.batch.sensor.issue.internal.DefaultIssue; -import org.sonar.api.batch.sensor.measure.Measure; -import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; -import org.sonar.api.batch.sensor.symbol.SymbolTableBuilder; -import org.sonar.api.batch.sensor.test.Coverage; -import org.sonar.api.batch.sensor.test.TestCaseCoverage; -import org.sonar.api.batch.sensor.test.TestCaseExecution; -import org.sonar.api.batch.sensor.test.internal.DefaultCoverage; -import org.sonar.api.batch.sensor.test.internal.DefaultTestCaseCoverage; -import org.sonar.api.batch.sensor.test.internal.DefaultTestCaseExecution; -import org.sonar.api.config.Settings; -import org.sonar.batch.duplication.BlockCache; -import org.sonar.batch.duplication.DefaultTokenBuilder; -import org.sonar.batch.duplication.DuplicationCache; -import org.sonar.batch.highlighting.DefaultHighlightingBuilder; -import org.sonar.batch.index.ComponentDataCache; -import org.sonar.batch.scan.SensorContextAdapter; -import org.sonar.batch.symbol.DefaultSymbolTableBuilder; -import org.sonar.duplications.internal.pmd.PmdBlockChunker; - -import java.io.Serializable; -import java.util.List; - -/** - * Common bits between {@link DefaultSensorContext} and {@link SensorContextAdapter} - * @author julien - * - */ -public abstract class BaseSensorContext implements SensorContext, SensorStorage { - - private final Settings settings; - private final FileSystem fs; - private final ActiveRules activeRules; - private final ComponentDataCache componentDataCache; - private final BlockCache blockCache; - private final DuplicationCache duplicationCache; - - protected BaseSensorContext(Settings settings, FileSystem fs, ActiveRules activeRules, ComponentDataCache componentDataCache, - BlockCache blockCache, DuplicationCache duplicationCache) { - this.settings = settings; - this.fs = fs; - this.activeRules = activeRules; - this.componentDataCache = componentDataCache; - this.blockCache = blockCache; - this.duplicationCache = duplicationCache; - } - - @Override - public Settings settings() { - return settings; - } - - @Override - public FileSystem fileSystem() { - return fs; - } - - @Override - public ActiveRules activeRules() { - return activeRules; - } - - @Override - public Measure newMeasure() { - return (Measure) new DefaultMeasure(this); - } - - @Override - public Issue newIssue() { - return new DefaultIssue(this); - } - - @Override - public HighlightingBuilder highlightingBuilder(InputFile inputFile) { - return new DefaultHighlightingBuilder(((DefaultInputFile) inputFile).key(), componentDataCache); - } - - @Override - public SymbolTableBuilder symbolTableBuilder(InputFile inputFile) { - return new DefaultSymbolTableBuilder(((DefaultInputFile) inputFile).key(), componentDataCache); - } - - @Override - public DuplicationTokenBuilder duplicationTokenBuilder(InputFile inputFile) { - PmdBlockChunker blockChunker = new PmdBlockChunker(getBlockSize(inputFile.language())); - - return new DefaultTokenBuilder(inputFile, blockCache, blockChunker); - } - - @Override - public DuplicationBuilder duplicationBuilder(InputFile inputFile) { - return new DefaultDuplicationBuilder(inputFile); - } - - @Override - public void saveDuplications(InputFile inputFile, List duplications) { - Preconditions.checkState(!duplications.isEmpty(), "Empty duplications"); - String effectiveKey = ((DefaultInputFile) inputFile).key(); - for (DuplicationGroup duplicationGroup : duplications) { - Preconditions.checkState(effectiveKey.equals(duplicationGroup.originBlock().resourceKey()), "Invalid duplication group"); - } - duplicationCache.put(effectiveKey, duplications); - } - - private int getBlockSize(String languageKey) { - int blockSize = settings.getInt("sonar.cpd." + languageKey + ".minimumLines"); - if (blockSize == 0) { - blockSize = getDefaultBlockSize(languageKey); - } - return blockSize; - } - - private static int getDefaultBlockSize(String languageKey) { - if ("cobol".equals(languageKey)) { - return 30; - } else if ("abap".equals(languageKey) || "natur".equals(languageKey)) { - return 20; - } else { - return 10; - } - } - - @Override - public Coverage newCoverage() { - return new DefaultCoverage(this); - } - - @Override - public TestCaseExecution newTestCaseExecution() { - return new DefaultTestCaseExecution(this); - } - - @Override - public TestCaseCoverage newTestCaseCoverage() { - return new DefaultTestCaseCoverage(this); - } - - @Override - public Dependency newDependency() { - return new DefaultDependency(this); - } - -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultSensorContext.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultSensorContext.java deleted file mode 100644 index cb70fa25b6a..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultSensorContext.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * 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.batch.scan2; - -import com.google.common.base.Strings; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.sonar.api.batch.bootstrap.ProjectDefinition; -import org.sonar.api.batch.fs.FileSystem; -import org.sonar.api.batch.fs.InputFile; -import org.sonar.api.batch.fs.InputPath; -import org.sonar.api.batch.measure.Metric; -import org.sonar.api.batch.rule.ActiveRules; -import org.sonar.api.batch.rule.internal.DefaultActiveRule; -import org.sonar.api.batch.sensor.dependency.Dependency; -import org.sonar.api.batch.sensor.issue.Issue; -import org.sonar.api.batch.sensor.issue.internal.DefaultIssue; -import org.sonar.api.batch.sensor.measure.Measure; -import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; -import org.sonar.api.batch.sensor.test.TestCaseCoverage; -import org.sonar.api.batch.sensor.test.TestCaseExecution; -import org.sonar.api.batch.sensor.test.internal.DefaultTestCaseExecution; -import org.sonar.api.config.Settings; -import org.sonar.api.measures.CoreMetrics; -import org.sonar.api.rule.RuleKey; -import org.sonar.api.utils.MessageException; -import org.sonar.batch.dependency.DependencyCache; -import org.sonar.batch.duplication.BlockCache; -import org.sonar.batch.duplication.DuplicationCache; -import org.sonar.batch.index.ComponentDataCache; -import org.sonar.batch.issue.IssueFilters; -import org.sonar.batch.scan.SensorContextAdapter; -import org.sonar.batch.test.TestCaseCoverageCache; -import org.sonar.batch.test.TestCaseExecutionCache; -import org.sonar.core.component.ComponentKeys; - -import java.io.Serializable; -import java.util.Arrays; -import java.util.List; - -public class DefaultSensorContext extends BaseSensorContext { - - private static final Logger LOG = LoggerFactory.getLogger(DefaultSensorContext.class); - - public static final List INTERNAL_METRICS = Arrays.asList( - // Computed by DsmDecorator - CoreMetrics.DEPENDENCY_MATRIX, - CoreMetrics.DIRECTORY_CYCLES, - CoreMetrics.DIRECTORY_EDGES_WEIGHT, - CoreMetrics.DIRECTORY_FEEDBACK_EDGES, - CoreMetrics.DIRECTORY_TANGLE_INDEX, - CoreMetrics.DIRECTORY_TANGLES, - CoreMetrics.FILE_CYCLES, - CoreMetrics.FILE_EDGES_WEIGHT, - CoreMetrics.FILE_FEEDBACK_EDGES, - CoreMetrics.FILE_TANGLE_INDEX, - CoreMetrics.FILE_TANGLES, - // Computed by ScmActivitySensor - CoreMetrics.SCM_AUTHORS_BY_LINE, - CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE, - CoreMetrics.SCM_REVISIONS_BY_LINE, - // Computed by core duplication plugin - CoreMetrics.DUPLICATIONS_DATA, - CoreMetrics.DUPLICATION_LINES_DATA, - CoreMetrics.DUPLICATED_FILES, - CoreMetrics.DUPLICATED_LINES, - CoreMetrics.DUPLICATED_BLOCKS - ); - private final MeasureCache measureCache; - private final IssueCache issueCache; - private final ProjectDefinition def; - private final ActiveRules activeRules; - private final IssueFilters issueFilters; - private final TestCaseExecutionCache testCaseExecutionCache; - private final TestCaseCoverageCache coveragePerTestCache; - private final DependencyCache dependencyCache; - - public DefaultSensorContext(ProjectDefinition def, MeasureCache measureCache, IssueCache issueCache, - Settings settings, FileSystem fs, ActiveRules activeRules, IssueFilters issueFilters, ComponentDataCache componentDataCache, - BlockCache blockCache, DuplicationCache duplicationCache, TestCaseExecutionCache testCaseCache, TestCaseCoverageCache coveragePerTestCache, DependencyCache dependencyCache) { - super(settings, fs, activeRules, componentDataCache, blockCache, duplicationCache); - this.def = def; - this.measureCache = measureCache; - this.issueCache = issueCache; - this.activeRules = activeRules; - this.issueFilters = issueFilters; - this.testCaseExecutionCache = testCaseCache; - this.coveragePerTestCache = coveragePerTestCache; - this.dependencyCache = dependencyCache; - } - - @Override - public void store(Measure newMeasure) { - DefaultMeasure measure = (DefaultMeasure) newMeasure; - if (!measure.isFromCore() && INTERNAL_METRICS.contains(measure.metric())) { - throw new IllegalArgumentException("Metric " + measure.metric().key() + " is an internal metric computed by SonarQube. Please remove or update offending plugin."); - } - InputFile inputFile = measure.inputFile(); - if (inputFile != null) { - measureCache.put(def.getKey(), ComponentKeys.createEffectiveKey(def.getKey(), inputFile), measure); - } else { - measureCache.put(def.getKey(), def.getKey(), measure); - } - } - - @Override - public void store(Issue issue) { - String resourceKey; - InputPath inputPath = issue.inputPath(); - if (inputPath != null) { - resourceKey = ComponentKeys.createEffectiveKey(def.getKey(), inputPath); - } else { - resourceKey = def.getKey(); - } - RuleKey ruleKey = issue.ruleKey(); - DefaultActiveRule activeRule = (DefaultActiveRule) activeRules.find(ruleKey); - if (activeRule == null) { - // rule does not exist or is not enabled -> ignore the issue - LOG.debug("Rule {} does not exists or is not enabled. Issue {} is ignored.", issue.ruleKey(), issue); - return; - } - if (Strings.isNullOrEmpty(activeRule.name()) && Strings.isNullOrEmpty(issue.message())) { - throw MessageException.of(String.format("The rule '%s' has no name and the related issue has no message.", ruleKey)); - } - - updateIssue((DefaultIssue) issue, activeRule); - - if (!issueFilters.accept(SensorContextAdapter.toDefaultIssue(def.getKey(), resourceKey, issue))) { - LOG.debug("Issue {} was excluded by some filters.", issue); - return; - } - issueCache.put(def.getKey(), resourceKey, (DefaultIssue) issue); - } - - private void updateIssue(DefaultIssue issue, DefaultActiveRule activeRule) { - if (Strings.isNullOrEmpty(issue.message())) { - issue.message(activeRule.name()); - } - } - - @Override - public void store(TestCaseExecution testCaseExecution) { - if (testCaseExecutionCache.contains(((DefaultTestCaseExecution) testCaseExecution).testFile(), testCaseExecution.name())) { - throw new IllegalArgumentException("There is already a test case with the same name: " + testCaseExecution.name()); - } - testCaseExecutionCache.put(((DefaultTestCaseExecution) testCaseExecution).testFile(), testCaseExecution); - } - - @Override - public void store(TestCaseCoverage testCaseCoverage) { - if (coveragePerTestCache.getCoverage(testCaseCoverage.testFile(), testCaseCoverage.testName(), testCaseCoverage.coveredFile()) != null) { - throw new IllegalArgumentException("Test coverage already registered for this combination of test file, test name and main file: " + testCaseCoverage); - } - coveragePerTestCache.put(testCaseCoverage); - } - - @Override - public void store(Dependency dep) { - if (dependencyCache.get(def.getKey(), dep.from(), dep.to()) != null) { - throw new IllegalStateException("Dependency between " + dep.from() + " and " + dep.to() + " was already saved."); - } - dependencyCache.put(def.getKey(), dep); - } - -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/MeasureCache.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/MeasureCache.java deleted file mode 100644 index e0c9d5a6db5..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/scan2/MeasureCache.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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.batch.scan2; - -import com.google.common.base.Preconditions; -import org.sonar.api.BatchComponent; -import org.sonar.api.batch.measure.MetricFinder; -import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; -import org.sonar.batch.index.Cache; -import org.sonar.batch.index.Cache.Entry; -import org.sonar.batch.index.Caches; -import org.sonar.batch.scan.filesystem.InputPathCache; - -/** - * Cache of all measures. This cache is shared amongst all project modules. - */ -public class MeasureCache implements BatchComponent { - - // project key -> component key -> metric key -> measure - private final Cache cache; - - public MeasureCache(Caches caches, MetricFinder metricFinder, InputPathCache inputPathCache) { - caches.registerValueCoder(DefaultMeasure.class, new DefaultMeasureValueCoder(metricFinder, inputPathCache)); - cache = caches.createCache("measures"); - } - - public Iterable> entries() { - return cache.entries(); - } - - public Iterable byModule(String projectKey) { - return cache.values(projectKey); - } - - public DefaultMeasure byMetric(String projectKey, String resourceKey, String metricKey) { - return cache.get(projectKey, resourceKey, metricKey); - } - - public MeasureCache put(String projectKey, String resourceKey, DefaultMeasure measure) { - Preconditions.checkNotNull(projectKey); - Preconditions.checkNotNull(resourceKey); - Preconditions.checkNotNull(measure); - cache.put(projectKey, resourceKey, measure.metric().key(), measure); - return this; - } - - public boolean contains(String projectKey, String resourceKey, DefaultMeasure measure) { - Preconditions.checkNotNull(projectKey); - Preconditions.checkNotNull(resourceKey); - Preconditions.checkNotNull(measure); - return cache.containsKey(projectKey, resourceKey, measure.metric().key()); - } - - public Iterable all() { - return cache.values(); - } - -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/ModuleScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/ModuleScanContainer.java deleted file mode 100644 index 5d3cb485f47..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/scan2/ModuleScanContainer.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * 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.batch.scan2; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.sonar.api.BatchComponent; -import org.sonar.api.batch.InstantiationStrategy; -import org.sonar.api.batch.bootstrap.ProjectDefinition; -import org.sonar.api.batch.rule.CheckFactory; -import org.sonar.api.platform.ComponentContainer; -import org.sonar.api.scan.filesystem.FileExclusions; -import org.sonar.batch.bootstrap.BatchExtensionDictionnary; -import org.sonar.batch.bootstrap.ExtensionInstaller; -import org.sonar.batch.bootstrap.ExtensionMatcher; -import org.sonar.batch.bootstrap.ExtensionUtils; -import org.sonar.batch.events.EventBus; -import org.sonar.batch.issue.IssuableFactory; -import org.sonar.batch.issue.IssueFilters; -import org.sonar.batch.issue.ModuleIssues; -import org.sonar.batch.issue.ignore.EnforceIssuesFilter; -import org.sonar.batch.issue.ignore.IgnoreIssuesFilter; -import org.sonar.batch.issue.ignore.pattern.IssueExclusionPatternInitializer; -import org.sonar.batch.issue.ignore.pattern.IssueInclusionPatternInitializer; -import org.sonar.batch.issue.ignore.scanner.IssueExclusionsLoader; -import org.sonar.batch.issue.ignore.scanner.IssueExclusionsRegexpScanner; -import org.sonar.batch.rule.ActiveRulesProvider; -import org.sonar.batch.rule.ModuleQProfiles; -import org.sonar.batch.rule.QProfileVerifier; -import org.sonar.batch.scan.LanguageVerifier; -import org.sonar.batch.scan.ModuleSettings; -import org.sonar.batch.scan.filesystem.DefaultModuleFileSystem; -import org.sonar.batch.scan.filesystem.DeprecatedFileFilters; -import org.sonar.batch.scan.filesystem.ExclusionFilters; -import org.sonar.batch.scan.filesystem.FileIndexer; -import org.sonar.batch.scan.filesystem.FileSystemLogger; -import org.sonar.batch.scan.filesystem.InputFileBuilderFactory; -import org.sonar.batch.scan.filesystem.LanguageDetectionFactory; -import org.sonar.batch.scan.filesystem.ModuleFileSystemInitializer; -import org.sonar.batch.scan.filesystem.ModuleInputFileCache; -import org.sonar.batch.scan.filesystem.StatusDetectionFactory; - -public class ModuleScanContainer extends ComponentContainer { - private static final Logger LOG = LoggerFactory.getLogger(ModuleScanContainer.class); - private final ProjectDefinition moduleDefinition; - - public ModuleScanContainer(ProjectScanContainer parent, ProjectDefinition moduleDefinition) { - super(parent); - this.moduleDefinition = moduleDefinition; - } - - @Override - protected void doBeforeStart() { - LOG.info("------------- Scan {}", moduleDefinition.getName()); - addCoreComponents(); - addExtensions(); - } - - private void addCoreComponents() { - add( - moduleDefinition, - ModuleSettings.class, - - EventBus.class, - ModuleScanExecutor.class, - ModuleScanExecutor.getPhaseClasses(), - moduleDefinition.getContainerExtensions(), - - // file system - ModuleInputFileCache.class, - FileExclusions.class, - ExclusionFilters.class, - DeprecatedFileFilters.class, - InputFileBuilderFactory.class, - StatusDetectionFactory.class, - LanguageDetectionFactory.class, - FileIndexer.class, - LanguageVerifier.class, - FileSystemLogger.class, - DefaultModuleFileSystem.class, - ModuleFileSystemInitializer.class, - QProfileVerifier.class, - - AnalyzerOptimizer.class, - - DefaultSensorContext.class, - BatchExtensionDictionnary.class, - IssueFilters.class, - - // rules - ModuleQProfiles.class, - new ActiveRulesProvider(), - CheckFactory.class, - - // issues - IssuableFactory.class, - ModuleIssues.class, - - // Measures - DefaultFileLinesContextFactory.class, - - // issue exclusions - IssueInclusionPatternInitializer.class, - IssueExclusionPatternInitializer.class, - IssueExclusionsRegexpScanner.class, - IssueExclusionsLoader.class, - EnforceIssuesFilter.class, - IgnoreIssuesFilter.class, - - AnalysisPublisher.class); - } - - private void addExtensions() { - ExtensionInstaller installer = getComponentByType(ExtensionInstaller.class); - installer.install(this, new ExtensionMatcher() { - @Override - public boolean accept(Object extension) { - return ExtensionUtils.isType(extension, BatchComponent.class) - && ExtensionUtils.isInstantiationStrategy(extension, InstantiationStrategy.PER_PROJECT); - } - }); - } - - @Override - protected void doAfterStart() { - getComponentByType(ModuleScanExecutor.class).execute(); - } - -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/ModuleScanExecutor.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/ModuleScanExecutor.java index 088125818df..943f93e1db0 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan2/ModuleScanExecutor.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan2/ModuleScanExecutor.java @@ -37,19 +37,16 @@ public final class ModuleScanExecutor { private final QProfileVerifier profileVerifier; private final IssueExclusionsLoader issueExclusionsLoader; - private AnalysisPublisher analyzisPublisher; - public ModuleScanExecutor(SensorsExecutor analyzersExecutor, SensorContext analyzerContext, FileSystemLogger fsLogger, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier, - IssueExclusionsLoader issueExclusionsLoader, AnalysisPublisher analyzisPublisher) { + IssueExclusionsLoader issueExclusionsLoader) { this.analyzersExecutor = analyzersExecutor; this.analyzerContext = analyzerContext; this.fsLogger = fsLogger; this.fs = fs; this.profileVerifier = profileVerifier; this.issueExclusionsLoader = issueExclusionsLoader; - this.analyzisPublisher = analyzisPublisher; } public static Collection getPhaseClasses() { @@ -73,8 +70,5 @@ public final class ModuleScanExecutor { analyzersExecutor.execute(analyzerContext); - // Export results - analyzisPublisher.execute(); - } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/ProjectScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/ProjectScanContainer.java deleted file mode 100644 index 5f796661473..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/scan2/ProjectScanContainer.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * 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.batch.scan2; - -import com.google.common.annotations.VisibleForTesting; -import org.sonar.api.BatchComponent; -import org.sonar.api.CoreProperties; -import org.sonar.api.batch.InstantiationStrategy; -import org.sonar.api.batch.bootstrap.ProjectBootstrapper; -import org.sonar.api.batch.bootstrap.ProjectDefinition; -import org.sonar.api.batch.bootstrap.ProjectReactor; -import org.sonar.api.config.Settings; -import org.sonar.api.platform.ComponentContainer; -import org.sonar.api.resources.Languages; -import org.sonar.api.scan.filesystem.PathResolver; -import org.sonar.batch.bootstrap.ExtensionInstaller; -import org.sonar.batch.bootstrap.ExtensionMatcher; -import org.sonar.batch.bootstrap.ExtensionUtils; -import org.sonar.batch.dependency.DependencyCache; -import org.sonar.batch.duplication.BlockCache; -import org.sonar.batch.duplication.DuplicationCache; -import org.sonar.batch.index.Caches; -import org.sonar.batch.index.ComponentDataCache; -import org.sonar.batch.index.ResourceCache; -import org.sonar.batch.languages.DefaultLanguagesReferential; -import org.sonar.batch.profiling.PhasesSumUpTimeProfiler; -import org.sonar.batch.referential.DefaultProjectReferentialsLoader; -import org.sonar.batch.referential.ProjectReferentialsLoader; -import org.sonar.batch.referential.ProjectReferentialsProvider; -import org.sonar.batch.scan.ProjectReactorBuilder; -import org.sonar.batch.scan.ProjectSettings; -import org.sonar.batch.scan.filesystem.InputPathCache; -import org.sonar.batch.scan.maven.FakeMavenPluginExecutor; -import org.sonar.batch.scan.maven.MavenPluginExecutor; -import org.sonar.batch.test.TestCaseCoverageCache; -import org.sonar.batch.test.TestCaseExecutionCache; - -public class ProjectScanContainer extends ComponentContainer { - public ProjectScanContainer(ComponentContainer taskContainer) { - super(taskContainer); - } - - @Override - protected void doBeforeStart() { - projectBootstrap(); - addBatchComponents(); - fixMavenExecutor(); - addBatchExtensions(); - Settings settings = getComponentByType(Settings.class); - if (settings != null && settings.getBoolean(CoreProperties.PROFILING_LOG_PROPERTY)) { - add(PhasesSumUpTimeProfiler.class); - } - } - - private void projectBootstrap() { - ProjectReactor reactor; - ProjectBootstrapper bootstrapper = getComponentByType(ProjectBootstrapper.class); - Settings settings = getComponentByType(Settings.class); - if (bootstrapper == null - // Starting from Maven plugin 2.3 then only DefaultProjectBootstrapper should be used. - || "true".equals(settings.getString("sonar.mojoUseRunner"))) { - // Use default SonarRunner project bootstrapper - ProjectReactorBuilder builder = getComponentByType(ProjectReactorBuilder.class); - reactor = builder.execute(); - } else { - reactor = bootstrapper.bootstrap(); - } - if (reactor == null) { - throw new IllegalStateException(bootstrapper + " has returned null as ProjectReactor"); - } - add(reactor); - if (getComponentByType(ProjectReferentialsLoader.class) == null) { - add(DefaultProjectReferentialsLoader.class); - } - } - - private void addBatchComponents() { - add( - new ProjectReferentialsProvider(), - ProjectSettings.class, - Caches.class, - ResourceCache.class, - - // lang - Languages.class, - DefaultLanguagesReferential.class, - - // Measures - MeasureCache.class, - - // file system - InputPathCache.class, - PathResolver.class, - - // issues - IssueCache.class, - - // Syntax highlighting and symbols - ComponentDataCache.class, - - // Duplications - BlockCache.class, - DuplicationCache.class, - - // Tests - TestCaseExecutionCache.class, - TestCaseCoverageCache.class, - - // Dependencies - DependencyCache.class, - - ScanTaskObservers.class); - } - - private void fixMavenExecutor() { - if (getComponentByType(MavenPluginExecutor.class) == null) { - add(FakeMavenPluginExecutor.class); - } - } - - private void addBatchExtensions() { - getComponentByType(ExtensionInstaller.class).install(this, new BatchExtensionFilter()); - } - - @Override - protected void doAfterStart() { - ProjectReactor tree = getComponentByType(ProjectReactor.class); - scanRecursively(tree.getRoot()); - - getComponentByType(ScanTaskObservers.class).notifyEndOfScanTask(); - } - - private void scanRecursively(ProjectDefinition module) { - for (ProjectDefinition subModules : module.getSubProjects()) { - scanRecursively(subModules); - } - scan(module); - } - - @VisibleForTesting - void scan(ProjectDefinition module) { - new ModuleScanContainer(this, module).execute(); - } - - static class BatchExtensionFilter implements ExtensionMatcher { - @Override - public boolean accept(Object extension) { - return ExtensionUtils.isType(extension, BatchComponent.class) - && ExtensionUtils.isInstantiationStrategy(extension, InstantiationStrategy.PER_BATCH); - } - } -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/ScanTaskObserver.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/ScanTaskObserver.java deleted file mode 100644 index 636ed9f34ed..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/scan2/ScanTaskObserver.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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.batch.scan2; - -import org.sonar.api.BatchExtension; - -public interface ScanTaskObserver extends BatchExtension { - - void scanTaskCompleted(ProjectScanContainer container); - -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/ScanTaskObservers.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/ScanTaskObservers.java deleted file mode 100644 index 6dc8fa6fd40..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/scan2/ScanTaskObservers.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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.batch.scan2; - -public class ScanTaskObservers { - - private ScanTaskObserver[] observers; - private ProjectScanContainer projectScanContainer; - - public ScanTaskObservers(ProjectScanContainer projectScanContainer, ScanTaskObserver... observers) { - this.projectScanContainer = projectScanContainer; - this.observers = observers; - } - - public ScanTaskObservers(ProjectScanContainer projectScanContainer) { - this(projectScanContainer, new ScanTaskObserver[0]); - } - - public void notifyEndOfScanTask() { - for (ScanTaskObserver scanTaskObserver : observers) { - scanTaskObserver.scanTaskCompleted(projectScanContainer); - } - } - -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorContext.java b/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorContext.java new file mode 100644 index 00000000000..e02fe9e1f90 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorContext.java @@ -0,0 +1,180 @@ +/* + * 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.batch.sensor; + +import com.google.common.base.Preconditions; +import org.sonar.api.batch.fs.FileSystem; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.fs.internal.DefaultInputFile; +import org.sonar.api.batch.rule.ActiveRules; +import org.sonar.api.batch.sensor.SensorContext; +import org.sonar.api.batch.sensor.SensorStorage; +import org.sonar.api.batch.sensor.dependency.Dependency; +import org.sonar.api.batch.sensor.dependency.internal.DefaultDependency; +import org.sonar.api.batch.sensor.duplication.DuplicationBuilder; +import org.sonar.api.batch.sensor.duplication.DuplicationGroup; +import org.sonar.api.batch.sensor.duplication.DuplicationTokenBuilder; +import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplicationBuilder; +import org.sonar.api.batch.sensor.highlighting.HighlightingBuilder; +import org.sonar.api.batch.sensor.issue.Issue; +import org.sonar.api.batch.sensor.issue.internal.DefaultIssue; +import org.sonar.api.batch.sensor.measure.NewMeasure; +import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; +import org.sonar.api.batch.sensor.symbol.SymbolTableBuilder; +import org.sonar.api.batch.sensor.test.Coverage; +import org.sonar.api.batch.sensor.test.TestCaseCoverage; +import org.sonar.api.batch.sensor.test.TestCaseExecution; +import org.sonar.api.batch.sensor.test.internal.DefaultCoverage; +import org.sonar.api.batch.sensor.test.internal.DefaultTestCaseCoverage; +import org.sonar.api.batch.sensor.test.internal.DefaultTestCaseExecution; +import org.sonar.api.config.Settings; +import org.sonar.batch.duplication.BlockCache; +import org.sonar.batch.duplication.DefaultTokenBuilder; +import org.sonar.batch.duplication.DuplicationCache; +import org.sonar.batch.highlighting.DefaultHighlightingBuilder; +import org.sonar.batch.index.ComponentDataCache; +import org.sonar.batch.symbol.DefaultSymbolTableBuilder; +import org.sonar.duplications.internal.pmd.PmdBlockChunker; + +import java.io.Serializable; +import java.util.List; + +/** + * Common bits between {@link ExperimentalSensorStorage} and {@link SensorContextAdapter} + * @author julien + * + */ +public class DefaultSensorContext implements SensorContext { + + private final Settings settings; + private final FileSystem fs; + private final ActiveRules activeRules; + private final ComponentDataCache componentDataCache; + private final BlockCache blockCache; + private final DuplicationCache duplicationCache; + private final SensorStorage sensorStorage; + + public DefaultSensorContext(Settings settings, FileSystem fs, ActiveRules activeRules, ComponentDataCache componentDataCache, + BlockCache blockCache, DuplicationCache duplicationCache, SensorStorage sensorStorage) { + this.settings = settings; + this.fs = fs; + this.activeRules = activeRules; + this.componentDataCache = componentDataCache; + this.blockCache = blockCache; + this.duplicationCache = duplicationCache; + this.sensorStorage = sensorStorage; + } + + @Override + public Settings settings() { + return settings; + } + + @Override + public FileSystem fileSystem() { + return fs; + } + + @Override + public ActiveRules activeRules() { + return activeRules; + } + + @Override + public NewMeasure newMeasure() { + return new DefaultMeasure(sensorStorage); + } + + @Override + public Issue newIssue() { + return new DefaultIssue(sensorStorage); + } + + @Override + public HighlightingBuilder highlightingBuilder(InputFile inputFile) { + return new DefaultHighlightingBuilder(((DefaultInputFile) inputFile).key(), componentDataCache); + } + + @Override + public SymbolTableBuilder symbolTableBuilder(InputFile inputFile) { + return new DefaultSymbolTableBuilder(((DefaultInputFile) inputFile).key(), componentDataCache); + } + + @Override + public DuplicationTokenBuilder duplicationTokenBuilder(InputFile inputFile) { + PmdBlockChunker blockChunker = new PmdBlockChunker(getBlockSize(inputFile.language())); + + return new DefaultTokenBuilder(inputFile, blockCache, blockChunker); + } + + @Override + public DuplicationBuilder duplicationBuilder(InputFile inputFile) { + return new DefaultDuplicationBuilder(inputFile); + } + + @Override + public void saveDuplications(InputFile inputFile, List duplications) { + Preconditions.checkState(!duplications.isEmpty(), "Empty duplications"); + String effectiveKey = ((DefaultInputFile) inputFile).key(); + for (DuplicationGroup duplicationGroup : duplications) { + Preconditions.checkState(effectiveKey.equals(duplicationGroup.originBlock().resourceKey()), "Invalid duplication group"); + } + duplicationCache.put(effectiveKey, duplications); + } + + private int getBlockSize(String languageKey) { + int blockSize = settings.getInt("sonar.cpd." + languageKey + ".minimumLines"); + if (blockSize == 0) { + blockSize = getDefaultBlockSize(languageKey); + } + return blockSize; + } + + private static int getDefaultBlockSize(String languageKey) { + if ("cobol".equals(languageKey)) { + return 30; + } else if ("abap".equals(languageKey) || "natur".equals(languageKey)) { + return 20; + } else { + return 10; + } + } + + @Override + public Coverage newCoverage() { + return new DefaultCoverage(sensorStorage); + } + + @Override + public TestCaseExecution newTestCaseExecution() { + return new DefaultTestCaseExecution(sensorStorage); + } + + @Override + public TestCaseCoverage newTestCaseCoverage() { + return new DefaultTestCaseCoverage(sensorStorage); + } + + @Override + public Dependency newDependency() { + return new DefaultDependency(sensorStorage); + } + +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorStorage.java b/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorStorage.java new file mode 100644 index 00000000000..c1c3e2ba384 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorStorage.java @@ -0,0 +1,262 @@ +/* + * 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.batch.sensor; + +import org.sonar.api.batch.fs.FileSystem; +import org.sonar.api.batch.fs.InputDir; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.fs.InputPath; +import org.sonar.api.batch.measure.MetricFinder; +import org.sonar.api.batch.rule.ActiveRules; +import org.sonar.api.batch.sensor.SensorStorage; +import org.sonar.api.batch.sensor.issue.Issue; +import org.sonar.api.batch.sensor.issue.Issue.Severity; +import org.sonar.api.batch.sensor.measure.Measure; +import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; +import org.sonar.api.batch.sensor.test.TestCaseCoverage; +import org.sonar.api.batch.sensor.test.TestCaseExecution; +import org.sonar.api.batch.sensor.test.internal.DefaultTestCaseExecution; +import org.sonar.api.component.ResourcePerspectives; +import org.sonar.api.config.Settings; +import org.sonar.api.design.Dependency; +import org.sonar.api.issue.Issuable; +import org.sonar.api.issue.internal.DefaultIssue; +import org.sonar.api.measures.Formula; +import org.sonar.api.measures.Metric; +import org.sonar.api.measures.PersistenceMode; +import org.sonar.api.measures.SumChildDistributionFormula; +import org.sonar.api.resources.Directory; +import org.sonar.api.resources.File; +import org.sonar.api.resources.Project; +import org.sonar.api.resources.Qualifiers; +import org.sonar.api.resources.Resource; +import org.sonar.api.resources.Scopes; +import org.sonar.api.rule.RuleKey; +import org.sonar.api.test.MutableTestCase; +import org.sonar.api.test.MutableTestPlan; +import org.sonar.api.test.MutableTestable; +import org.sonar.api.test.Testable; +import org.sonar.batch.duplication.BlockCache; +import org.sonar.batch.duplication.DuplicationCache; +import org.sonar.batch.index.ComponentDataCache; +import org.sonar.batch.index.DefaultIndex; +import org.sonar.batch.sensor.coverage.CoverageExclusions; +import org.sonar.core.component.ComponentKeys; + +public class DefaultSensorStorage implements SensorStorage { + + private static final String USES = "USES"; + private final MetricFinder metricFinder; + private final Project project; + private final ResourcePerspectives perspectives; + private final DefaultIndex sonarIndex; + private final CoverageExclusions coverageExclusions; + + public DefaultSensorStorage(MetricFinder metricFinder, Project project, + ResourcePerspectives perspectives, + Settings settings, FileSystem fs, ActiveRules activeRules, ComponentDataCache componentDataCache, BlockCache blockCache, + DuplicationCache duplicationCache, DefaultIndex sonarIndex, CoverageExclusions coverageExclusions) { + this.metricFinder = metricFinder; + this.project = project; + this.perspectives = perspectives; + this.sonarIndex = sonarIndex; + this.coverageExclusions = coverageExclusions; + } + + private Metric findMetricOrFail(String metricKey) { + Metric m = (Metric) metricFinder.findByKey(metricKey); + if (m == null) { + throw new IllegalStateException("Unknow metric with key: " + metricKey); + } + return m; + } + + @Override + public void store(Measure newMeasure) { + DefaultMeasure measure = (DefaultMeasure) newMeasure; + org.sonar.api.measures.Metric m = findMetricOrFail(measure.metric().key()); + org.sonar.api.measures.Measure measureToSave = new org.sonar.api.measures.Measure(m); + setValueAccordingToMetricType(newMeasure, m, measureToSave); + measureToSave.setFromCore(measure.isFromCore()); + if (newMeasure.inputFile() != null) { + Formula formula = newMeasure.metric() instanceof org.sonar.api.measures.Metric ? + ((org.sonar.api.measures.Metric) newMeasure.metric()).getFormula() : null; + if (formula instanceof SumChildDistributionFormula + && !Scopes.isHigherThanOrEquals(Scopes.FILE, ((SumChildDistributionFormula) formula).getMinimumScopeToPersist())) { + measureToSave.setPersistenceMode(PersistenceMode.MEMORY); + } + File sonarFile = getFile(newMeasure.inputFile()); + if (coverageExclusions.accept(sonarFile, measureToSave)) { + sonarIndex.addMeasure(sonarFile, measureToSave); + } + } else { + sonarIndex.addMeasure(project, measureToSave); + } + } + + private void setValueAccordingToMetricType(Measure measure, org.sonar.api.measures.Metric m, org.sonar.api.measures.Measure measureToSave) { + switch (m.getType()) { + case BOOL: + measureToSave.setValue(Boolean.TRUE.equals(measure.value()) ? 1.0 : 0.0); + break; + case INT: + case MILLISEC: + measureToSave.setValue(Double.valueOf((Integer) measure.value())); + break; + case FLOAT: + case PERCENT: + case RATING: + measureToSave.setValue((Double) measure.value()); + break; + case STRING: + case LEVEL: + case DATA: + case DISTRIB: + measureToSave.setData((String) measure.value()); + break; + case WORK_DUR: + measureToSave.setValue(Double.valueOf((Long) measure.value())); + break; + default: + throw new UnsupportedOperationException("Unsupported type :" + m.getType()); + } + } + + @Override + public void store(Issue issue) { + Resource r; + InputPath inputPath = issue.inputPath(); + if (inputPath != null) { + if (inputPath instanceof InputDir) { + r = Directory.create(inputPath.relativePath()); + } else { + r = File.create(inputPath.relativePath()); + } + } else { + r = project; + } + Issuable issuable = perspectives.as(Issuable.class, r); + if (issuable == null) { + return; + } + issuable.addIssue(toDefaultIssue(project.getKey(), ComponentKeys.createEffectiveKey(project, r), issue)); + } + + public static DefaultIssue toDefaultIssue(String projectKey, String componentKey, Issue issue) { + Severity overridenSeverity = issue.overridenSeverity(); + return new org.sonar.core.issue.DefaultIssueBuilder() + .componentKey(componentKey) + .projectKey(projectKey) + .ruleKey(RuleKey.of(issue.ruleKey().repository(), issue.ruleKey().rule())) + .effortToFix(issue.effortToFix()) + .line(issue.line()) + .message(issue.message()) + .severity(overridenSeverity != null ? overridenSeverity.name() : null) + .build(); + } + + @Override + public void store(TestCaseExecution testCase) { + File testRes = getTestResource(((DefaultTestCaseExecution) testCase).testFile()); + MutableTestPlan testPlan = perspectives.as(MutableTestPlan.class, testRes); + if (testPlan != null) { + testPlan + .addTestCase(testCase.name()) + .setDurationInMs(testCase.durationInMs()) + .setType(testCase.type().name()) + .setStatus(org.sonar.api.test.TestCase.Status.valueOf(testCase.status().name())) + .setMessage(testCase.message()) + .setStackTrace(testCase.stackTrace()); + } + } + + @Override + public void store(TestCaseCoverage testCaseCoverage) { + File testRes = getTestResource(testCaseCoverage.testFile()); + File mainRes = getMainResource(testCaseCoverage.coveredFile()); + Testable testAbleFile = perspectives.as(MutableTestable.class, mainRes); + if (testAbleFile != null) { + MutableTestPlan testPlan = perspectives.as(MutableTestPlan.class, testRes); + if (testPlan != null) { + for (MutableTestCase mutableTestCase : testPlan.testCasesByName(testCaseCoverage.testName())) { + mutableTestCase.setCoverageBlock(testAbleFile, testCaseCoverage.coveredLines()); + } + } else { + throw new IllegalStateException("Unable to get MutableTestPlan perspective from " + testRes); + } + } else { + throw new IllegalStateException("Unable to get MutableTestable perspective from " + mainRes); + } + } + + private File getTestResource(InputFile testFile) { + File testRes = File.create(testFile.relativePath()); + testRes.setQualifier(Qualifiers.UNIT_TEST_FILE); + // Reload + testRes = sonarIndex.getResource(testRes); + if (testRes == null) { + throw new IllegalArgumentException("Provided input file is not indexed or not a test file: " + testFile); + } + return testRes; + } + + private File getMainResource(InputFile mainFile) { + File mainRes = File.create(mainFile.relativePath()); + // Reload + mainRes = sonarIndex.getResource(mainRes); + if (mainRes == null) { + throw new IllegalArgumentException("Provided input file is not indexed or not a main file: " + mainRes); + } + return mainRes; + } + + private File getFile(InputFile file) { + if (file.type() == InputFile.Type.MAIN) { + return getMainResource(file); + } else { + return getTestResource(file); + } + } + + @Override + public void store(org.sonar.api.batch.sensor.dependency.Dependency dep) { + File fromResource = getFile(dep.from()); + File toResource = getFile(dep.to()); + if (sonarIndex.getEdge(fromResource, toResource) != null) { + throw new IllegalStateException("Dependency between " + dep.from() + " and " + dep.to() + " was already saved."); + } + Directory fromParent = fromResource.getParent(); + Directory toParent = toResource.getParent(); + Dependency parentDep = null; + if (!fromParent.equals(toParent)) { + parentDep = sonarIndex.getEdge(fromParent, toParent); + if (parentDep != null) { + parentDep.setWeight(parentDep.getWeight() + 1); + } else { + parentDep = new Dependency(fromParent, toParent).setUsage(USES).setWeight(1); + parentDep = sonarIndex.addDependency(parentDep); + } + } + sonarIndex.addDependency(new Dependency(fromResource, toResource) + .setUsage(USES) + .setWeight(dep.weight()) + .setParent(parentDep)); + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/sensor/coverage/CoverageConstants.java b/sonar-batch/src/main/java/org/sonar/batch/sensor/coverage/CoverageConstants.java new file mode 100644 index 00000000000..46aa7173716 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/sensor/coverage/CoverageConstants.java @@ -0,0 +1,39 @@ +/* + * 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.batch.sensor.coverage; + +import com.google.common.collect.ImmutableList; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.api.measures.Metric; + +import java.util.Collection; + +public class CoverageConstants { + + public static final Collection COVERAGE_METRICS = ImmutableList.of(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); + + public static final Collection LINE_COVERAGE_METRICS = ImmutableList.of(CoreMetrics.UNCOVERED_LINES, CoreMetrics.LINES_TO_COVER, CoreMetrics.NEW_UNCOVERED_LINES, + CoreMetrics.NEW_LINES_TO_COVER); + + public static final Collection BRANCH_COVERAGE_METRICS = ImmutableList.of(CoreMetrics.UNCOVERED_CONDITIONS, CoreMetrics.CONDITIONS_TO_COVER, + CoreMetrics.NEW_UNCOVERED_CONDITIONS, CoreMetrics.NEW_CONDITIONS_TO_COVER); +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/sensor/coverage/CoverageExclusions.java b/sonar-batch/src/main/java/org/sonar/batch/sensor/coverage/CoverageExclusions.java new file mode 100644 index 00000000000..1545c060d07 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/sensor/coverage/CoverageExclusions.java @@ -0,0 +1,100 @@ +/* + * 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.batch.sensor.coverage; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableList.Builder; +import com.google.common.collect.ImmutableSet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.sonar.api.CoreProperties; +import org.sonar.api.config.Settings; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.api.measures.Measure; +import org.sonar.api.measures.Metric; +import org.sonar.api.resources.Resource; +import org.sonar.api.utils.WildcardPattern; + +import java.util.Collection; +import java.util.Iterator; + +public class CoverageExclusions { + + private static final Logger LOG = LoggerFactory.getLogger(CoverageExclusions.class); + + private final Settings settings; + private final ImmutableSet coverageMetrics; + private Collection resourcePatterns; + + public CoverageExclusions(Settings settings) { + this.settings = settings; + this.coverageMetrics = ImmutableSet.builder() + .add(CoreMetrics.COVERAGE) + .addAll(CoverageConstants.COVERAGE_METRICS) + .add(CoreMetrics.LINE_COVERAGE) + .addAll(CoverageConstants.LINE_COVERAGE_METRICS) + .add(CoreMetrics.BRANCH_COVERAGE) + .addAll(CoverageConstants.BRANCH_COVERAGE_METRICS) + .build(); + + initPatterns(); + } + + public boolean accept(Resource resource, Measure measure) { + if (isCoverageMetric(measure.getMetric())) { + return !hasMatchingPattern(resource); + } else { + return true; + } + } + + private boolean isCoverageMetric(Metric metric) { + return this.coverageMetrics.contains(metric); + } + + private boolean hasMatchingPattern(Resource resource) { + boolean found = false; + Iterator iterator = resourcePatterns.iterator(); + while (!found && iterator.hasNext()) { + found = resource.matchFilePattern(iterator.next().toString()); + } + return found; + } + + @VisibleForTesting + final void initPatterns() { + Builder builder = ImmutableList.builder(); + for (String pattern : settings.getStringArray(CoreProperties.PROJECT_COVERAGE_EXCLUSIONS_PROPERTY)) { + builder.add(WildcardPattern.create(pattern)); + } + resourcePatterns = builder.build(); + log("Excluded sources for coverage: ", resourcePatterns); + } + + private void log(String title, Collection patterns) { + if (!patterns.isEmpty()) { + LOG.info(title); + for (WildcardPattern pattern : patterns) { + LOG.info(" " + pattern); + } + } + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/sensor/package-info.java b/sonar-batch/src/main/java/org/sonar/batch/sensor/package-info.java new file mode 100644 index 00000000000..de8138fcecd --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/sensor/package-info.java @@ -0,0 +1,21 @@ +/* + * 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. + */ +@javax.annotation.ParametersAreNonnullByDefault +package org.sonar.batch.sensor; diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchExtensionDictionnaryTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchExtensionDictionnaryTest.java index b0c2e3076d6..1509a65ffea 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchExtensionDictionnaryTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchExtensionDictionnaryTest.java @@ -22,10 +22,10 @@ package org.sonar.batch.bootstrap; import org.junit.Test; import org.sonar.api.BatchExtension; import org.sonar.api.batch.Sensor; -import org.sonar.api.batch.sensor.SensorContext; import org.sonar.api.platform.ComponentContainer; import org.sonar.api.resources.Project; import org.sonar.batch.scan2.AnalyzerOptimizer; +import org.sonar.batch.sensor.DefaultSensorContext; import java.util.Collection; @@ -41,7 +41,7 @@ public class BatchExtensionDictionnaryTest { for (BatchExtension extension : extensions) { iocContainer.addSingleton(extension); } - return new BatchExtensionDictionnary(iocContainer, mock(SensorContext.class), mock(AnalyzerOptimizer.class)); + return new BatchExtensionDictionnary(iocContainer, mock(DefaultSensorContext.class), mock(AnalyzerOptimizer.class)); } @Test diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/measures/MeasuresMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/measures/MeasuresMediumTest.java index 6787ae5710f..f11c843c541 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/measures/MeasuresMediumTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/measures/MeasuresMediumTest.java @@ -25,6 +25,9 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.rules.TemporaryFolder; +import org.sonar.api.batch.fs.internal.DefaultInputFile; +import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; +import org.sonar.api.measures.CoreMetrics; import org.sonar.batch.mediumtest.BatchMediumTester; import org.sonar.batch.mediumtest.TaskResult; import org.sonar.xoo.XooPlugin; @@ -92,10 +95,10 @@ public class MeasuresMediumTest { assertThat(result.measures()).hasSize(2); - // assertThat(result.measures()).contains(new DefaultMeasure() - // .forMetric(CoreMetrics.LINES) - // .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo")) - // .withValue(20)); + assertThat(result.measures()).contains(new DefaultMeasure() + .forMetric(CoreMetrics.LINES) + .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo")) + .withValue(20)); } diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/scm/ScmMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/scm/ScmMediumTest.java index b7aacbcd2d1..4a6e1a79cef 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/scm/ScmMediumTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/scm/ScmMediumTest.java @@ -27,6 +27,9 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; +import org.sonar.api.batch.fs.internal.DefaultInputFile; +import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; +import org.sonar.api.measures.CoreMetrics; import org.sonar.batch.mediumtest.BatchMediumTester; import org.sonar.batch.mediumtest.TaskResult; import org.sonar.xoo.XooPlugin; @@ -80,15 +83,15 @@ public class ScmMediumTest { assertThat(result.measures()).hasSize(5); - // assertThat(result.measures()).contains(new DefaultMeasure() - // .forMetric(CoreMetrics.LINES) - // .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo")) - // .withValue(5)); - // - // assertThat(result.measures()).contains(new DefaultMeasure() - // .forMetric(CoreMetrics.SCM_AUTHORS_BY_LINE) - // .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo")) - // .withValue("1=;2=julien;3=julien;4=julien;5=simon")); + assertThat(result.measures()).contains(new DefaultMeasure() + .forMetric(CoreMetrics.LINES) + .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo")) + .withValue(5)); + + assertThat(result.measures()).contains(new DefaultMeasure() + .forMetric(CoreMetrics.SCM_AUTHORS_BY_LINE) + .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo")) + .withValue("1=;2=julien;3=julien;4=julien;5=simon")); } @Test @@ -136,15 +139,15 @@ public class ScmMediumTest { assertThat(result.measures()).hasSize(5); - // assertThat(result.measures()).contains(new DefaultMeasure() - // .forMetric(CoreMetrics.LINES) - // .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo")) - // .withValue(5)); - // - // assertThat(result.measures()).contains(new DefaultMeasure() - // .forMetric(CoreMetrics.SCM_AUTHORS_BY_LINE) - // .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo")) - // .withValue("1=;2=julien;3=julien;4=julien;5=simon")); + assertThat(result.measures()).contains(new DefaultMeasure() + .forMetric(CoreMetrics.LINES) + .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo")) + .withValue(5)); + + assertThat(result.measures()).contains(new DefaultMeasure() + .forMetric(CoreMetrics.SCM_AUTHORS_BY_LINE) + .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo")) + .withValue("1=;2=julien;3=julien;4=julien;5=simon")); } @Test @@ -167,15 +170,15 @@ public class ScmMediumTest { assertThat(result.measures()).hasSize(5); - // assertThat(result.measures()).contains(new DefaultMeasure() - // .forMetric(CoreMetrics.LINES) - // .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo")) - // .withValue(5)); - // - // assertThat(result.measures()).contains(new DefaultMeasure() - // .forMetric(CoreMetrics.SCM_AUTHORS_BY_LINE) - // .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo")) - // .withValue("1=;2=julien;3=julien;4=julien;5=simon")); + assertThat(result.measures()).contains(new DefaultMeasure() + .forMetric(CoreMetrics.LINES) + .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo")) + .withValue(5)); + + assertThat(result.measures()).contains(new DefaultMeasure() + .forMetric(CoreMetrics.SCM_AUTHORS_BY_LINE) + .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo")) + .withValue("1=;2=julien;3=julien;4=julien;5=simon")); } private File prepareProject() throws IOException { diff --git a/sonar-batch/src/test/java/org/sonar/batch/phases/DecoratorsExecutorTest.java b/sonar-batch/src/test/java/org/sonar/batch/phases/DecoratorsExecutorTest.java index 1fd1c4e081c..3f471711146 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/phases/DecoratorsExecutorTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/phases/DecoratorsExecutorTest.java @@ -33,7 +33,7 @@ import org.sonar.batch.DefaultDecoratorContext; import org.sonar.batch.duplication.DuplicationCache; import org.sonar.batch.events.EventBus; import org.sonar.batch.scan.measure.MeasureCache; -import org.sonar.core.measure.MeasurementFilters; +import org.sonar.batch.sensor.coverage.CoverageExclusions; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.fail; @@ -67,7 +67,7 @@ public class DecoratorsExecutorTest { doThrow(new SonarException()).when(decorator).decorate(any(Resource.class), any(DecoratorContext.class)); DecoratorsExecutor executor = new DecoratorsExecutor(mock(BatchExtensionDictionnary.class), new Project("key"), mock(SonarIndex.class), - mock(EventBus.class), mock(MeasurementFilters.class), mock(MeasureCache.class), mock(MetricFinder.class), mock(DuplicationCache.class)); + mock(EventBus.class), mock(CoverageExclusions.class), mock(MeasureCache.class), mock(MetricFinder.class), mock(DuplicationCache.class)); try { executor.executeDecorator(decorator, mock(DefaultDecoratorContext.class), File.create("src/org/foo/Bar.java", "org/foo/Bar.java", null, false)); fail("Exception has not been thrown"); diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/SensorContextAdapterTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/SensorContextAdapterTest.java deleted file mode 100644 index a5610c66aa2..00000000000 --- a/sonar-batch/src/test/java/org/sonar/batch/scan/SensorContextAdapterTest.java +++ /dev/null @@ -1,348 +0,0 @@ -/* - * 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.batch.scan; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.mockito.ArgumentCaptor; -import org.sonar.api.batch.SensorContext; -import org.sonar.api.batch.SonarIndex; -import org.sonar.api.batch.fs.InputDir; -import org.sonar.api.batch.fs.InputFile; -import org.sonar.api.batch.fs.InputFile.Type; -import org.sonar.api.batch.fs.internal.DefaultFileSystem; -import org.sonar.api.batch.fs.internal.DefaultInputDir; -import org.sonar.api.batch.fs.internal.DefaultInputFile; -import org.sonar.api.batch.measure.MetricFinder; -import org.sonar.api.batch.rule.ActiveRules; -import org.sonar.api.batch.rule.internal.ActiveRulesBuilder; -import org.sonar.api.batch.sensor.dependency.internal.DefaultDependency; -import org.sonar.api.batch.sensor.issue.Issue.Severity; -import org.sonar.api.batch.sensor.issue.internal.DefaultIssue; -import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; -import org.sonar.api.component.ResourcePerspectives; -import org.sonar.api.config.Settings; -import org.sonar.api.design.Dependency; -import org.sonar.api.issue.Issuable; -import org.sonar.api.issue.Issue; -import org.sonar.api.measures.CoreMetrics; -import org.sonar.api.measures.PersistenceMode; -import org.sonar.api.resources.Directory; -import org.sonar.api.resources.File; -import org.sonar.api.resources.Project; -import org.sonar.api.resources.Resource; -import org.sonar.api.rule.RuleKey; -import org.sonar.batch.duplication.BlockCache; -import org.sonar.batch.duplication.DuplicationCache; -import org.sonar.batch.index.ComponentDataCache; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class SensorContextAdapterTest { - - @Rule - public ExpectedException thrown = ExpectedException.none(); - - private ActiveRules activeRules; - private DefaultFileSystem fs; - private SensorContextAdapter adaptor; - private SensorContext sensorContext; - private Settings settings; - private ResourcePerspectives resourcePerspectives; - private Project project; - private SonarIndex sonarIndex; - - @Before - public void prepare() { - activeRules = new ActiveRulesBuilder().build(); - fs = new DefaultFileSystem(); - MetricFinder metricFinder = mock(MetricFinder.class); - when(metricFinder.findByKey(CoreMetrics.NCLOC_KEY)).thenReturn(CoreMetrics.NCLOC); - when(metricFinder.findByKey(CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION_KEY)).thenReturn(CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION); - sensorContext = mock(SensorContext.class); - settings = new Settings(); - resourcePerspectives = mock(ResourcePerspectives.class); - ComponentDataCache componentDataCache = mock(ComponentDataCache.class); - BlockCache blockCache = mock(BlockCache.class); - project = new Project("myProject"); - sonarIndex = mock(SonarIndex.class); - adaptor = new SensorContextAdapter(sensorContext, metricFinder, project, - resourcePerspectives, settings, fs, activeRules, componentDataCache, blockCache, mock(DuplicationCache.class), sonarIndex); - } - - @Test - public void shouldProvideComponents() { - assertThat(adaptor.activeRules()).isEqualTo(activeRules); - assertThat(adaptor.fileSystem()).isEqualTo(fs); - assertThat(adaptor.settings()).isEqualTo(settings); - - assertThat(adaptor.newIssue()).isNotNull(); - assertThat(adaptor.newMeasure()).isNotNull(); - } - - @Test - public void shouldFailIfUnknowMetric() { - InputFile file = new DefaultInputFile("foo", "src/Foo.php"); - - thrown.expect(IllegalStateException.class); - thrown.expectMessage("Unknow metric with key: lines"); - - adaptor.store(new DefaultMeasure() - .onFile(file) - .forMetric(CoreMetrics.LINES) - .withValue(10)); - } - - @Test - public void shouldSaveFileMeasureToSensorContext() { - InputFile file = new DefaultInputFile("foo", "src/Foo.php"); - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(org.sonar.api.measures.Measure.class); - when(sensorContext.saveMeasure(eq(file), argumentCaptor.capture())).thenReturn(null); - - adaptor.store(new DefaultMeasure() - .onFile(file) - .forMetric(CoreMetrics.NCLOC) - .withValue(10)); - - org.sonar.api.measures.Measure m = argumentCaptor.getValue(); - assertThat(m.getValue()).isEqualTo(10.0); - assertThat(m.getMetric()).isEqualTo(CoreMetrics.NCLOC); - } - - @Test - public void shouldSetAppropriatePersistenceMode() { - // Metric FUNCTION_COMPLEXITY_DISTRIBUTION is only persisted on directories. - - InputFile file = new DefaultInputFile("foo", "src/Foo.php"); - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(org.sonar.api.measures.Measure.class); - when(sensorContext.saveMeasure(eq(file), argumentCaptor.capture())).thenReturn(null); - - adaptor.store(new DefaultMeasure() - .onFile(file) - .forMetric(CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION) - .withValue("foo")); - - org.sonar.api.measures.Measure m = argumentCaptor.getValue(); - assertThat(m.getData()).isEqualTo("foo"); - assertThat(m.getMetric()).isEqualTo(CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION); - assertThat(m.getPersistenceMode()).isEqualTo(PersistenceMode.MEMORY); - - } - - @Test - public void shouldSaveProjectMeasureToSensorContext() { - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(org.sonar.api.measures.Measure.class); - when(sensorContext.saveMeasure(argumentCaptor.capture())).thenReturn(null); - - adaptor.store(new DefaultMeasure() - .onProject() - .forMetric(CoreMetrics.NCLOC) - .withValue(10)); - - org.sonar.api.measures.Measure m = argumentCaptor.getValue(); - assertThat(m.getValue()).isEqualTo(10.0); - assertThat(m.getMetric()).isEqualTo(CoreMetrics.NCLOC); - } - - @Test - public void shouldAddIssueOnFile() { - InputFile file = new DefaultInputFile("foo", "src/Foo.php"); - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Issue.class); - - Issuable issuable = mock(Issuable.class); - when(resourcePerspectives.as(Issuable.class, File.create("src/Foo.php"))).thenReturn(issuable); - - when(issuable.addIssue(argumentCaptor.capture())).thenReturn(true); - - adaptor.store(new DefaultIssue() - .onFile(file) - .ruleKey(RuleKey.of("foo", "bar")) - .message("Foo") - .atLine(3) - .effortToFix(10.0)); - - Issue issue = argumentCaptor.getValue(); - assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("foo", "bar")); - assertThat(issue.message()).isEqualTo("Foo"); - assertThat(issue.line()).isEqualTo(3); - assertThat(issue.severity()).isNull(); - assertThat(issue.effortToFix()).isEqualTo(10.0); - } - - @Test - public void shouldAddIssueOnDirectory() { - InputDir dir = new DefaultInputDir("foo", "src"); - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Issue.class); - - Issuable issuable = mock(Issuable.class); - when(resourcePerspectives.as(Issuable.class, Directory.create("src"))).thenReturn(issuable); - - when(issuable.addIssue(argumentCaptor.capture())).thenReturn(true); - - adaptor.store(new DefaultIssue() - .onDir(dir) - .ruleKey(RuleKey.of("foo", "bar")) - .message("Foo") - .effortToFix(10.0)); - - Issue issue = argumentCaptor.getValue(); - assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("foo", "bar")); - assertThat(issue.message()).isEqualTo("Foo"); - assertThat(issue.line()).isNull(); - assertThat(issue.severity()).isNull(); - assertThat(issue.effortToFix()).isEqualTo(10.0); - } - - @Test - public void shouldAddIssueOnProject() { - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Issue.class); - - Issuable issuable = mock(Issuable.class); - when(resourcePerspectives.as(Issuable.class, (Resource) project)).thenReturn(issuable); - - when(issuable.addIssue(argumentCaptor.capture())).thenReturn(true); - - adaptor.store(new DefaultIssue() - .onProject() - .ruleKey(RuleKey.of("foo", "bar")) - .message("Foo") - .overrideSeverity(Severity.BLOCKER) - .effortToFix(10.0)); - - Issue issue = argumentCaptor.getValue(); - assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("foo", "bar")); - assertThat(issue.message()).isEqualTo("Foo"); - assertThat(issue.line()).isNull(); - assertThat(issue.severity()).isEqualTo("BLOCKER"); - assertThat(issue.effortToFix()).isEqualTo(10.0); - } - - @Test - public void shouldStoreDependencyInSameFolder() { - - File foo = File.create("src/Foo.java"); - File bar = File.create("src/Bar.java"); - when(sensorContext.getResource(foo)).thenReturn(foo); - when(sensorContext.getResource(bar)).thenReturn(bar); - - adaptor.store(new DefaultDependency() - .from(new DefaultInputFile("foo", "src/Foo.java").setType(Type.MAIN)) - .to(new DefaultInputFile("foo", "src/Bar.java").setType(Type.MAIN)) - .weight(3)); - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Dependency.class); - - verify(sensorContext).saveDependency(argumentCaptor.capture()); - assertThat(argumentCaptor.getValue().getFrom()).isEqualTo(foo); - assertThat(argumentCaptor.getValue().getTo()).isEqualTo(bar); - assertThat(argumentCaptor.getValue().getWeight()).isEqualTo(3); - assertThat(argumentCaptor.getValue().getUsage()).isEqualTo("USES"); - } - - @Test - public void throw_if_attempt_to_save_same_dep_twice() { - - File foo = File.create("src/Foo.java"); - File bar = File.create("src/Bar.java"); - when(sensorContext.getResource(foo)).thenReturn(foo); - when(sensorContext.getResource(bar)).thenReturn(bar); - when(sonarIndex.getEdge(foo, bar)).thenReturn(new Dependency(foo, bar)); - - thrown.expect(IllegalStateException.class); - thrown.expectMessage("Dependency between [moduleKey=foo, relative=src/Foo.java, abs=null] and [moduleKey=foo, relative=src/Bar.java, abs=null] was already saved."); - - adaptor.store(new DefaultDependency() - .from(new DefaultInputFile("foo", "src/Foo.java").setType(Type.MAIN)) - .to(new DefaultInputFile("foo", "src/Bar.java").setType(Type.MAIN)) - .weight(3)); - } - - @Test - public void shouldStoreDependencyInDifferentFolder() { - - File foo = File.create("src1/Foo.java"); - File bar = File.create("src2/Bar.java"); - when(sensorContext.getResource(foo)).thenReturn(foo); - when(sensorContext.getResource(bar)).thenReturn(bar); - - adaptor.store(new DefaultDependency() - .from(new DefaultInputFile("foo", "src1/Foo.java").setType(Type.MAIN)) - .to(new DefaultInputFile("foo", "src2/Bar.java").setType(Type.MAIN)) - .weight(3)); - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Dependency.class); - - verify(sensorContext, times(2)).saveDependency(argumentCaptor.capture()); - assertThat(argumentCaptor.getAllValues()).hasSize(2); - Dependency value1 = argumentCaptor.getAllValues().get(0); - assertThat(value1.getFrom()).isEqualTo(Directory.create("src1")); - assertThat(value1.getTo()).isEqualTo(Directory.create("src2")); - assertThat(value1.getWeight()).isEqualTo(1); - assertThat(value1.getUsage()).isEqualTo("USES"); - - Dependency value2 = argumentCaptor.getAllValues().get(1); - assertThat(value2.getFrom()).isEqualTo(foo); - assertThat(value2.getTo()).isEqualTo(bar); - assertThat(value2.getWeight()).isEqualTo(3); - assertThat(value2.getUsage()).isEqualTo("USES"); - } - - @Test - public void shouldIncrementParentWeight() { - - File foo = File.create("src1/Foo.java"); - File bar = File.create("src2/Bar.java"); - Directory src1 = Directory.create("src1"); - Directory src2 = Directory.create("src2"); - when(sensorContext.getResource(foo)).thenReturn(foo); - when(sensorContext.getResource(bar)).thenReturn(bar); - Dependency parentDep = new Dependency(src1, src2).setWeight(4); - when(sonarIndex.getEdge(src1, src2)).thenReturn(parentDep); - - adaptor.store(new DefaultDependency() - .from(new DefaultInputFile("foo", "src1/Foo.java").setType(Type.MAIN)) - .to(new DefaultInputFile("foo", "src2/Bar.java").setType(Type.MAIN)) - .weight(3)); - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Dependency.class); - - verify(sensorContext).saveDependency(argumentCaptor.capture()); - - assertThat(parentDep.getWeight()).isEqualTo(5); - - Dependency value = argumentCaptor.getValue(); - assertThat(value.getFrom()).isEqualTo(foo); - assertThat(value.getTo()).isEqualTo(bar); - assertThat(value.getWeight()).isEqualTo(3); - assertThat(value.getUsage()).isEqualTo("USES"); - } -} diff --git a/sonar-batch/src/test/java/org/sonar/batch/sensor/DefaultSensorContextTest.java b/sonar-batch/src/test/java/org/sonar/batch/sensor/DefaultSensorContextTest.java new file mode 100644 index 00000000000..b51dccd8f05 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/sensor/DefaultSensorContextTest.java @@ -0,0 +1,76 @@ +/* + * 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.batch.sensor; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.batch.fs.internal.DefaultFileSystem; +import org.sonar.api.batch.measure.MetricFinder; +import org.sonar.api.batch.rule.ActiveRules; +import org.sonar.api.batch.rule.internal.ActiveRulesBuilder; +import org.sonar.api.batch.sensor.SensorStorage; +import org.sonar.api.config.Settings; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.batch.duplication.BlockCache; +import org.sonar.batch.duplication.DuplicationCache; +import org.sonar.batch.index.ComponentDataCache; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class DefaultSensorContextTest { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + private ActiveRules activeRules; + private DefaultFileSystem fs; + private DefaultSensorContext adaptor; + private Settings settings; + private SensorStorage sensorStorage; + + @Before + public void prepare() { + activeRules = new ActiveRulesBuilder().build(); + fs = new DefaultFileSystem(); + MetricFinder metricFinder = mock(MetricFinder.class); + when(metricFinder.findByKey(CoreMetrics.NCLOC_KEY)).thenReturn(CoreMetrics.NCLOC); + when(metricFinder.findByKey(CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION_KEY)).thenReturn(CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION); + settings = new Settings(); + ComponentDataCache componentDataCache = mock(ComponentDataCache.class); + BlockCache blockCache = mock(BlockCache.class); + sensorStorage = mock(SensorStorage.class); + adaptor = new DefaultSensorContext(settings, fs, activeRules, componentDataCache, blockCache, mock(DuplicationCache.class), sensorStorage); + } + + @Test + public void shouldProvideComponents() { + assertThat(adaptor.activeRules()).isEqualTo(activeRules); + assertThat(adaptor.fileSystem()).isEqualTo(fs); + assertThat(adaptor.settings()).isEqualTo(settings); + + assertThat(adaptor.newIssue()).isNotNull(); + assertThat(adaptor.newMeasure()).isNotNull(); + } + +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/sensor/DefaultSensorStorageTest.java b/sonar-batch/src/test/java/org/sonar/batch/sensor/DefaultSensorStorageTest.java new file mode 100644 index 00000000000..c977124e861 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/sensor/DefaultSensorStorageTest.java @@ -0,0 +1,345 @@ +/* + * 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.batch.sensor; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.ArgumentCaptor; +import org.sonar.api.batch.fs.InputDir; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.fs.InputFile.Type; +import org.sonar.api.batch.fs.internal.DefaultFileSystem; +import org.sonar.api.batch.fs.internal.DefaultInputDir; +import org.sonar.api.batch.fs.internal.DefaultInputFile; +import org.sonar.api.batch.measure.MetricFinder; +import org.sonar.api.batch.rule.ActiveRules; +import org.sonar.api.batch.rule.internal.ActiveRulesBuilder; +import org.sonar.api.batch.sensor.dependency.internal.DefaultDependency; +import org.sonar.api.batch.sensor.issue.Issue.Severity; +import org.sonar.api.batch.sensor.issue.internal.DefaultIssue; +import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; +import org.sonar.api.component.ResourcePerspectives; +import org.sonar.api.config.Settings; +import org.sonar.api.design.Dependency; +import org.sonar.api.issue.Issuable; +import org.sonar.api.issue.Issue; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.api.measures.Measure; +import org.sonar.api.measures.PersistenceMode; +import org.sonar.api.resources.Directory; +import org.sonar.api.resources.File; +import org.sonar.api.resources.Project; +import org.sonar.api.resources.Resource; +import org.sonar.api.rule.RuleKey; +import org.sonar.batch.duplication.BlockCache; +import org.sonar.batch.duplication.DuplicationCache; +import org.sonar.batch.index.ComponentDataCache; +import org.sonar.batch.index.DefaultIndex; +import org.sonar.batch.sensor.coverage.CoverageExclusions; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class DefaultSensorStorageTest { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + private ActiveRules activeRules; + private DefaultFileSystem fs; + private DefaultSensorStorage sensorStorage; + private Settings settings; + private ResourcePerspectives resourcePerspectives; + private Project project; + private DefaultIndex sonarIndex; + + @Before + public void prepare() { + activeRules = new ActiveRulesBuilder().build(); + fs = new DefaultFileSystem(); + MetricFinder metricFinder = mock(MetricFinder.class); + when(metricFinder.findByKey(CoreMetrics.NCLOC_KEY)).thenReturn(CoreMetrics.NCLOC); + when(metricFinder.findByKey(CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION_KEY)).thenReturn(CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION); + settings = new Settings(); + resourcePerspectives = mock(ResourcePerspectives.class); + ComponentDataCache componentDataCache = mock(ComponentDataCache.class); + BlockCache blockCache = mock(BlockCache.class); + project = new Project("myProject"); + sonarIndex = mock(DefaultIndex.class); + CoverageExclusions coverageExclusions = mock(CoverageExclusions.class); + when(coverageExclusions.accept(any(Resource.class), any(Measure.class))).thenReturn(true); + sensorStorage = new DefaultSensorStorage(metricFinder, project, + resourcePerspectives, settings, fs, activeRules, componentDataCache, blockCache, mock(DuplicationCache.class), sonarIndex, coverageExclusions); + } + + @Test + public void shouldFailIfUnknowMetric() { + InputFile file = new DefaultInputFile("foo", "src/Foo.php"); + + thrown.expect(IllegalStateException.class); + thrown.expectMessage("Unknow metric with key: lines"); + + sensorStorage.store(new DefaultMeasure() + .onFile(file) + .forMetric(CoreMetrics.LINES) + .withValue(10)); + } + + @Test + public void shouldSaveFileMeasureToSensorContext() { + InputFile file = new DefaultInputFile("foo", "src/Foo.php"); + + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(org.sonar.api.measures.Measure.class); + File sonarFile = File.create("src/Foo.php"); + when(sonarIndex.addMeasure(eq(sonarFile), argumentCaptor.capture())).thenReturn(null); + when(sonarIndex.getResource(sonarFile)).thenReturn(sonarFile); + sensorStorage.store(new DefaultMeasure() + .onFile(file) + .forMetric(CoreMetrics.NCLOC) + .withValue(10)); + + org.sonar.api.measures.Measure m = argumentCaptor.getValue(); + assertThat(m.getValue()).isEqualTo(10.0); + assertThat(m.getMetric()).isEqualTo(CoreMetrics.NCLOC); + } + + @Test + public void shouldSetAppropriatePersistenceMode() { + // Metric FUNCTION_COMPLEXITY_DISTRIBUTION is only persisted on directories. + + InputFile file = new DefaultInputFile("foo", "src/Foo.php"); + + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(org.sonar.api.measures.Measure.class); + File sonarFile = File.create("src/Foo.php"); + + when(sonarIndex.addMeasure(eq(sonarFile), argumentCaptor.capture())).thenReturn(null); + + when(sonarIndex.getResource(sonarFile)).thenReturn(sonarFile); + + sensorStorage.store(new DefaultMeasure() + .onFile(file) + .forMetric(CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION) + .withValue("foo")); + + org.sonar.api.measures.Measure m = argumentCaptor.getValue(); + assertThat(m.getData()).isEqualTo("foo"); + assertThat(m.getMetric()).isEqualTo(CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION); + assertThat(m.getPersistenceMode()).isEqualTo(PersistenceMode.MEMORY); + + } + + @Test + public void shouldSaveProjectMeasureToSensorContext() { + + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(org.sonar.api.measures.Measure.class); + when(sonarIndex.addMeasure(eq(project), argumentCaptor.capture())).thenReturn(null); + + sensorStorage.store(new DefaultMeasure() + .onProject() + .forMetric(CoreMetrics.NCLOC) + .withValue(10)); + + org.sonar.api.measures.Measure m = argumentCaptor.getValue(); + assertThat(m.getValue()).isEqualTo(10.0); + assertThat(m.getMetric()).isEqualTo(CoreMetrics.NCLOC); + } + + @Test + public void shouldAddIssueOnFile() { + InputFile file = new DefaultInputFile("foo", "src/Foo.php"); + + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Issue.class); + + Issuable issuable = mock(Issuable.class); + when(resourcePerspectives.as(Issuable.class, File.create("src/Foo.php"))).thenReturn(issuable); + + when(issuable.addIssue(argumentCaptor.capture())).thenReturn(true); + + sensorStorage.store(new DefaultIssue() + .onFile(file) + .ruleKey(RuleKey.of("foo", "bar")) + .message("Foo") + .atLine(3) + .effortToFix(10.0)); + + Issue issue = argumentCaptor.getValue(); + assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("foo", "bar")); + assertThat(issue.message()).isEqualTo("Foo"); + assertThat(issue.line()).isEqualTo(3); + assertThat(issue.severity()).isNull(); + assertThat(issue.effortToFix()).isEqualTo(10.0); + } + + @Test + public void shouldAddIssueOnDirectory() { + InputDir dir = new DefaultInputDir("foo", "src"); + + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Issue.class); + + Issuable issuable = mock(Issuable.class); + when(resourcePerspectives.as(Issuable.class, Directory.create("src"))).thenReturn(issuable); + + when(issuable.addIssue(argumentCaptor.capture())).thenReturn(true); + + sensorStorage.store(new DefaultIssue() + .onDir(dir) + .ruleKey(RuleKey.of("foo", "bar")) + .message("Foo") + .effortToFix(10.0)); + + Issue issue = argumentCaptor.getValue(); + assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("foo", "bar")); + assertThat(issue.message()).isEqualTo("Foo"); + assertThat(issue.line()).isNull(); + assertThat(issue.severity()).isNull(); + assertThat(issue.effortToFix()).isEqualTo(10.0); + } + + @Test + public void shouldAddIssueOnProject() { + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Issue.class); + + Issuable issuable = mock(Issuable.class); + when(resourcePerspectives.as(Issuable.class, (Resource) project)).thenReturn(issuable); + + when(issuable.addIssue(argumentCaptor.capture())).thenReturn(true); + + sensorStorage.store(new DefaultIssue() + .onProject() + .ruleKey(RuleKey.of("foo", "bar")) + .message("Foo") + .overrideSeverity(Severity.BLOCKER) + .effortToFix(10.0)); + + Issue issue = argumentCaptor.getValue(); + assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("foo", "bar")); + assertThat(issue.message()).isEqualTo("Foo"); + assertThat(issue.line()).isNull(); + assertThat(issue.severity()).isEqualTo("BLOCKER"); + assertThat(issue.effortToFix()).isEqualTo(10.0); + } + + @Test + public void shouldStoreDependencyInSameFolder() { + + File foo = File.create("src/Foo.java"); + File bar = File.create("src/Bar.java"); + when(sonarIndex.getResource(foo)).thenReturn(foo); + when(sonarIndex.getResource(bar)).thenReturn(bar); + + sensorStorage.store(new DefaultDependency() + .from(new DefaultInputFile("foo", "src/Foo.java").setType(Type.MAIN)) + .to(new DefaultInputFile("foo", "src/Bar.java").setType(Type.MAIN)) + .weight(3)); + + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Dependency.class); + + verify(sonarIndex).addDependency(argumentCaptor.capture()); + assertThat(argumentCaptor.getValue().getFrom()).isEqualTo(foo); + assertThat(argumentCaptor.getValue().getTo()).isEqualTo(bar); + assertThat(argumentCaptor.getValue().getWeight()).isEqualTo(3); + assertThat(argumentCaptor.getValue().getUsage()).isEqualTo("USES"); + } + + @Test + public void throw_if_attempt_to_save_same_dep_twice() { + + File foo = File.create("src/Foo.java"); + File bar = File.create("src/Bar.java"); + when(sonarIndex.getResource(foo)).thenReturn(foo); + when(sonarIndex.getResource(bar)).thenReturn(bar); + when(sonarIndex.getEdge(foo, bar)).thenReturn(new Dependency(foo, bar)); + + thrown.expect(IllegalStateException.class); + thrown.expectMessage("Dependency between [moduleKey=foo, relative=src/Foo.java, abs=null] and [moduleKey=foo, relative=src/Bar.java, abs=null] was already saved."); + + sensorStorage.store(new DefaultDependency() + .from(new DefaultInputFile("foo", "src/Foo.java").setType(Type.MAIN)) + .to(new DefaultInputFile("foo", "src/Bar.java").setType(Type.MAIN)) + .weight(3)); + } + + @Test + public void shouldStoreDependencyInDifferentFolder() { + + File foo = File.create("src1/Foo.java"); + File bar = File.create("src2/Bar.java"); + when(sonarIndex.getResource(foo)).thenReturn(foo); + when(sonarIndex.getResource(bar)).thenReturn(bar); + + sensorStorage.store(new DefaultDependency() + .from(new DefaultInputFile("foo", "src1/Foo.java").setType(Type.MAIN)) + .to(new DefaultInputFile("foo", "src2/Bar.java").setType(Type.MAIN)) + .weight(3)); + + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Dependency.class); + + verify(sonarIndex, times(2)).addDependency(argumentCaptor.capture()); + assertThat(argumentCaptor.getAllValues()).hasSize(2); + Dependency value1 = argumentCaptor.getAllValues().get(0); + assertThat(value1.getFrom()).isEqualTo(Directory.create("src1")); + assertThat(value1.getTo()).isEqualTo(Directory.create("src2")); + assertThat(value1.getWeight()).isEqualTo(1); + assertThat(value1.getUsage()).isEqualTo("USES"); + + Dependency value2 = argumentCaptor.getAllValues().get(1); + assertThat(value2.getFrom()).isEqualTo(foo); + assertThat(value2.getTo()).isEqualTo(bar); + assertThat(value2.getWeight()).isEqualTo(3); + assertThat(value2.getUsage()).isEqualTo("USES"); + } + + @Test + public void shouldIncrementParentWeight() { + + File foo = File.create("src1/Foo.java"); + File bar = File.create("src2/Bar.java"); + Directory src1 = Directory.create("src1"); + Directory src2 = Directory.create("src2"); + when(sonarIndex.getResource(foo)).thenReturn(foo); + when(sonarIndex.getResource(bar)).thenReturn(bar); + Dependency parentDep = new Dependency(src1, src2).setWeight(4); + when(sonarIndex.getEdge(src1, src2)).thenReturn(parentDep); + + sensorStorage.store(new DefaultDependency() + .from(new DefaultInputFile("foo", "src1/Foo.java").setType(Type.MAIN)) + .to(new DefaultInputFile("foo", "src2/Bar.java").setType(Type.MAIN)) + .weight(3)); + + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Dependency.class); + + verify(sonarIndex).addDependency(argumentCaptor.capture()); + + assertThat(parentDep.getWeight()).isEqualTo(5); + + Dependency value = argumentCaptor.getValue(); + assertThat(value.getFrom()).isEqualTo(foo); + assertThat(value.getTo()).isEqualTo(bar); + assertThat(value.getWeight()).isEqualTo(3); + assertThat(value.getUsage()).isEqualTo("USES"); + } +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/sensor/coverage/CoverageExclusionsTest.java b/sonar-batch/src/test/java/org/sonar/batch/sensor/coverage/CoverageExclusionsTest.java new file mode 100644 index 00000000000..ec592a7962e --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/sensor/coverage/CoverageExclusionsTest.java @@ -0,0 +1,76 @@ +/* + * 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.batch.sensor.coverage; + +import org.junit.Before; +import org.junit.Test; +import org.sonar.api.config.PropertyDefinitions; +import org.sonar.api.config.Settings; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.api.measures.Measure; +import org.sonar.api.resources.File; +import org.sonar.api.resources.Resource; +import org.sonar.core.config.ExclusionProperties; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class CoverageExclusionsTest { + + private Settings settings; + + private CoverageExclusions filter; + + @Before + public void createFilter() { + settings = new Settings(new PropertyDefinitions(ExclusionProperties.all())); + filter = new CoverageExclusions(settings); + } + + @Test + public void shouldNotFilterNonCoverageMetrics() { + Measure otherMeasure = mock(Measure.class); + when(otherMeasure.getMetric()).thenReturn(CoreMetrics.LINES); + assertThat(filter.accept(mock(Resource.class), otherMeasure)).isTrue(); + } + + @Test + public void shouldFilterFileBasedOnPattern() { + Resource resource = File.create("src/org/polop/File.php", "org/polop/File.php", null, false); + Measure coverageMeasure = mock(Measure.class); + when(coverageMeasure.getMetric()).thenReturn(CoreMetrics.LINES_TO_COVER); + + settings.setProperty("sonar.coverage.exclusions", "src/org/polop/*"); + filter.initPatterns(); + assertThat(filter.accept(resource, coverageMeasure)).isFalse(); + } + + @Test + public void shouldNotFilterFileBasedOnPattern() { + Resource resource = File.create("src/org/polop/File.php", "org/polop/File.php", null, false); + Measure coverageMeasure = mock(Measure.class); + when(coverageMeasure.getMetric()).thenReturn(CoreMetrics.COVERAGE); + + settings.setProperty("sonar.coverage.exclusions", "src/org/other/*"); + filter.initPatterns(); + assertThat(filter.accept(resource, coverageMeasure)).isTrue(); + } +} diff --git a/sonar-core/src/main/java/org/sonar/core/measure/MeasurementFilter.java b/sonar-core/src/main/java/org/sonar/core/measure/MeasurementFilter.java deleted file mode 100644 index 324c7e4c1ca..00000000000 --- a/sonar-core/src/main/java/org/sonar/core/measure/MeasurementFilter.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.core.measure; - -import org.sonar.api.BatchExtension; - -import org.sonar.api.resources.Resource; -import org.sonar.api.measures.Measure; - -/** - * Allows to define filter {@link Measure}s when they are saved on {@link Resource}s - * @since 4.0 - * - */ -public interface MeasurementFilter extends BatchExtension { - - /** - * - * @param resource - * @param measure - * @return true if the given measure can be saved for the given resource - */ - boolean accept(Resource resource, Measure measure); -} diff --git a/sonar-core/src/main/java/org/sonar/core/measure/MeasurementFilters.java b/sonar-core/src/main/java/org/sonar/core/measure/MeasurementFilters.java deleted file mode 100644 index fa69974571d..00000000000 --- a/sonar-core/src/main/java/org/sonar/core/measure/MeasurementFilters.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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.core.measure; - -import com.google.common.collect.ImmutableList; -import org.sonar.api.BatchExtension; -import org.sonar.api.measures.Measure; -import org.sonar.api.resources.Resource; - -import java.util.Iterator; -import java.util.List; - -/** - * - * @since 4.0 - * - */ -public class MeasurementFilters implements BatchExtension { - - private List filters; - - public MeasurementFilters() { - this.filters = ImmutableList.of(); - } - - public MeasurementFilters(MeasurementFilter[] filters) { - this.filters = ImmutableList.copyOf(filters); - } - - public boolean accept(Resource resource, Measure measure) { - boolean accept = true; - Iterator iteratorFilter = filters.iterator(); - while(accept && iteratorFilter.hasNext()) { - accept &= iteratorFilter.next().accept(resource, measure); - } - return accept; - } -} diff --git a/sonar-core/src/main/java/org/sonar/core/measure/package-info.java b/sonar-core/src/main/java/org/sonar/core/measure/package-info.java deleted file mode 100644 index 036a513e710..00000000000 --- a/sonar-core/src/main/java/org/sonar/core/measure/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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. - */ -@ParametersAreNonnullByDefault -package org.sonar.core.measure; - -import javax.annotation.ParametersAreNonnullByDefault; - diff --git a/sonar-core/src/test/java/org/sonar/core/measure/MeasurementFiltersTest.java b/sonar-core/src/test/java/org/sonar/core/measure/MeasurementFiltersTest.java deleted file mode 100644 index cc0f1022f84..00000000000 --- a/sonar-core/src/test/java/org/sonar/core/measure/MeasurementFiltersTest.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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.core.measure; - -import org.assertj.core.util.Arrays; -import org.junit.Test; -import org.sonar.api.measures.Measure; -import org.sonar.api.resources.Resource; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.*; - -public class MeasurementFiltersTest { - - private MeasurementFilters filters; - - @Test - public void shouldAcceptEverythingWithEmptyFilters() { - filters = new MeasurementFilters(); - Resource resource = mock(Resource.class); - Measure measure = mock(Measure.class); - assertThat(filters.accept(resource, measure)).isTrue(); - } - - @Test - public void shouldAcceptIfAllFiltersAccept() { - Resource resource = mock(Resource.class); - Measure measure = mock(Measure.class); - MeasurementFilter filter1 = mock(MeasurementFilter.class); - when(filter1.accept(resource, measure)).thenReturn(true); - MeasurementFilter filter2 = mock(MeasurementFilter.class); - when(filter2.accept(resource, measure)).thenReturn(true); - - filters = new MeasurementFilters(Arrays.array(filter1, filter2)); - assertThat(filters.accept(resource, measure)).isTrue(); - } - - @Test - public void shouldNnotAcceptIfOneFilterDoesntAccept() { - Resource resource = mock(Resource.class); - Measure measure = mock(Measure.class); - MeasurementFilter filter1 = mock(MeasurementFilter.class); - when(filter1.accept(resource, measure)).thenReturn(false); - MeasurementFilter filter2 = mock(MeasurementFilter.class); - - filters = new MeasurementFilters(Arrays.array(filter1, filter2)); - assertThat(filters.accept(resource, measure)).isFalse(); - verifyZeroInteractions(filter2); - } -} diff --git a/sonar-deprecated/src/main/java/org/sonar/api/checks/NoSonarFilter.java b/sonar-deprecated/src/main/java/org/sonar/api/checks/NoSonarFilter.java index 7626ce1e018..16aa183e3a5 100644 --- a/sonar-deprecated/src/main/java/org/sonar/api/checks/NoSonarFilter.java +++ b/sonar-deprecated/src/main/java/org/sonar/api/checks/NoSonarFilter.java @@ -21,7 +21,7 @@ package org.sonar.api.checks; import com.google.common.collect.Maps; import org.apache.commons.lang.StringUtils; -import org.sonar.api.batch.SensorContext; +import org.sonar.api.batch.SonarIndex; import org.sonar.api.issue.Issue; import org.sonar.api.issue.batch.IssueFilterChain; import org.sonar.api.resources.Resource; @@ -37,16 +37,16 @@ import java.util.Set; public class NoSonarFilter implements org.sonar.api.issue.batch.IssueFilter { private final Map> noSonarLinesByKey = Maps.newHashMap(); - private SensorContext context; + private SonarIndex sonarIndex; - public NoSonarFilter(SensorContext context) { - this.context = context; + public NoSonarFilter(SonarIndex sonarIndex) { + this.sonarIndex = sonarIndex; } public void addResource(Resource model, Set noSonarLines) { if (model != null && noSonarLines != null) { // Reload resource to handle backward compatibility of resource keys - Resource resource = context.getResource(model); + Resource resource = sonarIndex.getResource(model); if (resource != null) { noSonarLinesByKey.put(resource.getEffectiveKey(), noSonarLines); } diff --git a/sonar-deprecated/src/test/java/org/sonar/api/checks/NoSonarFilterTest.java b/sonar-deprecated/src/test/java/org/sonar/api/checks/NoSonarFilterTest.java index 5be33366643..1521ca67b52 100644 --- a/sonar-deprecated/src/test/java/org/sonar/api/checks/NoSonarFilterTest.java +++ b/sonar-deprecated/src/test/java/org/sonar/api/checks/NoSonarFilterTest.java @@ -21,7 +21,7 @@ package org.sonar.api.checks; import org.junit.Before; import org.junit.Test; -import org.sonar.api.batch.SensorContext; +import org.sonar.api.batch.SonarIndex; import org.sonar.api.issue.Issue; import org.sonar.api.issue.batch.IssueFilterChain; import org.sonar.api.resources.File; @@ -37,8 +37,8 @@ import static org.mockito.Mockito.when; public class NoSonarFilterTest { - private SensorContext sensorContext = mock(SensorContext.class); - NoSonarFilter filter = new NoSonarFilter(sensorContext); + private SonarIndex sonarIndex = mock(SonarIndex.class); + NoSonarFilter filter = new NoSonarFilter(sonarIndex); private File javaFile; IssueFilterChain chain = mock(IssueFilterChain.class); @@ -47,7 +47,7 @@ public class NoSonarFilterTest { when(chain.accept(isA(Issue.class))).thenReturn(true); javaFile = new File("org.foo.Bar"); javaFile.setEffectiveKey("struts:org.apache.Action"); - when(sensorContext.getResource(javaFile)).thenReturn(javaFile); + when(sonarIndex.getResource(javaFile)).thenReturn(javaFile); } @Test diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/SensorContext.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/SensorContext.java index a21d421e6ac..b75209e1538 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/SensorContext.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/SensorContext.java @@ -40,7 +40,7 @@ import java.util.Set; /** * @since 1.10 */ -public interface SensorContext { +public interface SensorContext extends org.sonar.api.batch.sensor.SensorContext { /** * Indexes a resource as a direct child of project. This method does nothing and returns true if the resource already indexed. diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/maven/DependsUponMavenPlugin.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/maven/DependsUponMavenPlugin.java index 0e590c84593..e83df0c84e6 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/maven/DependsUponMavenPlugin.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/maven/DependsUponMavenPlugin.java @@ -33,7 +33,9 @@ import org.sonar.api.resources.Project; *

* * @since 1.10 + * @deprecated since 5.1 SQ platform don't want any dependency on Maven */ +@Deprecated @SupportedEnvironment("maven") public interface DependsUponMavenPlugin extends BatchExtension { diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/Sensor.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/Sensor.java index a0be6e447ab..01f0e109e53 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/Sensor.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/Sensor.java @@ -31,7 +31,7 @@ import org.sonar.api.BatchExtension; * For example the Cobertura Sensor parses Cobertura report and saves the first-level of measures on files. *

* - * @since 5.0 + * @since 5.1 */ public interface Sensor extends BatchExtension { diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorContext.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorContext.java index 805d9db2417..b32be9c7ab0 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorContext.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorContext.java @@ -29,6 +29,7 @@ import org.sonar.api.batch.sensor.duplication.DuplicationTokenBuilder; import org.sonar.api.batch.sensor.highlighting.HighlightingBuilder; import org.sonar.api.batch.sensor.issue.Issue; import org.sonar.api.batch.sensor.measure.Measure; +import org.sonar.api.batch.sensor.measure.NewMeasure; import org.sonar.api.batch.sensor.symbol.SymbolTableBuilder; import org.sonar.api.batch.sensor.test.Coverage; import org.sonar.api.batch.sensor.test.TestCaseCoverage; @@ -40,7 +41,7 @@ import java.util.List; /** * See {@link Sensor#execute(SensorContext)} - * @since 5.0 + * @since 5.1 */ public interface SensorContext { @@ -62,9 +63,9 @@ public interface SensorContext { // ----------- MEASURES -------------- /** - * Fluent builder to create a new {@link Measure}. Don't forget to call {@link Measure#save()} once all parameters are provided. + * Fluent builder to create a new {@link Measure}. Don't forget to call {@link NewMeasure#save()} once all parameters are provided. */ - Measure newMeasure(); + NewMeasure newMeasure(); // ----------- ISSUES -------------- diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/measure/Measure.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/measure/Measure.java index 86a0abdffad..c59f7a7be76 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/measure/Measure.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/measure/Measure.java @@ -27,21 +27,12 @@ import javax.annotation.CheckForNull; import java.io.Serializable; /** - * Builder to create new Measure. - * @since 5.0 + * Measure on File, Directory or Project. + * Should not be implemented by client. + * @since 5.1 */ public interface Measure { - /** - * The file the measure belongs to. - */ - Measure onFile(InputFile file); - - /** - * Tell that the measure is global to the project. - */ - Measure onProject(); - /** * The file the measure belong to. * @return null if measure is on project @@ -49,29 +40,14 @@ public interface Measure { @CheckForNull InputFile inputFile(); - /** - * Set the metric this measure belong to. - */ - Measure forMetric(Metric metric); - /** * The metric this measure belong to. */ Metric metric(); - /** - * Value of the measure. - */ - Measure withValue(G value); - /** * Value of the measure. */ G value(); - /** - * Save the measure. It is not permitted so save several measures of the same metric on the same file/project. - */ - void save(); - } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/measure/NewMeasure.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/measure/NewMeasure.java new file mode 100644 index 00000000000..cf8bccba48b --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/measure/NewMeasure.java @@ -0,0 +1,59 @@ +/* + * 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.api.batch.sensor.measure; + +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.measure.Metric; + +import java.io.Serializable; + +/** + * Builder to create new Measure. + * Should not be implemented by client. + * @since 5.1 + */ +public interface NewMeasure { + + /** + * The file the measure belongs to. + */ + NewMeasure onFile(InputFile file); + + /** + * Tell that the measure is global to the project. + */ + NewMeasure onProject(); + + /** + * Set the metric this measure belong to. + */ + NewMeasure forMetric(Metric metric); + + /** + * Value of the measure. + */ + NewMeasure withValue(G value); + + /** + * Save the measure. It is not permitted so save several measures of the same metric on the same file/project. + */ + void save(); + +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/measure/internal/DefaultMeasure.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/measure/internal/DefaultMeasure.java index 167f9e6af98..a6e4a0021fa 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/measure/internal/DefaultMeasure.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/measure/internal/DefaultMeasure.java @@ -27,13 +27,14 @@ import org.sonar.api.batch.measure.Metric; import org.sonar.api.batch.sensor.SensorStorage; import org.sonar.api.batch.sensor.internal.DefaultStorable; import org.sonar.api.batch.sensor.measure.Measure; +import org.sonar.api.batch.sensor.measure.NewMeasure; import javax.annotation.CheckForNull; import javax.annotation.Nullable; import java.io.Serializable; -public class DefaultMeasure extends DefaultStorable implements Measure { +public class DefaultMeasure extends DefaultStorable implements Measure, NewMeasure { private boolean onProject = false; private InputFile file; @@ -102,7 +103,7 @@ public class DefaultMeasure extends DefaultStorable impl Preconditions.checkNotNull(this.value, "Measure value can't be null"); Preconditions.checkNotNull(this.metric, "Measure metric can't be null"); Preconditions.checkState(this.metric.valueType().equals(this.value.getClass()), "Measure value should be of type " + this.metric.valueType()); - storage.store((Measure) this); + storage.store(this); } @Override diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/measures/MetricFinder.java b/sonar-plugin-api/src/main/java/org/sonar/api/measures/MetricFinder.java index c6f68aaedce..bb89c172a07 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/measures/MetricFinder.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/measures/MetricFinder.java @@ -29,7 +29,9 @@ import java.util.List; /** * @since 2.5 + * @deprecated since 5.1 use {@link org.sonar.api.batch.measure.MetricFinder} on batch side */ +@Deprecated public interface MetricFinder extends TaskComponent, ServerComponent { @CheckForNull