aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-batch
diff options
context:
space:
mode:
authorJulien HENRY <julien.henry@sonarsource.com>2015-04-01 21:02:38 +0200
committerJulien HENRY <julien.henry@sonarsource.com>2015-04-07 17:20:46 +0200
commitca8ad6b8b61305bd336325d05789da57b76efd7c (patch)
tree8391791a24c49a022d5b62f6d1e17165f4e21504 /sonar-batch
parentfa3100e005c2fc3884ae6cce708129b71830fe91 (diff)
downloadsonarqube-ca8ad6b8b61305bd336325d05789da57b76efd7c.tar.gz
sonarqube-ca8ad6b8b61305bd336325d05789da57b76efd7c.zip
SONAR-6339 Feed Coverage in compute report
Diffstat (limited to 'sonar-batch')
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/report/CoveragePublisher.java131
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/report/DuplicationsPublisher.java3
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java6
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java2
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorStorage.java50
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/sensor/DefaultSensorStorageTest.java9
6 files changed, 155 insertions, 46 deletions
diff --git a/sonar-batch/src/main/java/org/sonar/batch/report/CoveragePublisher.java b/sonar-batch/src/main/java/org/sonar/batch/report/CoveragePublisher.java
new file mode 100644
index 00000000000..b2b4eaf5442
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/report/CoveragePublisher.java
@@ -0,0 +1,131 @@
+/*
+ * 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.report;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Iterables;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.measures.Measure;
+import org.sonar.api.utils.KeyValueFormat;
+import org.sonar.batch.index.BatchResource;
+import org.sonar.batch.index.ResourceCache;
+import org.sonar.batch.protocol.output.BatchReport.Coverage;
+import org.sonar.batch.protocol.output.BatchReport.Coverage.Builder;
+import org.sonar.batch.protocol.output.BatchReportWriter;
+import org.sonar.batch.scan.measure.MeasureCache;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class CoveragePublisher implements ReportPublisherStep {
+
+ private final ResourceCache resourceCache;
+ private final MeasureCache measureCache;
+
+ public CoveragePublisher(ResourceCache resourceCache, MeasureCache measureCache) {
+ this.resourceCache = resourceCache;
+ this.measureCache = measureCache;
+ }
+
+ @Override
+ public void publish(BatchReportWriter writer) {
+ for (final BatchResource resource : resourceCache.all()) {
+ if (!resource.isFile()) {
+ continue;
+ }
+ Map<Integer, Coverage.Builder> coveragePerLine = new LinkedHashMap<>();
+
+ applyLineMeasure(resource.key(), ((InputFile) resource.inputPath()).lines(), CoreMetrics.COVERAGE_LINE_HITS_DATA_KEY, coveragePerLine, new MeasureOperation() {
+ @Override
+ public void apply(String value, Coverage.Builder builder) {
+ builder.setUtHits(Integer.parseInt(value) > 0);
+ builder.setConditions(1);
+ }
+ });
+ applyLineMeasure(resource.key(), ((InputFile) resource.inputPath()).lines(), CoreMetrics.CONDITIONS_BY_LINE_KEY, coveragePerLine, new MeasureOperation() {
+ @Override
+ public void apply(String value, Coverage.Builder builder) {
+ builder.setConditions(Integer.parseInt(value));
+ }
+ });
+ applyLineMeasure(resource.key(), ((InputFile) resource.inputPath()).lines(), CoreMetrics.COVERED_CONDITIONS_BY_LINE_KEY, coveragePerLine, new MeasureOperation() {
+ @Override
+ public void apply(String value, Coverage.Builder builder) {
+ builder.setUtCoveredConditions(Integer.parseInt(value));
+ }
+ });
+ applyLineMeasure(resource.key(), ((InputFile) resource.inputPath()).lines(), CoreMetrics.IT_COVERAGE_LINE_HITS_DATA_KEY, coveragePerLine, new MeasureOperation() {
+ @Override
+ public void apply(String value, Coverage.Builder builder) {
+ builder.setItHits(Integer.parseInt(value) > 0);
+ }
+ });
+ applyLineMeasure(resource.key(), ((InputFile) resource.inputPath()).lines(), CoreMetrics.IT_COVERED_CONDITIONS_BY_LINE_KEY, coveragePerLine, new MeasureOperation() {
+ @Override
+ public void apply(String value, Coverage.Builder builder) {
+ builder.setItCoveredConditions(Integer.parseInt(value));
+ }
+ });
+ applyLineMeasure(resource.key(), ((InputFile) resource.inputPath()).lines(), CoreMetrics.OVERALL_COVERED_CONDITIONS_BY_LINE_KEY, coveragePerLine, new MeasureOperation() {
+ @Override
+ public void apply(String value, Coverage.Builder builder) {
+ builder.setItCoveredConditions(Integer.parseInt(value));
+ }
+ });
+
+ writer.writeFileCoverage(resource.batchId(), Iterables.transform(coveragePerLine.values(), new Function<Coverage.Builder, Coverage>() {
+ @Override
+ public Coverage apply(Builder input) {
+ return input.build();
+ }
+ }));
+ }
+ }
+
+ void applyLineMeasure(String inputFileKey, int lineCount, String metricKey, Map<Integer, Coverage.Builder> coveragePerLine, MeasureOperation op) {
+ Iterable<Measure> measures = measureCache.byMetric(inputFileKey, metricKey);
+ if (measures.iterator().hasNext()) {
+ Measure measure = measures.iterator().next();
+ Map<Integer, String> lineMeasures = KeyValueFormat.parseIntString((String) measure.value());
+ for (Map.Entry<Integer, String> lineMeasure : lineMeasures.entrySet()) {
+ int lineIdx = lineMeasure.getKey();
+ if (lineIdx <= lineCount) {
+ String value = lineMeasure.getValue();
+ if (StringUtils.isNotEmpty(value)) {
+ Coverage.Builder coverageBuilder = coveragePerLine.get(lineIdx);
+ if (coverageBuilder == null) {
+ coverageBuilder = Coverage.newBuilder();
+ coverageBuilder.setLine(lineIdx);
+ coveragePerLine.put(lineIdx, coverageBuilder);
+ }
+ op.apply(value, coverageBuilder);
+ }
+ }
+ }
+ }
+ }
+
+ static interface MeasureOperation {
+ void apply(String value, Coverage.Builder builder);
+ }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/report/DuplicationsPublisher.java b/sonar-batch/src/main/java/org/sonar/batch/report/DuplicationsPublisher.java
index 0295e13bb2b..9b0dde87911 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/report/DuplicationsPublisher.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/report/DuplicationsPublisher.java
@@ -44,6 +44,9 @@ public class DuplicationsPublisher implements ReportPublisherStep {
@Override
public void publish(BatchReportWriter writer) {
for (final BatchResource resource : resourceCache.all()) {
+ if (!resource.isFile()) {
+ continue;
+ }
Iterable<DefaultDuplication> dups = duplicationCache.byComponent(resource.resource().getEffectiveKey());
if (dups.iterator().hasNext()) {
Iterable<org.sonar.batch.protocol.output.BatchReport.Duplication> reportDuplications = Iterables.transform(dups,
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 6e724866c67..d9a67454ad0 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
@@ -57,7 +57,6 @@ import org.sonar.batch.language.LanguageDistributionDecorator;
import org.sonar.batch.phases.*;
import org.sonar.batch.qualitygate.GenerateQualityGateEvents;
import org.sonar.batch.qualitygate.QualityGateVerifier;
-import org.sonar.batch.report.*;
import org.sonar.batch.rule.*;
import org.sonar.batch.scan.filesystem.*;
import org.sonar.batch.scan.report.IssuesReports;
@@ -114,11 +113,6 @@ public class ModuleScanContainer extends ComponentContainer {
SensorsExecutor.class,
InitializersExecutor.class,
ProjectInitializer.class,
- ReportPublisher.class,
- ComponentsPublisher.class,
- IssuesPublisher.class,
- MeasuresPublisher.class,
- DuplicationsPublisher.class,
moduleDefinition.getContainerExtensions(),
// file system
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
index 30bfafa9793..43ba3500126 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
@@ -186,6 +186,8 @@ public class ProjectScanContainer extends ComponentContainer {
ComponentsPublisher.class,
IssuesPublisher.class,
MeasuresPublisher.class,
+ DuplicationsPublisher.class,
+ CoveragePublisher.class,
ScanTaskObservers.class);
}
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
index 724c900176e..5aec595a9f7 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorStorage.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorStorage.java
@@ -22,8 +22,10 @@ package org.sonar.batch.sensor;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.Iterables;
-import org.sonar.api.batch.fs.*;
+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.fs.TextRange;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.measure.MetricFinder;
import org.sonar.api.batch.rule.ActiveRules;
@@ -43,7 +45,10 @@ 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.*;
+import org.sonar.api.resources.Directory;
+import org.sonar.api.resources.File;
+import org.sonar.api.resources.Project;
+import org.sonar.api.resources.Scopes;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.source.Symbol;
import org.sonar.batch.duplication.DuplicationCache;
@@ -151,18 +156,14 @@ public class DefaultSensorStorage implements SensorStorage {
@Override
public void store(Issue issue) {
- Resource r;
+ String componentKey;
InputPath inputPath = issue.inputPath();
if (inputPath != null) {
- if (inputPath instanceof InputDir) {
- r = Directory.create(inputPath.relativePath());
- } else {
- r = File.create(inputPath.relativePath());
- }
+ componentKey = ComponentKeys.createEffectiveKey(project.getKey(), inputPath);
} else {
- r = project;
+ componentKey = project.getKey();
}
- moduleIssues.initAndAddIssue(toDefaultIssue(project.getKey(), ComponentKeys.createEffectiveKey(project, r), issue));
+ moduleIssues.initAndAddIssue(toDefaultIssue(project.getKey(), componentKey, issue));
}
public static DefaultIssue toDefaultIssue(String projectKey, String componentKey, Issue issue) {
@@ -178,33 +179,12 @@ public class DefaultSensorStorage implements SensorStorage {
.build();
}
- 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);
+ BatchResource r = resourceCache.get(file);
+ if (r == null) {
+ throw new IllegalStateException("Provided input file is not indexed");
}
+ return (File) r.resource();
}
@Override
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
index 60f04a9f626..3114e054718 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/sensor/DefaultSensorStorageTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/sensor/DefaultSensorStorageTest.java
@@ -117,9 +117,9 @@ public class DefaultSensorStorageTest {
InputFile file = new DefaultInputFile("foo", "src/Foo.php");
ArgumentCaptor<org.sonar.api.measures.Measure> argumentCaptor = ArgumentCaptor.forClass(org.sonar.api.measures.Measure.class);
- File sonarFile = File.create("src/Foo.php");
+ Resource sonarFile = File.create("src/Foo.php").setEffectiveKey("foo:src/Foo.php");
+ resourceCache.add(sonarFile, null).setInputPath(file);
when(sonarIndex.addMeasure(eq(sonarFile), argumentCaptor.capture())).thenReturn(null);
- when(sonarIndex.getResource(sonarFile)).thenReturn(sonarFile);
sensorStorage.store(new DefaultMeasure()
.onFile(file)
.forMetric(CoreMetrics.NCLOC)
@@ -137,12 +137,11 @@ public class DefaultSensorStorageTest {
InputFile file = new DefaultInputFile("foo", "src/Foo.php");
ArgumentCaptor<org.sonar.api.measures.Measure> argumentCaptor = ArgumentCaptor.forClass(org.sonar.api.measures.Measure.class);
- File sonarFile = File.create("src/Foo.php");
+ Resource sonarFile = File.create("src/Foo.php").setEffectiveKey("foo:src/Foo.php");
+ resourceCache.add(sonarFile, null).setInputPath(file);
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)