aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulien HENRY <julien.henry@sonarsource.com>2018-09-04 16:08:53 +0200
committerSonarTech <sonartech@sonarsource.com>2018-09-24 20:20:58 +0200
commitcfba7fcb6500d8217bd81ecfcb8f47ec48ad55f2 (patch)
tree81398a80d0269b523e630495a580daf8ac144228
parent326b30334f0f5c0bb6a9565a3f6b367695bb1087 (diff)
downloadsonarqube-cfba7fcb6500d8217bd81ecfcb8f47ec48ad55f2.tar.gz
sonarqube-cfba7fcb6500d8217bd81ecfcb8f47ec48ad55f2.zip
SONAR-11209 Allow sensors to provide ad hoc rule metadata for external issues
-rw-r--r--plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java4
-rw-r--r--plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneExternalIssuePerLineSensor.java39
-rw-r--r--plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OnePredefinedRuleExternalIssuePerLineSensor.java (renamed from plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneExternalIssueWithDetailsPerLineSensor.java)33
-rw-r--r--plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/XooRulesDefinition.java9
-rw-r--r--plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/rule/XooRulesDefinitionTest.java5
-rw-r--r--server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/RuleRepository.java6
-rw-r--r--server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/RuleRepositoryImpl.java38
-rw-r--r--server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/TrackerRawInputFactory.java39
-rw-r--r--server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PersistExternalRulesStep.java2
-rw-r--r--server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/RuleRepositoryImplTest.java16
-rw-r--r--server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/RuleRepositoryRule.java8
-rw-r--r--server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/TrackerRawInputFactoryTest.java8
-rw-r--r--server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PersistExternalRulesStepTest.java12
-rw-r--r--server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PersistIssuesStepTest.java6
-rw-r--r--server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java4
-rw-r--r--server/sonar-server-common/src/main/java/org/sonar/server/rule/AddHocRuleCreator.java (renamed from server/sonar-server-common/src/main/java/org/sonar/server/rule/ExternalRuleCreator.java)17
-rw-r--r--server/sonar-server-common/src/main/java/org/sonar/server/rule/NewAddHocRule.java (renamed from server/sonar-server-common/src/main/java/org/sonar/server/rule/NewExternalRule.java)8
-rw-r--r--server/sonar-server-common/src/test/java/org/sonar/server/rule/AddHocRuleCreatorTest.java (renamed from server/sonar-server-common/src/test/java/org/sonar/server/rule/ExternalRuleCreatorTest.java)6
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/rule/NewAddHocRuleTest.java (renamed from server/sonar-server/src/test/java/org/sonar/server/rule/NewExternalRuleTest.java)8
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorContext.java9
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/InMemorySensorStorage.java11
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java12
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorStorage.java7
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/ExternalIssue.java10
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/NewExternalIssue.java14
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/AbstractDefaultIssue.java13
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultExternalIssue.java43
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssue.java12
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueLocation.java6
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/rule/AdHocRule.java62
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/rule/NewAdHocRule.java70
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/rule/internal/DefaultAdHocRule.java126
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/rule/internal/package-info.java21
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/rule/package-info.java21
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/rule/RuleKey.java12
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/server/rule/RulesDefinition.java8
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultExternalIssueTest.java4
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/rule/internal/DefaultAdHocRuleTest.java148
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/ExternalIssueImporter.java4
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ModuleIssues.java4
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/mediumtest/TaskResult.java12
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorContext.java11
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorStorage.java19
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/noop/NoOpNewAdHocRule.java69
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/noop/NoOpNewExternalIssue.java12
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/issues/ExternalIssuesMediumTest.java46
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/issues/IssuesMediumTest.java2
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/sensor/DefaultSensorContextTest.java2
-rw-r--r--sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/FileStructure.java4
-rw-r--r--sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/ScannerReportReader.java8
-rw-r--r--sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/ScannerReportWriter.java9
-rw-r--r--sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/viewer/ScannerReportViewerApp.java43
-rw-r--r--sonar-scanner-protocol/src/main/protobuf/scanner_report.proto16
53 files changed, 944 insertions, 194 deletions
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 50907147b20..cc66f2d9c1d 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,7 +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.OneExternalIssuePerLineSensor;
-import org.sonar.xoo.rule.OneExternalIssueWithDetailsPerLineSensor;
+import org.sonar.xoo.rule.OnePredefinedRuleExternalIssuePerLineSensor;
import org.sonar.xoo.rule.OneIssueOnDirPerFileSensor;
import org.sonar.xoo.rule.OneIssuePerDirectorySensor;
import org.sonar.xoo.rule.OneIssuePerFileSensor;
@@ -168,7 +168,7 @@ public class XooPlugin implements Plugin {
if (context.getSonarQubeVersion().isGreaterThanOrEqual(Version.create(7, 2))) {
context.addExtensions(
OneExternalIssuePerLineSensor.class,
- OneExternalIssueWithDetailsPerLineSensor.class,
+ OnePredefinedRuleExternalIssuePerLineSensor.class,
SignificantCodeSensor.class);
}
if (context.getSonarQubeVersion().isGreaterThanOrEqual(Version.create(7, 3))) {
diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneExternalIssuePerLineSensor.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneExternalIssuePerLineSensor.java
index c8d09704371..c75a8c7a169 100644
--- a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneExternalIssuePerLineSensor.java
+++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneExternalIssuePerLineSensor.java
@@ -22,54 +22,57 @@ package org.sonar.xoo.rule;
import org.sonar.api.batch.fs.FilePredicates;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.InputFile.Type;
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.rule.RuleKey;
import org.sonar.api.rules.RuleType;
import org.sonar.xoo.Xoo;
-import org.sonar.xoo.Xoo2;
public class OneExternalIssuePerLineSensor implements Sensor {
- public static final String RULE_KEY = "OneExternalIssuePerLine";
- public static final String ENGINE_KEY = "XooEngine";
+ public static final String RULE_ID = "OneExternalIssuePerLine";
+ public static final String ENGINE_ID = "XooEngine";
public static final String SEVERITY = "MAJOR";
public static final Long EFFORT = 10l;
public static final RuleType TYPE = RuleType.BUG;
- public static final String ACTIVATE_EXTERNAL_ISSUES = "sonar.oneExternalIssuePerLine.activate";
+ public static final String ACTIVATE = "sonar.oneExternalIssuePerLine.activate";
+ public static final String REGISTER_AD_HOC_RULE = "sonar.oneExternalIssuePerLine.adhocRule";
private static final String NAME = "One External Issue Per Line";
@Override
public void describe(SensorDescriptor descriptor) {
descriptor
.name(NAME)
- .onlyOnLanguages(Xoo.KEY, Xoo2.KEY)
- .onlyWhenConfiguration(c -> c.getBoolean(ACTIVATE_EXTERNAL_ISSUES).orElse(false));
+ .onlyOnLanguages(Xoo.KEY)
+ .onlyWhenConfiguration(c -> c.getBoolean(ACTIVATE).orElse(false));
}
@Override
public void execute(SensorContext context) {
- analyse(context, Xoo.KEY, XooRulesDefinition.XOO_REPOSITORY);
- analyse(context, Xoo2.KEY, XooRulesDefinition.XOO2_REPOSITORY);
- }
-
- private void analyse(SensorContext context, String language, String repo) {
FileSystem fs = context.fileSystem();
FilePredicates p = fs.predicates();
- for (InputFile file : fs.inputFiles(p.and(p.hasLanguages(language), p.hasType(Type.MAIN)))) {
- createIssues(file, context, repo);
+ for (InputFile file : fs.inputFiles(p.and(p.hasLanguages(Xoo.KEY), p.hasType(InputFile.Type.MAIN)))) {
+ createIssues(file, context);
+ }
+ if (context.config().getBoolean(REGISTER_AD_HOC_RULE).orElse(false)) {
+ context.newAdHocRule()
+ .engineId(ENGINE_ID)
+ .ruleId(RULE_ID)
+ .name("An ad hoc rule")
+ .description("blah blah")
+ .severity(Severity.BLOCKER)
+ .type(RuleType.BUG)
+ .save();
}
}
- private void createIssues(InputFile file, SensorContext context, String repo) {
- RuleKey ruleKey = RuleKey.of(repo, RULE_KEY);
+ private static void createIssues(InputFile file, SensorContext context) {
for (int line = 1; line <= file.lines(); line++) {
NewExternalIssue newIssue = context.newExternalIssue();
newIssue
- .forRule(ruleKey)
+ .engineId(ENGINE_ID)
+ .ruleId(RULE_ID)
.at(newIssue.newLocation()
.on(file)
.at(file.selectLine(line))
diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneExternalIssueWithDetailsPerLineSensor.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OnePredefinedRuleExternalIssuePerLineSensor.java
index 0598b7a8d40..779674808cc 100644
--- a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneExternalIssueWithDetailsPerLineSensor.java
+++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OnePredefinedRuleExternalIssuePerLineSensor.java
@@ -28,52 +28,45 @@ 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.rule.RuleKey;
import org.sonar.api.rules.RuleType;
import org.sonar.xoo.Xoo;
-import org.sonar.xoo.Xoo2;
-public class OneExternalIssueWithDetailsPerLineSensor implements Sensor {
- public static final String RULE_KEY = "OneExternalIssueWithDetailsPerLine";
- public static final String ENGINE_KEY = "XooEngine";
+public class OnePredefinedRuleExternalIssuePerLineSensor implements Sensor {
+ public static final String RULE_ID = "OnePredefinedRuleExternalIssuePerLine";
+ public static final String ENGINE_ID = "XooEngine";
public static final String SEVERITY = "MAJOR";
public static final Long EFFORT = 10l;
public static final RuleType TYPE = RuleType.BUG;
- public static final String ACTIVATE_EXTERNAL_ISSUES = "sonar.oneExternalIssueWithDetailsPerLine.activate";
- private static final String NAME = "One External Issue Per Line";
+ public static final String ACTIVATE = "sonar.onePredefinedRuleExternalIssuePerLine.activate";
+ private static final String NAME = "One External Issue Per Line With A Predefined Rule";
@Override
public void describe(SensorDescriptor descriptor) {
descriptor
.name(NAME)
- .onlyOnLanguages(Xoo.KEY, Xoo2.KEY)
- .onlyWhenConfiguration(c -> c.getBoolean(ACTIVATE_EXTERNAL_ISSUES).orElse(false));
+ .onlyOnLanguages(Xoo.KEY)
+ .onlyWhenConfiguration(c -> c.getBoolean(ACTIVATE).orElse(false));
}
@Override
public void execute(SensorContext context) {
- analyse(context, Xoo.KEY, XooRulesDefinition.XOO_REPOSITORY);
- analyse(context, Xoo2.KEY, XooRulesDefinition.XOO2_REPOSITORY);
- }
-
- private void analyse(SensorContext context, String language, String repo) {
FileSystem fs = context.fileSystem();
FilePredicates p = fs.predicates();
- for (InputFile file : fs.inputFiles(p.and(p.hasLanguages(language), p.hasType(Type.MAIN)))) {
- createIssues(file, context, repo);
+ for (InputFile file : fs.inputFiles(p.and(p.hasLanguages(Xoo.KEY), p.hasType(Type.MAIN)))) {
+ createIssues(file, context);
}
}
- private void createIssues(InputFile file, SensorContext context, String repo) {
- RuleKey ruleKey = RuleKey.of(repo, RULE_KEY);
+ private static void createIssues(InputFile file, SensorContext context) {
for (int line = 1; line <= file.lines(); line++) {
NewExternalIssue newIssue = context.newExternalIssue();
newIssue
- .forRule(ruleKey)
+ .engineId(ENGINE_ID)
+ .ruleId(RULE_ID)
.at(newIssue.newLocation()
.on(file)
.at(file.selectLine(line))
- .message("This issue is generated on each line and the rule contains details"))
+ .message("This issue is generated on each line and the rule is predefined"))
.severity(Severity.valueOf(SEVERITY))
.remediationEffortMinutes(EFFORT)
.type(TYPE)
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 8991b04bc28..aee1ba3c3fa 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
@@ -38,7 +38,6 @@ public class XooRulesDefinition implements RulesDefinition {
public static final String XOO_REPOSITORY = "xoo";
public static final String XOO2_REPOSITORY = "xoo2";
- public static final String XOO_EXTERNAL_REPOSITORY = "xoo";
private static final String TEN_MIN = "10min";
@@ -183,11 +182,11 @@ public class XooRulesDefinition implements RulesDefinition {
}
private static void defineRulesXooExternal(Context context) {
- NewRepository repo = context.createExternalRepository(XOO_EXTERNAL_REPOSITORY, Xoo.KEY).setName("XooExternal");
+ NewRepository repo = context.createExternalRepository(OneExternalIssuePerLineSensor.ENGINE_ID, Xoo.KEY).setName(OneExternalIssuePerLineSensor.ENGINE_ID);
- repo.createRule(OneExternalIssueWithDetailsPerLineSensor.RULE_KEY)
- .setSeverity(OneExternalIssueWithDetailsPerLineSensor.SEVERITY)
- .setType(OneExternalIssueWithDetailsPerLineSensor.TYPE)
+ repo.createRule(OnePredefinedRuleExternalIssuePerLineSensor.RULE_ID)
+ .setSeverity(OnePredefinedRuleExternalIssuePerLineSensor.SEVERITY)
+ .setType(OnePredefinedRuleExternalIssuePerLineSensor.TYPE)
.setScope(RuleScope.ALL)
.setHtmlDescription("Generates one external issue in each line")
.setName("One external issue per line");
diff --git a/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/rule/XooRulesDefinitionTest.java b/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/rule/XooRulesDefinitionTest.java
index 0ded44031fc..d5df1600b56 100644
--- a/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/rule/XooRulesDefinitionTest.java
+++ b/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/rule/XooRulesDefinitionTest.java
@@ -21,7 +21,6 @@ package org.sonar.xoo.rule;
import org.junit.Before;
import org.junit.Test;
-import org.sonar.api.SonarProduct;
import org.sonar.api.SonarQubeSide;
import org.sonar.api.internal.SonarRuntimeImpl;
import org.sonar.api.server.debt.DebtRemediationFunction;
@@ -73,9 +72,9 @@ public class XooRulesDefinitionTest {
@Test
public void define_xooExternal_rules() {
- RulesDefinition.Repository repo = context.repository("external_xoo");
+ RulesDefinition.Repository repo = context.repository("external_XooEngine");
assertThat(repo).isNotNull();
- assertThat(repo.name()).isEqualTo("XooExternal");
+ assertThat(repo.name()).isEqualTo("XooEngine");
assertThat(repo.language()).isEqualTo("xoo");
assertThat(repo.rules()).hasSize(1);
}
diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/RuleRepository.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/RuleRepository.java
index 123dc51d93c..a780920f733 100644
--- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/RuleRepository.java
+++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/RuleRepository.java
@@ -23,7 +23,7 @@ import java.util.Optional;
import java.util.function.Supplier;
import org.sonar.api.rule.RuleKey;
import org.sonar.db.DbSession;
-import org.sonar.server.rule.NewExternalRule;
+import org.sonar.server.rule.NewAddHocRule;
/**
* Repository of every rule in DB (including manual rules) whichever their status.
@@ -48,8 +48,8 @@ public interface RuleRepository {
Optional<Rule> findById(int id);
- void insertNewExternalRuleIfAbsent(RuleKey ruleKey, Supplier<NewExternalRule> ruleSupplier);
+ void addNewAddHocRuleIfAbsent(RuleKey ruleKey, Supplier<NewAddHocRule> ruleSupplier);
- void persistNewExternalRules(DbSession dbSession);
+ void persistNewAddHocRules(DbSession dbSession);
}
diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/RuleRepositoryImpl.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/RuleRepositoryImpl.java
index 65be96fdfa7..7a99e846c1c 100644
--- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/RuleRepositoryImpl.java
+++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/RuleRepositoryImpl.java
@@ -37,8 +37,8 @@ import org.sonar.db.DbSession;
import org.sonar.db.rule.DeprecatedRuleKeyDto;
import org.sonar.db.rule.RuleDto;
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
-import org.sonar.server.rule.ExternalRuleCreator;
-import org.sonar.server.rule.NewExternalRule;
+import org.sonar.server.rule.AddHocRuleCreator;
+import org.sonar.server.rule.NewAddHocRule;
import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;
@@ -50,34 +50,34 @@ public class RuleRepositoryImpl implements RuleRepository {
@CheckForNull
private Map<Integer, Rule> rulesById;
- private final ExternalRuleCreator creator;
+ private final AddHocRuleCreator creator;
private final DbClient dbClient;
private final AnalysisMetadataHolder analysisMetadataHolder;
- public RuleRepositoryImpl(ExternalRuleCreator creator, DbClient dbClient, AnalysisMetadataHolder analysisMetadataHolder) {
+ public RuleRepositoryImpl(AddHocRuleCreator creator, DbClient dbClient, AnalysisMetadataHolder analysisMetadataHolder) {
this.creator = creator;
this.dbClient = dbClient;
this.analysisMetadataHolder = analysisMetadataHolder;
}
- public void insertNewExternalRuleIfAbsent(RuleKey ruleKey, Supplier<NewExternalRule> ruleSupplier) {
+ public void addNewAddHocRuleIfAbsent(RuleKey ruleKey, Supplier<NewAddHocRule> ruleSupplier) {
ensureInitialized();
if (!rulesByKey.containsKey(ruleKey)) {
- rulesByKey.computeIfAbsent(ruleKey, s -> new ExternalRuleWrapper(ruleSupplier.get()));
+ rulesByKey.computeIfAbsent(ruleKey, s -> new AdHocRuleWrapper(ruleSupplier.get()));
}
}
@Override
- public void persistNewExternalRules(DbSession dbSession) {
+ public void persistNewAddHocRules(DbSession dbSession) {
ensureInitialized();
rulesByKey.values().stream()
- .filter(ExternalRuleWrapper.class::isInstance)
- .forEach(extRule -> persistAndIndex(dbSession, (ExternalRuleWrapper) extRule));
+ .filter(AdHocRuleWrapper.class::isInstance)
+ .forEach(r -> persistAndIndex(dbSession, (AdHocRuleWrapper) r));
}
- private void persistAndIndex(DbSession dbSession, ExternalRuleWrapper external) {
+ private void persistAndIndex(DbSession dbSession, AdHocRuleWrapper external) {
Rule rule = new RuleImpl(creator.persistAndIndex(dbSession, external.getDelegate()));
rulesById.put(rule.getId(), rule);
rulesByKey.put(external.getKey(), rule);
@@ -145,15 +145,15 @@ public class RuleRepositoryImpl implements RuleRepository {
}
}
- private static class ExternalRuleWrapper implements Rule {
- private final NewExternalRule externalRule;
+ private static class AdHocRuleWrapper implements Rule {
+ private final NewAddHocRule addHocRule;
- private ExternalRuleWrapper(NewExternalRule externalRule) {
- this.externalRule = externalRule;
+ private AdHocRuleWrapper(NewAddHocRule addHocRule) {
+ this.addHocRule = addHocRule;
}
- public NewExternalRule getDelegate() {
- return externalRule;
+ public NewAddHocRule getDelegate() {
+ return addHocRule;
}
@Override
@@ -163,12 +163,12 @@ public class RuleRepositoryImpl implements RuleRepository {
@Override
public RuleKey getKey() {
- return externalRule.getKey();
+ return addHocRule.getKey();
}
@Override
public String getName() {
- return externalRule.getName();
+ return addHocRule.getName();
}
@Override
@@ -201,7 +201,7 @@ public class RuleRepositoryImpl implements RuleRepository {
@CheckForNull
@Override
public String getPluginKey() {
- return externalRule.getPluginKey();
+ return addHocRule.getPluginKey();
}
}
}
diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/TrackerRawInputFactory.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/TrackerRawInputFactory.java
index 58801ef4de6..767627d6a79 100644
--- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/TrackerRawInputFactory.java
+++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/TrackerRawInputFactory.java
@@ -40,14 +40,13 @@ import org.sonar.scanner.protocol.Constants.Severity;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReport.IssueType;
import org.sonar.ce.task.projectanalysis.batch.BatchReportReader;
-import org.sonar.ce.task.projectanalysis.component.Component;
import org.sonar.ce.task.projectanalysis.component.TreeRootHolder;
import org.sonar.ce.task.projectanalysis.issue.commonrule.CommonRuleEngine;
import org.sonar.ce.task.projectanalysis.issue.filter.IssueFilter;
import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRulesHolder;
import org.sonar.ce.task.projectanalysis.source.SourceLinesHashRepository;
import org.sonar.server.rule.CommonRuleKeys;
-import org.sonar.server.rule.NewExternalRule;
+import org.sonar.server.rule.NewAddHocRule;
import static org.apache.commons.lang.StringUtils.isNotEmpty;
@@ -182,30 +181,30 @@ public class TrackerRawInputFactory {
return issue;
}
- private DefaultIssue toExternalIssue(LineHashSequence lineHashSeq, ScannerReport.ExternalIssue reportIssue) {
+ private DefaultIssue toExternalIssue(LineHashSequence lineHashSeq, ScannerReport.ExternalIssue reportExternalIssue) {
DefaultIssue issue = new DefaultIssue();
init(issue);
- issue.setRuleKey(RuleKey.of(RuleKey.EXTERNAL_RULE_REPO_PREFIX + reportIssue.getRuleRepository(), reportIssue.getRuleKey()));
- if (reportIssue.hasTextRange()) {
- int startLine = reportIssue.getTextRange().getStartLine();
+ issue.setRuleKey(RuleKey.of(RuleKey.EXTERNAL_RULE_REPO_PREFIX + reportExternalIssue.getEngineId(), reportExternalIssue.getRuleId()));
+ if (reportExternalIssue.hasTextRange()) {
+ int startLine = reportExternalIssue.getTextRange().getStartLine();
issue.setLine(startLine);
issue.setChecksum(lineHashSeq.getHashForLine(startLine));
} else {
issue.setChecksum("");
}
- if (isNotEmpty(reportIssue.getMsg())) {
- issue.setMessage(reportIssue.getMsg());
+ if (isNotEmpty(reportExternalIssue.getMsg())) {
+ issue.setMessage(reportExternalIssue.getMsg());
}
- if (reportIssue.getSeverity() != Severity.UNSET_SEVERITY) {
- issue.setSeverity(reportIssue.getSeverity().name());
+ if (reportExternalIssue.getSeverity() != Severity.UNSET_SEVERITY) {
+ issue.setSeverity(reportExternalIssue.getSeverity().name());
}
- issue.setEffort(Duration.create(reportIssue.getEffort() != 0 ? reportIssue.getEffort() : DEFAULT_EXTERNAL_ISSUE_EFFORT));
+ issue.setEffort(Duration.create(reportExternalIssue.getEffort() != 0 ? reportExternalIssue.getEffort() : DEFAULT_EXTERNAL_ISSUE_EFFORT));
DbIssues.Locations.Builder dbLocationsBuilder = DbIssues.Locations.newBuilder();
- if (reportIssue.hasTextRange()) {
- dbLocationsBuilder.setTextRange(convertTextRange(reportIssue.getTextRange()));
+ if (reportExternalIssue.hasTextRange()) {
+ dbLocationsBuilder.setTextRange(convertTextRange(reportExternalIssue.getTextRange()));
}
- for (ScannerReport.Flow flow : reportIssue.getFlowList()) {
+ for (ScannerReport.Flow flow : reportExternalIssue.getFlowList()) {
if (flow.getLocationCount() > 0) {
DbIssues.Flow.Builder dbFlowBuilder = DbIssues.Flow.newBuilder();
for (ScannerReport.IssueLocation location : flow.getLocationList()) {
@@ -216,16 +215,16 @@ public class TrackerRawInputFactory {
}
issue.setIsFromExternalRuleEngine(true);
issue.setLocations(dbLocationsBuilder.build());
- issue.setType(toRuleType(reportIssue.getType()));
+ issue.setType(toRuleType(reportExternalIssue.getType()));
- ruleRepository.insertNewExternalRuleIfAbsent(issue.getRuleKey(), () -> toExternalRule(reportIssue));
+ ruleRepository.addNewAddHocRuleIfAbsent(issue.getRuleKey(), () -> toAdHocRule(reportExternalIssue));
return issue;
}
- private NewExternalRule toExternalRule(ScannerReport.ExternalIssue reportIssue) {
- NewExternalRule.Builder builder = new NewExternalRule.Builder()
- .setName(RuleKey.of(reportIssue.getRuleRepository(), reportIssue.getRuleKey()).toString())
- .setKey(RuleKey.of(RuleKey.EXTERNAL_RULE_REPO_PREFIX + reportIssue.getRuleRepository(), reportIssue.getRuleKey()));
+ private NewAddHocRule toAdHocRule(ScannerReport.ExternalIssue reportIssue) {
+ NewAddHocRule.Builder builder = new NewAddHocRule.Builder()
+ .setName(reportIssue.getEngineId() + " " + reportIssue.getRuleId())
+ .setKey(RuleKey.of(RuleKey.EXTERNAL_RULE_REPO_PREFIX + reportIssue.getEngineId(), reportIssue.getRuleId()));
return builder.build();
}
diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PersistExternalRulesStep.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PersistExternalRulesStep.java
index 67baee66f5c..28c871d75fa 100644
--- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PersistExternalRulesStep.java
+++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PersistExternalRulesStep.java
@@ -37,7 +37,7 @@ public class PersistExternalRulesStep implements ComputationStep {
@Override
public void execute(ComputationStep.Context context) {
try (DbSession dbSession = dbClient.openSession(false)) {
- ruleRepository.persistNewExternalRules(dbSession);
+ ruleRepository.persistNewAddHocRules(dbSession);
}
}
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/RuleRepositoryImplTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/RuleRepositoryImplTest.java
index 623c082f094..c359b6919d1 100644
--- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/RuleRepositoryImplTest.java
+++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/RuleRepositoryImplTest.java
@@ -37,8 +37,8 @@ import org.sonar.db.rule.DeprecatedRuleKeyDto;
import org.sonar.db.rule.RuleDao;
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.db.rule.RuleDto;
-import org.sonar.server.rule.ExternalRuleCreator;
-import org.sonar.server.rule.NewExternalRule;
+import org.sonar.server.rule.AddHocRuleCreator;
+import org.sonar.server.rule.NewAddHocRule;
import org.sonar.server.rule.index.RuleIndexer;
import static org.assertj.core.api.Assertions.assertThat;
@@ -78,8 +78,8 @@ public class RuleRepositoryImplTest {
private RuleDao ruleDao = mock(RuleDao.class);
private RuleIndexer ruleIndexer = mock(RuleIndexer.class);
- private ExternalRuleCreator externalRuleCreator = new ExternalRuleCreator(db.getDbClient(), System2.INSTANCE, ruleIndexer);
- private RuleRepositoryImpl underTest = new RuleRepositoryImpl(externalRuleCreator, dbClient, analysisMetadataHolder);
+ private AddHocRuleCreator addHocRuleCreator = new AddHocRuleCreator(db.getDbClient(), System2.INSTANCE, ruleIndexer);
+ private RuleRepositoryImpl underTest = new RuleRepositoryImpl(addHocRuleCreator, dbClient, analysisMetadataHolder);
@Before
public void setUp() throws Exception {
@@ -270,7 +270,7 @@ public class RuleRepositoryImplTest {
public void accept_new_externally_defined_Rules() {
RuleKey ruleKey = RuleKey.of("eslint", "no-cond-assign");
- underTest.insertNewExternalRuleIfAbsent(ruleKey, () -> new NewExternalRule.Builder()
+ underTest.addNewAddHocRuleIfAbsent(ruleKey, () -> new NewAddHocRule.Builder()
.setKey(ruleKey)
.setPluginKey("eslint")
.build());
@@ -286,15 +286,15 @@ public class RuleRepositoryImplTest {
@Test
public void persist_new_externally_defined_Rules() {
- underTest = new RuleRepositoryImpl(externalRuleCreator, db.getDbClient(), analysisMetadataHolder);
+ underTest = new RuleRepositoryImpl(addHocRuleCreator, db.getDbClient(), analysisMetadataHolder);
RuleKey ruleKey = RuleKey.of("eslint", "no-cond-assign");
- underTest.insertNewExternalRuleIfAbsent(ruleKey, () -> new NewExternalRule.Builder()
+ underTest.addNewAddHocRuleIfAbsent(ruleKey, () -> new NewAddHocRule.Builder()
.setKey(ruleKey)
.setPluginKey("eslint")
.build());
- underTest.persistNewExternalRules(db.getSession());
+ underTest.persistNewAddHocRules(db.getSession());
db.commit();
Optional<RuleDefinitionDto> ruleDefinitionDto = db.getDbClient().ruleDao().selectDefinitionByKey(db.getSession(), ruleKey);
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/RuleRepositoryRule.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/RuleRepositoryRule.java
index 5044fcd2c77..ee875f21287 100644
--- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/RuleRepositoryRule.java
+++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/RuleRepositoryRule.java
@@ -26,7 +26,7 @@ import java.util.function.Supplier;
import org.junit.rules.ExternalResource;
import org.sonar.api.rule.RuleKey;
import org.sonar.db.DbSession;
-import org.sonar.server.rule.NewExternalRule;
+import org.sonar.server.rule.NewAddHocRule;
import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;
@@ -35,7 +35,7 @@ public class RuleRepositoryRule extends ExternalResource implements RuleReposito
private final Map<RuleKey, Rule> rulesByKey = new HashMap<>();
private final Map<Integer, Rule> rulesById = new HashMap<>();
- private final Map<RuleKey, NewExternalRule> newExternalRulesById = new HashMap<>();
+ private final Map<RuleKey, NewAddHocRule> newExternalRulesById = new HashMap<>();
@Override
protected void after() {
@@ -68,7 +68,7 @@ public class RuleRepositoryRule extends ExternalResource implements RuleReposito
}
@Override
- public void persistNewExternalRules(DbSession dbSession) {
+ public void persistNewAddHocRules(DbSession dbSession) {
throw new UnsupportedOperationException();
}
@@ -87,7 +87,7 @@ public class RuleRepositoryRule extends ExternalResource implements RuleReposito
}
@Override
- public void insertNewExternalRuleIfAbsent(RuleKey ruleKey, Supplier<NewExternalRule> ruleSupplier) {
+ public void addNewAddHocRuleIfAbsent(RuleKey ruleKey, Supplier<NewAddHocRule> ruleSupplier) {
newExternalRulesById.computeIfAbsent(ruleKey, k -> ruleSupplier.get());
}
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/TrackerRawInputFactoryTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/TrackerRawInputFactoryTest.java
index c977257a543..390f6d8035f 100644
--- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/TrackerRawInputFactoryTest.java
+++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/TrackerRawInputFactoryTest.java
@@ -191,8 +191,8 @@ public class TrackerRawInputFactoryTest {
ScannerReport.ExternalIssue reportIssue = ScannerReport.ExternalIssue.newBuilder()
.setTextRange(TextRange.newBuilder().setStartLine(2).build())
.setMsg("the message")
- .setRuleRepository("eslint")
- .setRuleKey("S001")
+ .setEngineId("eslint")
+ .setRuleId("S001")
.setSeverity(Constants.Severity.BLOCKER)
.setEffort(20l)
.setType(ScannerReport.IssueType.SECURITY_HOTSPOT)
@@ -224,8 +224,8 @@ public class TrackerRawInputFactoryTest {
ScannerReport.ExternalIssue reportIssue = ScannerReport.ExternalIssue.newBuilder()
.setTextRange(TextRange.newBuilder().setStartLine(2).build())
.setMsg("the message")
- .setRuleRepository("eslint")
- .setRuleKey("S001")
+ .setEngineId("eslint")
+ .setRuleId("S001")
.setSeverity(Constants.Severity.BLOCKER)
.setType(ScannerReport.IssueType.BUG)
.build();
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PersistExternalRulesStepTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PersistExternalRulesStepTest.java
index 87d44ddb343..2832628b193 100644
--- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PersistExternalRulesStepTest.java
+++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PersistExternalRulesStepTest.java
@@ -34,8 +34,8 @@ import org.sonar.db.DbTester;
import org.sonar.db.rule.RuleDao;
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.server.es.EsTester;
-import org.sonar.server.rule.ExternalRuleCreator;
-import org.sonar.server.rule.NewExternalRule;
+import org.sonar.server.rule.AddHocRuleCreator;
+import org.sonar.server.rule.NewAddHocRule;
import org.sonar.server.rule.index.RuleIndexDefinition;
import org.sonar.server.rule.index.RuleIndexer;
@@ -59,7 +59,7 @@ public class PersistExternalRulesStepTest extends BaseStepTest {
public EsTester es = EsTester.create();
private RuleIndexer indexer = new RuleIndexer(es.client(), dbClient);
- private ExternalRuleCreator externalRuleCreator = new ExternalRuleCreator(dbClient, System2.INSTANCE, indexer);
+ private AddHocRuleCreator addHocRuleCreator = new AddHocRuleCreator(dbClient, System2.INSTANCE, indexer);
@Override
protected ComputationStep step() {
@@ -68,7 +68,7 @@ public class PersistExternalRulesStepTest extends BaseStepTest {
@Before
public void setup() {
- ruleRepository = new RuleRepositoryImpl(externalRuleCreator, dbClient, analysisMetadataHolder);
+ ruleRepository = new RuleRepositoryImpl(addHocRuleCreator, dbClient, analysisMetadataHolder);
underTest = new PersistExternalRulesStep(dbClient, ruleRepository);
}
@@ -76,7 +76,7 @@ public class PersistExternalRulesStepTest extends BaseStepTest {
public void persist_and_index_new_external_rules() {
RuleKey ruleKey = RuleKey.of("eslint", "no-cond-assign");
- ruleRepository.insertNewExternalRuleIfAbsent(ruleKey, () -> new NewExternalRule.Builder()
+ ruleRepository.addNewAddHocRuleIfAbsent(ruleKey, () -> new NewAddHocRule.Builder()
.setKey(ruleKey)
.setPluginKey("eslint")
.setName("eslint:no-cond-assign")
@@ -105,7 +105,7 @@ public class PersistExternalRulesStepTest extends BaseStepTest {
public void do_not_persist_existing_external_rules() {
RuleKey ruleKey = RuleKey.of("eslint", "no-cond-assign");
db.rules().insert(ruleKey, r -> r.setIsExternal(true));
- ruleRepository.insertNewExternalRuleIfAbsent(ruleKey, () -> new NewExternalRule.Builder()
+ ruleRepository.addNewAddHocRuleIfAbsent(ruleKey, () -> new NewAddHocRule.Builder()
.setKey(ruleKey)
.setPluginKey("eslint")
.build());
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PersistIssuesStepTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PersistIssuesStepTest.java
index a5a7552b0ac..e5cdb6f6a12 100644
--- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PersistIssuesStepTest.java
+++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PersistIssuesStepTest.java
@@ -53,7 +53,7 @@ import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.db.rule.RuleTesting;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.server.issue.IssueStorage;
-import org.sonar.server.rule.ExternalRuleCreator;
+import org.sonar.server.rule.AddHocRuleCreator;
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
@@ -85,7 +85,7 @@ public class PersistIssuesStepTest extends BaseStepTest {
private IssueCache issueCache;
private ComputationStep underTest;
- private ExternalRuleCreator externalRuleCreator = mock(ExternalRuleCreator.class);
+ private AddHocRuleCreator addHocRuleCreator = mock(AddHocRuleCreator.class);
@Override
protected ComputationStep step() {
@@ -99,7 +99,7 @@ public class PersistIssuesStepTest extends BaseStepTest {
when(system2.now()).thenReturn(NOW);
reportReader.setMetadata(ScannerReport.Metadata.getDefaultInstance());
- underTest = new PersistIssuesStep(dbClient, system2, new UpdateConflictResolver(), new RuleRepositoryImpl(externalRuleCreator, dbClient, analysisMetadataHolder), issueCache,
+ underTest = new PersistIssuesStep(dbClient, system2, new UpdateConflictResolver(), new RuleRepositoryImpl(addHocRuleCreator, dbClient, analysisMetadataHolder), issueCache,
new IssueStorage());
}
diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java
index 6a70c5d6b79..dacec29f0b0 100644
--- a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java
+++ b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java
@@ -141,7 +141,7 @@ import org.sonar.server.qualitygate.QualityGateEvaluatorImpl;
import org.sonar.server.qualitygate.QualityGateFinder;
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
import org.sonar.server.rule.DefaultRuleFinder;
-import org.sonar.server.rule.ExternalRuleCreator;
+import org.sonar.server.rule.AddHocRuleCreator;
import org.sonar.server.rule.index.RuleIndex;
import org.sonar.server.rule.index.RuleIndexer;
import org.sonar.server.setting.DatabaseSettingLoader;
@@ -370,7 +370,7 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer {
XMLRuleParser.class,
DefaultRuleFinder.class,
RulesDefinitionXmlLoader.class,
- ExternalRuleCreator.class,
+ AddHocRuleCreator.class,
RuleIndexer.class,
// languages
diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/rule/ExternalRuleCreator.java b/server/sonar-server-common/src/main/java/org/sonar/server/rule/AddHocRuleCreator.java
index 9044ebff3a1..a2f938f9e7a 100644
--- a/server/sonar-server-common/src/main/java/org/sonar/server/rule/ExternalRuleCreator.java
+++ b/server/sonar-server-common/src/main/java/org/sonar/server/rule/AddHocRuleCreator.java
@@ -30,35 +30,36 @@ import org.sonar.server.rule.index.RuleIndexer;
import static org.sonar.api.rule.RuleStatus.READY;
import static org.sonar.db.rule.RuleDto.Scope.ALL;
-public class ExternalRuleCreator {
+public class AddHocRuleCreator {
private final DbClient dbClient;
private final System2 system2;
private final RuleIndexer ruleIndexer;
- public ExternalRuleCreator(DbClient dbClient, System2 system2, RuleIndexer ruleIndexer) {
+ public AddHocRuleCreator(DbClient dbClient, System2 system2, RuleIndexer ruleIndexer) {
this.dbClient = dbClient;
this.system2 = system2;
this.ruleIndexer = ruleIndexer;
}
/**
- * Persists a rule in the DB and indexes it.
+ * Persists a new add hoc rule in the DB and indexes it.
* @return the rule that was inserted in the DB, which <b>includes the generated ID</b>.
*/
- public RuleDto persistAndIndex(DbSession dbSession, NewExternalRule external) {
+ public RuleDto persistAndIndex(DbSession dbSession, NewAddHocRule adHoc) {
RuleDao dao = dbClient.ruleDao();
dao.insert(dbSession, new RuleDefinitionDto()
- .setRuleKey(external.getKey())
- .setPluginKey(external.getPluginKey())
+ .setRuleKey(adHoc.getKey())
+ .setPluginKey(adHoc.getPluginKey())
.setIsExternal(true)
- .setName(external.getName())
+ .setName(adHoc.getName())
+ .setIsAdHoc(true)
.setScope(ALL)
.setStatus(READY)
.setCreatedAt(system2.now())
.setUpdatedAt(system2.now()));
- RuleDto ruleDto = dao.selectOrFailByKey(dbSession, external.getKey());
+ RuleDto ruleDto = dao.selectOrFailByKey(dbSession, adHoc.getKey());
ruleIndexer.commitAndIndex(dbSession, ruleDto.getId());
return ruleDto;
}
diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/rule/NewExternalRule.java b/server/sonar-server-common/src/main/java/org/sonar/server/rule/NewAddHocRule.java
index a968a43d7ac..c84896b7791 100644
--- a/server/sonar-server-common/src/main/java/org/sonar/server/rule/NewExternalRule.java
+++ b/server/sonar-server-common/src/main/java/org/sonar/server/rule/NewAddHocRule.java
@@ -24,12 +24,12 @@ import javax.annotation.concurrent.Immutable;
import org.sonar.api.rule.RuleKey;
@Immutable
-public class NewExternalRule {
+public class NewAddHocRule {
private final RuleKey key;
private final String name;
private final String pluginKey;
- private NewExternalRule(Builder builder) {
+ private NewAddHocRule(Builder builder) {
Objects.requireNonNull(builder.key, "'key' not expected to be null for an external rule");
this.key = builder.key;
this.pluginKey = builder.pluginKey;
@@ -67,8 +67,8 @@ public class NewExternalRule {
return name;
}
- public NewExternalRule build() {
- return new NewExternalRule(this);
+ public NewAddHocRule build() {
+ return new NewAddHocRule(this);
}
public Builder setPluginKey(String pluginKey) {
diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/rule/ExternalRuleCreatorTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/rule/AddHocRuleCreatorTest.java
index 59d4d28fcfe..db5269e1b4b 100644
--- a/server/sonar-server-common/src/test/java/org/sonar/server/rule/ExternalRuleCreatorTest.java
+++ b/server/sonar-server-common/src/test/java/org/sonar/server/rule/AddHocRuleCreatorTest.java
@@ -30,7 +30,7 @@ import org.sonar.server.rule.index.RuleIndexer;
import static org.assertj.core.api.Assertions.assertThat;
-public class ExternalRuleCreatorTest {
+public class AddHocRuleCreatorTest {
@org.junit.Rule
public DbTester dbTester = DbTester.create(System2.INSTANCE);
@@ -38,13 +38,13 @@ public class ExternalRuleCreatorTest {
public EsTester es = EsTester.create();
private RuleIndexer indexer = new RuleIndexer(es.client(), dbTester.getDbClient());
- private ExternalRuleCreator underTest = new ExternalRuleCreator(dbTester.getDbClient(), System2.INSTANCE, indexer);
+ private AddHocRuleCreator underTest = new AddHocRuleCreator(dbTester.getDbClient(), System2.INSTANCE, indexer);
private DbSession dbSession = dbTester.getSession();
@Test
public void create_external_rule() {
RuleKey ruleKey = RuleKey.of("eslint", "no-cond-assign");
- NewExternalRule externalRule = new NewExternalRule.Builder()
+ NewAddHocRule externalRule = new NewAddHocRule.Builder()
.setKey(ruleKey)
.setPluginKey("eslint")
.setName("name")
diff --git a/server/sonar-server/src/test/java/org/sonar/server/rule/NewExternalRuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/rule/NewAddHocRuleTest.java
index 85816da9e6b..11917668f11 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/rule/NewExternalRuleTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/rule/NewAddHocRuleTest.java
@@ -25,20 +25,20 @@ import org.sonar.api.rule.RuleKey;
import static org.assertj.core.api.Assertions.assertThat;
-public class NewExternalRuleTest {
+public class NewAddHocRuleTest {
@org.junit.Rule
public ExpectedException exception = ExpectedException.none();
@Test
public void should_build_new_external_rule() {
- NewExternalRule.Builder builder = new NewExternalRule.Builder()
+ NewAddHocRule.Builder builder = new NewAddHocRule.Builder()
.setKey(RuleKey.of("repo", "rule"))
.setPluginKey("repo")
.setName("name");
assertThat(builder.name()).isEqualTo("name");
- NewExternalRule rule = builder.build();
+ NewAddHocRule rule = builder.build();
assertThat(rule.getName()).isEqualTo("name");
assertThat(rule.getPluginKey()).isEqualTo("repo");
@@ -49,7 +49,7 @@ public class NewExternalRuleTest {
exception.expect(NullPointerException.class);
exception.expectMessage("'key' not expected to be null for an external rule");
- new NewExternalRule.Builder()
+ new NewAddHocRule.Builder()
.build();
}
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorContext.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorContext.java
index ed4ffe22b3c..00dae1fdd65 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorContext.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorContext.java
@@ -20,7 +20,6 @@
package org.sonar.api.batch.sensor;
import java.io.Serializable;
-
import org.sonar.api.SonarRuntime;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
@@ -38,6 +37,8 @@ import org.sonar.api.batch.sensor.issue.NewExternalIssue;
import org.sonar.api.batch.sensor.issue.NewIssue;
import org.sonar.api.batch.sensor.measure.Measure;
import org.sonar.api.batch.sensor.measure.NewMeasure;
+import org.sonar.api.batch.sensor.rule.AdHocRule;
+import org.sonar.api.batch.sensor.rule.NewAdHocRule;
import org.sonar.api.batch.sensor.symbol.NewSymbolTable;
import org.sonar.api.config.Configuration;
import org.sonar.api.config.Settings;
@@ -122,6 +123,12 @@ public interface SensorContext {
*/
NewExternalIssue newExternalIssue();
+ /**
+ * Fluent builder to create a new {@link AdHocRule}. Don't forget to call {@link NewAdHocRule#save()} once all parameters are provided.
+ * @since 7.4
+ */
+ NewAdHocRule newAdHocRule();
+
// ------------ HIGHLIGHTING ------------
/**
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/InMemorySensorStorage.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/InMemorySensorStorage.java
index e46b8121830..681005b5ff7 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/InMemorySensorStorage.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/InMemorySensorStorage.java
@@ -34,7 +34,10 @@ import org.sonar.api.batch.sensor.error.AnalysisError;
import org.sonar.api.batch.sensor.highlighting.internal.DefaultHighlighting;
import org.sonar.api.batch.sensor.issue.ExternalIssue;
import org.sonar.api.batch.sensor.issue.Issue;
+import org.sonar.api.batch.sensor.issue.internal.DefaultExternalIssue;
import org.sonar.api.batch.sensor.measure.Measure;
+import org.sonar.api.batch.sensor.rule.AdHocRule;
+import org.sonar.api.batch.sensor.rule.internal.DefaultAdHocRule;
import org.sonar.api.batch.sensor.symbol.internal.DefaultSymbolTable;
import static com.google.common.base.Preconditions.checkArgument;
@@ -45,6 +48,7 @@ class InMemorySensorStorage implements SensorStorage {
Collection<Issue> allIssues = new ArrayList<>();
Collection<ExternalIssue> allExternalIssues = new ArrayList<>();
+ Collection<AdHocRule> allAdHocRules = new ArrayList<>();
Collection<AnalysisError> allAnalysisErrors = new ArrayList<>();
Map<String, DefaultHighlighting> highlightingByComponent = new HashMap<>();
@@ -71,6 +75,11 @@ class InMemorySensorStorage implements SensorStorage {
}
@Override
+ public void store(DefaultAdHocRule adHocRule) {
+ allAdHocRules.add(adHocRule);
+ }
+
+ @Override
public void store(DefaultHighlighting highlighting) {
String fileKey = highlighting.inputFile().key();
// Emulate duplicate storage check
@@ -119,7 +128,7 @@ class InMemorySensorStorage implements SensorStorage {
}
@Override
- public void store(ExternalIssue issue) {
+ public void store(DefaultExternalIssue issue) {
allExternalIssues.add(issue);
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java
index 3559ebdb258..8549c5943c5 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java
@@ -70,6 +70,9 @@ import org.sonar.api.batch.sensor.issue.internal.DefaultIssue;
import org.sonar.api.batch.sensor.measure.Measure;
import org.sonar.api.batch.sensor.measure.NewMeasure;
import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
+import org.sonar.api.batch.sensor.rule.AdHocRule;
+import org.sonar.api.batch.sensor.rule.NewAdHocRule;
+import org.sonar.api.batch.sensor.rule.internal.DefaultAdHocRule;
import org.sonar.api.batch.sensor.symbol.NewSymbolTable;
import org.sonar.api.batch.sensor.symbol.internal.DefaultSymbolTable;
import org.sonar.api.config.Configuration;
@@ -229,10 +232,19 @@ public class SensorContextTester implements SensorContext {
return new DefaultExternalIssue(sensorStorage);
}
+ @Override
+ public NewAdHocRule newAdHocRule() {
+ return new DefaultAdHocRule(sensorStorage);
+ }
+
public Collection<ExternalIssue> allExternalIssues() {
return sensorStorage.allExternalIssues;
}
+ public Collection<AdHocRule> allAdHocRules() {
+ return sensorStorage.allAdHocRules;
+ }
+
public Collection<AnalysisError> allAnalysisErrors() {
return sensorStorage.allAnalysisErrors;
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorStorage.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorStorage.java
index ede3c9e9910..69177b4d924 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorStorage.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorStorage.java
@@ -25,9 +25,10 @@ import org.sonar.api.batch.sensor.coverage.internal.DefaultCoverage;
import org.sonar.api.batch.sensor.cpd.internal.DefaultCpdTokens;
import org.sonar.api.batch.sensor.error.AnalysisError;
import org.sonar.api.batch.sensor.highlighting.internal.DefaultHighlighting;
-import org.sonar.api.batch.sensor.issue.ExternalIssue;
import org.sonar.api.batch.sensor.issue.Issue;
+import org.sonar.api.batch.sensor.issue.internal.DefaultExternalIssue;
import org.sonar.api.batch.sensor.measure.Measure;
+import org.sonar.api.batch.sensor.rule.internal.DefaultAdHocRule;
import org.sonar.api.batch.sensor.symbol.internal.DefaultSymbolTable;
/**
@@ -41,7 +42,9 @@ public interface SensorStorage {
void store(Issue issue);
- void store(ExternalIssue issue);
+ void store(DefaultExternalIssue issue);
+
+ void store(DefaultAdHocRule adHocRule);
void store(DefaultHighlighting highlighting);
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/ExternalIssue.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/ExternalIssue.java
index b151a6582aa..9f0cb1fd76d 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/ExternalIssue.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/ExternalIssue.java
@@ -30,6 +30,16 @@ import org.sonar.api.rules.RuleType;
*/
public interface ExternalIssue extends IIssue {
+ /**
+ * @since 7.4
+ */
+ String engineId();
+
+ /**
+ * @since 7.4
+ */
+ String ruleId();
+
Severity severity();
/**
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/NewExternalIssue.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/NewExternalIssue.java
index ba9a4d7f3ec..99e63eb4d09 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/NewExternalIssue.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/NewExternalIssue.java
@@ -34,10 +34,24 @@ import org.sonar.api.rules.RuleType;
public interface NewExternalIssue {
/**
* The {@link RuleKey} of the issue.
+ * @deprecated since 7.4. It is misleading, because of the "external_" prefix that is added on server side. Use {@link #engineId(String)} and {@link #ruleId(String)}
*/
+ @Deprecated
NewExternalIssue forRule(RuleKey ruleKey);
/**
+ * Unique identifier of the external analyzer (e.g. eslint, pmd, ...)
+ * @since 7.4
+ */
+ NewExternalIssue engineId(String engineId);
+
+ /**
+ * Unique rule identifier for a given {@link #engineId(String)}
+ * @since 7.4
+ */
+ NewExternalIssue ruleId(String ruleId);
+
+ /**
* Type of issue.
*/
NewExternalIssue type(RuleType type);
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/AbstractDefaultIssue.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/AbstractDefaultIssue.java
index c845eb1ab7f..b44534f78d2 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/AbstractDefaultIssue.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/AbstractDefaultIssue.java
@@ -26,17 +26,15 @@ import java.util.List;
import javax.annotation.Nullable;
import org.sonar.api.batch.sensor.internal.DefaultStorable;
import org.sonar.api.batch.sensor.internal.SensorStorage;
+import org.sonar.api.batch.sensor.issue.Issue.Flow;
import org.sonar.api.batch.sensor.issue.IssueLocation;
import org.sonar.api.batch.sensor.issue.NewIssueLocation;
-import org.sonar.api.batch.sensor.issue.Issue.Flow;
-import org.sonar.api.rule.RuleKey;
import static com.google.common.base.Preconditions.checkState;
import static java.util.Collections.unmodifiableList;
import static java.util.stream.Collectors.toList;
public abstract class AbstractDefaultIssue<T extends AbstractDefaultIssue> extends DefaultStorable {
- protected RuleKey ruleKey;
protected IssueLocation primaryLocation;
protected List<List<IssueLocation>> flows = new ArrayList<>();
@@ -48,15 +46,6 @@ public abstract class AbstractDefaultIssue<T extends AbstractDefaultIssue> exte
super(storage);
}
- public T forRule(RuleKey ruleKey) {
- this.ruleKey = ruleKey;
- return (T) this;
- }
-
- public RuleKey ruleKey() {
- return this.ruleKey;
- }
-
public IssueLocation primaryLocation() {
return primaryLocation;
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultExternalIssue.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultExternalIssue.java
index 9118a4a373c..c4554bcd8ad 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultExternalIssue.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultExternalIssue.java
@@ -25,6 +25,7 @@ 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.rule.RuleKey;
import org.sonar.api.rules.RuleType;
import static com.google.common.base.Preconditions.checkState;
@@ -35,6 +36,8 @@ public class DefaultExternalIssue extends AbstractDefaultIssue<DefaultExternalIs
private Long effort;
private Severity severity;
private RuleType type;
+ private String engineId;
+ private String ruleId;
public DefaultExternalIssue() {
super(null);
@@ -58,6 +61,16 @@ public class DefaultExternalIssue extends AbstractDefaultIssue<DefaultExternalIs
}
@Override
+ public String engineId() {
+ return engineId;
+ }
+
+ @Override
+ public String ruleId() {
+ return ruleId;
+ }
+
+ @Override
public Severity severity() {
return this.severity;
}
@@ -69,7 +82,8 @@ public class DefaultExternalIssue extends AbstractDefaultIssue<DefaultExternalIs
@Override
public void doSave() {
- requireNonNull(this.ruleKey, "Rule key is mandatory on external issue");
+ 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");
@@ -84,6 +98,33 @@ public class DefaultExternalIssue extends AbstractDefaultIssue<DefaultExternalIs
}
@Override
+ public NewExternalIssue engineId(String engineId) {
+ this.engineId = engineId;
+ return this;
+ }
+
+ @Override
+ public NewExternalIssue ruleId(String ruleId) {
+ this.ruleId = ruleId;
+ return this;
+ }
+
+ @Override
+ public DefaultExternalIssue forRule(RuleKey ruleKey) {
+ this.engineId = ruleKey.repository();
+ this.ruleId = ruleKey.rule();
+ return this;
+ }
+
+ @Override
+ public RuleKey ruleKey() {
+ if (engineId != null && ruleId != null) {
+ return RuleKey.of(RuleKey.EXTERNAL_RULE_REPO_PREFIX + engineId, ruleId);
+ }
+ return null;
+ }
+
+ @Override
public DefaultExternalIssue type(RuleType type) {
this.type = type;
return this;
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssue.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssue.java
index 65bebee580d..eb9ae29b61a 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssue.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssue.java
@@ -26,12 +26,14 @@ import org.sonar.api.batch.sensor.internal.SensorStorage;
import org.sonar.api.batch.sensor.issue.Issue;
import org.sonar.api.batch.sensor.issue.IssueLocation;
import org.sonar.api.batch.sensor.issue.NewIssue;
+import org.sonar.api.rule.RuleKey;
import static com.google.common.base.Preconditions.checkState;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;
public class DefaultIssue extends AbstractDefaultIssue<DefaultIssue> implements Issue, NewIssue {
+ private RuleKey ruleKey;
private Double gap;
private Severity overriddenSeverity;
@@ -43,6 +45,16 @@ public class DefaultIssue extends AbstractDefaultIssue<DefaultIssue> implements
super(storage);
}
+ public DefaultIssue forRule(RuleKey ruleKey) {
+ this.ruleKey = ruleKey;
+ return this;
+ }
+
+ public RuleKey ruleKey() {
+ return this.ruleKey;
+ }
+
+
@Override
public DefaultIssue gap(@Nullable Double gap) {
Preconditions.checkArgument(gap == null || gap >= 0, format("Gap must be greater than or equal 0 (got %s)", gap));
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueLocation.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueLocation.java
index fbb20c0353e..140b90593fe 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueLocation.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueLocation.java
@@ -90,10 +90,4 @@ public class DefaultIssueLocation implements NewIssueLocation, IssueLocation {
return this.message;
}
- public static void main (String[] args) {
-
- new DefaultIssueLocation().message("pipo");
-
- }
-
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/rule/AdHocRule.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/rule/AdHocRule.java
new file mode 100644
index 00000000000..6708bcd8533
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/rule/AdHocRule.java
@@ -0,0 +1,62 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.api.batch.sensor.rule;
+
+import org.sonar.api.batch.rule.Severity;
+import org.sonar.api.batch.sensor.Sensor;
+import org.sonar.api.rules.RuleType;
+
+/**
+ * Represents a rule imported from an external rule engine by a {@link Sensor}.
+ * @since 7.4
+ */
+public interface AdHocRule {
+
+ /**
+ * Unique identifier of the external analyzer (e.g. eslint, pmd, ...)
+ */
+ String engineId();
+
+ /**
+ * Unique rule identifier for a given {@link #engineId()}
+ */
+ String ruleId();
+
+ /**
+ * Name of the rule.
+ */
+ String name();
+
+ /**
+ * Description of the rule.
+ */
+ String description();
+
+ /**
+ * Default severity of the rule.
+ */
+ Severity severity();
+
+ /**
+ * Type of the rule.
+ */
+ RuleType type();
+
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/rule/NewAdHocRule.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/rule/NewAdHocRule.java
new file mode 100644
index 00000000000..993b19eeb02
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/rule/NewAdHocRule.java
@@ -0,0 +1,70 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.api.batch.sensor.rule;
+
+import org.sonar.api.batch.rule.Severity;
+import org.sonar.api.batch.sensor.Sensor;
+import org.sonar.api.rules.RuleType;
+
+/**
+ * Builder for a rule imported from an external rule engine by a {@link Sensor}. This allows to provide more metadata
+ * for rules associated to {@link org.sonar.api.batch.sensor.issue.ExternalIssue}.
+ * Don't forget to {@link #save()} after setting the fields.
+ *
+ * @since 7.4
+ */
+public interface NewAdHocRule {
+
+ /**
+ * Unique identifier of the external analyzer (e.g. eslint, pmd, ...)
+ */
+ NewAdHocRule engineId(String engineId);
+
+ /**
+ * Unique rule identifier for a given {@link #engineId(String)}
+ */
+ NewAdHocRule ruleId(String ruleId);
+
+ /**
+ * The name of the rule.
+ */
+ NewAdHocRule name(String name);
+
+ /**
+ * The description of the rule.
+ */
+ NewAdHocRule description(String description);
+
+ /**
+ * Type of the rule.
+ */
+ NewAdHocRule type(RuleType type);
+
+ /**
+ * Set the severity of the rule.
+ */
+ NewAdHocRule severity(Severity severity);
+
+ /**
+ * Save the rule. There is almost no validation, except that no duplicated ad hoc rule keys are permitted.
+ */
+ void save();
+
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/rule/internal/DefaultAdHocRule.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/rule/internal/DefaultAdHocRule.java
new file mode 100644
index 00000000000..0251f5ce839
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/rule/internal/DefaultAdHocRule.java
@@ -0,0 +1,126 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.api.batch.sensor.rule.internal;
+
+import javax.annotation.Nullable;
+import org.sonar.api.batch.rule.Severity;
+import org.sonar.api.batch.sensor.internal.DefaultStorable;
+import org.sonar.api.batch.sensor.internal.SensorStorage;
+import org.sonar.api.batch.sensor.rule.AdHocRule;
+import org.sonar.api.batch.sensor.rule.NewAdHocRule;
+import org.sonar.api.rules.RuleType;
+
+import static com.google.common.base.Preconditions.checkState;
+import static org.apache.commons.lang.StringUtils.isNotBlank;
+
+public class DefaultAdHocRule extends DefaultStorable implements AdHocRule, NewAdHocRule {
+ private Severity severity;
+ private RuleType type;
+ private String name;
+ private String description;
+ private String engineId;
+ private String ruleId;
+
+ public DefaultAdHocRule() {
+ super(null);
+ }
+
+ public DefaultAdHocRule(@Nullable SensorStorage storage) {
+ super(storage);
+ }
+
+ @Override
+ public DefaultAdHocRule severity(Severity severity) {
+ this.severity = severity;
+ return this;
+ }
+
+ @Override
+ public String engineId() {
+ return engineId;
+ }
+
+ @Override
+ public String ruleId() {
+ return ruleId;
+ }
+
+ @Override
+ public String name() {
+ return name;
+ }
+
+ @Override
+ public String description() {
+ return description;
+ }
+
+ @Override
+ public Severity severity() {
+ return this.severity;
+ }
+
+ @Override
+ public void doSave() {
+ checkState(isNotBlank(engineId), "Engine id is mandatory on ad hoc rule");
+ checkState(isNotBlank(ruleId), "Rule id is mandatory on ad hoc rule");
+ checkState(isNotBlank(name), "Name is mandatory on every ad hoc rule");
+ checkState(isNotBlank(description), "Description is mandatory on every ad hoc rule");
+ checkState(severity != null, "Severity is mandatory on every ad hoc rule");
+ checkState(type != null, "Type is mandatory on every ad hoc rule");
+ storage.store(this);
+ }
+
+ @Override
+ public RuleType type() {
+ return type;
+ }
+
+ @Override
+ public DefaultAdHocRule engineId(String engineId) {
+ this.engineId = engineId;
+ return this;
+ }
+
+ @Override
+ public DefaultAdHocRule ruleId(String ruleId) {
+ this.ruleId = ruleId;
+ return this;
+ }
+
+ @Override
+ public DefaultAdHocRule name(String name) {
+ this.name = name;
+ return this;
+ }
+
+ @Override
+ public DefaultAdHocRule description(String description) {
+ this.description = description;
+ return this;
+ }
+
+ @Override
+ public DefaultAdHocRule type(RuleType type) {
+ this.type = type;
+ return this;
+ }
+
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/rule/internal/package-info.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/rule/internal/package-info.java
new file mode 100644
index 00000000000..72502a544bb
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/rule/internal/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.
+ */
+@javax.annotation.ParametersAreNonnullByDefault
+package org.sonar.api.batch.sensor.rule.internal;
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/rule/package-info.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/rule/package-info.java
new file mode 100644
index 00000000000..aebc1b31470
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/rule/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.
+ */
+@javax.annotation.ParametersAreNonnullByDefault
+package org.sonar.api.batch.sensor.rule;
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/rule/RuleKey.java b/sonar-plugin-api/src/main/java/org/sonar/api/rule/RuleKey.java
index 1adb4eaf3d2..0c429837af8 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/rule/RuleKey.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/rule/RuleKey.java
@@ -34,11 +34,6 @@ import static org.apache.commons.lang.StringUtils.isEmpty;
@Immutable
public class RuleKey implements Serializable, Comparable<RuleKey> {
- /**
- * @deprecated since 5.5, manual rule feature has been dropped
- */
- @Deprecated
- public static final String MANUAL_REPOSITORY_KEY = "manual";
public static final String EXTERNAL_RULE_REPO_PREFIX = "external_";
private final String repository;
@@ -86,13 +81,6 @@ public class RuleKey implements Serializable, Comparable<RuleKey> {
return rule;
}
- /**
- * @deprecated since 5.5, manual rule feature has been dropped
- */
- @Deprecated
- public boolean isManual() {
- return false;
- }
@Override
public boolean equals(@Nullable Object o) {
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/server/rule/RulesDefinition.java b/sonar-plugin-api/src/main/java/org/sonar/api/server/rule/RulesDefinition.java
index 4d1a5304c55..eb7089dc97e 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/server/rule/RulesDefinition.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/server/rule/RulesDefinition.java
@@ -403,12 +403,12 @@ public interface RulesDefinition {
/**
* Creates a repository of rules from external rule engines.
- * The key will always be prefixed with "external_".
+ * The repository key will be "external_[engineId]".
*
* @since 7.2
*/
- public NewRepository createExternalRepository(String key, String language) {
- return new NewRepositoryImpl(this, key, language, true);
+ public NewRepository createExternalRepository(String engineId, String language) {
+ return new NewRepositoryImpl(this, RuleKey.EXTERNAL_RULE_REPO_PREFIX + engineId, language, true);
}
/**
@@ -504,7 +504,7 @@ public interface RulesDefinition {
private NewRepositoryImpl(Context context, String key, String language, boolean isExternal) {
this.context = context;
- this.key = isExternal ? (RuleKey.EXTERNAL_RULE_REPO_PREFIX + key) : key;
+ this.key = key;
this.name = key;
this.language = language;
this.isExternal = isExternal;
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultExternalIssueTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultExternalIssueTest.java
index dc77fbc63fb..d0d38a0f547 100644
--- a/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultExternalIssueTest.java
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultExternalIssueTest.java
@@ -56,7 +56,9 @@ public class DefaultExternalIssueTest {
.severity(Severity.BLOCKER);
assertThat(issue.primaryLocation().inputComponent()).isEqualTo(inputFile);
- assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("repo", "rule"));
+ assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("external_repo", "rule"));
+ assertThat(issue.engineId()).isEqualTo("repo");
+ assertThat(issue.ruleId()).isEqualTo("rule");
assertThat(issue.primaryLocation().textRange().start().line()).isEqualTo(1);
assertThat(issue.remediationEffort()).isEqualTo(10l);
assertThat(issue.type()).isEqualTo(RuleType.BUG);
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/rule/internal/DefaultAdHocRuleTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/rule/internal/DefaultAdHocRuleTest.java
new file mode 100644
index 00000000000..7a2b38084bf
--- /dev/null
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/rule/internal/DefaultAdHocRuleTest.java
@@ -0,0 +1,148 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.api.batch.sensor.rule.internal;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.batch.rule.Severity;
+import org.sonar.api.batch.sensor.internal.SensorStorage;
+import org.sonar.api.batch.sensor.rule.NewAdHocRule;
+import org.sonar.api.rules.RuleType;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+public class DefaultAdHocRuleTest {
+
+ @Rule
+ public ExpectedException exception = ExpectedException.none();
+
+ @Test
+ public void store() {
+ SensorStorage storage = mock(SensorStorage.class);
+ new DefaultAdHocRule(storage)
+ .engineId("engine")
+ .ruleId("ruleId")
+ .name("name")
+ .description("desc")
+ .severity(Severity.BLOCKER)
+ .type(RuleType.CODE_SMELL)
+ .save();
+
+ verify(storage).store(any(DefaultAdHocRule.class));
+ }
+
+ @Test
+ public void fail_to_store_if_no_engine_id() {
+ SensorStorage storage = mock(SensorStorage.class);
+ NewAdHocRule rule = new DefaultAdHocRule(storage)
+ .engineId(" ")
+ .ruleId("ruleId")
+ .name("name")
+ .description("desc")
+ .severity(Severity.BLOCKER)
+ .type(RuleType.CODE_SMELL);
+
+ exception.expect(IllegalStateException.class);
+ exception.expectMessage("Engine id is mandatory");
+ rule.save();
+ }
+
+ @Test
+ public void fail_to_store_if_no_rule_id() {
+ SensorStorage storage = mock(SensorStorage.class);
+ NewAdHocRule rule = new DefaultAdHocRule(storage)
+ .engineId("engine")
+ .ruleId(" ")
+ .name("name")
+ .description("desc")
+ .severity(Severity.BLOCKER)
+ .type(RuleType.CODE_SMELL);
+
+ exception.expect(IllegalStateException.class);
+ exception.expectMessage("Rule id is mandatory");
+ rule.save();
+ }
+
+ @Test
+ public void fail_to_store_if_no_name() {
+ SensorStorage storage = mock(SensorStorage.class);
+ NewAdHocRule rule = new DefaultAdHocRule(storage)
+ .engineId("engine")
+ .ruleId("ruleId")
+ .name(" ")
+ .description("desc")
+ .severity(Severity.BLOCKER)
+ .type(RuleType.CODE_SMELL);
+
+ exception.expect(IllegalStateException.class);
+ exception.expectMessage("Name is mandatory");
+ rule.save();
+ }
+
+ @Test
+ public void fail_to_store_if_no_description() {
+ SensorStorage storage = mock(SensorStorage.class);
+ NewAdHocRule rule = new DefaultAdHocRule(storage)
+ .engineId("engine")
+ .ruleId("ruleId")
+ .name("name")
+ .description(" ")
+ .severity(Severity.BLOCKER)
+ .type(RuleType.CODE_SMELL);
+
+ exception.expect(IllegalStateException.class);
+ exception.expectMessage("Description is mandatory");
+ rule.save();
+ }
+
+ @Test
+ public void fail_to_store_if_no_severity() {
+ SensorStorage storage = mock(SensorStorage.class);
+ NewAdHocRule rule = new DefaultAdHocRule(storage)
+ .engineId("engine")
+ .ruleId("ruleId")
+ .name("name")
+ .description("desc")
+ .type(RuleType.CODE_SMELL);
+
+ exception.expect(IllegalStateException.class);
+ exception.expectMessage("Severity is mandatory");
+ rule.save();
+ }
+
+ @Test
+ public void fail_to_store_if_no_type() {
+ SensorStorage storage = mock(SensorStorage.class);
+ NewAdHocRule rule = new DefaultAdHocRule(storage)
+ .engineId("engine")
+ .ruleId("ruleId")
+ .name("name")
+ .description("desc")
+ .severity(Severity.BLOCKER);
+
+ exception.expect(IllegalStateException.class);
+ exception.expectMessage("Type is mandatory");
+ rule.save();
+ }
+
+} \ No newline at end of file
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/ExternalIssueImporter.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/ExternalIssueImporter.java
index 74cf2e6434d..46d495bd458 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/ExternalIssueImporter.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/ExternalIssueImporter.java
@@ -29,7 +29,6 @@ import org.sonar.api.batch.rule.Severity;
import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.batch.sensor.issue.NewExternalIssue;
import org.sonar.api.batch.sensor.issue.NewIssueLocation;
-import org.sonar.api.rule.RuleKey;
import org.sonar.api.rules.RuleType;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
@@ -70,7 +69,8 @@ public class ExternalIssueImporter {
private boolean importIssue(Issue issue) {
NewExternalIssue externalIssue = context.newExternalIssue()
- .forRule(RuleKey.of(issue.engineId, issue.ruleId))
+ .engineId(issue.engineId)
+ .ruleId(issue.ruleId)
.severity(Severity.valueOf(issue.severity))
.type(RuleType.valueOf(issue.type));
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ModuleIssues.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ModuleIssues.java
index d064b302f48..a0b8974443d 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ModuleIssues.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ModuleIssues.java
@@ -123,8 +123,8 @@ public class ModuleIssues {
// non-null fields
builder.setSeverity(severity);
builder.setType(issueType);
- builder.setRuleRepository(issue.ruleKey().repository());
- builder.setRuleKey(issue.ruleKey().rule());
+ builder.setEngineId(issue.engineId());
+ builder.setRuleId(issue.ruleId());
builder.setMsg(primaryMessage);
locationBuilder.setMsg(primaryMessage);
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/mediumtest/TaskResult.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/mediumtest/TaskResult.java
index 80a33078927..79b08aa9dc2 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/mediumtest/TaskResult.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/mediumtest/TaskResult.java
@@ -305,4 +305,16 @@ public class TaskResult implements org.sonar.scanner.mediumtest.ScanTaskObserver
}
return null;
}
+
+ public List<ScannerReport.AdHocRule> adHocRules() {
+ List<ScannerReport.AdHocRule> result = new ArrayList<>();
+ try (CloseableIterator<ScannerReport.AdHocRule> it = getReportReader().readAdHocRules()) {
+ while (it.hasNext()) {
+ result.add(it.next());
+ }
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ return result;
+ }
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorContext.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorContext.java
index 299e7eadb98..f79f09d4f2a 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorContext.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorContext.java
@@ -45,12 +45,15 @@ import org.sonar.api.batch.sensor.issue.internal.DefaultExternalIssue;
import org.sonar.api.batch.sensor.issue.internal.DefaultIssue;
import org.sonar.api.batch.sensor.measure.NewMeasure;
import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
+import org.sonar.api.batch.sensor.rule.NewAdHocRule;
+import org.sonar.api.batch.sensor.rule.internal.DefaultAdHocRule;
import org.sonar.api.batch.sensor.symbol.NewSymbolTable;
import org.sonar.api.batch.sensor.symbol.internal.DefaultSymbolTable;
import org.sonar.api.config.Configuration;
import org.sonar.api.config.Settings;
import org.sonar.api.utils.Version;
import org.sonar.scanner.scan.branch.BranchConfiguration;
+import org.sonar.scanner.sensor.noop.NoOpNewAdHocRule;
import org.sonar.scanner.sensor.noop.NoOpNewAnalysisError;
import org.sonar.scanner.sensor.noop.NoOpNewCpdTokens;
import org.sonar.scanner.sensor.noop.NoOpNewExternalIssue;
@@ -66,6 +69,7 @@ public class DefaultSensorContext implements SensorContext {
static final NoOpNewCpdTokens NO_OP_NEW_CPD_TOKENS = new NoOpNewCpdTokens();
static final NoOpNewAnalysisError NO_OP_NEW_ANALYSIS_ERROR = new NoOpNewAnalysisError();
static final NoOpNewExternalIssue NO_OP_NEW_EXTERNAL_ISSUE = new NoOpNewExternalIssue();
+ static final NoOpNewAdHocRule NO_OP_NEW_AD_HOC_RULE = new NoOpNewAdHocRule();
static final NoOpNewSignificantCode NO_OP_NEW_SIGNIFICANT_CODE = new NoOpNewSignificantCode();
private final Settings mutableSettings;
@@ -142,7 +146,14 @@ public class DefaultSensorContext implements SensorContext {
return NO_OP_NEW_EXTERNAL_ISSUE;
}
return new DefaultExternalIssue(sensorStorage);
+ }
+ @Override
+ public NewAdHocRule newAdHocRule() {
+ if (analysisMode.isIssues()) {
+ return NO_OP_NEW_AD_HOC_RULE;
+ }
+ return new DefaultAdHocRule(sensorStorage);
}
@Override
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorStorage.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorStorage.java
index 859cda8b75d..f7f3b9898d6 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorStorage.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorStorage.java
@@ -42,10 +42,11 @@ import org.sonar.api.batch.sensor.cpd.internal.DefaultCpdTokens;
import org.sonar.api.batch.sensor.error.AnalysisError;
import org.sonar.api.batch.sensor.highlighting.internal.DefaultHighlighting;
import org.sonar.api.batch.sensor.internal.SensorStorage;
-import org.sonar.api.batch.sensor.issue.ExternalIssue;
import org.sonar.api.batch.sensor.issue.Issue;
+import org.sonar.api.batch.sensor.issue.internal.DefaultExternalIssue;
import org.sonar.api.batch.sensor.measure.Measure;
import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
+import org.sonar.api.batch.sensor.rule.internal.DefaultAdHocRule;
import org.sonar.api.batch.sensor.symbol.internal.DefaultSymbolTable;
import org.sonar.api.config.Configuration;
import org.sonar.api.utils.KeyValueFormat;
@@ -56,6 +57,7 @@ import org.sonar.duplications.block.Block;
import org.sonar.duplications.internal.pmd.PmdBlockChunker;
import org.sonar.scanner.cpd.index.SonarCpdBlockIndex;
import org.sonar.scanner.issue.ModuleIssues;
+import org.sonar.scanner.protocol.Constants;
import org.sonar.scanner.protocol.output.FileStructure;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
@@ -390,7 +392,7 @@ public class DefaultSensorStorage implements SensorStorage {
* Thread safe assuming that each issues for each file are only written once.
*/
@Override
- public void store(ExternalIssue externalIssue) {
+ public void store(DefaultExternalIssue externalIssue) {
if (externalIssue.primaryLocation().inputComponent() instanceof DefaultInputFile) {
DefaultInputFile defaultInputFile = (DefaultInputFile) externalIssue.primaryLocation().inputComponent();
defaultInputFile.setPublished(true);
@@ -399,6 +401,19 @@ public class DefaultSensorStorage implements SensorStorage {
}
@Override
+ public void store(DefaultAdHocRule adHocRule) {
+ ScannerReportWriter writer = reportPublisher.getWriter();
+ final ScannerReport.AdHocRule.Builder builder = ScannerReport.AdHocRule.newBuilder();
+ builder.setEngineId(adHocRule.engineId());
+ builder.setRuleId(adHocRule.ruleId());
+ builder.setName(adHocRule.name());
+ builder.setDescription(adHocRule.description());
+ builder.setSeverity(Constants.Severity.valueOf(adHocRule.severity().name()));
+ builder.setType(ScannerReport.IssueType.valueOf(adHocRule.type().name()));
+ writer.appendAdHocRule(builder.build());
+ }
+
+ @Override
public void store(DefaultHighlighting highlighting) {
ScannerReportWriter writer = reportPublisher.getWriter();
DefaultInputFile inputFile = (DefaultInputFile) highlighting.inputFile();
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/noop/NoOpNewAdHocRule.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/noop/NoOpNewAdHocRule.java
new file mode 100644
index 00000000000..cd679665d90
--- /dev/null
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/noop/NoOpNewAdHocRule.java
@@ -0,0 +1,69 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.scanner.sensor.noop;
+
+import org.sonar.api.batch.rule.Severity;
+import org.sonar.api.batch.sensor.rule.NewAdHocRule;
+import org.sonar.api.rules.RuleType;
+
+public class NoOpNewAdHocRule implements NewAdHocRule {
+
+ @Override
+ public NoOpNewAdHocRule engineId(String engineId) {
+ // no op
+ return this;
+ }
+
+ @Override
+ public NoOpNewAdHocRule ruleId(String ruleId) {
+ // no op
+ return this;
+ }
+
+ @Override
+ public NewAdHocRule name(String name) {
+ // no op
+ return this;
+ }
+
+ @Override
+ public NewAdHocRule description(String description) {
+ // no op
+ return this;
+ }
+
+ @Override
+ public NoOpNewAdHocRule type(RuleType type) {
+ // no op
+ return this;
+ }
+
+ @Override
+ public NoOpNewAdHocRule severity(Severity severity) {
+ // no op
+ return this;
+ }
+
+ @Override
+ public void save() {
+ // no op
+ }
+
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/noop/NoOpNewExternalIssue.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/noop/NoOpNewExternalIssue.java
index 555bb7f94f9..e66f026090a 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/noop/NoOpNewExternalIssue.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/noop/NoOpNewExternalIssue.java
@@ -35,6 +35,18 @@ public class NoOpNewExternalIssue implements NewExternalIssue {
}
@Override
+ public NewExternalIssue engineId(String engineId) {
+ // no op
+ return this;
+ }
+
+ @Override
+ public NewExternalIssue ruleId(String ruleId) {
+ // no op
+ return this;
+ }
+
+ @Override
public NewExternalIssue type(RuleType type) {
// no op
return this;
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/issues/ExternalIssuesMediumTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/issues/ExternalIssuesMediumTest.java
index dddb88040ff..fc3ce5b1798 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/issues/ExternalIssuesMediumTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/issues/ExternalIssuesMediumTest.java
@@ -31,12 +31,15 @@ import org.sonar.api.utils.log.LogTester;
import org.sonar.scanner.mediumtest.ScannerMediumTester;
import org.sonar.scanner.mediumtest.TaskResult;
import org.sonar.scanner.protocol.Constants.Severity;
+import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReport.ExternalIssue;
import org.sonar.scanner.protocol.output.ScannerReport.Issue;
import org.sonar.scanner.protocol.output.ScannerReport.IssueType;
import org.sonar.xoo.XooPlugin;
+import org.sonar.xoo.rule.OneExternalIssuePerLineSensor;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
public class ExternalIssuesMediumTest {
@Rule
@@ -56,7 +59,7 @@ public class ExternalIssuesMediumTest {
TaskResult result = tester
.newScanTask(new File(tmpDir, "sonar-project.properties"))
- .property("sonar.oneExternalIssuePerLine.activate", "true")
+ .property(OneExternalIssuePerLineSensor.ACTIVATE, "true")
.execute();
List<Issue> issues = result.issuesFor(result.inputFile("xources/hello/HelloJava.xoo"));
@@ -67,6 +70,37 @@ public class ExternalIssuesMediumTest {
ExternalIssue issue = externalIssues.get(0);
assertThat(issue.getTextRange().getStartLine()).isEqualTo(issue.getTextRange().getStartLine());
+
+ assertThat(result.adHocRules()).isEmpty();
+ }
+
+ @Test
+ public void testOneIssuePerLine_register_ad_hoc_rule() throws Exception {
+ File projectDir = new File(IssuesMediumTest.class.getResource("/mediumtest/xoo/sample").toURI());
+ File tmpDir = temp.newFolder();
+ FileUtils.copyDirectory(projectDir, tmpDir);
+
+ TaskResult result = tester
+ .newScanTask(new File(tmpDir, "sonar-project.properties"))
+ .property(OneExternalIssuePerLineSensor.ACTIVATE, "true")
+ .property(OneExternalIssuePerLineSensor.REGISTER_AD_HOC_RULE, "true")
+ .execute();
+
+ assertThat(result.adHocRules()).extracting(
+ ScannerReport.AdHocRule::getEngineId,
+ ScannerReport.AdHocRule::getRuleId,
+ ScannerReport.AdHocRule::getName,
+ ScannerReport.AdHocRule::getDescription,
+ ScannerReport.AdHocRule::getSeverity,
+ ScannerReport.AdHocRule::getType)
+ .containsExactlyInAnyOrder(
+ tuple(
+ OneExternalIssuePerLineSensor.ENGINE_ID,
+ OneExternalIssuePerLineSensor.RULE_ID,
+ "An ad hoc rule",
+ "blah blah",
+ Severity.BLOCKER,
+ IssueType.BUG));
}
@Test
@@ -90,7 +124,8 @@ public class ExternalIssuesMediumTest {
ExternalIssue issue = externalIssues.get(0);
assertThat(issue.getFlowCount()).isZero();
assertThat(issue.getMsg()).isEqualTo("fix the issue here");
- assertThat(issue.getRuleKey()).isEqualTo("rule1");
+ assertThat(issue.getEngineId()).isEqualTo("externalXoo");
+ assertThat(issue.getRuleId()).isEqualTo("rule1");
assertThat(issue.getSeverity()).isEqualTo(Severity.MAJOR);
assertThat(issue.getEffort()).isEqualTo(50l);
assertThat(issue.getType()).isEqualTo(IssueType.CODE_SMELL);
@@ -103,7 +138,8 @@ public class ExternalIssuesMediumTest {
issue = externalIssues.get(1);
assertThat(issue.getFlowCount()).isZero();
assertThat(issue.getMsg()).isEqualTo("fix the bug here");
- assertThat(issue.getRuleKey()).isEqualTo("rule2");
+ assertThat(issue.getEngineId()).isEqualTo("externalXoo");
+ assertThat(issue.getRuleId()).isEqualTo("rule2");
assertThat(issue.getSeverity()).isEqualTo(Severity.CRITICAL);
assertThat(issue.getType()).isEqualTo(IssueType.BUG);
assertThat(issue.getEffort()).isZero();
@@ -119,7 +155,8 @@ public class ExternalIssuesMediumTest {
issue = externalIssues2.iterator().next();
assertThat(issue.getFlowCount()).isEqualTo(2);
assertThat(issue.getMsg()).isEqualTo("fix the bug here");
- assertThat(issue.getRuleKey()).isEqualTo("rule3");
+ assertThat(issue.getEngineId()).isEqualTo("externalXoo");
+ assertThat(issue.getRuleId()).isEqualTo("rule3");
assertThat(issue.getSeverity()).isEqualTo(Severity.MAJOR);
assertThat(issue.getType()).isEqualTo(IssueType.BUG);
assertThat(issue.hasTextRange()).isFalse();
@@ -128,7 +165,6 @@ public class ExternalIssuesMediumTest {
assertThat(issue.getFlow(1).getLocationCount()).isOne();
assertThat(issue.getFlow(1).getLocation(0).getTextRange().getStartLine()).isEqualTo(3);
-
// one issue is located in a non-existing file
assertThat(logs.logs()).contains("External issues ignored for 1 unknown files, including: invalidFile");
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/issues/IssuesMediumTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/issues/IssuesMediumTest.java
index 0226398fdd9..84de3e207e3 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/issues/IssuesMediumTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/issues/IssuesMediumTest.java
@@ -78,7 +78,7 @@ public class IssuesMediumTest {
TaskResult result = tester
.newScanTask(new File(tmpDir, "sonar-project.properties"))
- .property(OneExternalIssuePerLineSensor.ACTIVATE_EXTERNAL_ISSUES, "true")
+ .property(OneExternalIssuePerLineSensor.ACTIVATE, "true")
.execute();
List<ExternalIssue> externalIssues = result.externalIssuesFor(result.inputFile("xources/hello/HelloJava.xoo"));
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/sensor/DefaultSensorContextTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/sensor/DefaultSensorContextTest.java
index e7f82f77ab5..dc58ee42d94 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/sensor/DefaultSensorContextTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/sensor/DefaultSensorContextTest.java
@@ -85,6 +85,7 @@ public class DefaultSensorContextTest {
assertThat(adaptor.newIssue()).isNotNull();
assertThat(adaptor.newExternalIssue()).isNotNull();
+ assertThat(adaptor.newAdHocRule()).isNotNull();
assertThat(adaptor.newMeasure()).isNotNull();
assertThat(adaptor.newAnalysisError()).isEqualTo(DefaultSensorContext.NO_OP_NEW_ANALYSIS_ERROR);
assertThat(adaptor.isCancelled()).isFalse();
@@ -105,6 +106,7 @@ public class DefaultSensorContextTest {
assertThat(adaptor.newCpdTokens()).isEqualTo(DefaultSensorContext.NO_OP_NEW_CPD_TOKENS);
assertThat(adaptor.newSymbolTable()).isEqualTo(DefaultSensorContext.NO_OP_NEW_SYMBOL_TABLE);
assertThat(adaptor.newExternalIssue()).isEqualTo(DefaultSensorContext.NO_OP_NEW_EXTERNAL_ISSUE);
+ assertThat(adaptor.newAdHocRule()).isEqualTo(DefaultSensorContext.NO_OP_NEW_AD_HOC_RULE);
assertThat(adaptor.newHighlighting()).isEqualTo(DefaultSensorContext.NO_OP_NEW_HIGHLIGHTING);
}
diff --git a/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/FileStructure.java b/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/FileStructure.java
index bab729b95b0..5b7e6ddb851 100644
--- a/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/FileStructure.java
+++ b/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/FileStructure.java
@@ -77,6 +77,10 @@ public class FileStructure {
return new File(dir, "activerules.pb");
}
+ public File adHocRules() {
+ return new File(dir, "adhocrules.pb");
+ }
+
public File fileFor(Domain domain, int componentRef) {
return new File(dir, domain.filePrefix + componentRef + domain.fileSuffix);
}
diff --git a/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/ScannerReportReader.java b/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/ScannerReportReader.java
index 65c7bb79a05..c52726e48c1 100644
--- a/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/ScannerReportReader.java
+++ b/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/ScannerReportReader.java
@@ -50,6 +50,14 @@ public class ScannerReportReader {
return Protobuf.readStream(file, ScannerReport.ActiveRule.parser());
}
+ public CloseableIterator<ScannerReport.AdHocRule> readAdHocRules() {
+ File file = fileStructure.adHocRules();
+ if (!fileExists(file)) {
+ return emptyCloseableIterator();
+ }
+ return Protobuf.readStream(file, ScannerReport.AdHocRule.parser());
+ }
+
public CloseableIterator<ScannerReport.Measure> readComponentMeasures(int componentRef) {
File file = fileStructure.fileFor(FileStructure.Domain.MEASURES, componentRef);
if (fileExists(file)) {
diff --git a/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/ScannerReportWriter.java b/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/ScannerReportWriter.java
index 1ccb6876e88..5fa89151689 100644
--- a/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/ScannerReportWriter.java
+++ b/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/ScannerReportWriter.java
@@ -109,6 +109,15 @@ public class ScannerReportWriter {
}
}
+ public void appendAdHocRule(ScannerReport.AdHocRule adHocRule) {
+ File file = fileStructure.adHocRules();
+ try (OutputStream out = new BufferedOutputStream(new FileOutputStream(file, true))) {
+ adHocRule.writeDelimitedTo(out);
+ } catch (Exception e) {
+ throw ContextException.of("Unable to write ad hoc rule", e).addContext("file", file);
+ }
+ }
+
public File writeComponentMeasures(int componentRef, Iterable<ScannerReport.Measure> measures) {
File file = fileStructure.fileFor(FileStructure.Domain.MEASURES, componentRef);
Protobuf.writeStream(measures, file, false);
diff --git a/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/viewer/ScannerReportViewerApp.java b/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/viewer/ScannerReportViewerApp.java
index c7ab72ff6d3..4df7d77c080 100644
--- a/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/viewer/ScannerReportViewerApp.java
+++ b/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/viewer/ScannerReportViewerApp.java
@@ -92,12 +92,16 @@ public class ScannerReportViewerApp {
private JEditorPane duplicationEditor;
private JScrollPane issuesTab;
private JEditorPane issuesEditor;
+ private JScrollPane externalIssuesTab;
+ private JEditorPane externalIssuesEditor;
private JScrollPane measuresTab;
private JEditorPane measuresEditor;
private JScrollPane scmTab;
private JEditorPane scmEditor;
private JScrollPane activeRuleTab;
private JEditorPane activeRuleEditor;
+ private JScrollPane adHocRuleTab;
+ private JEditorPane adHocRuleEditor;
private JScrollPane qualityProfileTab;
private JEditorPane qualityProfileEditor;
private JScrollPane pluginTab;
@@ -196,6 +200,7 @@ public class ScannerReportViewerApp {
updateTitle();
loadComponents();
updateActiveRules();
+ updateAdHocRules();
updateQualityProfiles();
updatePlugins();
}
@@ -254,6 +259,7 @@ public class ScannerReportViewerApp {
updateTests(component);
updateDuplications(component);
updateIssues(component);
+ updateExternalIssues(component);
updateMeasures(component);
updateScm(component);
updateCpdTextBlocks(component);
@@ -317,6 +323,19 @@ public class ScannerReportViewerApp {
}
}
+ private void updateExternalIssues(Component component) {
+ externalIssuesEditor.setText("");
+ try (CloseableIterator<ScannerReport.ExternalIssue> it = reader.readComponentExternalIssues(component.getRef())) {
+ while (it.hasNext()) {
+ ScannerReport.ExternalIssue issue = it.next();
+ int offset = externalIssuesEditor.getDocument().getEndPosition().getOffset();
+ externalIssuesEditor.getDocument().insertString(offset, issue.toString(), null);
+ }
+ } catch (Exception e) {
+ throw new IllegalStateException("Can't read external issues for " + getNodeName(component), e);
+ }
+ }
+
private void updateCoverage(Component component) {
coverageEditor.setText("");
try (CloseableIterator<ScannerReport.LineCoverage> it = reader.readComponentCoverage(component.getRef())) {
@@ -375,6 +394,18 @@ public class ScannerReportViewerApp {
}
}
+ private void updateAdHocRules() {
+ adHocRuleEditor.setText("");
+
+ StringBuilder builder = new StringBuilder();
+ try (CloseableIterator<ScannerReport.AdHocRule> adHocRuleCloseableIterator = reader.readAdHocRules()) {
+ while (adHocRuleCloseableIterator.hasNext()) {
+ builder.append(adHocRuleCloseableIterator.next().toString()).append("\n");
+ }
+ adHocRuleEditor.setText(builder.toString());
+ }
+ }
+
private void updateQualityProfiles() {
qualityProfileEditor.setText("");
@@ -536,6 +567,12 @@ public class ScannerReportViewerApp {
issuesEditor = new JEditorPane();
issuesTab.setViewportView(issuesEditor);
+ externalIssuesTab = new JScrollPane();
+ tabbedPane.addTab("External Issues", null, externalIssuesTab, null);
+
+ externalIssuesEditor = new JEditorPane();
+ externalIssuesTab.setViewportView(externalIssuesEditor);
+
measuresTab = new JScrollPane();
tabbedPane.addTab("Measures", null, measuresTab, null);
@@ -554,6 +591,12 @@ public class ScannerReportViewerApp {
activeRuleEditor = new JEditorPane();
activeRuleTab.setViewportView(activeRuleEditor);
+ adHocRuleTab = new JScrollPane();
+ tabbedPane.addTab("Add Hoc Rules", null, adHocRuleTab, null);
+
+ adHocRuleEditor = new JEditorPane();
+ adHocRuleTab.setViewportView(adHocRuleEditor);
+
qualityProfileTab = new JScrollPane();
tabbedPane.addTab("Quality Profiles", null, qualityProfileTab, null);
diff --git a/sonar-scanner-protocol/src/main/protobuf/scanner_report.proto b/sonar-scanner-protocol/src/main/protobuf/scanner_report.proto
index ac4c89980b8..0913fc179e9 100644
--- a/sonar-scanner-protocol/src/main/protobuf/scanner_report.proto
+++ b/sonar-scanner-protocol/src/main/protobuf/scanner_report.proto
@@ -187,19 +187,25 @@ message Issue {
}
message ExternalIssue {
- string rule_repository = 1;
- string rule_key = 2;
- // Only when issue component is a file. Can also be empty for a file if this is an issue global to the file.
+ string engine_id = 1;
+ string rule_id = 2;
string msg = 3;
Severity severity = 4;
int64 effort = 5;
- // Only when issue component is a file. Can also be empty for a file if this is an issue global to the file.
- // Will be identical to the first location of the first flow
TextRange text_range = 6;
repeated Flow flow = 7;
IssueType type = 8;
}
+message AdHocRule {
+ string engine_id = 1;
+ string rule_id = 2;
+ string name = 3;
+ string description = 4;
+ Severity severity = 5;
+ IssueType type = 6;
+}
+
enum IssueType {
UNSET = 0;
CODE_SMELL = 1;