diff options
author | Duarte Meneses <duarte.meneses@sonarsource.com> | 2019-06-06 09:45:41 -0500 |
---|---|---|
committer | SonarTech <sonartech@sonarsource.com> | 2019-07-12 20:21:14 +0200 |
commit | 7c7d9b6b90244d2c974207862071caccdb2c9bb5 (patch) | |
tree | d1b1035076f996207d9fcd60ec5ea0c06234ece4 /sonar-plugin-api | |
parent | 97e15208790028ed50187e58cd4580e6cef8e6b3 (diff) | |
download | sonarqube-7c7d9b6b90244d2c974207862071caccdb2c9bb5.tar.gz sonarqube-7c7d9b6b90244d2c974207862071caccdb2c9bb5.zip |
Extract implementation from plugin API - Server rule definition
Diffstat (limited to 'sonar-plugin-api')
8 files changed, 93 insertions, 694 deletions
diff --git a/sonar-plugin-api/build.gradle b/sonar-plugin-api/build.gradle index 1475a50d800..109d187e80b 100644 --- a/sonar-plugin-api/build.gradle +++ b/sonar-plugin-api/build.gradle @@ -34,6 +34,8 @@ dependencies { testCompile 'org.assertj:assertj-core' testCompile 'org.mockito:mockito-core' testCompile project(':sonar-scanner-engine') + testCompile project(':server:sonar-server') + } sourceSets { diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/server/rule/DefaultDebtRemediationFunctions.java b/sonar-plugin-api/src/main/java/org/sonar/api/server/rule/DefaultDebtRemediationFunctions.java deleted file mode 100644 index e597b20390a..00000000000 --- a/sonar-plugin-api/src/main/java/org/sonar/api/server/rule/DefaultDebtRemediationFunctions.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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.server.rule; - -import javax.annotation.Nullable; -import org.sonar.api.server.debt.DebtRemediationFunction; -import org.sonar.api.server.debt.internal.DefaultDebtRemediationFunction; -import org.sonar.api.utils.MessageException; - -/** - * Factory of {@link org.sonar.api.server.debt.DebtRemediationFunction} that keeps - * a context of rule for better error messages. Used only when declaring rules. - * - * @see org.sonar.api.server.rule.RulesDefinition - */ -class DefaultDebtRemediationFunctions implements RulesDefinition.DebtRemediationFunctions { - - private final String repoKey; - private final String key; - - DefaultDebtRemediationFunctions(String repoKey, String key) { - this.repoKey = repoKey; - this.key = key; - } - - @Override - public DebtRemediationFunction linear(String gapMultiplier) { - return create(DefaultDebtRemediationFunction.Type.LINEAR, gapMultiplier, null); - } - - @Override - public DebtRemediationFunction linearWithOffset(String gapMultiplier, String baseEffort) { - return create(DefaultDebtRemediationFunction.Type.LINEAR_OFFSET, gapMultiplier, baseEffort); - } - - @Override - public DebtRemediationFunction constantPerIssue(String baseEffort) { - return create(DefaultDebtRemediationFunction.Type.CONSTANT_ISSUE, null, baseEffort); - } - - @Override - public DebtRemediationFunction create(DebtRemediationFunction.Type type, @Nullable String gapMultiplier, @Nullable String baseEffort) { - try { - return new DefaultDebtRemediationFunction(type, gapMultiplier, baseEffort); - } catch (Exception e) { - throw MessageException.of(String.format("The rule '%s:%s' is invalid : %s ", this.repoKey, this.key, e.getMessage())); - } - } - -} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/server/rule/RuleTagsToTypeConverter.java b/sonar-plugin-api/src/main/java/org/sonar/api/server/rule/RuleTagsToTypeConverter.java index f5948b7a2cc..13175b65cba 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/server/rule/RuleTagsToTypeConverter.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/server/rule/RuleTagsToTypeConverter.java @@ -31,18 +31,18 @@ import static java.util.Collections.unmodifiableSet; * @see org.sonar.api.server.rule.RulesDefinition.NewRule#setType(RuleType) * @since 5.5 */ -class RuleTagsToTypeConverter { +public class RuleTagsToTypeConverter { public static final String TAG_BUG = "bug"; public static final String TAG_SECURITY = "security"; - static final Set<String> RESERVED_TAGS = unmodifiableSet(new HashSet<>(asList(TAG_BUG, TAG_SECURITY))); + public static final Set<String> RESERVED_TAGS = unmodifiableSet(new HashSet<>(asList(TAG_BUG, TAG_SECURITY))); private RuleTagsToTypeConverter() { // only statics } - static RuleType convert(Collection<String> tags) { + public static RuleType convert(Collection<String> tags) { if (tags.contains(TAG_BUG)) { return RuleType.BUG; } 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 c5a494dc23b..6ad36f5998e 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 @@ -19,45 +19,23 @@ */ package org.sonar.api.server.rule; -import java.io.IOException; import java.net.URL; -import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; import java.util.List; -import java.util.Locale; -import java.util.Map; import java.util.Set; -import java.util.TreeSet; import javax.annotation.CheckForNull; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang.StringUtils; import org.sonar.api.ExtensionPoint; import org.sonar.api.ce.ComputeEngineSide; import org.sonar.api.rule.RuleKey; import org.sonar.api.rule.RuleScope; import org.sonar.api.rule.RuleStatus; -import org.sonar.api.rule.Severity; import org.sonar.api.rules.RuleType; import org.sonar.api.server.ServerSide; import org.sonar.api.server.debt.DebtRemediationFunction; -import org.sonar.api.utils.log.Loggers; import org.sonarsource.api.sonarlint.SonarLintSide; -import static java.lang.String.format; -import static java.nio.charset.StandardCharsets.UTF_8; -import static java.util.Collections.emptyList; -import static java.util.Collections.unmodifiableList; -import static java.util.Collections.unmodifiableMap; -import static org.apache.commons.lang.StringUtils.defaultIfEmpty; -import static org.apache.commons.lang.StringUtils.isEmpty; -import static org.apache.commons.lang.StringUtils.trimToNull; -import static org.sonar.api.utils.Preconditions.checkArgument; -import static org.sonar.api.utils.Preconditions.checkState; - /** * Defines some coding rules of the same repository. For example the Java Findbugs plugin provides an implementation of * this extension point in order to define the rules that it supports. @@ -369,20 +347,15 @@ public interface RulesDefinition { /** * Instantiated by core but not by plugins, except for their tests. */ - class Context { - private final Map<String, Repository> repositoriesByKey = new HashMap<>(); - private String currentPluginKey; - - /** + interface Context { + /* * New builder for {@link org.sonar.api.server.rule.RulesDefinition.Repository}. * <br> * A plugin can add rules to a repository that is defined then executed by another plugin. For instance * the FbContrib plugin contributes to the Findbugs plugin rules. In this case no need * to execute {@link org.sonar.api.server.rule.RulesDefinition.NewRepository#setName(String)} */ - public NewRepository createRepository(String key, String language) { - return new NewRepositoryImpl(this, key, language, false); - } + NewRepository createRepository(String key, String language); /** * Creates a repository of rules from external rule engines. @@ -390,59 +363,34 @@ public interface RulesDefinition { * * @since 7.2 */ - public NewRepository createExternalRepository(String engineId, String language) { - return new NewRepositoryImpl(this, RuleKey.EXTERNAL_RULE_REPO_PREFIX + engineId, language, true); - } + NewRepository createExternalRepository(String engineId, String language); /** * @deprecated since 5.2. Simply use {@link #createRepository(String, String)} */ @Deprecated - public NewRepository extendRepository(String key, String language) { - return createRepository(key, language); - } + NewRepository extendRepository(String key, String language); @CheckForNull - public Repository repository(String key) { - return repositoriesByKey.get(key); - } + Repository repository(String key); - public List<Repository> repositories() { - return unmodifiableList(new ArrayList<>(repositoriesByKey.values())); - } + List<Repository> repositories(); /** * @deprecated returns empty list since 5.2. Concept of "extended repository" was misleading and not valuable. Simply declare * repositories and use {@link #repositories()}. See http://jira.sonarsource.com/browse/SONAR-6709 */ @Deprecated - public List<ExtendedRepository> extendedRepositories(String repositoryKey) { - return emptyList(); - } + List<ExtendedRepository> extendedRepositories(String repositoryKey); /** * @deprecated returns empty list since 5.2. Concept of "extended repository" was misleading and not valuable. Simply declare * repositories and use {@link #repositories()}. See http://jira.sonarsource.com/browse/SONAR-6709 */ @Deprecated - public List<ExtendedRepository> extendedRepositories() { - return emptyList(); - } + List<ExtendedRepository> extendedRepositories(); - private void registerRepository(NewRepositoryImpl newRepository) { - Repository existing = repositoriesByKey.get(newRepository.key()); - if (existing != null) { - String existingLanguage = existing.language(); - checkState(existingLanguage.equals(newRepository.language), - "The rule repository '%s' must not be defined for two different languages: %s and %s", - newRepository.key, existingLanguage, newRepository.language); - } - repositoriesByKey.put(newRepository.key, new RepositoryImpl(newRepository, existing)); - } - - public void setCurrentPluginKey(@Nullable String pluginKey) { - this.currentPluginKey = pluginKey; - } + void setCurrentPluginKey(@Nullable String pluginKey); } interface NewExtendedRepository { @@ -477,77 +425,6 @@ public interface RulesDefinition { A1, A2, A3, A4, A5, A6, A7, A8, A9, A10; } - class NewRepositoryImpl implements NewRepository { - private final Context context; - private final String key; - private final boolean isExternal; - private String language; - private String name; - private final Map<String, NewRule> newRules = new HashMap<>(); - - private NewRepositoryImpl(Context context, String key, String language, boolean isExternal) { - this.context = context; - this.key = key; - this.name = key; - this.language = language; - this.isExternal = isExternal; - } - - @Override - public boolean isExternal() { - return isExternal; - } - - @Override - public String key() { - return key; - } - - @Override - public NewRepositoryImpl setName(@Nullable String s) { - if (StringUtils.isNotEmpty(s)) { - this.name = s; - } - return this; - } - - @Override - public NewRule createRule(String ruleKey) { - checkArgument(!newRules.containsKey(ruleKey), "The rule '%s' of repository '%s' is declared several times", ruleKey, key); - NewRule newRule = new NewRule(context.currentPluginKey, key, ruleKey); - newRules.put(ruleKey, newRule); - return newRule; - } - - @CheckForNull - @Override - public NewRule rule(String ruleKey) { - return newRules.get(ruleKey); - } - - @Override - public Collection<NewRule> rules() { - return newRules.values(); - } - - @Override - public void done() { - // note that some validations can be done here, for example for - // verifying that at least one rule is declared - - context.registerRepository(this); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder("NewRepository{"); - sb.append("key='").append(key).append('\''); - sb.append(", language='").append(language).append('\''); - sb.append('}'); - return sb.toString(); - } - } - interface ExtendedRepository { String key(); @@ -568,98 +445,6 @@ public interface RulesDefinition { boolean isExternal(); } - @Immutable - class RepositoryImpl implements Repository { - private final String key; - private final String language; - private final String name; - private final boolean isExternal; - private final Map<String, Rule> rulesByKey; - - private RepositoryImpl(NewRepositoryImpl newRepository, @Nullable Repository mergeInto) { - this.key = newRepository.key; - this.language = newRepository.language; - this.isExternal = newRepository.isExternal; - Map<String, Rule> ruleBuilder = new HashMap<>(); - if (mergeInto != null) { - if (!StringUtils.equals(newRepository.language, mergeInto.language()) || !StringUtils.equals(newRepository.key, mergeInto.key())) { - throw new IllegalArgumentException(format("Bug - language and key of the repositories to be merged should be the sames: %s and %s", newRepository, mergeInto)); - } - this.name = StringUtils.defaultIfBlank(mergeInto.name(), newRepository.name); - for (Rule rule : mergeInto.rules()) { - if (!newRepository.key().startsWith("common-") && ruleBuilder.containsKey(rule.key())) { - Loggers.get(getClass()).warn("The rule '{}' of repository '{}' is declared several times", rule.key(), mergeInto.key()); - } - ruleBuilder.put(rule.key(), rule); - } - } else { - this.name = newRepository.name; - } - for (NewRule newRule : newRepository.newRules.values()) { - newRule.validate(); - ruleBuilder.put(newRule.key, new Rule(this, newRule)); - } - this.rulesByKey = unmodifiableMap(ruleBuilder); - } - - @Override - public String key() { - return key; - } - - @Override - public String language() { - return language; - } - - @Override - public String name() { - return name; - } - - @Override - public boolean isExternal() { - return isExternal; - } - - @Override - @CheckForNull - public Rule rule(String ruleKey) { - return rulesByKey.get(ruleKey); - } - - @Override - public List<Rule> rules() { - return unmodifiableList(new ArrayList<>(rulesByKey.values())); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - RepositoryImpl that = (RepositoryImpl) o; - return key.equals(that.key); - } - - @Override - public int hashCode() { - return key.hashCode(); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder("Repository{"); - sb.append("key='").append(key).append('\''); - sb.append(", language='").append(language).append('\''); - sb.append('}'); - return sb.toString(); - } - } - /** * Factory of {@link org.sonar.api.server.debt.DebtRemediationFunction}. */ @@ -699,83 +484,36 @@ public interface RulesDefinition { DebtRemediationFunction create(DebtRemediationFunction.Type type, @Nullable String gapMultiplier, @Nullable String baseEffort); } - class NewRule { - private final String pluginKey; - private final String repoKey; - private final String key; - private RuleType type; - private String name; - private String htmlDescription; - private String markdownDescription; - private String internalKey; - private String severity = Severity.MAJOR; - private boolean template; - private RuleStatus status = RuleStatus.defaultStatus(); - private DebtRemediationFunction debtRemediationFunction; - private String gapDescription; - private final Set<String> tags = new TreeSet<>(); - private final Set<String> securityStandards = new TreeSet<>(); - private final Map<String, NewParam> paramsByKey = new HashMap<>(); - private final DebtRemediationFunctions functions; - private boolean activatedByDefault; - private RuleScope scope; - private final Set<RuleKey> deprecatedRuleKeys = new TreeSet<>(); - - private NewRule(@Nullable String pluginKey, String repoKey, String key) { - this.pluginKey = pluginKey; - this.repoKey = repoKey; - this.key = key; - this.functions = new DefaultDebtRemediationFunctions(repoKey, key); - } + interface NewRule { - public String key() { - return this.key; - } + String key(); /** * @since 7.1 */ @CheckForNull - public RuleScope scope() { - return this.scope; - } + RuleScope scope(); /** * @since 7.1 */ - public NewRule setScope(RuleScope scope) { - this.scope = scope; - return this; - } + NewRule setScope(RuleScope scope); /** * Required rule name */ - public NewRule setName(String s) { - this.name = trimToNull(s); - return this; - } + NewRule setName(String s); - public NewRule setTemplate(boolean template) { - this.template = template; - return this; - } + NewRule setTemplate(boolean template); /** * Should this rule be enabled by default. For example in SonarLint standalone. * * @since 6.0 */ - public NewRule setActivatedByDefault(boolean activatedByDefault) { - this.activatedByDefault = activatedByDefault; - return this; - } + NewRule setActivatedByDefault(boolean activatedByDefault); - public NewRule setSeverity(String s) { - checkArgument(Severity.ALL.contains(s), "Severity of rule %s is not correct: %s", this, s); - this.severity = s; - return this; - } + NewRule setSeverity(String s); /** * The type as defined by the SonarQube Quality Model. @@ -793,73 +531,36 @@ public interface RulesDefinition { * * @since 5.5 */ - public NewRule setType(RuleType t) { - this.type = t; - return this; - } + NewRule setType(RuleType t); /** * The optional description, in HTML format, has no max length. It's exclusive with markdown description * (see {@link #setMarkdownDescription(String)}) */ - public NewRule setHtmlDescription(@Nullable String s) { - checkState(markdownDescription == null, "Rule '%s' already has a Markdown description", this); - this.htmlDescription = trimToNull(s); - return this; - } + NewRule setHtmlDescription(@Nullable String s); /** * Load description from a file available in classpath. Example : <code>setHtmlDescription(getClass().getResource("/myrepo/Rule1234.html")</code> */ - public NewRule setHtmlDescription(@Nullable URL classpathUrl) { - if (classpathUrl != null) { - try { - setHtmlDescription(IOUtils.toString(classpathUrl, UTF_8)); - } catch (IOException e) { - throw new IllegalStateException("Fail to read: " + classpathUrl, e); - } - } else { - this.htmlDescription = null; - } - return this; - } + NewRule setHtmlDescription(@Nullable URL classpathUrl); /** * The optional description, in a restricted Markdown format, has no max length. It's exclusive with HTML description * (see {@link #setHtmlDescription(String)}) */ - public NewRule setMarkdownDescription(@Nullable String s) { - checkState(htmlDescription == null, "Rule '%s' already has an HTML description", this); - this.markdownDescription = trimToNull(s); - return this; - } + NewRule setMarkdownDescription(@Nullable String s); /** * Load description from a file available in classpath. Example : {@code setMarkdownDescription(getClass().getResource("/myrepo/Rule1234.md")} */ - public NewRule setMarkdownDescription(@Nullable URL classpathUrl) { - if (classpathUrl != null) { - try { - setMarkdownDescription(IOUtils.toString(classpathUrl, UTF_8)); - } catch (IOException e) { - throw new IllegalStateException("Fail to read: " + classpathUrl, e); - } - } else { - this.markdownDescription = null; - } - return this; - } + NewRule setMarkdownDescription(@Nullable URL classpathUrl); /** * Default value is {@link org.sonar.api.rule.RuleStatus#READY}. The value * {@link org.sonar.api.rule.RuleStatus#REMOVED} is not accepted and raises an * {@link java.lang.IllegalArgumentException}. */ - public NewRule setStatus(RuleStatus status) { - checkArgument(RuleStatus.REMOVED != status, "Status 'REMOVED' is not accepted on rule '%s'", this); - this.status = status; - return this; - } + NewRule setStatus(RuleStatus status); /** * SQALE sub-characteristic. See http://www.sqale.org @@ -869,32 +570,23 @@ public interface RulesDefinition { * @deprecated in 5.5. SQALE Quality Model is replaced by SonarQube Quality Model. This method does nothing. * See https://jira.sonarsource.com/browse/MMF-184 */ - public NewRule setDebtSubCharacteristic(@Nullable String s) { - return this; - } + NewRule setDebtSubCharacteristic(@Nullable String s); /** * Factory of {@link org.sonar.api.server.debt.DebtRemediationFunction} */ - public DebtRemediationFunctions debtRemediationFunctions() { - return functions; - } + DebtRemediationFunctions debtRemediationFunctions(); /** * @see #debtRemediationFunctions() */ - public NewRule setDebtRemediationFunction(@Nullable DebtRemediationFunction fn) { - this.debtRemediationFunction = fn; - return this; - } + NewRule setDebtRemediationFunction(@Nullable DebtRemediationFunction fn); /** * @deprecated since 5.5, replaced by {@link #setGapDescription(String)} */ @Deprecated - public NewRule setEffortToFixDescription(@Nullable String s) { - return setGapDescription(s); - } + NewRule setEffortToFixDescription(@Nullable String s); /** * For rules that use LINEAR or LINEAR_OFFSET remediation functions, the meaning @@ -905,90 +597,44 @@ public interface RulesDefinition { * remediation function gap multiplier/base effort would be something like * "Effort to test one uncovered condition". */ - public NewRule setGapDescription(@Nullable String s) { - this.gapDescription = s; - return this; - } + NewRule setGapDescription(@Nullable String s); /** * Create a parameter with given unique key. Max length of key is 128 characters. */ - public NewParam createParam(String paramKey) { - checkArgument(!paramsByKey.containsKey(paramKey), "The parameter '%s' is declared several times on the rule %s", paramKey, this); - NewParam param = new NewParam(paramKey); - paramsByKey.put(paramKey, param); - return param; - } + NewParam createParam(String paramKey); @CheckForNull - public NewParam param(String paramKey) { - return paramsByKey.get(paramKey); - } + NewParam param(String paramKey); - public Collection<NewParam> params() { - return paramsByKey.values(); - } + Collection<NewParam> params(); /** * @see RuleTagFormat */ - public NewRule addTags(String... list) { - for (String tag : list) { - RuleTagFormat.validate(tag); - tags.add(tag); - } - return this; - } + NewRule addTags(String... list); /** * @see RuleTagFormat */ - public NewRule setTags(String... list) { - tags.clear(); - addTags(list); - return this; - } + NewRule setTags(String... list); /** * @since 7.3 */ - public NewRule addOwaspTop10(OwaspTop10... standards) { - for (OwaspTop10 owaspTop10 : standards) { - String standard = "owaspTop10:" + owaspTop10.name().toLowerCase(Locale.ENGLISH); - securityStandards.add(standard); - } - return this; - } + NewRule addOwaspTop10(OwaspTop10... standards); /** * @since 7.3 */ - public NewRule addCwe(int... nums) { - for (int num : nums) { - String standard = "cwe:" + num; - securityStandards.add(standard); - } - return this; - } + NewRule addCwe(int... nums); /** * Optional key that can be used by the rule engine. Not displayed * in webapp. For example the Java Checkstyle plugin feeds this field * with the internal path ("Checker/TreeWalker/AnnotationUseStyle"). */ - public NewRule setInternalKey(@Nullable String s) { - this.internalKey = s; - return this; - } - - private void validate() { - if (isEmpty(name)) { - throw new IllegalStateException(format("Name of rule %s is empty", this)); - } - if (isEmpty(htmlDescription) && isEmpty(markdownDescription)) { - throw new IllegalStateException(format("One of HTML description or Markdown description must be defined for rule %s", this)); - } - } + NewRule setInternalKey(@Nullable String s); /** * Register a repository and key under which this rule used to be known @@ -1000,134 +646,56 @@ public interface RulesDefinition { * @see Rule#deprecatedRuleKeys * @since 7.1 */ - public NewRule addDeprecatedRuleKey(String repository, String key) { - deprecatedRuleKeys.add(RuleKey.of(repository, key)); - return this; - } + NewRule addDeprecatedRuleKey(String repository, String key); @Override - public String toString() { - return format("[repository=%s, key=%s]", repoKey, key); - } + String toString(); } @Immutable - class Rule { - private final String pluginKey; - private final Repository repository; - private final String repoKey; - private final String key; - private final String name; - private final RuleType type; - private final String htmlDescription; - private final String markdownDescription; - private final String internalKey; - private final String severity; - private final boolean template; - private final DebtRemediationFunction debtRemediationFunction; - private final String gapDescription; - private final Set<String> tags; - private final Set<String> securityStandards; - private final Map<String, Param> params; - private final RuleStatus status; - private final boolean activatedByDefault; - private final RuleScope scope; - private final Set<RuleKey> deprecatedRuleKeys; - - private Rule(Repository repository, NewRule newRule) { - this.pluginKey = newRule.pluginKey; - this.repository = repository; - this.repoKey = newRule.repoKey; - this.key = newRule.key; - this.name = newRule.name; - this.htmlDescription = newRule.htmlDescription; - this.markdownDescription = newRule.markdownDescription; - this.internalKey = newRule.internalKey; - this.severity = newRule.severity; - this.template = newRule.template; - this.status = newRule.status; - this.debtRemediationFunction = newRule.debtRemediationFunction; - this.gapDescription = newRule.gapDescription; - this.scope = newRule.scope == null ? RuleScope.MAIN : newRule.scope; - this.type = newRule.type == null ? RuleTagsToTypeConverter.convert(newRule.tags) : newRule.type; - Set<String> tagsBuilder = new TreeSet<>(newRule.tags); - tagsBuilder.removeAll(RuleTagsToTypeConverter.RESERVED_TAGS); - this.tags = Collections.unmodifiableSet(tagsBuilder); - this.securityStandards = Collections.unmodifiableSet(new TreeSet<>(newRule.securityStandards)); - Map<String, Param> paramsBuilder = new HashMap<>(); - for (NewParam newParam : newRule.paramsByKey.values()) { - paramsBuilder.put(newParam.key, new Param(newParam)); - } - this.params = Collections.unmodifiableMap(paramsBuilder); - this.activatedByDefault = newRule.activatedByDefault; - this.deprecatedRuleKeys = Collections.unmodifiableSet(new TreeSet<>(newRule.deprecatedRuleKeys)); - } + interface Rule { - public Repository repository() { - return repository; - } + Repository repository(); /** * @since 6.6 the plugin the rule was declared in */ @CheckForNull - public String pluginKey() { - return pluginKey; - } + String pluginKey(); - public String key() { - return key; - } + String key(); - public String name() { - return name; - } + String name(); /** * @since 7.1 */ - public RuleScope scope() { - return scope; - } + RuleScope scope(); /** * @see NewRule#setType(RuleType) * @since 5.5 */ - public RuleType type() { - return type; - } + RuleType type(); - public String severity() { - return severity; - } + String severity(); @CheckForNull - public String htmlDescription() { - return htmlDescription; - } + String htmlDescription(); @CheckForNull - public String markdownDescription() { - return markdownDescription; - } + String markdownDescription(); - public boolean template() { - return template; - } + boolean template(); /** * Should this rule be enabled by default. For example in SonarLint standalone. * * @since 6.0 */ - public boolean activatedByDefault() { - return activatedByDefault; - } + boolean activatedByDefault(); - public RuleStatus status() { - return status; - } + RuleStatus status(); /** * @see #type() @@ -1136,45 +704,29 @@ public interface RulesDefinition { */ @CheckForNull @Deprecated - public String debtSubCharacteristic() { - return null; - } + String debtSubCharacteristic(); @CheckForNull - public DebtRemediationFunction debtRemediationFunction() { - return debtRemediationFunction; - } + DebtRemediationFunction debtRemediationFunction(); /** * @deprecated since 5.5, replaced by {@link #gapDescription()} */ @Deprecated @CheckForNull - public String effortToFixDescription() { - return gapDescription(); - } + String effortToFixDescription(); @CheckForNull - public String gapDescription() { - return gapDescription; - } + String gapDescription(); @CheckForNull - public Param param(String key) { - return params.get(key); - } + Param param(String key); - public List<Param> params() { - return unmodifiableList(new ArrayList<>(params.values())); - } + List<Param> params(); - public Set<String> tags() { - return tags; - } + Set<String> tags(); - public Set<String> securityStandards() { - return securityStandards; - } + Set<String> securityStandards(); /** * Deprecated rules keys for this rule. @@ -1234,140 +786,47 @@ public interface RulesDefinition { * @see NewRule#addDeprecatedRuleKey(String, String) * @since 7.1 */ - public Set<RuleKey> deprecatedRuleKeys() { - return deprecatedRuleKeys; - } + Set<RuleKey> deprecatedRuleKeys(); /** * @see RulesDefinition.NewRule#setInternalKey(String) */ @CheckForNull - public String internalKey() { - return internalKey; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Rule other = (Rule) o; - return key.equals(other.key) && repoKey.equals(other.repoKey); - } + String internalKey(); - @Override - public int hashCode() { - int result = repoKey.hashCode(); - result = 31 * result + key.hashCode(); - return result; - } - - @Override - public String toString() { - return format("[repository=%s, key=%s]", repoKey, key); - } } - class NewParam { - private final String key; - private String name; - private String description; - private String defaultValue; - private RuleParamType type = RuleParamType.STRING; - - private NewParam(String key) { - this.key = this.name = key; - } - - public String key() { - return key; - } + interface NewParam { + String key(); - public NewParam setName(@Nullable String s) { - // name must never be null. - this.name = StringUtils.defaultIfBlank(s, key); - return this; - } + NewParam setName(@Nullable String s); - public NewParam setType(RuleParamType t) { - this.type = t; - return this; - } + NewParam setType(RuleParamType t); /** * Plain-text description. Can be null. Max length is 4000 characters. */ - public NewParam setDescription(@Nullable String s) { - this.description = StringUtils.defaultIfBlank(s, null); - return this; - } + NewParam setDescription(@Nullable String s); /** * Empty default value will be converted to null. Max length is 4000 characters. */ - public NewParam setDefaultValue(@Nullable String s) { - this.defaultValue = defaultIfEmpty(s, null); - return this; - } + NewParam setDefaultValue(@Nullable String s); } @Immutable - class Param { - private final String key; - private final String name; - private final String description; - private final String defaultValue; - private final RuleParamType type; - - private Param(NewParam newParam) { - this.key = newParam.key; - this.name = newParam.name; - this.description = newParam.description; - this.defaultValue = newParam.defaultValue; - this.type = newParam.type; - } - - public String key() { - return key; - } + interface Param { + String key(); - public String name() { - return name; - } + String name(); @Nullable - public String description() { - return description; - } + String description(); @Nullable - public String defaultValue() { - return defaultValue; - } - - public RuleParamType type() { - return type; - } + String defaultValue(); - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Param that = (Param) o; - return key.equals(that.key); - } - - @Override - public int hashCode() { - return key.hashCode(); - } + RuleParamType type(); } /** diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/server/rule/RulesDefinitionAnnotationLoaderTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/server/rule/RulesDefinitionAnnotationLoaderTest.java index 888702ddfc5..bf7678ab757 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/server/rule/RulesDefinitionAnnotationLoaderTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/server/rule/RulesDefinitionAnnotationLoaderTest.java @@ -25,6 +25,7 @@ import org.sonar.api.rule.RuleStatus; import org.sonar.api.rule.Severity; import org.sonar.api.server.rule.RulesDefinition.NewRule; import org.sonar.check.Priority; +import org.sonar.server.rule.RuleDefinitionContext; import static org.assertj.core.api.Assertions.assertThat; @@ -57,7 +58,7 @@ public class RulesDefinitionAnnotationLoaderTest { @Test public void override_annotation_programmatically() { - RulesDefinition.Context context = new RulesDefinition.Context(); + RulesDefinition.Context context = new RuleDefinitionContext(); RulesDefinition.NewRepository newRepository = context.createRepository("squid", "java"); NewRule newRule = annotationLoader.loadRule(newRepository, RuleWithProperty.class); newRule.setName("Overridden name"); @@ -144,7 +145,7 @@ public class RulesDefinitionAnnotationLoaderTest { } private RulesDefinition.Repository load(Class annotatedClass) { - RulesDefinition.Context context = new RulesDefinition.Context(); + RulesDefinition.Context context = new RuleDefinitionContext(); RulesDefinition.NewExtendedRepository newRepository = context.createRepository("squid", "java"); annotationLoader.load(newRepository, annotatedClass); newRepository.done(); diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/server/rule/RulesDefinitionI18nLoaderTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/server/rule/RulesDefinitionI18nLoaderTest.java index db3fcfeb40f..d7c0ab4e3d8 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/server/rule/RulesDefinitionI18nLoaderTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/server/rule/RulesDefinitionI18nLoaderTest.java @@ -21,6 +21,7 @@ package org.sonar.api.server.rule; import org.junit.Test; import org.sonar.api.i18n.RuleI18n; +import org.sonar.server.rule.RuleDefinitionContext; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -36,7 +37,7 @@ public class RulesDefinitionI18nLoaderTest { when(i18n.getName("squid", "S0001")).thenReturn("SOne"); when(i18n.getDescription("squid", "S0001")).thenReturn("S One"); - RulesDefinition.Context context = new RulesDefinition.Context(); + RulesDefinition.Context context = new RuleDefinitionContext(); RulesDefinition.NewRepository repo = context.createRepository("squid", "java"); // rule without description repo.createRule("S0001"); @@ -53,7 +54,7 @@ public class RulesDefinitionI18nLoaderTest { public void do_not_override_if_no_bundle() { // i18n returns null values - RulesDefinition.Context context = new RulesDefinition.Context(); + RulesDefinition.Context context = new RuleDefinitionContext(); RulesDefinition.NewRepository repo = context.createRepository("squid", "java"); repo.createRule("S0001").setName("SOne").setHtmlDescription("S One"); @@ -70,7 +71,7 @@ public class RulesDefinitionI18nLoaderTest { when(i18n.getName("squid", "S0001")).thenReturn("SOne"); when(i18n.getDescription("squid", "S0001")).thenReturn("S One"); - RulesDefinition.Context context = new RulesDefinition.Context(); + RulesDefinition.Context context = new RuleDefinitionContext(); RulesDefinition.NewRepository repo = context.createRepository("squid", "java"); repo.createRule("S0001").setName("Bad").setHtmlDescription("Bad"); @@ -86,7 +87,7 @@ public class RulesDefinitionI18nLoaderTest { public void complete_param_description() { when(i18n.getParamDescription("squid", "S0001", "max")).thenReturn("Maximum"); - RulesDefinition.Context context = new RulesDefinition.Context(); + RulesDefinition.Context context = new RuleDefinitionContext(); RulesDefinition.NewRepository repo = context.createRepository("squid", "java"); repo.createRule("S0001").setName("SOne").setHtmlDescription("S One").createParam("max"); diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/server/rule/RulesDefinitionTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/server/rule/RulesDefinitionTest.java index 468ada4317b..50eea7cf408 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/server/rule/RulesDefinitionTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/server/rule/RulesDefinitionTest.java @@ -41,6 +41,7 @@ import org.sonar.api.rule.Severity; import org.sonar.api.rules.RuleType; import org.sonar.api.server.debt.DebtRemediationFunction; import org.sonar.api.utils.log.LogTester; +import org.sonar.server.rule.RuleDefinitionContext; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.fail; @@ -48,7 +49,7 @@ import static org.junit.Assert.fail; @RunWith(DataProviderRunner.class) public class RulesDefinitionTest { - RulesDefinition.Context context = new RulesDefinition.Context(); + RulesDefinition.Context context = new RuleDefinitionContext(); @Rule public LogTester logTester = new LogTester(); @@ -400,6 +401,7 @@ public class RulesDefinitionTest { /** * This is temporarily accepted only for the support of the common-rules that are still declared * by plugins. It could be removed in 7.0 + * * @since 5.2 */ @Test diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/server/rule/RulesDefinitionXmlLoaderTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/server/rule/RulesDefinitionXmlLoaderTest.java index 61111aa3847..3e180e3abca 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/server/rule/RulesDefinitionXmlLoaderTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/server/rule/RulesDefinitionXmlLoaderTest.java @@ -30,6 +30,7 @@ import org.sonar.api.rule.RuleStatus; import org.sonar.api.rule.Severity; import org.sonar.api.rules.RuleType; import org.sonar.api.server.debt.DebtRemediationFunction; +import org.sonar.server.rule.RuleDefinitionContext; import static org.assertj.core.api.Assertions.assertThat; import static org.sonar.api.utils.ExceptionCauseMatcher.hasType; @@ -294,7 +295,7 @@ public class RulesDefinitionXmlLoaderTest { } private RulesDefinition.Repository load(InputStream input, String encoding) { - RulesDefinition.Context context = new RulesDefinition.Context(); + RulesDefinition.Context context = new RuleDefinitionContext(); RulesDefinition.NewRepository newRepository = context.createRepository("squid", "java"); underTest.load(newRepository, input, encoding); newRepository.done(); @@ -302,7 +303,7 @@ public class RulesDefinitionXmlLoaderTest { } private RulesDefinition.Repository load(String xml) { - RulesDefinition.Context context = new RulesDefinition.Context(); + RulesDefinition.Context context = new RuleDefinitionContext(); RulesDefinition.NewRepository newRepository = context.createRepository("squid", "java"); underTest.load(newRepository, new StringReader(xml)); newRepository.done(); |