]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5575 Fix missing parameter when creating and updating custom rule with empty...
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Thu, 9 Oct 2014 12:37:47 +0000 (14:37 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Thu, 9 Oct 2014 12:39:18 +0000 (14:39 +0200)
23 files changed:
server/sonar-server/src/main/java/org/sonar/server/db/migrations/DatabaseMigrations.java
server/sonar-server/src/main/java/org/sonar/server/db/migrations/v45/AddMissingCustomRuleParametersMigration.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/rule/RuleCreator.java
server/sonar-server/src/main/java/org/sonar/server/rule/RuleUpdater.java
server/sonar-server/src/test/java/org/sonar/server/db/migrations/v45/AddMissingCustomRuleParametersMigrationTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/rule/RuleCreatorMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/rule/RuleUpdaterMediumTest.java
server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v45/AddMissingCustomRuleParametersMigrationTest/execute-result.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v45/AddMissingCustomRuleParametersMigrationTest/execute.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v45/AddMissingCustomRuleParametersMigrationTest/execute_when_custom_rule_have_no_parameter-result.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v45/AddMissingCustomRuleParametersMigrationTest/execute_when_custom_rule_have_no_parameter.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v45/AddMissingCustomRuleParametersMigrationTest/no_changes.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v45/AddMissingCustomRuleParametersMigrationTest/schema.sql [new file with mode: 0644]
server/sonar-web/src/main/webapp/WEB-INF/db/migrate/601_add_missing_custom_rule_parameters.rb [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java
sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java
sonar-core/src/main/java/org/sonar/core/persistence/migration/v45/Migration45Mapper.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/persistence/migration/v45/Rule.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/persistence/migration/v45/RuleParameter.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/persistence/migration/v45/package-info.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/rule/RuleParamDto.java
sonar-core/src/main/resources/org/sonar/core/persistence/migration/v45/Migration45Mapper.xml [new file with mode: 0644]
sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql

index 5d280b4f7a28b887f8df49b0d1797f248de2070d..d27f85f8344a8c063113e1a303d3162e84383ba6 100644 (file)
@@ -23,18 +23,9 @@ import com.google.common.collect.ImmutableList;
 import org.sonar.server.db.migrations.v36.ViolationMigration;
 import org.sonar.server.db.migrations.v42.CompleteIssueMessageMigration;
 import org.sonar.server.db.migrations.v42.PackageKeysMigration;
-import org.sonar.server.db.migrations.v43.ConvertIssueDebtToMinutesMigration;
-import org.sonar.server.db.migrations.v43.DevelopmentCostMeasuresMigration;
-import org.sonar.server.db.migrations.v43.IssueChangelogMigration;
-import org.sonar.server.db.migrations.v43.NotResolvedIssuesOnRemovedComponentsMigration;
-import org.sonar.server.db.migrations.v43.RequirementMeasuresMigration;
-import org.sonar.server.db.migrations.v43.TechnicalDebtMeasuresMigration;
-import org.sonar.server.db.migrations.v44.ChangeLogMigration;
-import org.sonar.server.db.migrations.v44.ConvertProfileMeasuresMigration;
-import org.sonar.server.db.migrations.v44.FeedQProfileDatesMigration;
-import org.sonar.server.db.migrations.v44.FeedQProfileKeysMigration;
-import org.sonar.server.db.migrations.v44.IssueActionPlanKeyMigration;
-import org.sonar.server.db.migrations.v44.MeasureDataMigration;
+import org.sonar.server.db.migrations.v43.*;
+import org.sonar.server.db.migrations.v44.*;
+import org.sonar.server.db.migrations.v45.AddMissingCustomRuleParametersMigration;
 import org.sonar.server.db.migrations.v45.AddMissingRuleParameterDefaultValuesMigration;
 import org.sonar.server.db.migrations.v45.DeleteMeasuresOnDeletedProfilesMigration;
 
@@ -67,7 +58,8 @@ public interface DatabaseMigrations {
 
     // 4.5
     AddMissingRuleParameterDefaultValuesMigration.class,
-    DeleteMeasuresOnDeletedProfilesMigration.class
+    DeleteMeasuresOnDeletedProfilesMigration.class,
+    AddMissingCustomRuleParametersMigration.class
   );
 
 }
diff --git a/server/sonar-server/src/main/java/org/sonar/server/db/migrations/v45/AddMissingCustomRuleParametersMigration.java b/server/sonar-server/src/main/java/org/sonar/server/db/migrations/v45/AddMissingCustomRuleParametersMigration.java
new file mode 100644 (file)
index 0000000..4df9123
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.db.migrations.v45;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Multimap;
+import org.sonar.api.utils.System2;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.migration.v45.Migration45Mapper;
+import org.sonar.core.persistence.migration.v45.Rule;
+import org.sonar.core.persistence.migration.v45.RuleParameter;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.db.migrations.DatabaseMigration;
+
+import javax.annotation.Nullable;
+
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * See http://jira.codehaus.org/browse/SONAR-5575
+ *
+ * Add missing parameters (with no value) on each custom rules
+ *
+ * @since 4.5
+ */
+public class AddMissingCustomRuleParametersMigration implements DatabaseMigration {
+
+  private final DbClient db;
+  private final System2 system;
+
+  public AddMissingCustomRuleParametersMigration(DbClient db, System2 system) {
+    this.db = db;
+    this.system = system;
+  }
+
+  @Override
+  public void execute() {
+    DbSession session = db.openSession(false);
+    try {
+      Migration45Mapper mapper = session.getMapper(Migration45Mapper.class);
+
+      List<RuleParameter> templateRuleParams = mapper.selectAllTemplateRuleParameters();
+      Multimap<Integer, RuleParameter> templateRuleParamsByRuleId = ArrayListMultimap.create();
+      for (RuleParameter templateRuleParam : templateRuleParams) {
+        templateRuleParamsByRuleId.put(templateRuleParam.getRuleId(), templateRuleParam);
+      }
+
+      List<Rule> customRules = mapper.selectAllCustomRules();
+      Multimap<Integer, Integer> customRuleIdsByTemplateRuleId = HashMultimap.create();
+      for (Rule customRule : customRules) {
+        customRuleIdsByTemplateRuleId.put(customRule.getTemplateId(), customRule.getId());
+      }
+
+      List<RuleParameter> customRuleParams = mapper.selectAllCustomRuleParameters();
+      Multimap<Integer, RuleParameter> customRuleParamsByRuleId = ArrayListMultimap.create();
+      for (RuleParameter customRuleParam : customRuleParams) {
+        customRuleParamsByRuleId.put(customRuleParam.getRuleId(), customRuleParam);
+      }
+
+      // For each parameters of template rules, verify that each custom rules has the parameter
+      for (Integer templateRuleId : templateRuleParamsByRuleId.keySet()) {
+        for (RuleParameter templateRuleParam : templateRuleParamsByRuleId.get(templateRuleId)) {
+          // Each custom rule should have this parameter
+          for (Integer customRuleId : customRuleIdsByTemplateRuleId.get(templateRuleId)) {
+            if (!hasParameter(templateRuleParam.getName(), customRuleParamsByRuleId.get(customRuleId))) {
+              // Insert new custom rule parameter
+              mapper.insertRuleParameter(new RuleParameter()
+                .setRuleId(customRuleId)
+                .setRuleTemplateId(templateRuleId)
+                .setName(templateRuleParam.getName())
+                .setDescription(templateRuleParam.getDescription())
+                .setType(templateRuleParam.getType())
+              );
+
+              // Update updated at date of custom rule in order to allow E/S indexation
+              mapper.updateRuleUpdateAt(customRuleId, new Date(system.now()));
+            }
+          }
+        }
+      }
+
+      session.commit();
+    } finally {
+      session.close();
+    }
+  }
+
+  private boolean hasParameter(final String parameter, Collection<RuleParameter> customRuleParams) {
+    return Iterables.any(customRuleParams, new Predicate<RuleParameter>() {
+      @Override
+      public boolean apply(@Nullable RuleParameter input) {
+        return input != null && input.getName().equals(parameter);
+      }
+    });
+  }
+}
index 0a60c46eca996d661d6c97c649603e5bf26318a3..aa17fafdffc8540e256335fedfeb4155a9c520d9 100644 (file)
@@ -33,6 +33,7 @@ import org.sonar.server.db.DbClient;
 import org.sonar.server.rule.index.RuleDoc;
 
 import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
 
 public class RuleCreator implements ServerComponent {
 
@@ -168,20 +169,18 @@ public class RuleCreator implements ServerComponent {
     dbClient.ruleDao().insert(dbSession, ruleDto);
 
     for (RuleParamDto templateRuleParamDto : dbClient.ruleDao().findRuleParamsByRuleKey(dbSession, templateRuleDto.getKey())) {
-      String newRuleParam = newRule.parameter(templateRuleParamDto.getName());
-      if (newRuleParam != null) {
-        createCustomRuleParams(newRuleParam, ruleDto, templateRuleParamDto, dbSession);
-      }
+      String customRuleParamValue = Strings.emptyToNull(newRule.parameter(templateRuleParamDto.getName()));
+      createCustomRuleParams(customRuleParamValue, ruleDto, templateRuleParamDto, dbSession);
     }
     return ruleKey;
   }
 
-  private void createCustomRuleParams(String param, RuleDto ruleDto, RuleParamDto templateRuleParam, DbSession dbSession){
+  private void createCustomRuleParams(@Nullable String paramValue, RuleDto ruleDto, RuleParamDto templateRuleParam, DbSession dbSession){
     RuleParamDto ruleParamDto = RuleParamDto.createFor(ruleDto)
       .setName(templateRuleParam.getName())
       .setType(templateRuleParam.getType())
       .setDescription(templateRuleParam.getDescription())
-      .setDefaultValue(param);
+      .setDefaultValue(paramValue);
     dbClient.ruleDao().addRuleParam(dbSession, ruleDto, ruleParamDto);
   }
 
index adeeabfa2bd13329121d2867c112e0439e9d5ce7..69f7f2a5db54e0ddc38feab86bbdd05d89dfae8d 100644 (file)
@@ -39,7 +39,12 @@ import org.sonar.core.technicaldebt.db.CharacteristicDto;
 import org.sonar.server.db.DbClient;
 import org.sonar.server.user.UserSession;
 
-import java.util.*;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import static com.google.common.collect.Lists.newArrayList;
 
 public class RuleUpdater implements ServerComponent {
 
@@ -265,8 +270,7 @@ public class RuleUpdater implements ServerComponent {
         throw new IllegalStateException(String.format("Template %s of rule %s does not exist",
           customRule.getTemplateId(), customRule.getKey()));
       }
-      List<RuleParamDto> templateRuleParams = dbClient.ruleDao().findRuleParamsByRuleKey(dbSession, templateRule.getKey());
-      List<String> paramKeys = new ArrayList<String>();
+      List<String> paramKeys = newArrayList();
 
       // Load active rules and its parameters in cache
       Multimap<RuleDto, ActiveRuleDto> activeRules = ArrayListMultimap.create();
@@ -278,36 +282,33 @@ public class RuleUpdater implements ServerComponent {
         }
       }
 
-      // Browse custom rule parameters to update or delete them
+      // Browse custom rule parameters to create, update or delete them
       deleteOrUpdateParameters(dbSession, update, customRule, paramKeys, activeRules, activeRuleParams);
-
-      // Browse template rule parameters to create new parameters
-      createNewParameters(dbSession, update, customRule, templateRuleParams, paramKeys, activeRules);
     }
   }
 
   private void deleteOrUpdateParameters(DbSession dbSession, RuleUpdate update, RuleDto customRule, List<String> paramKeys,
-    Multimap<RuleDto, ActiveRuleDto> activeRules, Multimap<ActiveRuleDto, ActiveRuleParamDto> activeRuleParams) {
+                                        Multimap<RuleDto, ActiveRuleDto> activeRules, Multimap<ActiveRuleDto, ActiveRuleParamDto> activeRuleParams) {
     for (RuleParamDto ruleParamDto : dbClient.ruleDao().findRuleParamsByRuleKey(dbSession, update.getRuleKey())) {
       String key = ruleParamDto.getName();
-      String value = update.parameter(key);
-      if (!Strings.isNullOrEmpty(value)) {
-        // Update rule param
-        ruleParamDto.setDefaultValue(value);
-        dbClient.ruleDao().updateRuleParam(dbSession, customRule, ruleParamDto);
+      String value = Strings.emptyToNull(update.parameter(key));
+
+      // Update rule param
+      ruleParamDto.setDefaultValue(value);
+      dbClient.ruleDao().updateRuleParam(dbSession, customRule, ruleParamDto);
 
-        // Update linked active rule params
+      if (value != null) {
+        // Update linked active rule params or create new one
         for (ActiveRuleDto activeRuleDto : activeRules.get(customRule)) {
           for (ActiveRuleParamDto activeRuleParamDto : activeRuleParams.get(activeRuleDto)) {
             if (activeRuleParamDto.getKey().equals(key)) {
               dbClient.activeRuleDao().updateParam(dbSession, activeRuleDto, activeRuleParamDto.setValue(value));
+            } else {
+              dbClient.activeRuleDao().addParam(dbSession, activeRuleDto, ActiveRuleParamDto.createFor(ruleParamDto).setValue(value));
             }
           }
         }
       } else {
-        // Delete rule param
-        dbClient.ruleDao().removeRuleParam(dbSession, customRule, ruleParamDto);
-
         // Delete linked active rule params
         for (ActiveRuleDto activeRuleDto : activeRules.get(customRule)) {
           for (ActiveRuleParamDto activeRuleParamDto : activeRuleParams.get(activeRuleDto)) {
@@ -321,31 +322,6 @@ public class RuleUpdater implements ServerComponent {
     }
   }
 
-  private void createNewParameters(DbSession dbSession, RuleUpdate update, RuleDto customRule, List<RuleParamDto> templateRuleParams, List<String> paramKeys,
-    Multimap<RuleDto, ActiveRuleDto> activeRules) {
-    for (RuleParamDto templateRuleParam : templateRuleParams) {
-      String key = templateRuleParam.getName();
-      if (!paramKeys.contains(key)) {
-        String value = update.parameter(key);
-        if (!Strings.isNullOrEmpty(value)) {
-
-          // Create new param
-          RuleParamDto paramDto = RuleParamDto.createFor(customRule)
-            .setName(key)
-            .setDescription(templateRuleParam.getDescription())
-            .setDefaultValue(value)
-            .setType(templateRuleParam.getType());
-          dbClient.ruleDao().addRuleParam(dbSession, customRule, paramDto);
-
-          // Create new active rule param
-          for (ActiveRuleDto activeRuleDto : activeRules.get(customRule)) {
-            dbClient.activeRuleDao().addParam(dbSession, activeRuleDto, ActiveRuleParamDto.createFor(paramDto).setValue(value));
-          }
-        }
-      }
-    }
-  }
-
   /**
    * Data loaded before update
    */
diff --git a/server/sonar-server/src/test/java/org/sonar/server/db/migrations/v45/AddMissingCustomRuleParametersMigrationTest.java b/server/sonar-server/src/test/java/org/sonar/server/db/migrations/v45/AddMissingCustomRuleParametersMigrationTest.java
new file mode 100644 (file)
index 0000000..f1db254
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.db.migrations.v45;
+
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.api.utils.System2;
+import org.sonar.core.persistence.TestDatabase;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.db.migrations.DatabaseMigration;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class AddMissingCustomRuleParametersMigrationTest {
+
+  @ClassRule
+  public static TestDatabase db = new TestDatabase().schema(AddMissingCustomRuleParametersMigrationTest.class, "schema.sql");
+
+  DatabaseMigration migration;
+  System2 system = mock(System2.class);
+
+  @Before
+  public void setUp() throws Exception {
+    db.executeUpdateSql("truncate table rules");
+    db.executeUpdateSql("truncate table rules_parameters");
+    DbClient dbClient = new DbClient(db.database(), db.myBatis());
+    migration = new AddMissingCustomRuleParametersMigration(dbClient, system);
+    when(system.now()).thenReturn(DateUtils.parseDate("2014-10-09").getTime());
+  }
+
+  @Test
+  public void execute() throws Exception {
+    db.prepareDbUnit(getClass(), "execute.xml");
+
+    migration.execute();
+
+    db.assertDbUnit(getClass(), "execute-result.xml", "rules", "rules_parameters");
+  }
+
+  @Test
+  public void execute_when_custom_rule_have_no_parameter() throws Exception {
+    db.prepareDbUnit(getClass(), "execute_when_custom_rule_have_no_parameter.xml");
+
+    migration.execute();
+
+    db.assertDbUnit(getClass(), "execute_when_custom_rule_have_no_parameter-result.xml", "rules", "rules_parameters");
+  }
+
+  @Test
+  public void no_changes() throws Exception {
+    db.prepareDbUnit(getClass(), "no_changes.xml");
+
+    migration.execute();
+
+    db.assertDbUnit(getClass(), "no_changes.xml", "rules", "rules_parameters");
+  }
+
+}
index 8751f33e0c2df57631e0b67f2d49acd9e1da0eb3..4eee09b2ffe081f8c4b203d82d4bfb6479029d95 100644 (file)
@@ -112,6 +112,55 @@ public class RuleCreatorMediumTest {
     assertThat(param.getDefaultValue()).isEqualTo("a.*");
   }
 
+  @Test
+  public void create_custom_rule_with_empty_parameter_value() throws Exception {
+    // insert template rule
+    RuleDto templateRule = createTemplateRule();
+
+    NewRule newRule = NewRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey())
+      .setName("My custom")
+      .setHtmlDescription("Some description")
+      .setSeverity(Severity.MAJOR)
+      .setStatus(RuleStatus.READY)
+      .setParameters(ImmutableMap.of("regex", ""));
+
+    RuleKey customRuleKey = creator.create(newRule);
+    dbSession.clearCache();
+
+    List<RuleParamDto> params = db.ruleDao().findRuleParamsByRuleKey(dbSession, customRuleKey);
+    assertThat(params).hasSize(1);
+
+    RuleParamDto param = params.get(0);
+    assertThat(param.getName()).isEqualTo("regex");
+    assertThat(param.getDescription()).isEqualTo("Reg ex");
+    assertThat(param.getType()).isEqualTo("STRING");
+    assertThat(param.getDefaultValue()).isNull();
+  }
+
+  @Test
+  public void create_custom_rule_with_no_parameter_value() throws Exception {
+    // insert template rule
+    RuleDto templateRule = createTemplateRule();
+
+    NewRule newRule = NewRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey())
+      .setName("My custom")
+      .setHtmlDescription("Some description")
+      .setSeverity(Severity.MAJOR)
+      .setStatus(RuleStatus.READY);
+
+    RuleKey customRuleKey = creator.create(newRule);
+    dbSession.clearCache();
+
+    List<RuleParamDto> params = db.ruleDao().findRuleParamsByRuleKey(dbSession, customRuleKey);
+    assertThat(params).hasSize(1);
+
+    RuleParamDto param = params.get(0);
+    assertThat(param.getName()).isEqualTo("regex");
+    assertThat(param.getDescription()).isEqualTo("Reg ex");
+    assertThat(param.getType()).isEqualTo("STRING");
+    assertThat(param.getDefaultValue()).isNull();
+  }
+
   @Test
   public void reactivate_custom_rule_if_already_exists_in_removed_status() throws Exception {
     String key = "CUSTOM_RULE";
@@ -193,42 +242,6 @@ public class RuleCreatorMediumTest {
     }
   }
 
-  @Test
-  public void not_fail_to_create_custom_rule_when_a_param_is_missing() throws Exception {
-    // insert template rule
-    RuleDto templateRule = createTemplateRule();
-
-    NewRule newRule = NewRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey())
-      .setName("My custom")
-      .setHtmlDescription("Some description")
-      .setSeverity(Severity.MAJOR)
-      .setStatus(RuleStatus.READY);
-
-    RuleKey customRuleKey = creator.create(newRule);
-    dbSession.clearCache();
-
-    List<RuleParamDto> params = db.ruleDao().findRuleParamsByRuleKey(dbSession, customRuleKey);
-    assertThat(params).hasSize(0);
-  }
-
-  @Test
-  public void fail_to_create_custom_rule_when_missing_key() throws Exception {
-    // insert template rule
-    RuleDto templateRule = createTemplateRule();
-
-    try {
-      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("Custom key should be set");
-    }
-  }
-
   @Test
   public void fail_to_create_custom_rule_when_invalid_key() throws Exception {
     // insert template rule
index 18fb0f0f6f73aa12d75b6d003ebcb6904cf6f807..c387a7b8851425791636cebae3ad9a39bd276811 100644 (file)
@@ -400,8 +400,10 @@ public class RuleUpdaterMediumTest {
     // Create template rule
     RuleDto templateRule = RuleTesting.newTemplateRule(RuleKey.of("java", "S001"));
     ruleDao.insert(dbSession, templateRule);
-    RuleParamDto templateRuleParam = RuleParamDto.createFor(templateRule).setName("regex").setType("STRING").setDescription("Reg ex").setDefaultValue(".*");
-    ruleDao.addRuleParam(dbSession, templateRule, templateRuleParam);
+    RuleParamDto templateRuleParam1 = RuleParamDto.createFor(templateRule).setName("regex").setType("STRING").setDescription("Reg ex").setDefaultValue(".*");
+    RuleParamDto templateRuleParam2 = RuleParamDto.createFor(templateRule).setName("format").setType("STRING").setDescription("Format");
+    ruleDao.addRuleParam(dbSession, templateRule, templateRuleParam1);
+    ruleDao.addRuleParam(dbSession, templateRule, templateRuleParam2);
 
     // Create custom rule
     RuleDto customRule = RuleTesting.newCustomRule(templateRule)
@@ -410,7 +412,8 @@ public class RuleUpdaterMediumTest {
       .setSeverity(Severity.MINOR)
       .setStatus(RuleStatus.BETA);
     ruleDao.insert(dbSession, customRule);
-    ruleDao.addRuleParam(dbSession, customRule, templateRuleParam.setDefaultValue("a.*"));
+    ruleDao.addRuleParam(dbSession, customRule, templateRuleParam1.setDefaultValue("a.*"));
+    ruleDao.addRuleParam(dbSession, customRule, templateRuleParam2.setDefaultValue(null));
 
     dbSession.commit();
 
@@ -432,10 +435,45 @@ public class RuleUpdaterMediumTest {
     assertThat(customRuleReloaded.htmlDescription()).isEqualTo("New description");
     assertThat(customRuleReloaded.severity()).isEqualTo("MAJOR");
     assertThat(customRuleReloaded.status()).isEqualTo(RuleStatus.READY);
-    assertThat(customRuleReloaded.params()).hasSize(1);
+    assertThat(customRuleReloaded.params()).hasSize(2);
+
+    assertThat(customRuleReloaded.params().get(0).defaultValue()).isEqualTo("b.*");
+    assertThat(customRuleReloaded.params().get(1).defaultValue()).isNull();
+  }
+
+  @Test
+  public void update_custom_rule_with_empty_parameter() throws Exception {
+    // Create template rule
+    RuleDto templateRule = RuleTesting.newTemplateRule(RuleKey.of("java", "S001"));
+    ruleDao.insert(dbSession, templateRule);
+    RuleParamDto templateRuleParam = RuleParamDto.createFor(templateRule).setName("regex").setType("STRING").setDescription("Reg ex");
+    ruleDao.addRuleParam(dbSession, templateRule, templateRuleParam);
 
+    // Create custom rule
+    RuleDto customRule = RuleTesting.newCustomRule(templateRule)
+      .setName("Old name")
+      .setDescription("Old description")
+      .setSeverity(Severity.MINOR)
+      .setStatus(RuleStatus.BETA);
+    ruleDao.insert(dbSession, customRule);
+    ruleDao.addRuleParam(dbSession, customRule, templateRuleParam);
+
+    dbSession.commit();
+
+    // Update custom rule without setting a value for the parameter
+    RuleUpdate update = RuleUpdate.createForCustomRule(customRule.getKey())
+      .setName("New name")
+      .setMarkdownDescription("New description")
+      .setSeverity("MAJOR")
+      .setStatus(RuleStatus.READY);
+    updater.update(update, UserSession.get());
+
+    dbSession.clearCache();
+
+    // Verify custom rule is updated
+    Rule customRuleReloaded = ruleIndex.getByKey(customRule.getKey());
     RuleParam param = customRuleReloaded.params().get(0);
-    assertThat(param.defaultValue()).isEqualTo("b.*");
+    assertThat(param.defaultValue()).isNull();
   }
 
   @Test
@@ -450,11 +488,12 @@ public class RuleUpdaterMediumTest {
     RuleParamDto templateRuleParam3 = RuleParamDto.createFor(templateRule).setName("message").setType("STRING").setDescription("message");
     ruleDao.addRuleParam(dbSession, templateRule, templateRuleParam3);
 
-    // Create custom rule with 2 parameters
+    // Create custom rule
     RuleDto customRule = RuleTesting.newCustomRule(templateRule).setSeverity(Severity.MAJOR).setLanguage("xoo");
     ruleDao.insert(dbSession, customRule);
     ruleDao.addRuleParam(dbSession, customRule, templateRuleParam1.setDefaultValue("a.*"));
     ruleDao.addRuleParam(dbSession, customRule, templateRuleParam2.setDefaultValue("txt"));
+    ruleDao.addRuleParam(dbSession, customRule, templateRuleParam3);
 
     // Create a quality profile
     QualityProfileDto profileDto = QProfileTesting.newXooP1();
@@ -476,12 +515,13 @@ public class RuleUpdaterMediumTest {
 
     // Verify custom rule parameters has been updated
     Rule customRuleReloaded = ruleIndex.getByKey(customRule.getKey());
-    assertThat(customRuleReloaded.params()).hasSize(2);
+    assertThat(customRuleReloaded.params()).hasSize(3);
     assertThat(customRuleReloaded.param("regex")).isNotNull();
     assertThat(customRuleReloaded.param("regex").defaultValue()).isEqualTo("b.*");
     assertThat(customRuleReloaded.param("message")).isNotNull();
     assertThat(customRuleReloaded.param("message").defaultValue()).isEqualTo("a message");
-    assertThat(customRuleReloaded.param("format")).isNull();
+    assertThat(customRuleReloaded.param("format")).isNotNull();
+    assertThat(customRuleReloaded.param("format").defaultValue()).isNull();
 
     RuleParam param = customRuleReloaded.params().get(0);
     assertThat(param.defaultValue()).isEqualTo("b.*");
@@ -490,8 +530,8 @@ public class RuleUpdaterMediumTest {
     ActiveRule activeRule = tester.get(ActiveRuleIndex.class).getByKey(ActiveRuleKey.of(profileDto.getKey(), customRule.getKey()));
     assertThat(activeRule.params()).hasSize(2);
     assertThat(activeRule.params().get("regex")).isEqualTo("b.*");
-    assertThat(activeRule.params().get("format")).isNull();
     assertThat(activeRule.params().get("message")).isEqualTo("a message");
+    assertThat(activeRule.params().get("format")).isNull();
 
     // Verify that severity has not changed
     assertThat(activeRule.severity()).isEqualTo(Severity.BLOCKER);
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v45/AddMissingCustomRuleParametersMigrationTest/execute-result.xml b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v45/AddMissingCustomRuleParametersMigrationTest/execute-result.xml
new file mode 100644 (file)
index 0000000..a4b4ab4
--- /dev/null
@@ -0,0 +1,31 @@
+<dataset>
+
+  <!-- Template rule -->
+  <rules id="1" plugin_rule_key="ArchitecturalConstraint" plugin_name="xoo" name="Architectural constraint" description="Architectural constraint" status="READY" priority="1" language="xoo"
+         note_data="[null]" note_user_login="[null]" note_created_at="[null]" note_updated_at="[null]" description_format="HTML" tags="[null]" system_tags="[null]" plugin_config_key="[null]"
+         characteristic_id="[null]" default_characteristic_id="[null]"
+         remediation_function="[null]" default_remediation_function="[null]"
+         remediation_coeff="[null]" default_remediation_coeff="[null]"
+         remediation_offset="[null]" default_remediation_offset="[null]"
+         effort_to_fix_description="[null]"
+         is_template="[true]" template_id="[null]" created_at="2014-01-01" updated_at="2014-01-01"/>
+  <rules_parameters id="1" rule_id="1" name="max" param_type="INT" default_value="10" description="[null]" />
+  <rules_parameters id="2" rule_id="1" name="format" param_type="STRING" default_value="txt" description="[null]" />
+  <rules_parameters id="3" rule_id="1" name="type" param_type="STRING" default_value="[null]" description="[null]" />
+  <rules_parameters id="4" rule_id="1" name="param" param_type="STRING" default_value="" description="[null]" />
+
+  <!-- Custom rule, 2 parameters should be added -->
+  <rules id="2" plugin_rule_key="ArchitecturalConstraint_2" plugin_name="xoo" name="Architectural constraint 2" description="Architectural constraint 2" status="READY" priority="1" language="xoo"
+         note_data="[null]" note_user_login="[null]" note_created_at="[null]" note_updated_at="[null]" description_format="HTML" tags="[null]" system_tags="[null]" plugin_config_key="[null]"
+         characteristic_id="[null]" default_characteristic_id="[null]"
+         remediation_function="[null]" default_remediation_function="[null]"
+         remediation_coeff="[null]" default_remediation_coeff="[null]"
+         remediation_offset="[null]" default_remediation_offset="[null]"
+         effort_to_fix_description="[null]"
+         is_template="[false]" template_id="1" created_at="2014-01-01" updated_at="2014-10-09"/>
+  <rules_parameters id="5" rule_id="2" name="max" param_type="INT" default_value="10" description="[null]" />
+  <rules_parameters id="6" rule_id="2" name="format" param_type="STRING" default_value="csv" description="[null]" />
+  <rules_parameters id="7" rule_id="2" name="type" param_type="STRING" default_value="[null]" description="[null]" />
+  <rules_parameters id="8" rule_id="2" name="param" param_type="STRING" default_value="[null]" description="[null]" />
+
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v45/AddMissingCustomRuleParametersMigrationTest/execute.xml b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v45/AddMissingCustomRuleParametersMigrationTest/execute.xml
new file mode 100644 (file)
index 0000000..58b9732
--- /dev/null
@@ -0,0 +1,29 @@
+<dataset>
+
+  <!-- Template rule -->
+  <rules id="1" plugin_rule_key="ArchitecturalConstraint" plugin_name="xoo" name="Architectural constraint" description="Architectural constraint" status="READY" priority="1" language="xoo"
+         note_data="[null]" note_user_login="[null]" note_created_at="[null]" note_updated_at="[null]" description_format="HTML" tags="[null]" system_tags="[null]" plugin_config_key="[null]"
+         characteristic_id="[null]" default_characteristic_id="[null]"
+         remediation_function="[null]" default_remediation_function="[null]"
+         remediation_coeff="[null]" default_remediation_coeff="[null]"
+         remediation_offset="[null]" default_remediation_offset="[null]"
+         effort_to_fix_description="[null]"
+         is_template="[true]" template_id="[null]" created_at="2014-01-01" updated_at="2014-01-01"/>
+  <rules_parameters id="1" rule_id="1" name="max" param_type="INT" default_value="10" description="[null]" />
+  <rules_parameters id="2" rule_id="1" name="format" param_type="STRING" default_value="txt" description="[null]" />
+  <rules_parameters id="3" rule_id="1" name="type" param_type="STRING" default_value="[null]" description="[null]" />
+  <rules_parameters id="4" rule_id="1" name="param" param_type="STRING" default_value="" description="[null]" />
+
+  <!-- Custom rule, 2 parameters are existing, 2 parameters should be added -->
+  <rules id="2" plugin_rule_key="ArchitecturalConstraint_2" plugin_name="xoo" name="Architectural constraint 2" description="Architectural constraint 2" status="READY" priority="1" language="xoo"
+         note_data="[null]" note_user_login="[null]" note_created_at="[null]" note_updated_at="[null]" description_format="HTML" tags="[null]" system_tags="[null]" plugin_config_key="[null]"
+         characteristic_id="[null]" default_characteristic_id="[null]"
+         remediation_function="[null]" default_remediation_function="[null]"
+         remediation_coeff="[null]" default_remediation_coeff="[null]"
+         remediation_offset="[null]" default_remediation_offset="[null]"
+         effort_to_fix_description="[null]"
+         is_template="[false]" template_id="1" created_at="2014-01-01" updated_at="2014-01-01"/>
+  <rules_parameters id="5" rule_id="2" name="max" param_type="INT" default_value="10" description="[null]" />
+  <rules_parameters id="6" rule_id="2" name="format" param_type="STRING" default_value="csv" description="[null]" />
+
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v45/AddMissingCustomRuleParametersMigrationTest/execute_when_custom_rule_have_no_parameter-result.xml b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v45/AddMissingCustomRuleParametersMigrationTest/execute_when_custom_rule_have_no_parameter-result.xml
new file mode 100644 (file)
index 0000000..76c7c18
--- /dev/null
@@ -0,0 +1,31 @@
+<dataset>
+
+  <!-- Template rule -->
+  <rules id="1" plugin_rule_key="ArchitecturalConstraint" plugin_name="xoo" name="Architectural constraint" description="Architectural constraint" status="READY" priority="1" language="xoo"
+         note_data="[null]" note_user_login="[null]" note_created_at="[null]" note_updated_at="[null]" description_format="HTML" tags="[null]" system_tags="[null]" plugin_config_key="[null]"
+         characteristic_id="[null]" default_characteristic_id="[null]"
+         remediation_function="[null]" default_remediation_function="[null]"
+         remediation_coeff="[null]" default_remediation_coeff="[null]"
+         remediation_offset="[null]" default_remediation_offset="[null]"
+         effort_to_fix_description="[null]"
+         is_template="[true]" template_id="[null]" created_at="2014-01-01" updated_at="2014-01-01"/>
+  <rules_parameters id="1" rule_id="1" name="max" param_type="INT" default_value="10" description="[null]" />
+  <rules_parameters id="2" rule_id="1" name="format" param_type="STRING" default_value="txt" description="[null]" />
+  <rules_parameters id="3" rule_id="1" name="type" param_type="STRING" default_value="[null]" description="[null]" />
+  <rules_parameters id="4" rule_id="1" name="param" param_type="STRING" default_value="" description="[null]" />
+
+  <!-- Custom rule, 0 parameter are existing, 4 parameters should be added -->
+  <rules id="3" plugin_rule_key="ArchitecturalConstraint_3" plugin_name="xoo" name="Architectural constraint 3" description="Architectural constraint 3" status="READY" priority="1" language="xoo"
+         note_data="[null]" note_user_login="[null]" note_created_at="[null]" note_updated_at="[null]" description_format="HTML" tags="[null]" system_tags="[null]" plugin_config_key="[null]"
+         characteristic_id="[null]" default_characteristic_id="[null]"
+         remediation_function="[null]" default_remediation_function="[null]"
+         remediation_coeff="[null]" default_remediation_coeff="[null]"
+         remediation_offset="[null]" default_remediation_offset="[null]"
+         effort_to_fix_description="[null]"
+         is_template="[false]" template_id="1" created_at="2014-01-01" updated_at="2014-10-09"/>
+  <rules_parameters id="5" rule_id="3" name="max" param_type="INT" default_value="[null]" description="[null]" />
+  <rules_parameters id="6" rule_id="3" name="format" param_type="STRING" default_value="[null]" description="[null]" />
+  <rules_parameters id="7" rule_id="3" name="type" param_type="STRING" default_value="[null]" description="[null]" />
+  <rules_parameters id="8" rule_id="3" name="param" param_type="STRING" default_value="[null]" description="[null]" />
+
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v45/AddMissingCustomRuleParametersMigrationTest/execute_when_custom_rule_have_no_parameter.xml b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v45/AddMissingCustomRuleParametersMigrationTest/execute_when_custom_rule_have_no_parameter.xml
new file mode 100644 (file)
index 0000000..dd676e5
--- /dev/null
@@ -0,0 +1,27 @@
+<dataset>
+
+  <!-- Template rule -->
+  <rules id="1" plugin_rule_key="ArchitecturalConstraint" plugin_name="xoo" name="Architectural constraint" description="Architectural constraint" status="READY" priority="1" language="xoo"
+         note_data="[null]" note_user_login="[null]" note_created_at="[null]" note_updated_at="[null]" description_format="HTML" tags="[null]" system_tags="[null]" plugin_config_key="[null]"
+         characteristic_id="[null]" default_characteristic_id="[null]"
+         remediation_function="[null]" default_remediation_function="[null]"
+         remediation_coeff="[null]" default_remediation_coeff="[null]"
+         remediation_offset="[null]" default_remediation_offset="[null]"
+         effort_to_fix_description="[null]"
+         is_template="[true]" template_id="[null]" created_at="2014-01-01" updated_at="2014-01-01"/>
+  <rules_parameters id="1" rule_id="1" name="max" param_type="INT" default_value="10" description="[null]" />
+  <rules_parameters id="2" rule_id="1" name="format" param_type="STRING" default_value="txt" description="[null]" />
+  <rules_parameters id="3" rule_id="1" name="type" param_type="STRING" default_value="[null]" description="[null]" />
+  <rules_parameters id="4" rule_id="1" name="param" param_type="STRING" default_value="" description="[null]" />
+
+  <!-- Custom rule, 0 parameter are existing, 4 parameters should be added -->
+  <rules id="3" plugin_rule_key="ArchitecturalConstraint_3" plugin_name="xoo" name="Architectural constraint 3" description="Architectural constraint 3" status="READY" priority="1" language="xoo"
+         note_data="[null]" note_user_login="[null]" note_created_at="[null]" note_updated_at="[null]" description_format="HTML" tags="[null]" system_tags="[null]" plugin_config_key="[null]"
+         characteristic_id="[null]" default_characteristic_id="[null]"
+         remediation_function="[null]" default_remediation_function="[null]"
+         remediation_coeff="[null]" default_remediation_coeff="[null]"
+         remediation_offset="[null]" default_remediation_offset="[null]"
+         effort_to_fix_description="[null]"
+         is_template="[false]" template_id="1" created_at="2014-01-01" updated_at="2014-01-01"/>
+
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v45/AddMissingCustomRuleParametersMigrationTest/no_changes.xml b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v45/AddMissingCustomRuleParametersMigrationTest/no_changes.xml
new file mode 100644 (file)
index 0000000..ed072ad
--- /dev/null
@@ -0,0 +1,25 @@
+<dataset>
+
+  <!-- Template rule -->
+  <rules id="10" plugin_rule_key="Rule2" plugin_name="xoo" name="Rule2" description="Rule2" status="READY" priority="1" language="xoo"
+         note_data="[null]" note_user_login="[null]" note_created_at="[null]" note_updated_at="[null]" description_format="HTML" tags="[null]" system_tags="[null]" plugin_config_key="[null]"
+         characteristic_id="[null]" default_characteristic_id="[null]"
+         remediation_function="[null]" default_remediation_function="[null]"
+         remediation_coeff="[null]" default_remediation_coeff="[null]"
+         remediation_offset="[null]" default_remediation_offset="[null]"
+         effort_to_fix_description="[null]"
+         is_template="[true]" template_id="[null]" created_at="2014-01-01" updated_at="2014-01-01"/>
+  <rules_parameters id="10" rule_id="10" name="max" param_type="INT" default_value="10" description="[null]" />
+
+  <!-- Custom rule, no parameter should be added -->
+  <rules id="11" plugin_rule_key="Rule2_2" plugin_name="xoo" name="Rule2_2" description="Rule2_2" status="READY" priority="1" language="xoo"
+         note_data="[null]" note_user_login="[null]" note_created_at="[null]" note_updated_at="[null]" description_format="HTML" tags="[null]" system_tags="[null]" plugin_config_key="[null]"
+         characteristic_id="[null]" default_characteristic_id="[null]"
+         remediation_function="[null]" default_remediation_function="[null]"
+         remediation_coeff="[null]" default_remediation_coeff="[null]"
+         remediation_offset="[null]" default_remediation_offset="[null]"
+         effort_to_fix_description="[null]"
+         is_template="[false]" template_id="10" created_at="2014-01-01" updated_at="2014-01-01"/>
+  <rules_parameters id="11" rule_id="11" name="max" param_type="INT" default_value="10" description="[null]" />
+
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v45/AddMissingCustomRuleParametersMigrationTest/schema.sql b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v45/AddMissingCustomRuleParametersMigrationTest/schema.sql
new file mode 100644 (file)
index 0000000..0bf3861
--- /dev/null
@@ -0,0 +1,40 @@
+CREATE TABLE "RULES_PARAMETERS" (
+  "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+  "RULE_ID" INTEGER NOT NULL,
+  "NAME" VARCHAR(128) NOT NULL,
+  "PARAM_TYPE" VARCHAR(512) NOT NULL,
+  "DEFAULT_VALUE" VARCHAR(4000),
+  "DESCRIPTION" VARCHAR(4000)
+);
+
+CREATE TABLE "RULES" (
+  "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+  "PLUGIN_RULE_KEY" VARCHAR(200) NOT NULL,
+  "PLUGIN_NAME" VARCHAR(255) NOT NULL,
+  "DESCRIPTION" VARCHAR(16777215),
+  "DESCRIPTION_FORMAT" VARCHAR(20),
+  "PRIORITY" INTEGER,
+  "IS_TEMPLATE" BOOLEAN DEFAULT FALSE,
+  "TEMPLATE_ID" INTEGER,
+  "PLUGIN_CONFIG_KEY" VARCHAR(500),
+  "NAME" VARCHAR(200),
+  "STATUS" VARCHAR(40),
+  "LANGUAGE" VARCHAR(20),
+  "NOTE_DATA" CLOB(2147483647),
+  "NOTE_USER_LOGIN" VARCHAR(255),
+  "NOTE_CREATED_AT" TIMESTAMP,
+  "NOTE_UPDATED_AT" TIMESTAMP,
+  "CHARACTERISTIC_ID" INTEGER,
+  "DEFAULT_CHARACTERISTIC_ID" INTEGER,
+  "REMEDIATION_FUNCTION" VARCHAR(20),
+  "DEFAULT_REMEDIATION_FUNCTION" VARCHAR(20),
+  "REMEDIATION_COEFF" VARCHAR(20),
+  "DEFAULT_REMEDIATION_COEFF" VARCHAR(20),
+  "REMEDIATION_OFFSET" VARCHAR(20),
+  "DEFAULT_REMEDIATION_OFFSET" VARCHAR(20),
+  "EFFORT_TO_FIX_DESCRIPTION" VARCHAR(4000),
+  "TAGS" VARCHAR(4000),
+  "SYSTEM_TAGS" VARCHAR(4000),
+  "CREATED_AT" TIMESTAMP,
+  "UPDATED_AT" TIMESTAMP
+);
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/601_add_missing_custom_rule_parameters.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/601_add_missing_custom_rule_parameters.rb
new file mode 100644 (file)
index 0000000..55d0467
--- /dev/null
@@ -0,0 +1,30 @@
+#
+# SonarQube, open source software quality management tool.
+# Copyright (C) 2008-2014 SonarSource
+# mailto:contact AT sonarsource DOT com
+#
+# SonarQube is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# SonarQube is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+
+#
+# SonarQube 4.5.1
+# SONAR-5575
+#
+class AddMissingCustomRuleParameters < ActiveRecord::Migration
+
+  def self.up
+    execute_java_migration 'org.sonar.server.db.migrations.v45.AddMissingCustomRuleParametersMigration'
+  end
+end
index dcb5e436527b9850ba8427212c5256202d21a13a..af91a6ae928d96f6faa182259288655751cdf8ce 100644 (file)
@@ -33,7 +33,7 @@ import java.util.List;
  */
 public class DatabaseVersion implements BatchComponent, ServerComponent {
 
-  public static final int LAST_VERSION = 600;
+  public static final int LAST_VERSION = 601;
 
   public static enum Status {
     UP_TO_DATE, REQUIRES_UPGRADE, REQUIRES_DOWNGRADE, FRESH_INSTALL
index 3e9c9d2f5f4a4c43e7958431d5ede9bded6d5e99..58cf793f0e1ea2a3d87fe5d0d9dcbe0e8b72d883 100644 (file)
@@ -53,6 +53,7 @@ import org.sonar.core.notification.db.NotificationQueueDto;
 import org.sonar.core.notification.db.NotificationQueueMapper;
 import org.sonar.core.permission.*;
 import org.sonar.core.persistence.migration.v44.Migration44Mapper;
+import org.sonar.core.persistence.migration.v45.Migration45Mapper;
 import org.sonar.core.properties.PropertiesMapper;
 import org.sonar.core.properties.PropertyDto;
 import org.sonar.core.purge.PurgeMapper;
@@ -170,7 +171,8 @@ public class MyBatis implements BatchComponent, ServerComponent {
       org.sonar.api.database.model.MeasureMapper.class, SnapshotDataMapper.class, SnapshotSourceMapper.class, ActionPlanMapper.class, ActionPlanStatsMapper.class,
       NotificationQueueMapper.class, CharacteristicMapper.class,
       GroupMembershipMapper.class, QualityProfileMapper.class, ActiveRuleMapper.class,
-      MeasureMapper.class, MetricMapper.class, QualityGateMapper.class, QualityGateConditionMapper.class, ComponentMapper.class, ProjectQgateAssociationMapper.class
+      MeasureMapper.class, MetricMapper.class, QualityGateMapper.class, QualityGateConditionMapper.class, ComponentMapper.class, ProjectQgateAssociationMapper.class,
+      Migration45Mapper.class
     };
     loadMappers(conf, mappers);
     configureLogback(mappers);
diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/migration/v45/Migration45Mapper.java b/sonar-core/src/main/java/org/sonar/core/persistence/migration/v45/Migration45Mapper.java
new file mode 100644 (file)
index 0000000..4f78491
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.core.persistence.migration.v45;
+
+import org.apache.ibatis.annotations.Insert;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Result;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.Date;
+import java.util.List;
+
+public interface Migration45Mapper {
+
+  @Select("SELECT rules_parameters.id, rules_parameters.rule_id as \"ruleId\", rules_parameters.name as \"name\", rules_parameters.param_type as \"type\", " +
+    "  rules_parameters.default_value as \"defaultValue\", rules_parameters.description, rules.template_id as \"ruleTemplateId\" " +
+    "FROM rules_parameters " +
+    "  INNER JOIN rules ON rules.id = rules_parameters.rule_id " +
+    "WHERE rules.is_template = ${_true}")
+  @Result(javaType = RuleParameter.class)
+  List<RuleParameter> selectAllTemplateRuleParameters();
+
+  @Select("SELECT rules_parameters.id, rules_parameters.rule_id as \"ruleId\", rules_parameters.name as \"name\", rules_parameters.param_type as \"type\", " +
+    "  rules_parameters.default_value as \"defaultValue\", rules_parameters.description, rules.template_id as \"ruleTemplateId\" " +
+    "FROM rules_parameters " +
+    "  INNER JOIN rules ON rules.id = rules_parameters.rule_id " +
+    "WHERE rules.template_id IS NOT NULL")
+  @Result(javaType = RuleParameter.class)
+  List<RuleParameter> selectAllCustomRuleParameters();
+
+  @Select("SELECT id, plugin_rule_key as \"ruleKey\", plugin_name as \"repositoryKey\", is_template as \"isTemplate\", template_id as \"templateId\"" +
+    "FROM rules " +
+    "WHERE rules.template_id IS NOT NULL")
+  @Result(javaType = Rule.class)
+  List<Rule> selectAllCustomRules();
+
+  @Insert("INSERT INTO rules_parameters (rule_id, name, param_type, default_value, description)" +
+    " VALUES (#{ruleId}, #{name}, #{type}, #{defaultValue}, #{description})")
+  void insertRuleParameter(RuleParameter ruleParameter);
+
+  @Insert("UPDATE rules SET updated_at=#{date} WHERE id=#{id}")
+  void updateRuleUpdateAt(@Param("id") Integer ruleId, @Param("date") Date updatedAt);
+
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/migration/v45/Rule.java b/sonar-core/src/main/java/org/sonar/core/persistence/migration/v45/Rule.java
new file mode 100644 (file)
index 0000000..a54d2f3
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.core.persistence.migration.v45;
+
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+/**
+ * SONAR-5575
+ * <p/>
+ * Used in the Active Record Migration 601.
+ *
+ * @since 4.5
+ */
+public final class Rule {
+
+  private Integer id;
+  private String repositoryKey;
+  private String ruleKey;
+  private boolean isTemplate;
+  private Integer templateId;
+
+  public Integer getId() {
+    return id;
+  }
+
+  public Rule setId(Integer id) {
+    this.id = id;
+    return this;
+  }
+
+  public String getRepositoryKey() {
+    return repositoryKey;
+  }
+
+  public Rule setRepositoryKey(String repositoryKey) {
+    this.repositoryKey = repositoryKey;
+    return this;
+  }
+
+  public String getRuleKey() {
+    return ruleKey;
+  }
+
+  public Rule setRuleKey(String ruleKey) {
+    this.ruleKey = ruleKey;
+    return this;
+  }
+
+  public boolean isTemplate() {
+    return isTemplate;
+  }
+
+  public Rule setIsTemplate(boolean isTemplate) {
+    this.isTemplate = isTemplate;
+    return this;
+  }
+
+  @CheckForNull
+  public Integer getTemplateId() {
+    return templateId;
+  }
+
+  public Rule setTemplateId(@Nullable Integer templateId) {
+    this.templateId = templateId;
+    return this;
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (!(obj instanceof Rule)) {
+      return false;
+    }
+    if (this == obj) {
+      return true;
+    }
+    Rule other = (Rule) obj;
+    return new EqualsBuilder()
+      .append(repositoryKey, other.getRepositoryKey())
+      .append(ruleKey, other.getRuleKey())
+      .isEquals();
+  }
+
+  @Override
+  public int hashCode() {
+    return new HashCodeBuilder(17, 37)
+      .append(repositoryKey)
+      .append(ruleKey)
+      .toHashCode();
+  }
+
+
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/migration/v45/RuleParameter.java b/sonar-core/src/main/java/org/sonar/core/persistence/migration/v45/RuleParameter.java
new file mode 100644 (file)
index 0000000..c930518
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.core.persistence.migration.v45;
+
+import org.apache.commons.lang.builder.ReflectionToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+/**
+ * SONAR-5575
+ * <p/>
+ * Used in the Active Record Migration 601.
+ *
+ * @since 4.5
+ */
+public class RuleParameter {
+
+  private Integer id;
+  private Integer ruleId;
+  private Integer ruleTemplateId;
+  private String name;
+  private String type;
+  private String defaultValue;
+  private String description;
+
+  public Integer getId() {
+    return id;
+  }
+
+  public RuleParameter setId(Integer id) {
+    this.id = id;
+    return this;
+  }
+
+  public Integer getRuleId() {
+    return ruleId;
+  }
+
+  public RuleParameter setRuleId(Integer ruleId) {
+    this.ruleId = ruleId;
+    return this;
+  }
+
+  @CheckForNull
+  public Integer getRuleTemplateId() {
+    return ruleTemplateId;
+  }
+
+  public RuleParameter setRuleTemplateId(@Nullable Integer ruleTemplateId) {
+    this.ruleTemplateId = ruleTemplateId;
+    return this;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public RuleParameter setName(String name) {
+    this.name = name;
+    return this;
+  }
+
+  public String getType() {
+    return type;
+  }
+
+  public RuleParameter setType(String type) {
+    this.type = type;
+    return this;
+  }
+
+  @CheckForNull
+  public String getDefaultValue() {
+    return defaultValue;
+  }
+
+  public RuleParameter setDefaultValue(@Nullable String defaultValue) {
+    this.defaultValue = defaultValue;
+    return this;
+  }
+
+  public String getDescription() {
+    return description;
+  }
+
+  public RuleParameter setDescription(String description) {
+    this.description = description;
+    return this;
+  }
+
+  @Override
+  public String toString() {
+    return new ReflectionToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).toString();
+  }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/migration/v45/package-info.java b/sonar-core/src/main/java/org/sonar/core/persistence/migration/v45/package-info.java
new file mode 100644 (file)
index 0000000..4e661d7
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.core.persistence.migration.v45;
+
+import javax.annotation.ParametersAreNonnullByDefault;
index 7d1436974bc3faf0f0998067e19931ba6600e9ef..ddddb819bed43c3817d9d67622d93fab27a1a33f 100644 (file)
@@ -23,6 +23,9 @@ package org.sonar.core.rule;
 import org.apache.commons.lang.builder.ReflectionToStringBuilder;
 import org.apache.commons.lang.builder.ToStringStyle;
 
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
 public class RuleParamDto {
 
   private Integer id;
@@ -68,11 +71,12 @@ public class RuleParamDto {
     return this;
   }
 
+  @CheckForNull
   public String getDefaultValue() {
     return defaultValue;
   }
 
-  public RuleParamDto setDefaultValue(String defaultValue) {
+  public RuleParamDto setDefaultValue(@Nullable String defaultValue) {
     this.defaultValue = defaultValue;
     return this;
   }
diff --git a/sonar-core/src/main/resources/org/sonar/core/persistence/migration/v45/Migration45Mapper.xml b/sonar-core/src/main/resources/org/sonar/core/persistence/migration/v45/Migration45Mapper.xml
new file mode 100644 (file)
index 0000000..ea7778e
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+
+<mapper namespace="org.sonar.core.persistence.migration.v45.Migration45Mapper">
+
+</mapper>
+
index 687099904a9054f31393ea32c3aa99215aebfe8f..53b8dcc9d122fc2c921e2721181e8dc42980a093 100644 (file)
@@ -255,6 +255,7 @@ INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('582');
 INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('583');
 INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('584');
 INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('600');
+INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('601');
 
 INSERT INTO USERS(ID, LOGIN, NAME, EMAIL, CRYPTED_PASSWORD, SALT, CREATED_AT, UPDATED_AT, REMEMBER_TOKEN, REMEMBER_TOKEN_EXPIRES_AT) VALUES (1, 'admin', 'Administrator', '', 'a373a0e667abb2604c1fd571eb4ad47fe8cc0878', '48bc4b0d93179b5103fd3885ea9119498e9d161b', '2011-09-26 22:27:48.0', '2011-09-26 22:27:48.0', null, null);
 ALTER TABLE USERS ALTER COLUMN ID RESTART WITH 2;