]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-15056 It should be possible to create external issues with project location
authorTobias Stadler <ts.stadler@gmx.de>
Sat, 25 Jul 2020 20:02:39 +0000 (22:02 +0200)
committersonartech <sonartech@sonarsource.com>
Fri, 18 Jun 2021 20:03:41 +0000 (20:03 +0000)
plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java
plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneExternalIssueOnProjectSensor.java [new file with mode: 0644]
sonar-plugin-api-impl/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultExternalIssue.java
sonar-plugin-api-impl/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultExternalIssueTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/issues/IssuesMediumTest.java

index e493d2864020e43fc85b2bff058668aec66524fc..0880d497f44e2834447be8514a2e9db2b4df70e9 100644 (file)
@@ -52,6 +52,7 @@ import org.sonar.xoo.rule.OneBugIssuePerTestLineSensor;
 import org.sonar.xoo.rule.OneCodeSmellIssuePerLineSensor;
 import org.sonar.xoo.rule.OneCodeSmellIssuePerTestLineSensor;
 import org.sonar.xoo.rule.OneDayDebtPerFileSensor;
+import org.sonar.xoo.rule.OneExternalIssueOnProjectSensor;
 import org.sonar.xoo.rule.OneExternalIssuePerLineSensor;
 import org.sonar.xoo.rule.OneIssueOnDirPerFileSensor;
 import org.sonar.xoo.rule.OneIssuePerDirectorySensor;
@@ -146,6 +147,7 @@ public class XooPlugin implements Plugin {
       OneIssuePerUnknownFileSensor.class,
 
       OneExternalIssuePerLineSensor.class,
+      OneExternalIssueOnProjectSensor.class,
       OnePredefinedRuleExternalIssuePerLineSensor.class,
       OnePredefinedAndAdHocRuleExternalIssuePerLineSensor.class,
 
diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneExternalIssueOnProjectSensor.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneExternalIssueOnProjectSensor.java
new file mode 100644 (file)
index 0000000..047b906
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 SonarSource SA
+ * mailto:info 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 org.sonar.api.batch.rule.Severity;
+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.NewExternalIssue;
+import org.sonar.api.rules.RuleType;
+import org.sonar.xoo.Xoo;
+
+public class OneExternalIssueOnProjectSensor implements Sensor {
+  public static final String ENGINE_ID = "XooEngine";
+  public static final String SEVERITY = "MAJOR";
+  public static final RuleType TYPE = RuleType.BUG;
+  public static final String ACTIVATE = "sonar.oneExternalIssueOnProject.activate";
+  public static final String RULE_ID = "OneExternalIssueOnProject";
+
+  @Override
+  public void describe(SensorDescriptor descriptor) {
+    descriptor
+      .name("One External Issue At Project Level")
+      .onlyOnLanguages(Xoo.KEY)
+      .onlyWhenConfiguration(c -> c.getBoolean(ACTIVATE).orElse(false));
+  }
+
+  @Override
+  public void execute(SensorContext context) {
+    analyse(context);
+  }
+
+  private static void analyse(SensorContext context) {
+    NewExternalIssue newIssue = context.newExternalIssue();
+    newIssue
+      .engineId(ENGINE_ID)
+      .ruleId(RULE_ID)
+      .at(newIssue.newLocation()
+        .on(context.project())
+        .message("This issue is generated at project level"))
+      .severity(Severity.valueOf(SEVERITY))
+      .type(TYPE)
+      .save();
+  }
+}
index eca02788543e6cb4c3b8ccc554840c179cda1637..93c298d76ea787ea59a664297f9a7c4eea9b97bc 100644 (file)
 package org.sonar.api.batch.sensor.issue.internal;
 
 import javax.annotation.Nullable;
+import org.sonar.api.batch.fs.internal.DefaultInputProject;
 import org.sonar.api.batch.rule.Severity;
 import org.sonar.api.batch.sensor.internal.SensorStorage;
 import org.sonar.api.batch.sensor.issue.ExternalIssue;
 import org.sonar.api.batch.sensor.issue.NewExternalIssue;
-import org.sonar.api.batch.fs.internal.DefaultInputProject;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rules.RuleType;
 
@@ -86,7 +86,6 @@ public class DefaultExternalIssue extends AbstractDefaultIssue<DefaultExternalIs
     requireNonNull(this.engineId, "Engine id is mandatory on external issue");
     requireNonNull(this.ruleId, "Rule id is mandatory on external issue");
     checkState(primaryLocation != null, "Primary location is mandatory on every external issue");
-    checkState(primaryLocation.inputComponent().isFile(), "External issues must be located in files");
     checkState(primaryLocation.message() != null, "External issues must have a message");
     checkState(severity != null, "Severity is mandatory on every external issue");
     checkState(type != null, "Type is mandatory on every external issue");
index b59b0d1d9ab20cafc0c22936c4ad54e1574b32ca..9659c371e229d5b84e3566818ed33f77b12c6303 100644 (file)
@@ -26,16 +26,13 @@ import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.junit.rules.TemporaryFolder;
 import org.sonar.api.batch.bootstrap.ProjectDefinition;
-import org.sonar.api.batch.fs.InputComponent;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.fs.internal.DefaultInputProject;
+import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
 import org.sonar.api.batch.rule.Severity;
 import org.sonar.api.batch.sensor.internal.SensorStorage;
-import org.sonar.api.batch.sensor.issue.internal.DefaultExternalIssue;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rules.RuleType;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.fs.internal.DefaultInputProject;
-import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
-import org.sonar.api.batch.sensor.issue.internal.DefaultIssueLocation;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
@@ -92,35 +89,46 @@ public class DefaultExternalIssueTest {
   }
 
   @Test
-  public void fail_to_store_if_no_type() {
+  public void build_project_issue() {
     SensorStorage storage = mock(SensorStorage.class);
     DefaultExternalIssue issue = new DefaultExternalIssue(project, storage)
       .at(new DefaultIssueLocation()
-        .on(inputFile)
-        .at(inputFile.selectLine(1))
+        .on(project)
         .message("Wrong way!"))
       .forRule(RuleKey.of("repo", "rule"))
       .remediationEffortMinutes(10l)
+      .type(RuleType.BUG)
       .severity(Severity.BLOCKER);
 
-    exception.expect(IllegalStateException.class);
-    exception.expectMessage("Type is mandatory");
+    assertThat(issue.primaryLocation().inputComponent()).isEqualTo(project);
+    assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("external_repo", "rule"));
+    assertThat(issue.engineId()).isEqualTo("repo");
+    assertThat(issue.ruleId()).isEqualTo("rule");
+    assertThat(issue.primaryLocation().textRange()).isNull();
+    assertThat(issue.remediationEffort()).isEqualTo(10l);
+    assertThat(issue.type()).isEqualTo(RuleType.BUG);
+    assertThat(issue.severity()).isEqualTo(Severity.BLOCKER);
+    assertThat(issue.primaryLocation().message()).isEqualTo("Wrong way!");
+
     issue.save();
+
+    verify(storage).store(issue);
   }
 
   @Test
-  public void fail_to_store_if_primary_location_is_not_a_file() {
+  public void fail_to_store_if_no_type() {
     SensorStorage storage = mock(SensorStorage.class);
     DefaultExternalIssue issue = new DefaultExternalIssue(project, storage)
       .at(new DefaultIssueLocation()
-        .on(mock(InputComponent.class))
+        .on(inputFile)
+        .at(inputFile.selectLine(1))
         .message("Wrong way!"))
       .forRule(RuleKey.of("repo", "rule"))
       .remediationEffortMinutes(10l)
       .severity(Severity.BLOCKER);
 
     exception.expect(IllegalStateException.class);
-    exception.expectMessage("External issues must be located in files");
+    exception.expectMessage("Type is mandatory");
     issue.save();
   }
 
index 5a584bd275d00600aac0915c1ee221e503dd4caa..176db54d632aca16a3360ae156136eec04c41522 100644 (file)
@@ -38,6 +38,7 @@ import org.sonar.scanner.protocol.output.ScannerReport.ExternalIssue;
 import org.sonar.scanner.protocol.output.ScannerReport.Issue;
 import org.sonar.xoo.XooPlugin;
 import org.sonar.xoo.rule.HasTagSensor;
+import org.sonar.xoo.rule.OneExternalIssueOnProjectSensor;
 import org.sonar.xoo.rule.OneExternalIssuePerLineSensor;
 import org.sonar.xoo.rule.XooRulesDefinition;
 
@@ -92,6 +93,21 @@ public class IssuesMediumTest {
     assertThat(externalIssues).hasSize(8 /* lines */);
   }
 
+  @Test
+  public void testOneExternalIssueOnProject() throws Exception {
+    File projectDir = new File("test-resources/mediumtest/xoo/sample");
+    File tmpDir = temp.newFolder();
+    FileUtils.copyDirectory(projectDir, tmpDir);
+
+    AnalysisResult result = tester
+      .newAnalysis(new File(tmpDir, "sonar-project.properties"))
+      .property(OneExternalIssueOnProjectSensor.ACTIVATE, "true")
+      .execute();
+
+    List<ExternalIssue> externalIssues = result.externalIssuesFor(result.project());
+    assertThat(externalIssues).hasSize(1);
+  }
+
   @Test
   public void findActiveRuleByInternalKey() throws Exception {
     File projectDir = new File("test-resources/mediumtest/xoo/sample");