diff options
author | Julien HENRY <julien.henry@sonarsource.com> | 2014-06-19 23:25:55 +0200 |
---|---|---|
committer | Julien HENRY <julien.henry@sonarsource.com> | 2014-06-19 23:26:57 +0200 |
commit | 369f12960fba6653e630042ab977c97e479a3076 (patch) | |
tree | c3896b2a5f2caf4fdc8037567a862e810b43b38f /sonar-batch/src/test/java | |
parent | 71a6a922a2d07ae8db9f13036a9653e772380762 (diff) | |
download | sonarqube-369f12960fba6653e630042ab977c97e479a3076.tar.gz sonarqube-369f12960fba6653e630042ab977c97e479a3076.zip |
SONAR-5389 Add support of FileLinesContextFactory + publish analysis
Diffstat (limited to 'sonar-batch/src/test/java')
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(); + } +} |