aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-batch/src/test/java
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/src/test/java
parent71a6a922a2d07ae8db9f13036a9653e772380762 (diff)
downloadsonarqube-369f12960fba6653e630042ab977c97e479a3076.tar.gz
sonarqube-369f12960fba6653e630042ab977c97e479a3076.zip
SONAR-5389 Add support of FileLinesContextFactory + publish analysis
Diffstat (limited to 'sonar-batch/src/test/java')
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/mediumtest/AnalyzerMediumTester.java417
-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
4 files changed, 180 insertions, 424 deletions
diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/AnalyzerMediumTester.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/AnalyzerMediumTester.java
deleted file mode 100644
index d69b371f57d..00000000000
--- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/AnalyzerMediumTester.java
+++ /dev/null
@@ -1,417 +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.mediumtest;
-
-import com.google.common.collect.BiMap;
-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;
-import org.sonar.api.batch.debt.internal.DefaultDebtModel;
-import org.sonar.api.batch.rule.internal.ActiveRulesBuilder;
-import org.sonar.api.batch.rule.internal.RulesBuilder;
-import org.sonar.api.batch.rules.QProfile;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.measures.Metric;
-import org.sonar.api.measures.MetricFinder;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rules.Rule;
-import org.sonar.api.rules.RuleFinder;
-import org.sonar.api.rules.RuleQuery;
-import org.sonar.batch.bootstrap.PluginsReferential;
-import org.sonar.batch.bootstrapper.Batch;
-import org.sonar.batch.bootstrapper.EnvironmentInformation;
-import org.sonar.batch.languages.Language;
-import org.sonar.batch.languages.LanguagesReferential;
-import org.sonar.batch.rules.QProfilesReferential;
-import org.sonar.batch.scan2.AnalyzerIssueCache;
-import org.sonar.batch.scan2.AnalyzerMeasureCache;
-import org.sonar.batch.scan2.ProjectScanContainer;
-import org.sonar.batch.scan2.ScanTaskObserver;
-import org.sonar.batch.settings.SettingsReferential;
-import org.sonar.core.plugins.DefaultPluginMetadata;
-import org.sonar.core.plugins.RemotePlugin;
-
-import java.io.File;
-import java.io.FileReader;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-
-public class AnalyzerMediumTester extends ExternalResource {
-
- private Batch batch;
-
- public static AnalyzerMediumTesterBuilder builder() {
- return new AnalyzerMediumTesterBuilder().registerCoreMetrics();
- }
-
- public static class AnalyzerMediumTesterBuilder {
- private final FakeSettingsReferential settingsReferential = new FakeSettingsReferential();
- private final FackPluginsReferential pluginsReferential = new FackPluginsReferential();
- private final FakeMetricFinder metricFinder = new FakeMetricFinder();
- private final FakeRuleFinder ruleFinder = new FakeRuleFinder();
- private final FakeQProfileReferential qProfileReferential = new FakeQProfileReferential();
- private final FakeLanguageReferential languageReferential = new FakeLanguageReferential();
- private final Map<String, String> bootstrapProperties = new HashMap<String, String>();
- private final RulesBuilder rulesBuilder = new RulesBuilder();
- private final ActiveRulesBuilder activeRulesBuilder = new ActiveRulesBuilder();
- private int metricId = 1;
-
- public AnalyzerMediumTester build() {
- return new AnalyzerMediumTester(this);
- }
-
- public AnalyzerMediumTesterBuilder registerPlugin(String pluginKey, File location) {
- pluginsReferential.addPlugin(pluginKey, location);
- return this;
- }
-
- public AnalyzerMediumTesterBuilder registerPlugin(String pluginKey, SonarPlugin instance) {
- pluginsReferential.addPlugin(pluginKey, instance);
- return this;
- }
-
- public AnalyzerMediumTesterBuilder registerCoreMetrics() {
- for (Metric<?> m : CoreMetrics.getMetrics()) {
- registerMetric(m);
- }
- return this;
- }
-
- public AnalyzerMediumTesterBuilder registerMetric(Metric<?> metric) {
- metricFinder.add(metricId++, metric);
- return this;
- }
-
- public AnalyzerMediumTesterBuilder addQProfile(String language, String name) {
- qProfileReferential.add(new QProfile("TODO", name, language));
- return this;
- }
-
- public AnalyzerMediumTesterBuilder addDefaultQProfile(String language, String name) {
- qProfileReferential.add(new QProfile("TODO", name, language));
- settingsReferential.globalSettings().put("sonar.profile." + language, name);
- return this;
- }
-
- public AnalyzerMediumTesterBuilder registerLanguage(org.sonar.api.resources.Language... languages) {
- languageReferential.register(languages);
- return this;
- }
-
- public AnalyzerMediumTesterBuilder bootstrapProperties(Map<String, String> props) {
- bootstrapProperties.putAll(props);
- return this;
- }
-
- public AnalyzerMediumTesterBuilder activateRule(RuleKey key) {
- rulesBuilder.add(key);
- activeRulesBuilder.create(key).activate();
- return this;
- }
-
- public AnalyzerMediumTesterBuilder registerInactiveRule(RuleKey key) {
- rulesBuilder.add(key);
- return this;
- }
-
- }
-
- @Override
- protected void before() throws Throwable {
- batch.start();
- }
-
- @Override
- protected void after() {
- batch.stop();
- }
-
- private AnalyzerMediumTester(AnalyzerMediumTesterBuilder builder) {
- batch = Batch.builder()
- .setEnableLoggingConfiguration(true)
- .addComponents(
- new EnvironmentInformation("mediumTest", "1.0"),
- builder.settingsReferential,
- builder.pluginsReferential,
- builder.metricFinder,
- builder.ruleFinder,
- builder.qProfileReferential,
- builder.rulesBuilder.build(),
- builder.activeRulesBuilder.build(),
- new DefaultDebtModel(),
- builder.languageReferential)
- .setBootstrapProperties(builder.bootstrapProperties)
- .build();
- }
-
- public TaskBuilder newTask() {
- return new TaskBuilder(this);
- }
-
- public TaskBuilder newScanTask(File sonarProps) {
- Properties prop = new Properties();
- FileReader reader = null;
- try {
- reader = new FileReader(sonarProps);
- prop.load(reader);
- } catch (Exception e) {
- throw new IllegalStateException("Unable to read configuration file", e);
- } finally {
- if (reader != null) {
- IOUtils.closeQuietly(reader);
- }
- }
- TaskBuilder builder = new TaskBuilder(this);
- builder.property("sonar.task", "scan");
- builder.property("sonar.projectBaseDir", sonarProps.getParentFile().getAbsolutePath());
- for (Map.Entry entry : prop.entrySet()) {
- builder.property(entry.getKey().toString(), entry.getValue().toString());
- }
- return builder;
- }
-
- public static class TaskBuilder {
- private final Map<String, String> taskProperties = new HashMap<String, String>();
- private AnalyzerMediumTester tester;
-
- public TaskBuilder(AnalyzerMediumTester tester) {
- this.tester = tester;
- }
-
- public TaskResult start() {
- TaskResult result = new TaskResult();
- tester.batch.executeTask(taskProperties,
- result
- );
- return result;
- }
-
- public TaskBuilder properties(Map<String, String> props) {
- taskProperties.putAll(props);
- return this;
- }
-
- public TaskBuilder property(String key, String value) {
- taskProperties.put(key, value);
- return this;
- }
- }
-
- public static class TaskResult implements ScanTaskObserver {
- private List<AnalyzerIssue> issues = new ArrayList<AnalyzerIssue>();
- private List<AnalyzerMeasure> measures = new ArrayList<AnalyzerMeasure>();
-
- @Override
- public void scanTaskCompleted(ProjectScanContainer container) {
- for (AnalyzerIssue issue : container.getComponentByType(AnalyzerIssueCache.class).all()) {
- issues.add(issue);
- }
-
- for (AnalyzerMeasure<?> measure : container.getComponentByType(AnalyzerMeasureCache.class).all()) {
- measures.add(measure);
- }
- }
-
- public List<AnalyzerIssue> issues() {
- return issues;
- }
-
- public List<AnalyzerMeasure> measures() {
- return measures;
- }
-
- }
-
- private static class FakeSettingsReferential implements SettingsReferential {
-
- private Map<String, String> globalSettings = new HashMap<String, String>();
- private Map<String, Map<String, String>> projectSettings = new HashMap<String, Map<String, String>>();
-
- @Override
- public Map<String, String> globalSettings() {
- return globalSettings;
- }
-
- @Override
- public Map<String, String> projectSettings(String projectKey) {
- return projectSettings.containsKey(projectKey) ? projectSettings.get(projectKey) : Collections.<String, String>emptyMap();
- }
-
- }
-
- private static class FackPluginsReferential implements PluginsReferential {
-
- private List<RemotePlugin> pluginList = new ArrayList<RemotePlugin>();
- private Map<RemotePlugin, File> pluginFiles = new HashMap<RemotePlugin, File>();
- Map<PluginMetadata, SonarPlugin> localPlugins = new HashMap<PluginMetadata, SonarPlugin>();
-
- @Override
- public List<RemotePlugin> pluginList() {
- return pluginList;
- }
-
- @Override
- public File pluginFile(RemotePlugin remote) {
- return pluginFiles.get(remote);
- }
-
- public FackPluginsReferential addPlugin(String pluginKey, File location) {
- RemotePlugin plugin = new RemotePlugin(pluginKey, false);
- pluginList.add(plugin);
- pluginFiles.put(plugin, location);
- return this;
- }
-
- public FackPluginsReferential addPlugin(String pluginKey, SonarPlugin pluginInstance) {
- localPlugins.put(DefaultPluginMetadata.create(null).setKey(pluginKey), pluginInstance);
- return this;
- }
-
- @Override
- public Map<PluginMetadata, SonarPlugin> localPlugins() {
- return localPlugins;
- }
-
- }
-
- private static class FakeMetricFinder implements MetricFinder {
-
- private Map<String, Metric> metricsByKey = Maps.newLinkedHashMap();
- private Map<Integer, Metric> metricsById = Maps.newLinkedHashMap();
-
- public FakeMetricFinder add(int id, Metric metric) {
- metricsByKey.put(metric.getKey(), metric);
- metricsById.put(id, metric);
- return this;
- }
-
- @Override
- public Metric findById(int metricId) {
- return metricsById.get(metricId);
- }
-
- @Override
- public Metric findByKey(String key) {
- return metricsByKey.get(key);
- }
-
- @Override
- public Collection<Metric> findAll(List<String> metricKeys) {
- List<Metric> result = Lists.newLinkedList();
- for (String metricKey : metricKeys) {
- Metric metric = findByKey(metricKey);
- if (metric != null) {
- result.add(metric);
- }
- }
- return result;
- }
-
- @Override
- public Collection<Metric> findAll() {
- return metricsByKey.values();
- }
-
- }
-
- private static class FakeRuleFinder implements RuleFinder {
- private BiMap<Integer, Rule> rulesById = HashBiMap.create();
- private Map<String, Map<String, Rule>> rulesByRepoKeyAndRuleKey = Maps.newHashMap();
-
- @Override
- public Rule findById(int ruleId) {
- return rulesById.get(ruleId);
- }
-
- @Override
- public Rule findByKey(String repositoryKey, String ruleKey) {
- Map<String, Rule> repository = rulesByRepoKeyAndRuleKey.get(repositoryKey);
- return repository != null ? repository.get(ruleKey) : null;
- }
-
- @Override
- public Rule findByKey(RuleKey key) {
- return findByKey(key.repository(), key.rule());
- }
-
- @Override
- public Rule find(RuleQuery query) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Collection<Rule> findAll(RuleQuery query) {
- throw new UnsupportedOperationException();
- }
- }
-
- private static class FakeQProfileReferential implements QProfilesReferential {
-
- private Map<String, Map<String, QProfile>> profiles = new HashMap<String, Map<String, QProfile>>();
-
- @Override
- public QProfile get(String language, String name) {
- return profiles.get(language).get(name);
- }
-
- public void add(QProfile qprofile) {
- if (!profiles.containsKey(qprofile.language())) {
- profiles.put(qprofile.language(), new HashMap<String, QProfile>());
- }
- profiles.get(qprofile.language()).put(qprofile.name(), qprofile);
- }
-
- }
-
- private static class FakeLanguageReferential implements LanguagesReferential {
-
- private Map<String, Language> languages = new HashMap<String, Language>();
-
- public FakeLanguageReferential register(org.sonar.api.resources.Language... languages) {
- for (org.sonar.api.resources.Language language : languages) {
- this.languages.put(language.getKey(), new Language(language.getKey(), language.getName(), language.getFileSuffixes()));
- }
- return this;
- }
-
- @Override
- public Language get(String languageKey) {
- return languages.get(languageKey);
- }
-
- @Override
- public Collection<Language> all() {
- return languages.values();
- }
-
- }
-
-}
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();
+ }
+}