summaryrefslogtreecommitdiffstats
path: root/sonar-batch
diff options
context:
space:
mode:
authorJulien HENRY <julien.henry@sonarsource.com>2014-06-19 23:25:55 +0200
committerJulien HENRY <julien.henry@sonarsource.com>2014-06-19 23:26:57 +0200
commit369f12960fba6653e630042ab977c97e479a3076 (patch)
treec3896b2a5f2caf4fdc8037567a862e810b43b38f /sonar-batch
parent71a6a922a2d07ae8db9f13036a9653e772380762 (diff)
downloadsonarqube-369f12960fba6653e630042ab977c97e479a3076.tar.gz
sonarqube-369f12960fba6653e630042ab977c97e479a3076.zip
SONAR-5389 Add support of FileLinesContextFactory + publish analysis
Diffstat (limited to 'sonar-batch')
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/DefaultFileLinesContext.java5
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/mediumtest/AnalyzerMediumTester.java (renamed from sonar-batch/src/test/java/org/sonar/batch/mediumtest/AnalyzerMediumTester.java)9
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/mediumtest/package-info.java23
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzerIssueCache.java14
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzerMeasureCache.java19
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzisPublisher.java189
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultAnalyzerContext.java14
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultFileLinesContext.java158
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultFileLinesContextFactory.java58
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan2/ModuleScanContainer.java7
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan2/ModuleScanExecutor.java12
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/tasks/package-info.java23
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/XooMediumTest.java73
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/XooPlugin.java2
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/lang/ScmActivityAnalyzer.java112
-rw-r--r--sonar-batch/src/test/resources/mediumtest/xoo/sample/sonar-project.properties (renamed from sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/sonar-project.properties)0
-rw-r--r--sonar-batch/src/test/resources/mediumtest/xoo/sample/testx/ClassOneTest.xoo (renamed from sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/testx/ClassOneTest.xoo)0
-rw-r--r--sonar-batch/src/test/resources/mediumtest/xoo/sample/testx/ClassOneTest.xoo.measures (renamed from sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/testx/ClassOneTest.xoo.measures)0
-rw-r--r--sonar-batch/src/test/resources/mediumtest/xoo/sample/testx/ClassOneTest.xoo.scm (renamed from sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/testx/ClassOneTest.xoo.scm)0
-rw-r--r--sonar-batch/src/test/resources/mediumtest/xoo/sample/xources/hello/HelloJava.xoo (renamed from sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/HelloJava.xoo)0
-rw-r--r--sonar-batch/src/test/resources/mediumtest/xoo/sample/xources/hello/HelloJava.xoo.measures (renamed from sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/HelloJava.xoo.measures)0
-rw-r--r--sonar-batch/src/test/resources/mediumtest/xoo/sample/xources/hello/HelloJava.xoo.scm (renamed from sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/HelloJava.xoo.scm)0
-rw-r--r--sonar-batch/src/test/resources/mediumtest/xoo/sample/xources/hello/helloscala.xoo (renamed from sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/helloscala.xoo)0
-rw-r--r--sonar-batch/src/test/resources/mediumtest/xoo/sample/xources/hello/helloscala.xoo.measures (renamed from sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/helloscala.xoo.measures)0
24 files changed, 678 insertions, 40 deletions
diff --git a/sonar-batch/src/main/java/org/sonar/batch/DefaultFileLinesContext.java b/sonar-batch/src/main/java/org/sonar/batch/DefaultFileLinesContext.java
index cd9498b7c35..98c5ef1dc78 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/DefaultFileLinesContext.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/DefaultFileLinesContext.java
@@ -19,7 +19,6 @@
*/
package org.sonar.batch;
-import com.google.common.annotations.Beta;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
@@ -36,10 +35,6 @@ import org.sonar.api.utils.KeyValueFormat.Converter;
import java.util.Map;
-/**
- * @since 2.14
- */
-@Beta
public class DefaultFileLinesContext implements FileLinesContext {
private final SonarIndex index;
diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/AnalyzerMediumTester.java b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/AnalyzerMediumTester.java
index d69b371f57d..c35ccff3216 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/AnalyzerMediumTester.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/AnalyzerMediumTester.java
@@ -24,7 +24,6 @@ import com.google.common.collect.HashBiMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.io.IOUtils;
-import org.junit.rules.ExternalResource;
import org.sonar.api.SonarPlugin;
import org.sonar.api.batch.analyzer.issue.AnalyzerIssue;
import org.sonar.api.batch.analyzer.measure.AnalyzerMeasure;
@@ -64,7 +63,7 @@ import java.util.List;
import java.util.Map;
import java.util.Properties;
-public class AnalyzerMediumTester extends ExternalResource {
+public class AnalyzerMediumTester {
private Batch batch;
@@ -144,13 +143,11 @@ public class AnalyzerMediumTester extends ExternalResource {
}
- @Override
- protected void before() throws Throwable {
+ public void start() throws Throwable {
batch.start();
}
- @Override
- protected void after() {
+ public void stop() {
batch.stop();
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/package-info.java b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/package-info.java
new file mode 100644
index 00000000000..40991844d12
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.batch.mediumtest;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzerIssueCache.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzerIssueCache.java
index 613507de041..4adc383a00d 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzerIssueCache.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzerIssueCache.java
@@ -29,24 +29,28 @@ import org.sonar.batch.index.Caches;
*/
public class AnalyzerIssueCache implements BatchComponent {
- // component key -> issue key -> issue
+ // project key -> resource key -> issue key -> issue
private final Cache<DefaultAnalyzerIssue> cache;
public AnalyzerIssueCache(Caches caches) {
cache = caches.createCache("issues");
}
- public Iterable<DefaultAnalyzerIssue> byComponent(String resourceKey) {
- return cache.values(resourceKey);
+ public Iterable<DefaultAnalyzerIssue> byComponent(String projectKey, String resourceKey) {
+ return cache.values(projectKey, resourceKey);
}
public Iterable<DefaultAnalyzerIssue> all() {
return cache.values();
}
- public AnalyzerIssueCache put(String resourceKey, DefaultAnalyzerIssue issue) {
- cache.put(resourceKey, issue.key(), issue);
+ public AnalyzerIssueCache put(String projectKey, String resourceKey, DefaultAnalyzerIssue issue) {
+ cache.put(projectKey, resourceKey, issue.key(), issue);
return this;
}
+ public Iterable<DefaultAnalyzerIssue> byModule(String projectKey) {
+ return cache.values(projectKey);
+ }
+
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzerMeasureCache.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzerMeasureCache.java
index 07d313f2249..030ff3e6ccc 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzerMeasureCache.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzerMeasureCache.java
@@ -31,6 +31,7 @@ import org.sonar.batch.index.Caches;
*/
public class AnalyzerMeasureCache implements BatchComponent {
+ // project key -> component key -> metric key -> measure
private final Cache<DefaultAnalyzerMeasure> cache;
public AnalyzerMeasureCache(Caches caches) {
@@ -41,21 +42,27 @@ public class AnalyzerMeasureCache implements BatchComponent {
return cache.entries();
}
- public DefaultAnalyzerMeasure<?> byMetric(String resourceKey, String metricKey) {
- return cache.get(resourceKey, metricKey);
+ public Iterable<DefaultAnalyzerMeasure> byModule(String projectKey) {
+ return cache.values(projectKey);
}
- public AnalyzerMeasureCache put(String resourceKey, DefaultAnalyzerMeasure<?> measure) {
+ public DefaultAnalyzerMeasure<?> byMetric(String projectKey, String resourceKey, String metricKey) {
+ return cache.get(projectKey, resourceKey, metricKey);
+ }
+
+ public AnalyzerMeasureCache put(String projectKey, String resourceKey, DefaultAnalyzerMeasure<?> measure) {
+ Preconditions.checkNotNull(projectKey);
Preconditions.checkNotNull(resourceKey);
Preconditions.checkNotNull(measure);
- cache.put(resourceKey, measure.metric().key(), measure);
+ cache.put(projectKey, resourceKey, measure.metric().key(), measure);
return this;
}
- public boolean contains(String resourceKey, DefaultAnalyzerMeasure<?> measure) {
+ public boolean contains(String projectKey, String resourceKey, DefaultAnalyzerMeasure<?> measure) {
+ Preconditions.checkNotNull(projectKey);
Preconditions.checkNotNull(resourceKey);
Preconditions.checkNotNull(measure);
- return cache.containsKey(resourceKey, measure.metric().key());
+ return cache.containsKey(projectKey, resourceKey, measure.metric().key());
}
public Iterable<DefaultAnalyzerMeasure> all() {
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzisPublisher.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzisPublisher.java
new file mode 100644
index 00000000000..2c2e29d9067
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzisPublisher.java
@@ -0,0 +1,189 @@
+/*
+ * 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.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.batch.analyzer.issue.AnalyzerIssue;
+import org.sonar.api.batch.analyzer.measure.AnalyzerMeasure;
+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.config.Settings;
+import org.sonar.api.utils.ZipUtils;
+import org.sonar.api.utils.text.JsonWriter;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Properties;
+
+public final class AnalyzisPublisher {
+
+ public static final Logger LOG = LoggerFactory.getLogger(AnalyzisPublisher.class);
+ private final Settings settings;
+ private final FileSystem fs;
+ private final AnalyzerMeasureCache measureCache;
+ private final ProjectDefinition def;
+ private AnalyzerIssueCache issueCache;
+
+ public AnalyzisPublisher(ProjectDefinition def, Settings settings, FileSystem fs, AnalyzerMeasureCache measureCache, AnalyzerIssueCache 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");
+ FileWriter issueWriter = null;
+ try {
+ issueWriter = new FileWriter(issuesFile);
+ JsonWriter jsonWriter = JsonWriter.of(issueWriter);
+ jsonWriter
+ .beginObject().name("issues")
+ .beginArray();
+ for (AnalyzerIssue issue : issueCache.byModule(def.getKey())) {
+ jsonWriter.beginObject()
+ .prop("repository", issue.ruleKey().repository())
+ .prop("rule", issue.ruleKey().rule());
+ if (issue.inputFile() != null) {
+ jsonWriter.prop("filePath", issue.inputFile().relativePath());
+ }
+ jsonWriter.prop("message", issue.message())
+ .prop("effortToFix", issue.effortToFix())
+ .prop("line", issue.line())
+ .endObject();
+ }
+ jsonWriter.endArray()
+ .endObject()
+ .close();
+ } catch (IOException e) {
+
+ } finally {
+ IOUtils.closeQuietly(issueWriter);
+ }
+ }
+
+ private void exportMeasures(File exportDir) {
+ File measuresFile = new File(exportDir, "measures.json");
+ FileWriter measureWriter = null;
+ try {
+ measureWriter = new FileWriter(measuresFile);
+ JsonWriter jsonWriter = JsonWriter.of(measureWriter);
+ jsonWriter
+ .beginObject().name("measures")
+ .beginArray();
+ for (AnalyzerMeasure<?> measure : measureCache.byModule(def.getKey())) {
+ jsonWriter.beginObject()
+ .prop("metricKey", measure.metric().key());
+ if (measure.inputFile() != null) {
+ jsonWriter.prop("filePath", measure.inputFile().relativePath());
+ }
+ jsonWriter.prop("value", String.valueOf(measure.value()))
+ .endObject();
+ }
+ jsonWriter.endArray()
+ .endObject()
+ .close();
+ } catch (IOException e) {
+
+ } finally {
+ IOUtils.closeQuietly(measureWriter);
+ }
+ }
+
+ 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());
+ FileWriter writer = null;
+ try {
+ writer = new FileWriter(propsFile);
+ props.store(writer, "SonarQube batch");
+ } catch (IOException e) {
+ throw unableToExport(e);
+ } finally {
+ IOUtils.closeQuietly(writer);
+ }
+ }
+
+ 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/DefaultAnalyzerContext.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultAnalyzerContext.java
index cb46ec2204c..8e16ccd1f97 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultAnalyzerContext.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultAnalyzerContext.java
@@ -83,30 +83,30 @@ public class DefaultAnalyzerContext implements AnalyzerContext {
@Override
public AnalyzerMeasure getMeasure(String metricKey) {
- return measureCache.byMetric(def.getKey(), metricKey);
+ return measureCache.byMetric(def.getKey(), def.getKey(), metricKey);
}
@Override
public <G extends Serializable> AnalyzerMeasure<G> getMeasure(Metric<G> metric) {
- return (AnalyzerMeasure<G>) measureCache.byMetric(def.getKey(), metric.key());
+ return (AnalyzerMeasure<G>) measureCache.byMetric(def.getKey(), def.getKey(), metric.key());
}
@Override
public AnalyzerMeasure getMeasure(InputFile file, String metricKey) {
- return measureCache.byMetric(ComponentKeys.createEffectiveKey(def.getKey(), file), metricKey);
+ return measureCache.byMetric(def.getKey(), ComponentKeys.createEffectiveKey(def.getKey(), file), metricKey);
}
@Override
public <G extends Serializable> AnalyzerMeasure<G> getMeasure(InputFile file, Metric<G> metric) {
- return (AnalyzerMeasure<G>) measureCache.byMetric(ComponentKeys.createEffectiveKey(def.getKey(), file), metric.key());
+ return (AnalyzerMeasure<G>) measureCache.byMetric(def.getKey(), ComponentKeys.createEffectiveKey(def.getKey(), file), metric.key());
}
@Override
public void addMeasure(AnalyzerMeasure<?> measure) {
if (measure.inputFile() != null) {
- measureCache.put(ComponentKeys.createEffectiveKey(def.getKey(), measure.inputFile()), (DefaultAnalyzerMeasure) measure);
+ measureCache.put(def.getKey(), ComponentKeys.createEffectiveKey(def.getKey(), measure.inputFile()), (DefaultAnalyzerMeasure) measure);
} else {
- measureCache.put(def.getKey(), (DefaultAnalyzerMeasure) measure);
+ measureCache.put(def.getKey(), def.getKey(), (DefaultAnalyzerMeasure) measure);
}
}
@@ -125,7 +125,7 @@ public class DefaultAnalyzerContext implements AnalyzerContext {
}
if (issueFilters.accept(AnalyzerContextAdaptor.toDefaultIssue(def.getKey(), resourceKey, issue), null)) {
- issueCache.put(resourceKey, (DefaultAnalyzerIssue) issue);
+ issueCache.put(def.getKey(), resourceKey, (DefaultAnalyzerIssue) issue);
}
}
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultFileLinesContext.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultFileLinesContext.java
new file mode 100644
index 00000000000..729a4076d3d
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultFileLinesContext.java
@@ -0,0 +1,158 @@
+/*
+ * 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.Objects;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import org.sonar.api.batch.analyzer.measure.AnalyzerMeasure;
+import org.sonar.api.batch.analyzer.measure.internal.DefaultAnalyzerMeasureBuilder;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.measures.FileLinesContext;
+import org.sonar.api.measures.Metric;
+import org.sonar.api.measures.MetricFinder;
+import org.sonar.api.utils.KeyValueFormat;
+import org.sonar.api.utils.KeyValueFormat.Converter;
+import org.sonar.core.component.ComponentKeys;
+
+import java.util.Map;
+
+public class DefaultFileLinesContext implements FileLinesContext {
+
+ private final AnalyzerMeasureCache measureCache;
+ private final InputFile inputFile;
+
+ /**
+ * metric key -> line -> value
+ */
+ private final Map<String, Map<Integer, Object>> map = Maps.newHashMap();
+ private String projectKey;
+ private MetricFinder metricFinder;
+
+ public DefaultFileLinesContext(MetricFinder metricFinder, AnalyzerMeasureCache measureCache, String projectKey, InputFile inputFile) {
+ this.metricFinder = metricFinder;
+ this.projectKey = projectKey;
+ Preconditions.checkNotNull(measureCache);
+ this.measureCache = measureCache;
+ this.inputFile = inputFile;
+ }
+
+ public void setIntValue(String metricKey, int line, int value) {
+ Preconditions.checkNotNull(metricKey);
+ Preconditions.checkArgument(line > 0);
+
+ setValue(metricKey, line, value);
+ }
+
+ public Integer getIntValue(String metricKey, int line) {
+ Preconditions.checkNotNull(metricKey);
+ Preconditions.checkArgument(line > 0);
+
+ Map lines = map.get(metricKey);
+ if (lines == null) {
+ // not in memory, so load
+ lines = loadData(metricKey, KeyValueFormat.newIntegerConverter());
+ map.put(metricKey, lines);
+ }
+ return (Integer) lines.get(line);
+ }
+
+ public void setStringValue(String metricKey, int line, String value) {
+ Preconditions.checkNotNull(metricKey);
+ Preconditions.checkArgument(line > 0);
+ Preconditions.checkNotNull(value);
+
+ setValue(metricKey, line, value);
+ }
+
+ public String getStringValue(String metricKey, int line) {
+ Preconditions.checkNotNull(metricKey);
+ Preconditions.checkArgument(line > 0);
+
+ Map lines = map.get(metricKey);
+ if (lines == null) {
+ // not in memory, so load
+ lines = loadData(metricKey, KeyValueFormat.newStringConverter());
+ map.put(metricKey, lines);
+ }
+ return (String) lines.get(line);
+ }
+
+ private Map<Integer, Object> getOrCreateLines(String metricKey) {
+ Map<Integer, Object> lines = map.get(metricKey);
+ if (lines == null) {
+ lines = Maps.newHashMap();
+ map.put(metricKey, lines);
+ }
+ return lines;
+ }
+
+ private void setValue(String metricKey, int line, Object value) {
+ getOrCreateLines(metricKey).put(line, value);
+ }
+
+ public void save() {
+ for (Map.Entry<String, Map<Integer, Object>> entry : map.entrySet()) {
+ String metricKey = entry.getKey();
+ Metric metric = metricFinder.findByKey(metricKey);
+ if (metric == null) {
+ throw new IllegalStateException("Unable to find metric with key: " + metricKey);
+ }
+ Map<Integer, Object> lines = entry.getValue();
+ if (shouldSave(lines)) {
+ String data = KeyValueFormat.format(lines);
+ measureCache.put(projectKey, ComponentKeys.createEffectiveKey(projectKey, inputFile), new DefaultAnalyzerMeasureBuilder<String>()
+ .forMetric(metric)
+ .onFile(inputFile)
+ .withValue(data)
+ .build());
+ entry.setValue(ImmutableMap.copyOf(lines));
+ }
+ }
+ }
+
+ private Map loadData(String metricKey, Converter converter) {
+ AnalyzerMeasure measure = measureCache.byMetric(projectKey, ComponentKeys.createEffectiveKey(projectKey, inputFile), metricKey);
+ if (measure == null) {
+ // no such measure
+ return ImmutableMap.of();
+ }
+ return ImmutableMap.copyOf(KeyValueFormat.parse((String) measure.value(), KeyValueFormat.newIntegerConverter(), converter));
+ }
+
+ /**
+ * Checks that measure was not saved.
+ *
+ * @see #loadData(String, Converter)
+ * @see #save()
+ */
+ private boolean shouldSave(Map<Integer, Object> lines) {
+ return !(lines instanceof ImmutableMap);
+ }
+
+ @Override
+ public String toString() {
+ return Objects.toStringHelper(this)
+ .add("map", map)
+ .toString();
+ }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultFileLinesContextFactory.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultFileLinesContextFactory.java
new file mode 100644
index 00000000000..9dd70c7f3e8
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultFileLinesContextFactory.java
@@ -0,0 +1,58 @@
+/*
+ * 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.batch.bootstrap.ProjectDefinition;
+import org.sonar.api.batch.fs.FileSystem;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.measures.FileLinesContext;
+import org.sonar.api.measures.FileLinesContextFactory;
+import org.sonar.api.measures.MetricFinder;
+import org.sonar.api.resources.Resource;
+import org.sonar.batch.scan.filesystem.InputFileCache;
+
+public class DefaultFileLinesContextFactory implements FileLinesContextFactory {
+
+ private final AnalyzerMeasureCache measureCache;
+ private final MetricFinder metricFinder;
+ private final ProjectDefinition def;
+ private InputFileCache fileCache;
+
+ public DefaultFileLinesContextFactory(InputFileCache fileCache, FileSystem fs, MetricFinder metricFinder, AnalyzerMeasureCache measureCache, ProjectDefinition def) {
+ this.fileCache = fileCache;
+ this.metricFinder = metricFinder;
+ this.measureCache = measureCache;
+ this.def = def;
+ }
+
+ @Override
+ public FileLinesContext createFor(Resource model) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public FileLinesContext createFor(InputFile inputFile) {
+ if (fileCache.get(def.getKey(), inputFile.relativePath()) == null) {
+ throw new IllegalStateException("InputFile is not indexed: " + inputFile);
+ }
+ return new DefaultFileLinesContext(metricFinder, measureCache, def.getKey(), inputFile);
+ }
+
+}
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
index 3ec356536ad..6309146221c 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan2/ModuleScanContainer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan2/ModuleScanContainer.java
@@ -112,13 +112,18 @@ public class ModuleScanContainer extends ComponentContainer {
IssuableFactory.class,
ModuleIssues.class,
+ // Measures
+ DefaultFileLinesContextFactory.class,
+
// issue exclusions
IssueInclusionPatternInitializer.class,
IssueExclusionPatternInitializer.class,
IssueExclusionsRegexpScanner.class,
IssueExclusionsLoader.class,
EnforceIssuesFilter.class,
- IgnoreIssuesFilter.class);
+ IgnoreIssuesFilter.class,
+
+ AnalyzisPublisher.class);
}
private void addExtensions() {
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 55423ee2eb5..db5406afad4 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
@@ -19,11 +19,10 @@
*/
package org.sonar.batch.scan2;
-import org.sonar.api.batch.analyzer.AnalyzerContext;
-
import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.sonar.api.batch.analyzer.AnalyzerContext;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.batch.issue.ignore.scanner.IssueExclusionsLoader;
import org.sonar.batch.phases.SensorsExecutor;
@@ -44,16 +43,19 @@ public final class ModuleScanExecutor {
private final QProfileVerifier profileVerifier;
private final IssueExclusionsLoader issueExclusionsLoader;
+ private AnalyzisPublisher analyzisPublisher;
+
public ModuleScanExecutor(AnalyzersExecutor analyzersExecutor,
AnalyzerContext analyzerContext,
FileSystemLogger fsLogger, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier,
- IssueExclusionsLoader issueExclusionsLoader) {
+ IssueExclusionsLoader issueExclusionsLoader, AnalyzisPublisher analyzisPublisher) {
this.analyzersExecutor = analyzersExecutor;
this.analyzerContext = analyzerContext;
this.fsLogger = fsLogger;
this.fs = fs;
this.profileVerifier = profileVerifier;
this.issueExclusionsLoader = issueExclusionsLoader;
+ this.analyzisPublisher = analyzisPublisher;
}
public static Collection<Class> getPhaseClasses() {
@@ -76,5 +78,9 @@ public final class ModuleScanExecutor {
issueExclusionsLoader.execute();
analyzersExecutor.execute(analyzerContext);
+
+ // Export results
+ analyzisPublisher.execute();
+
}
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/tasks/package-info.java b/sonar-batch/src/main/java/org/sonar/batch/tasks/package-info.java
new file mode 100644
index 00000000000..0f2b4e035bb
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/tasks/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.batch.tasks;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/XooMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/XooMediumTest.java
index 0b3cc9d77ef..6a9fdb2403f 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/XooMediumTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/XooMediumTest.java
@@ -21,6 +21,8 @@ package org.sonar.batch.mediumtest.xoo;
import com.google.common.collect.ImmutableMap;
import org.apache.commons.io.FileUtils;
+import org.junit.After;
+import org.junit.Before;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.analyzer.issue.AnalyzerIssue;
@@ -43,7 +45,6 @@ public class XooMediumTest {
@org.junit.Rule
public TemporaryFolder temp = new TemporaryFolder();
- @org.junit.Rule
public AnalyzerMediumTester tester = AnalyzerMediumTester.builder()
// .registerPlugin("xoo", new File("target/sonar-xoo-plugin-2.0-SNAPSHOT.jar"))
.registerPlugin("xoo", new XooPlugin())
@@ -53,21 +54,31 @@ public class XooMediumTest {
.bootstrapProperties(ImmutableMap.of("sonar.analysis.mode", "sensor"))
.build();
+ @Before
+ public void prepare() throws Throwable {
+ tester.start();
+ }
+
+ @After
+ public void stop() {
+ tester.stop();
+ }
+
@Test
- public void mediumTestOfSample() throws Exception {
- File projectDir = new File(XooMediumTest.class.getResource("/org/sonar/batch/mediumtest/xoo/sample").toURI());
+ public void mediumTestOfSampleProject() throws Exception {
+ File projectDir = new File(XooMediumTest.class.getResource("/mediumtest/xoo/sample").toURI());
TaskResult result = tester
.newScanTask(new File(projectDir, "sonar-project.properties"))
.start();
- assertThat(result.measures()).hasSize(13);
+ assertThat(result.measures()).hasSize(19);
assertThat(result.issues()).hasSize(24);
}
@Test
public void testIssueExclusion() throws Exception {
- File projectDir = new File(XooMediumTest.class.getResource("/org/sonar/batch/mediumtest/xoo/sample").toURI());
+ File projectDir = new File(XooMediumTest.class.getResource("/mediumtest/xoo/sample").toURI());
TaskResult result = tester
.newScanTask(new File(projectDir, "sonar-project.properties"))
@@ -75,12 +86,12 @@ public class XooMediumTest {
.property("sonar.issue.ignore.allfile.1.fileRegexp", "object")
.start();
- assertThat(result.measures()).hasSize(13);
+ assertThat(result.measures()).hasSize(19);
assertThat(result.issues()).hasSize(19);
}
@Test
- public void mediumTest() throws IOException {
+ public void testMeasuresAndIssues() throws IOException {
File baseDir = temp.newFolder();
File srcDir = new File(baseDir, "src");
@@ -124,4 +135,52 @@ public class XooMediumTest {
assertThat(foundIssueAtLine1).isTrue();
}
+ @Test
+ public void testScmActivityAnalyzer() throws IOException {
+
+ File baseDir = temp.newFolder();
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ File xooFile = new File(srcDir, "sample.xoo");
+ File xooMeasureFile = new File(srcDir, "sample.xoo.measures");
+ File xooScmFile = new File(srcDir, "sample.xoo.scm");
+ FileUtils.write(xooFile, "Sample xoo\ncontent");
+ FileUtils.write(xooMeasureFile, "lines:5");
+ FileUtils.write(xooScmFile,
+ // revision,author,dateTime
+ "1,julien,2013-01-04\n" +
+ "1,julien,2013-01-04\n" +
+ "2,julien,2013-02-03\n" +
+ "2,julien,2013-02-03\n" +
+ "3,simon,2013-03-04\n"
+ );
+
+ TaskResult result = tester.newTask()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.task", "scan")
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.projectName", "Foo Project")
+ .put("sonar.projectVersion", "1.0-SNAPSHOT")
+ .put("sonar.projectDescription", "Description of Foo Project")
+ .put("sonar.sources", "src")
+ .build())
+ .start();
+
+ assertThat(result.measures()).hasSize(4);
+
+ assertThat(result.measures()).contains(new DefaultAnalyzerMeasureBuilder<Integer>()
+ .forMetric(CoreMetrics.LINES)
+ .onFile(new DefaultInputFile("src/sample.xoo"))
+ .withValue(5)
+ .build());
+
+ assertThat(result.measures()).contains(new DefaultAnalyzerMeasureBuilder<String>()
+ .forMetric(CoreMetrics.SCM_AUTHORS_BY_LINE)
+ .onFile(new DefaultInputFile("src/sample.xoo"))
+ .withValue("1=julien;2=julien;3=julien;4=julien;5=simon")
+ .build());
+ }
+
}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/XooPlugin.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/XooPlugin.java
index a93cdbf6b22..ff113906138 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/XooPlugin.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/XooPlugin.java
@@ -22,6 +22,7 @@ package org.sonar.batch.mediumtest.xoo.plugin;
import org.sonar.api.SonarPlugin;
import org.sonar.batch.mediumtest.xoo.plugin.base.Xoo;
import org.sonar.batch.mediumtest.xoo.plugin.lang.MeasureAnalyzer;
+import org.sonar.batch.mediumtest.xoo.plugin.lang.ScmActivityAnalyzer;
import org.sonar.batch.mediumtest.xoo.plugin.rule.OneIssuePerLineAnalyzer;
import java.util.Arrays;
@@ -34,6 +35,7 @@ public final class XooPlugin extends SonarPlugin {
return Arrays.asList(
// language
MeasureAnalyzer.class,
+ ScmActivityAnalyzer.class,
Xoo.class,
// rules
diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/lang/ScmActivityAnalyzer.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/lang/ScmActivityAnalyzer.java
new file mode 100644
index 00000000000..346036a52ff
--- /dev/null
+++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/lang/ScmActivityAnalyzer.java
@@ -0,0 +1,112 @@
+/*
+ * 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.mediumtest.xoo.plugin.lang;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Charsets;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.batch.analyzer.Analyzer;
+import org.sonar.api.batch.analyzer.AnalyzerContext;
+import org.sonar.api.batch.analyzer.AnalyzerDescriptor;
+import org.sonar.api.batch.fs.FileSystem;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.measures.FileLinesContext;
+import org.sonar.api.measures.FileLinesContextFactory;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.batch.mediumtest.xoo.plugin.base.Xoo;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Date;
+import java.util.List;
+
+public class ScmActivityAnalyzer implements Analyzer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ScmActivityAnalyzer.class);
+
+ private static final String SCM_EXTENSION = ".scm";
+
+ private final FileSystem fs;
+ private final FileLinesContextFactory fileLinesContextFactory;
+
+ public ScmActivityAnalyzer(FileLinesContextFactory fileLinesContextFactory, FileSystem fileSystem) {
+ this.fs = fileSystem;
+ this.fileLinesContextFactory = fileLinesContextFactory;
+ }
+
+ @Override
+ public void describe(AnalyzerDescriptor descriptor) {
+ descriptor
+ .name(this.getClass().getSimpleName())
+ .provides(CoreMetrics.SCM_AUTHORS_BY_LINE,
+ CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE,
+ CoreMetrics.SCM_REVISIONS_BY_LINE)
+ .workOnLanguages(Xoo.KEY);
+ }
+
+ @Override
+ public void analyse(AnalyzerContext context) {
+ for (InputFile inputFile : fs.inputFiles(fs.predicates().hasLanguage(Xoo.KEY))) {
+ processFile(inputFile);
+ }
+
+ }
+
+ @VisibleForTesting
+ protected void processFile(InputFile inputFile) {
+ File ioFile = inputFile.file();
+ File scmDataFile = new java.io.File(ioFile.getParentFile(), ioFile.getName() + SCM_EXTENSION);
+ if (!scmDataFile.exists()) {
+ LOG.debug("Skipping SCM data injection for " + inputFile.relativePath());
+ return;
+ }
+
+ FileLinesContext fileLinesContext = fileLinesContextFactory.createFor(inputFile);
+ try {
+ List<String> lines = FileUtils.readLines(scmDataFile, Charsets.UTF_8.name());
+ int lineNumber = 0;
+ for (String line : lines) {
+ lineNumber++;
+ if (StringUtils.isNotBlank(line)) {
+ // revision,author,dateTime
+ String[] fields = StringUtils.split(line, ',');
+ if (fields.length < 3) {
+ throw new IllegalStateException("Not enough fields on line " + lineNumber);
+ }
+ String revision = fields[0];
+ String author = fields[1];
+ // Will throw an exception, when date is not in format "yyyy-MM-dd"
+ Date date = DateUtils.parseDate(fields[2]);
+
+ fileLinesContext.setStringValue(CoreMetrics.SCM_REVISIONS_BY_LINE_KEY, lineNumber, revision);
+ fileLinesContext.setStringValue(CoreMetrics.SCM_AUTHORS_BY_LINE_KEY, lineNumber, author);
+ fileLinesContext.setStringValue(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE_KEY, lineNumber, DateUtils.formatDateTime(date));
+ }
+ }
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ fileLinesContext.save();
+ }
+}
diff --git a/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/sonar-project.properties b/sonar-batch/src/test/resources/mediumtest/xoo/sample/sonar-project.properties
index 8810e376701..8810e376701 100644
--- a/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/sonar-project.properties
+++ b/sonar-batch/src/test/resources/mediumtest/xoo/sample/sonar-project.properties
diff --git a/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/testx/ClassOneTest.xoo b/sonar-batch/src/test/resources/mediumtest/xoo/sample/testx/ClassOneTest.xoo
index 8c0967e496f..8c0967e496f 100644
--- a/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/testx/ClassOneTest.xoo
+++ b/sonar-batch/src/test/resources/mediumtest/xoo/sample/testx/ClassOneTest.xoo
diff --git a/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/testx/ClassOneTest.xoo.measures b/sonar-batch/src/test/resources/mediumtest/xoo/sample/testx/ClassOneTest.xoo.measures
index 23b08dc0e0e..23b08dc0e0e 100644
--- a/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/testx/ClassOneTest.xoo.measures
+++ b/sonar-batch/src/test/resources/mediumtest/xoo/sample/testx/ClassOneTest.xoo.measures
diff --git a/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/testx/ClassOneTest.xoo.scm b/sonar-batch/src/test/resources/mediumtest/xoo/sample/testx/ClassOneTest.xoo.scm
index 2cec35b8a72..2cec35b8a72 100644
--- a/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/testx/ClassOneTest.xoo.scm
+++ b/sonar-batch/src/test/resources/mediumtest/xoo/sample/testx/ClassOneTest.xoo.scm
diff --git a/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/HelloJava.xoo b/sonar-batch/src/test/resources/mediumtest/xoo/sample/xources/hello/HelloJava.xoo
index 1d9c60d56b7..1d9c60d56b7 100644
--- a/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/HelloJava.xoo
+++ b/sonar-batch/src/test/resources/mediumtest/xoo/sample/xources/hello/HelloJava.xoo
diff --git a/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/HelloJava.xoo.measures b/sonar-batch/src/test/resources/mediumtest/xoo/sample/xources/hello/HelloJava.xoo.measures
index 388d08b58a8..388d08b58a8 100644
--- a/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/HelloJava.xoo.measures
+++ b/sonar-batch/src/test/resources/mediumtest/xoo/sample/xources/hello/HelloJava.xoo.measures
diff --git a/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/HelloJava.xoo.scm b/sonar-batch/src/test/resources/mediumtest/xoo/sample/xources/hello/HelloJava.xoo.scm
index 03a9de2f486..03a9de2f486 100644
--- a/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/HelloJava.xoo.scm
+++ b/sonar-batch/src/test/resources/mediumtest/xoo/sample/xources/hello/HelloJava.xoo.scm
diff --git a/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/helloscala.xoo b/sonar-batch/src/test/resources/mediumtest/xoo/sample/xources/hello/helloscala.xoo
index 53cb085156c..53cb085156c 100644
--- a/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/helloscala.xoo
+++ b/sonar-batch/src/test/resources/mediumtest/xoo/sample/xources/hello/helloscala.xoo
diff --git a/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/helloscala.xoo.measures b/sonar-batch/src/test/resources/mediumtest/xoo/sample/xources/hello/helloscala.xoo.measures
index c47948fc955..c47948fc955 100644
--- a/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/helloscala.xoo.measures
+++ b/sonar-batch/src/test/resources/mediumtest/xoo/sample/xources/hello/helloscala.xoo.measures