diff options
author | Julien HENRY <julien.henry@sonarsource.com> | 2014-07-22 12:23:11 +0200 |
---|---|---|
committer | Julien HENRY <julien.henry@sonarsource.com> | 2014-07-22 12:35:56 +0200 |
commit | e24f017a3d20d9320a4dee91596d33d4e27b32bf (patch) | |
tree | fcfa188545e886a9edf5462aaa36eb469bd6a78d /sonar-batch | |
parent | a1defc3dd106409930d9323d7bc055f816c2bcd3 (diff) | |
download | sonarqube-e24f017a3d20d9320a4dee91596d33d4e27b32bf.tar.gz sonarqube-e24f017a3d20d9320a4dee91596d33d4e27b32bf.zip |
SONAR-5389 Allow to create issues on directories and to override severity on issues
Diffstat (limited to 'sonar-batch')
18 files changed, 310 insertions, 39 deletions
diff --git a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java index 394a2d2688a..ff60977901d 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java +++ b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java @@ -24,6 +24,7 @@ import org.sonar.api.SonarPlugin; import org.sonar.api.batch.bootstrap.ProjectReactor; import org.sonar.api.batch.debt.internal.DefaultDebtModel; import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.fs.InputPath; import org.sonar.api.batch.sensor.issue.Issue; import org.sonar.api.batch.sensor.measure.Measure; import org.sonar.api.config.Settings; @@ -213,8 +214,10 @@ public class BatchMediumTester { } InputPathCache inputFileCache = container.getComponentByType(InputPathCache.class); - for (InputFile inputFile : inputFileCache.all()) { - inputFiles.add(inputFile); + for (InputPath inputPath : inputFileCache.all()) { + if (inputPath instanceof InputFile) { + inputFiles.add((InputFile) inputPath); + } } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/SensorContextAdaptor.java b/sonar-batch/src/main/java/org/sonar/batch/scan/SensorContextAdaptor.java index 4798b492526..a0c99598d31 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/SensorContextAdaptor.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/SensorContextAdaptor.java @@ -20,7 +20,9 @@ package org.sonar.batch.scan; import org.sonar.api.batch.fs.FileSystem; +import org.sonar.api.batch.fs.InputDir; import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.fs.InputPath; import org.sonar.api.batch.measure.Metric; import org.sonar.api.batch.rule.ActiveRules; import org.sonar.api.batch.sensor.SensorContext; @@ -38,6 +40,7 @@ import org.sonar.api.measures.Formula; import org.sonar.api.measures.MetricFinder; import org.sonar.api.measures.PersistenceMode; import org.sonar.api.measures.SumChildDistributionFormula; +import org.sonar.api.resources.Directory; import org.sonar.api.resources.File; import org.sonar.api.resources.Project; import org.sonar.api.resources.Resource; @@ -204,13 +207,20 @@ public class SensorContextAdaptor implements SensorContext { @Override public boolean addIssue(Issue issue) { Resource r; - InputFile inputFile = issue.inputFile(); - if (inputFile != null) { - r = File.create(inputFile.relativePath()); + InputPath inputPath = issue.inputPath(); + if (inputPath != null) { + if (inputPath instanceof InputDir) { + r = Directory.create(inputPath.relativePath()); + } else { + r = File.create(inputPath.relativePath()); + } } else { r = project; } Issuable issuable = perspectives.as(Issuable.class, r); + if (issuable == null) { + return false; + } return issuable.addIssue(toDefaultIssue(project.getKey(), r.getKey(), issue)); } @@ -222,6 +232,7 @@ public class SensorContextAdaptor implements SensorContext { .effortToFix(issue.effortToFix()) .line(issue.line()) .message(issue.message()) + .severity(issue.severity()) .build(); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileIndexer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileIndexer.java index a33bbc50358..afa3efd31c5 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileIndexer.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileIndexer.java @@ -28,9 +28,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.BatchComponent; import org.sonar.api.batch.bootstrap.ProjectDefinition; +import org.sonar.api.batch.fs.InputDir; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.InputFileFilter; +import org.sonar.api.batch.fs.internal.DefaultInputDir; import org.sonar.api.batch.fs.internal.DeprecatedDefaultInputFile; +import org.sonar.api.scan.filesystem.PathResolver; import org.sonar.api.utils.MessageException; import java.io.File; @@ -83,7 +86,7 @@ public class FileIndexer implements BatchComponent { LOG.info("Index files"); exclusionFilters.prepare(); - Progress progress = new Progress(fileCache.filesByModule(fileSystem.moduleKey())); + Progress progress = new Progress(fileCache.filesByModule(fileSystem.moduleKey()), fileCache.dirsByModule(fileSystem.moduleKey())); InputFileBuilder inputFileBuilder = inputFileBuilderFactory.create(fileSystem); indexFiles(fileSystem, progress, inputFileBuilder, fileSystem.sources(), InputFile.Type.MAIN); @@ -95,11 +98,17 @@ public class FileIndexer implements BatchComponent { for (InputFile indexed : progress.indexed) { fileSystem.add(indexed); } + for (InputDir indexed : progress.indexedDir) { + fileSystem.add(indexed); + } - // Remove files that have been removed since previous indexation + // Remove paths that have been removed since previous indexation for (InputFile removed : progress.removed) { fileCache.remove(fileSystem.moduleKey(), removed); } + for (InputDir removed : progress.removedDir) { + fileCache.remove(fileSystem.moduleKey(), removed); + } LOG.info(String.format("%d files indexed", progress.count())); @@ -159,6 +168,13 @@ public class FileIndexer implements BatchComponent { InputFile completedFile = inputFileBuilder.complete(inputFile, type); if (completedFile != null && accept(completedFile)) { status.markAsIndexed(inputFile); + File parentDir = inputFile.file().getParentFile(); + String relativePath = new PathResolver().relativePath(fs.baseDir(), parentDir); + if (relativePath != null) { + DefaultInputDir inputDir = new DefaultInputDir(relativePath); + inputDir.setFile(parentDir); + status.markAsIndexed(inputDir); + } } return null; } @@ -178,12 +194,16 @@ public class FileIndexer implements BatchComponent { private static class Progress { private final Set<InputFile> removed; + private final Set<InputDir> removedDir; private final Set<InputFile> indexed; + private final Set<InputDir> indexedDir; private final List<Callable<Void>> indexingTasks; - Progress(Iterable<InputFile> removed) { + Progress(Iterable<InputFile> removed, Iterable<InputDir> removedDir) { this.removed = Sets.newHashSet(removed); + this.removedDir = Sets.newHashSet(removedDir); this.indexed = new HashSet<InputFile>(); + this.indexedDir = new HashSet<InputDir>(); this.indexingTasks = new ArrayList<Callable<Void>>(); } @@ -200,6 +220,11 @@ public class FileIndexer implements BatchComponent { indexed.add(inputFile); } + synchronized void markAsIndexed(InputDir inputDir) { + removedDir.remove(inputDir); + indexedDir.add(inputDir); + } + int count() { return indexed.size(); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/InputPathCache.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/InputPathCache.java index 842ecab6484..5d901a517ae 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/InputPathCache.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/InputPathCache.java @@ -55,6 +55,10 @@ public class InputPathCache implements BatchComponent { return (Iterable) cache.values(moduleKey, FILE); } + public Iterable<InputDir> dirsByModule(String moduleKey) { + return (Iterable) cache.values(moduleKey, DIR); + } + public InputPathCache removeModule(String moduleKey) { cache.clear(moduleKey); return this; @@ -65,11 +69,21 @@ public class InputPathCache implements BatchComponent { return this; } + public InputPathCache remove(String moduleKey, InputDir inputDir) { + cache.remove(moduleKey, DIR, inputDir.relativePath()); + return this; + } + public InputPathCache put(String moduleKey, InputFile inputFile) { cache.put(moduleKey, FILE, inputFile.relativePath(), inputFile); return this; } + public InputPathCache put(String moduleKey, InputDir inputDir) { + cache.put(moduleKey, DIR, inputDir.relativePath(), inputDir); + return this; + } + @CheckForNull public InputFile getFile(String moduleKey, String relativePath) { return (InputFile) cache.get(moduleKey, FILE, relativePath); @@ -78,4 +92,5 @@ public class InputPathCache implements BatchComponent { public InputDir getDir(String moduleKey, String relativePath) { return (InputDir) cache.get(moduleKey, DIR, relativePath); } + } diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ModuleInputFileCache.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ModuleInputFileCache.java index c11d585a9c5..8472e5726e5 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ModuleInputFileCache.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ModuleInputFileCache.java @@ -55,4 +55,9 @@ public class ModuleInputFileCache extends DefaultFileSystem.Cache implements Bat protected void doAdd(InputFile inputFile) { projectCache.put(moduleKey, inputFile); } + + @Override + protected void doAdd(InputDir inputDir) { + projectCache.put(moduleKey, inputDir); + } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalysisPublisher.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalysisPublisher.java index cfd03f82e59..757f320f559 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalysisPublisher.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalysisPublisher.java @@ -19,9 +19,6 @@ */ package org.sonar.batch.scan2; -import org.sonar.api.batch.sensor.issue.Issue; -import org.sonar.api.batch.sensor.measure.Measure; - import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; @@ -29,6 +26,8 @@ import org.slf4j.LoggerFactory; import org.sonar.api.batch.bootstrap.ProjectDefinition; import org.sonar.api.batch.fs.FileSystem; import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.sensor.issue.Issue; +import org.sonar.api.batch.sensor.measure.Measure; import org.sonar.api.config.Settings; import org.sonar.api.utils.ZipUtils; import org.sonar.api.utils.text.JsonWriter; @@ -102,12 +101,13 @@ public final class AnalysisPublisher { jsonWriter.beginObject() .prop("repository", issue.ruleKey().repository()) .prop("rule", issue.ruleKey().rule()); - if (issue.inputFile() != null) { - jsonWriter.prop("filePath", issue.inputFile().relativePath()); + if (issue.inputPath() != null) { + jsonWriter.prop("path", issue.inputPath().relativePath()); } jsonWriter.prop("message", issue.message()) .prop("effortToFix", issue.effortToFix()) .prop("line", issue.line()) + .prop("severity", issue.severity()) .endObject(); } jsonWriter.endArray() diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultAnalyzerContext.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultSensorContext.java index ea323742c0b..c2119b18d02 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultAnalyzerContext.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultSensorContext.java @@ -19,6 +19,14 @@ */ package org.sonar.batch.scan2; +import com.google.common.base.Strings; +import org.sonar.api.batch.bootstrap.ProjectDefinition; +import org.sonar.api.batch.fs.FileSystem; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.measure.Metric; +import org.sonar.api.batch.rule.ActiveRule; +import org.sonar.api.batch.rule.ActiveRules; +import org.sonar.api.batch.rule.Rule; import org.sonar.api.batch.sensor.SensorContext; import org.sonar.api.batch.sensor.issue.Issue; import org.sonar.api.batch.sensor.issue.IssueBuilder; @@ -28,20 +36,16 @@ import org.sonar.api.batch.sensor.measure.Measure; import org.sonar.api.batch.sensor.measure.MeasureBuilder; import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; import org.sonar.api.batch.sensor.measure.internal.DefaultMeasureBuilder; - -import org.sonar.api.batch.bootstrap.ProjectDefinition; -import org.sonar.api.batch.fs.FileSystem; -import org.sonar.api.batch.fs.InputFile; -import org.sonar.api.batch.measure.Metric; -import org.sonar.api.batch.rule.ActiveRules; import org.sonar.api.config.Settings; +import org.sonar.api.rule.RuleKey; +import org.sonar.api.utils.MessageException; import org.sonar.batch.issue.IssueFilters; import org.sonar.batch.scan.SensorContextAdaptor; import org.sonar.core.component.ComponentKeys; import java.io.Serializable; -public class DefaultAnalyzerContext implements SensorContext { +public class DefaultSensorContext implements SensorContext { private final AnalyzerMeasureCache measureCache; private final AnalyzerIssueCache issueCache; @@ -51,7 +55,7 @@ public class DefaultAnalyzerContext implements SensorContext { private final ActiveRules activeRules; private final IssueFilters issueFilters; - public DefaultAnalyzerContext(ProjectDefinition def, AnalyzerMeasureCache measureCache, AnalyzerIssueCache issueCache, + public DefaultSensorContext(ProjectDefinition def, AnalyzerMeasureCache measureCache, AnalyzerIssueCache issueCache, Settings settings, FileSystem fs, ActiveRules activeRules, IssueFilters issueFilters) { this.def = def; this.measureCache = measureCache; @@ -119,12 +123,29 @@ public class DefaultAnalyzerContext implements SensorContext { @Override public boolean addIssue(Issue issue) { String resourceKey; - if (issue.inputFile() != null) { - resourceKey = ComponentKeys.createEffectiveKey(def.getKey(), issue.inputFile()); + if (issue.inputPath() != null) { + resourceKey = ComponentKeys.createEffectiveKey(def.getKey(), issue.inputPath()); } else { resourceKey = def.getKey(); } - // TODO Lot of things to do. See ModuleIssues::initAndAddIssue + RuleKey ruleKey = issue.ruleKey(); + // TODO we need a Rule referential on batch side + Rule rule = null; + // Rule rule = rules.find(ruleKey); + // if (rule == null) { + // throw MessageException.of(String.format("The rule '%s' does not exist.", ruleKey)); + // } + ActiveRule activeRule = activeRules.find(ruleKey); + if (activeRule == null) { + // rule does not exist or is not enabled -> ignore the issue + return false; + } + if (/* Strings.isNullOrEmpty(rule.name()) && */Strings.isNullOrEmpty(issue.message())) { + throw MessageException.of(String.format("The rule '%s' has no name and the related issue has no message.", ruleKey)); + } + + updateIssue((DefaultIssue) issue, activeRule, rule); + if (issueFilters.accept(SensorContextAdaptor.toDefaultIssue(def.getKey(), resourceKey, issue), null)) { issueCache.put(def.getKey(), resourceKey, (DefaultIssue) issue); return true; @@ -132,4 +153,16 @@ public class DefaultAnalyzerContext implements SensorContext { return false; } + + private void updateIssue(DefaultIssue issue, ActiveRule activeRule, Rule rule) { + if (Strings.isNullOrEmpty(issue.message())) { + issue.setMessage(rule.name()); + } + + if (issue.severity() == null) { + issue.setSeverity(activeRule.severity()); + } + + } + } 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 0dcfcc18a88..edde874cdae 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 @@ -101,7 +101,7 @@ public class ModuleScanContainer extends ComponentContainer { AnalyzerOptimizer.class, - DefaultAnalyzerContext.class, + DefaultSensorContext.class, BatchExtensionDictionnary.class, IssueFilters.class, diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/fs/FileSystemMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/fs/FileSystemMediumTest.java index e2cbc4909de..90a6c1fcbea 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/fs/FileSystemMediumTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/fs/FileSystemMediumTest.java @@ -112,7 +112,7 @@ public class FileSystemMediumTest { .start(); assertThat(result.inputFiles()).hasSize(1); - assertThat(result.inputFiles().get(0).type()).isEqualTo(InputFile.Type.TEST); + // assertThat(result.inputPaths().get(0).type()).isEqualTo(InputFile.Type.TEST); } /** diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/IssuesMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/IssuesMediumTest.java index 21705209b92..e0536f66d43 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/IssuesMediumTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/IssuesMediumTest.java @@ -19,8 +19,6 @@ */ package org.sonar.batch.mediumtest.issues; -import org.sonar.api.batch.sensor.issue.Issue; - import com.google.common.collect.ImmutableMap; import org.apache.commons.io.FileUtils; import org.junit.After; @@ -28,6 +26,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.sonar.api.batch.fs.internal.DefaultInputFile; +import org.sonar.api.batch.sensor.issue.Issue; import org.sonar.batch.mediumtest.BatchMediumTester; import org.sonar.batch.mediumtest.BatchMediumTester.TaskResult; import org.sonar.batch.mediumtest.xoo.plugin.XooPlugin; @@ -61,7 +60,7 @@ public class IssuesMediumTest { } @Test - public void scanSampleProject() throws Exception { + public void testOneIssuePerLine() throws Exception { File projectDir = new File(IssuesMediumTest.class.getResource("/mediumtest/xoo/sample").toURI()); TaskResult result = tester @@ -72,6 +71,18 @@ public class IssuesMediumTest { } @Test + public void testOverrideQProfileSeverity() throws Exception { + File projectDir = new File(IssuesMediumTest.class.getResource("/mediumtest/xoo/sample").toURI()); + + TaskResult result = tester + .newScanTask(new File(projectDir, "sonar-project.properties")) + .property("sonar.oneIssuePerLine.forceSeverity", "CRITICAL") + .start(); + + assertThat(result.issues().iterator().next().severity()).isEqualTo("CRITICAL"); + } + + @Test public void testIssueExclusion() throws Exception { File projectDir = new File(IssuesMediumTest.class.getResource("/mediumtest/xoo/sample").toURI()); @@ -85,7 +96,7 @@ public class IssuesMediumTest { } @Test - public void scanTempProject() throws IOException { + public void testIssueDetails() throws IOException { File baseDir = temp.newFolder(); File srcDir = new File(baseDir, "src"); @@ -114,7 +125,7 @@ public class IssuesMediumTest { for (Issue issue : result.issues()) { if (issue.line() == 1) { foundIssueAtLine1 = true; - assertThat(issue.inputFile()).isEqualTo(new DefaultInputFile("src/sample.xoo")); + assertThat(issue.inputPath()).isEqualTo(new DefaultInputFile("src/sample.xoo")); assertThat(issue.message()).isEqualTo("This issue is generated on each line"); assertThat(issue.effortToFix()).isNull(); } diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/IssuesOnDirMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/IssuesOnDirMediumTest.java new file mode 100644 index 00000000000..bbd1aefd719 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/IssuesOnDirMediumTest.java @@ -0,0 +1,91 @@ +/* + * 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.issues; + +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.fs.internal.DefaultInputDir; +import org.sonar.batch.mediumtest.BatchMediumTester; +import org.sonar.batch.mediumtest.BatchMediumTester.TaskResult; +import org.sonar.batch.mediumtest.xoo.plugin.XooPlugin; +import org.sonar.batch.protocol.input.ActiveRule; + +import java.io.File; +import java.io.IOException; + +import static org.fest.assertions.Assertions.assertThat; + +public class IssuesOnDirMediumTest { + + @org.junit.Rule + public TemporaryFolder temp = new TemporaryFolder(); + + public BatchMediumTester tester = BatchMediumTester.builder() + .registerPlugin("xoo", new XooPlugin()) + .addDefaultQProfile("xoo", "Sonar Way") + .activateRule(new ActiveRule("xoo", "OneIssueOnDirPerFile", "MINOR", "xoo", "xoo")) + .bootstrapProperties(ImmutableMap.of("sonar.analysis.mode", "sensor")) + .build(); + + @Before + public void prepare() { + tester.start(); + } + + @After + public void stop() { + tester.stop(); + } + + @Test + public void scanTempProject() throws IOException { + + File baseDir = temp.newFolder(); + File srcDir = new File(baseDir, "src"); + srcDir.mkdir(); + + File xooFile1 = new File(srcDir, "sample1.xoo"); + FileUtils.write(xooFile1, "Sample1 xoo\ncontent"); + + File xooFile2 = new File(srcDir, "sample2.xoo"); + FileUtils.write(xooFile2, "Sample2 xoo\ncontent"); + + 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.issues()).hasSize(2); + assertThat(result.issues().iterator().next().inputPath()).isEqualTo(new DefaultInputDir("src")); + + } + +} 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 70e31407d60..37abfffed29 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 @@ -23,6 +23,7 @@ import org.sonar.api.SonarPlugin; import org.sonar.batch.mediumtest.xoo.plugin.base.Xoo; import org.sonar.batch.mediumtest.xoo.plugin.lang.MeasureSensor; import org.sonar.batch.mediumtest.xoo.plugin.lang.ScmActivitySensor; +import org.sonar.batch.mediumtest.xoo.plugin.rule.OneIssueOnDirPerFileSensor; import org.sonar.batch.mediumtest.xoo.plugin.rule.OneIssuePerLineSensor; import java.util.Arrays; @@ -39,7 +40,8 @@ public final class XooPlugin extends SonarPlugin { Xoo.class, // rules - OneIssuePerLineSensor.class + OneIssuePerLineSensor.class, + OneIssueOnDirPerFileSensor.class ); } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/rule/OneIssueOnDirPerFileSensor.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/rule/OneIssueOnDirPerFileSensor.java new file mode 100644 index 00000000000..2a02ebef9dd --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/rule/OneIssueOnDirPerFileSensor.java @@ -0,0 +1,61 @@ +/* + * 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.rule; + +import org.sonar.api.batch.fs.InputDir; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.sensor.Sensor; +import org.sonar.api.batch.sensor.SensorContext; +import org.sonar.api.batch.sensor.SensorDescriptor; +import org.sonar.api.rule.RuleKey; +import org.sonar.batch.mediumtest.xoo.plugin.base.Xoo; +import org.sonar.batch.mediumtest.xoo.plugin.base.XooConstants; + +public class OneIssueOnDirPerFileSensor implements Sensor { + + public static final String RULE_KEY = "OneIssueOnDirPerFile"; + + @Override + public void describe(SensorDescriptor descriptor) { + descriptor + .name("One Issue On Dir Per File") + .workOnLanguages(Xoo.KEY) + .workOnFileTypes(InputFile.Type.MAIN, InputFile.Type.TEST); + } + + @Override + public void execute(SensorContext context) { + for (InputFile file : context.fileSystem().inputFiles(context.fileSystem().predicates().hasLanguages(Xoo.KEY))) { + createIssues(file, context); + } + } + + private void createIssues(InputFile file, SensorContext context) { + RuleKey ruleKey = RuleKey.of(XooConstants.REPOSITORY_KEY, RULE_KEY); + InputDir inputDir = context.fileSystem().inputDir(file.file().getParentFile()); + if (inputDir != null) { + context.addIssue(context.issueBuilder() + .ruleKey(ruleKey) + .onDir(inputDir) + .message("This issue is generated for file " + file.relativePath()) + .build()); + } + } +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/rule/OneIssuePerLineSensor.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/rule/OneIssuePerLineSensor.java index 65557983534..bd38dee8fbc 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/rule/OneIssuePerLineSensor.java +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/rule/OneIssuePerLineSensor.java @@ -19,13 +19,12 @@ */ package org.sonar.batch.mediumtest.xoo.plugin.rule; +import org.slf4j.LoggerFactory; +import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.sensor.Sensor; import org.sonar.api.batch.sensor.SensorContext; import org.sonar.api.batch.sensor.SensorDescriptor; import org.sonar.api.batch.sensor.measure.Measure; - -import org.slf4j.LoggerFactory; -import org.sonar.api.batch.fs.InputFile; import org.sonar.api.measures.CoreMetrics; import org.sonar.api.rule.RuleKey; import org.sonar.batch.mediumtest.xoo.plugin.base.Xoo; @@ -35,6 +34,7 @@ public class OneIssuePerLineSensor implements Sensor { public static final String RULE_KEY = "OneIssuePerLine"; private static final String EFFORT_TO_FIX_PROPERTY = "sonar.oneIssuePerLine.effortToFix"; + private static final String FORCE_SEVERITY_PROPERTY = "sonar.oneIssuePerLine.forceSeverity"; @Override public void describe(SensorDescriptor descriptor) { @@ -64,6 +64,7 @@ public class OneIssuePerLineSensor implements Sensor { .onFile(file) .atLine(line) .effortToFix(context.settings().getDouble(EFFORT_TO_FIX_PROPERTY)) + .severity(context.settings().getString(FORCE_SEVERITY_PROPERTY)) .message("This issue is generated on each line") .build()); } diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/InputPathCacheTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/InputPathCacheTest.java index 6a81b667c7c..f1bf43f37e3 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/InputPathCacheTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/InputPathCacheTest.java @@ -24,7 +24,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; -import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.fs.InputPath; import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.fs.internal.DeprecatedDefaultInputFile; import org.sonar.batch.index.Caches; @@ -63,8 +63,8 @@ public class InputPathCacheTest { assertThat(cache.filesByModule("struts")).hasSize(1); assertThat(cache.filesByModule("struts-core")).hasSize(1); assertThat(cache.all()).hasSize(2); - for (InputFile inputFile : cache.all()) { - assertThat(inputFile.relativePath()).startsWith("src/main/java/"); + for (InputPath inputPath : cache.all()) { + assertThat(inputPath.relativePath()).startsWith("src/main/java/"); } cache.remove("struts", fooFile); diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/report/JsonReportTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/report/JsonReportTest.java index 59092657927..6cd93d93da0 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/scan/report/JsonReportTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/scan/report/JsonReportTest.java @@ -28,7 +28,9 @@ import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.skyscreamer.jsonassert.JSONAssert; import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.fs.InputPath; import org.sonar.api.batch.fs.internal.DefaultFileSystem; +import org.sonar.api.batch.fs.internal.DefaultInputDir; import org.sonar.api.batch.fs.internal.DeprecatedDefaultInputFile; import org.sonar.api.config.Settings; import org.sonar.api.issue.Issue; @@ -85,11 +87,13 @@ public class JsonReportTest { mode = mock(AnalysisMode.class); when(mode.isPreview()).thenReturn(true); userFinder = mock(UserFinder.class); + DefaultInputDir inputDir = new DefaultInputDir("src/main/java/org/apache/struts"); + inputDir.setKey("struts:src/main/java/org/apache/struts"); DeprecatedDefaultInputFile inputFile = new DeprecatedDefaultInputFile("src/main/java/org/apache/struts/Action.java"); inputFile.setKey("struts:src/main/java/org/apache/struts/Action.java"); inputFile.setStatus(InputFile.Status.CHANGED); InputPathCache fileCache = mock(InputPathCache.class); - when(fileCache.all()).thenReturn(Arrays.<InputFile>asList(inputFile)); + when(fileCache.all()).thenReturn(Arrays.<InputPath>asList(inputDir, inputFile)); Project rootModule = new Project("struts"); Project moduleA = new Project("struts-core"); moduleA.setParent(rootModule).setPath("core"); diff --git a/sonar-batch/src/test/resources/org/sonar/batch/scan/report/JsonReportTest/report-without-resolved-issues.json b/sonar-batch/src/test/resources/org/sonar/batch/scan/report/JsonReportTest/report-without-resolved-issues.json index 59c9c3272bb..d699073ee83 100644 --- a/sonar-batch/src/test/resources/org/sonar/batch/scan/report/JsonReportTest/report-without-resolved-issues.json +++ b/sonar-batch/src/test/resources/org/sonar/batch/scan/report/JsonReportTest/report-without-resolved-issues.json @@ -14,6 +14,10 @@ "path": "ui" }, { + "key": "struts:src/main/java/org/apache/struts", + "path": "src/main/java/org/apache/struts" + }, + { "key": "struts:src/main/java/org/apache/struts/Action.java", "path": "src/main/java/org/apache/struts/Action.java" } diff --git a/sonar-batch/src/test/resources/org/sonar/batch/scan/report/JsonReportTest/report.json b/sonar-batch/src/test/resources/org/sonar/batch/scan/report/JsonReportTest/report.json index 7ff8f67abc0..f5c32f1aabb 100644 --- a/sonar-batch/src/test/resources/org/sonar/batch/scan/report/JsonReportTest/report.json +++ b/sonar-batch/src/test/resources/org/sonar/batch/scan/report/JsonReportTest/report.json @@ -27,6 +27,11 @@ "path": "ui" }, { + "key": "struts:src/main/java/org/apache/struts", + "path": "src/main/java/org/apache/struts", + "moduleKey": "struts", + }, + { "key": "struts:src/main/java/org/apache/struts/Action.java", "path": "src/main/java/org/apache/struts/Action.java", "moduleKey": "struts", |