import org.sonar.api.SonarPlugin;
import org.sonar.xoo.rule.XooQualityProfile;
-import org.sonar.xoo.rule.XooRuleDefinitions;
+import org.sonar.xoo.rule.XooRulesDefinition;
import java.util.Arrays;
import java.util.List;
public List getExtensions() {
return Arrays.asList(
Xoo.class,
- XooRuleDefinitions.class,
+ XooRulesDefinition.class,
XooQualityProfile.class);
}
public RulesProfile createProfile(ValidationMessages validation) {
final RulesProfile profile = RulesProfile.create("Basic", Xoo.KEY);
- profile.activateRule(Rule.create(XooRuleDefinitions.XOO_REPOSITORY, "x1"), RulePriority.MAJOR);
+ profile.activateRule(Rule.create(XooRulesDefinition.XOO_REPOSITORY, "x1"), RulePriority.MAJOR);
return profile;
}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.xoo.rule;
-
-import org.sonar.api.rule.RuleStatus;
-import org.sonar.api.rule.Severity;
-import org.sonar.api.server.rule.RuleDefinitions;
-import org.sonar.api.server.rule.RuleParamType;
-import org.sonar.xoo.Xoo;
-
-/**
- * Define all the coding rules that are supported on the repository named "xoo".
- */
-public class XooRuleDefinitions implements RuleDefinitions {
-
- public static final String XOO_REPOSITORY = "xoo";
-
- @Override
- public void define(Context context) {
- NewRepository repository = context.createRepository(XOO_REPOSITORY, Xoo.KEY).setName("Xoo");
-
- // define a single rule programmatically. Note that rules
- // can be loaded from JSON or XML files too.
- NewRule x1Rule = repository.createRule("x1")
- .setName("No empty line")
- .setHtmlDescription("Generate an issue on empty lines of Xoo source files")
-
- // optional tags
- .setTags("style", "security")
-
- // optional status. Default value is READY.
- .setStatus(RuleStatus.BETA)
-
- // default severity when the rule is activated on a Quality profile. Default value is MAJOR.
- .setSeverity(Severity.MINOR);
-
- x1Rule.createParam("acceptWhitespace")
- .setDefaultValue("false")
- .setType(RuleParamType.BOOLEAN)
- .setDescription("Accept whitespaces on the line");
-
- // don't forget to call done() to finalize the definition
- repository.done();
- }
-
-}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.xoo.rule;
+
+import org.sonar.api.rule.RuleStatus;
+import org.sonar.api.rule.Severity;
+import org.sonar.api.server.rule.RuleParamType;
+import org.sonar.api.server.rule.RulesDefinition;
+import org.sonar.xoo.Xoo;
+
+/**
+ * Define all the coding rules that are supported on the repository named "xoo".
+ */
+public class XooRulesDefinition implements RulesDefinition {
+
+ public static final String XOO_REPOSITORY = "xoo";
+
+ @Override
+ public void define(Context context) {
+ NewRepository repository = context.createRepository(XOO_REPOSITORY, Xoo.KEY).setName("Xoo");
+
+ // define a single rule programmatically. Note that rules
+ // can be loaded from JSON or XML files too.
+ NewRule x1Rule = repository.createRule("x1")
+ .setName("No empty line")
+ .setHtmlDescription("Generate an issue on empty lines of Xoo source files")
+
+ // optional tags
+ .setTags("style", "security")
+
+ // optional status. Default value is READY.
+ .setStatus(RuleStatus.BETA)
+
+ // default severity when the rule is activated on a Quality profile. Default value is MAJOR.
+ .setSeverity(Severity.MINOR);
+
+ x1Rule.createParam("acceptWhitespace")
+ .setDefaultValue("false")
+ .setType(RuleParamType.BOOLEAN)
+ .setDescription("Accept whitespaces on the line");
+
+ // don't forget to call done() to finalize the definition
+ repository.done();
+ }
+
+}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.xoo.rule;
-
-import org.junit.Test;
-import org.sonar.api.server.rule.RuleDefinitions;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class XooRuleDefinitionsTest {
-
- @Test
- public void define_xoo_rules() {
- XooRuleDefinitions def = new XooRuleDefinitions();
- RuleDefinitions.Context context = new RuleDefinitions.Context();
- def.define(context);
-
- RuleDefinitions.Repository repo = context.repository("xoo");
- assertThat(repo).isNotNull();
- assertThat(repo.name()).isEqualTo("Xoo");
- assertThat(repo.language()).isEqualTo("xoo");
- assertThat(repo.rules()).hasSize(1);
-
- RuleDefinitions.Rule x1 = repo.rule("x1");
- assertThat(x1.key()).isEqualTo("x1");
- assertThat(x1.tags()).containsOnly("style", "security");
- assertThat(x1.htmlDescription()).isNotEmpty();
- }
-}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.xoo.rule;
+
+import org.junit.Test;
+import org.sonar.api.server.rule.RulesDefinition;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class XooRulesDefinitionTest {
+
+ @Test
+ public void define_xoo_rules() {
+ XooRulesDefinition def = new XooRulesDefinition();
+ RulesDefinition.Context context = new RulesDefinition.Context();
+ def.define(context);
+
+ RulesDefinition.Repository repo = context.repository("xoo");
+ assertThat(repo).isNotNull();
+ assertThat(repo.name()).isEqualTo("Xoo");
+ assertThat(repo.language()).isEqualTo("xoo");
+ assertThat(repo.rules()).hasSize(1);
+
+ RulesDefinition.Rule x1 = repo.rule("x1");
+ assertThat(x1.key()).isEqualTo("x1");
+ assertThat(x1.tags()).containsOnly("style", "security");
+ assertThat(x1.htmlDescription()).isNotEmpty();
+ }
+}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 com.google.common.collect.*;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang.StringUtils;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.ServerExtension;
-import org.sonar.api.rule.RemediationFunction;
-import org.sonar.api.rule.RuleStatus;
-import org.sonar.api.rule.Severity;
-
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.Immutable;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Defines the coding rules. For example the Java Findbugs plugin provides an implementation of
- * this extension point in order to define the rules that it supports.
- * <p/>
- * This interface replaces the deprecated class org.sonar.api.rules.RuleRepository.
- *
- * @since 4.3
- */
-public interface RuleDefinitions extends ServerExtension {
-
- /**
- * Instantiated by core but not by plugins
- */
- class Context {
- private final Map<String, Repository> repositoriesByKey = Maps.newHashMap();
- private final ListMultimap<String, ExtendedRepository> extendedRepositoriesByKey = ArrayListMultimap.create();
-
-
- public NewRepository createRepository(String key, String language) {
- return new NewRepositoryImpl(this, key, language, false);
- }
-
- public NewExtendedRepository extendRepository(String key, String language) {
- return new NewRepositoryImpl(this, key, language, true);
- }
-
- @CheckForNull
- public Repository repository(String key) {
- return repositoriesByKey.get(key);
- }
-
- public List<Repository> repositories() {
- return ImmutableList.copyOf(repositoriesByKey.values());
- }
-
- public List<ExtendedRepository> extendedRepositories(String repositoryKey) {
- return ImmutableList.copyOf(extendedRepositoriesByKey.get(repositoryKey));
- }
-
- public List<ExtendedRepository> extendedRepositories() {
- return ImmutableList.copyOf(extendedRepositoriesByKey.values());
- }
-
- private void registerRepository(NewRepositoryImpl newRepository) {
- if (repositoriesByKey.containsKey(newRepository.key)) {
- throw new IllegalStateException(String.format("The rule repository '%s' is defined several times", newRepository.key));
- }
- repositoriesByKey.put(newRepository.key, new RepositoryImpl(newRepository));
- }
-
- private void registerExtendedRepository(NewRepositoryImpl newRepository) {
- extendedRepositoriesByKey.put(newRepository.key, new RepositoryImpl(newRepository));
- }
- }
-
- interface NewExtendedRepository {
- NewRule createRule(String ruleKey);
-
- /**
- * Reads definition of rule from the annotations provided by the library sonar-check-api.
- */
- NewRule loadAnnotatedClass(Class clazz);
-
- /**
- * Reads definitions of rules from the annotations provided by the library sonar-check-api.
- */
- NewExtendedRepository loadAnnotatedClasses(Class... classes);
-
- /**
- * Reads definitions of rules from a XML file. Format is :
- * <pre>
- * <rules>
- * <rule>
- * <!-- required fields -->
- * <key>the-rule-key</key>
- * <name>The purpose of the rule</name>
- * <description>
- * <![CDATA[The description]]>
- * </description>
- *
- * <!-- optional fields -->
- * <internalKey>Checker/TreeWalker/LocalVariableName</internalKey>
- * <severity>BLOCKER</severity>
- * <cardinality>MULTIPLE</cardinality>
- * <status>BETA</status>
- * <param>
- * <key>the-param-key</key>
- * <tag>style</tag>
- * <tag>security</tag>
- * <description>
- * <![CDATA[
- * the param-description
- * ]]>
- * </description>
- * <defaultValue>42</defaultValue>
- * </param>
- * <param>
- * <key>another-param</key>
- * </param>
- *
- * <!-- deprecated fields -->
- * <configKey>Checker/TreeWalker/LocalVariableName</configKey>
- * <priority>BLOCKER</priority>
- * </rule>
- * </rules>
- *
- * </pre>
- */
- NewExtendedRepository loadXml(InputStream xmlInput, String encoding);
-
- void done();
- }
-
- interface NewRepository extends NewExtendedRepository {
- NewRepository setName(String s);
-
- @CheckForNull
- NewRule rule(String ruleKey);
- }
-
- class NewRepositoryImpl implements NewRepository {
- private final Context context;
- private final boolean extended;
- private final String key;
- private String language;
- private String name;
- private final Map<String, NewRule> newRules = Maps.newHashMap();
-
- private NewRepositoryImpl(Context context, String key, String language, boolean extended) {
- this.extended = extended;
- this.context = context;
- this.key = this.name = key;
- this.language = language;
- }
-
- @Override
- public NewRepositoryImpl setName(@Nullable String s) {
- if (StringUtils.isNotEmpty(s)) {
- this.name = s;
- }
- return this;
- }
-
- @Override
- public NewRule createRule(String ruleKey) {
- if (newRules.containsKey(ruleKey)) {
- // Should fail in a perfect world, but at the time being the Findbugs plugin
- // defines several times the rule EC_INCOMPATIBLE_ARRAY_COMPARE
- // See http://jira.codehaus.org/browse/SONARJAVA-428
- LoggerFactory.getLogger(getClass()).warn(String.format("The rule '%s' of repository '%s' is declared several times", ruleKey, key));
- }
- NewRule newRule = new NewRule(key, ruleKey);
- newRules.put(ruleKey, newRule);
- return newRule;
- }
-
- @CheckForNull
- @Override
- public NewRule rule(String ruleKey) {
- return newRules.get(ruleKey);
- }
-
- @Override
- public NewRepositoryImpl loadAnnotatedClasses(Class... classes) {
- new RuleDefinitionsFromAnnotations().loadRules(this, classes);
- return this;
- }
-
- @Override
- public RuleDefinitions.NewRule loadAnnotatedClass(Class clazz) {
- return new RuleDefinitionsFromAnnotations().loadRule(this, clazz);
- }
-
- @Override
- public NewRepositoryImpl loadXml(InputStream xmlInput, String encoding) {
- new RuleDefinitionsFromXml().loadRules(this, xmlInput, encoding);
- return this;
- }
-
- @Override
- public void done() {
- // note that some validations can be done here, for example for
- // verifying that at least one rule is declared
-
- if (extended) {
- context.registerExtendedRepository(this);
- } else {
- context.registerRepository(this);
- }
- }
- }
-
- interface ExtendedRepository {
- String key();
-
- String language();
-
- @CheckForNull
- Rule rule(String ruleKey);
-
- List<Rule> rules();
- }
-
- interface Repository extends ExtendedRepository {
- String name();
- }
-
- @Immutable
- class RepositoryImpl implements Repository {
- private final String key, language, name;
- private final Map<String, Rule> rulesByKey;
-
- private RepositoryImpl(NewRepositoryImpl newRepository) {
- this.key = newRepository.key;
- this.language = newRepository.language;
- this.name = newRepository.name;
- ImmutableMap.Builder<String, Rule> ruleBuilder = ImmutableMap.builder();
- for (NewRule newRule : newRepository.newRules.values()) {
- newRule.validate();
- ruleBuilder.put(newRule.key, new Rule(this, newRule));
- }
- this.rulesByKey = ruleBuilder.build();
- }
-
- @Override
- public String key() {
- return key;
- }
-
- @Override
- public String language() {
- return language;
- }
-
- @Override
- public String name() {
- return name;
- }
-
- @Override
- @CheckForNull
- public Rule rule(String ruleKey) {
- return rulesByKey.get(ruleKey);
- }
-
- @Override
- public List<Rule> rules() {
- return ImmutableList.copyOf(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();
- }
- }
-
- class NewRule {
- private final String repoKey, key;
- private String name, htmlDescription, internalKey, severity = Severity.MAJOR;
- private boolean template;
- private RuleStatus status = RuleStatus.defaultStatus();
- private String characteristicKey;
- private RemediationFunction remediationFunction;
- private String remediationFactor;
- private String remediationOffset;
- private String effortToFixL10nKey;
- private final Set<String> tags = Sets.newTreeSet();
- private final Map<String, NewParam> paramsByKey = Maps.newHashMap();
-
- private NewRule(String repoKey, String key) {
- this.repoKey = repoKey;
- this.key = key;
- }
-
- public String key() {
- return this.key;
- }
-
- public NewRule setName(@Nullable String s) {
- this.name = StringUtils.trim(s);
- return this;
- }
-
- public NewRule setTemplate(boolean template) {
- this.template = template;
- return this;
- }
-
- public NewRule setSeverity(String s) {
- if (!Severity.ALL.contains(s)) {
- throw new IllegalArgumentException(String.format("Severity of rule %s is not correct: %s", this, s));
- }
- this.severity = s;
- return this;
- }
-
- public NewRule setHtmlDescription(String s) {
- this.htmlDescription = StringUtils.trim(s);
- return this;
- }
-
- /**
- * 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));
- } catch (IOException e) {
- throw new IllegalStateException("Fail to read: " + classpathUrl, e);
- }
- } else {
- this.htmlDescription = null;
- }
- return this;
- }
-
- public NewRule setStatus(RuleStatus status) {
- if (status.equals(RuleStatus.REMOVED)) {
- throw new IllegalArgumentException(String.format("Status 'REMOVED' is not accepted on rule '%s'", this));
- }
- this.status = status;
- return this;
- }
-
- public NewRule setCharacteristicKey(@Nullable String characteristicKey) {
- this.characteristicKey = characteristicKey;
- return this;
- }
-
- public NewRule setRemediationFunction(@Nullable RemediationFunction remediationFunction) {
- this.remediationFunction = remediationFunction;
- return this;
- }
-
- public NewRule setRemediationFactor(@Nullable String remediationFactor) {
- // TODO validate format
- this.remediationFactor = StringUtils.deleteWhitespace(remediationFactor);
- return this;
- }
-
- public NewRule setRemediationOffset(@Nullable String remediationOffset) {
- // TODO validate format
- this.remediationOffset = StringUtils.deleteWhitespace(remediationOffset);
- return this;
- }
-
- public NewRule setEffortToFixL10nKey(@Nullable String effortToFixL10nKey) {
- this.effortToFixL10nKey = effortToFixL10nKey;
- return this;
- }
-
- public NewParam createParam(String paramKey) {
- if (paramsByKey.containsKey(paramKey)) {
- throw new IllegalArgumentException(String.format("The parameter '%s' is declared several times on the rule %s", paramKey, this));
- }
- NewParam param = new NewParam(paramKey);
- paramsByKey.put(paramKey, param);
- return param;
- }
-
- @CheckForNull
- public NewParam param(String paramKey) {
- return paramsByKey.get(paramKey);
- }
-
- /**
- * @see RuleTagFormat
- */
- public NewRule addTags(String... list) {
- for (String tag : list) {
- RuleTagFormat.validate(tag);
- tags.add(tag);
- }
- return this;
- }
-
- /**
- * @see RuleTagFormat
- */
- public NewRule setTags(String... list) {
- tags.clear();
- addTags(list);
- return this;
- }
-
- /**
- * 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 (StringUtils.isBlank(name)) {
- throw new IllegalStateException(String.format("Name of rule %s is empty", this));
- }
- if (StringUtils.isBlank(htmlDescription)) {
- throw new IllegalStateException(String.format("HTML description of rule %s is empty", this));
- }
- }
-
- @Override
- public String toString() {
- return String.format("[repository=%s, key=%s]", repoKey, key);
- }
- }
-
- @Immutable
- class Rule {
- private final Repository repository;
- private final String repoKey, key, name, htmlDescription, internalKey, severity;
- private final boolean template;
- private final String characteristicKey;
- private final RemediationFunction remediationFunction;
- private final String remediationFactor;
- private final String remediationOffset;
- private final String effortToFixL10nKey;
- private final Set<String> tags;
- private final Map<String, Param> params;
- private final RuleStatus status;
-
- private Rule(Repository repository, NewRule newRule) {
- this.repository = repository;
- this.repoKey = newRule.repoKey;
- this.key = newRule.key;
- this.name = newRule.name;
- this.htmlDescription = newRule.htmlDescription;
- this.internalKey = newRule.internalKey;
- this.severity = newRule.severity;
- this.template = newRule.template;
- this.status = newRule.status;
- this.characteristicKey = newRule.characteristicKey;
- this.remediationFunction = newRule.remediationFunction;
- this.remediationFactor = newRule.remediationFactor;
- this.remediationOffset = newRule.remediationOffset;
- this.effortToFixL10nKey = newRule.effortToFixL10nKey;
- this.tags = ImmutableSortedSet.copyOf(newRule.tags);
- ImmutableMap.Builder<String, Param> paramsBuilder = ImmutableMap.builder();
- for (NewParam newParam : newRule.paramsByKey.values()) {
- paramsBuilder.put(newParam.key, new Param(newParam));
- }
- this.params = paramsBuilder.build();
- }
-
- public Repository repository() {
- return repository;
- }
-
- public String key() {
- return key;
- }
-
- public String name() {
- return name;
- }
-
- public String severity() {
- return severity;
- }
-
- @CheckForNull
- public String htmlDescription() {
- return htmlDescription;
- }
-
- public boolean template() {
- return template;
- }
-
- public RuleStatus status() {
- return status;
- }
-
- @CheckForNull
- public String characteristicKey() {
- return characteristicKey;
- }
-
- @CheckForNull
- public RemediationFunction remediationFunction() {
- return remediationFunction;
- }
-
- @CheckForNull
- public String remediationFactor() {
- return remediationFactor;
- }
-
- @CheckForNull
- public String remediationOffset() {
- return remediationOffset;
- }
-
- @CheckForNull
- public String effortToFixL10nKey() {
- return effortToFixL10nKey;
- }
-
- @CheckForNull
- public Param param(String key) {
- return params.get(key);
- }
-
- public List<Param> params() {
- return ImmutableList.copyOf(params.values());
- }
-
- public Set<String> tags() {
- return tags;
- }
-
- /**
- * @see RuleDefinitions.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);
- }
-
- @Override
- public int hashCode() {
- int result = repoKey.hashCode();
- result = 31 * result + key.hashCode();
- return result;
- }
-
- @Override
- public String toString() {
- return String.format("[repository=%s, key=%s]", repoKey, key);
- }
- }
-
- class NewParam {
- private final String key;
- private String name, description, defaultValue;
- private RuleParamType type = RuleParamType.STRING;
-
- private NewParam(String key) {
- this.key = this.name = key;
- }
-
- public NewParam setName(@Nullable String s) {
- // name must never be null.
- this.name = StringUtils.defaultIfBlank(s, key);
- return this;
- }
-
- public NewParam setType(RuleParamType t) {
- this.type = t;
- return this;
- }
-
- /**
- * Plain-text description. Can be null.
- */
- public NewParam setDescription(@Nullable String s) {
- this.description = StringUtils.defaultIfBlank(s, null);
- return this;
- }
-
- public NewParam setDefaultValue(@Nullable String s) {
- this.defaultValue = s;
- return this;
- }
- }
-
- @Immutable
- class Param {
- private final String key, name, description, 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;
- }
-
- public String name() {
- return name;
- }
-
- @Nullable
- public String description() {
- return description;
- }
-
- @Nullable
- public String defaultValue() {
- return defaultValue;
- }
-
- public RuleParamType type() {
- return type;
- }
-
- @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();
- }
- }
-
- /**
- * This method is executed when server is started.
- */
- void define(Context context);
-
-}
/**
* Read definitions of rules based on the annotations provided by sonar-check-api.
* </p>
- * It is internally used by {@link RuleDefinitions} and can't be directly
+ * It is internally used by {@link RulesDefinition} and can't be directly
* used by plugins.
*
* @since 4.2
private static final Logger LOG = LoggerFactory.getLogger(RuleDefinitionsFromAnnotations.class);
- void loadRules(RuleDefinitions.NewRepository repo, Class... annotatedClasses) {
+ void loadRules(RulesDefinition.NewRepository repo, Class... annotatedClasses) {
for (Class annotatedClass : annotatedClasses) {
loadRule(repo, annotatedClass);
}
}
@CheckForNull
- RuleDefinitions.NewRule loadRule(RuleDefinitions.NewRepository repo, Class clazz) {
+ RulesDefinition.NewRule loadRule(RulesDefinition.NewRepository repo, Class clazz) {
org.sonar.check.Rule ruleAnnotation = AnnotationUtils.getAnnotation(clazz, org.sonar.check.Rule.class);
if (ruleAnnotation != null) {
return loadRule(repo, clazz, ruleAnnotation);
}
}
- private RuleDefinitions.NewRule loadRule(RuleDefinitions.NewRepository repo, Class clazz, org.sonar.check.Rule ruleAnnotation) {
+ private RulesDefinition.NewRule loadRule(RulesDefinition.NewRepository repo, Class clazz, org.sonar.check.Rule ruleAnnotation) {
String ruleKey = StringUtils.defaultIfEmpty(ruleAnnotation.key(), clazz.getCanonicalName());
String ruleName = StringUtils.defaultIfEmpty(ruleAnnotation.name(), null);
String description = StringUtils.defaultIfEmpty(ruleAnnotation.description(), null);
- RuleDefinitions.NewRule rule = repo.createRule(ruleKey);
+ RulesDefinition.NewRule rule = repo.createRule(ruleKey);
rule.setName(ruleName).setHtmlDescription(description);
rule.setSeverity(ruleAnnotation.priority().name());
rule.setTemplate(ruleAnnotation.cardinality() == Cardinality.MULTIPLE);
return rule;
}
- private void loadParameters(RuleDefinitions.NewRule rule, Field field) {
+ private void loadParameters(RulesDefinition.NewRule rule, Field field) {
org.sonar.check.RuleProperty propertyAnnotation = field.getAnnotation(org.sonar.check.RuleProperty.class);
if (propertyAnnotation != null) {
String fieldKey = StringUtils.defaultIfEmpty(propertyAnnotation.key(), field.getName());
- RuleDefinitions.NewParam param = rule.createParam(fieldKey)
+ RulesDefinition.NewParam param = rule.createParam(fieldKey)
.setDescription(propertyAnnotation.description())
.setDefaultValue(propertyAnnotation.defaultValue());
import org.codehaus.staxmate.SMInputFactory;
import org.codehaus.staxmate.in.SMHierarchicCursor;
import org.codehaus.staxmate.in.SMInputCursor;
-import org.sonar.api.rule.Severity;
import org.sonar.api.rule.RuleStatus;
+import org.sonar.api.rule.Severity;
import org.sonar.check.Cardinality;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
+
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
*/
class RuleDefinitionsFromXml {
- void loadRules(RuleDefinitions.NewRepository repo, InputStream input, String encoding) {
+ void loadRules(RulesDefinition.NewRepository repo, InputStream input, String encoding) {
Reader reader = null;
try {
reader = new InputStreamReader(input, encoding);
}
}
- void loadRules(RuleDefinitions.NewRepository repo, Reader reader) {
+ void loadRules(RulesDefinition.NewRepository repo, Reader reader) {
XMLInputFactory xmlFactory = XMLInputFactory.newInstance();
xmlFactory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE);
xmlFactory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.FALSE);
}
}
- private void processRule(RuleDefinitions.NewRepository repo, SMInputCursor ruleC) throws XMLStreamException {
+ private void processRule(RulesDefinition.NewRepository repo, SMInputCursor ruleC) throws XMLStreamException {
String key = null, name = null, description = null, internalKey = null, severity = Severity.defaultSeverity(), status = null;
Cardinality cardinality = Cardinality.SINGLE;
List<ParamStruct> params = new ArrayList<ParamStruct>();
tags.add(StringUtils.trim(cursor.collectDescendantText(false)));
}
}
- RuleDefinitions.NewRule rule = repo.createRule(key)
+ RulesDefinition.NewRule rule = repo.createRule(key)
.setHtmlDescription(description)
.setSeverity(severity)
.setName(name)
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 com.google.common.collect.*;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.ServerExtension;
+import org.sonar.api.rule.RemediationFunction;
+import org.sonar.api.rule.RuleStatus;
+import org.sonar.api.rule.Severity;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Defines the coding rules. For example the Java Findbugs plugin provides an implementation of
+ * this extension point in order to define the rules that it supports.
+ * <p/>
+ * This interface replaces the deprecated class org.sonar.api.rules.RuleRepository.
+ *
+ * @since 4.3
+ */
+public interface RulesDefinition extends ServerExtension {
+
+ /**
+ * Instantiated by core but not by plugins
+ */
+ class Context {
+ private final Map<String, Repository> repositoriesByKey = Maps.newHashMap();
+ private final ListMultimap<String, ExtendedRepository> extendedRepositoriesByKey = ArrayListMultimap.create();
+
+
+ public NewRepository createRepository(String key, String language) {
+ return new NewRepositoryImpl(this, key, language, false);
+ }
+
+ public NewExtendedRepository extendRepository(String key, String language) {
+ return new NewRepositoryImpl(this, key, language, true);
+ }
+
+ @CheckForNull
+ public Repository repository(String key) {
+ return repositoriesByKey.get(key);
+ }
+
+ public List<Repository> repositories() {
+ return ImmutableList.copyOf(repositoriesByKey.values());
+ }
+
+ public List<ExtendedRepository> extendedRepositories(String repositoryKey) {
+ return ImmutableList.copyOf(extendedRepositoriesByKey.get(repositoryKey));
+ }
+
+ public List<ExtendedRepository> extendedRepositories() {
+ return ImmutableList.copyOf(extendedRepositoriesByKey.values());
+ }
+
+ private void registerRepository(NewRepositoryImpl newRepository) {
+ if (repositoriesByKey.containsKey(newRepository.key)) {
+ throw new IllegalStateException(String.format("The rule repository '%s' is defined several times", newRepository.key));
+ }
+ repositoriesByKey.put(newRepository.key, new RepositoryImpl(newRepository));
+ }
+
+ private void registerExtendedRepository(NewRepositoryImpl newRepository) {
+ extendedRepositoriesByKey.put(newRepository.key, new RepositoryImpl(newRepository));
+ }
+ }
+
+ interface NewExtendedRepository {
+ NewRule createRule(String ruleKey);
+
+ /**
+ * Reads definition of rule from the annotations provided by the library sonar-check-api.
+ */
+ NewRule loadAnnotatedClass(Class clazz);
+
+ /**
+ * Reads definitions of rules from the annotations provided by the library sonar-check-api.
+ */
+ NewExtendedRepository loadAnnotatedClasses(Class... classes);
+
+ /**
+ * Reads definitions of rules from a XML file. Format is :
+ * <pre>
+ * <rules>
+ * <rule>
+ * <!-- required fields -->
+ * <key>the-rule-key</key>
+ * <name>The purpose of the rule</name>
+ * <description>
+ * <![CDATA[The description]]>
+ * </description>
+ *
+ * <!-- optional fields -->
+ * <internalKey>Checker/TreeWalker/LocalVariableName</internalKey>
+ * <severity>BLOCKER</severity>
+ * <cardinality>MULTIPLE</cardinality>
+ * <status>BETA</status>
+ * <param>
+ * <key>the-param-key</key>
+ * <tag>style</tag>
+ * <tag>security</tag>
+ * <description>
+ * <![CDATA[
+ * the param-description
+ * ]]>
+ * </description>
+ * <defaultValue>42</defaultValue>
+ * </param>
+ * <param>
+ * <key>another-param</key>
+ * </param>
+ *
+ * <!-- deprecated fields -->
+ * <configKey>Checker/TreeWalker/LocalVariableName</configKey>
+ * <priority>BLOCKER</priority>
+ * </rule>
+ * </rules>
+ *
+ * </pre>
+ */
+ NewExtendedRepository loadXml(InputStream xmlInput, String encoding);
+
+ void done();
+ }
+
+ interface NewRepository extends NewExtendedRepository {
+ NewRepository setName(String s);
+
+ @CheckForNull
+ NewRule rule(String ruleKey);
+ }
+
+ class NewRepositoryImpl implements NewRepository {
+ private final Context context;
+ private final boolean extended;
+ private final String key;
+ private String language;
+ private String name;
+ private final Map<String, NewRule> newRules = Maps.newHashMap();
+
+ private NewRepositoryImpl(Context context, String key, String language, boolean extended) {
+ this.extended = extended;
+ this.context = context;
+ this.key = this.name = key;
+ this.language = language;
+ }
+
+ @Override
+ public NewRepositoryImpl setName(@Nullable String s) {
+ if (StringUtils.isNotEmpty(s)) {
+ this.name = s;
+ }
+ return this;
+ }
+
+ @Override
+ public NewRule createRule(String ruleKey) {
+ if (newRules.containsKey(ruleKey)) {
+ // Should fail in a perfect world, but at the time being the Findbugs plugin
+ // defines several times the rule EC_INCOMPATIBLE_ARRAY_COMPARE
+ // See http://jira.codehaus.org/browse/SONARJAVA-428
+ LoggerFactory.getLogger(getClass()).warn(String.format("The rule '%s' of repository '%s' is declared several times", ruleKey, key));
+ }
+ NewRule newRule = new NewRule(key, ruleKey);
+ newRules.put(ruleKey, newRule);
+ return newRule;
+ }
+
+ @CheckForNull
+ @Override
+ public NewRule rule(String ruleKey) {
+ return newRules.get(ruleKey);
+ }
+
+ @Override
+ public NewRepositoryImpl loadAnnotatedClasses(Class... classes) {
+ new RuleDefinitionsFromAnnotations().loadRules(this, classes);
+ return this;
+ }
+
+ @Override
+ public RulesDefinition.NewRule loadAnnotatedClass(Class clazz) {
+ return new RuleDefinitionsFromAnnotations().loadRule(this, clazz);
+ }
+
+ @Override
+ public NewRepositoryImpl loadXml(InputStream xmlInput, String encoding) {
+ new RuleDefinitionsFromXml().loadRules(this, xmlInput, encoding);
+ return this;
+ }
+
+ @Override
+ public void done() {
+ // note that some validations can be done here, for example for
+ // verifying that at least one rule is declared
+
+ if (extended) {
+ context.registerExtendedRepository(this);
+ } else {
+ context.registerRepository(this);
+ }
+ }
+ }
+
+ interface ExtendedRepository {
+ String key();
+
+ String language();
+
+ @CheckForNull
+ Rule rule(String ruleKey);
+
+ List<Rule> rules();
+ }
+
+ interface Repository extends ExtendedRepository {
+ String name();
+ }
+
+ @Immutable
+ class RepositoryImpl implements Repository {
+ private final String key, language, name;
+ private final Map<String, Rule> rulesByKey;
+
+ private RepositoryImpl(NewRepositoryImpl newRepository) {
+ this.key = newRepository.key;
+ this.language = newRepository.language;
+ this.name = newRepository.name;
+ ImmutableMap.Builder<String, Rule> ruleBuilder = ImmutableMap.builder();
+ for (NewRule newRule : newRepository.newRules.values()) {
+ newRule.validate();
+ ruleBuilder.put(newRule.key, new Rule(this, newRule));
+ }
+ this.rulesByKey = ruleBuilder.build();
+ }
+
+ @Override
+ public String key() {
+ return key;
+ }
+
+ @Override
+ public String language() {
+ return language;
+ }
+
+ @Override
+ public String name() {
+ return name;
+ }
+
+ @Override
+ @CheckForNull
+ public Rule rule(String ruleKey) {
+ return rulesByKey.get(ruleKey);
+ }
+
+ @Override
+ public List<Rule> rules() {
+ return ImmutableList.copyOf(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();
+ }
+ }
+
+ class NewRule {
+ private final String repoKey, key;
+ private String name, htmlDescription, internalKey, severity = Severity.MAJOR;
+ private boolean template;
+ private RuleStatus status = RuleStatus.defaultStatus();
+ private String characteristicKey;
+ private RemediationFunction remediationFunction;
+ private String remediationFactor;
+ private String remediationOffset;
+ private String effortToFixL10nKey;
+ private final Set<String> tags = Sets.newTreeSet();
+ private final Map<String, NewParam> paramsByKey = Maps.newHashMap();
+
+ private NewRule(String repoKey, String key) {
+ this.repoKey = repoKey;
+ this.key = key;
+ }
+
+ public String key() {
+ return this.key;
+ }
+
+ public NewRule setName(@Nullable String s) {
+ this.name = StringUtils.trim(s);
+ return this;
+ }
+
+ public NewRule setTemplate(boolean template) {
+ this.template = template;
+ return this;
+ }
+
+ public NewRule setSeverity(String s) {
+ if (!Severity.ALL.contains(s)) {
+ throw new IllegalArgumentException(String.format("Severity of rule %s is not correct: %s", this, s));
+ }
+ this.severity = s;
+ return this;
+ }
+
+ public NewRule setHtmlDescription(String s) {
+ this.htmlDescription = StringUtils.trim(s);
+ return this;
+ }
+
+ /**
+ * 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));
+ } catch (IOException e) {
+ throw new IllegalStateException("Fail to read: " + classpathUrl, e);
+ }
+ } else {
+ this.htmlDescription = null;
+ }
+ return this;
+ }
+
+ public NewRule setStatus(RuleStatus status) {
+ if (status.equals(RuleStatus.REMOVED)) {
+ throw new IllegalArgumentException(String.format("Status 'REMOVED' is not accepted on rule '%s'", this));
+ }
+ this.status = status;
+ return this;
+ }
+
+ public NewRule setCharacteristicKey(@Nullable String characteristicKey) {
+ this.characteristicKey = characteristicKey;
+ return this;
+ }
+
+ public NewRule setRemediationFunction(@Nullable RemediationFunction remediationFunction) {
+ this.remediationFunction = remediationFunction;
+ return this;
+ }
+
+ public NewRule setRemediationFactor(@Nullable String remediationFactor) {
+ // TODO validate format
+ this.remediationFactor = StringUtils.deleteWhitespace(remediationFactor);
+ return this;
+ }
+
+ public NewRule setRemediationOffset(@Nullable String remediationOffset) {
+ // TODO validate format
+ this.remediationOffset = StringUtils.deleteWhitespace(remediationOffset);
+ return this;
+ }
+
+ public NewRule setEffortToFixL10nKey(@Nullable String effortToFixL10nKey) {
+ this.effortToFixL10nKey = effortToFixL10nKey;
+ return this;
+ }
+
+ public NewParam createParam(String paramKey) {
+ if (paramsByKey.containsKey(paramKey)) {
+ throw new IllegalArgumentException(String.format("The parameter '%s' is declared several times on the rule %s", paramKey, this));
+ }
+ NewParam param = new NewParam(paramKey);
+ paramsByKey.put(paramKey, param);
+ return param;
+ }
+
+ @CheckForNull
+ public NewParam param(String paramKey) {
+ return paramsByKey.get(paramKey);
+ }
+
+ /**
+ * @see RuleTagFormat
+ */
+ public NewRule addTags(String... list) {
+ for (String tag : list) {
+ RuleTagFormat.validate(tag);
+ tags.add(tag);
+ }
+ return this;
+ }
+
+ /**
+ * @see RuleTagFormat
+ */
+ public NewRule setTags(String... list) {
+ tags.clear();
+ addTags(list);
+ return this;
+ }
+
+ /**
+ * 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 (StringUtils.isBlank(name)) {
+ throw new IllegalStateException(String.format("Name of rule %s is empty", this));
+ }
+ if (StringUtils.isBlank(htmlDescription)) {
+ throw new IllegalStateException(String.format("HTML description of rule %s is empty", this));
+ }
+ }
+
+ @Override
+ public String toString() {
+ return String.format("[repository=%s, key=%s]", repoKey, key);
+ }
+ }
+
+ @Immutable
+ class Rule {
+ private final Repository repository;
+ private final String repoKey, key, name, htmlDescription, internalKey, severity;
+ private final boolean template;
+ private final String characteristicKey;
+ private final RemediationFunction remediationFunction;
+ private final String remediationFactor;
+ private final String remediationOffset;
+ private final String effortToFixL10nKey;
+ private final Set<String> tags;
+ private final Map<String, Param> params;
+ private final RuleStatus status;
+
+ private Rule(Repository repository, NewRule newRule) {
+ this.repository = repository;
+ this.repoKey = newRule.repoKey;
+ this.key = newRule.key;
+ this.name = newRule.name;
+ this.htmlDescription = newRule.htmlDescription;
+ this.internalKey = newRule.internalKey;
+ this.severity = newRule.severity;
+ this.template = newRule.template;
+ this.status = newRule.status;
+ this.characteristicKey = newRule.characteristicKey;
+ this.remediationFunction = newRule.remediationFunction;
+ this.remediationFactor = newRule.remediationFactor;
+ this.remediationOffset = newRule.remediationOffset;
+ this.effortToFixL10nKey = newRule.effortToFixL10nKey;
+ this.tags = ImmutableSortedSet.copyOf(newRule.tags);
+ ImmutableMap.Builder<String, Param> paramsBuilder = ImmutableMap.builder();
+ for (NewParam newParam : newRule.paramsByKey.values()) {
+ paramsBuilder.put(newParam.key, new Param(newParam));
+ }
+ this.params = paramsBuilder.build();
+ }
+
+ public Repository repository() {
+ return repository;
+ }
+
+ public String key() {
+ return key;
+ }
+
+ public String name() {
+ return name;
+ }
+
+ public String severity() {
+ return severity;
+ }
+
+ @CheckForNull
+ public String htmlDescription() {
+ return htmlDescription;
+ }
+
+ public boolean template() {
+ return template;
+ }
+
+ public RuleStatus status() {
+ return status;
+ }
+
+ @CheckForNull
+ public String characteristicKey() {
+ return characteristicKey;
+ }
+
+ @CheckForNull
+ public RemediationFunction remediationFunction() {
+ return remediationFunction;
+ }
+
+ @CheckForNull
+ public String remediationFactor() {
+ return remediationFactor;
+ }
+
+ @CheckForNull
+ public String remediationOffset() {
+ return remediationOffset;
+ }
+
+ @CheckForNull
+ public String effortToFixL10nKey() {
+ return effortToFixL10nKey;
+ }
+
+ @CheckForNull
+ public Param param(String key) {
+ return params.get(key);
+ }
+
+ public List<Param> params() {
+ return ImmutableList.copyOf(params.values());
+ }
+
+ public Set<String> tags() {
+ return tags;
+ }
+
+ /**
+ * @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);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = repoKey.hashCode();
+ result = 31 * result + key.hashCode();
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("[repository=%s, key=%s]", repoKey, key);
+ }
+ }
+
+ class NewParam {
+ private final String key;
+ private String name, description, defaultValue;
+ private RuleParamType type = RuleParamType.STRING;
+
+ private NewParam(String key) {
+ this.key = this.name = key;
+ }
+
+ public NewParam setName(@Nullable String s) {
+ // name must never be null.
+ this.name = StringUtils.defaultIfBlank(s, key);
+ return this;
+ }
+
+ public NewParam setType(RuleParamType t) {
+ this.type = t;
+ return this;
+ }
+
+ /**
+ * Plain-text description. Can be null.
+ */
+ public NewParam setDescription(@Nullable String s) {
+ this.description = StringUtils.defaultIfBlank(s, null);
+ return this;
+ }
+
+ public NewParam setDefaultValue(@Nullable String s) {
+ this.defaultValue = s;
+ return this;
+ }
+ }
+
+ @Immutable
+ class Param {
+ private final String key, name, description, 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;
+ }
+
+ public String name() {
+ return name;
+ }
+
+ @Nullable
+ public String description() {
+ return description;
+ }
+
+ @Nullable
+ public String defaultValue() {
+ return defaultValue;
+ }
+
+ public RuleParamType type() {
+ return type;
+ }
+
+ @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();
+ }
+ }
+
+ /**
+ * This method is executed when server is started.
+ */
+ void define(Context context);
+
+}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.rule.RuleStatus;
-import org.sonar.api.rule.Severity;
-import org.sonar.api.server.rule.RuleDefinitions.NewRule;
-import org.sonar.check.Priority;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class RuleDefinitionsFromAnnotationsTest {
-
- @org.junit.Rule
- public final ExpectedException thrown = ExpectedException.none();
-
- @Test
- public void rule_with_property() {
- RuleDefinitions.Repository repository = load(RuleWithProperty.class);
- assertThat(repository.rules()).hasSize(1);
- RuleDefinitions.Rule rule = repository.rules().get(0);
- assertThat(rule.key()).isEqualTo("foo");
- assertThat(rule.status()).isEqualTo(RuleStatus.BETA);
- assertThat(rule.name()).isEqualTo("bar");
- assertThat(rule.htmlDescription()).isEqualTo("Foo Bar");
- assertThat(rule.severity()).isEqualTo(Severity.BLOCKER);
- assertThat(rule.params()).hasSize(1);
- assertThat(rule.tags()).isEmpty();
-
- RuleDefinitions.Param prop = rule.param("property");
- assertThat(prop.key()).isEqualTo("property");
- assertThat(prop.description()).isEqualTo("Ignore ?");
- assertThat(prop.defaultValue()).isEqualTo("false");
- assertThat(prop.type()).isEqualTo(RuleParamType.STRING);
- }
-
- @Test
- public void override_annotation_programmatically() {
- RuleDefinitions.Context context = new RuleDefinitions.Context();
- RuleDefinitions.NewRepository newRepository = context.createRepository("squid", "java");
- NewRule newRule = newRepository.loadAnnotatedClass(RuleWithProperty.class);
- newRule.setName("Overriden name");
- newRule.param("property").setDefaultValue("true");
- newRule.param("property").setDescription("Overriden");
- newRepository.done();
-
- RuleDefinitions.Repository repository = context.repository("squid");
- assertThat(repository.rules()).hasSize(1);
- RuleDefinitions.Rule rule = repository.rules().get(0);
- assertThat(rule.key()).isEqualTo("foo");
- assertThat(rule.status()).isEqualTo(RuleStatus.BETA);
- assertThat(rule.name()).isEqualTo("Overriden name");
- assertThat(rule.htmlDescription()).isEqualTo("Foo Bar");
- assertThat(rule.severity()).isEqualTo(Severity.BLOCKER);
- assertThat(rule.params()).hasSize(1);
-
- RuleDefinitions.Param prop = rule.param("property");
- assertThat(prop.key()).isEqualTo("property");
- assertThat(prop.description()).isEqualTo("Overriden");
- assertThat(prop.defaultValue()).isEqualTo("true");
- assertThat(prop.type()).isEqualTo(RuleParamType.STRING);
- }
-
- @Test
- public void rule_with_integer_property() {
- RuleDefinitions.Repository repository = load(RuleWithIntegerProperty.class);
-
- RuleDefinitions.Param prop = repository.rules().get(0).param("property");
- assertThat(prop.description()).isEqualTo("Max");
- assertThat(prop.defaultValue()).isEqualTo("12");
- assertThat(prop.type()).isEqualTo(RuleParamType.INTEGER);
- }
-
- @Test
- public void rule_with_text_property() {
- RuleDefinitions.Repository repository = load(RuleWithTextProperty.class);
-
- RuleDefinitions.Param prop = repository.rules().get(0).param("property");
- assertThat(prop.description()).isEqualTo("text");
- assertThat(prop.defaultValue()).isEqualTo("Long text");
- assertThat(prop.type()).isEqualTo(RuleParamType.TEXT);
- }
-
- @Test
- public void should_recognize_type() {
- assertThat(RuleDefinitionsFromAnnotations.guessType(Integer.class)).isEqualTo(RuleParamType.INTEGER);
- assertThat(RuleDefinitionsFromAnnotations.guessType(int.class)).isEqualTo(RuleParamType.INTEGER);
- assertThat(RuleDefinitionsFromAnnotations.guessType(Float.class)).isEqualTo(RuleParamType.FLOAT);
- assertThat(RuleDefinitionsFromAnnotations.guessType(float.class)).isEqualTo(RuleParamType.FLOAT);
- assertThat(RuleDefinitionsFromAnnotations.guessType(Boolean.class)).isEqualTo(RuleParamType.BOOLEAN);
- assertThat(RuleDefinitionsFromAnnotations.guessType(boolean.class)).isEqualTo(RuleParamType.BOOLEAN);
- assertThat(RuleDefinitionsFromAnnotations.guessType(String.class)).isEqualTo(RuleParamType.STRING);
- assertThat(RuleDefinitionsFromAnnotations.guessType(Object.class)).isEqualTo(RuleParamType.STRING);
- }
-
- @Test
- public void use_classname_when_missing_key() {
- RuleDefinitions.Repository repository = load(RuleWithoutKey.class);
- assertThat(repository.rules()).hasSize(1);
- RuleDefinitions.Rule rule = repository.rules().get(0);
- assertThat(rule.key()).isEqualTo(RuleWithoutKey.class.getCanonicalName());
- assertThat(rule.name()).isEqualTo("foo");
- }
-
- @Test
- public void rule_with_tags() {
- RuleDefinitions.Repository repository = load(RuleWithTags.class);
- assertThat(repository.rules()).hasSize(1);
- RuleDefinitions.Rule rule = repository.rules().get(0);
- assertThat(rule.tags()).containsOnly("style", "security");
- }
-
- @Test
- public void overridden_class() {
- RuleDefinitions.Repository repository = load(OverridingRule.class);
- assertThat(repository.rules()).hasSize(1);
- RuleDefinitions.Rule rule = repository.rules().get(0);
- assertThat(rule.key()).isEqualTo("overriding_foo");
- assertThat(rule.name()).isEqualTo("Overriding Foo");
- assertThat(rule.severity()).isEqualTo(Severity.MAJOR);
- assertThat(rule.htmlDescription()).isEqualTo("Desc of Overriding Foo");
- assertThat(rule.params()).hasSize(2);
- }
-
- private RuleDefinitions.Repository load(Class annotatedClass) {
- RuleDefinitions.Context context = new RuleDefinitions.Context();
- RuleDefinitions.NewExtendedRepository newRepository = context.createRepository("squid", "java")
- .loadAnnotatedClasses(annotatedClass);
- newRepository.done();
- return context.repository("squid");
- }
-
- @org.sonar.check.Rule(name = "foo", description = "Foo")
- static class RuleWithoutKey {
- }
-
- @org.sonar.check.Rule(key = "foo", name = "bar", description = "Foo Bar", priority = Priority.BLOCKER, status = "BETA")
- static class RuleWithProperty {
- @org.sonar.check.RuleProperty(description = "Ignore ?", defaultValue = "false")
- private String property;
- }
-
- @org.sonar.check.Rule(key = "overriding_foo", name = "Overriding Foo", description = "Desc of Overriding Foo")
- static class OverridingRule extends RuleWithProperty {
- @org.sonar.check.RuleProperty
- private String additionalProperty;
- }
-
- @org.sonar.check.Rule(key = "foo", name = "bar", description = "Foo Bar", priority = Priority.BLOCKER)
- static class RuleWithIntegerProperty {
- @org.sonar.check.RuleProperty(description = "Max", defaultValue = "12")
- private Integer property;
- }
-
- @org.sonar.check.Rule(key = "foo", name = "bar", description = "Foo Bar", priority = Priority.BLOCKER)
- static class RuleWithTextProperty {
- @org.sonar.check.RuleProperty(description = "text", defaultValue = "Long text", type = "TEXT")
- protected String property;
- }
-
- @org.sonar.check.Rule(key = "foo", name = "bar", description = "Foo Bar", priority = Priority.BLOCKER)
- static class RuleWithInvalidPropertyType {
- @org.sonar.check.RuleProperty(description = "text", defaultValue = "Long text", type = "INVALID")
- public String property;
- }
-
- @org.sonar.check.Rule(key = "foo", name = "bar", description = "Bar", tags = {"style", "security"})
- static class RuleWithTags {
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 com.google.common.base.Charsets;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.rule.Severity;
-import org.sonar.api.rule.RuleStatus;
-
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.io.StringReader;
-import java.io.UnsupportedEncodingException;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class RuleDefinitionsFromXmlTest {
-
- @org.junit.Rule
- public final ExpectedException thrown = ExpectedException.none();
-
- private RuleDefinitions.Repository load(Reader reader) {
- RuleDefinitions.Context context = new RuleDefinitions.Context();
- RuleDefinitions.NewRepository newRepository = context.createRepository("squid", "java");
- new RuleDefinitionsFromXml().loadRules(newRepository, reader);
- newRepository.done();
- return context.repository("squid");
- }
-
- @Test
- public void should_parse_xml() throws Exception {
- InputStreamReader reader = new InputStreamReader(getClass().getResourceAsStream("/org/sonar/api/server/rule/RuleDefinitionsFromXmlTest/rules.xml"), Charsets.UTF_8.name());
- RuleDefinitions.Repository repository = load(reader);
- assertThat(repository.rules()).hasSize(2);
-
- RuleDefinitions.Rule rule = repository.rule("complete");
- assertThat(rule.key()).isEqualTo("complete");
- assertThat(rule.name()).isEqualTo("Complete");
- assertThat(rule.htmlDescription()).isEqualTo("Description of Complete");
- assertThat(rule.severity()).isEqualTo(Severity.BLOCKER);
- assertThat(rule.template()).isTrue();
- assertThat(rule.status()).isEqualTo(RuleStatus.BETA);
- assertThat(rule.internalKey()).isEqualTo("Checker/TreeWalker/LocalVariableName");
- assertThat(rule.tags()).containsOnly("style", "security");
-
- assertThat(rule.params()).hasSize(2);
- RuleDefinitions.Param ignore = rule.param("ignore");
- assertThat(ignore.key()).isEqualTo("ignore");
- assertThat(ignore.description()).isEqualTo("Ignore ?");
- assertThat(ignore.defaultValue()).isEqualTo("false");
-
- rule = repository.rule("minimal");
- assertThat(rule.key()).isEqualTo("minimal");
- assertThat(rule.name()).isEqualTo("Minimal");
- assertThat(rule.htmlDescription()).isEqualTo("Description of Minimal");
- assertThat(rule.params()).isEmpty();
- assertThat(rule.status()).isEqualTo(RuleStatus.READY);
- assertThat(rule.severity()).isEqualTo(Severity.MAJOR);
- }
-
- @Test
- public void should_fail_if_missing_rule_key() {
- thrown.expect(IllegalStateException.class);
- load(new StringReader("<rules><rule><name>Foo</name></rule></rules>"));
- }
-
- @Test
- public void should_fail_if_missing_property_key() {
- thrown.expect(IllegalStateException.class);
- load(new StringReader("<rules><rule><key>foo</key><name>Foo</name><param></param></rule></rules>"));
- }
-
- @Test
- public void should_fail_on_invalid_rule_parameter_type() {
- thrown.expect(IllegalStateException.class);
- load(new StringReader("<rules><rule><key>foo</key><name>Foo</name><param><key>key</key><type>INVALID</type></param></rule></rules>"));
- }
-
- @Test
- public void test_utf8_encoding() throws UnsupportedEncodingException {
- InputStreamReader reader = new InputStreamReader(getClass().getResourceAsStream("/org/sonar/api/server/rule/RuleDefinitionsFromXmlTest/utf8.xml"), Charsets.UTF_8.name());
- RuleDefinitions.Repository repository = load(reader);
-
- assertThat(repository.rules()).hasSize(1);
- RuleDefinitions.Rule rule = repository.rules().get(0);
- assertThat(rule.key()).isEqualTo("com.puppycrawl.tools.checkstyle.checks.naming.LocalVariableNameCheck");
- assertThat(rule.name()).isEqualTo("M & M");
- assertThat(rule.htmlDescription().charAt(0)).isEqualTo('\u00E9');
- assertThat(rule.htmlDescription().charAt(1)).isEqualTo('\u00E0');
- assertThat(rule.htmlDescription().charAt(2)).isEqualTo('\u0026');
- }
-
- @Test
- public void should_support_deprecated_format() throws UnsupportedEncodingException {
- // the deprecated format uses some attributes instead of nodes
- InputStreamReader reader = new InputStreamReader(getClass().getResourceAsStream("/org/sonar/api/server/rule/RuleDefinitionsFromXmlTest/deprecated.xml"), Charsets.UTF_8.name());
- RuleDefinitions.Repository repository = load(reader);
-
- assertThat(repository.rules()).hasSize(1);
- RuleDefinitions.Rule rule = repository.rules().get(0);
- assertThat(rule.key()).isEqualTo("org.sonar.it.checkstyle.MethodsCountCheck");
- assertThat(rule.internalKey()).isEqualTo("Checker/TreeWalker/org.sonar.it.checkstyle.MethodsCountCheck");
- assertThat(rule.severity()).isEqualTo(Severity.CRITICAL);
- assertThat(rule.htmlDescription()).isEqualTo("Count methods");
- assertThat(rule.param("minMethodsCount")).isNotNull();
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 org.junit.Ignore;
-import org.junit.Test;
-import org.sonar.api.rule.RemediationFunction;
-import org.sonar.api.rule.RuleStatus;
-import org.sonar.api.rule.Severity;
-
-import java.net.URL;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.fest.assertions.Fail.fail;
-
-public class RuleDefinitionsTest {
-
- RuleDefinitions.Context context = new RuleDefinitions.Context();
-
- @Test
- public void define_repositories() throws Exception {
- assertThat(context.repositories()).isEmpty();
-
- context.createRepository("findbugs", "java").setName("Findbugs").done();
- context.createRepository("checkstyle", "java").done();
-
- assertThat(context.repositories()).hasSize(2);
- RuleDefinitions.Repository findbugs = context.repository("findbugs");
- assertThat(findbugs).isNotNull();
- assertThat(findbugs.key()).isEqualTo("findbugs");
- assertThat(findbugs.language()).isEqualTo("java");
- assertThat(findbugs.name()).isEqualTo("Findbugs");
- assertThat(findbugs.rules()).isEmpty();
- RuleDefinitions.Repository checkstyle = context.repository("checkstyle");
- assertThat(checkstyle).isNotNull();
- assertThat(checkstyle.key()).isEqualTo("checkstyle");
- assertThat(checkstyle.language()).isEqualTo("java");
-
- // default name is key
- assertThat(checkstyle.name()).isEqualTo("checkstyle");
- assertThat(checkstyle.rules()).isEmpty();
- assertThat(context.repository("unknown")).isNull();
-
- // test equals() and hashCode()
- assertThat(findbugs).isEqualTo(findbugs).isNotEqualTo(checkstyle).isNotEqualTo("findbugs").isNotEqualTo(null);
- assertThat(findbugs.hashCode()).isEqualTo(findbugs.hashCode());
- }
-
- @Test
- public void define_rules() {
- RuleDefinitions.NewRepository newFindbugs = context.createRepository("findbugs", "java");
- newFindbugs.createRule("NPE")
- .setName("Detect NPE")
- .setHtmlDescription("Detect <code>java.lang.NullPointerException</code>")
- .setSeverity(Severity.BLOCKER)
- .setInternalKey("/something")
- .setStatus(RuleStatus.BETA)
- .setCharacteristicKey("COMPILER")
- .setRemediationFunction(RemediationFunction.LINEAR_OFFSET)
- .setRemediationFactor("1h")
- .setRemediationOffset("10min")
- .setEffortToFixL10nKey("squid.S115.effortToFix")
- .setTags("one", "two")
- .addTags("two", "three", "four");
- newFindbugs.createRule("ABC").setName("ABC").setHtmlDescription("ABC");
- newFindbugs.done();
-
- RuleDefinitions.Repository findbugs = context.repository("findbugs");
- assertThat(findbugs.rules()).hasSize(2);
-
- RuleDefinitions.Rule npeRule = findbugs.rule("NPE");
- assertThat(npeRule.key()).isEqualTo("NPE");
- assertThat(npeRule.name()).isEqualTo("Detect NPE");
- assertThat(npeRule.severity()).isEqualTo(Severity.BLOCKER);
- assertThat(npeRule.htmlDescription()).isEqualTo("Detect <code>java.lang.NullPointerException</code>");
- assertThat(npeRule.tags()).containsOnly("one", "two", "three", "four");
- assertThat(npeRule.params()).isEmpty();
- assertThat(npeRule.internalKey()).isEqualTo("/something");
- assertThat(npeRule.template()).isFalse();
- assertThat(npeRule.status()).isEqualTo(RuleStatus.BETA);
- assertThat(npeRule.characteristicKey()).isEqualTo("COMPILER");
- assertThat(npeRule.remediationFunction()).isEqualTo(RemediationFunction.LINEAR_OFFSET);
- assertThat(npeRule.remediationFactor()).isEqualTo("1h");
- assertThat(npeRule.remediationOffset()).isEqualTo("10min");
- assertThat(npeRule.effortToFixL10nKey()).isEqualTo("squid.S115.effortToFix");
- assertThat(npeRule.toString()).isEqualTo("[repository=findbugs, key=NPE]");
- assertThat(npeRule.repository()).isSameAs(findbugs);
-
- // test equals() and hashCode()
- RuleDefinitions.Rule otherRule = findbugs.rule("ABC");
- assertThat(npeRule).isEqualTo(npeRule).isNotEqualTo(otherRule).isNotEqualTo("NPE").isNotEqualTo(null);
- assertThat(npeRule.hashCode()).isEqualTo(npeRule.hashCode());
- }
-
- @Test
- public void define_rule_with_default_fields() {
- RuleDefinitions.NewRepository newFindbugs = context.createRepository("findbugs", "java");
- newFindbugs.createRule("NPE").setName("NPE").setHtmlDescription("NPE");
- newFindbugs.done();
-
- RuleDefinitions.Rule rule = context.repository("findbugs").rule("NPE");
- assertThat(rule.key()).isEqualTo("NPE");
- assertThat(rule.severity()).isEqualTo(Severity.MAJOR);
- assertThat(rule.params()).isEmpty();
- assertThat(rule.internalKey()).isNull();
- assertThat(rule.status()).isEqualTo(RuleStatus.defaultStatus());
- assertThat(rule.tags()).isEmpty();
- assertThat(rule.characteristicKey()).isNull();
- assertThat(rule.remediationFunction()).isNull();
- assertThat(rule.remediationFactor()).isNull();
- assertThat(rule.remediationOffset()).isNull();
- }
-
- @Test
- public void define_rule_parameters() {
- RuleDefinitions.NewRepository newFindbugs = context.createRepository("findbugs", "java");
- RuleDefinitions.NewRule newNpe = newFindbugs.createRule("NPE").setName("NPE").setHtmlDescription("NPE");
- newNpe.createParam("level").setDefaultValue("LOW").setName("Level").setDescription("The level").setType(RuleParamType.INTEGER);
- newNpe.createParam("effort");
- newFindbugs.done();
-
- RuleDefinitions.Rule rule = context.repository("findbugs").rule("NPE");
- assertThat(rule.params()).hasSize(2);
-
- RuleDefinitions.Param level = rule.param("level");
- assertThat(level.key()).isEqualTo("level");
- assertThat(level.name()).isEqualTo("Level");
- assertThat(level.description()).isEqualTo("The level");
- assertThat(level.defaultValue()).isEqualTo("LOW");
- assertThat(level.type()).isEqualTo(RuleParamType.INTEGER);
-
- RuleDefinitions.Param effort = rule.param("effort");
- assertThat(effort.key()).isEqualTo("effort").isEqualTo(effort.name());
- assertThat(effort.description()).isNull();
- assertThat(effort.defaultValue()).isNull();
- assertThat(effort.type()).isEqualTo(RuleParamType.STRING);
-
- // test equals() and hashCode()
- assertThat(level).isEqualTo(level).isNotEqualTo(effort).isNotEqualTo("level").isNotEqualTo(null);
- assertThat(level.hashCode()).isEqualTo(level.hashCode());
- }
-
- @Test
- public void sanitize_rule_name() {
- RuleDefinitions.NewRepository newFindbugs = context.createRepository("findbugs", "java");
- newFindbugs.createRule("NPE").setName(" \n NullPointer \n ").setHtmlDescription("NPE");
- newFindbugs.done();
-
- RuleDefinitions.Rule rule = context.repository("findbugs").rule("NPE");
- assertThat(rule.name()).isEqualTo("NullPointer");
- }
-
- @Test
- public void sanitize_remediation_factor_and_offset() {
- RuleDefinitions.NewRepository newFindbugs = context.createRepository("findbugs", "java");
- newFindbugs.createRule("NPE")
- .setName("Detect NPE")
- .setHtmlDescription("NPE")
- .setRemediationFactor(" 1 h ")
- .setRemediationOffset(" 10 mi n ");
- newFindbugs.done();
-
- RuleDefinitions.Rule npeRule = context.repository("findbugs").rule("NPE");
- assertThat(npeRule.remediationFactor()).isEqualTo("1h");
- assertThat(npeRule.remediationOffset()).isEqualTo("10min");
- }
-
- @Test
- public void extend_repository() {
- assertThat(context.extendedRepositories()).isEmpty();
-
- // for example fb-contrib
- RuleDefinitions.NewExtendedRepository newFindbugs = context.extendRepository("findbugs", "java");
- newFindbugs.createRule("NPE").setName("NPE").setHtmlDescription("NPE");
- newFindbugs.done();
-
- assertThat(context.repositories()).isEmpty();
- assertThat(context.extendedRepositories()).hasSize(1);
- assertThat(context.extendedRepositories("other")).isEmpty();
- assertThat(context.extendedRepositories("findbugs")).hasSize(1);
-
- RuleDefinitions.ExtendedRepository findbugs = context.extendedRepositories("findbugs").get(0);
- assertThat(findbugs.language()).isEqualTo("java");
- assertThat(findbugs.rule("NPE")).isNotNull();
- }
-
- @Test
- public void cant_set_blank_repository_name() throws Exception {
- context.createRepository("findbugs", "java").setName(null).done();
-
- assertThat(context.repository("findbugs").name()).isEqualTo("findbugs");
- }
-
- @Test
- public void fail_if_duplicated_repo_keys() {
- context.createRepository("findbugs", "java").done();
- try {
- context.createRepository("findbugs", "whatever_the_language").done();
- fail();
- } catch (Exception e) {
- assertThat(e).isInstanceOf(IllegalStateException.class).hasMessage("The rule repository 'findbugs' is defined several times");
- }
- }
-
- @Test
- public void warning_if_duplicated_rule_keys() {
- RuleDefinitions.NewRepository findbugs = context.createRepository("findbugs", "java");
- findbugs.createRule("NPE");
- findbugs.createRule("NPE");
- // do not fail as long as http://jira.codehaus.org/browse/SONARJAVA-428 is not fixed
- }
-
- @Test
- public void fail_if_duplicated_rule_param_keys() {
- RuleDefinitions.NewRule rule = context.createRepository("findbugs", "java").createRule("NPE");
- rule.createParam("level");
- try {
- rule.createParam("level");
- fail();
- } catch (Exception e) {
- assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("The parameter 'level' is declared several times on the rule [repository=findbugs, key=NPE]");
- }
- }
-
- @Test
- public void fail_if_blank_rule_name() {
- RuleDefinitions.NewRepository newRepository = context.createRepository("findbugs", "java");
- newRepository.createRule("NPE").setName(null).setHtmlDescription("NPE");
- try {
- newRepository.done();
- fail();
- } catch (Exception e) {
- assertThat(e).isInstanceOf(IllegalStateException.class).hasMessage("Name of rule [repository=findbugs, key=NPE] is empty");
- }
- }
-
- @Test
- public void fail_if_bad_rule_tag() {
- try {
- // whitespaces are not allowed in tags
- context.createRepository("findbugs", "java").createRule("NPE").setTags("coding style");
- fail();
- } catch (Exception e) {
- assertThat(e).isInstanceOf(IllegalArgumentException.class)
- .hasMessage("Tag 'coding style' is invalid. Rule tags accept only the following characters: a-z, 0-9, '+', '-', '#', '.'");
- }
- }
-
- @Test
- public void load_rule_description_from_file() {
- RuleDefinitions.NewRepository newRepository = context.createRepository("findbugs", "java");
- newRepository.createRule("NPE").setName("NPE").setHtmlDescription(getClass().getResource("/org/sonar/api/server/rule/RuleDefinitionsTest/sample.html"));
- newRepository.done();
-
- RuleDefinitions.Rule rule = context.repository("findbugs").rule("NPE");
- assertThat(rule.htmlDescription()).isEqualTo("description of rule loaded from file");
- }
-
- @Test
- public void fail_to_load_rule_description_from_file() {
- RuleDefinitions.NewRepository newRepository = context.createRepository("findbugs", "java");
- newRepository.createRule("NPE").setName("NPE").setHtmlDescription((URL)null);
- try {
- newRepository.done();
- fail();
- } catch (IllegalStateException e) {
- assertThat(e).hasMessage("HTML description of rule [repository=findbugs, key=NPE] is empty");
- }
- }
-
- @Test
- public void fail_if_blank_rule_html_description() {
- RuleDefinitions.NewRepository newRepository = context.createRepository("findbugs", "java");
- newRepository.createRule("NPE").setName("NPE").setHtmlDescription((String)null);
- try {
- newRepository.done();
- fail();
- } catch (IllegalStateException e) {
- assertThat(e).hasMessage("HTML description of rule [repository=findbugs, key=NPE] is empty");
- }
- }
-
- @Test
- public void fail_if_bad_rule_severity() {
- try {
- context.createRepository("findbugs", "java").createRule("NPE").setSeverity("VERY HIGH");
- fail();
- } catch (IllegalArgumentException e) {
- assertThat(e).hasMessage("Severity of rule [repository=findbugs, key=NPE] is not correct: VERY HIGH");
- }
- }
-
- @Test
- public void fail_if_removed_status() {
- try {
- context.createRepository("findbugs", "java").createRule("NPE").setStatus(RuleStatus.REMOVED);
- fail();
- } catch (IllegalArgumentException e) {
- assertThat(e).hasMessage("Status 'REMOVED' is not accepted on rule '[repository=findbugs, key=NPE]'");
- }
- }
-
- @Test
- @Ignore("TODO")
- public void fail_if_bad_remediation_factor_or_offset() {
- try {
- context.createRepository("findbugs", "java").createRule("NPE").setRemediationFactor("ten hours");
- fail();
- } catch (IllegalArgumentException e) {
- assertThat(e).hasMessage("Duration 'ten hours' is invalid, it should use the following sample format : 2d 10h 15min");
- }
-
- try {
- context.createRepository("findbugs", "java").createRule("NPE").setRemediationOffset("ten hours");
- fail();
- } catch (IllegalArgumentException e) {
- assertThat(e).hasMessage("Duration 'ten hours' is invalid, it should use the following sample format : 2d 10h 15min");
- }
- }
-
-}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 org.junit.Test;
+import org.junit.rules.ExpectedException;
+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 static org.fest.assertions.Assertions.assertThat;
+
+public class RulesDefinitionFromAnnotationsTest {
+
+ @org.junit.Rule
+ public final ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void rule_with_property() {
+ RulesDefinition.Repository repository = load(RuleWithProperty.class);
+ assertThat(repository.rules()).hasSize(1);
+ RulesDefinition.Rule rule = repository.rules().get(0);
+ assertThat(rule.key()).isEqualTo("foo");
+ assertThat(rule.status()).isEqualTo(RuleStatus.BETA);
+ assertThat(rule.name()).isEqualTo("bar");
+ assertThat(rule.htmlDescription()).isEqualTo("Foo Bar");
+ assertThat(rule.severity()).isEqualTo(Severity.BLOCKER);
+ assertThat(rule.params()).hasSize(1);
+ assertThat(rule.tags()).isEmpty();
+
+ RulesDefinition.Param prop = rule.param("property");
+ assertThat(prop.key()).isEqualTo("property");
+ assertThat(prop.description()).isEqualTo("Ignore ?");
+ assertThat(prop.defaultValue()).isEqualTo("false");
+ assertThat(prop.type()).isEqualTo(RuleParamType.STRING);
+ }
+
+ @Test
+ public void override_annotation_programmatically() {
+ RulesDefinition.Context context = new RulesDefinition.Context();
+ RulesDefinition.NewRepository newRepository = context.createRepository("squid", "java");
+ NewRule newRule = newRepository.loadAnnotatedClass(RuleWithProperty.class);
+ newRule.setName("Overriden name");
+ newRule.param("property").setDefaultValue("true");
+ newRule.param("property").setDescription("Overriden");
+ newRepository.done();
+
+ RulesDefinition.Repository repository = context.repository("squid");
+ assertThat(repository.rules()).hasSize(1);
+ RulesDefinition.Rule rule = repository.rules().get(0);
+ assertThat(rule.key()).isEqualTo("foo");
+ assertThat(rule.status()).isEqualTo(RuleStatus.BETA);
+ assertThat(rule.name()).isEqualTo("Overriden name");
+ assertThat(rule.htmlDescription()).isEqualTo("Foo Bar");
+ assertThat(rule.severity()).isEqualTo(Severity.BLOCKER);
+ assertThat(rule.params()).hasSize(1);
+
+ RulesDefinition.Param prop = rule.param("property");
+ assertThat(prop.key()).isEqualTo("property");
+ assertThat(prop.description()).isEqualTo("Overriden");
+ assertThat(prop.defaultValue()).isEqualTo("true");
+ assertThat(prop.type()).isEqualTo(RuleParamType.STRING);
+ }
+
+ @Test
+ public void rule_with_integer_property() {
+ RulesDefinition.Repository repository = load(RuleWithIntegerProperty.class);
+
+ RulesDefinition.Param prop = repository.rules().get(0).param("property");
+ assertThat(prop.description()).isEqualTo("Max");
+ assertThat(prop.defaultValue()).isEqualTo("12");
+ assertThat(prop.type()).isEqualTo(RuleParamType.INTEGER);
+ }
+
+ @Test
+ public void rule_with_text_property() {
+ RulesDefinition.Repository repository = load(RuleWithTextProperty.class);
+
+ RulesDefinition.Param prop = repository.rules().get(0).param("property");
+ assertThat(prop.description()).isEqualTo("text");
+ assertThat(prop.defaultValue()).isEqualTo("Long text");
+ assertThat(prop.type()).isEqualTo(RuleParamType.TEXT);
+ }
+
+ @Test
+ public void should_recognize_type() {
+ assertThat(RuleDefinitionsFromAnnotations.guessType(Integer.class)).isEqualTo(RuleParamType.INTEGER);
+ assertThat(RuleDefinitionsFromAnnotations.guessType(int.class)).isEqualTo(RuleParamType.INTEGER);
+ assertThat(RuleDefinitionsFromAnnotations.guessType(Float.class)).isEqualTo(RuleParamType.FLOAT);
+ assertThat(RuleDefinitionsFromAnnotations.guessType(float.class)).isEqualTo(RuleParamType.FLOAT);
+ assertThat(RuleDefinitionsFromAnnotations.guessType(Boolean.class)).isEqualTo(RuleParamType.BOOLEAN);
+ assertThat(RuleDefinitionsFromAnnotations.guessType(boolean.class)).isEqualTo(RuleParamType.BOOLEAN);
+ assertThat(RuleDefinitionsFromAnnotations.guessType(String.class)).isEqualTo(RuleParamType.STRING);
+ assertThat(RuleDefinitionsFromAnnotations.guessType(Object.class)).isEqualTo(RuleParamType.STRING);
+ }
+
+ @Test
+ public void use_classname_when_missing_key() {
+ RulesDefinition.Repository repository = load(RuleWithoutKey.class);
+ assertThat(repository.rules()).hasSize(1);
+ RulesDefinition.Rule rule = repository.rules().get(0);
+ assertThat(rule.key()).isEqualTo(RuleWithoutKey.class.getCanonicalName());
+ assertThat(rule.name()).isEqualTo("foo");
+ }
+
+ @Test
+ public void rule_with_tags() {
+ RulesDefinition.Repository repository = load(RuleWithTags.class);
+ assertThat(repository.rules()).hasSize(1);
+ RulesDefinition.Rule rule = repository.rules().get(0);
+ assertThat(rule.tags()).containsOnly("style", "security");
+ }
+
+ @Test
+ public void overridden_class() {
+ RulesDefinition.Repository repository = load(OverridingRule.class);
+ assertThat(repository.rules()).hasSize(1);
+ RulesDefinition.Rule rule = repository.rules().get(0);
+ assertThat(rule.key()).isEqualTo("overriding_foo");
+ assertThat(rule.name()).isEqualTo("Overriding Foo");
+ assertThat(rule.severity()).isEqualTo(Severity.MAJOR);
+ assertThat(rule.htmlDescription()).isEqualTo("Desc of Overriding Foo");
+ assertThat(rule.params()).hasSize(2);
+ }
+
+ private RulesDefinition.Repository load(Class annotatedClass) {
+ RulesDefinition.Context context = new RulesDefinition.Context();
+ RulesDefinition.NewExtendedRepository newRepository = context.createRepository("squid", "java")
+ .loadAnnotatedClasses(annotatedClass);
+ newRepository.done();
+ return context.repository("squid");
+ }
+
+ @org.sonar.check.Rule(name = "foo", description = "Foo")
+ static class RuleWithoutKey {
+ }
+
+ @org.sonar.check.Rule(key = "foo", name = "bar", description = "Foo Bar", priority = Priority.BLOCKER, status = "BETA")
+ static class RuleWithProperty {
+ @org.sonar.check.RuleProperty(description = "Ignore ?", defaultValue = "false")
+ private String property;
+ }
+
+ @org.sonar.check.Rule(key = "overriding_foo", name = "Overriding Foo", description = "Desc of Overriding Foo")
+ static class OverridingRule extends RuleWithProperty {
+ @org.sonar.check.RuleProperty
+ private String additionalProperty;
+ }
+
+ @org.sonar.check.Rule(key = "foo", name = "bar", description = "Foo Bar", priority = Priority.BLOCKER)
+ static class RuleWithIntegerProperty {
+ @org.sonar.check.RuleProperty(description = "Max", defaultValue = "12")
+ private Integer property;
+ }
+
+ @org.sonar.check.Rule(key = "foo", name = "bar", description = "Foo Bar", priority = Priority.BLOCKER)
+ static class RuleWithTextProperty {
+ @org.sonar.check.RuleProperty(description = "text", defaultValue = "Long text", type = "TEXT")
+ protected String property;
+ }
+
+ @org.sonar.check.Rule(key = "foo", name = "bar", description = "Foo Bar", priority = Priority.BLOCKER)
+ static class RuleWithInvalidPropertyType {
+ @org.sonar.check.RuleProperty(description = "text", defaultValue = "Long text", type = "INVALID")
+ public String property;
+ }
+
+ @org.sonar.check.Rule(key = "foo", name = "bar", description = "Bar", tags = {"style", "security"})
+ static class RuleWithTags {
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 com.google.common.base.Charsets;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.rule.RuleStatus;
+import org.sonar.api.rule.Severity;
+
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.UnsupportedEncodingException;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class RulesDefinitionFromXmlTest {
+
+ @org.junit.Rule
+ public final ExpectedException thrown = ExpectedException.none();
+
+ private RulesDefinition.Repository load(Reader reader) {
+ RulesDefinition.Context context = new RulesDefinition.Context();
+ RulesDefinition.NewRepository newRepository = context.createRepository("squid", "java");
+ new RuleDefinitionsFromXml().loadRules(newRepository, reader);
+ newRepository.done();
+ return context.repository("squid");
+ }
+
+ @Test
+ public void should_parse_xml() throws Exception {
+ InputStreamReader reader = new InputStreamReader(getClass().getResourceAsStream("/org/sonar/api/server/rule/RuleDefinitionsFromXmlTest/rules.xml"), Charsets.UTF_8.name());
+ RulesDefinition.Repository repository = load(reader);
+ assertThat(repository.rules()).hasSize(2);
+
+ RulesDefinition.Rule rule = repository.rule("complete");
+ assertThat(rule.key()).isEqualTo("complete");
+ assertThat(rule.name()).isEqualTo("Complete");
+ assertThat(rule.htmlDescription()).isEqualTo("Description of Complete");
+ assertThat(rule.severity()).isEqualTo(Severity.BLOCKER);
+ assertThat(rule.template()).isTrue();
+ assertThat(rule.status()).isEqualTo(RuleStatus.BETA);
+ assertThat(rule.internalKey()).isEqualTo("Checker/TreeWalker/LocalVariableName");
+ assertThat(rule.tags()).containsOnly("style", "security");
+
+ assertThat(rule.params()).hasSize(2);
+ RulesDefinition.Param ignore = rule.param("ignore");
+ assertThat(ignore.key()).isEqualTo("ignore");
+ assertThat(ignore.description()).isEqualTo("Ignore ?");
+ assertThat(ignore.defaultValue()).isEqualTo("false");
+
+ rule = repository.rule("minimal");
+ assertThat(rule.key()).isEqualTo("minimal");
+ assertThat(rule.name()).isEqualTo("Minimal");
+ assertThat(rule.htmlDescription()).isEqualTo("Description of Minimal");
+ assertThat(rule.params()).isEmpty();
+ assertThat(rule.status()).isEqualTo(RuleStatus.READY);
+ assertThat(rule.severity()).isEqualTo(Severity.MAJOR);
+ }
+
+ @Test
+ public void should_fail_if_missing_rule_key() {
+ thrown.expect(IllegalStateException.class);
+ load(new StringReader("<rules><rule><name>Foo</name></rule></rules>"));
+ }
+
+ @Test
+ public void should_fail_if_missing_property_key() {
+ thrown.expect(IllegalStateException.class);
+ load(new StringReader("<rules><rule><key>foo</key><name>Foo</name><param></param></rule></rules>"));
+ }
+
+ @Test
+ public void should_fail_on_invalid_rule_parameter_type() {
+ thrown.expect(IllegalStateException.class);
+ load(new StringReader("<rules><rule><key>foo</key><name>Foo</name><param><key>key</key><type>INVALID</type></param></rule></rules>"));
+ }
+
+ @Test
+ public void test_utf8_encoding() throws UnsupportedEncodingException {
+ InputStreamReader reader = new InputStreamReader(getClass().getResourceAsStream("/org/sonar/api/server/rule/RuleDefinitionsFromXmlTest/utf8.xml"), Charsets.UTF_8.name());
+ RulesDefinition.Repository repository = load(reader);
+
+ assertThat(repository.rules()).hasSize(1);
+ RulesDefinition.Rule rule = repository.rules().get(0);
+ assertThat(rule.key()).isEqualTo("com.puppycrawl.tools.checkstyle.checks.naming.LocalVariableNameCheck");
+ assertThat(rule.name()).isEqualTo("M & M");
+ assertThat(rule.htmlDescription().charAt(0)).isEqualTo('\u00E9');
+ assertThat(rule.htmlDescription().charAt(1)).isEqualTo('\u00E0');
+ assertThat(rule.htmlDescription().charAt(2)).isEqualTo('\u0026');
+ }
+
+ @Test
+ public void should_support_deprecated_format() throws UnsupportedEncodingException {
+ // the deprecated format uses some attributes instead of nodes
+ InputStreamReader reader = new InputStreamReader(getClass().getResourceAsStream("/org/sonar/api/server/rule/RuleDefinitionsFromXmlTest/deprecated.xml"), Charsets.UTF_8.name());
+ RulesDefinition.Repository repository = load(reader);
+
+ assertThat(repository.rules()).hasSize(1);
+ RulesDefinition.Rule rule = repository.rules().get(0);
+ assertThat(rule.key()).isEqualTo("org.sonar.it.checkstyle.MethodsCountCheck");
+ assertThat(rule.internalKey()).isEqualTo("Checker/TreeWalker/org.sonar.it.checkstyle.MethodsCountCheck");
+ assertThat(rule.severity()).isEqualTo(Severity.CRITICAL);
+ assertThat(rule.htmlDescription()).isEqualTo("Count methods");
+ assertThat(rule.param("minMethodsCount")).isNotNull();
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 org.junit.Ignore;
+import org.junit.Test;
+import org.sonar.api.rule.RemediationFunction;
+import org.sonar.api.rule.RuleStatus;
+import org.sonar.api.rule.Severity;
+
+import java.net.URL;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
+
+public class RulesDefinitionTest {
+
+ RulesDefinition.Context context = new RulesDefinition.Context();
+
+ @Test
+ public void define_repositories() throws Exception {
+ assertThat(context.repositories()).isEmpty();
+
+ context.createRepository("findbugs", "java").setName("Findbugs").done();
+ context.createRepository("checkstyle", "java").done();
+
+ assertThat(context.repositories()).hasSize(2);
+ RulesDefinition.Repository findbugs = context.repository("findbugs");
+ assertThat(findbugs).isNotNull();
+ assertThat(findbugs.key()).isEqualTo("findbugs");
+ assertThat(findbugs.language()).isEqualTo("java");
+ assertThat(findbugs.name()).isEqualTo("Findbugs");
+ assertThat(findbugs.rules()).isEmpty();
+ RulesDefinition.Repository checkstyle = context.repository("checkstyle");
+ assertThat(checkstyle).isNotNull();
+ assertThat(checkstyle.key()).isEqualTo("checkstyle");
+ assertThat(checkstyle.language()).isEqualTo("java");
+
+ // default name is key
+ assertThat(checkstyle.name()).isEqualTo("checkstyle");
+ assertThat(checkstyle.rules()).isEmpty();
+ assertThat(context.repository("unknown")).isNull();
+
+ // test equals() and hashCode()
+ assertThat(findbugs).isEqualTo(findbugs).isNotEqualTo(checkstyle).isNotEqualTo("findbugs").isNotEqualTo(null);
+ assertThat(findbugs.hashCode()).isEqualTo(findbugs.hashCode());
+ }
+
+ @Test
+ public void define_rules() {
+ RulesDefinition.NewRepository newFindbugs = context.createRepository("findbugs", "java");
+ newFindbugs.createRule("NPE")
+ .setName("Detect NPE")
+ .setHtmlDescription("Detect <code>java.lang.NullPointerException</code>")
+ .setSeverity(Severity.BLOCKER)
+ .setInternalKey("/something")
+ .setStatus(RuleStatus.BETA)
+ .setCharacteristicKey("COMPILER")
+ .setRemediationFunction(RemediationFunction.LINEAR_OFFSET)
+ .setRemediationFactor("1h")
+ .setRemediationOffset("10min")
+ .setEffortToFixL10nKey("squid.S115.effortToFix")
+ .setTags("one", "two")
+ .addTags("two", "three", "four");
+ newFindbugs.createRule("ABC").setName("ABC").setHtmlDescription("ABC");
+ newFindbugs.done();
+
+ RulesDefinition.Repository findbugs = context.repository("findbugs");
+ assertThat(findbugs.rules()).hasSize(2);
+
+ RulesDefinition.Rule npeRule = findbugs.rule("NPE");
+ assertThat(npeRule.key()).isEqualTo("NPE");
+ assertThat(npeRule.name()).isEqualTo("Detect NPE");
+ assertThat(npeRule.severity()).isEqualTo(Severity.BLOCKER);
+ assertThat(npeRule.htmlDescription()).isEqualTo("Detect <code>java.lang.NullPointerException</code>");
+ assertThat(npeRule.tags()).containsOnly("one", "two", "three", "four");
+ assertThat(npeRule.params()).isEmpty();
+ assertThat(npeRule.internalKey()).isEqualTo("/something");
+ assertThat(npeRule.template()).isFalse();
+ assertThat(npeRule.status()).isEqualTo(RuleStatus.BETA);
+ assertThat(npeRule.characteristicKey()).isEqualTo("COMPILER");
+ assertThat(npeRule.remediationFunction()).isEqualTo(RemediationFunction.LINEAR_OFFSET);
+ assertThat(npeRule.remediationFactor()).isEqualTo("1h");
+ assertThat(npeRule.remediationOffset()).isEqualTo("10min");
+ assertThat(npeRule.effortToFixL10nKey()).isEqualTo("squid.S115.effortToFix");
+ assertThat(npeRule.toString()).isEqualTo("[repository=findbugs, key=NPE]");
+ assertThat(npeRule.repository()).isSameAs(findbugs);
+
+ // test equals() and hashCode()
+ RulesDefinition.Rule otherRule = findbugs.rule("ABC");
+ assertThat(npeRule).isEqualTo(npeRule).isNotEqualTo(otherRule).isNotEqualTo("NPE").isNotEqualTo(null);
+ assertThat(npeRule.hashCode()).isEqualTo(npeRule.hashCode());
+ }
+
+ @Test
+ public void define_rule_with_default_fields() {
+ RulesDefinition.NewRepository newFindbugs = context.createRepository("findbugs", "java");
+ newFindbugs.createRule("NPE").setName("NPE").setHtmlDescription("NPE");
+ newFindbugs.done();
+
+ RulesDefinition.Rule rule = context.repository("findbugs").rule("NPE");
+ assertThat(rule.key()).isEqualTo("NPE");
+ assertThat(rule.severity()).isEqualTo(Severity.MAJOR);
+ assertThat(rule.params()).isEmpty();
+ assertThat(rule.internalKey()).isNull();
+ assertThat(rule.status()).isEqualTo(RuleStatus.defaultStatus());
+ assertThat(rule.tags()).isEmpty();
+ assertThat(rule.characteristicKey()).isNull();
+ assertThat(rule.remediationFunction()).isNull();
+ assertThat(rule.remediationFactor()).isNull();
+ assertThat(rule.remediationOffset()).isNull();
+ }
+
+ @Test
+ public void define_rule_parameters() {
+ RulesDefinition.NewRepository newFindbugs = context.createRepository("findbugs", "java");
+ RulesDefinition.NewRule newNpe = newFindbugs.createRule("NPE").setName("NPE").setHtmlDescription("NPE");
+ newNpe.createParam("level").setDefaultValue("LOW").setName("Level").setDescription("The level").setType(RuleParamType.INTEGER);
+ newNpe.createParam("effort");
+ newFindbugs.done();
+
+ RulesDefinition.Rule rule = context.repository("findbugs").rule("NPE");
+ assertThat(rule.params()).hasSize(2);
+
+ RulesDefinition.Param level = rule.param("level");
+ assertThat(level.key()).isEqualTo("level");
+ assertThat(level.name()).isEqualTo("Level");
+ assertThat(level.description()).isEqualTo("The level");
+ assertThat(level.defaultValue()).isEqualTo("LOW");
+ assertThat(level.type()).isEqualTo(RuleParamType.INTEGER);
+
+ RulesDefinition.Param effort = rule.param("effort");
+ assertThat(effort.key()).isEqualTo("effort").isEqualTo(effort.name());
+ assertThat(effort.description()).isNull();
+ assertThat(effort.defaultValue()).isNull();
+ assertThat(effort.type()).isEqualTo(RuleParamType.STRING);
+
+ // test equals() and hashCode()
+ assertThat(level).isEqualTo(level).isNotEqualTo(effort).isNotEqualTo("level").isNotEqualTo(null);
+ assertThat(level.hashCode()).isEqualTo(level.hashCode());
+ }
+
+ @Test
+ public void sanitize_rule_name() {
+ RulesDefinition.NewRepository newFindbugs = context.createRepository("findbugs", "java");
+ newFindbugs.createRule("NPE").setName(" \n NullPointer \n ").setHtmlDescription("NPE");
+ newFindbugs.done();
+
+ RulesDefinition.Rule rule = context.repository("findbugs").rule("NPE");
+ assertThat(rule.name()).isEqualTo("NullPointer");
+ }
+
+ @Test
+ public void sanitize_remediation_factor_and_offset() {
+ RulesDefinition.NewRepository newFindbugs = context.createRepository("findbugs", "java");
+ newFindbugs.createRule("NPE")
+ .setName("Detect NPE")
+ .setHtmlDescription("NPE")
+ .setRemediationFactor(" 1 h ")
+ .setRemediationOffset(" 10 mi n ");
+ newFindbugs.done();
+
+ RulesDefinition.Rule npeRule = context.repository("findbugs").rule("NPE");
+ assertThat(npeRule.remediationFactor()).isEqualTo("1h");
+ assertThat(npeRule.remediationOffset()).isEqualTo("10min");
+ }
+
+ @Test
+ public void extend_repository() {
+ assertThat(context.extendedRepositories()).isEmpty();
+
+ // for example fb-contrib
+ RulesDefinition.NewExtendedRepository newFindbugs = context.extendRepository("findbugs", "java");
+ newFindbugs.createRule("NPE").setName("NPE").setHtmlDescription("NPE");
+ newFindbugs.done();
+
+ assertThat(context.repositories()).isEmpty();
+ assertThat(context.extendedRepositories()).hasSize(1);
+ assertThat(context.extendedRepositories("other")).isEmpty();
+ assertThat(context.extendedRepositories("findbugs")).hasSize(1);
+
+ RulesDefinition.ExtendedRepository findbugs = context.extendedRepositories("findbugs").get(0);
+ assertThat(findbugs.language()).isEqualTo("java");
+ assertThat(findbugs.rule("NPE")).isNotNull();
+ }
+
+ @Test
+ public void cant_set_blank_repository_name() throws Exception {
+ context.createRepository("findbugs", "java").setName(null).done();
+
+ assertThat(context.repository("findbugs").name()).isEqualTo("findbugs");
+ }
+
+ @Test
+ public void fail_if_duplicated_repo_keys() {
+ context.createRepository("findbugs", "java").done();
+ try {
+ context.createRepository("findbugs", "whatever_the_language").done();
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(IllegalStateException.class).hasMessage("The rule repository 'findbugs' is defined several times");
+ }
+ }
+
+ @Test
+ public void warning_if_duplicated_rule_keys() {
+ RulesDefinition.NewRepository findbugs = context.createRepository("findbugs", "java");
+ findbugs.createRule("NPE");
+ findbugs.createRule("NPE");
+ // do not fail as long as http://jira.codehaus.org/browse/SONARJAVA-428 is not fixed
+ }
+
+ @Test
+ public void fail_if_duplicated_rule_param_keys() {
+ RulesDefinition.NewRule rule = context.createRepository("findbugs", "java").createRule("NPE");
+ rule.createParam("level");
+ try {
+ rule.createParam("level");
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("The parameter 'level' is declared several times on the rule [repository=findbugs, key=NPE]");
+ }
+ }
+
+ @Test
+ public void fail_if_blank_rule_name() {
+ RulesDefinition.NewRepository newRepository = context.createRepository("findbugs", "java");
+ newRepository.createRule("NPE").setName(null).setHtmlDescription("NPE");
+ try {
+ newRepository.done();
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(IllegalStateException.class).hasMessage("Name of rule [repository=findbugs, key=NPE] is empty");
+ }
+ }
+
+ @Test
+ public void fail_if_bad_rule_tag() {
+ try {
+ // whitespaces are not allowed in tags
+ context.createRepository("findbugs", "java").createRule("NPE").setTags("coding style");
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Tag 'coding style' is invalid. Rule tags accept only the following characters: a-z, 0-9, '+', '-', '#', '.'");
+ }
+ }
+
+ @Test
+ public void load_rule_description_from_file() {
+ RulesDefinition.NewRepository newRepository = context.createRepository("findbugs", "java");
+ newRepository.createRule("NPE").setName("NPE").setHtmlDescription(getClass().getResource("/org/sonar/api/server/rule/RuleDefinitionsTest/sample.html"));
+ newRepository.done();
+
+ RulesDefinition.Rule rule = context.repository("findbugs").rule("NPE");
+ assertThat(rule.htmlDescription()).isEqualTo("description of rule loaded from file");
+ }
+
+ @Test
+ public void fail_to_load_rule_description_from_file() {
+ RulesDefinition.NewRepository newRepository = context.createRepository("findbugs", "java");
+ newRepository.createRule("NPE").setName("NPE").setHtmlDescription((URL)null);
+ try {
+ newRepository.done();
+ fail();
+ } catch (IllegalStateException e) {
+ assertThat(e).hasMessage("HTML description of rule [repository=findbugs, key=NPE] is empty");
+ }
+ }
+
+ @Test
+ public void fail_if_blank_rule_html_description() {
+ RulesDefinition.NewRepository newRepository = context.createRepository("findbugs", "java");
+ newRepository.createRule("NPE").setName("NPE").setHtmlDescription((String)null);
+ try {
+ newRepository.done();
+ fail();
+ } catch (IllegalStateException e) {
+ assertThat(e).hasMessage("HTML description of rule [repository=findbugs, key=NPE] is empty");
+ }
+ }
+
+ @Test
+ public void fail_if_bad_rule_severity() {
+ try {
+ context.createRepository("findbugs", "java").createRule("NPE").setSeverity("VERY HIGH");
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertThat(e).hasMessage("Severity of rule [repository=findbugs, key=NPE] is not correct: VERY HIGH");
+ }
+ }
+
+ @Test
+ public void fail_if_removed_status() {
+ try {
+ context.createRepository("findbugs", "java").createRule("NPE").setStatus(RuleStatus.REMOVED);
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertThat(e).hasMessage("Status 'REMOVED' is not accepted on rule '[repository=findbugs, key=NPE]'");
+ }
+ }
+
+ @Test
+ @Ignore("TODO")
+ public void fail_if_bad_remediation_factor_or_offset() {
+ try {
+ context.createRepository("findbugs", "java").createRule("NPE").setRemediationFactor("ten hours");
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertThat(e).hasMessage("Duration 'ten hours' is invalid, it should use the following sample format : 2d 10h 15min");
+ }
+
+ try {
+ context.createRepository("findbugs", "java").createRule("NPE").setRemediationOffset("ten hours");
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertThat(e).hasMessage("Duration 'ten hours' is invalid, it should use the following sample format : 2d 10h 15min");
+ }
+ }
+
+}
ComponentContainer startupContainer = servicesContainer.createChild();
startupContainer.addSingleton(GwtPublisher.class);
startupContainer.addSingleton(RegisterMetrics.class);
- startupContainer.addSingleton(DeprecatedRuleDefinitions.class);
+ startupContainer.addSingleton(DeprecatedRulesDefinition.class);
startupContainer.addSingleton(RuleDefinitionsLoader.class);
startupContainer.addSingleton(RuleRegistration.class);
startupContainer.addSingleton(RegisterNewProfiles.class);
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.server.rule;
-
-import com.google.common.base.Predicate;
-import com.google.common.collect.Iterables;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.RuleStatus;
-import org.sonar.api.rules.RuleParam;
-import org.sonar.api.rules.RuleRepository;
-import org.sonar.api.server.rule.RuleDefinitions;
-import org.sonar.api.server.rule.RuleParamType;
-import org.sonar.check.Cardinality;
-import org.sonar.core.i18n.RuleI18nManager;
-import org.sonar.core.technicaldebt.DebtRulesXMLImporter;
-import org.sonar.core.technicaldebt.TechnicalDebtModelRepository;
-
-import javax.annotation.CheckForNull;
-
-import java.io.Reader;
-import java.util.Collection;
-import java.util.List;
-
-import static com.google.common.collect.Lists.newArrayList;
-
-/**
- * Inject deprecated RuleRepository into RuleDefinitions for backward-compatibility.
- *
- * @since 4.2
- */
-public class DeprecatedRuleDefinitions implements RuleDefinitions {
-
- private final RuleI18nManager i18n;
- private final RuleRepository[] repositories;
-
- private final TechnicalDebtModelRepository languageModelFinder;
- private final DebtRulesXMLImporter importer;
-
- public DeprecatedRuleDefinitions(RuleI18nManager i18n, RuleRepository[] repositories, TechnicalDebtModelRepository languageModelFinder, DebtRulesXMLImporter importer) {
- this.i18n = i18n;
- this.repositories = repositories;
- this.languageModelFinder = languageModelFinder;
- this.importer = importer;
- }
-
- public DeprecatedRuleDefinitions(RuleI18nManager i18n, TechnicalDebtModelRepository languageModelFinder, DebtRulesXMLImporter importer) {
- this(i18n, new RuleRepository[0], languageModelFinder, importer);
- }
-
- @Override
- public void define(Context context) {
- // Load rule debt definitions from xml files provided by plugin
- List<DebtRulesXMLImporter.RuleDebt> ruleDebts = loadRuleDebtList();
-
- for (RuleRepository repository : repositories) {
- // RuleRepository API does not handle difference between new and extended repositories,
- NewRepository newRepository;
- if (context.repository(repository.getKey()) == null) {
- newRepository = context.createRepository(repository.getKey(), repository.getLanguage());
- newRepository.setName(repository.getName());
- } else {
- newRepository = (NewRepository) context.extendRepository(repository.getKey(), repository.getLanguage());
- }
- for (org.sonar.api.rules.Rule rule : repository.createRules()) {
- NewRule newRule = newRepository.createRule(rule.getKey());
- newRule.setName(ruleName(repository.getKey(), rule));
- newRule.setHtmlDescription(ruleDescription(repository.getKey(), rule));
- newRule.setInternalKey(rule.getConfigKey());
- newRule.setTemplate(Cardinality.MULTIPLE.equals(rule.getCardinality()));
- newRule.setSeverity(rule.getSeverity().toString());
- newRule.setStatus(rule.getStatus() == null ? RuleStatus.defaultStatus() : RuleStatus.valueOf(rule.getStatus()));
- newRule.setTags(rule.getTags());
- for (RuleParam param : rule.getParams()) {
- NewParam newParam = newRule.createParam(param.getKey());
- newParam.setDefaultValue(param.getDefaultValue());
- newParam.setDescription(paramDescription(repository.getKey(), rule.getKey(), param));
- newParam.setType(RuleParamType.parse(param.getType()));
- }
- updateRuleDebtDefinitions(newRule, repository.getKey(), rule.getKey(), ruleDebts);
- }
- newRepository.done();
- }
- }
-
- private void updateRuleDebtDefinitions(NewRule newRule, String repoKey, String ruleKey, List<DebtRulesXMLImporter.RuleDebt> ruleDebts){
- DebtRulesXMLImporter.RuleDebt ruleDebt = findRequirement(ruleDebts, repoKey, ruleKey);
- if (ruleDebt != null) {
- newRule.setCharacteristicKey(ruleDebt.characteristicKey());
- newRule.setRemediationFunction(ruleDebt.function());
- newRule.setRemediationFactor(ruleDebt.factor());
- newRule.setRemediationOffset(ruleDebt.offset());
- }
- }
-
- @CheckForNull
- private String ruleName(String repositoryKey, org.sonar.api.rules.Rule rule) {
- String name = i18n.getName(repositoryKey, rule.getKey());
- if (StringUtils.isNotBlank(name)) {
- return name;
- }
- return StringUtils.defaultIfBlank(rule.getName(), null);
- }
-
- @CheckForNull
- private String ruleDescription(String repositoryKey, org.sonar.api.rules.Rule rule) {
- String description = i18n.getDescription(repositoryKey, rule.getKey());
- if (StringUtils.isNotBlank(description)) {
- return description;
- }
- return StringUtils.defaultIfBlank(rule.getDescription(), null);
- }
-
- @CheckForNull
- private String paramDescription(String repositoryKey, String ruleKey, RuleParam param) {
- String desc = StringUtils.defaultIfEmpty(
- i18n.getParamDescription(repositoryKey, ruleKey, param.getKey()),
- param.getDescription()
- );
- return StringUtils.defaultIfBlank(desc, null);
- }
-
- public List<DebtRulesXMLImporter.RuleDebt> loadRuleDebtList() {
- List<DebtRulesXMLImporter.RuleDebt> ruleDebtList = newArrayList();
- for (String pluginKey : getContributingPluginListWithoutSqale()) {
- ruleDebtList.addAll(loadRuleDebtsFromXml(pluginKey));
- }
- return ruleDebtList;
- }
-
- public List<DebtRulesXMLImporter.RuleDebt> loadRuleDebtsFromXml(String pluginKey) {
- Reader xmlFileReader = null;
- try {
- xmlFileReader = languageModelFinder.createReaderForXMLFile(pluginKey);
- return importer.importXML(xmlFileReader);
- } finally {
- IOUtils.closeQuietly(xmlFileReader);
- }
- }
-
- private Collection<String> getContributingPluginListWithoutSqale() {
- Collection<String> pluginList = newArrayList(languageModelFinder.getContributingPluginList());
- pluginList.remove(TechnicalDebtModelRepository.DEFAULT_MODEL);
- return pluginList;
- }
-
- @CheckForNull
- private DebtRulesXMLImporter.RuleDebt findRequirement(List<DebtRulesXMLImporter.RuleDebt> requirements, final String repoKey, final String ruleKey) {
- return Iterables.find(requirements, new Predicate<DebtRulesXMLImporter.RuleDebt>() {
- @Override
- public boolean apply(DebtRulesXMLImporter.RuleDebt input) {
- return input.ruleKey().equals(RuleKey.of(repoKey, ruleKey));
- }
- }, null);
- }
-
-}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.server.rule;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.RuleStatus;
+import org.sonar.api.rules.RuleParam;
+import org.sonar.api.rules.RuleRepository;
+import org.sonar.api.server.rule.RuleParamType;
+import org.sonar.api.server.rule.RulesDefinition;
+import org.sonar.check.Cardinality;
+import org.sonar.core.i18n.RuleI18nManager;
+import org.sonar.core.technicaldebt.DebtRulesXMLImporter;
+import org.sonar.core.technicaldebt.TechnicalDebtModelRepository;
+
+import javax.annotation.CheckForNull;
+
+import java.io.Reader;
+import java.util.Collection;
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+/**
+ * Inject deprecated RuleRepository into RuleDefinitions for backward-compatibility.
+ *
+ * @since 4.2
+ */
+public class DeprecatedRulesDefinition implements RulesDefinition {
+
+ private final RuleI18nManager i18n;
+ private final RuleRepository[] repositories;
+
+ private final TechnicalDebtModelRepository languageModelFinder;
+ private final DebtRulesXMLImporter importer;
+
+ public DeprecatedRulesDefinition(RuleI18nManager i18n, RuleRepository[] repositories, TechnicalDebtModelRepository languageModelFinder, DebtRulesXMLImporter importer) {
+ this.i18n = i18n;
+ this.repositories = repositories;
+ this.languageModelFinder = languageModelFinder;
+ this.importer = importer;
+ }
+
+ public DeprecatedRulesDefinition(RuleI18nManager i18n, TechnicalDebtModelRepository languageModelFinder, DebtRulesXMLImporter importer) {
+ this(i18n, new RuleRepository[0], languageModelFinder, importer);
+ }
+
+ @Override
+ public void define(Context context) {
+ // Load rule debt definitions from xml files provided by plugin
+ List<DebtRulesXMLImporter.RuleDebt> ruleDebts = loadRuleDebtList();
+
+ for (RuleRepository repository : repositories) {
+ // RuleRepository API does not handle difference between new and extended repositories,
+ NewRepository newRepository;
+ if (context.repository(repository.getKey()) == null) {
+ newRepository = context.createRepository(repository.getKey(), repository.getLanguage());
+ newRepository.setName(repository.getName());
+ } else {
+ newRepository = (NewRepository) context.extendRepository(repository.getKey(), repository.getLanguage());
+ }
+ for (org.sonar.api.rules.Rule rule : repository.createRules()) {
+ NewRule newRule = newRepository.createRule(rule.getKey());
+ newRule.setName(ruleName(repository.getKey(), rule));
+ newRule.setHtmlDescription(ruleDescription(repository.getKey(), rule));
+ newRule.setInternalKey(rule.getConfigKey());
+ newRule.setTemplate(Cardinality.MULTIPLE.equals(rule.getCardinality()));
+ newRule.setSeverity(rule.getSeverity().toString());
+ newRule.setStatus(rule.getStatus() == null ? RuleStatus.defaultStatus() : RuleStatus.valueOf(rule.getStatus()));
+ newRule.setTags(rule.getTags());
+ for (RuleParam param : rule.getParams()) {
+ NewParam newParam = newRule.createParam(param.getKey());
+ newParam.setDefaultValue(param.getDefaultValue());
+ newParam.setDescription(paramDescription(repository.getKey(), rule.getKey(), param));
+ newParam.setType(RuleParamType.parse(param.getType()));
+ }
+ updateRuleDebtDefinitions(newRule, repository.getKey(), rule.getKey(), ruleDebts);
+ }
+ newRepository.done();
+ }
+ }
+
+ private void updateRuleDebtDefinitions(NewRule newRule, String repoKey, String ruleKey, List<DebtRulesXMLImporter.RuleDebt> ruleDebts){
+ DebtRulesXMLImporter.RuleDebt ruleDebt = findRequirement(ruleDebts, repoKey, ruleKey);
+ if (ruleDebt != null) {
+ newRule.setCharacteristicKey(ruleDebt.characteristicKey());
+ newRule.setRemediationFunction(ruleDebt.function());
+ newRule.setRemediationFactor(ruleDebt.factor());
+ newRule.setRemediationOffset(ruleDebt.offset());
+ }
+ }
+
+ @CheckForNull
+ private String ruleName(String repositoryKey, org.sonar.api.rules.Rule rule) {
+ String name = i18n.getName(repositoryKey, rule.getKey());
+ if (StringUtils.isNotBlank(name)) {
+ return name;
+ }
+ return StringUtils.defaultIfBlank(rule.getName(), null);
+ }
+
+ @CheckForNull
+ private String ruleDescription(String repositoryKey, org.sonar.api.rules.Rule rule) {
+ String description = i18n.getDescription(repositoryKey, rule.getKey());
+ if (StringUtils.isNotBlank(description)) {
+ return description;
+ }
+ return StringUtils.defaultIfBlank(rule.getDescription(), null);
+ }
+
+ @CheckForNull
+ private String paramDescription(String repositoryKey, String ruleKey, RuleParam param) {
+ String desc = StringUtils.defaultIfEmpty(
+ i18n.getParamDescription(repositoryKey, ruleKey, param.getKey()),
+ param.getDescription()
+ );
+ return StringUtils.defaultIfBlank(desc, null);
+ }
+
+ public List<DebtRulesXMLImporter.RuleDebt> loadRuleDebtList() {
+ List<DebtRulesXMLImporter.RuleDebt> ruleDebtList = newArrayList();
+ for (String pluginKey : getContributingPluginListWithoutSqale()) {
+ ruleDebtList.addAll(loadRuleDebtsFromXml(pluginKey));
+ }
+ return ruleDebtList;
+ }
+
+ public List<DebtRulesXMLImporter.RuleDebt> loadRuleDebtsFromXml(String pluginKey) {
+ Reader xmlFileReader = null;
+ try {
+ xmlFileReader = languageModelFinder.createReaderForXMLFile(pluginKey);
+ return importer.importXML(xmlFileReader);
+ } finally {
+ IOUtils.closeQuietly(xmlFileReader);
+ }
+ }
+
+ private Collection<String> getContributingPluginListWithoutSqale() {
+ Collection<String> pluginList = newArrayList(languageModelFinder.getContributingPluginList());
+ pluginList.remove(TechnicalDebtModelRepository.DEFAULT_MODEL);
+ return pluginList;
+ }
+
+ @CheckForNull
+ private DebtRulesXMLImporter.RuleDebt findRequirement(List<DebtRulesXMLImporter.RuleDebt> requirements, final String repoKey, final String ruleKey) {
+ return Iterables.find(requirements, new Predicate<DebtRulesXMLImporter.RuleDebt>() {
+ @Override
+ public boolean apply(DebtRulesXMLImporter.RuleDebt input) {
+ return input.ruleKey().equals(RuleKey.of(repoKey, ruleKey));
+ }
+ }, null);
+ }
+
+}
package org.sonar.server.rule;
import org.sonar.api.ServerComponent;
-import org.sonar.api.server.rule.RuleDefinitions;
+import org.sonar.api.server.rule.RulesDefinition;
/**
* Loads all instances of RuleDefinitions and initializes RuleRepositories. Used at server startup.
*/
public class RuleDefinitionsLoader implements ServerComponent {
- private final RuleDefinitions[] definitions;
+ private final RulesDefinition[] definitions;
private final RuleRepositories repositories;
- public RuleDefinitionsLoader(RuleRepositories repositories, RuleDefinitions[] definitions) {
+ public RuleDefinitionsLoader(RuleRepositories repositories, RulesDefinition[] definitions) {
this.repositories = repositories;
this.definitions = definitions;
}
public RuleDefinitionsLoader(RuleRepositories repositories) {
- this(repositories, new RuleDefinitions[0]);
+ this(repositories, new RulesDefinition[0]);
}
- public RuleDefinitions.Context load() {
- RuleDefinitions.Context context = new RuleDefinitions.Context();
- for (RuleDefinitions definition : definitions) {
+ public RulesDefinition.Context load() {
+ RulesDefinition.Context context = new RulesDefinition.Context();
+ for (RulesDefinition definition : definitions) {
definition.define(context);
}
repositories.register(context);
import org.sonar.api.rule.RemediationFunction;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rules.Rule;
-import org.sonar.api.server.rule.RuleDefinitions;
+import org.sonar.api.server.rule.RulesDefinition;
import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.TimeProfiler;
TimeProfiler profiler = new TimeProfiler().start("Register rules");
SqlSession sqlSession = myBatis.openSession();
try {
- RuleDefinitions.Context context = defLoader.load();
+ RulesDefinition.Context context = defLoader.load();
Buffer buffer = new Buffer(system.now());
List<CharacteristicDto> characteristicDtos = characteristicDao.selectEnabledCharacteristics();
selectRulesFromDb(buffer, sqlSession);
}
}
- private void enableRuleDefinitions(RuleDefinitions.Context context, Buffer buffer, List<CharacteristicDto> characteristicDtos, SqlSession sqlSession) {
- for (RuleDefinitions.Repository repoDef : context.repositories()) {
+ private void enableRuleDefinitions(RulesDefinition.Context context, Buffer buffer, List<CharacteristicDto> characteristicDtos, SqlSession sqlSession) {
+ for (RulesDefinition.Repository repoDef : context.repositories()) {
enableRepository(buffer, sqlSession, repoDef, characteristicDtos);
}
- for (RuleDefinitions.ExtendedRepository extendedRepoDef : context.extendedRepositories()) {
+ for (RulesDefinition.ExtendedRepository extendedRepoDef : context.extendedRepositories()) {
if (context.repository(extendedRepoDef.key()) == null) {
LOG.warn(String.format("Extension is ignored, repository %s does not exist", extendedRepoDef.key()));
} else {
}
}
- private void enableRepository(Buffer buffer, SqlSession sqlSession, RuleDefinitions.ExtendedRepository repoDef, List<CharacteristicDto> characteristicDtos) {
+ private void enableRepository(Buffer buffer, SqlSession sqlSession, RulesDefinition.ExtendedRepository repoDef, List<CharacteristicDto> characteristicDtos) {
int count = 0;
- for (RuleDefinitions.Rule ruleDef : repoDef.rules()) {
+ for (RulesDefinition.Rule ruleDef : repoDef.rules()) {
RuleDto dto = buffer.rule(RuleKey.of(ruleDef.repository().key(), ruleDef.key()));
if (dto == null) {
dto = enableAndInsert(buffer, sqlSession, ruleDef, characteristicDtos);
sqlSession.commit();
}
- private RuleDto enableAndInsert(Buffer buffer, SqlSession sqlSession, RuleDefinitions.Rule ruleDef, List<CharacteristicDto> characteristicDtos) {
+ private RuleDto enableAndInsert(Buffer buffer, SqlSession sqlSession, RulesDefinition.Rule ruleDef, List<CharacteristicDto> characteristicDtos) {
RemediationFunction remediationFunction = ruleDef.remediationFunction();
RuleDto ruleDto = new RuleDto()
ruleDao.insert(ruleDto, sqlSession);
buffer.add(ruleDto);
- for (RuleDefinitions.Param param : ruleDef.params()) {
+ for (RulesDefinition.Param param : ruleDef.params()) {
RuleParamDto paramDto = new RuleParamDto()
.setRuleId(ruleDto.getId())
.setDefaultValue(param.defaultValue())
return ruleDto;
}
- private void enableAndUpdate(Buffer buffer, SqlSession sqlSession, RuleDefinitions.Rule ruleDef, RuleDto dto, List<CharacteristicDto> characteristicDtos) {
+ private void enableAndUpdate(Buffer buffer, SqlSession sqlSession, RulesDefinition.Rule ruleDef, RuleDto dto, List<CharacteristicDto> characteristicDtos) {
if (mergeRule(buffer, ruleDef, dto, characteristicDtos)) {
ruleDao.update(dto);
}
buffer.markProcessed(dto);
}
- private boolean mergeRule(Buffer buffer, RuleDefinitions.Rule def, RuleDto dto, List<CharacteristicDto> characteristicDtos) {
+ private boolean mergeRule(Buffer buffer, RulesDefinition.Rule def, RuleDto dto, List<CharacteristicDto> characteristicDtos) {
boolean changed = false;
if (!StringUtils.equals(dto.getName(), def.name())) {
dto.setName(def.name());
return changed;
}
- private boolean mergeDebtDefinitions(RuleDefinitions.Rule def, RuleDto dto, List<CharacteristicDto> characteristicDtos) {
+ private boolean mergeDebtDefinitions(RulesDefinition.Rule def, RuleDto dto, List<CharacteristicDto> characteristicDtos) {
boolean changed = false;
CharacteristicDto characteristic = findCharacteristic(characteristicDtos, def);
return changed;
}
- private void mergeParams(Buffer buffer, SqlSession sqlSession, RuleDefinitions.Rule ruleDef, RuleDto dto) {
+ private void mergeParams(Buffer buffer, SqlSession sqlSession, RulesDefinition.Rule ruleDef, RuleDto dto) {
Collection<RuleParamDto> paramDtos = buffer.paramsForRuleId(dto.getId());
Set<String> persistedParamKeys = Sets.newHashSet();
for (RuleParamDto paramDto : paramDtos) {
- RuleDefinitions.Param paramDef = ruleDef.param(paramDto.getName());
+ RulesDefinition.Param paramDef = ruleDef.param(paramDto.getName());
if (paramDef == null) {
activeRuleDao.deleteParametersWithParamId(paramDto.getId(), sqlSession);
ruleDao.deleteParam(paramDto, sqlSession);
persistedParamKeys.add(paramDto.getName());
}
}
- for (RuleDefinitions.Param param : ruleDef.params()) {
+ for (RulesDefinition.Param param : ruleDef.params()) {
if (!persistedParamKeys.contains(param.key())) {
RuleParamDto paramDto = new RuleParamDto()
.setRuleId(dto.getId())
}
}
- private boolean mergeParam(RuleParamDto paramDto, RuleDefinitions.Param paramDef) {
+ private boolean mergeParam(RuleParamDto paramDto, RulesDefinition.Param paramDef) {
boolean changed = false;
if (!StringUtils.equals(paramDto.getType(), paramDef.type().toString())) {
paramDto.setType(paramDef.type().toString());
return changed;
}
- private void mergeTags(Buffer buffer, SqlSession sqlSession, RuleDefinitions.Rule ruleDef, RuleDto dto) {
+ private void mergeTags(Buffer buffer, SqlSession sqlSession, RulesDefinition.Rule ruleDef, RuleDto dto) {
Set<String> existingSystemTags = Sets.newHashSet();
Collection<RuleRuleTagDto> tagDtos = ImmutableList.copyOf(buffer.tagsForRuleId(dto.getId()));
* The side effect of this approach is that extended repositories will not be managed the same way.
* If an extended repository do not exists anymore, then related active rules will be removed.
*/
- private void removeActiveRulesOnStillExistingRepositories(List<RuleDto> removedRules, RuleDefinitions.Context context) {
- List<String> repositoryKeys = newArrayList(Iterables.transform(context.repositories(), new Function<RuleDefinitions.Repository, String>() {
+ private void removeActiveRulesOnStillExistingRepositories(List<RuleDto> removedRules, RulesDefinition.Context context) {
+ List<String> repositoryKeys = newArrayList(Iterables.transform(context.repositories(), new Function<RulesDefinition.Repository, String>() {
@Override
- public String apply(RuleDefinitions.Repository input) {
+ public String apply(RulesDefinition.Repository input) {
return input.key();
}
}
}
@CheckForNull
- private CharacteristicDto findCharacteristic(List<CharacteristicDto> characteristicDtos, RuleDefinitions.Rule ruleDef) {
+ private CharacteristicDto findCharacteristic(List<CharacteristicDto> characteristicDtos, RulesDefinition.Rule ruleDef) {
final String key = ruleDef.characteristicKey();
if (key == null) {
// Rule is not linked to a characteristic, nothing to do
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.SetMultimap;
import org.sonar.api.ServerComponent;
-import org.sonar.api.server.rule.RuleDefinitions;
+import org.sonar.api.server.rule.RulesDefinition;
import javax.annotation.CheckForNull;
+
import java.util.Collection;
import java.util.Map;
import java.util.SortedSet;
public static class Repository implements Comparable<Repository> {
private final String key, name, language;
- private Repository(RuleDefinitions.Repository repoDef) {
+ private Repository(RulesDefinition.Repository repoDef) {
this.key = repoDef.key();
this.name = repoDef.name();
this.language = repoDef.language();
private Map<String, Repository> repositoriesByKey;
private SetMultimap<String, Repository> repositoriesByLang;
- void register(RuleDefinitions.Context context) {
+ void register(RulesDefinition.Context context) {
ImmutableSortedSet.Builder<Repository> listBuilder = ImmutableSortedSet.naturalOrder();
ImmutableSetMultimap.Builder<String, Repository> langBuilder = ImmutableSetMultimap.builder();
ImmutableMap.Builder<String, Repository> keyBuilder = ImmutableMap.builder();
- for (RuleDefinitions.Repository repoDef : context.repositories()) {
+ for (RulesDefinition.Repository repoDef : context.repositories()) {
Repository repository = new Repository(repoDef);
listBuilder.add(repository);
langBuilder.put(repository.language(), repository);
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.server.rule;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-import org.sonar.api.rule.RemediationFunction;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.RuleStatus;
-import org.sonar.api.rule.Severity;
-import org.sonar.api.rules.Rule;
-import org.sonar.api.rules.RulePriority;
-import org.sonar.api.rules.RuleRepository;
-import org.sonar.api.server.rule.RuleDefinitions;
-import org.sonar.core.i18n.RuleI18nManager;
-import org.sonar.core.technicaldebt.DebtRulesXMLImporter;
-import org.sonar.core.technicaldebt.TechnicalDebtModelRepository;
-
-import java.io.Reader;
-import java.util.Arrays;
-import java.util.List;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class DeprecatedRuleDefinitionsTest {
-
- @Mock
- RuleI18nManager i18n;
-
- @Mock
- TechnicalDebtModelRepository debtModelRepository;
-
- @Mock
- DebtRulesXMLImporter importer;
-
- static class CheckstyleRules extends RuleRepository {
- public CheckstyleRules() {
- super("checkstyle", "java");
- setName("Checkstyle");
- }
-
- @Override
- public List<Rule> createRules() {
- Rule rule = Rule.create("checkstyle", "ConstantName", "Constant Name");
- rule.setDescription("Checks that constant names conform to the specified format");
- rule.setConfigKey("Checker/TreeWalker/ConstantName");
- rule.setSeverity(RulePriority.BLOCKER);
- rule.setStatus(Rule.STATUS_BETA);
- rule.setTags(new String[]{"style", "security"});
- rule.createParameter("format").setDescription("Regular expression").setDefaultValue("A-Z").setType("REGULAR_EXPRESSION");
- return Arrays.asList(rule);
- }
- }
-
- static class UseBundles extends RuleRepository {
- public UseBundles() {
- super("checkstyle", "java");
- setName("Checkstyle");
- }
-
- @Override
- public List<Rule> createRules() {
- Rule rule = Rule.create("checkstyle", "ConstantName");
- rule.createParameter("format");
- return Arrays.asList(rule);
- }
- }
-
- @Test
- public void wrap_deprecated_rule_repositories() throws Exception {
- RuleDefinitions.Context context = new RuleDefinitions.Context();
- new DeprecatedRuleDefinitions(i18n, new RuleRepository[]{new CheckstyleRules()}, debtModelRepository, importer).define(context);
-
- assertThat(context.repositories()).hasSize(1);
- RuleDefinitions.Repository checkstyle = context.repository("checkstyle");
- assertThat(checkstyle).isNotNull();
- assertThat(checkstyle.key()).isEqualTo("checkstyle");
- assertThat(checkstyle.name()).isEqualTo("Checkstyle");
- assertThat(checkstyle.language()).isEqualTo("java");
- assertThat(checkstyle.rules()).hasSize(1);
- RuleDefinitions.Rule rule = checkstyle.rule("ConstantName");
- assertThat(rule).isNotNull();
- assertThat(rule.key()).isEqualTo("ConstantName");
- assertThat(rule.name()).isEqualTo("Constant Name");
- assertThat(rule.htmlDescription()).isEqualTo("Checks that constant names conform to the specified format");
- assertThat(rule.severity()).isEqualTo(Severity.BLOCKER);
- assertThat(rule.internalKey()).isEqualTo("Checker/TreeWalker/ConstantName");
- assertThat(rule.status()).isEqualTo(RuleStatus.BETA);
- assertThat(rule.tags()).containsOnly("style", "security");
- assertThat(rule.params()).hasSize(1);
- RuleDefinitions.Param param = rule.param("format");
- assertThat(param).isNotNull();
- assertThat(param.key()).isEqualTo("format");
- assertThat(param.name()).isEqualTo("format");
- assertThat(param.description()).isEqualTo("Regular expression");
- assertThat(param.defaultValue()).isEqualTo("A-Z");
- }
-
- @Test
- public void emulate_the_day_deprecated_api_can_be_dropped() throws Exception {
- RuleDefinitions.Context context = new RuleDefinitions.Context();
-
- // no more RuleRepository !
- new DeprecatedRuleDefinitions(i18n, debtModelRepository, importer);
-
- assertThat(context.repositories()).isEmpty();
- }
-
- @Test
- public void use_l10n_bundles() throws Exception {
- RuleDefinitions.Context context = new RuleDefinitions.Context();
- when(i18n.getName("checkstyle", "ConstantName")).thenReturn("Constant Name");
- when(i18n.getDescription("checkstyle", "ConstantName")).thenReturn("Checks that constant names conform to the specified format");
- when(i18n.getParamDescription("checkstyle", "ConstantName", "format")).thenReturn("Regular expression");
-
- new DeprecatedRuleDefinitions(i18n, new RuleRepository[]{new UseBundles()}, debtModelRepository, importer).define(context);
-
- RuleDefinitions.Repository checkstyle = context.repository("checkstyle");
- RuleDefinitions.Rule rule = checkstyle.rule("ConstantName");
- assertThat(rule.key()).isEqualTo("ConstantName");
- assertThat(rule.name()).isEqualTo("Constant Name");
- assertThat(rule.htmlDescription()).isEqualTo("Checks that constant names conform to the specified format");
- RuleDefinitions.Param param = rule.param("format");
- assertThat(param.key()).isEqualTo("format");
- assertThat(param.name()).isEqualTo("format");
- assertThat(param.description()).isEqualTo("Regular expression");
- }
-
- @Test
- public void define_rule_debt() throws Exception {
- RuleDefinitions.Context context = new RuleDefinitions.Context();
-
- List<DebtRulesXMLImporter.RuleDebt> ruleDebts = newArrayList(
- new DebtRulesXMLImporter.RuleDebt()
- .setCharacteristicKey("MEMORY_EFFICIENCY")
- .setRuleKey(RuleKey.of("checkstyle", "ConstantName"))
- .setFunction(RemediationFunction.LINEAR_OFFSET)
- .setFactor("1d")
- .setOffset("10min")
- );
-
- Reader javaModelReader = mock(Reader.class);
- when(debtModelRepository.createReaderForXMLFile("java")).thenReturn(javaModelReader);
- when(debtModelRepository.getContributingPluginList()).thenReturn(newArrayList("java"));
- when(importer.importXML(eq(javaModelReader))).thenReturn(ruleDebts);
-
- new DeprecatedRuleDefinitions(i18n, new RuleRepository[]{new CheckstyleRules()}, debtModelRepository, importer).define(context);
-
- assertThat(context.repositories()).hasSize(1);
- RuleDefinitions.Repository checkstyle = context.repository("checkstyle");
- assertThat(checkstyle.rules()).hasSize(1);
-
- RuleDefinitions.Rule rule = checkstyle.rule("ConstantName");
- assertThat(rule).isNotNull();
- assertThat(rule.key()).isEqualTo("ConstantName");
- assertThat(rule.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
- assertThat(rule.remediationFunction()).isEqualTo(RemediationFunction.LINEAR_OFFSET);
- assertThat(rule.remediationFactor()).isEqualTo("1d");
- assertThat(rule.remediationOffset()).isEqualTo("10min");
- }
-
-}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.server.rule;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.sonar.api.rule.RemediationFunction;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.RuleStatus;
+import org.sonar.api.rule.Severity;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RulePriority;
+import org.sonar.api.rules.RuleRepository;
+import org.sonar.api.server.rule.RulesDefinition;
+import org.sonar.core.i18n.RuleI18nManager;
+import org.sonar.core.technicaldebt.DebtRulesXMLImporter;
+import org.sonar.core.technicaldebt.TechnicalDebtModelRepository;
+
+import java.io.Reader;
+import java.util.Arrays;
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class DeprecatedRulesDefinitionTest {
+
+ @Mock
+ RuleI18nManager i18n;
+
+ @Mock
+ TechnicalDebtModelRepository debtModelRepository;
+
+ @Mock
+ DebtRulesXMLImporter importer;
+
+ static class CheckstyleRules extends RuleRepository {
+ public CheckstyleRules() {
+ super("checkstyle", "java");
+ setName("Checkstyle");
+ }
+
+ @Override
+ public List<Rule> createRules() {
+ Rule rule = Rule.create("checkstyle", "ConstantName", "Constant Name");
+ rule.setDescription("Checks that constant names conform to the specified format");
+ rule.setConfigKey("Checker/TreeWalker/ConstantName");
+ rule.setSeverity(RulePriority.BLOCKER);
+ rule.setStatus(Rule.STATUS_BETA);
+ rule.setTags(new String[]{"style", "security"});
+ rule.createParameter("format").setDescription("Regular expression").setDefaultValue("A-Z").setType("REGULAR_EXPRESSION");
+ return Arrays.asList(rule);
+ }
+ }
+
+ static class UseBundles extends RuleRepository {
+ public UseBundles() {
+ super("checkstyle", "java");
+ setName("Checkstyle");
+ }
+
+ @Override
+ public List<Rule> createRules() {
+ Rule rule = Rule.create("checkstyle", "ConstantName");
+ rule.createParameter("format");
+ return Arrays.asList(rule);
+ }
+ }
+
+ @Test
+ public void wrap_deprecated_rule_repositories() throws Exception {
+ RulesDefinition.Context context = new RulesDefinition.Context();
+ new DeprecatedRulesDefinition(i18n, new RuleRepository[]{new CheckstyleRules()}, debtModelRepository, importer).define(context);
+
+ assertThat(context.repositories()).hasSize(1);
+ RulesDefinition.Repository checkstyle = context.repository("checkstyle");
+ assertThat(checkstyle).isNotNull();
+ assertThat(checkstyle.key()).isEqualTo("checkstyle");
+ assertThat(checkstyle.name()).isEqualTo("Checkstyle");
+ assertThat(checkstyle.language()).isEqualTo("java");
+ assertThat(checkstyle.rules()).hasSize(1);
+ RulesDefinition.Rule rule = checkstyle.rule("ConstantName");
+ assertThat(rule).isNotNull();
+ assertThat(rule.key()).isEqualTo("ConstantName");
+ assertThat(rule.name()).isEqualTo("Constant Name");
+ assertThat(rule.htmlDescription()).isEqualTo("Checks that constant names conform to the specified format");
+ assertThat(rule.severity()).isEqualTo(Severity.BLOCKER);
+ assertThat(rule.internalKey()).isEqualTo("Checker/TreeWalker/ConstantName");
+ assertThat(rule.status()).isEqualTo(RuleStatus.BETA);
+ assertThat(rule.tags()).containsOnly("style", "security");
+ assertThat(rule.params()).hasSize(1);
+ RulesDefinition.Param param = rule.param("format");
+ assertThat(param).isNotNull();
+ assertThat(param.key()).isEqualTo("format");
+ assertThat(param.name()).isEqualTo("format");
+ assertThat(param.description()).isEqualTo("Regular expression");
+ assertThat(param.defaultValue()).isEqualTo("A-Z");
+ }
+
+ @Test
+ public void emulate_the_day_deprecated_api_can_be_dropped() throws Exception {
+ RulesDefinition.Context context = new RulesDefinition.Context();
+
+ // no more RuleRepository !
+ new DeprecatedRulesDefinition(i18n, debtModelRepository, importer);
+
+ assertThat(context.repositories()).isEmpty();
+ }
+
+ @Test
+ public void use_l10n_bundles() throws Exception {
+ RulesDefinition.Context context = new RulesDefinition.Context();
+ when(i18n.getName("checkstyle", "ConstantName")).thenReturn("Constant Name");
+ when(i18n.getDescription("checkstyle", "ConstantName")).thenReturn("Checks that constant names conform to the specified format");
+ when(i18n.getParamDescription("checkstyle", "ConstantName", "format")).thenReturn("Regular expression");
+
+ new DeprecatedRulesDefinition(i18n, new RuleRepository[]{new UseBundles()}, debtModelRepository, importer).define(context);
+
+ RulesDefinition.Repository checkstyle = context.repository("checkstyle");
+ RulesDefinition.Rule rule = checkstyle.rule("ConstantName");
+ assertThat(rule.key()).isEqualTo("ConstantName");
+ assertThat(rule.name()).isEqualTo("Constant Name");
+ assertThat(rule.htmlDescription()).isEqualTo("Checks that constant names conform to the specified format");
+ RulesDefinition.Param param = rule.param("format");
+ assertThat(param.key()).isEqualTo("format");
+ assertThat(param.name()).isEqualTo("format");
+ assertThat(param.description()).isEqualTo("Regular expression");
+ }
+
+ @Test
+ public void define_rule_debt() throws Exception {
+ RulesDefinition.Context context = new RulesDefinition.Context();
+
+ List<DebtRulesXMLImporter.RuleDebt> ruleDebts = newArrayList(
+ new DebtRulesXMLImporter.RuleDebt()
+ .setCharacteristicKey("MEMORY_EFFICIENCY")
+ .setRuleKey(RuleKey.of("checkstyle", "ConstantName"))
+ .setFunction(RemediationFunction.LINEAR_OFFSET)
+ .setFactor("1d")
+ .setOffset("10min")
+ );
+
+ Reader javaModelReader = mock(Reader.class);
+ when(debtModelRepository.createReaderForXMLFile("java")).thenReturn(javaModelReader);
+ when(debtModelRepository.getContributingPluginList()).thenReturn(newArrayList("java"));
+ when(importer.importXML(eq(javaModelReader))).thenReturn(ruleDebts);
+
+ new DeprecatedRulesDefinition(i18n, new RuleRepository[]{new CheckstyleRules()}, debtModelRepository, importer).define(context);
+
+ assertThat(context.repositories()).hasSize(1);
+ RulesDefinition.Repository checkstyle = context.repository("checkstyle");
+ assertThat(checkstyle.rules()).hasSize(1);
+
+ RulesDefinition.Rule rule = checkstyle.rule("ConstantName");
+ assertThat(rule).isNotNull();
+ assertThat(rule.key()).isEqualTo("ConstantName");
+ assertThat(rule.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
+ assertThat(rule.remediationFunction()).isEqualTo(RemediationFunction.LINEAR_OFFSET);
+ assertThat(rule.remediationFactor()).isEqualTo("1d");
+ assertThat(rule.remediationOffset()).isEqualTo("10min");
+ }
+
+}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.server.rule;
-
-import org.junit.Test;
-import org.sonar.api.server.rule.RuleDefinitions;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class RuleDefinitionsLoaderTest {
- @Test
- public void no_definitions() {
- RuleRepositories repositories = new RuleRepositories();
-
- RuleDefinitions.Context context = new RuleDefinitionsLoader(repositories).load();
-
- assertThat(context.repositories()).isEmpty();
- assertThat(repositories.repositories()).isEmpty();
- }
-
- @Test
- public void load_definitions() {
- RuleRepositories repositories = new RuleRepositories();
-
- RuleDefinitions.Context context = new RuleDefinitionsLoader(repositories, new RuleDefinitions[]{
- new FindbugsDefinitions(), new SquidDefinitions()
- }).load();
-
- assertThat(context.repositories()).hasSize(2);
- assertThat(context.repository("findbugs")).isNotNull();
- assertThat(context.repository("squid")).isNotNull();
- assertThat(repositories.repositories()).hasSize(2);
- assertThat(repositories.repository("findbugs")).isNotNull();
- assertThat(repositories.repository("squid")).isNotNull();
- }
-
- static class FindbugsDefinitions implements RuleDefinitions {
- @Override
- public void define(Context context) {
- NewRepository repo = context.createRepository("findbugs", "java");
- repo.setName("Findbugs");
- repo.createRule("ABC")
- .setName("ABC")
- .setHtmlDescription("Description of ABC");
- repo.done();
- }
- }
-
- static class SquidDefinitions implements RuleDefinitions {
- @Override
- public void define(Context context) {
- NewRepository repo = context.createRepository("squid", "java");
- repo.setName("Squid");
- repo.createRule("DEF")
- .setName("DEF")
- .setHtmlDescription("Description of DEF");
- repo.done();
- }
- }
-}
import org.sonar.api.rule.RemediationFunction;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rule.Severity;
-import org.sonar.api.server.rule.RuleDefinitions;
+import org.sonar.api.server.rule.RulesDefinition;
import org.sonar.api.utils.MessageException;
import org.sonar.core.persistence.AbstractDaoTestCase;
import org.sonar.core.persistence.MyBatis;
activeRuleDao = new ActiveRuleDao(myBatis);
ruleTagOperations = new RuleTagOperations(ruleTagDao, esRuleTags);
characteristicDao = new CharacteristicDao(myBatis);
- task = new RuleRegistration(new RuleDefinitionsLoader(mock(RuleRepositories.class), new RuleDefinitions[]{new FakeRepository()}),
+ task = new RuleRegistration(new RuleDefinitionsLoader(mock(RuleRepositories.class), new RulesDefinition[]{new FakeRepository()}),
profilesManager, ruleRegistry, esRuleTags, ruleTagOperations, myBatis, ruleDao, ruleTagDao, activeRuleDao, characteristicDao, mock(RegisterDebtModel.class));
}
@Test
public void test_high_number_of_rules() {
- task = new RuleRegistration(new RuleDefinitionsLoader(mock(RuleRepositories.class), new RuleDefinitions[]{new BigRepository()}),
+ task = new RuleRegistration(new RuleDefinitionsLoader(mock(RuleRepositories.class), new RulesDefinition[]{new BigRepository()}),
profilesManager, ruleRegistry, esRuleTags, ruleTagOperations, myBatis, ruleDao, ruleTagDao, activeRuleDao, characteristicDao, mock(RegisterDebtModel.class));
setupData("shared");
@Test
public void insert_extended_repositories() {
- task = new RuleRegistration(new RuleDefinitionsLoader(mock(RuleRepositories.class), new RuleDefinitions[]{
+ task = new RuleRegistration(new RuleDefinitionsLoader(mock(RuleRepositories.class), new RulesDefinition[]{
new FindbugsRepository(), new FbContribRepository()}),
profilesManager, ruleRegistry, esRuleTags, ruleTagOperations, myBatis, ruleDao, ruleTagDao, activeRuleDao, characteristicDao, mock(RegisterDebtModel.class));
checkTables("insert_extended_repositories", EXCLUDED_COLUMN_NAMES_INCLUDING_DEBT, "rules");
}
- static class FakeRepository implements RuleDefinitions {
+ static class FakeRepository implements RulesDefinition {
@Override
public void define(Context context) {
NewRepository repo = context.createRepository("fake", "java");
}
}
- static class BigRepository implements RuleDefinitions {
+ static class BigRepository implements RulesDefinition {
static final int SIZE = 500;
@Override
}
}
- static class FindbugsRepository implements RuleDefinitions {
+ static class FindbugsRepository implements RulesDefinition {
@Override
public void define(Context context) {
NewRepository repo = context.createRepository("findbugs", "java");
}
}
- static class FbContribRepository implements RuleDefinitions {
+ static class FbContribRepository implements RulesDefinition {
@Override
public void define(Context context) {
NewExtendedRepository repo = context.extendRepository("findbugs", "java");
package org.sonar.server.rule;
import org.junit.Test;
-import org.sonar.api.server.rule.RuleDefinitions;
+import org.sonar.api.server.rule.RulesDefinition;
import static org.fest.assertions.Assertions.assertThat;
public class RuleRepositoriesTest {
@Test
public void should_register_repositories() {
- RuleDefinitions.Context context = new RuleDefinitions.Context();
+ RulesDefinition.Context context = new RulesDefinition.Context();
new SquidDefinitions().define(context);
new FindbugsDefinitions().define(context);
assertThat(findbugs).isEqualTo(findbugs).isNotEqualTo(squid).isNotEqualTo("findbugs").isNotEqualTo(null);
}
- static class FindbugsDefinitions implements RuleDefinitions {
+ static class FindbugsDefinitions implements RulesDefinition {
@Override
public void define(Context context) {
NewRepository repo = context.createRepository("findbugs", "java");
}
}
- static class SquidDefinitions implements RuleDefinitions {
+ static class SquidDefinitions implements RulesDefinition {
@Override
public void define(Context context) {
NewRepository repo = context.createRepository("squid", "java");
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.server.rule;
+
+import org.junit.Test;
+import org.sonar.api.server.rule.RulesDefinition;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class RulesDefinitionLoaderTest {
+ @Test
+ public void no_definitions() {
+ RuleRepositories repositories = new RuleRepositories();
+
+ RulesDefinition.Context context = new RuleDefinitionsLoader(repositories).load();
+
+ assertThat(context.repositories()).isEmpty();
+ assertThat(repositories.repositories()).isEmpty();
+ }
+
+ @Test
+ public void load_definitions() {
+ RuleRepositories repositories = new RuleRepositories();
+
+ RulesDefinition.Context context = new RuleDefinitionsLoader(repositories, new RulesDefinition[]{
+ new FindbugsDefinitions(), new SquidDefinitions()
+ }).load();
+
+ assertThat(context.repositories()).hasSize(2);
+ assertThat(context.repository("findbugs")).isNotNull();
+ assertThat(context.repository("squid")).isNotNull();
+ assertThat(repositories.repositories()).hasSize(2);
+ assertThat(repositories.repository("findbugs")).isNotNull();
+ assertThat(repositories.repository("squid")).isNotNull();
+ }
+
+ static class FindbugsDefinitions implements RulesDefinition {
+ @Override
+ public void define(Context context) {
+ NewRepository repo = context.createRepository("findbugs", "java");
+ repo.setName("Findbugs");
+ repo.createRule("ABC")
+ .setName("ABC")
+ .setHtmlDescription("Description of ABC");
+ repo.done();
+ }
+ }
+
+ static class SquidDefinitions implements RulesDefinition {
+ @Override
+ public void define(Context context) {
+ NewRepository repo = context.createRepository("squid", "java");
+ repo.setName("Squid");
+ repo.createRule("DEF")
+ .setName("DEF")
+ .setHtmlDescription("Description of DEF");
+ repo.done();
+ }
+ }
+}