+++ /dev/null
-/*
- * 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.impl.server;
-
-import javax.annotation.Nullable;
-import org.sonar.api.server.debt.DebtRemediationFunction;
-import org.sonar.api.server.debt.internal.DefaultDebtRemediationFunction;
-import org.sonar.api.server.rule.RulesDefinition;
-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()));
- }
- }
-
-}
+++ /dev/null
-/*
- * 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.impl.server;
-
-import javax.annotation.Nullable;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.server.rule.RuleParamType;
-import org.sonar.api.server.rule.RulesDefinition;
-
-import static org.apache.commons.lang.StringUtils.defaultIfEmpty;
-
-public class DefaultNewParam extends RulesDefinition.NewParam {
- private final String key;
- private String name;
- private String description;
- private String defaultValue;
- private RuleParamType type = RuleParamType.STRING;
-
- DefaultNewParam(String key) {
- this.key = this.name = key;
- }
-
- @Override
- public String key() {
- return key;
- }
-
- @Override
- public DefaultNewParam setName(@Nullable String s) {
- // name must never be null.
- this.name = StringUtils.defaultIfBlank(s, key);
- return this;
- }
-
- @Override
- public DefaultNewParam setType(RuleParamType t) {
- this.type = t;
- return this;
- }
-
- @Override
- public DefaultNewParam setDescription(@Nullable String s) {
- this.description = StringUtils.defaultIfBlank(s, null);
- return this;
- }
-
- @Override
- public DefaultNewParam setDefaultValue(@Nullable String s) {
- this.defaultValue = defaultIfEmpty(s, null);
- return this;
- }
-
- public String name() {
- return name;
- }
-
- public String description() {
- return description;
- }
-
- public String defaultValue() {
- return defaultValue;
- }
-
- public RuleParamType type() {
- return type;
- }
-}
+++ /dev/null
-/*
- * 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.impl.server;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.server.rule.RulesDefinition;
-
-import static org.sonar.api.utils.Preconditions.checkArgument;
-
-public class DefaultNewRepository implements RulesDefinition.NewRepository {
- private final RulesDefinitionContext context;
- private final String key;
- private final boolean isExternal;
- private final String language;
- private String name;
- private final Map<String, RulesDefinition.NewRule> newRules = new HashMap<>();
-
- DefaultNewRepository(RulesDefinitionContext 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;
- }
-
- String language() {
- return language;
- }
-
- Map<String, RulesDefinition.NewRule> newRules() {
- return newRules;
- }
-
- String name() {
- return name;
- }
-
- @Override
- public DefaultNewRepository setName(@Nullable String s) {
- if (StringUtils.isNotEmpty(s)) {
- this.name = s;
- }
- return this;
- }
-
- @Override
- public RulesDefinition.NewRule createRule(String ruleKey) {
- checkArgument(!newRules.containsKey(ruleKey), "The rule '%s' of repository '%s' is declared several times", ruleKey, key);
- RulesDefinition.NewRule newRule = new DefaultNewRule(context.currentPluginKey(), key, ruleKey);
- newRules.put(ruleKey, newRule);
- return newRule;
- }
-
- @CheckForNull
- @Override
- public RulesDefinition.NewRule rule(String ruleKey) {
- return newRules.get(ruleKey);
- }
-
- @Override
- public Collection<RulesDefinition.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();
- }
-}
+++ /dev/null
-/*
- * 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.impl.server;
-
-import java.io.IOException;
-import java.net.URL;
-import java.util.Collection;
-import java.util.HashMap;
-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 org.apache.commons.io.IOUtils;
-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.debt.DebtRemediationFunction;
-import org.sonar.api.server.rule.RuleTagFormat;
-import org.sonar.api.server.rule.RulesDefinition;
-
-import static java.lang.String.format;
-import static java.nio.charset.StandardCharsets.UTF_8;
-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;
-
-class DefaultNewRule extends RulesDefinition.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, RulesDefinition.NewParam> paramsByKey = new HashMap<>();
- private final RulesDefinition.DebtRemediationFunctions functions;
- private boolean activatedByDefault;
- private RuleScope scope;
- private final Set<RuleKey> deprecatedRuleKeys = new TreeSet<>();
-
- DefaultNewRule(@Nullable String pluginKey, String repoKey, String key) {
- this.pluginKey = pluginKey;
- this.repoKey = repoKey;
- this.key = key;
- this.functions = new DefaultDebtRemediationFunctions(repoKey, key);
- }
-
- @Override
- public String key() {
- return this.key;
- }
-
- @CheckForNull
- @Override
- public RuleScope scope() {
- return this.scope;
- }
-
- @Override
- public DefaultNewRule setScope(RuleScope scope) {
- this.scope = scope;
- return this;
- }
-
- @Override
- public DefaultNewRule setName(String s) {
- this.name = trimToNull(s);
- return this;
- }
-
- @Override
- public DefaultNewRule setTemplate(boolean template) {
- this.template = template;
- return this;
- }
-
- @Override
- public DefaultNewRule setActivatedByDefault(boolean activatedByDefault) {
- this.activatedByDefault = activatedByDefault;
- return this;
- }
-
- @Override
- public DefaultNewRule setSeverity(String s) {
- checkArgument(Severity.ALL.contains(s), "Severity of rule %s is not correct: %s", this, s);
- this.severity = s;
- return this;
- }
-
- @Override
- public DefaultNewRule setType(RuleType t) {
- this.type = t;
- return this;
- }
-
- @Override
- public DefaultNewRule setHtmlDescription(@Nullable String s) {
- checkState(markdownDescription == null, "Rule '%s' already has a Markdown description", this);
- this.htmlDescription = trimToNull(s);
- return this;
- }
-
- @Override
- public DefaultNewRule 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;
- }
-
- @Override
- public DefaultNewRule setMarkdownDescription(@Nullable String s) {
- checkState(htmlDescription == null, "Rule '%s' already has an HTML description", this);
- this.markdownDescription = trimToNull(s);
- return this;
- }
-
- @Override
- public DefaultNewRule 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;
- }
-
- @Override
- public DefaultNewRule setStatus(RuleStatus status) {
- checkArgument(RuleStatus.REMOVED != status, "Status 'REMOVED' is not accepted on rule '%s'", this);
- this.status = status;
- return this;
- }
-
- @Override
- public DefaultNewRule setDebtSubCharacteristic(@Nullable String s) {
- return this;
- }
-
- @Override
- public RulesDefinition.DebtRemediationFunctions debtRemediationFunctions() {
- return functions;
- }
-
- @Override
- public DefaultNewRule setDebtRemediationFunction(@Nullable DebtRemediationFunction fn) {
- this.debtRemediationFunction = fn;
- return this;
- }
-
- @Deprecated
- @Override
- public DefaultNewRule setEffortToFixDescription(@Nullable String s) {
- return setGapDescription(s);
- }
-
- @Override
- public DefaultNewRule setGapDescription(@Nullable String s) {
- this.gapDescription = s;
- return this;
- }
-
- @Override
- public RulesDefinition.NewParam createParam(String paramKey) {
- checkArgument(!paramsByKey.containsKey(paramKey), "The parameter '%s' is declared several times on the rule %s", paramKey, this);
- DefaultNewParam param = new DefaultNewParam(paramKey);
- paramsByKey.put(paramKey, param);
- return param;
- }
-
- @CheckForNull
- @Override
- public RulesDefinition.NewParam param(String paramKey) {
- return paramsByKey.get(paramKey);
- }
-
- @Override
- public Collection<RulesDefinition.NewParam> params() {
- return paramsByKey.values();
- }
-
- @Override
- public DefaultNewRule addTags(String... list) {
- for (String tag : list) {
- RuleTagFormat.validate(tag);
- tags.add(tag);
- }
- return this;
- }
-
- @Override
- public DefaultNewRule setTags(String... list) {
- tags.clear();
- addTags(list);
- return this;
- }
-
- @Override
- public DefaultNewRule addOwaspTop10(RulesDefinition.OwaspTop10... standards) {
- for (RulesDefinition.OwaspTop10 owaspTop10 : standards) {
- String standard = "owaspTop10:" + owaspTop10.name().toLowerCase(Locale.ENGLISH);
- securityStandards.add(standard);
- }
- return this;
- }
-
- @Override
- public DefaultNewRule addCwe(int... nums) {
- for (int num : nums) {
- String standard = "cwe:" + num;
- securityStandards.add(standard);
- }
- return this;
- }
-
- @Override
- public DefaultNewRule setInternalKey(@Nullable String s) {
- this.internalKey = s;
- return this;
- }
-
- 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));
- }
- }
-
- @Override
- public DefaultNewRule addDeprecatedRuleKey(String repository, String key) {
- deprecatedRuleKeys.add(RuleKey.of(repository, key));
- return this;
- }
-
- String pluginKey() {
- return pluginKey;
- }
-
- String repoKey() {
- return repoKey;
- }
-
- RuleType type() {
- return type;
- }
-
- String name() {
- return name;
- }
-
- String htmlDescription() {
- return htmlDescription;
- }
-
- String markdownDescription() {
- return markdownDescription;
- }
-
- @CheckForNull
- String internalKey() {
- return internalKey;
- }
-
- String severity() {
- return severity;
- }
-
- boolean template() {
- return template;
- }
-
- RuleStatus status() {
- return status;
- }
-
- DebtRemediationFunction debtRemediationFunction() {
- return debtRemediationFunction;
- }
-
- String gapDescription() {
- return gapDescription;
- }
-
- Set<String> tags() {
- return tags;
- }
-
- Set<String> securityStandards() {
- return securityStandards;
- }
-
- Map<String, RulesDefinition.NewParam> paramsByKey() {
- return paramsByKey;
- }
-
- boolean activatedByDefault() {
- return activatedByDefault;
- }
-
- Set<RuleKey> deprecatedRuleKeys() {
- return deprecatedRuleKeys;
- }
-
- @Override
- public String toString() {
- return format("[repository=%s, key=%s]", repoKey, key);
- }
-}
+++ /dev/null
-/*
- * 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.impl.server;
-
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.Immutable;
-import org.sonar.api.server.rule.RuleParamType;
-import org.sonar.api.server.rule.RulesDefinition;
-
-@Immutable
-public class DefaultParam implements RulesDefinition.Param {
- private final String key;
- private final String name;
- private final String description;
- private final String defaultValue;
- private final RuleParamType type;
-
- DefaultParam(DefaultNewParam newParam) {
- this.key = newParam.key();
- this.name = newParam.name();
- this.description = newParam.description();
- this.defaultValue = newParam.defaultValue();
- this.type = newParam.type();
- }
-
- @Override
- public String key() {
- return key;
- }
-
- @Override
- public String name() {
- return name;
- }
-
- @Override
- @Nullable
- public String description() {
- return description;
- }
-
- @Override
- @Nullable
- public String defaultValue() {
- return defaultValue;
- }
-
- @Override
- public RuleParamType type() {
- return type;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- RulesDefinition.Param that = (RulesDefinition.Param) o;
- return key.equals(that.key());
- }
-
- @Override
- public int hashCode() {
- return key.hashCode();
- }
-
-}
+++ /dev/null
-/*
- * 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.impl.server;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.Immutable;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.server.rule.RulesDefinition;
-import org.sonar.api.utils.log.Loggers;
-
-import static java.lang.String.format;
-import static java.util.Collections.unmodifiableList;
-import static java.util.Collections.unmodifiableMap;
-
-@Immutable
-class DefaultRepository implements RulesDefinition.Repository {
- private final String key;
- private final String language;
- private final String name;
- private final boolean isExternal;
- private final Map<String, RulesDefinition.Rule> rulesByKey;
-
- DefaultRepository(DefaultNewRepository newRepository, @Nullable RulesDefinition.Repository mergeInto) {
- this.key = newRepository.key();
- this.language = newRepository.language();
- this.isExternal = newRepository.isExternal();
- Map<String, RulesDefinition.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 (RulesDefinition.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 (RulesDefinition.NewRule newRule : newRepository.newRules().values()) {
- DefaultNewRule defaultNewRule = (DefaultNewRule) newRule;
- defaultNewRule.validate();
- ruleBuilder.put(newRule.key(), new DefaultRule(this, defaultNewRule));
- }
- 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 RulesDefinition.Rule rule(String ruleKey) {
- return rulesByKey.get(ruleKey);
- }
-
- @Override
- public List<RulesDefinition.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;
- }
- DefaultRepository that = (DefaultRepository) 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();
- }
-}
+++ /dev/null
-/*
- * 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.impl.server;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-import javax.annotation.CheckForNull;
-import javax.annotation.concurrent.Immutable;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.RuleScope;
-import org.sonar.api.rule.RuleStatus;
-import org.sonar.api.rules.RuleType;
-import org.sonar.api.server.debt.DebtRemediationFunction;
-import org.sonar.api.server.rule.RuleTagsToTypeConverter;
-import org.sonar.api.server.rule.RulesDefinition;
-
-import static java.lang.String.format;
-import static java.util.Collections.unmodifiableList;
-
-@Immutable
-public class DefaultRule implements RulesDefinition.Rule {
- private final String pluginKey;
- private final RulesDefinition.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, RulesDefinition.Param> params;
- private final RuleStatus status;
- private final boolean activatedByDefault;
- private final RuleScope scope;
- private final Set<RuleKey> deprecatedRuleKeys;
-
- DefaultRule(DefaultRepository repository, DefaultNewRule 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, RulesDefinition.Param> paramsBuilder = new HashMap<>();
- for (RulesDefinition.NewParam newParam : newRule.paramsByKey().values()) {
- paramsBuilder.put(newParam.key(), new DefaultParam((DefaultNewParam) newParam));
- }
- this.params = Collections.unmodifiableMap(paramsBuilder);
- this.activatedByDefault = newRule.activatedByDefault();
- this.deprecatedRuleKeys = Collections.unmodifiableSet(new TreeSet<>(newRule.deprecatedRuleKeys()));
- }
-
- public RulesDefinition.Repository repository() {
- return repository;
- }
-
- @Override
- @CheckForNull
- public String pluginKey() {
- return pluginKey;
- }
-
- @Override
- public String key() {
- return key;
- }
-
- @Override
- public String name() {
- return name;
- }
-
- @Override
- public RuleScope scope() {
- return scope;
- }
-
- @Override
- public RuleType type() {
- return type;
- }
-
- @Override
- public String severity() {
- return severity;
- }
-
- @Override
- @CheckForNull
- public String htmlDescription() {
- return htmlDescription;
- }
-
- @Override
- @CheckForNull
- public String markdownDescription() {
- return markdownDescription;
- }
-
- @Override
- public boolean template() {
- return template;
- }
-
- @Override
- public boolean activatedByDefault() {
- return activatedByDefault;
- }
-
- @Override
- public RuleStatus status() {
- return status;
- }
-
- @CheckForNull
- @Deprecated
- @Override
- public String debtSubCharacteristic() {
- return null;
- }
-
- @CheckForNull
- @Override
- public DebtRemediationFunction debtRemediationFunction() {
- return debtRemediationFunction;
- }
-
- @Deprecated
- @CheckForNull
- @Override
- public String effortToFixDescription() {
- return gapDescription();
- }
-
- @CheckForNull
- @Override
- public String gapDescription() {
- return gapDescription;
- }
-
- @CheckForNull
- @Override
- public RulesDefinition.Param param(String key) {
- return params.get(key);
- }
-
- @Override
- public List<RulesDefinition.Param> params() {
- return unmodifiableList(new ArrayList<>(params.values()));
- }
-
- @Override
- public Set<String> tags() {
- return tags;
- }
-
- @Override
- public Set<String> securityStandards() {
- return securityStandards;
- }
-
- @Override
- public Set<RuleKey> deprecatedRuleKeys() {
- return deprecatedRuleKeys;
- }
-
- @CheckForNull
- @Override
- public String internalKey() {
- return internalKey;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- DefaultRule other = (DefaultRule) o;
- return key.equals(other.key) && repoKey.equals(other.repoKey);
- }
-
- @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);
- }
-}
-
import javax.annotation.Nullable;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.server.rule.RulesDefinition;
+import org.sonar.api.server.rule.internal.DefaultNewRepository;
+import org.sonar.api.server.rule.internal.DefaultRepository;
import static java.util.Collections.emptyList;
import static java.util.Collections.unmodifiableList;
return emptyList();
}
- void registerRepository(DefaultNewRepository newRepository) {
+ public void registerRepository(DefaultNewRepository newRepository) {
RulesDefinition.Repository existing = repositoriesByKey.get(newRepository.key());
if (existing != null) {
String existingLanguage = existing.language();
+++ /dev/null
-/*
- * 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.impl.server;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.RuleScope;
-import org.sonar.api.rule.RuleStatus;
-import org.sonar.api.rules.RuleType;
-import org.sonar.api.server.debt.DebtRemediationFunction;
-import org.sonar.api.server.rule.RulesDefinition;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-
-public class DefaultNewRuleTest {
- @Rule
- public ExpectedException exception = ExpectedException.none();
-
- private DefaultNewRule rule = new DefaultNewRule("plugin", "repo", "key");
-
- @Test
- public void testSimpleSetGet() {
- assertThat(rule.pluginKey()).isEqualTo("plugin");
- assertThat(rule.repoKey()).isEqualTo("repo");
- assertThat(rule.key()).isEqualTo("key");
-
- rule.setScope(RuleScope.MAIN);
- assertThat(rule.scope()).isEqualTo(RuleScope.MAIN);
-
- rule.setName(" name ");
- assertThat(rule.name()).isEqualTo("name");
-
- rule.setHtmlDescription(" html ");
- assertThat(rule.htmlDescription()).isEqualTo("html");
-
- rule.setTemplate(true);
- assertThat(rule.template()).isTrue();
-
- rule.setActivatedByDefault(true);
- assertThat(rule.activatedByDefault()).isTrue();
-
- RulesDefinition.NewParam param1 = rule.createParam("param1");
- assertThat(rule.param("param1")).isEqualTo(param1);
- assertThat(rule.params()).containsOnly(param1);
-
- rule.setTags("tag1", "tag2");
- rule.addTags("tag3");
- assertThat(rule.tags()).containsExactly("tag1", "tag2", "tag3");
-
- rule.setEffortToFixDescription("effort");
- assertThat(rule.gapDescription()).isEqualTo("effort");
-
- rule.setGapDescription("gap");
- assertThat(rule.gapDescription()).isEqualTo("gap");
-
- rule.setInternalKey("internal");
- assertThat(rule.internalKey()).isEqualTo("internal");
-
- rule.addDeprecatedRuleKey("deprecatedrepo", "deprecatedkey");
- assertThat(rule.deprecatedRuleKeys()).containsOnly(RuleKey.of("deprecatedrepo", "deprecatedkey"));
-
- rule.setStatus(RuleStatus.READY);
- assertThat(rule.status()).isEqualTo(RuleStatus.READY);
-
- rule.addCwe(12);
- rule.addCwe(10);
- assertThat(rule.securityStandards()).containsOnly("cwe:10", "cwe:12");
-
- rule.setType(RuleType.SECURITY_HOTSPOT);
- assertThat(rule.type()).isEqualTo(RuleType.SECURITY_HOTSPOT);
-
- DebtRemediationFunction f = mock(DebtRemediationFunction.class);
- rule.setDebtRemediationFunction(f);
- assertThat(rule.debtRemediationFunction()).isEqualTo(f);
-
- rule.setSeverity("MAJOR");
- assertThat(rule.severity()).isEqualTo("MAJOR");
- }
-
- @Test
- public void validate_fails() {
- rule.setHtmlDescription("html");
- exception.expect(IllegalStateException.class);
- rule.validate();
- }
-
- @Test
- public void validate_succeeds() {
- rule.setHtmlDescription("html");
- rule.setName("name");
- rule.validate();
- }
-
- @Test
- public void set_markdown_description() {
- rule.setMarkdownDescription("markdown");
- assertThat(rule.markdownDescription()).isEqualTo("markdown");
- }
- @Test
- public void fail_if_severity_is_invalid() {
- exception.expect(IllegalArgumentException.class);
- rule.setSeverity("invalid");
- }
-
- @Test
- public void fail_setting_markdown_if_html_is_set() {
- exception.expect(IllegalStateException.class);
- rule.setHtmlDescription("html");
- rule.setMarkdownDescription("markdown");
- }
-
- @Test
- public void fail_if_set_status_to_removed() {
- exception.expect(IllegalArgumentException.class);
- rule.setStatus(RuleStatus.REMOVED);
- }
-}
+++ /dev/null
-/*
- * 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.impl.server;
-
-import org.junit.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-
-public class DefaultRepositoryTest {
- @Test
- public void create_simple_repo() {
- RulesDefinitionContext ctx = mock(RulesDefinitionContext.class);
- DefaultNewRepository newRepo = new DefaultNewRepository(ctx, "key", "lang", false);
- newRepo.createRule("rule1")
- .setName("rule1")
- .setHtmlDescription("desc");
- newRepo.setName("name");
- DefaultRepository repo = new DefaultRepository(newRepo, null);
-
- assertThat(repo.isExternal()).isFalse();
- assertThat(repo.key()).isEqualTo("key");
- assertThat(repo.language()).isEqualTo("lang");
- assertThat(repo.isExternal()).isFalse();
- assertThat(repo.name()).isEqualTo("name");
- assertThat(repo.rules()).extracting(r -> r.key()).containsOnly("rule1");
-
- }
-}
+++ /dev/null
-/*
- * 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.impl.server;
-
-import org.junit.Test;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.RuleScope;
-import org.sonar.api.rule.RuleStatus;
-import org.sonar.api.rules.RuleType;
-import org.sonar.api.server.debt.DebtRemediationFunction;
-import org.sonar.api.server.rule.RulesDefinition;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-
-public class DefaultRuleTest {
- @Test
- public void getters() {
- DefaultRepository repo = mock(DefaultRepository.class);
- DefaultNewRule rule = new DefaultNewRule("plugin", "repo", "key");
-
- rule.setScope(RuleScope.MAIN);
- rule.setName(" name ");
- rule.setHtmlDescription(" html ");
- rule.setTemplate(true);
- rule.setActivatedByDefault(true);
- RulesDefinition.NewParam param1 = rule.createParam("param1");
- rule.setTags("tag1", "tag2");
- rule.addTags("tag3");
- rule.setEffortToFixDescription("effort");
- rule.setGapDescription("gap");
- rule.setInternalKey("internal");
- rule.addDeprecatedRuleKey("deprecatedrepo", "deprecatedkey");
- rule.setStatus(RuleStatus.READY);
- rule.addCwe(12);
- rule.addCwe(10);
- rule.setType(RuleType.SECURITY_HOTSPOT);
- DebtRemediationFunction f = mock(DebtRemediationFunction.class);
- rule.setDebtRemediationFunction(f);
- rule.setSeverity("MAJOR");
-
- DefaultRule defaultRule = new DefaultRule(repo, rule);
- assertThat(defaultRule.scope()).isEqualTo(RuleScope.MAIN);
- assertThat(defaultRule.name()).isEqualTo("name");
- assertThat(defaultRule.htmlDescription()).isEqualTo("html");
- assertThat(defaultRule.template()).isTrue();
- assertThat(defaultRule.activatedByDefault()).isTrue();
- assertThat(defaultRule.params()).containsOnly(new DefaultParam(new DefaultNewParam("param1")));
- assertThat(defaultRule.tags()).containsOnly("tag1", "tag2", "tag3");
- assertThat(defaultRule.effortToFixDescription()).isEqualTo("gap");
- assertThat(defaultRule.gapDescription()).isEqualTo("gap");
- assertThat(defaultRule.internalKey()).isEqualTo("internal");
- assertThat(defaultRule.deprecatedRuleKeys()).containsOnly(RuleKey.of("deprecatedrepo", "deprecatedkey"));
- assertThat(defaultRule.status()).isEqualTo(RuleStatus.READY);
- assertThat(rule.securityStandards()).containsOnly("cwe:10", "cwe:12");
- assertThat(defaultRule.type()).isEqualTo(RuleType.SECURITY_HOTSPOT);
- assertThat(defaultRule.debtRemediationFunction()).isEqualTo(f);
- assertThat(defaultRule.markdownDescription()).isNull();
- assertThat(defaultRule.severity()).isEqualTo("MAJOR");
- }
-
- @Test
- public void to_string() {
- DefaultRepository repo = mock(DefaultRepository.class);
- DefaultNewRule rule = new DefaultNewRule("plugin", "repo", "key");
- DefaultRule defaultRule = new DefaultRule(repo, rule);
-
- assertThat(defaultRule.toString()).isEqualTo("[repository=repo, key=key]");
- }
-}
package org.sonar.api.server.rule;
import java.net.URL;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.api.rules.RuleType;
import org.sonar.api.server.ServerSide;
import org.sonar.api.server.debt.DebtRemediationFunction;
+import org.sonar.api.server.rule.internal.DefaultNewRepository;
+import org.sonar.api.server.rule.internal.DefaultRepository;
import org.sonarsource.api.sonarlint.SonarLintSide;
+import static java.util.Collections.emptyList;
+import static java.util.Collections.unmodifiableList;
+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.
}
}
+ /**
+ * This implementation will be removed as soon as analyzers stop instantiating it.
+ * Use RulesDefinitionContext in sonar-plugin-api-impl.
+ */
+ class Context extends AbstractContext {
+ private final Map<String, Repository> repositoriesByKey = new HashMap<>();
+ private String currentPluginKey;
+
+ @Override
+ public RulesDefinition.NewRepository createRepository(String key, String language) {
+ return new DefaultNewRepository(this, key, language, false);
+ }
+
+ @Override
+ public RulesDefinition.NewRepository createExternalRepository(String engineId, String language) {
+ return new DefaultNewRepository(this, RuleKey.EXTERNAL_RULE_REPO_PREFIX + engineId, language, true);
+ }
+
+ @Override
+ @Deprecated
+ public RulesDefinition.NewRepository extendRepository(String key, String language) {
+ return createRepository(key, language);
+ }
+
+ @Override
+ @CheckForNull
+ public RulesDefinition.Repository repository(String key) {
+ return repositoriesByKey.get(key);
+ }
+
+ @Override
+ public List<RulesDefinition.Repository> repositories() {
+ return unmodifiableList(new ArrayList<>(repositoriesByKey.values()));
+ }
+
+ @Override
+ @Deprecated
+ public List<RulesDefinition.ExtendedRepository> extendedRepositories(String repositoryKey) {
+ return emptyList();
+ }
+
+ @Override
+ @Deprecated
+ public List<RulesDefinition.ExtendedRepository> extendedRepositories() {
+ return emptyList();
+ }
+
+ public void registerRepository(DefaultNewRepository newRepository) {
+ RulesDefinition.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 DefaultRepository(newRepository, existing));
+ }
+
+ public String currentPluginKey() {
+ return currentPluginKey;
+ }
+
+ @Override
+ public void setCurrentPluginKey(@Nullable String pluginKey) {
+ this.currentPluginKey = pluginKey;
+ }
+ }
+
/**
* Instantiated by core but not by plugins, except for their tests.
*/
- abstract class Context {
+ abstract class AbstractContext {
/*
* New builder for {@link org.sonar.api.server.rule.RulesDefinition.Repository}.
* <br>
}
@Immutable
- interface Rule {
+ abstract class Rule {
- Repository repository();
+ public abstract Repository repository();
/**
* @since 6.6 the plugin the rule was declared in
*/
@CheckForNull
- String pluginKey();
+ public abstract String pluginKey();
- String key();
+ public abstract String key();
- String name();
+ public abstract String name();
/**
* @since 7.1
*/
- RuleScope scope();
+ public abstract RuleScope scope();
/**
* @see NewRule#setType(RuleType)
* @since 5.5
*/
- RuleType type();
+ public abstract RuleType type();
- String severity();
+ public abstract String severity();
@CheckForNull
- String htmlDescription();
+ public abstract String htmlDescription();
@CheckForNull
- String markdownDescription();
+ public abstract String markdownDescription();
- boolean template();
+ public abstract boolean template();
/**
* Should this rule be enabled by default. For example in SonarLint standalone.
*
* @since 6.0
*/
- boolean activatedByDefault();
+ public abstract boolean activatedByDefault();
- RuleStatus status();
+ public abstract RuleStatus status();
/**
* @see #type()
*/
@CheckForNull
@Deprecated
- String debtSubCharacteristic();
+ public abstract String debtSubCharacteristic();
@CheckForNull
- DebtRemediationFunction debtRemediationFunction();
+ public abstract DebtRemediationFunction debtRemediationFunction();
/**
* @deprecated since 5.5, replaced by {@link #gapDescription()}
*/
@Deprecated
@CheckForNull
- String effortToFixDescription();
+ public abstract String effortToFixDescription();
@CheckForNull
- String gapDescription();
+ public abstract String gapDescription();
@CheckForNull
- Param param(String key);
+ public abstract Param param(String key);
- List<Param> params();
+ public abstract List<Param> params();
- Set<String> tags();
+ public abstract Set<String> tags();
- Set<String> securityStandards();
+ public abstract Set<String> securityStandards();
/**
* Deprecated rules keys for this rule.
* @see NewRule#addDeprecatedRuleKey(String, String)
* @since 7.1
*/
- Set<RuleKey> deprecatedRuleKeys();
+ public abstract Set<RuleKey> deprecatedRuleKeys();
/**
* @see RulesDefinition.NewRule#setInternalKey(String)
*/
@CheckForNull
- String internalKey();
+ public abstract String internalKey();
}
--- /dev/null
+/*
+ * 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.internal;
+
+import javax.annotation.Nullable;
+import org.sonar.api.server.debt.DebtRemediationFunction;
+import org.sonar.api.server.debt.internal.DefaultDebtRemediationFunction;
+import org.sonar.api.server.rule.RulesDefinition;
+import org.sonar.api.utils.MessageException;
+
+/**
+ * Factory of {@link DebtRemediationFunction} that keeps
+ * a context of rule for better error messages. Used only when declaring rules.
+ *
+ * @see 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()));
+ }
+ }
+
+}
--- /dev/null
+/*
+ * 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.internal;
+
+import javax.annotation.Nullable;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.server.rule.RuleParamType;
+import org.sonar.api.server.rule.RulesDefinition;
+
+import static org.apache.commons.lang.StringUtils.defaultIfEmpty;
+
+public class DefaultNewParam extends RulesDefinition.NewParam {
+ private final String key;
+ private String name;
+ private String description;
+ private String defaultValue;
+ private RuleParamType type = RuleParamType.STRING;
+
+ DefaultNewParam(String key) {
+ this.key = this.name = key;
+ }
+
+ @Override
+ public String key() {
+ return key;
+ }
+
+ @Override
+ public DefaultNewParam setName(@Nullable String s) {
+ // name must never be null.
+ this.name = StringUtils.defaultIfBlank(s, key);
+ return this;
+ }
+
+ @Override
+ public DefaultNewParam setType(RuleParamType t) {
+ this.type = t;
+ return this;
+ }
+
+ @Override
+ public DefaultNewParam setDescription(@Nullable String s) {
+ this.description = StringUtils.defaultIfBlank(s, null);
+ return this;
+ }
+
+ @Override
+ public DefaultNewParam setDefaultValue(@Nullable String s) {
+ this.defaultValue = defaultIfEmpty(s, null);
+ return this;
+ }
+
+ public String name() {
+ return name;
+ }
+
+ public String description() {
+ return description;
+ }
+
+ public String defaultValue() {
+ return defaultValue;
+ }
+
+ public RuleParamType type() {
+ return type;
+ }
+}
--- /dev/null
+/*
+ * 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.internal;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.server.rule.RulesDefinition;
+
+import static org.sonar.api.utils.Preconditions.checkArgument;
+
+public class DefaultNewRepository implements RulesDefinition.NewRepository {
+ private final RulesDefinition.Context context;
+ private final String key;
+ private final boolean isExternal;
+ private final String language;
+ private String name;
+ private final Map<String, RulesDefinition.NewRule> newRules = new HashMap<>();
+
+ public DefaultNewRepository(RulesDefinition.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;
+ }
+
+ public String language() {
+ return language;
+ }
+
+ public Map<String, RulesDefinition.NewRule> newRules() {
+ return newRules;
+ }
+
+ public String name() {
+ return name;
+ }
+
+ @Override
+ public DefaultNewRepository setName(@Nullable String s) {
+ if (StringUtils.isNotEmpty(s)) {
+ this.name = s;
+ }
+ return this;
+ }
+
+ @Override
+ public RulesDefinition.NewRule createRule(String ruleKey) {
+ checkArgument(!newRules.containsKey(ruleKey), "The rule '%s' of repository '%s' is declared several times", ruleKey, key);
+ RulesDefinition.NewRule newRule = new DefaultNewRule(context.currentPluginKey(), key, ruleKey);
+ newRules.put(ruleKey, newRule);
+ return newRule;
+ }
+
+ @CheckForNull
+ @Override
+ public RulesDefinition.NewRule rule(String ruleKey) {
+ return newRules.get(ruleKey);
+ }
+
+ @Override
+ public Collection<RulesDefinition.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();
+ }
+}
--- /dev/null
+/*
+ * 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.internal;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Collection;
+import java.util.HashMap;
+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 org.apache.commons.io.IOUtils;
+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.debt.DebtRemediationFunction;
+import org.sonar.api.server.rule.RuleTagFormat;
+import org.sonar.api.server.rule.RulesDefinition;
+
+import static java.lang.String.format;
+import static java.nio.charset.StandardCharsets.UTF_8;
+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;
+
+class DefaultNewRule extends RulesDefinition.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, RulesDefinition.NewParam> paramsByKey = new HashMap<>();
+ private final RulesDefinition.DebtRemediationFunctions functions;
+ private boolean activatedByDefault;
+ private RuleScope scope;
+ private final Set<RuleKey> deprecatedRuleKeys = new TreeSet<>();
+
+ DefaultNewRule(@Nullable String pluginKey, String repoKey, String key) {
+ this.pluginKey = pluginKey;
+ this.repoKey = repoKey;
+ this.key = key;
+ this.functions = new DefaultDebtRemediationFunctions(repoKey, key);
+ }
+
+ @Override
+ public String key() {
+ return this.key;
+ }
+
+ @CheckForNull
+ @Override
+ public RuleScope scope() {
+ return this.scope;
+ }
+
+ @Override
+ public DefaultNewRule setScope(RuleScope scope) {
+ this.scope = scope;
+ return this;
+ }
+
+ @Override
+ public DefaultNewRule setName(String s) {
+ this.name = trimToNull(s);
+ return this;
+ }
+
+ @Override
+ public DefaultNewRule setTemplate(boolean template) {
+ this.template = template;
+ return this;
+ }
+
+ @Override
+ public DefaultNewRule setActivatedByDefault(boolean activatedByDefault) {
+ this.activatedByDefault = activatedByDefault;
+ return this;
+ }
+
+ @Override
+ public DefaultNewRule setSeverity(String s) {
+ checkArgument(Severity.ALL.contains(s), "Severity of rule %s is not correct: %s", this, s);
+ this.severity = s;
+ return this;
+ }
+
+ @Override
+ public DefaultNewRule setType(RuleType t) {
+ this.type = t;
+ return this;
+ }
+
+ @Override
+ public DefaultNewRule setHtmlDescription(@Nullable String s) {
+ checkState(markdownDescription == null, "Rule '%s' already has a Markdown description", this);
+ this.htmlDescription = trimToNull(s);
+ return this;
+ }
+
+ @Override
+ public DefaultNewRule 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;
+ }
+
+ @Override
+ public DefaultNewRule setMarkdownDescription(@Nullable String s) {
+ checkState(htmlDescription == null, "Rule '%s' already has an HTML description", this);
+ this.markdownDescription = trimToNull(s);
+ return this;
+ }
+
+ @Override
+ public DefaultNewRule 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;
+ }
+
+ @Override
+ public DefaultNewRule setStatus(RuleStatus status) {
+ checkArgument(RuleStatus.REMOVED != status, "Status 'REMOVED' is not accepted on rule '%s'", this);
+ this.status = status;
+ return this;
+ }
+
+ @Override
+ public DefaultNewRule setDebtSubCharacteristic(@Nullable String s) {
+ return this;
+ }
+
+ @Override
+ public RulesDefinition.DebtRemediationFunctions debtRemediationFunctions() {
+ return functions;
+ }
+
+ @Override
+ public DefaultNewRule setDebtRemediationFunction(@Nullable DebtRemediationFunction fn) {
+ this.debtRemediationFunction = fn;
+ return this;
+ }
+
+ @Deprecated
+ @Override
+ public DefaultNewRule setEffortToFixDescription(@Nullable String s) {
+ return setGapDescription(s);
+ }
+
+ @Override
+ public DefaultNewRule setGapDescription(@Nullable String s) {
+ this.gapDescription = s;
+ return this;
+ }
+
+ @Override
+ public RulesDefinition.NewParam createParam(String paramKey) {
+ checkArgument(!paramsByKey.containsKey(paramKey), "The parameter '%s' is declared several times on the rule %s", paramKey, this);
+ DefaultNewParam param = new DefaultNewParam(paramKey);
+ paramsByKey.put(paramKey, param);
+ return param;
+ }
+
+ @CheckForNull
+ @Override
+ public RulesDefinition.NewParam param(String paramKey) {
+ return paramsByKey.get(paramKey);
+ }
+
+ @Override
+ public Collection<RulesDefinition.NewParam> params() {
+ return paramsByKey.values();
+ }
+
+ @Override
+ public DefaultNewRule addTags(String... list) {
+ for (String tag : list) {
+ RuleTagFormat.validate(tag);
+ tags.add(tag);
+ }
+ return this;
+ }
+
+ @Override
+ public DefaultNewRule setTags(String... list) {
+ tags.clear();
+ addTags(list);
+ return this;
+ }
+
+ @Override
+ public DefaultNewRule addOwaspTop10(RulesDefinition.OwaspTop10... standards) {
+ for (RulesDefinition.OwaspTop10 owaspTop10 : standards) {
+ String standard = "owaspTop10:" + owaspTop10.name().toLowerCase(Locale.ENGLISH);
+ securityStandards.add(standard);
+ }
+ return this;
+ }
+
+ @Override
+ public DefaultNewRule addCwe(int... nums) {
+ for (int num : nums) {
+ String standard = "cwe:" + num;
+ securityStandards.add(standard);
+ }
+ return this;
+ }
+
+ @Override
+ public DefaultNewRule setInternalKey(@Nullable String s) {
+ this.internalKey = s;
+ return this;
+ }
+
+ 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));
+ }
+ }
+
+ @Override
+ public DefaultNewRule addDeprecatedRuleKey(String repository, String key) {
+ deprecatedRuleKeys.add(RuleKey.of(repository, key));
+ return this;
+ }
+
+ String pluginKey() {
+ return pluginKey;
+ }
+
+ String repoKey() {
+ return repoKey;
+ }
+
+ RuleType type() {
+ return type;
+ }
+
+ String name() {
+ return name;
+ }
+
+ String htmlDescription() {
+ return htmlDescription;
+ }
+
+ String markdownDescription() {
+ return markdownDescription;
+ }
+
+ @CheckForNull
+ String internalKey() {
+ return internalKey;
+ }
+
+ String severity() {
+ return severity;
+ }
+
+ boolean template() {
+ return template;
+ }
+
+ RuleStatus status() {
+ return status;
+ }
+
+ DebtRemediationFunction debtRemediationFunction() {
+ return debtRemediationFunction;
+ }
+
+ String gapDescription() {
+ return gapDescription;
+ }
+
+ Set<String> tags() {
+ return tags;
+ }
+
+ Set<String> securityStandards() {
+ return securityStandards;
+ }
+
+ Map<String, RulesDefinition.NewParam> paramsByKey() {
+ return paramsByKey;
+ }
+
+ boolean activatedByDefault() {
+ return activatedByDefault;
+ }
+
+ Set<RuleKey> deprecatedRuleKeys() {
+ return deprecatedRuleKeys;
+ }
+
+ @Override
+ public String toString() {
+ return format("[repository=%s, key=%s]", repoKey, key);
+ }
+}
--- /dev/null
+/*
+ * 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.internal;
+
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+import org.sonar.api.server.rule.RuleParamType;
+import org.sonar.api.server.rule.RulesDefinition;
+
+@Immutable
+public class DefaultParam implements RulesDefinition.Param {
+ private final String key;
+ private final String name;
+ private final String description;
+ private final String defaultValue;
+ private final RuleParamType type;
+
+ DefaultParam(DefaultNewParam newParam) {
+ this.key = newParam.key();
+ this.name = newParam.name();
+ this.description = newParam.description();
+ this.defaultValue = newParam.defaultValue();
+ this.type = newParam.type();
+ }
+
+ @Override
+ public String key() {
+ return key;
+ }
+
+ @Override
+ public String name() {
+ return name;
+ }
+
+ @Override
+ @Nullable
+ public String description() {
+ return description;
+ }
+
+ @Override
+ @Nullable
+ public String defaultValue() {
+ return defaultValue;
+ }
+
+ @Override
+ public RuleParamType type() {
+ return type;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ RulesDefinition.Param that = (RulesDefinition.Param) o;
+ return key.equals(that.key());
+ }
+
+ @Override
+ public int hashCode() {
+ return key.hashCode();
+ }
+
+}
--- /dev/null
+/*
+ * 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.internal;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.server.rule.RulesDefinition;
+import org.sonar.api.utils.log.Loggers;
+
+import static java.lang.String.format;
+import static java.util.Collections.unmodifiableList;
+import static java.util.Collections.unmodifiableMap;
+
+@Immutable
+public class DefaultRepository implements RulesDefinition.Repository {
+ private final String key;
+ private final String language;
+ private final String name;
+ private final boolean isExternal;
+ private final Map<String, RulesDefinition.Rule> rulesByKey;
+
+ public DefaultRepository(DefaultNewRepository newRepository, @Nullable RulesDefinition.Repository mergeInto) {
+ this.key = newRepository.key();
+ this.language = newRepository.language();
+ this.isExternal = newRepository.isExternal();
+ Map<String, RulesDefinition.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 (RulesDefinition.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 (RulesDefinition.NewRule newRule : newRepository.newRules().values()) {
+ DefaultNewRule defaultNewRule = (DefaultNewRule) newRule;
+ defaultNewRule.validate();
+ ruleBuilder.put(newRule.key(), new DefaultRule(this, defaultNewRule));
+ }
+ 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 RulesDefinition.Rule rule(String ruleKey) {
+ return rulesByKey.get(ruleKey);
+ }
+
+ @Override
+ public List<RulesDefinition.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;
+ }
+ DefaultRepository that = (DefaultRepository) 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();
+ }
+}
--- /dev/null
+/*
+ * 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.internal;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import javax.annotation.CheckForNull;
+import javax.annotation.concurrent.Immutable;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.RuleScope;
+import org.sonar.api.rule.RuleStatus;
+import org.sonar.api.rules.RuleType;
+import org.sonar.api.server.debt.DebtRemediationFunction;
+import org.sonar.api.server.rule.RuleTagsToTypeConverter;
+import org.sonar.api.server.rule.RulesDefinition;
+
+import static java.lang.String.format;
+import static java.util.Collections.unmodifiableList;
+
+@Immutable
+public class DefaultRule extends RulesDefinition.Rule {
+ private final String pluginKey;
+ private final RulesDefinition.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, RulesDefinition.Param> params;
+ private final RuleStatus status;
+ private final boolean activatedByDefault;
+ private final RuleScope scope;
+ private final Set<RuleKey> deprecatedRuleKeys;
+
+ DefaultRule(DefaultRepository repository, DefaultNewRule 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, RulesDefinition.Param> paramsBuilder = new HashMap<>();
+ for (RulesDefinition.NewParam newParam : newRule.paramsByKey().values()) {
+ paramsBuilder.put(newParam.key(), new DefaultParam((DefaultNewParam) newParam));
+ }
+ this.params = Collections.unmodifiableMap(paramsBuilder);
+ this.activatedByDefault = newRule.activatedByDefault();
+ this.deprecatedRuleKeys = Collections.unmodifiableSet(new TreeSet<>(newRule.deprecatedRuleKeys()));
+ }
+
+ @Override
+ public RulesDefinition.Repository repository() {
+ return repository;
+ }
+
+ @Override
+ @CheckForNull
+ public String pluginKey() {
+ return pluginKey;
+ }
+
+ @Override
+ public String key() {
+ return key;
+ }
+
+ @Override
+ public String name() {
+ return name;
+ }
+
+ @Override
+ public RuleScope scope() {
+ return scope;
+ }
+
+ @Override
+ public RuleType type() {
+ return type;
+ }
+
+ @Override
+ public String severity() {
+ return severity;
+ }
+
+ @Override
+ @CheckForNull
+ public String htmlDescription() {
+ return htmlDescription;
+ }
+
+ @Override
+ @CheckForNull
+ public String markdownDescription() {
+ return markdownDescription;
+ }
+
+ @Override
+ public boolean template() {
+ return template;
+ }
+
+ @Override
+ public boolean activatedByDefault() {
+ return activatedByDefault;
+ }
+
+ @Override
+ public RuleStatus status() {
+ return status;
+ }
+
+ @CheckForNull
+ @Deprecated
+ @Override
+ public String debtSubCharacteristic() {
+ return null;
+ }
+
+ @CheckForNull
+ @Override
+ public DebtRemediationFunction debtRemediationFunction() {
+ return debtRemediationFunction;
+ }
+
+ @Deprecated
+ @CheckForNull
+ @Override
+ public String effortToFixDescription() {
+ return gapDescription();
+ }
+
+ @CheckForNull
+ @Override
+ public String gapDescription() {
+ return gapDescription;
+ }
+
+ @CheckForNull
+ @Override
+ public RulesDefinition.Param param(String key) {
+ return params.get(key);
+ }
+
+ @Override
+ public List<RulesDefinition.Param> params() {
+ return unmodifiableList(new ArrayList<>(params.values()));
+ }
+
+ @Override
+ public Set<String> tags() {
+ return tags;
+ }
+
+ @Override
+ public Set<String> securityStandards() {
+ return securityStandards;
+ }
+
+ @Override
+ public Set<RuleKey> deprecatedRuleKeys() {
+ return deprecatedRuleKeys;
+ }
+
+ @CheckForNull
+ @Override
+ public String internalKey() {
+ return internalKey;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ DefaultRule other = (DefaultRule) o;
+ return key.equals(other.key) && repoKey.equals(other.repoKey);
+ }
+
+ @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);
+ }
+}
+
--- /dev/null
+/*
+ * 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.internal;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.RuleScope;
+import org.sonar.api.rule.RuleStatus;
+import org.sonar.api.rules.RuleType;
+import org.sonar.api.server.debt.DebtRemediationFunction;
+import org.sonar.api.server.rule.RulesDefinition;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+public class DefaultNewRuleTest {
+ @Rule
+ public ExpectedException exception = ExpectedException.none();
+
+ private DefaultNewRule rule = new DefaultNewRule("plugin", "repo", "key");
+
+ @Test
+ public void testSimpleSetGet() {
+ assertThat(rule.pluginKey()).isEqualTo("plugin");
+ assertThat(rule.repoKey()).isEqualTo("repo");
+ assertThat(rule.key()).isEqualTo("key");
+
+ rule.setScope(RuleScope.MAIN);
+ assertThat(rule.scope()).isEqualTo(RuleScope.MAIN);
+
+ rule.setName(" name ");
+ assertThat(rule.name()).isEqualTo("name");
+
+ rule.setHtmlDescription(" html ");
+ assertThat(rule.htmlDescription()).isEqualTo("html");
+
+ rule.setTemplate(true);
+ assertThat(rule.template()).isTrue();
+
+ rule.setActivatedByDefault(true);
+ assertThat(rule.activatedByDefault()).isTrue();
+
+ RulesDefinition.NewParam param1 = rule.createParam("param1");
+ assertThat(rule.param("param1")).isEqualTo(param1);
+ assertThat(rule.params()).containsOnly(param1);
+
+ rule.setTags("tag1", "tag2");
+ rule.addTags("tag3");
+ assertThat(rule.tags()).containsExactly("tag1", "tag2", "tag3");
+
+ rule.setEffortToFixDescription("effort");
+ assertThat(rule.gapDescription()).isEqualTo("effort");
+
+ rule.setGapDescription("gap");
+ assertThat(rule.gapDescription()).isEqualTo("gap");
+
+ rule.setInternalKey("internal");
+ assertThat(rule.internalKey()).isEqualTo("internal");
+
+ rule.addDeprecatedRuleKey("deprecatedrepo", "deprecatedkey");
+ assertThat(rule.deprecatedRuleKeys()).containsOnly(RuleKey.of("deprecatedrepo", "deprecatedkey"));
+
+ rule.setStatus(RuleStatus.READY);
+ assertThat(rule.status()).isEqualTo(RuleStatus.READY);
+
+ rule.addCwe(12);
+ rule.addCwe(10);
+ assertThat(rule.securityStandards()).containsOnly("cwe:10", "cwe:12");
+
+ rule.setType(RuleType.SECURITY_HOTSPOT);
+ assertThat(rule.type()).isEqualTo(RuleType.SECURITY_HOTSPOT);
+
+ DebtRemediationFunction f = mock(DebtRemediationFunction.class);
+ rule.setDebtRemediationFunction(f);
+ assertThat(rule.debtRemediationFunction()).isEqualTo(f);
+
+ rule.setSeverity("MAJOR");
+ assertThat(rule.severity()).isEqualTo("MAJOR");
+ }
+
+ @Test
+ public void validate_fails() {
+ rule.setHtmlDescription("html");
+ exception.expect(IllegalStateException.class);
+ rule.validate();
+ }
+
+ @Test
+ public void validate_succeeds() {
+ rule.setHtmlDescription("html");
+ rule.setName("name");
+ rule.validate();
+ }
+
+ @Test
+ public void set_markdown_description() {
+ rule.setMarkdownDescription("markdown");
+ assertThat(rule.markdownDescription()).isEqualTo("markdown");
+ }
+ @Test
+ public void fail_if_severity_is_invalid() {
+ exception.expect(IllegalArgumentException.class);
+ rule.setSeverity("invalid");
+ }
+
+ @Test
+ public void fail_setting_markdown_if_html_is_set() {
+ exception.expect(IllegalStateException.class);
+ rule.setHtmlDescription("html");
+ rule.setMarkdownDescription("markdown");
+ }
+
+ @Test
+ public void fail_if_set_status_to_removed() {
+ exception.expect(IllegalArgumentException.class);
+ rule.setStatus(RuleStatus.REMOVED);
+ }
+}
--- /dev/null
+/*
+ * 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.internal;
+
+import org.junit.Test;
+import org.sonar.api.impl.server.RulesDefinitionContext;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+public class DefaultRepositoryTest {
+ @Test
+ public void create_simple_repo() {
+ RulesDefinitionContext ctx = mock(RulesDefinitionContext.class);
+ DefaultNewRepository newRepo = new DefaultNewRepository(ctx, "key", "lang", false);
+ newRepo.createRule("rule1")
+ .setName("rule1")
+ .setHtmlDescription("desc");
+ newRepo.setName("name");
+ DefaultRepository repo = new DefaultRepository(newRepo, null);
+
+ assertThat(repo.isExternal()).isFalse();
+ assertThat(repo.key()).isEqualTo("key");
+ assertThat(repo.language()).isEqualTo("lang");
+ assertThat(repo.isExternal()).isFalse();
+ assertThat(repo.name()).isEqualTo("name");
+ assertThat(repo.rules()).extracting(r -> r.key()).containsOnly("rule1");
+
+ }
+}
--- /dev/null
+/*
+ * 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.internal;
+
+import org.junit.Test;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.RuleScope;
+import org.sonar.api.rule.RuleStatus;
+import org.sonar.api.rules.RuleType;
+import org.sonar.api.server.debt.DebtRemediationFunction;
+import org.sonar.api.server.rule.RulesDefinition;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+public class DefaultRuleTest {
+ @Test
+ public void getters() {
+ DefaultRepository repo = mock(DefaultRepository.class);
+ DefaultNewRule rule = new DefaultNewRule("plugin", "repo", "key");
+
+ rule.setScope(RuleScope.MAIN);
+ rule.setName(" name ");
+ rule.setHtmlDescription(" html ");
+ rule.setTemplate(true);
+ rule.setActivatedByDefault(true);
+ RulesDefinition.NewParam param1 = rule.createParam("param1");
+ rule.setTags("tag1", "tag2");
+ rule.addTags("tag3");
+ rule.setEffortToFixDescription("effort");
+ rule.setGapDescription("gap");
+ rule.setInternalKey("internal");
+ rule.addDeprecatedRuleKey("deprecatedrepo", "deprecatedkey");
+ rule.setStatus(RuleStatus.READY);
+ rule.addCwe(12);
+ rule.addCwe(10);
+ rule.setType(RuleType.SECURITY_HOTSPOT);
+ DebtRemediationFunction f = mock(DebtRemediationFunction.class);
+ rule.setDebtRemediationFunction(f);
+ rule.setSeverity("MAJOR");
+
+ DefaultRule defaultRule = new DefaultRule(repo, rule);
+ assertThat(defaultRule.scope()).isEqualTo(RuleScope.MAIN);
+ assertThat(defaultRule.name()).isEqualTo("name");
+ assertThat(defaultRule.htmlDescription()).isEqualTo("html");
+ assertThat(defaultRule.template()).isTrue();
+ assertThat(defaultRule.activatedByDefault()).isTrue();
+ assertThat(defaultRule.params()).containsOnly(new DefaultParam(new DefaultNewParam("param1")));
+ assertThat(defaultRule.tags()).containsOnly("tag1", "tag2", "tag3");
+ assertThat(defaultRule.effortToFixDescription()).isEqualTo("gap");
+ assertThat(defaultRule.gapDescription()).isEqualTo("gap");
+ assertThat(defaultRule.internalKey()).isEqualTo("internal");
+ assertThat(defaultRule.deprecatedRuleKeys()).containsOnly(RuleKey.of("deprecatedrepo", "deprecatedkey"));
+ assertThat(defaultRule.status()).isEqualTo(RuleStatus.READY);
+ assertThat(rule.securityStandards()).containsOnly("cwe:10", "cwe:12");
+ assertThat(defaultRule.type()).isEqualTo(RuleType.SECURITY_HOTSPOT);
+ assertThat(defaultRule.debtRemediationFunction()).isEqualTo(f);
+ assertThat(defaultRule.markdownDescription()).isNull();
+ assertThat(defaultRule.severity()).isEqualTo("MAJOR");
+ }
+
+ @Test
+ public void to_string() {
+ DefaultRepository repo = mock(DefaultRepository.class);
+ DefaultNewRule rule = new DefaultNewRule("plugin", "repo", "key");
+ DefaultRule defaultRule = new DefaultRule(repo, rule);
+
+ assertThat(defaultRule.toString()).isEqualTo("[repository=repo, key=key]");
+ }
+}