diff options
author | Julien HENRY <julien.henry@sonarsource.com> | 2018-09-04 16:08:53 +0200 |
---|---|---|
committer | SonarTech <sonartech@sonarsource.com> | 2018-09-24 20:20:58 +0200 |
commit | cfba7fcb6500d8217bd81ecfcb8f47ec48ad55f2 (patch) | |
tree | 81398a80d0269b523e630495a580daf8ac144228 /sonar-plugin-api | |
parent | 326b30334f0f5c0bb6a9565a3f6b367695bb1087 (diff) | |
download | sonarqube-cfba7fcb6500d8217bd81ecfcb8f47ec48ad55f2.tar.gz sonarqube-cfba7fcb6500d8217bd81ecfcb8f47ec48ad55f2.zip |
SONAR-11209 Allow sensors to provide ad hoc rule metadata for external issues
Diffstat (limited to 'sonar-plugin-api')
19 files changed, 569 insertions, 40 deletions
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 |