]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-4535 create activate / deactivate / update severity actions in QProfiles
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Wed, 18 Dec 2013 15:39:58 +0000 (16:39 +0100)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Wed, 18 Dec 2013 15:39:58 +0000 (16:39 +0100)
36 files changed:
sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java
sonar-core/src/main/java/org/sonar/core/qualityprofile/db/ActiveRuleDao.java
sonar-core/src/main/java/org/sonar/core/qualityprofile/db/ActiveRuleDto.java
sonar-core/src/main/java/org/sonar/core/qualityprofile/db/ActiveRuleMapper.java
sonar-core/src/main/java/org/sonar/core/rule/RuleDao.java
sonar-core/src/main/java/org/sonar/core/rule/RuleParamDto.java
sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql
sonar-core/src/main/resources/org/sonar/core/persistence/schema-h2.ddl
sonar-core/src/main/resources/org/sonar/core/qualityprofile/db/ActiveRuleMapper.xml
sonar-core/src/test/java/org/sonar/core/qualityprofile/db/ActiveRuleDaoTest.java
sonar-core/src/test/resources/org/sonar/core/qualityprofile/db/ActiveRuleDaoTest/delete-result.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/qualityprofile/db/ActiveRuleDaoTest/delete_parameters-result.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/qualityprofile/db/ActiveRuleDaoTest/empty.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/qualityprofile/db/ActiveRuleDaoTest/insertParameter-result.xml
sonar-core/src/test/resources/org/sonar/core/qualityprofile/db/ActiveRuleDaoTest/shared.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/qualityprofile/db/ActiveRuleDaoTest/update-result.xml [new file with mode: 0644]
sonar-plugin-api/src/main/java/org/sonar/api/rule/Severity.java
sonar-plugin-api/src/main/java/org/sonar/api/rules/ActiveRule.java
sonar-plugin-api/src/main/java/org/sonar/api/rules/ActiveRuleParam.java
sonar-plugin-api/src/main/java/org/sonar/api/rules/RulePriority.java
sonar-server/src/main/java/org/sonar/server/configuration/ProfilesBackup.java
sonar-server/src/main/java/org/sonar/server/configuration/ProfilesManager.java
sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileOperations.java
sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfiles.java
sonar-server/src/main/java/org/sonar/server/user/RubyUserSession.java
sonar-server/src/main/java/org/sonar/server/user/UserSession.java
sonar-server/src/main/webapp/WEB-INF/app/controllers/application_controller.rb
sonar-server/src/main/webapp/WEB-INF/db/migrate/483_add_rules_parameter_key_to_active_rule_parameters.rb [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/db/migrate/484_copy_rule_parameters_name_to_active_rule_parameters.rb [new file with mode: 0644]
sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileOperationsTest.java
sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfilesTest.java
sonar-server/src/test/java/org/sonar/server/user/MockUserSession.java
sonar-server/src/test/java/org/sonar/server/user/RubyUserSessionTest.java
sonar-server/src/test/resources/org/sonar/server/configuration/InheritedProfilesTest/shouldActivateInChildren-result.xml
sonar-server/src/test/resources/org/sonar/server/configuration/InheritedProfilesTest/shouldActivateInChildren.xml
sonar-server/src/test/resources/org/sonar/server/configuration/RuleChangeTest/ruleReverted.xml

index f9785136f17fbe73cad2626bc75dbd67d7211374..d2ca80341e3d0a6616aa2527e9409468314a09b2 100644 (file)
@@ -33,7 +33,7 @@ import java.util.List;
  */
 public class DatabaseVersion implements BatchComponent, ServerComponent {
 
-  public static final int LAST_VERSION = 482;
+  public static final int LAST_VERSION = 484;
 
   public static enum Status {
     UP_TO_DATE, REQUIRES_UPGRADE, REQUIRES_DOWNGRADE, FRESH_INSTALL
index 2346103e655d1abc876471571dc1db194c8ff873..00dc167dced82aed5de1b9e17e4710cbfb21c31e 100644 (file)
@@ -32,6 +32,28 @@ public class ActiveRuleDao implements ServerComponent {
     this.mybatis = mybatis;
   }
 
+  public ActiveRuleDto selectById(Integer id) {
+    SqlSession session = mybatis.openSession();
+    try {
+      return session.getMapper(ActiveRuleMapper.class).selectById(id);
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  public ActiveRuleDto selectByProfileAndRule(Integer profileId, Integer ruleId) {
+    SqlSession session = mybatis.openSession();
+    try {
+      return selectByProfileAndRule(profileId, ruleId, session);
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  public ActiveRuleDto selectByProfileAndRule(Integer profileId, Integer ruleId, SqlSession session) {
+    return session.getMapper(ActiveRuleMapper.class).selectByProfileAndRule(profileId, ruleId);
+  }
+
   public void insert(ActiveRuleDto dto, SqlSession session) {
     session.getMapper(ActiveRuleMapper.class).insert(dto);
   }
@@ -46,6 +68,20 @@ public class ActiveRuleDao implements ServerComponent {
     }
   }
 
+  public void update(ActiveRuleDto dto, SqlSession session) {
+    session.getMapper(ActiveRuleMapper.class).update(dto);
+  }
+
+  public void update(ActiveRuleDto dto) {
+    SqlSession session = mybatis.openSession();
+    try {
+      update(dto, session);
+      session.commit();
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
   public void insert(ActiveRuleParamDto dto, SqlSession session) {
     session.getMapper(ActiveRuleMapper.class).insertParameter(dto);
   }
@@ -60,4 +96,32 @@ public class ActiveRuleDao implements ServerComponent {
     }
   }
 
+  public void delete(Integer activeRuleId, SqlSession session) {
+    session.getMapper(ActiveRuleMapper.class).delete(activeRuleId);
+  }
+
+  public void delete(Integer activeRuleId) {
+    SqlSession session = mybatis.openSession();
+    try {
+      delete(activeRuleId, session);
+      session.commit();
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  public void deleteParameters(Integer activeRuleIdo, SqlSession session) {
+    session.getMapper(ActiveRuleMapper.class).deleteParameters(activeRuleIdo);
+  }
+
+  public void deleteParameters(Integer activeRuleId) {
+    SqlSession session = mybatis.openSession();
+    try {
+      deleteParameters(activeRuleId, session);
+      session.commit();
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
 }
index f04dd148cb83344316f8b2c8cf36a21bc8d4608b..07137e58fd377592fb27538d0569a53368e898aa 100644 (file)
@@ -83,31 +83,35 @@ public class ActiveRuleDto {
     return noteCreatedAt;
   }
 
-  public void setNoteCreatedAt(Date noteCreatedAt) {
+  public ActiveRuleDto setNoteCreatedAt(Date noteCreatedAt) {
     this.noteCreatedAt = noteCreatedAt;
+    return this;
   }
 
   public Date getNoteUpdatedAt() {
     return noteUpdatedAt;
   }
 
-  public void setNoteUpdatedAt(Date noteUpdatedAt) {
+  public ActiveRuleDto setNoteUpdatedAt(Date noteUpdatedAt) {
     this.noteUpdatedAt = noteUpdatedAt;
+    return this;
   }
 
   public String getNoteUserLogin() {
     return noteUserLogin;
   }
 
-  public void setNoteUserLogin(String noteUserLogin) {
+  public ActiveRuleDto setNoteUserLogin(String noteUserLogin) {
     this.noteUserLogin = noteUserLogin;
+    return this;
   }
 
   public String getNoteData() {
     return noteData;
   }
 
-  public void setNoteData(String noteData) {
+  public ActiveRuleDto setNoteData(String noteData) {
     this.noteData = noteData;
+    return this;
   }
 }
index e4068570c50053d870aa7ebe15615ad7cde091d3..0805237691d2fe601f18caab2dc2d96475963477 100644 (file)
 
 package org.sonar.core.qualityprofile.db;
 
+import org.apache.ibatis.annotations.Param;
+
+import javax.annotation.CheckForNull;
+
 public interface ActiveRuleMapper {
 
+  @CheckForNull
+  ActiveRuleDto selectById(Integer id);
+
+  @CheckForNull
+  ActiveRuleDto selectByProfileAndRule(@Param("profileId") Integer profileId, @Param("ruleId") Integer ruleId);
+
   void insert(ActiveRuleDto dto);
 
+  void update(ActiveRuleDto dto);
+
   void insertParameter(ActiveRuleParamDto dto);
 
+  void delete(Integer activeRuleId);
+
+  void deleteParameters(Integer activeRuleId);
+
 }
index 82001371398bb17dbbee1aca044ad8cb109959d5..60fcf4b6b74b9e5683e218eaa37c47e2d0f345f8 100644 (file)
@@ -85,7 +85,7 @@ public class RuleDao implements BatchComponent, ServerComponent {
   public void insert(Collection<RuleDto> rules) {
     SqlSession session = mybatis.openBatchSession();
     try {
-      for (RuleDto rule: rules) {
+      for (RuleDto rule : rules) {
         getMapper(session).insert(rule);
       }
       session.commit();
@@ -106,12 +106,16 @@ public class RuleDao implements BatchComponent, ServerComponent {
   public List<RuleParamDto> selectParameters(Long id) {
     SqlSession session = mybatis.openSession();
     try {
-      return getMapper(session).selectParamsForRule(id);
+      return selectParameters(id, session);
     } finally {
       MyBatis.closeQuietly(session);
     }
   }
 
+  public List<RuleParamDto> selectParameters(Long id, SqlSession session) {
+    return getMapper(session).selectParamsForRule(id);
+  }
+
   private RuleMapper getMapper(SqlSession session) {
     return session.getMapper(RuleMapper.class);
   }
index 793b56d22bfd0fc44500b42a9a9e542e3bd0a9b7..7a4f999f74360124c912ddf6454a52d78502b9e7 100644 (file)
@@ -33,47 +33,53 @@ public class RuleParamDto {
     return id;
   }
 
-  public void setId(int id) {
+  public RuleParamDto setId(int id) {
     this.id = id;
+    return this;
   }
 
   public Long getRuleId() {
     return ruleId;
   }
 
-  public void setRuleId(Long ruleId) {
+  public RuleParamDto setRuleId(Long ruleId) {
     this.ruleId = ruleId;
+    return this;
   }
 
   public String getName() {
     return name;
   }
 
-  public void setName(String name) {
+  public RuleParamDto setName(String name) {
     this.name = name;
+    return this;
   }
 
   public String getType() {
     return type;
   }
 
-  public void setType(String type) {
+  public RuleParamDto setType(String type) {
     this.type = type;
+    return this;
   }
 
   public String getDefaultValue() {
     return defaultValue;
   }
 
-  public void setDefaultValue(String defaultValue) {
+  public RuleParamDto setDefaultValue(String defaultValue) {
     this.defaultValue = defaultValue;
+    return this;
   }
 
   public String getDescription() {
     return description;
   }
 
-  public void setDescription(String description) {
+  public RuleParamDto setDescription(String description) {
     this.description = description;
+    return this;
   }
 }
index 3c128f020a14789fc28452285f62950d11df51bd..e0ce7afbee136a5e6fe9e09b2835772719ed7236 100644 (file)
@@ -193,6 +193,8 @@ INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('466');
 INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('480');
 INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('481');
 INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('482');
+INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('483');
+INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('484');
 
 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;
index 670337719f12c8004a7290c969a35f99d4005e7c..1ef71efa658b024394f804731a51360f8895a288 100644 (file)
@@ -319,6 +319,7 @@ CREATE TABLE "ACTIVE_RULE_PARAMETERS" (
   "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
   "ACTIVE_RULE_ID" INTEGER NOT NULL,
   "RULES_PARAMETER_ID" INTEGER NOT NULL,
+  "RULES_PARAMETER_KEY" VARCHAR(128),
   "VALUE" VARCHAR(4000)
 );
 
index e47f8f4abae75410c6202af6c6f4536e8b1924d1..009bf47efc166b5827c300ba0350e5e0d947e337 100644 (file)
@@ -4,27 +4,64 @@
 <mapper namespace="org.sonar.core.qualityprofile.db.ActiveRuleMapper">
 
   <sql id="activeRuleColumns">
-    p.id,
-    p.profile_id as profileId,
-    p.rule_id as ruleId,
-    p.failure_level as severity,
-    p.version as version,
-    p.used_profile as used,
-    p.note_created_at,
-    p.note_updated_at,
-    p.note_user_login,
-    p.note_data
+    a.id,
+    a.profile_id as profileId,
+    a.rule_id as ruleId,
+    a.failure_level as severity,
+    a.inheritance as inheritance,
+    a.note_data as noteData,
+    a.note_user_login as noteUserLogin,
+    a.note_updated_at as noteUpdatedAt,
+    a.note_created_at as noteCreatedAt
   </sql>
 
+  <select id="selectById" parameterType="Integer" resultType="ActiveRule">
+    SELECT <include refid="activeRuleColumns"/>
+    FROM active_rules a
+    <where>
+      AND id=#{id}
+    </where>
+  </select>
+
+  <select id="selectByProfileAndRule" parameterType="map" resultType="ActiveRule">
+    SELECT <include refid="activeRuleColumns"/>
+    FROM active_rules a
+    <where>
+      AND profile_id=#{profileId}
+      AND rule_id=#{ruleId}
+    </where>
+  </select>
+
   <insert id="insert" parameterType="ActiveRule" keyColumn="id" useGeneratedKeys="true" keyProperty="id">
     INSERT INTO active_rules (profile_id, rule_id, failure_level, inheritance, note_created_at, note_updated_at, note_user_login, note_data)
     VALUES (#{profileId}, #{ruleId}, #{severity}, #{inheritance}, #{noteCreatedAt}, #{noteUpdatedAt}, #{noteUserLogin}, #{noteData})
   </insert>
 
+  <update id="update" parameterType="ActiveRule">
+    UPDATE active_rules SET
+    profile_id=#{profileId},
+    rule_id=#{ruleId},
+    failure_level=#{severity},
+    inheritance=#{inheritance},
+    note_created_at=#{noteCreatedAt},
+    note_updated_at=#{noteUpdatedAt},
+    note_user_login=#{noteUserLogin},
+    note_data=#{noteData}
+    WHERE id=#{id}
+  </update>
+
   <insert id="insertParameter" parameterType="ActiveRuleParam" keyColumn="id" useGeneratedKeys="true" keyProperty="id">
-    INSERT INTO active_rule_parameters (active_rule_id, rules_parameter_id, value)
-    VALUES (#{activeRuleId}, #{rulesParameterId}, #{value})
+    INSERT INTO active_rule_parameters (active_rule_id, rules_parameter_id, rules_parameter_key, value)
+    VALUES (#{activeRuleId}, #{rulesParameterId}, #{key}, #{value})
   </insert>
 
+  <update id="delete" parameterType="Integer">
+    DELETE FROM active_rules WHERE id=#{id}
+  </update>
+
+  <update id="deleteParameters" parameterType="Integer">
+    DELETE FROM active_rule_parameters WHERE active_rule_id=#{id}
+  </update>
+
 </mapper>
 
index ddfe06f8c65103f5858e22e11929dc5849d6bc57..53114042072ac13a100ddc98bb3ea7951decf048 100644 (file)
@@ -22,8 +22,11 @@ package org.sonar.core.qualityprofile.db;
 
 import org.junit.Before;
 import org.junit.Test;
+import org.sonar.api.utils.DateUtils;
 import org.sonar.core.persistence.AbstractDaoTestCase;
 
+import static org.fest.assertions.Assertions.assertThat;
+
 public class ActiveRuleDaoTest extends AbstractDaoTestCase {
 
   ActiveRuleDao dao;
@@ -33,8 +36,42 @@ public class ActiveRuleDaoTest extends AbstractDaoTestCase {
     dao = new ActiveRuleDao(getMyBatis());
   }
 
+  @Test
+  public void select_by_id() {
+    setupData("shared");
+
+    ActiveRuleDto result = dao.selectById(1);
+    assertThat(result.getId()).isEqualTo(1);
+    assertThat(result.getProfileId()).isEqualTo(1);
+    assertThat(result.getRulId()).isEqualTo(10);
+    assertThat(result.getSeverity()).isEqualTo(2);
+    assertThat(result.getInheritance()).isEqualTo("INHERITED");
+    assertThat(result.getNoteData()).isEqualTo("some note");
+    assertThat(result.getNoteUserLogin()).isEqualTo("henry");
+    assertThat(result.getNoteCreatedAt()).isEqualTo(DateUtils.parseDate("2013-12-18"));
+    assertThat(result.getNoteUpdatedAt()).isEqualTo(DateUtils.parseDate("2013-12-18"));
+  }
+
+  @Test
+  public void select_by_profile_and_rule() {
+    setupData("shared");
+
+    ActiveRuleDto result = dao.selectByProfileAndRule(1, 10);
+    assertThat(result.getId()).isEqualTo(1);
+    assertThat(result.getProfileId()).isEqualTo(1);
+    assertThat(result.getRulId()).isEqualTo(10);
+    assertThat(result.getSeverity()).isEqualTo(2);
+    assertThat(result.getInheritance()).isEqualTo("INHERITED");
+    assertThat(result.getNoteData()).isEqualTo("some note");
+    assertThat(result.getNoteUserLogin()).isEqualTo("henry");
+    assertThat(result.getNoteCreatedAt()).isEqualTo(DateUtils.parseDate("2013-12-18"));
+    assertThat(result.getNoteUpdatedAt()).isEqualTo(DateUtils.parseDate("2013-12-18"));
+  }
+
   @Test
   public void insert() {
+    setupData("empty");
+
     ActiveRuleDto dto = new ActiveRuleDto()
       .setProfileId(1)
       .setRuleId(10)
@@ -46,15 +83,53 @@ public class ActiveRuleDaoTest extends AbstractDaoTestCase {
     checkTables("insert", "active_rules");
   }
 
+  @Test
+  public void update() {
+    setupData("shared");
+
+    ActiveRuleDto dto = new ActiveRuleDto()
+      .setId(1)
+      .setProfileId(1)
+      .setRuleId(10)
+      .setSeverity(4)
+      .setInheritance(null)
+      .setNoteData("text");
+
+    dao.update(dto);
+
+    checkTables("update", "active_rules");
+  }
+
   @Test
   public void insert_parameter() {
+    setupData("empty");
+
     ActiveRuleParamDto dto = new ActiveRuleParamDto()
       .setActiveRuleId(1)
       .setRulesParameterId(1)
+      .setKey("max")
       .setValue("20");
 
     dao.insert(dto);
 
     checkTables("insertParameter", "active_rule_parameters");
   }
+
+  @Test
+  public void delete() {
+    setupData("shared");
+
+    dao.delete(1);
+
+    checkTables("delete", "active_rules");
+  }
+
+  @Test
+  public void delete_parameters() {
+    setupData("shared");
+
+    dao.deleteParameters(1);
+
+    checkTables("delete_parameters", "active_rule_parameters");
+  }
 }
diff --git a/sonar-core/src/test/resources/org/sonar/core/qualityprofile/db/ActiveRuleDaoTest/delete-result.xml b/sonar-core/src/test/resources/org/sonar/core/qualityprofile/db/ActiveRuleDaoTest/delete-result.xml
new file mode 100644 (file)
index 0000000..2a65aa4
--- /dev/null
@@ -0,0 +1,9 @@
+<dataset>
+
+  <!--<active_rules id="1" profile_id="1" rule_id="10" failure_level="2" inheritance="INHERITED"-->
+                <!--note_created_at="2013-12-18" note_updated_at="2013-12-18" note_user_login="henry" note_data="some note"/>-->
+
+  <active_rules id="2" profile_id="1" rule_id="11" failure_level="0" inheritance="[null]"
+                note_created_at="2013-12-18" note_updated_at="2013-12-18" note_user_login="john" note_data="other note"/>
+
+</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/qualityprofile/db/ActiveRuleDaoTest/delete_parameters-result.xml b/sonar-core/src/test/resources/org/sonar/core/qualityprofile/db/ActiveRuleDaoTest/delete_parameters-result.xml
new file mode 100644 (file)
index 0000000..b986e9f
--- /dev/null
@@ -0,0 +1,14 @@
+<dataset>
+
+  <active_rules id="1" profile_id="1" rule_id="10" failure_level="2" inheritance="INHERITED"
+    note_created_at="[null]" note_updated_at="[null]" note_user_login="[null]" note_data="[null]"/>
+
+  <active_rules id="2" profile_id="1" rule_id="11" failure_level="0" inheritance="[null]"
+                note_created_at="[null]" note_updated_at="[null]" note_user_login="[null]" note_data="[null]"/>
+
+  <!--<active_rule_parameters id="1" active_rule_id="1" rules_parameter_id="1" rules_parameter_key="max" value="20"/>-->
+  <!--<active_rule_parameters id="2" active_rule_id="1" rules_parameter_id="2" rules_parameter_key="format" value="html"/>-->
+
+  <active_rule_parameters id="3" active_rule_id="2" rules_parameter_id="1" rules_parameter_key="max" value="15"/>
+
+</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/qualityprofile/db/ActiveRuleDaoTest/empty.xml b/sonar-core/src/test/resources/org/sonar/core/qualityprofile/db/ActiveRuleDaoTest/empty.xml
new file mode 100644 (file)
index 0000000..871dedc
--- /dev/null
@@ -0,0 +1,3 @@
+<dataset>
+
+</dataset>
index 69ec55f80073f73fdd6e7267d1f7d95164ebed93..ed2e17d48d365cd31a68ac6e722ead683c882446 100644 (file)
@@ -1,5 +1,5 @@
 <dataset>
 
-  <active_rule_parameters id="1" active_rule_id="1" rules_parameter_id="1" value="20"/>
+  <active_rule_parameters id="1" active_rule_id="1" rules_parameter_id="1" rules_parameter_key="max" value="20"/>
 
 </dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/qualityprofile/db/ActiveRuleDaoTest/shared.xml b/sonar-core/src/test/resources/org/sonar/core/qualityprofile/db/ActiveRuleDaoTest/shared.xml
new file mode 100644 (file)
index 0000000..3d92151
--- /dev/null
@@ -0,0 +1,14 @@
+<dataset>
+
+  <active_rules id="1" profile_id="1" rule_id="10" failure_level="2" inheritance="INHERITED"
+    note_created_at="2013-12-18" note_updated_at="2013-12-18" note_user_login="henry" note_data="some note"/>
+
+  <active_rules id="2" profile_id="1" rule_id="11" failure_level="0" inheritance="[null]"
+    note_created_at="2013-12-18" note_updated_at="2013-12-18" note_user_login="john" note_data="other note"/>
+
+  <active_rule_parameters id="1" active_rule_id="1" rules_parameter_id="1" rules_parameter_key="max" value="20"/>
+  <active_rule_parameters id="2" active_rule_id="1" rules_parameter_id="2" rules_parameter_key="format" value="html"/>
+
+  <active_rule_parameters id="3" active_rule_id="2" rules_parameter_id="1" rules_parameter_key="max" value="15"/>
+
+</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/qualityprofile/db/ActiveRuleDaoTest/update-result.xml b/sonar-core/src/test/resources/org/sonar/core/qualityprofile/db/ActiveRuleDaoTest/update-result.xml
new file mode 100644 (file)
index 0000000..87b48ac
--- /dev/null
@@ -0,0 +1,9 @@
+<dataset>
+
+  <active_rules id="1" profile_id="1" rule_id="10" failure_level="4" inheritance="[null]"
+                note_created_at="[null]" note_updated_at="[null]" note_user_login="[null]" note_data="text"/>
+
+  <active_rules id="2" profile_id="1" rule_id="11" failure_level="0" inheritance="[null]"
+                note_created_at="2013-12-18" note_updated_at="2013-12-18" note_user_login="john" note_data="other note"/>
+
+</dataset>
index 7fe9fe683482246ec3cd939bbdbeebbd9719e369..24e320f40314332933d81b6353c025a71a935376 100644 (file)
@@ -43,6 +43,10 @@ public final class Severity {
     return ALL.get(ordinal);
   }
 
+  public static Integer ordinal(String severiy) {
+    return ALL.indexOf(severiy);
+  }
+
   private Severity() {
     // utility
   }
index 8b0d89c0c8ebeb6cdd11a138850862530bc87687..55772eac07d95c5366dbc16ec69d4fb6a4445872 100644 (file)
@@ -208,7 +208,7 @@ public class ActiveRule implements Cloneable {
   public ActiveRule setParameter(String key, String value) {
     RuleParam ruleParameter = rule.getParam(key);
     if (ruleParameter != null) {
-      activeRuleParams.add(new ActiveRuleParam(this, ruleParameter, value));
+      activeRuleParams.add(new ActiveRuleParam(this, ruleParameter, key, value));
     }
     return this;
   }
index 1db0a4de32ca4c105c02f73f9864567390c1b7de..f634ce381108752d2f6da62b48b7ba922236e474 100644 (file)
  */
 package org.sonar.api.rules;
 
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.FetchType;
-import javax.persistence.GeneratedValue;
-import javax.persistence.Id;
-import javax.persistence.JoinColumn;
-import javax.persistence.ManyToOne;
-import javax.persistence.Table;
+import javax.persistence.*;
 
 @Entity
 @Table(name = "active_rule_parameters")
@@ -45,6 +38,9 @@ public class ActiveRuleParam implements Cloneable {
   @JoinColumn(name = "rules_parameter_id")
   private RuleParam ruleParam;
 
+  @Column(name = "rules_parameter_key", updatable = false, nullable = false, length = 128)
+  private String paramKey;
+
   @Column(name = "value", updatable = false, nullable = true, length = 4000)
   private String value;
 
@@ -71,10 +67,11 @@ public class ActiveRuleParam implements Cloneable {
    * @deprecated visibility should be decreased to protected or package
    */
   @Deprecated
-  public ActiveRuleParam(ActiveRule activeRule, RuleParam ruleParam, String value) {
+  public ActiveRuleParam(ActiveRule activeRule, RuleParam ruleParam, String paramKey, String value) {
     this.activeRule = activeRule;
     this.ruleParam = ruleParam;
     this.value = value;
+    this.paramKey = paramKey;
   }
 
   public ActiveRule getActiveRule() {
@@ -109,6 +106,15 @@ public class ActiveRuleParam implements Cloneable {
     this.value = value;
   }
 
+  public String getParamKey() {
+    return paramKey;
+  }
+
+  public void setParamKey(String paramKey) {
+    this.paramKey = paramKey;
+  }
+
+
   public String getKey() {
     return ruleParam.getKey();
   }
@@ -132,7 +138,7 @@ public class ActiveRuleParam implements Cloneable {
 
   @Override
   public Object clone() {
-    return new ActiveRuleParam(getActiveRule(), getRuleParam(), getValue());
+    return new ActiveRuleParam(getActiveRule(), getRuleParam(), getParamKey(), getValue());
   }
 
 }
index 35f0a000582bce162e3bdbb5a3b5ffb4c09c2164..3f4bb152db89f09c74de7fc8c980369e66f59b29 100644 (file)
@@ -35,7 +35,6 @@ public enum RulePriority {
 
   private static final String UNKNOWN_PRIORITY = "Unknown priority ";
 
-
   /**
    * A class to map priority level prior to Sonar 1.10 to the new ones
    *
@@ -78,4 +77,8 @@ public enum RulePriority {
     }
     throw new IllegalArgumentException(UNKNOWN_PRIORITY + checkPriority);
   }
+
+  public static RulePriority valueOfInt(int ordinal) {
+    return RulePriority.values()[ordinal];
+  }
 }
index c4291cd73ddee4e4490c60af006e0be5be18b216..db5c6770c4be3ac1613606f4fa724093cde1b6e4 100644 (file)
@@ -19,8 +19,6 @@
  */
 package org.sonar.server.configuration;
 
-import org.sonar.core.preview.PreviewCache;
-
 import com.thoughtworks.xstream.XStream;
 import com.thoughtworks.xstream.converters.Converter;
 import com.thoughtworks.xstream.converters.MarshallingContext;
@@ -33,19 +31,11 @@ import org.sonar.api.database.DatabaseSession;
 import org.sonar.api.measures.Metric;
 import org.sonar.api.profiles.Alert;
 import org.sonar.api.profiles.RulesProfile;
-import org.sonar.api.rules.ActiveRule;
-import org.sonar.api.rules.ActiveRuleParam;
-import org.sonar.api.rules.Rule;
-import org.sonar.api.rules.RuleParam;
-import org.sonar.api.rules.RulePriority;
+import org.sonar.api.rules.*;
+import org.sonar.core.preview.PreviewCache;
 import org.sonar.jpa.dao.RulesDao;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 public class ProfilesBackup implements Backupable {
 
@@ -244,7 +234,7 @@ public class ProfilesBackup implements Backupable {
             while (reader.hasMoreChildren()) {
               reader.moveDown();
               Map<String, String> valuesParam = readNode(reader);
-              ActiveRuleParam activeRuleParam = new ActiveRuleParam(null, new RuleParam(null, valuesParam.get(KEY), null, null),
+              ActiveRuleParam activeRuleParam = new ActiveRuleParam(null, new RuleParam(null, valuesParam.get(KEY), null, null), valuesParam.get(KEY),
                 valuesParam.get(VALUE));
               params.add(activeRuleParam);
               reader.moveUp();
index b594dab10e01f6629c24fde691148d8f7d78e86c..d05d08233eac0941e0c39c7fe167870e8386fcd6 100644 (file)
@@ -126,6 +126,7 @@ public class ProfilesManager extends BaseDao {
     dryRunCache.reportGlobalModification();
   }
 
+
   /**
    * Rule was activated
    */
index 3332e99b08b83ef2d59f6da460b7c031f7e328bb..3929bb79164f6c835ab11253b3add3a0ed673b6c 100644 (file)
@@ -29,8 +29,10 @@ import org.sonar.api.ServerComponent;
 import org.sonar.api.profiles.ProfileExporter;
 import org.sonar.api.profiles.ProfileImporter;
 import org.sonar.api.profiles.RulesProfile;
+import org.sonar.api.rule.Severity;
 import org.sonar.api.rules.ActiveRule;
 import org.sonar.api.rules.ActiveRuleParam;
+import org.sonar.api.rules.Rule;
 import org.sonar.api.rules.RulePriority;
 import org.sonar.api.utils.ValidationMessages;
 import org.sonar.core.permission.GlobalPermissions;
@@ -39,10 +41,15 @@ import org.sonar.core.preview.PreviewCache;
 import org.sonar.core.properties.PropertiesDao;
 import org.sonar.core.properties.PropertyDto;
 import org.sonar.core.qualityprofile.db.*;
+import org.sonar.core.rule.RuleDao;
+import org.sonar.core.rule.RuleParamDto;
+import org.sonar.server.configuration.ProfilesManager;
 import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.rule.RuleRegistry;
 import org.sonar.server.user.UserSession;
 
+import javax.annotation.CheckForNull;
+
 import java.io.StringReader;
 import java.util.List;
 import java.util.Map;
@@ -56,30 +63,38 @@ public class QProfileOperations implements ServerComponent {
   private final MyBatis myBatis;
   private final QualityProfileDao dao;
   private final ActiveRuleDao activeRuleDao;
+  private final RuleDao ruleDao;
   private final PropertiesDao propertiesDao;
   private final List<ProfileExporter> exporters;
   private final List<ProfileImporter> importers;
   private final PreviewCache dryRunCache;
   private final RuleRegistry ruleRegistry;
 
+  // Should not be used as it still uses Hibernate
+  private final ProfilesManager profilesManager;
+
   /**
    * Used by pico when no plugin provide profile exporter / importer
    */
-  public QProfileOperations(MyBatis myBatis, QualityProfileDao dao, ActiveRuleDao activeRuleDao, PropertiesDao propertiesDao,
-                            PreviewCache dryRunCache, RuleRegistry ruleRegistry) {
-    this(myBatis, dao, activeRuleDao, propertiesDao, Lists.<ProfileExporter>newArrayList(), Lists.<ProfileImporter>newArrayList(), dryRunCache, ruleRegistry);
+  public QProfileOperations(MyBatis myBatis, QualityProfileDao dao, ActiveRuleDao activeRuleDao, RuleDao ruleDao, PropertiesDao propertiesDao,
+                            PreviewCache dryRunCache, RuleRegistry ruleRegistry, ProfilesManager profilesManager) {
+    this(myBatis, dao, activeRuleDao, ruleDao, propertiesDao, Lists.<ProfileExporter>newArrayList(), Lists.<ProfileImporter>newArrayList(), dryRunCache, ruleRegistry,
+      profilesManager);
   }
 
-  public QProfileOperations(MyBatis myBatis, QualityProfileDao dao, ActiveRuleDao activeRuleDao, PropertiesDao propertiesDao,
-                            List<ProfileExporter> exporters, List<ProfileImporter> importers, PreviewCache dryRunCache, RuleRegistry ruleRegistry) {
+  public QProfileOperations(MyBatis myBatis, QualityProfileDao dao, ActiveRuleDao activeRuleDao, RuleDao ruleDao, PropertiesDao propertiesDao,
+                            List<ProfileExporter> exporters, List<ProfileImporter> importers, PreviewCache dryRunCache, RuleRegistry ruleRegistry,
+                            ProfilesManager profilesManager) {
     this.myBatis = myBatis;
     this.dao = dao;
     this.activeRuleDao = activeRuleDao;
+    this.ruleDao = ruleDao;
     this.propertiesDao = propertiesDao;
     this.exporters = exporters;
     this.importers = importers;
     this.dryRunCache = dryRunCache;
     this.ruleRegistry = ruleRegistry;
+    this.profilesManager = profilesManager;
   }
 
   public NewProfileResult newProfile(String name, String language, Map<String, String> xmlProfilesByPlugin, UserSession userSession) {
@@ -88,18 +103,18 @@ public class QProfileOperations implements ServerComponent {
     NewProfileResult result = new NewProfileResult();
     List<RulesProfile> importProfiles = readProfilesFromXml(result, xmlProfilesByPlugin);
 
-    SqlSession sqlSession = myBatis.openSession();
+    SqlSession session = myBatis.openSession();
     try {
       QualityProfileDto dto = new QualityProfileDto().setName(name).setLanguage(language).setVersion(1).setUsed(false);
-      dao.insert(dto, sqlSession);
+      dao.insert(dto, session);
       for (RulesProfile rulesProfile : importProfiles) {
-        importProfile(dto, rulesProfile, sqlSession);
+        importProfile(dto, rulesProfile, session);
       }
       result.setProfile(QProfile.from(dto));
-      sqlSession.commit();
+      session.commit();
       dryRunCache.reportGlobalModification();
     } finally {
-      MyBatis.closeQuietly(sqlSession);
+      MyBatis.closeQuietly(session);
     }
     return result;
   }
@@ -115,6 +130,69 @@ public class QProfileOperations implements ServerComponent {
     propertiesDao.setProperty(new PropertyDto().setKey(PROPERTY_PREFIX + qualityProfile.getLanguage()).setValue(qualityProfile.getName()));
   }
 
+  public void activateRule(QualityProfileDto qualityProfile, Rule rule, String severity, UserSession userSession) {
+    checkPermission(userSession);
+
+    SqlSession session = myBatis.openSession();
+    try {
+      ActiveRuleDto activeRule = findActiveRule(qualityProfile, rule);
+      if (activeRule == null) {
+        newActiveRule(qualityProfile, rule, severity, userSession, session);
+      } else {
+        updateSeverity(activeRule, severity, userSession, session);
+      }
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  private void newActiveRule(QualityProfileDto qualityProfile, Rule rule, String severity, UserSession userSession, SqlSession session) {
+    ActiveRuleDto activeRuleDto = new ActiveRuleDto()
+      .setProfileId(qualityProfile.getId())
+      .setRuleId(rule.getId())
+      .setSeverity(Severity.ordinal(severity));
+    activeRuleDao.insert(activeRuleDto, session);
+
+    List<RuleParamDto> ruleParams = ruleDao.selectParameters(rule.getId().longValue(), session);
+    for (RuleParamDto ruleParam : ruleParams) {
+      ActiveRuleParamDto activeRuleParam = new ActiveRuleParamDto()
+        .setActiveRuleId(activeRuleDto.getId())
+        .setRulesParameterId(ruleParam.getId())
+        .setKey(ruleParam.getName())
+        .setValue(ruleParam.getDefaultValue());
+      activeRuleDao.insert(activeRuleParam, session);
+    }
+    session.commit();
+
+    profilesManager.activated(qualityProfile.getId(), activeRuleDto.getId(), userSession.name());
+  }
+
+  private void updateSeverity(ActiveRuleDto activeRule, String newSeverity, UserSession userSession, SqlSession session) {
+    Integer oldSeverity = activeRule.getSeverity();
+    activeRule.setSeverity(Severity.ordinal(newSeverity));
+    activeRuleDao.update(activeRule, session);
+    session.commit();
+
+    profilesManager.ruleSeverityChanged(activeRule.getProfileId(), activeRule.getId(), RulePriority.valueOfInt(oldSeverity), RulePriority.valueOf(newSeverity),
+      userSession.name());
+  }
+
+  public void deactivateRule(QualityProfileDto qualityProfile, Rule rule, UserSession userSession) {
+    checkPermission(userSession);
+
+    SqlSession session = myBatis.openSession();
+    try {
+      ActiveRuleDto activeRule = validate(qualityProfile, rule);
+
+      activeRuleDao.delete(activeRule.getId(), session);
+      activeRuleDao.deleteParameters(activeRule.getId(), session);
+      session.commit();
+      profilesManager.deactivated(activeRule.getProfileId(), activeRule.getId(), userSession.name());
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
   private List<RulesProfile> readProfilesFromXml(NewProfileResult result, Map<String, String> xmlProfilesByPlugin) {
     List<RulesProfile> profiles = newArrayList();
     ValidationMessages messages = ValidationMessages.create();
@@ -189,4 +267,16 @@ public class QProfileOperations implements ServerComponent {
     userSession.checkGlobalPermission(GlobalPermissions.QUALITY_PROFILE_ADMIN);
   }
 
+  private ActiveRuleDto validate(QualityProfileDto qualityProfile, Rule rule) {
+    ActiveRuleDto activeRuleDto = findActiveRule(qualityProfile, rule);
+    if (activeRuleDto == null) {
+      throw new BadRequestException("No rule has been activated on this profile.");
+    }
+    return activeRuleDto;
+  }
+
+  @CheckForNull
+  private ActiveRuleDto findActiveRule(QualityProfileDto qualityProfile, Rule rule) {
+    return activeRuleDao.selectByProfileAndRule(qualityProfile.getId(), rule.getId());
+  }
 }
index c06b1a16d5992174c467e09136fdd2e1ddcc712b..83c79be48ce8153bff0731a83c53fb85992cf508 100644 (file)
@@ -23,6 +23,8 @@ package org.sonar.server.qualityprofile;
 import com.google.common.base.Strings;
 import org.sonar.api.ServerComponent;
 import org.sonar.api.component.Component;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RuleFinder;
 import org.sonar.core.component.ComponentDto;
 import org.sonar.core.qualityprofile.db.QualityProfileDao;
 import org.sonar.core.qualityprofile.db.QualityProfileDto;
@@ -43,6 +45,7 @@ public class QProfiles implements ServerComponent {
 
   private final QualityProfileDao qualityProfileDao;
   private final ResourceDao resourceDao;
+  private final RuleFinder ruleFinder;
 
   private final QProfileProjectService projectService;
 
@@ -50,10 +53,11 @@ public class QProfiles implements ServerComponent {
   private final QProfileOperations operations;
   private final ProfileRules rules;
 
-  public QProfiles(QualityProfileDao qualityProfileDao, ResourceDao resourceDao, QProfileProjectService projectService, QProfileSearch search,
+  public QProfiles(QualityProfileDao qualityProfileDao, ResourceDao resourceDao, RuleFinder ruleFinder, QProfileProjectService projectService, QProfileSearch search,
                    QProfileOperations operations, ProfileRules rules) {
     this.qualityProfileDao = qualityProfileDao;
     this.resourceDao = resourceDao;
+    this.ruleFinder = ruleFinder;
     this.projectService = projectService;
     this.search = search;
     this.operations = operations;
@@ -145,7 +149,7 @@ public class QProfiles implements ServerComponent {
   }
 
   public void addProject(int profileId, long projectId) {
-    ComponentDto project = (ComponentDto) findNotNull(projectId);
+    ComponentDto project = (ComponentDto) findProjectNotNull(projectId);
     QualityProfileDto qualityProfile = findNotNull(profileId);
 
     projectService.addProject(qualityProfile, project, UserSession.get());
@@ -153,14 +157,14 @@ public class QProfiles implements ServerComponent {
 
   public void removeProject(int profileId, long projectId) {
     QualityProfileDto qualityProfile = findNotNull(profileId);
-    ComponentDto project = (ComponentDto) findNotNull(projectId);
+    ComponentDto project = (ComponentDto) findProjectNotNull(projectId);
 
     projectService.removeProject(qualityProfile, project, UserSession.get());
   }
 
   public void removeProjectByLanguage(String language, long projectId) {
     Validation.checkMandatoryParameter(language, "language");
-    ComponentDto project = (ComponentDto) findNotNull(projectId);
+    ComponentDto project = (ComponentDto) findProjectNotNull(projectId);
 
     projectService.removeProject(language, project, UserSession.get());
   }
@@ -189,16 +193,33 @@ public class QProfiles implements ServerComponent {
     return rules.countInactiveRules(query);
   }
 
+  public void activateRule(int profileId, int ruleId, String severity) {
+    QualityProfileDto qualityProfile = findNotNull(profileId);
+    Rule rule = findRuleNotNull(ruleId);
+    operations.activateRule(qualityProfile, rule, severity, UserSession.get());
+  }
+
+  public void deactivateRule(int profileId, int ruleId) {
+    QualityProfileDto qualityProfile = findNotNull(profileId);
+    Rule rule = findRuleNotNull(ruleId);
+    operations.deactivateRule(qualityProfile, rule, UserSession.get());
+  }
+
+  //
+  // Quality profile validation
+  //
+
   private void validateNewProfile(String name, String language) {
-    validateName(name);
+    validateProfileName(name);
     Validation.checkMandatoryParameter(language, "language");
     checkNotAlreadyExists(name, language);
   }
 
   private QualityProfileDto validateRenameProfile(Integer profileId, String newName) {
-    validateName(newName);
+    validateProfileName(newName);
     QualityProfileDto profileDto = findNotNull(profileId);
     if (!profileDto.getName().equals(newName)) {
+      // TODO move this check to the service
       checkNotAlreadyExists(newName, profileDto.getLanguage());
     }
     return profileDto;
@@ -220,14 +241,6 @@ public class QProfiles implements ServerComponent {
     return checkNotNull(qualityProfile);
   }
 
-  private Component findNotNull(long projectId) {
-    Component component = resourceDao.findById(projectId);
-    if (component == null) {
-      throw new NotFoundException("This project does not exists.");
-    }
-    return component;
-  }
-
   private QualityProfileDto checkNotNull(QualityProfileDto qualityProfile) {
     if (qualityProfile == null) {
       throw new NotFoundException("This quality profile does not exists.");
@@ -245,10 +258,35 @@ public class QProfiles implements ServerComponent {
     return qualityProfileDao.selectById(id);
   }
 
-  private void validateName(String name) {
+  private void validateProfileName(String name) {
     if (Strings.isNullOrEmpty(name)) {
       throw BadRequestException.ofL10n("quality_profiles.please_type_profile_name");
     }
   }
 
+  //
+  // Project validation
+  //
+
+  private Component findProjectNotNull(long projectId) {
+    Component component = resourceDao.findById(projectId);
+    if (component == null) {
+      throw new NotFoundException("This project does not exists.");
+    }
+    return component;
+  }
+
+  //
+  // Rule validation
+  //
+
+  private Rule findRuleNotNull(int ruleId) {
+    Rule rule = ruleFinder.findById(ruleId);
+    if (rule == null) {
+      throw new NotFoundException("This rule does not exists.");
+    }
+    return rule;
+  }
+
+
 }
index e603cde6813165b8be6d3a1f40f53f5bb5b3bf4c..acd870100815c0924b07797b5df598963292b52d 100644 (file)
@@ -27,8 +27,8 @@ public class RubyUserSession {
   /**
    * Invoked by Ruby code - see application_controller.rb
    */
-  public static void setSession(@Nullable Integer userId, @Nullable String login, @Nullable String localeRubyKey) {
-    UserSession session = new UserSession().setLogin(login).setUserId(userId).setLocale(JRubyI18n.toLocale(localeRubyKey));
+  public static void setSession(@Nullable Integer userId, @Nullable String login, @Nullable String name, @Nullable String localeRubyKey) {
+    UserSession session = new UserSession().setLogin(login).setName(name).setUserId(userId).setLocale(JRubyI18n.toLocale(localeRubyKey));
     UserSession.set(session);
   }
 
index 9a991ff175c079e4eb063266dce9616d63cce2fb..d2c92f311588f210c8441b6c5a49e8715448093f 100644 (file)
@@ -32,6 +32,7 @@ import org.sonar.server.platform.Platform;
 
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
+
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
@@ -52,6 +53,7 @@ public class UserSession {
 
   private Integer userId;
   private String login;
+  private String name;
   private Locale locale = Locale.ENGLISH;
   List<String> globalPermissions = null;
 
@@ -71,6 +73,16 @@ public class UserSession {
     return this;
   }
 
+  @CheckForNull
+  public String name() {
+    return name;
+  }
+
+  UserSession setName(@Nullable String s) {
+    this.name = Strings.emptyToNull(s);
+    return this;
+  }
+
   @CheckForNull
   public Integer userId() {
     return userId;
index d073a943ed0d34a7f6f01f7c494c095cfa9b05ea..64bcc347291a4df4126a3a3ae2d402d382670b5d 100644 (file)
@@ -100,9 +100,9 @@ class ApplicationController < ActionController::Base
     end
 
     if current_user && current_user.id
-      Java::OrgSonarServerUser::RubyUserSession.setSession(current_user.id.to_i, current_user.login, I18n.locale.to_s)
+      Java::OrgSonarServerUser::RubyUserSession.setSession(current_user.id.to_i, current_user.login, current_user.name, I18n.locale.to_s)
     else
-      Java::OrgSonarServerUser::RubyUserSession.setSession(nil, nil, I18n.locale.to_s)
+      Java::OrgSonarServerUser::RubyUserSession.setSession(nil, nil, nil, I18n.locale.to_s)
     end
   end
 
diff --git a/sonar-server/src/main/webapp/WEB-INF/db/migrate/483_add_rules_parameter_key_to_active_rule_parameters.rb b/sonar-server/src/main/webapp/WEB-INF/db/migrate/483_add_rules_parameter_key_to_active_rule_parameters.rb
new file mode 100644 (file)
index 0000000..4a2468a
--- /dev/null
@@ -0,0 +1,30 @@
+#
+# SonarQube, open source software quality management tool.
+# Copyright (C) 2008-2013 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.2
+# SONAR-4950
+#
+class AddRulesParameterKeyToActiveRuleParameters < ActiveRecord::Migration
+
+  def self.up
+    add_column 'active_rule_parameters', :rules_parameter_key, :string, :null => true, :limit => 128
+  end
+end
diff --git a/sonar-server/src/main/webapp/WEB-INF/db/migrate/484_copy_rule_parameters_name_to_active_rule_parameters.rb b/sonar-server/src/main/webapp/WEB-INF/db/migrate/484_copy_rule_parameters_name_to_active_rule_parameters.rb
new file mode 100644 (file)
index 0000000..e9abbcb
--- /dev/null
@@ -0,0 +1,47 @@
+#
+# SonarQube, open source software quality management tool.
+# Copyright (C) 2008-2013 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.2
+# SONAR-4950
+#
+class CopyRuleParametersNameToActiveRuleParameters < ActiveRecord::Migration
+
+  class ActiveRuleParameter < ActiveRecord::Base
+  end
+
+  class RulesParameter < ActiveRecord::Base
+  end
+
+  def self.up
+    ActiveRuleParameter.reset_column_information
+
+    rule_params_by_id = {}
+    RulesParameter.all.each do |rule_param|
+      rule_params_by_id[rule_param.id] = rule_param
+    end
+
+    ActiveRuleParameter.all.each do |active_rule_parameter|
+      rule_param = rule_params_by_id[active_rule_parameter.rules_parameter_id]
+      active_rule_parameter.rules_parameter_key = rule_param.name if rule_param
+      active_rule_parameter.save
+    end
+  end
+end
index 635d5e4d3b64df408ca8ed2e04fdf436d113eb80..68cd7b8b58106f7013538cce495a2bf30f4e2a74 100644 (file)
@@ -34,6 +34,7 @@ import org.mockito.stubbing.Answer;
 import org.sonar.api.profiles.ProfileExporter;
 import org.sonar.api.profiles.ProfileImporter;
 import org.sonar.api.profiles.RulesProfile;
+import org.sonar.api.rule.Severity;
 import org.sonar.api.rules.ActiveRule;
 import org.sonar.api.rules.Rule;
 import org.sonar.api.rules.RulePriority;
@@ -44,6 +45,9 @@ import org.sonar.core.preview.PreviewCache;
 import org.sonar.core.properties.PropertiesDao;
 import org.sonar.core.properties.PropertyDto;
 import org.sonar.core.qualityprofile.db.*;
+import org.sonar.core.rule.RuleDao;
+import org.sonar.core.rule.RuleParamDto;
+import org.sonar.server.configuration.ProfilesManager;
 import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.exceptions.ForbiddenException;
 import org.sonar.server.rule.RuleRegistry;
@@ -74,6 +78,9 @@ public class QProfileOperationsTest {
   @Mock
   ActiveRuleDao activeRuleDao;
 
+  @Mock
+  RuleDao ruleDao;
+
   @Mock
   PropertiesDao propertiesDao;
 
@@ -83,16 +90,32 @@ public class QProfileOperationsTest {
   @Mock
   RuleRegistry ruleRegistry;
 
+  @Mock
+  ProfilesManager profilesManager;
+
   List<ProfileExporter> exporters = newArrayList();
 
   List<ProfileImporter> importers = newArrayList();
 
   QProfileOperations operations;
 
+  Integer currentId = 1;
+
   @Before
   public void setUp() throws Exception {
     when(myBatis.openSession()).thenReturn(session);
-    operations = new QProfileOperations(myBatis, qualityProfileDao, activeRuleDao, propertiesDao, exporters, importers, dryRunCache, ruleRegistry);
+
+    // Associate an id when inserting an object to simulate the db id generator
+    doAnswer(new Answer() {
+      public Object answer(InvocationOnMock invocation) {
+        Object[] args = invocation.getArguments();
+        ActiveRuleDto dto = (ActiveRuleDto) args[0];
+        dto.setId(currentId++);
+        return null;
+      }
+    }).when(activeRuleDao).insert(any(ActiveRuleDto.class), any(SqlSession.class));
+
+    operations = new QProfileOperations(myBatis, qualityProfileDao, activeRuleDao, ruleDao, propertiesDao, exporters, importers, dryRunCache, ruleRegistry, profilesManager);
   }
 
   @Test
@@ -127,10 +150,10 @@ public class QProfileOperationsTest {
   public void create_profile_from_xml_plugin() throws Exception {
     RulesProfile profile = RulesProfile.create("Default", "java");
     Rule rule = Rule.create("pmd", "rule1");
-    rule.createParameter("paramKey");
+    rule.createParameter("max");
     rule.setId(10);
     ActiveRule activeRule = profile.activateRule(rule, RulePriority.BLOCKER);
-    activeRule.setParameter("paramKey", "paramValue");
+    activeRule.setParameter("max", "10");
 
     Map<String, String> xmlProfilesByPlugin = newHashMap();
     xmlProfilesByPlugin.put("pmd", "<xml/>");
@@ -154,8 +177,8 @@ public class QProfileOperationsTest {
 
     ArgumentCaptor<ActiveRuleParamDto> activeRuleParamArgument = ArgumentCaptor.forClass(ActiveRuleParamDto.class);
     verify(activeRuleDao).insert(activeRuleParamArgument.capture(), eq(session));
-    assertThat(activeRuleParamArgument.getValue().getKey()).isEqualTo("paramKey");
-    assertThat(activeRuleParamArgument.getValue().getValue()).isEqualTo("paramValue");
+    assertThat(activeRuleParamArgument.getValue().getKey()).isEqualTo("max");
+    assertThat(activeRuleParamArgument.getValue().getValue()).isEqualTo("10");
 
     verify(ruleRegistry).bulkIndexActiveRules(anyListOf(ActiveRuleDto.class), any(Multimap.class));
   }
@@ -210,4 +233,77 @@ public class QProfileOperationsTest {
     assertThat(argumentCaptor.getValue().getValue()).isEqualTo("My profile");
   }
 
+  @Test
+  public void activate_rule() throws Exception {
+    QualityProfileDto qualityProfile = new QualityProfileDto().setId(1).setName("My profile").setLanguage("java");
+    Rule rule = Rule.create().setRepositoryKey("squid").setKey("AvoidCycle");
+    rule.setId(10);
+    when(ruleDao.selectParameters(eq(10L), eq(session))).thenReturn(newArrayList(new RuleParamDto().setId(20).setName("max").setDefaultValue("10")));
+
+    operations.activateRule(qualityProfile, rule, Severity.CRITICAL, MockUserSession.create().setName("nicolas").setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN));
+
+    ArgumentCaptor<ActiveRuleDto> activeRuleArgument = ArgumentCaptor.forClass(ActiveRuleDto.class);
+    verify(activeRuleDao).insert(activeRuleArgument.capture(), eq(session));
+    assertThat(activeRuleArgument.getValue().getRulId()).isEqualTo(10);
+    assertThat(activeRuleArgument.getValue().getSeverity()).isEqualTo(3);
+
+    ArgumentCaptor<ActiveRuleParamDto> activeRuleParamArgument = ArgumentCaptor.forClass(ActiveRuleParamDto.class);
+    verify(activeRuleDao).insert(activeRuleParamArgument.capture(), eq(session));
+    assertThat(activeRuleParamArgument.getValue().getKey()).isEqualTo("max");
+    assertThat(activeRuleParamArgument.getValue().getValue()).isEqualTo("10");
+
+    verify(session).commit();
+    verify(profilesManager).activated(eq(1), anyInt(), eq("nicolas"));
+  }
+
+  @Test
+  public void update_severity() throws Exception {
+    QualityProfileDto qualityProfile = new QualityProfileDto().setId(1).setName("My profile").setLanguage("java");
+    Rule rule = Rule.create().setRepositoryKey("squid").setKey("AvoidCycle");
+    rule.setId(10);
+    ActiveRuleDto activeRule = new ActiveRuleDto().setId(5).setProfileId(1).setRuleId(10).setSeverity(1);
+    when(activeRuleDao.selectByProfileAndRule(1, 10)).thenReturn(activeRule);
+
+    operations.activateRule(qualityProfile, rule, Severity.MAJOR, MockUserSession.create().setName("nicolas").setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN));
+
+    verify(activeRuleDao).update(eq(activeRule), eq(session));
+
+    verify(session).commit();
+    verify(profilesManager).ruleSeverityChanged(eq(1), eq(5), eq(RulePriority.MINOR), eq(RulePriority.MAJOR), eq("nicolas"));
+  }
+
+  @Test
+  public void deactivate_rule() throws Exception {
+    QualityProfileDto qualityProfile = new QualityProfileDto().setId(1).setName("My profile").setLanguage("java");
+    Rule rule = Rule.create().setRepositoryKey("squid").setKey("AvoidCycle");
+    rule.setId(10);
+    ActiveRuleDto activeRule = new ActiveRuleDto().setId(5).setProfileId(1).setRuleId(10).setSeverity(1);
+    when(activeRuleDao.selectByProfileAndRule(1, 10)).thenReturn(activeRule);
+
+    operations.deactivateRule(qualityProfile, rule, MockUserSession.create().setName("nicolas").setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN));
+
+    verify(activeRuleDao).delete(eq(5), eq(session));
+    verify(activeRuleDao).deleteParameters(eq(5), eq(session));
+    verify(session).commit();
+    verify(profilesManager).deactivated(eq(1), anyInt(), eq("nicolas"));
+  }
+
+  @Test
+  public void fail_to_deactivate_rule_if_no_active_rule_on_profile() throws Exception {
+    QualityProfileDto qualityProfile = new QualityProfileDto().setId(1).setName("My profile").setLanguage("java");
+    Rule rule = Rule.create().setRepositoryKey("squid").setKey("AvoidCycle");
+    rule.setId(10);
+    when(activeRuleDao.selectByProfileAndRule(1, 10)).thenReturn(null);
+
+    try {
+      operations.deactivateRule(qualityProfile, rule, MockUserSession.create().setName("nicolas").setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN));
+      fail();
+    } catch (Exception e) {
+      assertThat(e).isInstanceOf(BadRequestException.class);
+    }
+    verify(activeRuleDao, never()).update(any(ActiveRuleDto.class), eq(session));
+    verify(session, never()).commit();
+    verifyZeroInteractions(profilesManager);
+  }
+
 }
index 7d3852b4ced567454788b3b9fc67626be2dba72f..dcd7695bbe8ebd8263ebf9312d6e59f31401a5cf 100644 (file)
@@ -26,6 +26,9 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.runners.MockitoJUnitRunner;
+import org.sonar.api.rule.Severity;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RuleFinder;
 import org.sonar.core.component.ComponentDto;
 import org.sonar.core.qualityprofile.db.QualityProfileDao;
 import org.sonar.core.qualityprofile.db.QualityProfileDto;
@@ -55,6 +58,9 @@ public class QProfilesTest {
   @Mock
   ResourceDao resourceDao;
 
+  @Mock
+  RuleFinder ruleFinder;
+
   @Mock
   QProfileProjectService projectService;
 
@@ -71,7 +77,7 @@ public class QProfilesTest {
 
   @Before
   public void setUp() throws Exception {
-    qProfiles = new QProfiles(qualityProfileDao, resourceDao, projectService, search, service, rules);
+    qProfiles = new QProfiles(qualityProfileDao, resourceDao, ruleFinder, projectService, search, service, rules);
   }
 
   @Test
@@ -273,4 +279,47 @@ public class QProfilesTest {
     assertThat(qProfiles.searchInactiveRules(query, paging)).isEqualTo(result);
   }
 
+  @Test
+  public void activate_rule() throws Exception {
+    QualityProfileDto qualityProfile = new QualityProfileDto().setId(1).setName("My profile").setLanguage("java");
+    when(qualityProfileDao.selectById(1)).thenReturn(qualityProfile);
+    Rule rule = Rule.create().setRepositoryKey("squid").setKey("AvoidCycle");
+    rule.setId(10);
+    when(ruleFinder.findById(10)).thenReturn(rule);
+
+    qProfiles.activateRule(1, 10, Severity.BLOCKER);
+
+    verify(service).activateRule(eq(qualityProfile), eq(rule), eq(Severity.BLOCKER), any(UserSession.class));
+  }
+
+  @Test
+  public void fail_to_activate_rule_if_rule_not_found() throws Exception {
+    QualityProfileDto qualityProfile = new QualityProfileDto().setId(1).setName("My profile").setLanguage("java");
+    when(qualityProfileDao.selectById(1)).thenReturn(qualityProfile);
+    Rule rule = Rule.create().setRepositoryKey("squid").setKey("AvoidCycle");
+    rule.setId(10);
+    when(ruleFinder.findById(10)).thenReturn(null);
+
+    try {
+      qProfiles.activateRule(1, 10, Severity.BLOCKER);
+      fail();
+    } catch (Exception e) {
+      assertThat(e).isInstanceOf(NotFoundException.class);
+    }
+    verifyZeroInteractions(service);
+  }
+
+  @Test
+  public void deactivate_rule() throws Exception {
+    QualityProfileDto qualityProfile = new QualityProfileDto().setId(1).setName("My profile").setLanguage("java");
+    when(qualityProfileDao.selectById(1)).thenReturn(qualityProfile);
+    Rule rule = Rule.create().setRepositoryKey("squid").setKey("AvoidCycle");
+    rule.setId(10);
+    when(ruleFinder.findById(10)).thenReturn(rule);
+
+    qProfiles.deactivateRule(1, 10);
+
+    verify(service).deactivateRule(eq(qualityProfile), eq(rule), any(UserSession.class));
+  }
+
 }
index d5770638049a59cac3c4dcbe4754ef870e84b762..c7f76929102a6844fdc0ad1f5175addbcaf4ce85 100644 (file)
@@ -56,6 +56,11 @@ public class MockUserSession extends UserSession {
     return this;
   }
 
+  public MockUserSession setName(@Nullable String name) {
+    super.setName(name);
+    return this;
+  }
+
   public MockUserSession setUserId(@Nullable Integer userId) {
     super.setUserId(userId);
     return this;
index afe3d1265a55da293382aaac8f5169564ce00e45..c816f38ac9e132e9fe943ef59444bb241b6b3946 100644 (file)
@@ -28,12 +28,13 @@ import static org.fest.assertions.Assertions.assertThat;
 public class RubyUserSessionTest {
   @Test
   public void should_set_session() throws Exception {
-    RubyUserSession.setSession(123, "karadoc", "fr");
+    RubyUserSession.setSession(123, "karadoc", "Karadoc", "fr");
 
     UserSession session = UserSession.get();
 
     assertThat(session).isNotNull();
     assertThat(session.login()).isEqualTo("karadoc");
+    assertThat(session.name()).isEqualTo("Karadoc");
     assertThat(session.userId()).isEqualTo(123);
     assertThat(session.isLoggedIn()).isTrue();
     assertThat(session.locale()).isEqualTo(Locale.FRENCH);
@@ -41,12 +42,13 @@ public class RubyUserSessionTest {
 
   @Test
   public void should_set_anonymous_session() throws Exception {
-    RubyUserSession.setSession(null, null, "fr");
+    RubyUserSession.setSession(null, null, null, "fr");
 
     UserSession session = UserSession.get();
 
     assertThat(session).isNotNull();
     assertThat(session.login()).isNull();
+    assertThat(session.name()).isNull();
     assertThat(session.userId()).isNull();
     assertThat(session.isLoggedIn()).isFalse();
     assertThat(session.locale()).isEqualTo(Locale.FRENCH);
index edfeb956ecf34e77ce739f8f2fd9095329ba08a8..6990ee887cfb5e03b72c3a33fece5e8503e4f3d8 100644 (file)
 
   <active_rules id="1" profile_id="1" rule_id="1" failure_level="2" inheritance="[null]"
     note_created_at="[null]" note_updated_at="[null]" note_user_login="[null]" note_data="[null]" />
-  <active_rule_parameters id="1" active_rule_id="1" rules_parameter_id="1" value="30"/>
+  <active_rule_parameters id="1" active_rule_id="1" rules_parameter_id="1" rules_parameter_key="param1" value="30"/>
 
   <active_rules id="2" profile_id="2" rule_id="1" failure_level="2" inheritance="INHERITED"
     note_created_at="[null]" note_updated_at="[null]" note_user_login="[null]" note_data="[null]" />
-  <active_rule_parameters id="2" active_rule_id="2" rules_parameter_id="1" value="30"/>
+  <active_rule_parameters id="2" active_rule_id="2" rules_parameter_id="1" rules_parameter_key="param1" value="30"/>
 
 </dataset>
index 67bea788819f4ba96bd541d9226fc89781b69c0d..cf8d9f25a59310c2d0ebf503cc150a03a874f149 100644 (file)
@@ -10,6 +10,6 @@
   <rules_profiles id="2" version="1" used_profile="true" name="child" language="java" parent_name="parent" />
 
   <active_rules id="1" profile_id="1" rule_id="1" failure_level="2" inheritance="[null]"/>
-  <active_rule_parameters id="1" active_rule_id="1" rules_parameter_id="1" value="30"/>
+  <active_rule_parameters id="1" active_rule_id="1" rules_parameter_id="1" rules_parameter_key="param1" value="30"/>
 
 </dataset>
index d6e7fc81799864c0a3329fa3f6f05282dacf4d77..5ef9bf1a269a548628b1315ad097961218a52463 100644 (file)
   <rules_profiles id="2" version="1" used_profile="true" name="child" language="java" parent_name="parent" />
 
   <active_rules id="2" profile_id="1" rule_id="2" failure_level="2" inheritance="[null]"/>
-  <active_rule_parameters id="3" active_rule_id="2" rules_parameter_id="14" value="50"/>
+  <active_rule_parameters id="3" active_rule_id="2" rules_parameter_id="14" rules_parameter_key="param2" value="50"/>
 
   <active_rules id="3" profile_id="2" rule_id="2" failure_level="3" inheritance="OVERRIDES"/>
-  <active_rule_parameters id="1" active_rule_id="3" rules_parameter_id="13" value="30"/>
-  <active_rule_parameters id="2" active_rule_id="3" rules_parameter_id="14" value="100"/>
+  <active_rule_parameters id="1" active_rule_id="3" rules_parameter_id="13" rules_parameter_key="param1" value="30"/>
+  <active_rule_parameters id="2" active_rule_id="3" rules_parameter_id="14" rules_parameter_key="param2" value="100"/>
 
 </dataset>