aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-server/src
diff options
context:
space:
mode:
authorJulien Lancelot <julien.lancelot@sonarsource.com>2014-06-16 14:08:01 +0200
committerJulien Lancelot <julien.lancelot@sonarsource.com>2014-06-16 14:15:15 +0200
commit3665c9298b15f8d5242259df84482574fdf62b5e (patch)
tree5bae351ed42bcdd39152f809a6a4127ff5fb4ae4 /sonar-server/src
parent6375e8f2d0b8c8cc7479dd8327a05985e5248b78 (diff)
downloadsonarqube-3665c9298b15f8d5242259df84482574fdf62b5e.tar.gz
sonarqube-3665c9298b15f8d5242259df84482574fdf62b5e.zip
SONAR-4514 New web service to manage manual rules
Diffstat (limited to 'sonar-server/src')
-rw-r--r--sonar-server/src/main/java/org/sonar/server/rule/NewRule.java47
-rw-r--r--sonar-server/src/main/java/org/sonar/server/rule/RubyRuleService.java2
-rw-r--r--sonar-server/src/main/java/org/sonar/server/rule/Rule.java2
-rw-r--r--sonar-server/src/main/java/org/sonar/server/rule/RuleCreator.java68
-rw-r--r--sonar-server/src/main/java/org/sonar/server/rule/RuleUpdate.java40
-rw-r--r--sonar-server/src/main/java/org/sonar/server/rule/index/RuleDoc.java23
-rw-r--r--sonar-server/src/main/java/org/sonar/server/rule/ws/CreateAction.java60
-rw-r--r--sonar-server/src/main/java/org/sonar/server/rule/ws/UpdateAction.java4
-rw-r--r--sonar-server/src/test/java/org/sonar/server/rule/RegisterRulesMediumTest.java12
-rw-r--r--sonar-server/src/test/java/org/sonar/server/rule/RuleCreatorMediumTest.java211
-rw-r--r--sonar-server/src/test/java/org/sonar/server/rule/RuleServiceMediumTest.java18
-rw-r--r--sonar-server/src/test/java/org/sonar/server/rule/RuleTesting.java7
-rw-r--r--sonar-server/src/test/java/org/sonar/server/rule/RuleUpdaterMediumTest.java137
-rw-r--r--sonar-server/src/test/java/org/sonar/server/rule/ws/CreateActionMediumTest.java53
-rw-r--r--sonar-server/src/test/java/org/sonar/server/rule/ws/UpdateActionMediumTest.java4
-rw-r--r--sonar-server/src/test/resources/org/sonar/server/rule/ws/CreateActionMediumTest/create_manual_rule.json14
-rw-r--r--sonar-server/src/test/resources/org/sonar/server/rule/ws/CreateActionMediumTest/create_manual_rule_without_severity.json13
17 files changed, 579 insertions, 136 deletions
diff --git a/sonar-server/src/main/java/org/sonar/server/rule/NewRule.java b/sonar-server/src/main/java/org/sonar/server/rule/NewRule.java
index 4ae05bf8632..3b2b2539a0a 100644
--- a/sonar-server/src/main/java/org/sonar/server/rule/NewRule.java
+++ b/sonar-server/src/main/java/org/sonar/server/rule/NewRule.java
@@ -19,6 +19,8 @@
*/
package org.sonar.server.rule;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.RuleStatus;
@@ -36,13 +38,14 @@ public class NewRule {
private RuleStatus status;
private final Map<String, String> parameters = Maps.newHashMap();
- public String ruleKey() {
- return ruleKey;
+ private boolean isCustomRule = false;
+
+ private NewRule() {
+ // No direct call to constructor
}
- public NewRule setRuleKey(String ruleKey) {
- this.ruleKey = ruleKey;
- return this;
+ public String ruleKey() {
+ return ruleKey;
}
@CheckForNull
@@ -50,14 +53,6 @@ public class NewRule {
return templateKey;
}
- /**
- * For the creation a custom rule
- */
- public NewRule setTemplateKey(@Nullable RuleKey templateKey) {
- this.templateKey = templateKey;
- return this;
- }
-
@CheckForNull
public String name() {
return name;
@@ -94,6 +89,7 @@ public class NewRule {
}
public NewRule setStatus(@Nullable RuleStatus status) {
+ checkCustomRule();
this.status = status;
return this;
}
@@ -108,8 +104,33 @@ public class NewRule {
}
public NewRule setParameters(Map<String, String> params) {
+ checkCustomRule();
this.parameters.clear();
this.parameters.putAll(params);
return this;
}
+
+ private void checkCustomRule(){
+ if (!isCustomRule) {
+ throw new IllegalStateException("Not a custom rule");
+ }
+ }
+
+ public static NewRule createForCustomRule(String customKey, RuleKey templateKey) {
+ Preconditions.checkArgument(!Strings.isNullOrEmpty(customKey), "Custom key should be set");
+ Preconditions.checkArgument(templateKey != null, "Template key should be set");
+ NewRule newRule = new NewRule();
+ newRule.ruleKey = customKey;
+ newRule.templateKey = templateKey;
+ newRule.isCustomRule = true;
+ return newRule;
+ }
+
+ public static NewRule createForManualRule(String manualKey) {
+ Preconditions.checkArgument(!Strings.isNullOrEmpty(manualKey), "Manual key should be set");
+ NewRule newRule = new NewRule();
+ newRule.ruleKey = manualKey;
+ return newRule;
+ }
+
}
diff --git a/sonar-server/src/main/java/org/sonar/server/rule/RubyRuleService.java b/sonar-server/src/main/java/org/sonar/server/rule/RubyRuleService.java
index 66a27e4ab80..ef362e4372d 100644
--- a/sonar-server/src/main/java/org/sonar/server/rule/RubyRuleService.java
+++ b/sonar-server/src/main/java/org/sonar/server/rule/RubyRuleService.java
@@ -87,7 +87,7 @@ public class RubyRuleService implements ServerComponent, Startable {
// sqale
public void updateRule(Map<String, Object> params) {
- RuleUpdate update = new RuleUpdate(RuleKey.parse((String) params.get("ruleKey")));
+ RuleUpdate update = RuleUpdate.createForPluginRule(RuleKey.parse((String) params.get("ruleKey")));
update.setDebtSubCharacteristic(Strings.emptyToNull((String) params.get("debtCharacteristicKey")));
String fn = (String) params.get("debtRemediationFunction");
if (fn == null) {
diff --git a/sonar-server/src/main/java/org/sonar/server/rule/Rule.java b/sonar-server/src/main/java/org/sonar/server/rule/Rule.java
index 5237f23c7b1..74b785903ad 100644
--- a/sonar-server/src/main/java/org/sonar/server/rule/Rule.java
+++ b/sonar-server/src/main/java/org/sonar/server/rule/Rule.java
@@ -100,4 +100,6 @@ public interface Rule {
@CheckForNull
Date noteUpdatedAt();
+
+ boolean isManual();
}
diff --git a/sonar-server/src/main/java/org/sonar/server/rule/RuleCreator.java b/sonar-server/src/main/java/org/sonar/server/rule/RuleCreator.java
index 6e43422287e..48ad462dce3 100644
--- a/sonar-server/src/main/java/org/sonar/server/rule/RuleCreator.java
+++ b/sonar-server/src/main/java/org/sonar/server/rule/RuleCreator.java
@@ -23,11 +23,13 @@ package org.sonar.server.rule;
import com.google.common.base.Strings;
import org.sonar.api.ServerComponent;
import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rule.Severity;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.rule.RuleDto;
import org.sonar.core.rule.RuleParamDto;
import org.sonar.server.db.DbClient;
+import org.sonar.server.rule.index.RuleDoc;
public class RuleCreator implements ServerComponent {
@@ -41,33 +43,41 @@ public class RuleCreator implements ServerComponent {
DbSession dbSession = dbClient.openSession(false);
try {
RuleKey templateKey = newRule.templateKey();
+ // Creation of a custom rule
if (templateKey != null) {
RuleDto templateRule = dbClient.ruleDao().getByKey(dbSession, templateKey);
if (!templateRule.isTemplate()) {
throw new IllegalArgumentException("This rule is not a template rule: " + templateKey.toString());
}
- validateRule(newRule);
+ validateCustomRule(newRule);
RuleKey customRuleKey = RuleKey.of(templateRule.getRepositoryKey(), newRule.ruleKey());
checkRuleKeyUnicity(customRuleKey, dbSession);
createCustomRule(customRuleKey, newRule, templateRule, dbSession);
+
+ dbSession.commit();
+ return customRuleKey;
+ } else {
+ // Creation of a manual rule
+ validateManualRule(newRule);
+
+ RuleKey customRuleKey = RuleKey.of(RuleDoc.MANUAL_REPOSITORY, newRule.ruleKey());
+ checkRuleKeyUnicity(customRuleKey, dbSession);
+ createManualRule(customRuleKey, newRule, dbSession);
+
dbSession.commit();
return customRuleKey;
}
- throw new IllegalArgumentException("Not supported");
} finally {
dbSession.close();
}
}
- private static void validateRule(NewRule newRule) {
+ private static void validateCustomRule(NewRule newRule) {
validateRuleKey(newRule.ruleKey());
- if (Strings.isNullOrEmpty(newRule.name())) {
- throw new IllegalArgumentException("The name is missing");
- }
- if (Strings.isNullOrEmpty(newRule.htmlDescription())) {
- throw new IllegalArgumentException("The description is missing");
- }
+ validateName(newRule);
+ validateDescription(newRule);
+
String severity = newRule.severity();
if (Strings.isNullOrEmpty(severity)) {
throw new IllegalArgumentException("The severity is missing");
@@ -79,13 +89,31 @@ public class RuleCreator implements ServerComponent {
}
}
+ private static void validateManualRule(NewRule newRule) {
+ validateRuleKey(newRule.ruleKey());
+ validateName(newRule);
+ validateDescription(newRule);
+
+ if (!newRule.parameters().isEmpty()) {
+ throw new IllegalArgumentException("No parameter can be set on a manual rule");
+ }
+ }
+
+ private static void validateName(NewRule newRule){
+ if (Strings.isNullOrEmpty(newRule.name())) {
+ throw new IllegalArgumentException("The name is missing");
+ }
+ }
+
+ private static void validateDescription(NewRule newRule){
+ if (Strings.isNullOrEmpty(newRule.htmlDescription())) {
+ throw new IllegalArgumentException("The description is missing");
+ }
+ }
+
private static void validateRuleKey(String ruleKey) {
- if (Strings.isNullOrEmpty(ruleKey)) {
- throw new IllegalArgumentException("The rule key is missing");
- } else {
- if (!ruleKey.matches("^[\\w]+$")) {
- throw new IllegalArgumentException(String.format("The rule key '%s' is invalid, it should only contains : a-z, 0-9, '_'", ruleKey));
- }
+ if (!ruleKey.matches("^[\\w]+$")) {
+ throw new IllegalArgumentException(String.format("The rule key '%s' is invalid, it should only contains : a-z, 0-9, '_'", ruleKey));
}
}
@@ -131,4 +159,14 @@ public class RuleCreator implements ServerComponent {
dbClient.ruleDao().addRuleParam(dbSession, ruleDto, ruleParamDto);
}
+ private RuleKey createManualRule(RuleKey ruleKey, NewRule newRule, DbSession dbSession){
+ RuleDto ruleDto = RuleDto.createFor(ruleKey)
+ .setName(newRule.name())
+ .setDescription(newRule.htmlDescription())
+ .setSeverity(newRule.severity())
+ .setStatus(RuleStatus.READY);
+ dbClient.ruleDao().insert(dbSession, ruleDto);
+ return ruleKey;
+ }
+
}
diff --git a/sonar-server/src/main/java/org/sonar/server/rule/RuleUpdate.java b/sonar-server/src/main/java/org/sonar/server/rule/RuleUpdate.java
index 584053fa04f..3b2f080afdd 100644
--- a/sonar-server/src/main/java/org/sonar/server/rule/RuleUpdate.java
+++ b/sonar-server/src/main/java/org/sonar/server/rule/RuleUpdate.java
@@ -39,7 +39,7 @@ public class RuleUpdate {
private boolean changeTags = false, changeMarkdownNote = false, changeDebtSubCharacteristic = false, changeDebtRemediationFunction = false,
changeName = false, changeDescription = false, changeSeverity = false, changeStatus = false, changeParameters = false;
- private boolean isCustomRule = false;
+ private boolean isCustomRule, isManual;
private Set<String> tags;
private String markdownNote;
private String debtSubCharacteristicKey;
@@ -49,7 +49,7 @@ public class RuleUpdate {
private RuleStatus status;
private final Map<String, String> parameters = Maps.newHashMap();
- public RuleUpdate(RuleKey ruleKey) {
+ private RuleUpdate(RuleKey ruleKey) {
this.ruleKey = ruleKey;
}
@@ -117,7 +117,7 @@ public class RuleUpdate {
}
public RuleUpdate setName(@Nullable String name) {
- checkCustomRule();
+ checkCustomOrManualRule();
this.name = name;
this.changeName = true;
return this;
@@ -129,7 +129,7 @@ public class RuleUpdate {
}
public RuleUpdate setHtmlDescription(@Nullable String htmlDescription) {
- checkCustomRule();
+ checkCustomOrManualRule();
this.htmlDescription = htmlDescription;
this.changeDescription = true;
return this;
@@ -141,7 +141,7 @@ public class RuleUpdate {
}
public RuleUpdate setSeverity(@Nullable String severity) {
- checkCustomRule();
+ checkCustomOrManualRule();
this.severity = severity;
this.changeSeverity = true;
return this;
@@ -233,13 +233,39 @@ public class RuleUpdate {
}
}
- public static RuleUpdate createForRule(RuleKey ruleKey) {
- return new RuleUpdate(ruleKey);
+ private void checkCustomOrManualRule(){
+ if (!isCustomRule && !isManual) {
+ throw new IllegalStateException("Not a custom or a manual rule");
+ }
+ }
+
+ /**
+ * Use to update a rule provided by a plugin (name, description, severity, status and parameters cannot by changed)
+ */
+ public static RuleUpdate createForPluginRule(RuleKey ruleKey) {
+ RuleUpdate ruleUpdate = new RuleUpdate(ruleKey);
+ ruleUpdate.isCustomRule = false;
+ ruleUpdate.isManual = false;
+ return ruleUpdate;
}
+ /**
+ * Use to update a custom rule
+ */
public static RuleUpdate createForCustomRule(RuleKey ruleKey) {
RuleUpdate ruleUpdate = new RuleUpdate(ruleKey);
ruleUpdate.isCustomRule = true;
+ ruleUpdate.isManual = false;
+ return ruleUpdate;
+ }
+
+ /**
+ * Use to update a manual rule (status and parameters cannot by changed)
+ */
+ public static RuleUpdate createForManualRule(RuleKey ruleKey) {
+ RuleUpdate ruleUpdate = new RuleUpdate(ruleKey);
+ ruleUpdate.isManual = true;
+ ruleUpdate.isCustomRule = false;
return ruleUpdate;
}
diff --git a/sonar-server/src/main/java/org/sonar/server/rule/index/RuleDoc.java b/sonar-server/src/main/java/org/sonar/server/rule/index/RuleDoc.java
index 960baebd6a5..3d3d7b30186 100644
--- a/sonar-server/src/main/java/org/sonar/server/rule/index/RuleDoc.java
+++ b/sonar-server/src/main/java/org/sonar/server/rule/index/RuleDoc.java
@@ -44,6 +44,8 @@ import java.util.Map;
*/
public class RuleDoc extends BaseDoc implements Rule {
+ public final static String MANUAL_REPOSITORY = "manual";
+
RuleDoc(@Nullable Map<String, Object> fields) {
super(fields);
}
@@ -69,13 +71,15 @@ public class RuleDoc extends BaseDoc implements Rule {
}
@Override
+ @CheckForNull
public String internalKey() {
return getNullableField(RuleNormalizer.RuleField.INTERNAL_KEY.field());
}
@Override
+ @CheckForNull
public String language() {
- return getField(RuleNormalizer.RuleField.LANGUAGE.field());
+ return getNullableField(RuleNormalizer.RuleField.LANGUAGE.field());
}
@Override
@@ -89,11 +93,13 @@ public class RuleDoc extends BaseDoc implements Rule {
}
@Override
+ @CheckForNull
public String severity() {
- return (String) getField(RuleNormalizer.RuleField.SEVERITY.field());
+ return (String) getNullableField(RuleNormalizer.RuleField.SEVERITY.field());
}
@Override
+ @CheckForNull
public RuleStatus status() {
return RuleStatus.valueOf((String) getField(RuleNormalizer.RuleField.STATUS.field()));
}
@@ -104,6 +110,7 @@ public class RuleDoc extends BaseDoc implements Rule {
}
@Override
+ @CheckForNull
public RuleKey templateKey() {
String templateKey = getNullableField(RuleNormalizer.RuleField.TEMPLATE_KEY.field());
return templateKey != null ? RuleKey.parse(templateKey) : null;
@@ -170,16 +177,19 @@ public class RuleDoc extends BaseDoc implements Rule {
}
@Override
+ @CheckForNull
public String debtCharacteristicKey() {
return (String) getNullableField(RuleNormalizer.RuleField.CHARACTERISTIC.field());
}
@Override
+ @CheckForNull
public String debtSubCharacteristicKey() {
return (String) getNullableField(RuleNormalizer.RuleField.SUB_CHARACTERISTIC.field());
}
@Override
+ @CheckForNull
public DebtRemediationFunction debtRemediationFunction() {
final String function = getNullableField(RuleNormalizer.RuleField.DEBT_FUNCTION_TYPE.field());
if (function == null || function.isEmpty()) {
@@ -205,21 +215,25 @@ public class RuleDoc extends BaseDoc implements Rule {
}
@Override
+ @CheckForNull
public String markdownNote() {
return getNullableField(RuleNormalizer.RuleField.NOTE.field());
}
@Override
+ @CheckForNull
public String noteLogin() {
return (String) getNullableField(RuleNormalizer.RuleField.NOTE_LOGIN.field());
}
@Override
+ @CheckForNull
public Date noteCreatedAt() {
return IndexUtils.parseDateTime((String) getNullableField(RuleNormalizer.RuleField.NOTE_CREATED_AT.field()));
}
@Override
+ @CheckForNull
public Date noteUpdatedAt() {
return IndexUtils.parseDateTime((String) getNullableField(RuleNormalizer.RuleField.NOTE_UPDATED_AT.field()));
}
@@ -235,6 +249,11 @@ public class RuleDoc extends BaseDoc implements Rule {
}
@Override
+ public boolean isManual() {
+ return getField(RuleNormalizer.RuleField.REPOSITORY.field()).equals(MANUAL_REPOSITORY);
+ }
+
+ @Override
public String toString() {
return ReflectionToStringBuilder.toString(this);
}
diff --git a/sonar-server/src/main/java/org/sonar/server/rule/ws/CreateAction.java b/sonar-server/src/main/java/org/sonar/server/rule/ws/CreateAction.java
index 0046a95e645..32a49c8aa6a 100644
--- a/sonar-server/src/main/java/org/sonar/server/rule/ws/CreateAction.java
+++ b/sonar-server/src/main/java/org/sonar/server/rule/ws/CreateAction.java
@@ -29,6 +29,7 @@ import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.KeyValueFormat;
import org.sonar.api.utils.text.JsonWriter;
+import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.rule.NewRule;
import org.sonar.server.rule.Rule;
import org.sonar.server.rule.RuleService;
@@ -39,7 +40,8 @@ import org.sonar.server.search.BaseDoc;
*/
public class CreateAction implements RequestHandler {
- public static final String PARAM_KEY = "key";
+ public static final String PARAM_CUSTOM_KEY = "custom_key";
+ public static final String PARAM_MANUAL_KEY = "manual_key";
public static final String PARAM_NAME = "name";
public static final String PARAM_DESCRIPTION = "html_description";
public static final String PARAM_SEVERITY = "severity";
@@ -64,13 +66,18 @@ public class CreateAction implements RequestHandler {
.setHandler(this);
action
- .createParam(PARAM_KEY)
- .setDescription("Key of the rule")
+ .createParam(PARAM_CUSTOM_KEY)
+ .setDescription("Key of the custom rule")
.setExampleValue("Todo_should_not_be_used");
action
+ .createParam(PARAM_MANUAL_KEY)
+ .setDescription("Key of the manual rule")
+ .setExampleValue("Error_handling");
+
+ action
.createParam(PARAM_TEMPLATE_KEY)
- .setDescription("Key of the template rule in order to create a custom rule")
+ .setDescription("Key of the template rule in order to create a custom rule (mandatory for custom rule)")
.setExampleValue("java:XPath");
action
@@ -87,36 +94,47 @@ public class CreateAction implements RequestHandler {
action
.createParam(PARAM_SEVERITY)
- .setDescription("Rule severity")
- .setRequired(true)
+ .setDescription("Rule severity (Only for custom rule)")
.setPossibleValues(Severity.ALL);
action
.createParam(PARAM_STATUS)
- .setDescription("Rule status")
- .setRequired(true)
+ .setDescription("Rule status (Only for custom rule)")
.setDefaultValue(RuleStatus.READY)
.setPossibleValues(RuleStatus.values());
action.createParam(PARAMS)
- .setDescription("Parameters as semi-colon list of <key>=<value>, for example 'params=key1=v1;key2=v2'");
+ .setDescription("Parameters as semi-colon list of <key>=<value>, for example 'params=key1=v1;key2=v2' (Only for custom rule)");
}
@Override
public void handle(Request request, Response response) {
- String templateRuleKey = request.param(PARAM_TEMPLATE_KEY);
- NewRule newRule = new NewRule()
- .setRuleKey(request.mandatoryParam(PARAM_KEY))
- .setTemplateKey(templateRuleKey != null ? RuleKey.parse(templateRuleKey) : null)
- .setName(request.mandatoryParam(PARAM_NAME))
- .setHtmlDescription(request.mandatoryParam(PARAM_DESCRIPTION))
- .setSeverity(request.mandatoryParam(PARAM_SEVERITY))
- .setStatus(RuleStatus.valueOf(request.mandatoryParam(PARAM_STATUS)));
- String params = request.param(PARAMS);
- if (!Strings.isNullOrEmpty(params)) {
- newRule.setParameters(KeyValueFormat.parse(params));
+ String customKey = request.param(PARAM_CUSTOM_KEY);
+ String manualKey = request.param(PARAM_MANUAL_KEY);
+ if (Strings.isNullOrEmpty(customKey) && Strings.isNullOrEmpty(manualKey)) {
+ throw new BadRequestException(String.format("Either '%s' or '%s' parameters should be set", PARAM_CUSTOM_KEY, PARAM_MANUAL_KEY));
+ }
+
+ if (!Strings.isNullOrEmpty(customKey)) {
+ NewRule newRule = NewRule.createForCustomRule(customKey, RuleKey.parse(request.mandatoryParam(PARAM_TEMPLATE_KEY)))
+ .setName(request.mandatoryParam(PARAM_NAME))
+ .setHtmlDescription(request.mandatoryParam(PARAM_DESCRIPTION))
+ .setSeverity(request.mandatoryParam(PARAM_SEVERITY))
+ .setStatus(RuleStatus.valueOf(request.mandatoryParam(PARAM_STATUS)));
+ String params = request.param(PARAMS);
+ if (!Strings.isNullOrEmpty(params)) {
+ newRule.setParameters(KeyValueFormat.parse(params));
+ }
+ writeResponse(response, service.create(newRule));
+ }
+
+ if (!Strings.isNullOrEmpty(manualKey)) {
+ NewRule newRule = NewRule.createForManualRule(manualKey)
+ .setName(request.mandatoryParam(PARAM_NAME))
+ .setHtmlDescription(request.mandatoryParam(PARAM_DESCRIPTION))
+ .setSeverity(request.param(PARAM_SEVERITY));
+ writeResponse(response, service.create(newRule));
}
- writeResponse(response, service.create(newRule));
}
private void writeResponse(Response response, RuleKey ruleKey) {
diff --git a/sonar-server/src/main/java/org/sonar/server/rule/ws/UpdateAction.java b/sonar-server/src/main/java/org/sonar/server/rule/ws/UpdateAction.java
index 656539f186f..0086b9d538b 100644
--- a/sonar-server/src/main/java/org/sonar/server/rule/ws/UpdateAction.java
+++ b/sonar-server/src/main/java/org/sonar/server/rule/ws/UpdateAction.java
@@ -168,8 +168,10 @@ public class UpdateAction implements RequestHandler {
}
if (rule.templateKey() != null) {
return RuleUpdate.createForCustomRule(key);
+ } else if (rule.isManual()) {
+ return RuleUpdate.createForManualRule(key);
} else {
- return RuleUpdate.createForRule(key);
+ return RuleUpdate.createForPluginRule(key);
}
}
diff --git a/sonar-server/src/test/java/org/sonar/server/rule/RegisterRulesMediumTest.java b/sonar-server/src/test/java/org/sonar/server/rule/RegisterRulesMediumTest.java
index ea968ae0764..1c3b2bf51ad 100644
--- a/sonar-server/src/test/java/org/sonar/server/rule/RegisterRulesMediumTest.java
+++ b/sonar-server/src/test/java/org/sonar/server/rule/RegisterRulesMediumTest.java
@@ -190,9 +190,7 @@ public class RegisterRulesMediumTest {
Rule templateRule = index.getByKey(RuleKey.of("xoo", "template1"));
// Create custom rule
- RuleKey customRuleKey = tester.get(RuleCreator.class).create(new NewRule()
- .setRuleKey("CUSTOM_RULE")
- .setTemplateKey(templateRule.key())
+ RuleKey customRuleKey = tester.get(RuleCreator.class).create(NewRule.createForCustomRule("CUSTOM_RULE", templateRule.key())
.setName("My custom")
.setHtmlDescription("Some description")
.setSeverity(Severity.MAJOR)
@@ -230,9 +228,7 @@ public class RegisterRulesMediumTest {
Rule templateRule = index.getByKey(RuleKey.of("xoo", "template1"));
// Create custom rule
- RuleKey customRuleKey = tester.get(RuleCreator.class).create(new NewRule()
- .setRuleKey("CUSTOM_RULE")
- .setTemplateKey(templateRule.key())
+ RuleKey customRuleKey = tester.get(RuleCreator.class).create(NewRule.createForCustomRule("CUSTOM_RULE", templateRule.key())
.setName("My custom")
.setHtmlDescription("Some description")
.setSeverity(Severity.MAJOR)
@@ -258,9 +254,7 @@ public class RegisterRulesMediumTest {
Rule templateRule = index.getByKey(RuleKey.of("xoo", "template1"));
// Create custom rule
- RuleKey customRuleKey = tester.get(RuleCreator.class).create(new NewRule()
- .setRuleKey("CUSTOM_RULE")
- .setTemplateKey(templateRule.key())
+ RuleKey customRuleKey = tester.get(RuleCreator.class).create(NewRule.createForCustomRule("CUSTOM_RULE", templateRule.key())
.setName("My custom")
.setHtmlDescription("Some description")
.setSeverity(Severity.MAJOR)
diff --git a/sonar-server/src/test/java/org/sonar/server/rule/RuleCreatorMediumTest.java b/sonar-server/src/test/java/org/sonar/server/rule/RuleCreatorMediumTest.java
index fd6cb7435a5..9dfd4e6fbeb 100644
--- a/sonar-server/src/test/java/org/sonar/server/rule/RuleCreatorMediumTest.java
+++ b/sonar-server/src/test/java/org/sonar/server/rule/RuleCreatorMediumTest.java
@@ -35,6 +35,7 @@ import org.sonar.core.rule.RuleDto;
import org.sonar.core.rule.RuleParamDto;
import org.sonar.server.db.DbClient;
import org.sonar.server.rule.db.RuleDao;
+import org.sonar.server.rule.index.RuleIndex;
import org.sonar.server.tester.ServerTester;
import java.util.List;
@@ -51,6 +52,7 @@ public class RuleCreatorMediumTest {
DbClient db = tester.get(DbClient.class);
RuleDao dao = tester.get(RuleDao.class);
RuleCreator creator = tester.get(RuleCreator.class);
+ RuleIndex ruleIndex = tester.get(RuleIndex.class);
@Before
public void before() {
@@ -69,9 +71,7 @@ public class RuleCreatorMediumTest {
RuleDto templateRule = createTemplateRule();
// Create custom rule
- NewRule newRule = new NewRule()
- .setRuleKey("CUSTOM_RULE")
- .setTemplateKey(templateRule.getKey())
+ NewRule newRule = NewRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey())
.setName("My custom")
.setHtmlDescription("Some description")
.setSeverity(Severity.MAJOR)
@@ -116,9 +116,7 @@ public class RuleCreatorMediumTest {
// insert template rule
RuleDto templateRule = createTemplateRule();
- NewRule newRule = new NewRule()
- .setRuleKey("CUSTOM_RULE")
- .setTemplateKey(templateRule.getKey())
+ NewRule newRule = NewRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey())
.setName("My custom")
.setHtmlDescription("Some description")
.setSeverity(Severity.MAJOR)
@@ -136,19 +134,16 @@ public class RuleCreatorMediumTest {
// insert template rule
RuleDto templateRule = createTemplateRule();
- NewRule newRule = new NewRule()
- .setName("My custom")
- .setTemplateKey(templateRule.getKey())
- .setHtmlDescription("Some description")
- .setSeverity(Severity.MAJOR)
- .setStatus(RuleStatus.READY)
- .setParameters(ImmutableMap.of("regex", "a.*"));
-
try {
- creator.create(newRule);
+ NewRule newRule = NewRule.createForCustomRule("", templateRule.getKey())
+ .setName("My custom")
+ .setHtmlDescription("Some description")
+ .setSeverity(Severity.MAJOR)
+ .setStatus(RuleStatus.READY)
+ .setParameters(ImmutableMap.of("regex", "a.*"));
fail();
} catch (Exception e) {
- assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("The rule key is missing");
+ assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Custom key should be set");
}
}
@@ -157,10 +152,8 @@ public class RuleCreatorMediumTest {
// insert template rule
RuleDto templateRule = createTemplateRule();
- NewRule newRule = new NewRule()
- .setRuleKey("*INVALID*")
+ NewRule newRule = NewRule.createForCustomRule("*INVALID*", templateRule.getKey())
.setName("My custom")
- .setTemplateKey(templateRule.getKey())
.setHtmlDescription("Some description")
.setSeverity(Severity.MAJOR)
.setStatus(RuleStatus.READY)
@@ -180,10 +173,8 @@ public class RuleCreatorMediumTest {
RuleDto templateRule = createTemplateRule();
// Create a custom rule
- NewRule newRule = new NewRule()
- .setRuleKey("CUSTOM_RULE")
+ NewRule newRule = NewRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey())
.setName("My custom")
- .setTemplateKey(templateRule.getKey())
.setHtmlDescription("Some description")
.setSeverity(Severity.MAJOR)
.setStatus(RuleStatus.READY)
@@ -192,10 +183,8 @@ public class RuleCreatorMediumTest {
try {
// Create another custom rule having same key
- newRule = new NewRule()
- .setRuleKey("CUSTOM_RULE")
+ newRule = NewRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey())
.setName("My another custom")
- .setTemplateKey(templateRule.getKey())
.setHtmlDescription("Some description")
.setSeverity(Severity.MAJOR)
.setStatus(RuleStatus.READY)
@@ -212,9 +201,7 @@ public class RuleCreatorMediumTest {
// insert template rule
RuleDto templateRule = createTemplateRule();
- NewRule newRule = new NewRule()
- .setRuleKey("CUSTOM_RULE")
- .setTemplateKey(templateRule.getKey())
+ NewRule newRule = NewRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey())
.setHtmlDescription("Some description")
.setSeverity(Severity.MAJOR)
.setStatus(RuleStatus.READY)
@@ -233,9 +220,7 @@ public class RuleCreatorMediumTest {
// insert template rule
RuleDto templateRule = createTemplateRule();
- NewRule newRule = new NewRule()
- .setRuleKey("CUSTOM_RULE")
- .setTemplateKey(templateRule.getKey())
+ NewRule newRule = NewRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey())
.setName("My custom")
.setSeverity(Severity.MAJOR)
.setStatus(RuleStatus.READY)
@@ -254,9 +239,7 @@ public class RuleCreatorMediumTest {
// insert template rule
RuleDto templateRule = createTemplateRule();
- NewRule newRule = new NewRule()
- .setRuleKey("CUSTOM_RULE")
- .setTemplateKey(templateRule.getKey())
+ NewRule newRule = NewRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey())
.setName("My custom")
.setHtmlDescription("Some description")
.setStatus(RuleStatus.READY)
@@ -275,9 +258,7 @@ public class RuleCreatorMediumTest {
// insert template rule
RuleDto templateRule = createTemplateRule();
- NewRule newRule = new NewRule()
- .setRuleKey("CUSTOM_RULE")
- .setTemplateKey(templateRule.getKey())
+ NewRule newRule = NewRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey())
.setName("My custom")
.setHtmlDescription("Some description")
.setSeverity("INVALID")
@@ -297,9 +278,7 @@ public class RuleCreatorMediumTest {
// insert template rule
RuleDto templateRule = createTemplateRule();
- NewRule newRule = new NewRule()
- .setRuleKey("CUSTOM_RULE")
- .setTemplateKey(templateRule.getKey())
+ NewRule newRule = NewRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey())
.setName("My custom")
.setHtmlDescription("Some description")
.setSeverity(Severity.MAJOR)
@@ -321,9 +300,7 @@ public class RuleCreatorMediumTest {
dbSession.commit();
// Create custom rule with unknown template rule
- NewRule newRule = new NewRule()
- .setRuleKey("CUSTOM_RULE")
- .setTemplateKey(rule.getKey())
+ NewRule newRule = NewRule.createForCustomRule("CUSTOM_RULE", rule.getKey())
.setName("My custom")
.setHtmlDescription("Some description")
.setSeverity(Severity.MAJOR)
@@ -338,6 +315,154 @@ public class RuleCreatorMediumTest {
}
}
+ @Test
+ public void create_manual_rule() throws Exception {
+ NewRule newRule = NewRule.createForManualRule("MANUAL_RULE")
+ .setName("My manual")
+ .setHtmlDescription("Some description");
+ RuleKey ruleKey = creator.create(newRule);
+
+ dbSession.clearCache();
+
+ Rule rule = ruleIndex.getByKey(ruleKey);
+ assertThat(rule).isNotNull();
+ assertThat(rule.key()).isEqualTo(RuleKey.of("manual", "MANUAL_RULE"));
+ assertThat(rule.name()).isEqualTo("My manual");
+ assertThat(rule.htmlDescription()).isEqualTo("Some description");
+ assertThat(rule.severity()).isNull();
+ assertThat(rule.status()).isEqualTo(RuleStatus.READY);
+ assertThat(rule.language()).isNull();
+ assertThat(rule.internalKey()).isNull();
+ assertThat(rule.debtSubCharacteristicKey()).isNull();
+ assertThat(rule.debtRemediationFunction()).isNull();
+ assertThat(rule.tags()).isEmpty();
+ assertThat(rule.systemTags()).isEmpty();
+ assertThat(rule.params()).isEmpty();
+ }
+
+ @Test
+ public void create_manual_rule_with_severity() throws Exception {
+ NewRule newRule = NewRule.createForManualRule("MANUAL_RULE")
+ .setName("My manual")
+ .setHtmlDescription("Some description")
+ .setSeverity(Severity.BLOCKER);
+ RuleKey ruleKey = creator.create(newRule);
+
+ dbSession.clearCache();
+
+ Rule rule = ruleIndex.getByKey(ruleKey);
+ assertThat(rule).isNotNull();
+ assertThat(rule.key()).isEqualTo(RuleKey.of("manual", "MANUAL_RULE"));
+ assertThat(rule.name()).isEqualTo("My manual");
+ assertThat(rule.htmlDescription()).isEqualTo("Some description");
+ assertThat(rule.severity()).isEqualTo(Severity.BLOCKER);
+ assertThat(rule.status()).isEqualTo(RuleStatus.READY);
+ assertThat(rule.language()).isNull();
+ assertThat(rule.internalKey()).isNull();
+ assertThat(rule.debtSubCharacteristicKey()).isNull();
+ assertThat(rule.debtRemediationFunction()).isNull();
+ assertThat(rule.tags()).isEmpty();
+ assertThat(rule.systemTags()).isEmpty();
+ assertThat(rule.params()).isEmpty();
+ }
+
+ @Test
+ public void fail_to_create_manual_rule_when_missing_key() throws Exception {
+ try {
+ NewRule.createForManualRule("")
+ .setName("My manual")
+ .setHtmlDescription("Some description");
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Manual key should be set");
+ }
+ }
+
+ @Test
+ public void fail_to_create_manual_rule_when_invalid_key() throws Exception {
+ NewRule newRule = NewRule.createForManualRule("*INVALID*")
+ .setName("My custom")
+ .setHtmlDescription("Some description");
+
+ try {
+ creator.create(newRule);
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("The rule key '*INVALID*' is invalid, it should only contains : a-z, 0-9, '_'");
+ }
+ }
+
+ @Test
+ public void fail_to_create_manual_rule_when_rule_key_already_exits() throws Exception {
+ NewRule newRule = NewRule.createForManualRule("MANUAL_RULE")
+ .setName("My manual")
+ .setHtmlDescription("Some description");
+ creator.create(newRule);
+
+ try {
+ // Create another rule having same key
+ newRule = NewRule.createForManualRule("MANUAL_RULE")
+ .setName("My other manual")
+ .setHtmlDescription("Some description");
+ creator.create(newRule);
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("A rule with the key 'MANUAL_RULE' already exits");
+ }
+ }
+
+ @Test
+ public void fail_to_create_manual_rule_when_missing_name() throws Exception {
+ NewRule newRule = NewRule.createForManualRule("MANUAL_RULE")
+ .setHtmlDescription("Some description");
+
+ try {
+ creator.create(newRule);
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("The name is missing");
+ }
+ }
+
+ @Test
+ public void fail_to_create_manual_rule_when_missing_description() throws Exception {
+ NewRule newRule = NewRule.createForManualRule("MANUAL_RULE")
+ .setName("My manual");
+
+ try {
+ creator.create(newRule);
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("The description is missing");
+ }
+ }
+
+ @Test
+ public void fail_to_create_manual_rule_with_status() throws Exception {
+ try {
+ NewRule.createForManualRule("MANUAL_RULE")
+ .setName("My manual")
+ .setHtmlDescription("Some description")
+ .setStatus(RuleStatus.BETA);
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(IllegalStateException.class).hasMessage("Not a custom rule");
+ }
+ }
+
+ @Test
+ public void fail_to_create_manual_rule_with_parameters() throws Exception {
+ try {
+ NewRule.createForManualRule("MANUAL_RULE")
+ .setName("My manual")
+ .setHtmlDescription("Some description")
+ .setParameters(ImmutableMap.of("regex", "a.*"));
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(IllegalStateException.class).hasMessage("Not a custom rule");
+ }
+ }
+
private RuleDto createTemplateRule() {
RuleDto templateRule = dao.insert(dbSession,
RuleTesting.newDto(RuleKey.of("java", "S001"))
diff --git a/sonar-server/src/test/java/org/sonar/server/rule/RuleServiceMediumTest.java b/sonar-server/src/test/java/org/sonar/server/rule/RuleServiceMediumTest.java
index c0c317887b9..709a297e4cb 100644
--- a/sonar-server/src/test/java/org/sonar/server/rule/RuleServiceMediumTest.java
+++ b/sonar-server/src/test/java/org/sonar/server/rule/RuleServiceMediumTest.java
@@ -99,7 +99,7 @@ public class RuleServiceMediumTest {
dao.insert(dbSession, RuleTesting.newDto(key));
dbSession.commit();
- RuleUpdate update = new RuleUpdate(key);
+ RuleUpdate update = RuleUpdate.createForCustomRule(key);
update.setMarkdownNote("my *note*");
service.update(update);
@@ -121,12 +121,12 @@ public class RuleServiceMediumTest {
.setSystemTags(Sets.newHashSet("java8", "javadoc")));
dbSession.commit();
- RuleUpdate update = new RuleUpdate(key).setMarkdownNote("my *note*");
+ RuleUpdate update = RuleUpdate.createForPluginRule(key).setMarkdownNote("my *note*");
service.update(update);
}
@Test
- public void create_custom_rule() throws Exception {
+ public void create_rule() throws Exception {
MockUserSession.set()
.setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN)
.setLogin("me");
@@ -137,9 +137,7 @@ public class RuleServiceMediumTest {
dbSession.commit();
// Create custom rule
- NewRule newRule = new NewRule()
- .setRuleKey("MY_CUSTOM")
- .setTemplateKey(templateRuleKey)
+ NewRule newRule = NewRule.createForCustomRule("MY_CUSTOM", templateRuleKey)
.setName("My custom")
.setHtmlDescription("Some description")
.setSeverity(Severity.MAJOR)
@@ -157,11 +155,11 @@ public class RuleServiceMediumTest {
public void do_not_create_if_not_granted() throws Exception {
MockUserSession.set().setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
- service.create(new NewRule());
+ service.create(NewRule.createForCustomRule("MY_CUSTOM", RuleKey.of("java", "S001")));
}
@Test
- public void delete_custom_rule() throws Exception {
+ public void delete_rule() throws Exception {
MockUserSession.set()
.setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN)
.setLogin("me");
@@ -172,9 +170,7 @@ public class RuleServiceMediumTest {
dbSession.commit();
// Create custom rule
- NewRule newRule = new NewRule()
- .setRuleKey("MY_CUSTOM")
- .setTemplateKey(templateRuleKey)
+ NewRule newRule = NewRule.createForCustomRule("MY_CUSTOM", templateRuleKey)
.setName("My custom")
.setHtmlDescription("Some description")
.setSeverity(Severity.MAJOR)
diff --git a/sonar-server/src/test/java/org/sonar/server/rule/RuleTesting.java b/sonar-server/src/test/java/org/sonar/server/rule/RuleTesting.java
index c11aff6a7b7..71fbd736ea4 100644
--- a/sonar-server/src/test/java/org/sonar/server/rule/RuleTesting.java
+++ b/sonar-server/src/test/java/org/sonar/server/rule/RuleTesting.java
@@ -74,4 +74,11 @@ public class RuleTesting {
.setTemplateId(templateRule.getId());
}
+ public static RuleDto newManualRule(String manualKey){
+ return new RuleDto().setRuleKey(manualKey)
+ .setRepositoryKey("manual")
+ .setDescription("Description " + manualKey)
+ .setStatus(RuleStatus.READY);
+ }
+
}
diff --git a/sonar-server/src/test/java/org/sonar/server/rule/RuleUpdaterMediumTest.java b/sonar-server/src/test/java/org/sonar/server/rule/RuleUpdaterMediumTest.java
index 08748a5b3b8..82124c640c2 100644
--- a/sonar-server/src/test/java/org/sonar/server/rule/RuleUpdaterMediumTest.java
+++ b/sonar-server/src/test/java/org/sonar/server/rule/RuleUpdaterMediumTest.java
@@ -85,7 +85,7 @@ public class RuleUpdaterMediumTest {
ruleDao.insert(dbSession, RuleTesting.newDto(RULE_KEY).setStatus(RuleStatus.REMOVED));
dbSession.commit();
- RuleUpdate update = new RuleUpdate(RULE_KEY).setTags(Sets.newHashSet("java9"));
+ RuleUpdate update = RuleUpdate.createForPluginRule(RULE_KEY).setTags(Sets.newHashSet("java9"));
try {
updater.update(update, UserSession.get());
fail();
@@ -107,7 +107,7 @@ public class RuleUpdaterMediumTest {
.setRemediationOffset("5min"));
dbSession.commit();
- RuleUpdate update = new RuleUpdate(RULE_KEY);
+ RuleUpdate update = RuleUpdate.createForPluginRule(RULE_KEY);
assertThat(update.isEmpty()).isTrue();
updater.update(update, UserSession.get());
@@ -138,7 +138,7 @@ public class RuleUpdaterMediumTest {
.setRemediationOffset("5min"));
dbSession.commit();
- RuleUpdate update = new RuleUpdate(RULE_KEY);
+ RuleUpdate update = RuleUpdate.createForPluginRule(RULE_KEY);
update.setMarkdownNote("my *note*");
updater.update(update, UserSession.get());
@@ -163,7 +163,7 @@ public class RuleUpdaterMediumTest {
.setNoteUserLogin("me"));
dbSession.commit();
- RuleUpdate update = new RuleUpdate(RULE_KEY).setMarkdownNote(null);
+ RuleUpdate update = RuleUpdate.createForPluginRule(RULE_KEY).setMarkdownNote(null);
updater.update(update, UserSession.get());
dbSession.clearCache();
@@ -183,7 +183,7 @@ public class RuleUpdaterMediumTest {
dbSession.commit();
// java8 is a system tag -> ignore
- RuleUpdate update = new RuleUpdate(RULE_KEY).setTags(Sets.newHashSet("bug", "java8"));
+ RuleUpdate update = RuleUpdate.createForPluginRule(RULE_KEY).setTags(Sets.newHashSet("bug", "java8"));
updater.update(update, UserSession.get());
dbSession.clearCache();
@@ -203,7 +203,7 @@ public class RuleUpdaterMediumTest {
.setSystemTags(Sets.newHashSet("java8", "javadoc")));
dbSession.commit();
- RuleUpdate update = new RuleUpdate(RULE_KEY).setTags(null);
+ RuleUpdate update = RuleUpdate.createForPluginRule(RULE_KEY).setTags(null);
updater.update(update, UserSession.get());
dbSession.clearCache();
@@ -230,7 +230,7 @@ public class RuleUpdaterMediumTest {
dbSession.commit();
DefaultDebtRemediationFunction fn = new DefaultDebtRemediationFunction(DebtRemediationFunction.Type.CONSTANT_ISSUE, null, "1min");
- RuleUpdate update = new RuleUpdate(RULE_KEY)
+ RuleUpdate update = RuleUpdate.createForPluginRule(RULE_KEY)
.setDebtSubCharacteristic("SOFT_RELIABILITY")
.setDebtRemediationFunction(fn);
updater.update(update, UserSession.get());
@@ -266,7 +266,7 @@ public class RuleUpdaterMediumTest {
.setRemediationOffset("1min"));
dbSession.commit();
- RuleUpdate update = new RuleUpdate(RULE_KEY)
+ RuleUpdate update = RuleUpdate.createForPluginRule(RULE_KEY)
.setDebtSubCharacteristic(RuleUpdate.DEFAULT_DEBT_CHARACTERISTIC);
updater.update(update, UserSession.get());
@@ -301,7 +301,7 @@ public class RuleUpdaterMediumTest {
.setRemediationOffset("1min"));
dbSession.commit();
- RuleUpdate update = new RuleUpdate(RULE_KEY)
+ RuleUpdate update = RuleUpdate.createForPluginRule(RULE_KEY)
.setDebtSubCharacteristic(null);
updater.update(update, UserSession.get());
@@ -425,6 +425,125 @@ public class RuleUpdaterMediumTest {
assertThat(activeRule.severity()).isEqualTo(Severity.BLOCKER);
}
+ @Test
+ public void update_manual_rule() throws Exception {
+ // Create manual rule
+ RuleDto manualRule = RuleTesting.newManualRule("My manual")
+ .setName("Old name")
+ .setDescription("Old description")
+ .setSeverity(Severity.INFO);
+ ruleDao.insert(dbSession, manualRule);
+
+ dbSession.commit();
+
+ // Update manual rule
+ RuleUpdate update = RuleUpdate.createForManualRule(manualRule.getKey())
+ .setName("New name")
+ .setHtmlDescription("New description")
+ .setSeverity(Severity.CRITICAL);
+ updater.update(update, UserSession.get());
+
+ dbSession.clearCache();
+
+ // Verify manual rule is updated
+ Rule manualRuleReloaded = ruleIndex.getByKey(manualRule.getKey());
+ assertThat(manualRuleReloaded).isNotNull();
+ assertThat(manualRuleReloaded.name()).isEqualTo("New name");
+ assertThat(manualRuleReloaded.htmlDescription()).isEqualTo("New description");
+ assertThat(manualRuleReloaded.severity()).isEqualTo(Severity.CRITICAL);
+ }
+
+ @Test
+ public void fail_to_update_manual_rule_if_status_is_set() throws Exception {
+ // Create manual rule
+ RuleDto manualRule = RuleTesting.newManualRule("My manual");
+ ruleDao.insert(dbSession, manualRule);
+
+ dbSession.commit();
+
+ try {
+ // Update manual rule
+ RuleUpdate.createForManualRule(manualRule.getKey())
+ .setStatus(RuleStatus.BETA);
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(IllegalStateException.class).hasMessage("Not a custom rule");
+ }
+ }
+
+ @Test
+ public void fail_to_update_manual_rule_if_parameters_are_set() throws Exception {
+ // Create manual rule
+ RuleDto manualRule = RuleTesting.newManualRule("My manual");
+ ruleDao.insert(dbSession, manualRule);
+
+ dbSession.commit();
+
+ try {
+ // Update manual rule
+ RuleUpdate.createForManualRule(manualRule.getKey())
+ .setStatus(RuleStatus.BETA)
+ .setParameters(ImmutableMap.of("regex", "b.*", "message", "a message"));
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(IllegalStateException.class).hasMessage("Not a custom rule");
+ }
+ }
+
+ @Test
+ public void fail_to_update_plugin_rule_if_name_is_set() throws Exception {
+ // Create rule rule
+ RuleDto ruleDto = RuleTesting.newDto(RuleKey.of("squid", "S01"));
+ ruleDao.insert(dbSession, ruleDto);
+
+ dbSession.commit();
+
+ try {
+ // Update rule
+ RuleUpdate.createForPluginRule(ruleDto.getKey())
+ .setName("New name");
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(IllegalStateException.class).hasMessage("Not a custom or a manual rule");
+ }
+ }
+
+ @Test
+ public void fail_to_update_plugin_rule_if_description_is_set() throws Exception {
+ // Create rule rule
+ RuleDto ruleDto = RuleTesting.newDto(RuleKey.of("squid", "S01"));
+ ruleDao.insert(dbSession, ruleDto);
+
+ dbSession.commit();
+
+ try {
+ // Update rule
+ RuleUpdate.createForPluginRule(ruleDto.getKey())
+ .setHtmlDescription("New description");
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(IllegalStateException.class).hasMessage("Not a custom or a manual rule");
+ }
+ }
+
+ @Test
+ public void fail_to_update_plugin_rule_if_severity_is_set() throws Exception {
+ // Create rule rule
+ RuleDto ruleDto = RuleTesting.newDto(RuleKey.of("squid", "S01"));
+ ruleDao.insert(dbSession, ruleDto);
+
+ dbSession.commit();
+
+ try {
+ // Update rule
+ RuleUpdate.createForPluginRule(ruleDto.getKey())
+ .setSeverity(Severity.CRITICAL);
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(IllegalStateException.class).hasMessage("Not a custom or a manual rule");
+ }
+ }
+
private void insertDebtCharacteristics(DbSession dbSession) {
CharacteristicDto reliability = DebtTesting.newCharacteristicDto("RELIABILITY");
db.debtCharacteristicDao().insert(reliability, dbSession);
diff --git a/sonar-server/src/test/java/org/sonar/server/rule/ws/CreateActionMediumTest.java b/sonar-server/src/test/java/org/sonar/server/rule/ws/CreateActionMediumTest.java
index fb074ecdcc1..1c84857326b 100644
--- a/sonar-server/src/test/java/org/sonar/server/rule/ws/CreateActionMediumTest.java
+++ b/sonar-server/src/test/java/org/sonar/server/rule/ws/CreateActionMediumTest.java
@@ -32,6 +32,7 @@ import org.sonar.core.persistence.DbSession;
import org.sonar.core.rule.RuleDto;
import org.sonar.core.rule.RuleParamDto;
import org.sonar.server.db.DbClient;
+import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.rule.RuleService;
import org.sonar.server.rule.RuleTesting;
import org.sonar.server.rule.db.RuleDao;
@@ -39,6 +40,9 @@ import org.sonar.server.tester.ServerTester;
import org.sonar.server.user.MockUserSession;
import org.sonar.server.ws.WsTester;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
+
@RunWith(MockitoJUnitRunner.class)
public class CreateActionMediumTest {
@@ -78,7 +82,7 @@ public class CreateActionMediumTest {
session.commit();
WsTester.TestRequest request = wsTester.newGetRequest("api/rules", "create")
- .setParam("key", "MY_CUSTOM")
+ .setParam("custom_key", "MY_CUSTOM")
.setParam("template_key", templateRule.getKey().toString())
.setParam("name", "My custom rule")
.setParam("html_description", "Description")
@@ -88,4 +92,51 @@ public class CreateActionMediumTest {
request.execute().assertJson(getClass(), "create_custom_rule.json", false);
}
+ @Test
+ public void create_manual_rule() throws Exception {
+ MockUserSession.set()
+ .setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN)
+ .setLogin("me");
+
+ WsTester.TestRequest request = wsTester.newGetRequest("api/rules", "create")
+ .setParam("manual_key", "MY_MANUAL")
+ .setParam("name", "My manual rule")
+ .setParam("html_description", "Description")
+ .setParam("severity", "MAJOR");
+ request.execute().assertJson(getClass(), "create_manual_rule.json", false);
+ }
+
+ @Test
+ public void create_manual_rule_without_severity() throws Exception {
+ MockUserSession.set()
+ .setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN)
+ .setLogin("me");
+
+ WsTester.TestRequest request = wsTester.newGetRequest("api/rules", "create")
+ .setParam("manual_key", "MY_MANUAL")
+ .setParam("name", "My manual rule")
+ .setParam("html_description", "Description");
+ request.execute().assertJson(getClass(), "create_manual_rule_without_severity.json", false);
+ }
+
+ @Test
+ public void fail_if_custom_key_and_manual_key_parameters_are_not_set() throws Exception {
+ MockUserSession.set()
+ .setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN)
+ .setLogin("me");
+
+ WsTester.TestRequest request = wsTester.newGetRequest("api/rules", "create")
+ .setParam("key", "MY_MANUAL")
+ .setParam("name", "My manual rule")
+ .setParam("html_description", "Description")
+ .setParam("severity", "MAJOR");
+
+ try {
+ request.execute();
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(BadRequestException.class).hasMessage("Either 'custom_key' or 'manual_key' parameters should be set");
+ }
+ }
+
}
diff --git a/sonar-server/src/test/java/org/sonar/server/rule/ws/UpdateActionMediumTest.java b/sonar-server/src/test/java/org/sonar/server/rule/ws/UpdateActionMediumTest.java
index 1ca8956e27f..8d241c2b315 100644
--- a/sonar-server/src/test/java/org/sonar/server/rule/ws/UpdateActionMediumTest.java
+++ b/sonar-server/src/test/java/org/sonar/server/rule/ws/UpdateActionMediumTest.java
@@ -82,9 +82,7 @@ public class UpdateActionMediumTest {
session.commit();
// Custom rule
- NewRule newRule = new NewRule()
- .setRuleKey("MY_CUSTOM")
- .setTemplateKey(templateRule.getKey())
+ NewRule newRule = NewRule.createForCustomRule("MY_CUSTOM", templateRule.getKey())
.setName("Old custom")
.setHtmlDescription("Old description")
.setSeverity(Severity.MINOR)
diff --git a/sonar-server/src/test/resources/org/sonar/server/rule/ws/CreateActionMediumTest/create_manual_rule.json b/sonar-server/src/test/resources/org/sonar/server/rule/ws/CreateActionMediumTest/create_manual_rule.json
new file mode 100644
index 00000000000..a78fb0fadf3
--- /dev/null
+++ b/sonar-server/src/test/resources/org/sonar/server/rule/ws/CreateActionMediumTest/create_manual_rule.json
@@ -0,0 +1,14 @@
+{
+ "rule": {
+ "key": "manual:MY_MANUAL",
+ "repo": "manual",
+ "name": "My manual rule",
+ "htmlDesc": "Description",
+ "severity": "MAJOR",
+ "status": "READY",
+ "isTemplate": false,
+ "tags": [],
+ "sysTags": [],
+ "params": []
+ }
+}
diff --git a/sonar-server/src/test/resources/org/sonar/server/rule/ws/CreateActionMediumTest/create_manual_rule_without_severity.json b/sonar-server/src/test/resources/org/sonar/server/rule/ws/CreateActionMediumTest/create_manual_rule_without_severity.json
new file mode 100644
index 00000000000..0f0e195298e
--- /dev/null
+++ b/sonar-server/src/test/resources/org/sonar/server/rule/ws/CreateActionMediumTest/create_manual_rule_without_severity.json
@@ -0,0 +1,13 @@
+{
+ "rule": {
+ "key": "manual:MY_MANUAL",
+ "repo": "manual",
+ "name": "My manual rule",
+ "htmlDesc": "Description",
+ "status": "READY",
+ "isTemplate": false,
+ "tags": [],
+ "sysTags": [],
+ "params": []
+ }
+}