]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-4514 New web service to manage manual rules
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Mon, 16 Jun 2014 12:08:01 +0000 (14:08 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Mon, 16 Jun 2014 12:15:15 +0000 (14:15 +0200)
17 files changed:
sonar-server/src/main/java/org/sonar/server/rule/NewRule.java
sonar-server/src/main/java/org/sonar/server/rule/RubyRuleService.java
sonar-server/src/main/java/org/sonar/server/rule/Rule.java
sonar-server/src/main/java/org/sonar/server/rule/RuleCreator.java
sonar-server/src/main/java/org/sonar/server/rule/RuleUpdate.java
sonar-server/src/main/java/org/sonar/server/rule/index/RuleDoc.java
sonar-server/src/main/java/org/sonar/server/rule/ws/CreateAction.java
sonar-server/src/main/java/org/sonar/server/rule/ws/UpdateAction.java
sonar-server/src/test/java/org/sonar/server/rule/RegisterRulesMediumTest.java
sonar-server/src/test/java/org/sonar/server/rule/RuleCreatorMediumTest.java
sonar-server/src/test/java/org/sonar/server/rule/RuleServiceMediumTest.java
sonar-server/src/test/java/org/sonar/server/rule/RuleTesting.java
sonar-server/src/test/java/org/sonar/server/rule/RuleUpdaterMediumTest.java
sonar-server/src/test/java/org/sonar/server/rule/ws/CreateActionMediumTest.java
sonar-server/src/test/java/org/sonar/server/rule/ws/UpdateActionMediumTest.java
sonar-server/src/test/resources/org/sonar/server/rule/ws/CreateActionMediumTest/create_manual_rule.json [new file with mode: 0644]
sonar-server/src/test/resources/org/sonar/server/rule/ws/CreateActionMediumTest/create_manual_rule_without_severity.json [new file with mode: 0644]

index 4ae05bf863277ae294ae4f42f1d06b12061506d2..3b2b2539a0aaaa78c11c5f72e1ac8a5d4597687d 100644 (file)
@@ -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;
+  }
+
 }
index 66a27e4ab80e7f740baca2b88a8c26180b7f7473..ef362e4372d04a4871954c24c713e6dbc96078af 100644 (file)
@@ -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) {
index 5237f23c7b1970582eb903639a7c803878b62e55..74b785903adafab34cf22f3f0012411672df996e 100644 (file)
@@ -100,4 +100,6 @@ public interface Rule {
 
   @CheckForNull
   Date noteUpdatedAt();
+
+  boolean isManual();
 }
index 6e43422287e590bd264ce996106ee6c8b7e8356e..48ad462dce329096e9f1371d44fcec7991ce80b7 100644 (file)
@@ -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;
+  }
+
 }
index 584053fa04f7cce943e2c0ae1298738cb6a6a51c..3b2f080afdd2f3e0248bd5b76435c98d8066ebbd 100644 (file)
@@ -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;
   }
 
index 960baebd6a5a211a1176fa0618cd3b62af2212bc..3d3d7b301863cfcdae8f4383c28f371985ca06c8 100644 (file)
@@ -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()));
   }
@@ -234,6 +248,11 @@ public class RuleDoc extends BaseDoc implements Rule {
     return IndexUtils.parseDateTime((String) getNullableField(RuleNormalizer.RuleField.UPDATED_AT.field()));
   }
 
+  @Override
+  public boolean isManual() {
+    return getField(RuleNormalizer.RuleField.REPOSITORY.field()).equals(MANUAL_REPOSITORY);
+  }
+
   @Override
   public String toString() {
     return ReflectionToStringBuilder.toString(this);
index 0046a95e64502616ec9d101bd215a9ec15b3dc87..32a49c8aa6ae296a3ef3a3f959d426ad39face3d 100644 (file)
@@ -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) {
index 656539f186fd88ef8fb600aae903175c18997718..0086b9d538b18f7c5df02036ced1fd29697ebf49 100644 (file)
@@ -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);
     }
   }
 
index ea968ae0764ac61e05a1741700f5aead2ec44eec..1c3b2bf51ad41ffb10d0b2fb6b2bf818c3ffc208 100644 (file)
@@ -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)
index fd6cb7435a577524f5441f7d824b48c420406258..9dfd4e6fbebd70a041dc5b547a789f4baa3ac33c 100644 (file)
@@ -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"))
index c0c317887b901a68a4616cb8ae1a73aea435fada..709a297e4cbc3073ad42131205c30873edb06fd6 100644 (file)
@@ -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)
index c11aff6a7b7151fa0b3965bbd7ce35968b22f0bf..71fbd736ea4b7b197f7ca69548ed6def5b9b143a 100644 (file)
@@ -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);
+  }
+
 }
index 08748a5b3b876a0bec5ec26ca5fc4ad79ff84c64..82124c640c2b861aae0d43dfd28573c4291b6bd3 100644 (file)
@@ -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);
index fb074ecdcc102a8001f736117a37240ee24dccb4..1c84857326bc4b453f31124318c407162fa14b64 100644 (file)
@@ -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");
+    }
+  }
+
 }
index 1ca8956e27fdec8878b1fef332f7c6f5e04f3d8f..8d241c2b315e7cd770e1f7946869463d4f103c80 100644 (file)
@@ -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 (file)
index 0000000..a78fb0f
--- /dev/null
@@ -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 (file)
index 0000000..0f0e195
--- /dev/null
@@ -0,0 +1,13 @@
+{
+  "rule": {
+    "key": "manual:MY_MANUAL",
+    "repo": "manual",
+    "name": "My manual rule",
+    "htmlDesc": "Description",
+    "status": "READY",
+    "isTemplate": false,
+    "tags": [],
+    "sysTags": [],
+    "params": []
+  }
+}