aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-batch
diff options
context:
space:
mode:
authorJulien HENRY <julien.henry@sonarsource.com>2014-07-22 12:23:11 +0200
committerJulien HENRY <julien.henry@sonarsource.com>2014-07-22 12:35:56 +0200
commite24f017a3d20d9320a4dee91596d33d4e27b32bf (patch)
treefcfa188545e886a9edf5462aaa36eb469bd6a78d /sonar-batch
parenta1defc3dd106409930d9323d7bc055f816c2bcd3 (diff)
downloadsonarqube-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')
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java7
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/SensorContextAdaptor.java17
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileIndexer.java31
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/InputPathCache.java15
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ModuleInputFileCache.java5
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan2/AnalysisPublisher.java10
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultSensorContext.java (renamed from sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultAnalyzerContext.java)55
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan2/ModuleScanContainer.java2
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/mediumtest/fs/FileSystemMediumTest.java2
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/IssuesMediumTest.java21
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/IssuesOnDirMediumTest.java91
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/XooPlugin.java4
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/rule/OneIssueOnDirPerFileSensor.java61
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/rule/OneIssuePerLineSensor.java7
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/InputPathCacheTest.java6
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/scan/report/JsonReportTest.java6
-rw-r--r--sonar-batch/src/test/resources/org/sonar/batch/scan/report/JsonReportTest/report-without-resolved-issues.json4
-rw-r--r--sonar-batch/src/test/resources/org/sonar/batch/scan/report/JsonReportTest/report.json5
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",