From 8a08d8d93634e061f928e2f03edbee5f7b5a377e Mon Sep 17 00:00:00 2001 From: Janos Gyerik Date: Tue, 31 Jan 2017 15:57:10 +0100 Subject: [PATCH] Add OneIssuePerDirectory rule in Xoo (#1606) --- .../main/java/org/sonar/xoo/XooPlugin.java | 2 + .../xoo/rule/OneIssuePerDirectorySensor.java | 67 +++++++++++++++++++ .../sonar/xoo/rule/XooRulesDefinition.java | 4 ++ .../mediumtest/fs/FileSystemMediumTest.java | 51 ++++++++++++++ 4 files changed, 124 insertions(+) create mode 100644 plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneIssuePerDirectorySensor.java diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java index 6c0dec7a8b9..83bc123e2e3 100644 --- a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java +++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java @@ -49,6 +49,7 @@ import org.sonar.xoo.rule.OneBlockerIssuePerFileSensor; import org.sonar.xoo.rule.OneBugIssuePerLineSensor; import org.sonar.xoo.rule.OneDayDebtPerFileSensor; import org.sonar.xoo.rule.OneIssueOnDirPerFileSensor; +import org.sonar.xoo.rule.OneIssuePerDirectorySensor; import org.sonar.xoo.rule.OneIssuePerFileSensor; import org.sonar.xoo.rule.OneIssuePerLineSensor; import org.sonar.xoo.rule.OneIssuePerModuleSensor; @@ -121,6 +122,7 @@ public class XooPlugin implements Plugin { OneIssuePerLineSensor.class, OneDayDebtPerFileSensor.class, OneIssuePerFileSensor.class, + OneIssuePerDirectorySensor.class, OneIssuePerModuleSensor.class, OneIssueOnDirPerFileSensor.class, OneIssuePerUnknownFileSensor.class, diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneIssuePerDirectorySensor.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneIssuePerDirectorySensor.java new file mode 100644 index 00000000000..8a3e35fdbeb --- /dev/null +++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneIssuePerDirectorySensor.java @@ -0,0 +1,67 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program 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. + * + * This program 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.xoo.rule; + +import java.util.Objects; +import java.util.stream.StreamSupport; +import org.sonar.api.batch.fs.FilePredicates; +import org.sonar.api.batch.fs.FileSystem; +import org.sonar.api.batch.fs.InputFile.Type; +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.issue.NewIssue; +import org.sonar.api.rule.RuleKey; + +public class OneIssuePerDirectorySensor implements Sensor { + + public static final String RULE_KEY = "OneIssuePerDirectory"; + + @Override + public void describe(SensorDescriptor descriptor) { + descriptor + .name("One Issue Per Directory") + .createIssuesForRuleRepositories(XooRulesDefinition.XOO_REPOSITORY); + } + + @Override + public void execute(SensorContext context) { + analyse(context); + } + + private static void analyse(SensorContext context) { + FileSystem fs = context.fileSystem(); + FilePredicates p = fs.predicates(); + RuleKey ruleKey = RuleKey.of(XooRulesDefinition.XOO_REPOSITORY, RULE_KEY); + StreamSupport.stream(fs.inputFiles(p.hasType(Type.MAIN)).spliterator(), false) + .map(file -> fs.inputDir(file.file().getParentFile())) + .filter(Objects::nonNull) + .distinct() + .forEach(inputDir -> { + NewIssue newIssue = context.newIssue(); + newIssue + .forRule(ruleKey) + .at(newIssue.newLocation() + .on(inputDir) + .message("This issue is generated for any non-empty directory")) + .save(); + }); + } +} diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/XooRulesDefinition.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/XooRulesDefinition.java index 23ecb196b2d..84f5f5a7a3a 100644 --- a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/XooRulesDefinition.java +++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/XooRulesDefinition.java @@ -91,6 +91,10 @@ public class XooRulesDefinition implements RulesDefinition { .setHtmlDescription("Generate an issue on each file"); oneIssuePerFile.setDebtRemediationFunction(oneIssuePerFile.debtRemediationFunctions().linear("10min")); + NewRule oneIssuePerDirectory = repo.createRule(OneIssuePerDirectorySensor.RULE_KEY).setName("One Issue Per Directory") + .setHtmlDescription("Generate an issue on each non-empty directory"); + oneIssuePerFile.setDebtRemediationFunction(oneIssuePerDirectory.debtRemediationFunctions().linear("10min")); + NewRule oneDayDebtPerFile = repo.createRule(OneDayDebtPerFileSensor.RULE_KEY).setName("One Day Debt Per File") .setHtmlDescription("Generate an issue on each file with a debt of one day"); oneDayDebtPerFile.setDebtRemediationFunction(oneDayDebtPerFile.debtRemediationFunctions().linear("1d")); diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/FileSystemMediumTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/FileSystemMediumTest.java index 1aaa9b7b02f..6e777488397 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/FileSystemMediumTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/FileSystemMediumTest.java @@ -20,6 +20,9 @@ package org.sonar.scanner.mediumtest.fs; import com.google.common.collect.ImmutableMap; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.junit.After; @@ -272,6 +275,54 @@ public class FileSystemMediumTest { tester2.stop(); } + @Test + public void publishDirsWithIssues() throws IOException { + ScannerMediumTester tester2 = ScannerMediumTester.builder() + .registerPlugin("xoo", new XooPlugin()) + .addDefaultQProfile("xoo", "Sonar Way") + .addRules(new XooRulesDefinition()) + .addActiveRule("xoo", "OneIssuePerDirectory", null, "OneIssuePerDirectory", "MAJOR", null, "xoo") + .build(); + tester2.start(); + + builder = ImmutableMap.builder() + .put("sonar.task", "scan") + .put("sonar.verbose", "true") + .put("sonar.projectBaseDir", baseDir.getAbsolutePath()) + .put("sonar.projectKey", "com.foo.project") + .put("sonar.projectVersion", "1.0-SNAPSHOT") + .put("sonar.projectDescription", "Description of Foo Project"); + + Path unknownRelative = Paths.get("src/unknown/file.unknown"); + Path unknown = baseDir.toPath().resolve(unknownRelative); + Files.createDirectories(unknown.getParent()); + Files.write(unknown, "dummy content".getBytes()); + + Path emptyDirRelative = Paths.get("src/emptydir"); + Files.createDirectories(emptyDirRelative); + + TaskResult result = tester2.newTask() + .properties(builder + .put("sonar.sources", "src") + .build()) + .start(); + + DefaultInputFile unknownInputFile = (DefaultInputFile) result.inputFile(unknownRelative.toString()); + InputDir unknownInputDir = result.inputDir(unknownRelative.getParent().toString()); + assertThat(unknownInputFile.publish()).isFalse(); + assertThat(result.getReportComponent(unknownInputDir.key())).isNotNull(); + + // no issues on empty dir + InputDir emptyInputDir = result.inputDir(emptyDirRelative.toString()); + assertThat(emptyInputDir).isNull(); + + // no issues on parent dir + InputDir parentInputDir = result.inputDir(unknownRelative.getParent().getParent().toString()); + assertThat(parentInputDir).isNull(); + + tester2.stop(); + } + @Test public void scanProjectWithSourceDir() throws IOException { File srcDir = new File(baseDir, "src"); -- 2.39.5