aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorEric Hartmann <hartmann.eric@gmail.com>2018-02-01 10:07:09 +0100
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>2018-02-08 13:41:00 +0100
commit1daf83302783077e02b624ce2f06bdde8a89a343 (patch)
tree2ecec303b6cd685aa0c8e029f4001c5fe2a5c496 /server
parenta201df8720aab627050b9f14f0b35c75780e3a92 (diff)
downloadsonarqube-1daf83302783077e02b624ce2f06bdde8a89a343.tar.gz
sonarqube-1daf83302783077e02b624ce2f06bdde8a89a343.zip
SONAR-10311 Store deprecated keys of rule at startup
Diffstat (limited to 'server')
-rw-r--r--server/sonar-db-core/src/main/java/org/sonar/db/version/SqTables.java1
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/rule/DeprecatedRuleKeyDto.java141
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDao.java16
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleMapper.java7
-rw-r--r--server/sonar-db-dao/src/main/resources/org/sonar/db/rule/RuleMapper.xml40
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleDaoTest.java107
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleDbTester.java20
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleTesting.java13
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/rule/RegisterRules.java103
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/rule/SingleDeprecatedRuleKey.java150
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/rule/RegisterRulesTest.java199
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/rule/SingleDeprecatedRuleKeyTest.java129
12 files changed, 826 insertions, 100 deletions
diff --git a/server/sonar-db-core/src/main/java/org/sonar/db/version/SqTables.java b/server/sonar-db-core/src/main/java/org/sonar/db/version/SqTables.java
index 37755361fa7..1843f327d76 100644
--- a/server/sonar-db-core/src/main/java/org/sonar/db/version/SqTables.java
+++ b/server/sonar-db-core/src/main/java/org/sonar/db/version/SqTables.java
@@ -59,6 +59,7 @@ public final class SqTables {
"ce_task_input",
"ce_scanner_context",
"default_qprofiles",
+ "deprecated_rule_keys",
"duplications_index",
"es_queue",
"events",
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/rule/DeprecatedRuleKeyDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/rule/DeprecatedRuleKeyDto.java
new file mode 100644
index 00000000000..e18c6fdeece
--- /dev/null
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/rule/DeprecatedRuleKeyDto.java
@@ -0,0 +1,141 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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.db.rule;
+
+import java.util.Objects;
+import javax.annotation.CheckForNull;
+
+/**
+ * Map the table "deprecated_rule_keys"
+ */
+public class DeprecatedRuleKeyDto {
+ /**
+ * Uuid of the deprecated key
+ */
+ private String uuid;
+ /**
+ * the id of the current rule for this deprecated key
+ */
+ private Integer ruleId;
+ /**
+ * repository key that was deprecated
+ */
+ private String oldRepositoryKey;
+ /**
+ * rule key that was deprecated, not nullable
+ */
+ private String oldRuleKey;
+ /**
+ * creation date of the row
+ */
+ private Long createdAt;
+
+ /**
+ * current repository key retrieved from an external join on rule_id
+ */
+ private String newRepositoryKey;
+ /**
+ * current rule key retrieved from an external join on rule_id
+ */
+ private String newRuleKey;
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ public DeprecatedRuleKeyDto setUuid(String uuid) {
+ this.uuid = uuid;
+ return this;
+ }
+
+ public Integer getRuleId() {
+ return ruleId;
+ }
+
+ public DeprecatedRuleKeyDto setRuleId(Integer ruleId) {
+ this.ruleId = ruleId;
+ return this;
+ }
+
+ public String getOldRepositoryKey() {
+ return oldRepositoryKey;
+ }
+
+ public DeprecatedRuleKeyDto setOldRepositoryKey(String oldRepositoryKey) {
+ this.oldRepositoryKey = oldRepositoryKey;
+ return this;
+ }
+
+ public String getOldRuleKey() {
+ return oldRuleKey;
+ }
+
+ public DeprecatedRuleKeyDto setOldRuleKey(String oldRuleKey) {
+ this.oldRuleKey = oldRuleKey;
+ return this;
+ }
+
+ /**
+ * This value may be null if the rule has been deleted
+ *
+ * @return the current repository key
+ */
+ @CheckForNull
+ public String getNewRepositoryKey() {
+ return newRepositoryKey;
+ }
+
+ /**
+ * This value may be null if the rule has been deleted
+ *
+ * @return the current rule key
+ */
+ @CheckForNull
+ public String getNewRuleKey() {
+ return newRuleKey;
+ }
+
+ public long getCreatedAt() {
+ return createdAt;
+ }
+
+ public DeprecatedRuleKeyDto setCreatedAt(long createdAt) {
+ this.createdAt = createdAt;
+ return this;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(uuid);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ final DeprecatedRuleKeyDto other = (DeprecatedRuleKeyDto) obj;
+ return Objects.equals(this.uuid, other.uuid);
+ }
+}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDao.java
index 96d540e8579..3ee2b77d40a 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDao.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDao.java
@@ -22,6 +22,7 @@ package org.sonar.db.rule;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
+import java.util.Set;
import java.util.function.Consumer;
import javax.annotation.Nullable;
import org.apache.ibatis.session.ResultHandler;
@@ -38,6 +39,7 @@ import static java.util.Collections.emptyList;
import static java.util.Optional.ofNullable;
import static org.sonar.db.DatabaseUtils.executeLargeInputs;
import static org.sonar.db.DatabaseUtils.executeLargeInputsWithoutOutput;
+import static org.sonar.db.DatabaseUtils.executeLargeUpdates;
public class RuleDao implements Dao {
@@ -238,4 +240,18 @@ public class RuleDao implements Dao {
mapper(session).deleteParameter(ruleParameterId);
}
+ public Set<DeprecatedRuleKeyDto> selectAllDeprecatedRuleKeys(DbSession session) {
+ return mapper(session).selectAllDeprecatedRuleKeys();
+ }
+
+ public void deleteDeprecatedRuleKeys(DbSession dbSession, Collection<String> uuids) {
+ if (uuids.isEmpty()) {
+ return;
+ }
+ executeLargeUpdates(uuids, mapper(dbSession)::deleteDeprecatedRuleKeys);
+ }
+
+ public void insert(DbSession dbSession, DeprecatedRuleKeyDto deprecatedRuleKey) {
+ mapper(dbSession).insertDeprecatedRuleKey(deprecatedRuleKey);
+ }
}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleMapper.java
index 09a7c498169..f3c689e33a4 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleMapper.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleMapper.java
@@ -20,6 +20,7 @@
package org.sonar.db.rule;
import java.util.List;
+import java.util.Set;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.session.ResultHandler;
import org.sonar.db.es.RuleExtensionId;
@@ -83,4 +84,10 @@ public interface RuleMapper {
void updateParameter(RuleParamDto param);
void deleteParameter(Integer paramId);
+
+ Set<DeprecatedRuleKeyDto> selectAllDeprecatedRuleKeys();
+
+ void deleteDeprecatedRuleKeys(@Param("uuids") List<String> uuids);
+
+ void insertDeprecatedRuleKey(DeprecatedRuleKeyDto deprecatedRuleKeyDto);
}
diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/rule/RuleMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/rule/RuleMapper.xml
index 6cfde04506c..37ed0bf0628 100644
--- a/server/sonar-db-dao/src/main/resources/org/sonar/db/rule/RuleMapper.xml
+++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/rule/RuleMapper.xml
@@ -497,5 +497,45 @@
where
id=#{id,jdbcType=INTEGER}
</update>
+
+ <select id="selectAllDeprecatedRuleKeys" resultType="org.sonar.db.rule.DeprecatedRuleKeyDto">
+ SELECT
+ drk.uuid,
+ drk.rule_id as "ruleId",
+ drk.old_repository_key as "oldRepositoryKey",
+ drk.old_rule_key as "oldRuleKey",
+ r.plugin_rule_key as "newRuleKey",
+ r.plugin_name as "newRepositoryKey",
+ drk.created_at as "createdAt"
+ FROM
+ deprecated_rule_keys drk
+ LEFT OUTER JOIN rules r on r.id = drk.rule_id
+ </select>
+
+ <delete id="deleteDeprecatedRuleKeys">
+ DELETE FROM
+ deprecated_rule_keys
+ WHERE
+ <foreach collection="uuids" index="index" item="uuid" open="" separator=" or " close="">
+ uuid=#{uuid,jdbcType=INTEGER}
+ </foreach>
+ </delete>
+
+ <insert id="insertDeprecatedRuleKey" parameterType="org.sonar.db.rule.DeprecatedRuleKeyDto" keyColumn="uuid" useGeneratedKeys="false" keyProperty="uuid">
+ INSERT INTO deprecated_rule_keys (
+ uuid,
+ rule_id,
+ old_repository_key,
+ old_rule_key,
+ created_at
+ )
+ values (
+ #{uuid,jdbcType=VARCHAR},
+ #{ruleId,jdbcType=INTEGER},
+ #{oldRepositoryKey,jdbcType=VARCHAR},
+ #{oldRuleKey,jdbcType=VARCHAR},
+ #{createdAt,jdbcType=BIGINT}
+ )
+ </insert>
</mapper>
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleDaoTest.java
index 0cd2d997ee9..dd698f8eca3 100644
--- a/server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleDaoTest.java
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleDaoTest.java
@@ -25,7 +25,9 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
+import java.util.Set;
import java.util.function.Consumer;
+import org.apache.ibatis.exceptions.PersistenceException;
import org.apache.ibatis.session.ResultHandler;
import org.junit.Before;
import org.junit.Rule;
@@ -48,7 +50,9 @@ import org.sonar.db.rule.RuleDto.Scope;
import static com.google.common.collect.Sets.newHashSet;
import static java.util.Arrays.asList;
+import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
+import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
@@ -747,7 +751,7 @@ public class RuleDaoTest {
@Test
public void scrollIndexingRulesByKeys_scrolls_nothing_if_key_does_not_exist() {
Accumulator<RuleForIndexingDto> accumulator = new Accumulator<>();
- RuleDefinitionDto r1 = db.rules().insert();
+ db.rules().insert();
underTest.scrollIndexingRulesByKeys(db.getSession(), singletonList(RuleKey.of("does", "not exist")), accumulator);
@@ -778,7 +782,7 @@ public class RuleDaoTest {
RuleMetadataDto r1Extension = db.rules().insertOrUpdateMetadata(r1, organization, r -> r.setTagsField("t1,t2"));
RuleExtensionId r1ExtensionId = new RuleExtensionId(organization.getUuid(), r1.getRepositoryKey(), r1.getRuleKey());
RuleDefinitionDto r2 = db.rules().insert();
- RuleMetadataDto r2Extension = db.rules().insertOrUpdateMetadata(r2, organization, r -> r.setTagsField("t1,t3"));
+ db.rules().insertOrUpdateMetadata(r2, organization, r -> r.setTagsField("t1,t3"));
underTest.scrollIndexingRuleExtensionsByIds(db.getSession(), singletonList(r1ExtensionId), accumulator);
@@ -788,7 +792,104 @@ public class RuleDaoTest {
tuple(r1.getKey(), organization.getUuid(), r1Extension.getTagsAsString()));
}
- private static class Accumulator<T> implements Consumer<T> {
+ @Test
+ public void selectAllDeprecatedRuleKeys() {
+ RuleDefinitionDto r1 = db.rules().insert();
+ RuleDefinitionDto r2 = db.rules().insert();
+
+ db.rules().insertDeprecatedKey(r -> r.setRuleId(r1.getId()));
+ db.rules().insertDeprecatedKey(r -> r.setRuleId(r2.getId()));
+
+ db.getSession().commit();
+
+ Set<DeprecatedRuleKeyDto> deprecatedRuleKeyDtos = underTest.selectAllDeprecatedRuleKeys(db.getSession());
+ assertThat(deprecatedRuleKeyDtos).hasSize(2);
+ }
+
+ @Test
+ public void selectAllDeprecatedRuleKeys_return_values_even_if_there_is_no_rule() {
+ db.rules().insertDeprecatedKey();
+ db.rules().insertDeprecatedKey();
+
+ Set<DeprecatedRuleKeyDto> deprecatedRuleKeyDtos = underTest.selectAllDeprecatedRuleKeys(db.getSession());
+ assertThat(deprecatedRuleKeyDtos).hasSize(2);
+ assertThat(deprecatedRuleKeyDtos)
+ .extracting(DeprecatedRuleKeyDto::getNewRepositoryKey, DeprecatedRuleKeyDto::getNewRuleKey)
+ .containsExactly(
+ tuple(null, null),
+ tuple(null, null)
+ );
+ }
+
+ @Test
+ public void deleteDeprecatedRuleKeys_with_empty_list_has_no_effect() {
+ db.rules().insertDeprecatedKey();
+ db.rules().insertDeprecatedKey();
+
+ assertThat(underTest.selectAllDeprecatedRuleKeys(db.getSession())).hasSize(2);
+
+ underTest.deleteDeprecatedRuleKeys(db.getSession(), emptyList());
+
+ assertThat(underTest.selectAllDeprecatedRuleKeys(db.getSession())).hasSize(2);
+ }
+
+ @Test
+ public void deleteDeprecatedRuleKeys_with_non_existing_uuid_has_no_effect() {
+ db.rules().insertDeprecatedKey(d -> d.setUuid("A1"));
+ db.rules().insertDeprecatedKey(d -> d.setUuid("A2"));
+
+ assertThat(underTest.selectAllDeprecatedRuleKeys(db.getSession())).hasSize(2);
+
+ underTest.deleteDeprecatedRuleKeys(db.getSession(), asList("B1", "B2"));
+
+ assertThat(underTest.selectAllDeprecatedRuleKeys(db.getSession())).hasSize(2);
+ }
+
+ @Test
+ public void deleteDeprecatedRuleKeys() {
+ DeprecatedRuleKeyDto deprecatedRuleKeyDto1 = db.rules().insertDeprecatedKey();
+ db.rules().insertDeprecatedKey();;
+
+ assertThat(underTest.selectAllDeprecatedRuleKeys(db.getSession())).hasSize(2);
+
+ underTest.deleteDeprecatedRuleKeys(db.getSession(), singletonList(deprecatedRuleKeyDto1.getUuid()));
+ assertThat(underTest.selectAllDeprecatedRuleKeys(db.getSession())).hasSize(1);
+ }
+
+ @Test
+ public void insertDeprecatedRuleKey() {
+ RuleDefinitionDto r1 = db.rules().insert();
+ DeprecatedRuleKeyDto deprecatedRuleKeyDto = db.rules().insertDeprecatedKey(d -> d.setRuleId(r1.getId()));
+
+ db.getSession().commit();
+
+ Set<DeprecatedRuleKeyDto> deprecatedRuleKeyDtos = underTest.selectAllDeprecatedRuleKeys(db.getSession());
+ assertThat(deprecatedRuleKeyDtos).hasSize(1);
+
+ DeprecatedRuleKeyDto deprecatedRuleKeyDto1 = deprecatedRuleKeyDtos.iterator().next();
+ assertThat(deprecatedRuleKeyDto1.getOldRepositoryKey()).isEqualTo(deprecatedRuleKeyDto.getOldRepositoryKey());
+ assertThat(deprecatedRuleKeyDto1.getOldRuleKey()).isEqualTo(deprecatedRuleKeyDto.getOldRuleKey());
+ assertThat(deprecatedRuleKeyDto1.getNewRepositoryKey()).isEqualTo(r1.getRepositoryKey());
+ assertThat(deprecatedRuleKeyDto1.getNewRuleKey()).isEqualTo(r1.getRuleKey());
+ assertThat(deprecatedRuleKeyDto1.getUuid()).isEqualTo(deprecatedRuleKeyDto.getUuid());
+ assertThat(deprecatedRuleKeyDto1.getCreatedAt()).isEqualTo(deprecatedRuleKeyDto.getCreatedAt());
+ assertThat(deprecatedRuleKeyDto1.getRuleId()).isEqualTo(r1.getId());
+ }
+
+ @Test
+ public void insertDeprecatedRuleKey_with_same_RuleKey_should_fail() {
+ String repositoryKey = randomAlphanumeric(50);
+ String ruleKey = randomAlphanumeric(50);
+ db.rules().insertDeprecatedKey(d -> d.setOldRepositoryKey(repositoryKey)
+ .setOldRuleKey(ruleKey));
+
+ thrown.expect(PersistenceException.class);
+
+ db.rules().insertDeprecatedKey(d -> d.setOldRepositoryKey(repositoryKey)
+ .setOldRuleKey(ruleKey));
+ }
+
+ private static class Accumulator<T> implements Consumer<T> {
private final List<T> list = new ArrayList<>();
@Override
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleDbTester.java b/server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleDbTester.java
index d816f4fe0fb..6bfaf0d2831 100644
--- a/server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleDbTester.java
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleDbTester.java
@@ -19,14 +19,15 @@
*/
package org.sonar.db.rule;
-import java.util.Arrays;
import java.util.function.Consumer;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.server.rule.RuleParamType;
import org.sonar.db.DbTester;
import org.sonar.db.organization.OrganizationDto;
+import static java.util.Arrays.asList;
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
+import static org.sonar.db.rule.RuleTesting.newDeprecatedRuleKey;
import static org.sonar.db.rule.RuleTesting.newRule;
import static org.sonar.db.rule.RuleTesting.newRuleDto;
@@ -49,7 +50,7 @@ public class RuleDbTester {
@SafeVarargs
public final RuleDefinitionDto insert(Consumer<RuleDefinitionDto>... populaters) {
RuleDefinitionDto rule = newRule();
- Arrays.asList(populaters).forEach(populater -> populater.accept(rule));
+ asList(populaters).forEach(populater -> populater.accept(rule));
return insert(rule);
}
@@ -74,7 +75,7 @@ public class RuleDbTester {
@SafeVarargs
public final RuleMetadataDto insertOrUpdateMetadata(RuleDefinitionDto rule, OrganizationDto organization, Consumer<RuleMetadataDto>... populaters) {
RuleMetadataDto dto = RuleTesting.newRuleMetadata(rule, organization);
- Arrays.asList(populaters).forEach(populater -> populater.accept(dto));
+ asList(populaters).forEach(populater -> populater.accept(dto));
return insertOrUpdateMetadata(dto);
}
@@ -91,7 +92,7 @@ public class RuleDbTester {
@SafeVarargs
public final RuleParamDto insertRuleParam(RuleDefinitionDto rule, Consumer<RuleParamDto>... populaters) {
RuleParamDto param = RuleTesting.newRuleParam(rule);
- Arrays.asList(populaters).forEach(populater -> populater.accept(param));
+ asList(populaters).forEach(populater -> populater.accept(param));
db.getDbClient().ruleDao().insertRuleParam(db.getSession(), rule, param);
db.commit();
return param;
@@ -127,7 +128,7 @@ public class RuleDbTester {
@SafeVarargs
public final RuleDto insertRule(OrganizationDto organization, Consumer<RuleDto>... populaters) {
RuleDto ruleDto = newRuleDto(organization);
- Arrays.asList(populaters).forEach(populater -> populater.accept(ruleDto));
+ asList(populaters).forEach(populater -> populater.accept(ruleDto));
return insertRule(ruleDto);
}
@@ -137,6 +138,15 @@ public class RuleDbTester {
return insertRule(ruleDto);
}
+ @SafeVarargs
+ public final DeprecatedRuleKeyDto insertDeprecatedKey(Consumer<DeprecatedRuleKeyDto>... deprecatedRuleKeyDtoConsumers) {
+ DeprecatedRuleKeyDto deprecatedRuleKeyDto = newDeprecatedRuleKey();
+ asList(deprecatedRuleKeyDtoConsumers).forEach(c -> c.accept(deprecatedRuleKeyDto));
+ db.getDbClient().ruleDao().insert(db.getSession(), deprecatedRuleKeyDto);
+ return deprecatedRuleKeyDto;
+ }
+
+
public RuleParamDto insertRuleParam(RuleDto rule) {
RuleParamDto param = new RuleParamDto();
param.setRuleId(rule.getId());
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleTesting.java b/server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleTesting.java
index 7256c275bd8..3339cc08120 100644
--- a/server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleTesting.java
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleTesting.java
@@ -28,6 +28,8 @@ import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rule.Severity;
import org.sonar.api.rules.RuleType;
import org.sonar.api.server.rule.RuleParamType;
+import org.sonar.core.util.UuidFactory;
+import org.sonar.core.util.UuidFactoryFast;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.rule.RuleDto.Format;
import org.sonar.db.rule.RuleDto.Scope;
@@ -49,6 +51,8 @@ public class RuleTesting {
public static final RuleKey XOO_X2 = RuleKey.of("xoo", "x2");
public static final RuleKey XOO_X3 = RuleKey.of("xoo", "x3");
+ private static final UuidFactory uuidFactory = UuidFactoryFast.getInstance();
+
private RuleTesting() {
// only static helpers
}
@@ -112,6 +116,15 @@ public class RuleTesting {
.setType(RuleParamType.STRING.type());
}
+ public static DeprecatedRuleKeyDto newDeprecatedRuleKey() {
+ return new DeprecatedRuleKeyDto()
+ .setUuid(uuidFactory.create())
+ .setOldRepositoryKey(randomAlphanumeric(50))
+ .setOldRuleKey(randomAlphanumeric(50))
+ .setRuleId(nextInt(100_000))
+ .setCreatedAt(System.currentTimeMillis());
+ }
+
/**
* @deprecated use newRule(...)
*/
diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/RegisterRules.java b/server/sonar-server/src/main/java/org/sonar/server/rule/RegisterRules.java
index 3920e843356..8f82e6ac4c3 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/rule/RegisterRules.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/rule/RegisterRules.java
@@ -21,13 +21,14 @@ package org.sonar.server.rule;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.apache.commons.lang.ObjectUtils;
@@ -44,11 +45,13 @@ import org.sonar.api.utils.System2;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler;
+import org.sonar.core.util.UuidFactory;
import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.qualityprofile.ActiveRuleDto;
import org.sonar.db.qualityprofile.ActiveRuleParamDto;
+import org.sonar.db.rule.DeprecatedRuleKeyDto;
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.db.rule.RuleDto.Format;
import org.sonar.db.rule.RuleDto.Scope;
@@ -62,7 +65,10 @@ import org.sonar.server.rule.index.RuleIndexer;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Lists.newArrayList;
+import static com.google.common.collect.Sets.difference;
import static java.lang.String.format;
+import static java.util.Collections.emptySet;
+import static java.util.stream.Collectors.toSet;
/**
* Register rules at server startup
@@ -80,10 +86,11 @@ public class RegisterRules implements Startable {
private final System2 system2;
private final OrganizationFlags organizationFlags;
private final WebServerRuleFinder webServerRuleFinder;
+ private final UuidFactory uuidFactory;
public RegisterRules(RuleDefinitionsLoader defLoader, QProfileRules qProfileRules, DbClient dbClient, RuleIndexer ruleIndexer,
ActiveRuleIndexer activeRuleIndexer, Languages languages, System2 system2, OrganizationFlags organizationFlags,
- WebServerRuleFinder webServerRuleFinder) {
+ WebServerRuleFinder webServerRuleFinder, UuidFactory uuidFactory) {
this.defLoader = defLoader;
this.qProfileRules = qProfileRules;
this.dbClient = dbClient;
@@ -93,6 +100,7 @@ public class RegisterRules implements Startable {
this.system2 = system2;
this.organizationFlags = organizationFlags;
this.webServerRuleFinder = webServerRuleFinder;
+ this.uuidFactory = uuidFactory;
}
@Override
@@ -100,14 +108,20 @@ public class RegisterRules implements Startable {
Profiler profiler = Profiler.create(LOG).startInfo("Register rules");
try (DbSession dbSession = dbClient.openSession(false)) {
Map<RuleKey, RuleDefinitionDto> allRules = loadRules(dbSession);
- List<RuleKey> keysToIndex = new ArrayList<>();
+ Map<Integer, Set<SingleDeprecatedRuleKey>> existingDeprecatedRuleKeys = loadDeprecatedRuleKeys(dbSession);
RulesDefinition.Context context = defLoader.load();
+
+ List<RulesDefinition.ExtendedRepository> repositories = getRepositories(context);
+
+ List<RuleKey> keysToIndex = new ArrayList<>();
boolean orgsEnabled = organizationFlags.isEnabled(dbSession);
- for (RulesDefinition.ExtendedRepository repoDef : getRepositories(context)) {
+
+ for (RulesDefinition.ExtendedRepository repoDef : repositories) {
if (languages.get(repoDef.language()) != null) {
for (RulesDefinition.Rule ruleDef : repoDef.rules()) {
RuleKey ruleKey = RuleKey.of(ruleDef.repository().key(), ruleDef.key());
+
if (ruleDef.template() && orgsEnabled) {
RuleDefinitionDto ruleDefinition = allRules.get(ruleKey);
if (ruleDefinition != null && ruleDefinition.getStatus() == RuleStatus.REMOVED) {
@@ -118,7 +132,7 @@ public class RegisterRules implements Startable {
}
continue;
}
- boolean relevantForIndex = registerRule(ruleDef, allRules, dbSession);
+ boolean relevantForIndex = registerRule(ruleDef, allRules, existingDeprecatedRuleKeys, dbSession);
if (relevantForIndex) {
keysToIndex.add(ruleKey);
}
@@ -126,6 +140,7 @@ public class RegisterRules implements Startable {
dbSession.commit();
}
}
+
List<RuleDefinitionDto> removedRules = processRemainingDbRules(allRules.values(), dbSession);
List<ActiveRuleChange> changes = removeActiveRulesOnStillExistingRepositories(dbSession, removedRules, context);
dbSession.commit();
@@ -142,6 +157,11 @@ public class RegisterRules implements Startable {
}
}
+ @Override
+ public void stop() {
+ // nothing
+ }
+
private void persistRepositories(DbSession dbSession, List<RulesDefinition.Repository> repositories) {
dbClient.ruleRepositoryDao().truncate(dbSession);
List<RuleRepositoryDto> dtos = repositories
@@ -152,12 +172,8 @@ public class RegisterRules implements Startable {
dbSession.commit();
}
- @Override
- public void stop() {
- // nothing
- }
-
- private boolean registerRule(RulesDefinition.Rule ruleDef, Map<RuleKey, RuleDefinitionDto> allRules, DbSession session) {
+ private boolean registerRule(RulesDefinition.Rule ruleDef, Map<RuleKey, RuleDefinitionDto> allRules, Map<Integer,
+ Set<SingleDeprecatedRuleKey>> existingDeprecatedRuleKeys, DbSession session) {
RuleKey ruleKey = RuleKey.of(ruleDef.repository().key(), ruleDef.key());
RuleDefinitionDto existingRule = allRules.remove(ruleKey);
@@ -171,24 +187,16 @@ public class RegisterRules implements Startable {
newRule = false;
}
- boolean executeUpdate = false;
- if (mergeRule(ruleDef, rule)) {
- executeUpdate = true;
- }
-
- if (mergeDebtDefinitions(ruleDef, rule)) {
- executeUpdate = true;
- }
-
- if (mergeTags(ruleDef, rule)) {
- executeUpdate = true;
- }
+ boolean executeUpdate = mergeRule(ruleDef, rule);
+ executeUpdate |= mergeDebtDefinitions(ruleDef, rule);
+ executeUpdate |= mergeTags(ruleDef, rule);
if (executeUpdate) {
update(session, rule);
}
mergeParams(ruleDef, rule, session);
+ updateDeprecatedKeys(ruleDef, rule, existingDeprecatedRuleKeys, session);
return newRule || executeUpdate;
}
@@ -200,6 +208,14 @@ public class RegisterRules implements Startable {
return rules;
}
+ private Map<Integer, Set<SingleDeprecatedRuleKey>> loadDeprecatedRuleKeys(DbSession dbSession) {
+ return dbClient.ruleDao().selectAllDeprecatedRuleKeys(dbSession)
+ .stream()
+ .map(SingleDeprecatedRuleKey::from)
+ .collect(Collectors.groupingBy(SingleDeprecatedRuleKey::getRuleId, toSet()));
+ }
+
+
private List<RulesDefinition.ExtendedRepository> getRepositories(RulesDefinition.Context context) {
List<RulesDefinition.ExtendedRepository> repositories = new ArrayList<>();
for (RulesDefinition.Repository repoDef : context.repositories()) {
@@ -256,7 +272,7 @@ public class RegisterRules implements Startable {
}
}
- private boolean mergeRule(RulesDefinition.Rule def, RuleDefinitionDto dto) {
+ private static boolean mergeRule(RulesDefinition.Rule def, RuleDefinitionDto dto) {
boolean changed = false;
if (!StringUtils.equals(dto.getName(), def.name())) {
dto.setName(def.name());
@@ -303,7 +319,7 @@ public class RegisterRules implements Startable {
return changed;
}
- private boolean mergeDescription(RulesDefinition.Rule def, RuleDefinitionDto dto) {
+ private static boolean mergeDescription(RulesDefinition.Rule def, RuleDefinitionDto dto) {
boolean changed = false;
if (def.htmlDescription() != null && !StringUtils.equals(dto.getDescription(), def.htmlDescription())) {
dto.setDescription(def.htmlDescription());
@@ -317,7 +333,7 @@ public class RegisterRules implements Startable {
return changed;
}
- private boolean mergeDebtDefinitions(RulesDefinition.Rule def, RuleDefinitionDto dto) {
+ private static boolean mergeDebtDefinitions(RulesDefinition.Rule def, RuleDefinitionDto dto) {
// Debt definitions are set to null if the sub-characteristic and the remediation function are null
DebtRemediationFunction debtRemediationFunction = def.debtRemediationFunction();
boolean hasDebt = debtRemediationFunction != null;
@@ -331,7 +347,7 @@ public class RegisterRules implements Startable {
return mergeDebtDefinitions(dto, null, null, null, null);
}
- private boolean mergeDebtDefinitions(RuleDefinitionDto dto, @Nullable String remediationFunction,
+ private static boolean mergeDebtDefinitions(RuleDefinitionDto dto, @Nullable String remediationFunction,
@Nullable String remediationCoefficient, @Nullable String remediationOffset, @Nullable String effortToFixDescription) {
boolean changed = false;
@@ -399,7 +415,7 @@ public class RegisterRules implements Startable {
}
}
- private boolean mergeParam(RuleParamDto paramDto, RulesDefinition.Param paramDef) {
+ private static boolean mergeParam(RuleParamDto paramDto, RulesDefinition.Param paramDef) {
boolean changed = false;
if (!StringUtils.equals(paramDto.getType(), paramDef.type().toString())) {
paramDto.setType(paramDef.type().toString());
@@ -420,7 +436,7 @@ public class RegisterRules implements Startable {
boolean changed = false;
if (RuleStatus.REMOVED == ruleDef.status()) {
- dto.setSystemTags(Collections.emptySet());
+ dto.setSystemTags(emptySet());
changed = true;
} else if (dto.getSystemTags().size() != ruleDef.tags().size() ||
!dto.getSystemTags().containsAll(ruleDef.tags())) {
@@ -432,6 +448,33 @@ public class RegisterRules implements Startable {
return changed;
}
+ private void updateDeprecatedKeys(RulesDefinition.Rule ruleDef, RuleDefinitionDto rule,
+ Map<Integer, Set<SingleDeprecatedRuleKey>> existingDeprecatedKeysById, DbSession dbSession) {
+
+ Set<SingleDeprecatedRuleKey> deprecatedRuleKeysFromDefinition = SingleDeprecatedRuleKey.from(ruleDef);
+ Set<SingleDeprecatedRuleKey> deprecatedRuleKeysFromDB = existingDeprecatedKeysById.getOrDefault(rule.getId(), emptySet());
+
+ // DeprecatedKeys that must be deleted
+ List<String> uuidsToBeDeleted = difference(deprecatedRuleKeysFromDB, deprecatedRuleKeysFromDefinition).stream()
+ .map(SingleDeprecatedRuleKey::getUuid)
+ .collect(MoreCollectors.toList());
+
+ dbClient.ruleDao().deleteDeprecatedRuleKeys(dbSession, uuidsToBeDeleted);
+
+ // DeprecatedKeys that must be created
+ Sets.SetView<SingleDeprecatedRuleKey> deprecatedRuleKeysToBeCreated = difference(deprecatedRuleKeysFromDefinition, deprecatedRuleKeysFromDB);
+
+ deprecatedRuleKeysToBeCreated
+ .forEach(r -> dbClient.ruleDao().insert(dbSession, new DeprecatedRuleKeyDto()
+ .setUuid(uuidFactory.create())
+ .setRuleId(rule.getId())
+ .setOldRepositoryKey(r.getOldRepositoryKey())
+ .setOldRuleKey(r.getOldRuleKey())
+ .setCreatedAt(system2.now())
+ )
+ );
+ }
+
private List<RuleDefinitionDto> processRemainingDbRules(Collection<RuleDefinitionDto> existingRules, DbSession session) {
// custom rules check status of template, so they must be processed at the end
List<RuleDefinitionDto> customRules = newArrayList();
@@ -465,7 +508,7 @@ public class RegisterRules implements Startable {
private void removeRule(DbSession session, List<RuleDefinitionDto> removedRules, RuleDefinitionDto rule) {
LOG.info(format("Disable rule %s", rule.getKey()));
rule.setStatus(RuleStatus.REMOVED);
- rule.setSystemTags(Collections.emptySet());
+ rule.setSystemTags(emptySet());
update(session, rule);
// FIXME resetting the tags for all organizations must be handled a different way
// rule.setTags(Collections.emptySet());
diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/SingleDeprecatedRuleKey.java b/server/sonar-server/src/main/java/org/sonar/server/rule/SingleDeprecatedRuleKey.java
new file mode 100644
index 00000000000..fdfc5b93c56
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/rule/SingleDeprecatedRuleKey.java
@@ -0,0 +1,150 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.server.rule;
+
+import java.util.Objects;
+import java.util.Set;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.server.rule.RulesDefinition;
+import org.sonar.core.util.stream.MoreCollectors;
+import org.sonar.db.rule.DeprecatedRuleKeyDto;
+
+@Immutable
+class SingleDeprecatedRuleKey {
+ private String oldRuleKey;
+ private String oldRepositoryKey;
+ private String newRuleKey;
+ private String newRepositoryKey;
+ private String uuid;
+ private Integer ruleId;
+
+ /**
+ * static methods {@link #from(RulesDefinition.Rule)} and {@link #from(DeprecatedRuleKeyDto)} must be used
+ */
+ private SingleDeprecatedRuleKey() {
+ // empty
+ }
+
+ public static Set<SingleDeprecatedRuleKey> from(RulesDefinition.Rule rule) {
+ return rule.deprecatedRuleKeys().stream()
+ .map(r -> new SingleDeprecatedRuleKey()
+ .setNewRepositoryKey(rule.repository().key())
+ .setNewRuleKey(rule.key())
+ .setOldRepositoryKey(r.repository())
+ .setOldRuleKey(r.rule()))
+ .collect(MoreCollectors.toSet(rule.deprecatedRuleKeys().size()));
+ }
+
+ public static SingleDeprecatedRuleKey from(DeprecatedRuleKeyDto rule) {
+ return new SingleDeprecatedRuleKey()
+ .setUuid(rule.getUuid())
+ .setRuleId(rule.getRuleId())
+ .setNewRepositoryKey(rule.getNewRepositoryKey())
+ .setNewRuleKey(rule.getNewRuleKey())
+ .setOldRepositoryKey(rule.getOldRepositoryKey())
+ .setOldRuleKey(rule.getOldRuleKey());
+ }
+
+ public String getOldRuleKey() {
+ return oldRuleKey;
+ }
+
+ public String getOldRepositoryKey() {
+ return oldRepositoryKey;
+ }
+
+ public RuleKey getOldRuleKeyAsRuleKey() {
+ return RuleKey.of(oldRepositoryKey, oldRuleKey);
+ }
+
+ @CheckForNull
+ public String getNewRuleKey() {
+ return newRuleKey;
+ }
+
+ @CheckForNull
+ public String getNewRepositoryKey() {
+ return newRepositoryKey;
+ }
+
+ @CheckForNull
+ public String getUuid() {
+ return uuid;
+ }
+
+ @CheckForNull
+ public Integer getRuleId() {
+ return ruleId;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof SingleDeprecatedRuleKey)) {
+ return false;
+ }
+ SingleDeprecatedRuleKey that = (SingleDeprecatedRuleKey) o;
+ return Objects.equals(oldRuleKey, that.oldRuleKey) &&
+ Objects.equals(oldRepositoryKey, that.oldRepositoryKey) &&
+ Objects.equals(newRuleKey, that.newRuleKey) &&
+ Objects.equals(newRepositoryKey, that.newRepositoryKey);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(oldRuleKey, oldRepositoryKey, newRuleKey, newRepositoryKey);
+ }
+
+ private SingleDeprecatedRuleKey setRuleId(Integer ruleId) {
+ this.ruleId = ruleId;
+ return this;
+ }
+
+ private SingleDeprecatedRuleKey setUuid(String uuid) {
+ this.uuid = uuid;
+ return this;
+ }
+
+ private SingleDeprecatedRuleKey setOldRuleKey(String oldRuleKey) {
+ this.oldRuleKey = oldRuleKey;
+ return this;
+ }
+
+ private SingleDeprecatedRuleKey setOldRepositoryKey(String oldRepositoryKey) {
+ this.oldRepositoryKey = oldRepositoryKey;
+ return this;
+ }
+
+ private SingleDeprecatedRuleKey setNewRuleKey(@Nullable String newRuleKey) {
+ this.newRuleKey = newRuleKey;
+ return this;
+ }
+
+ private SingleDeprecatedRuleKey setNewRepositoryKey(@Nullable String newRepositoryKey) {
+ this.newRepositoryKey = newRepositoryKey;
+ return this;
+ }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/rule/RegisterRulesTest.java b/server/sonar-server/src/test/java/org/sonar/server/rule/RegisterRulesTest.java
index 4bf6459bf56..5be05c9d9dc 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/rule/RegisterRulesTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/rule/RegisterRulesTest.java
@@ -21,6 +21,7 @@ package org.sonar.server.rule;
import java.util.Date;
import java.util.List;
+import java.util.Set;
import java.util.stream.IntStream;
import org.junit.Before;
import org.junit.Test;
@@ -37,10 +38,13 @@ import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
+import org.sonar.core.util.UuidFactory;
+import org.sonar.core.util.UuidFactoryFast;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.organization.OrganizationDto;
+import org.sonar.db.rule.DeprecatedRuleKeyDto;
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.db.rule.RuleDto;
import org.sonar.db.rule.RuleDto.Scope;
@@ -69,6 +73,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.sonar.api.rule.Severity.BLOCKER;
import static org.sonar.api.rule.Severity.INFO;
+import static org.sonar.api.server.rule.RulesDefinition.*;
public class RegisterRulesTest {
@@ -98,6 +103,7 @@ public class RegisterRulesTest {
private RuleIndex ruleIndex;
private OrganizationDto defaultOrganization;
private OrganizationFlags organizationFlags = TestOrganizationFlags.standalone();
+ private UuidFactory uuidFactory = UuidFactoryFast.getInstance();
@Before
public void before() {
@@ -150,7 +156,7 @@ public class RegisterRulesTest {
// register one rule
execute(context -> {
- RulesDefinition.NewRepository repo = context.createRepository("fake", "java");
+ NewRepository repo = context.createRepository("fake", "java");
repo.createRule(ruleKey)
.setName(randomAlphanumeric(5))
.setHtmlDescription(randomAlphanumeric(20));
@@ -192,7 +198,7 @@ public class RegisterRulesTest {
// register many rules
execute(context -> {
- RulesDefinition.NewRepository repo = context.createRepository("fake", "java");
+ NewRepository repo = context.createRepository("fake", "java");
IntStream.range(0, numberOfRules)
.mapToObj(i -> "rule-" + i)
.forEach(ruleKey -> repo.createRule(ruleKey)
@@ -298,32 +304,26 @@ public class RegisterRulesTest {
@Test
public void add_new_tag() {
- execute(new RulesDefinition() {
- @Override
- public void define(RulesDefinition.Context context) {
- RulesDefinition.NewRepository repo = context.createRepository("fake", "java");
- repo.createRule("rule1")
- .setName("Rule One")
- .setHtmlDescription("Description of Rule One")
- .setTags("tag1");
- repo.done();
- }
+ execute((RulesDefinition) context -> {
+ NewRepository repo = context.createRepository("fake", "java");
+ repo.createRule("rule1")
+ .setName("Rule One")
+ .setHtmlDescription("Description of Rule One")
+ .setTags("tag1");
+ repo.done();
});
OrganizationDto defaultOrganization = dbTester.getDefaultOrganization();
RuleDto rule = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, RULE_KEY1);
assertThat(rule.getSystemTags()).containsOnly("tag1");
- execute(new RulesDefinition() {
- @Override
- public void define(RulesDefinition.Context context) {
- RulesDefinition.NewRepository repo = context.createRepository("fake", "java");
- repo.createRule("rule1")
- .setName("Rule One")
- .setHtmlDescription("Description of Rule One")
- .setTags("tag1", "tag2");
- repo.done();
- }
+ execute((RulesDefinition) context -> {
+ NewRepository repo = context.createRepository("fake", "java");
+ repo.createRule("rule1")
+ .setName("Rule One")
+ .setHtmlDescription("Description of Rule One")
+ .setTags("tag1", "tag2");
+ repo.done();
});
rule = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, RULE_KEY1);
@@ -333,27 +333,21 @@ public class RegisterRulesTest {
@Test
public void update_only_rule_name() {
when(system.now()).thenReturn(DATE1.getTime());
- execute(new RulesDefinition() {
- @Override
- public void define(Context context) {
- NewRepository repo = context.createRepository("fake", "java");
- repo.createRule("rule")
- .setName("Name1")
- .setHtmlDescription("Description");
- repo.done();
- }
+ execute((RulesDefinition) context -> {
+ NewRepository repo = context.createRepository("fake", "java");
+ repo.createRule("rule")
+ .setName("Name1")
+ .setHtmlDescription("Description");
+ repo.done();
});
when(system.now()).thenReturn(DATE2.getTime());
- execute(new RulesDefinition() {
- @Override
- public void define(Context context) {
- NewRepository repo = context.createRepository("fake", "java");
- repo.createRule("rule")
- .setName("Name2")
- .setHtmlDescription("Description");
- repo.done();
- }
+ execute((RulesDefinition) context -> {
+ NewRepository repo = context.createRepository("fake", "java");
+ repo.createRule("rule")
+ .setName("Name2")
+ .setHtmlDescription("Description");
+ repo.done();
});
// rule1 has been updated
@@ -368,27 +362,21 @@ public class RegisterRulesTest {
@Test
public void update_only_rule_description() {
when(system.now()).thenReturn(DATE1.getTime());
- execute(new RulesDefinition() {
- @Override
- public void define(Context context) {
- NewRepository repo = context.createRepository("fake", "java");
- repo.createRule("rule")
- .setName("Name")
- .setHtmlDescription("Desc1");
- repo.done();
- }
+ execute((RulesDefinition) context -> {
+ NewRepository repo = context.createRepository("fake", "java");
+ repo.createRule("rule")
+ .setName("Name")
+ .setHtmlDescription("Desc1");
+ repo.done();
});
when(system.now()).thenReturn(DATE2.getTime());
- execute(new RulesDefinition() {
- @Override
- public void define(Context context) {
- NewRepository repo = context.createRepository("fake", "java");
- repo.createRule("rule")
- .setName("Name")
- .setHtmlDescription("Desc2");
- repo.done();
- }
+ execute((RulesDefinition) context -> {
+ NewRepository repo = context.createRepository("fake", "java");
+ repo.createRule("rule")
+ .setName("Name")
+ .setHtmlDescription("Desc2");
+ repo.done();
});
// rule1 has been updated
@@ -431,7 +419,6 @@ public class RegisterRulesTest {
when(system.now()).thenReturn(DATE2.getTime());
execute(new FakeRepositoryV1());
- String organizationUuid = dbTester.getDefaultOrganization().getUuid();
RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, RULE_KEY1);
assertThat(rule1.getCreatedAt()).isEqualTo(DATE1.getTime());
assertThat(rule1.getUpdatedAt()).isEqualTo(DATE1.getTime());
@@ -443,7 +430,6 @@ public class RegisterRulesTest {
assertThat(dbClient.ruleDao().selectAllDefinitions(dbTester.getSession())).hasSize(2);
assertThat(esTester.getIds(RuleIndexDefinition.INDEX_TYPE_RULE)).containsOnly(RULE_KEY1.toString(), RULE_KEY2.toString());
- String organizationUuid = dbTester.getDefaultOrganization().getUuid();
RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, RULE_KEY2);
assertThat(rule2.getStatus()).isEqualTo(RuleStatus.READY);
@@ -530,6 +516,94 @@ public class RegisterRulesTest {
assertThat(logTester.logs(LoggerLevel.INFO)).contains("Template rule test:rule1 will not be imported, because organizations are enabled.");
}
+ @Test
+ public void rules_that_deprecate_previous_rule_must_be_recorded() {
+ execute(context -> {
+ NewRepository repo = context.createRepository("fake", "java");
+ repo.createRule("rule1")
+ .setName("One")
+ .setHtmlDescription("Description of One")
+ .setSeverity(BLOCKER)
+ .setInternalKey("config1")
+ .setTags("tag1", "tag2", "tag3")
+ .setType(RuleType.CODE_SMELL)
+ .setStatus(RuleStatus.BETA);
+ repo.done();
+ });
+
+ execute(context -> {
+ NewRepository repo = context.createRepository("fake", "java");
+ repo.createRule("newKey")
+ .setName("One")
+ .setHtmlDescription("Description of One")
+ .setSeverity(BLOCKER)
+ .setInternalKey("config1")
+ .setTags("tag1", "tag2", "tag3")
+ .setType(RuleType.CODE_SMELL)
+ .setStatus(RuleStatus.BETA)
+ .addDeprecatedRuleKey("fake", "rule1")
+ .addDeprecatedRuleKey("fake", "rule2");
+ repo.done();
+ });
+
+ List<RuleDefinitionDto> rules = dbClient.ruleDao().selectAllDefinitions(dbTester.getSession());
+ Set<DeprecatedRuleKeyDto> deprecatedRuleKeys = dbClient.ruleDao().selectAllDeprecatedRuleKeys(dbTester.getSession());
+ //assertThat(rules).hasSize(1); FIXME this must be true when renaming is done
+ assertThat(deprecatedRuleKeys).hasSize(2);
+ }
+
+ @Test
+ public void rules_that_remove_deprecated_key_must_remove_records() {
+ execute(context -> {
+ NewRepository repo = context.createRepository("fake", "java");
+ repo.createRule("rule1")
+ .setName("One")
+ .setHtmlDescription("Description of One")
+ .setSeverity(BLOCKER)
+ .setInternalKey("config1")
+ .setTags("tag1", "tag2", "tag3")
+ .setType(RuleType.CODE_SMELL)
+ .setStatus(RuleStatus.BETA);
+ repo.done();
+ });
+
+ execute(context -> {
+ NewRepository repo = context.createRepository("fake", "java");
+ repo.createRule("newKey")
+ .setName("One")
+ .setHtmlDescription("Description of One")
+ .setSeverity(BLOCKER)
+ .setInternalKey("config1")
+ .setTags("tag1", "tag2", "tag3")
+ .setType(RuleType.CODE_SMELL)
+ .setStatus(RuleStatus.BETA)
+ .addDeprecatedRuleKey("fake", "rule1")
+ .addDeprecatedRuleKey("fake", "rule2");
+ repo.done();
+ });
+
+ //assertThat(dbClient.ruleDao().selectAllDefinitions(dbTester.getSession())).hasSize(1); FIXME this must be true when renaming is done
+ Set<DeprecatedRuleKeyDto> deprecatedRuleKeys = dbClient.ruleDao().selectAllDeprecatedRuleKeys(dbTester.getSession());
+ assertThat(deprecatedRuleKeys).hasSize(2);
+
+ execute(context -> {
+ NewRepository repo = context.createRepository("fake", "java");
+ repo.createRule("newKey")
+ .setName("One")
+ .setHtmlDescription("Description of One")
+ .setSeverity(BLOCKER)
+ .setInternalKey("config1")
+ .setTags("tag1", "tag2", "tag3")
+ .setType(RuleType.CODE_SMELL)
+ .setStatus(RuleStatus.BETA);
+ repo.done();
+ });
+
+ //assertThat(dbClient.ruleDao().selectAllDefinitions(dbTester.getSession())).hasSize(1); FIXME this must be true when renaming is done
+ deprecatedRuleKeys = dbClient.ruleDao().selectAllDeprecatedRuleKeys(dbTester.getSession());
+ assertThat(deprecatedRuleKeys).hasSize(0);
+ }
+
private void execute(RulesDefinition... defs) {
ServerPluginRepository pluginRepository = mock(ServerPluginRepository.class);
when(pluginRepository.getPluginKey(any(RulesDefinition.class))).thenReturn(FAKE_PLUGIN_KEY);
@@ -539,7 +613,8 @@ public class RegisterRulesTest {
when(languages.get("java")).thenReturn(mock(Language.class));
reset(webServerRuleFinder);
- RegisterRules task = new RegisterRules(loader, qProfileRules, dbClient, ruleIndexer, activeRuleIndexer, languages, system, organizationFlags, webServerRuleFinder);
+ RegisterRules task = new RegisterRules(loader, qProfileRules, dbClient, ruleIndexer, activeRuleIndexer,
+ languages, system, organizationFlags, webServerRuleFinder, uuidFactory);
task.start();
// Execute a commit to refresh session state as the task is using its own session
dbTester.getSession().commit();
@@ -658,7 +733,7 @@ public class RegisterRulesTest {
static class RepositoryWithOneTemplateRule implements RulesDefinition {
@Override
public void define(Context context) {
- RulesDefinition.NewRepository repo = context.createRepository("test", "java");
+ NewRepository repo = context.createRepository("test", "java");
repo.createRule("rule1")
.setName("Rule One")
.setHtmlDescription("Description of Rule One")
diff --git a/server/sonar-server/src/test/java/org/sonar/server/rule/SingleDeprecatedRuleKeyTest.java b/server/sonar-server/src/test/java/org/sonar/server/rule/SingleDeprecatedRuleKeyTest.java
new file mode 100644
index 00000000000..0311797284b
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/rule/SingleDeprecatedRuleKeyTest.java
@@ -0,0 +1,129 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.server.rule;
+
+import com.google.common.collect.ImmutableSet;
+import java.util.Set;
+import org.assertj.core.groups.Tuple;
+import org.junit.Test;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.server.rule.RulesDefinition;
+import org.sonar.core.util.stream.MoreCollectors;
+import org.sonar.db.rule.DeprecatedRuleKeyDto;
+
+import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
+import static org.apache.commons.lang.math.RandomUtils.nextInt;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.groups.Tuple.tuple;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class SingleDeprecatedRuleKeyTest {
+
+ @Test
+ public void test_creation_from_DeprecatedRuleKeyDto() {
+ // Creation from DeprecatedRuleKeyDto
+ DeprecatedRuleKeyDto deprecatedRuleKeyDto = new DeprecatedRuleKeyDto()
+ .setOldRuleKey(randomAlphanumeric(50))
+ .setOldRepositoryKey(randomAlphanumeric(50))
+ .setRuleId(nextInt(1000))
+ .setUuid(randomAlphanumeric(40));
+
+ SingleDeprecatedRuleKey singleDeprecatedRuleKey = SingleDeprecatedRuleKey.from(deprecatedRuleKeyDto);
+
+ assertThat(singleDeprecatedRuleKey.getOldRepositoryKey()).isEqualTo(deprecatedRuleKeyDto.getOldRepositoryKey());
+ assertThat(singleDeprecatedRuleKey.getOldRuleKey()).isEqualTo(deprecatedRuleKeyDto.getOldRuleKey());
+ assertThat(singleDeprecatedRuleKey.getNewRepositoryKey()).isEqualTo(deprecatedRuleKeyDto.getNewRepositoryKey());
+ assertThat(singleDeprecatedRuleKey.getNewRuleKey()).isEqualTo(deprecatedRuleKeyDto.getNewRuleKey());
+ assertThat(singleDeprecatedRuleKey.getUuid()).isEqualTo(deprecatedRuleKeyDto.getUuid());
+ assertThat(singleDeprecatedRuleKey.getRuleId()).isEqualTo(deprecatedRuleKeyDto.getRuleId());
+ assertThat(singleDeprecatedRuleKey.getOldRuleKeyAsRuleKey())
+ .isEqualTo(RuleKey.of(deprecatedRuleKeyDto.getOldRepositoryKey(), deprecatedRuleKeyDto.getOldRuleKey()));
+ }
+
+ @Test
+ public void test_creation_from_RulesDefinitionRule() {
+ // Creation from RulesDefinition.Rule
+ ImmutableSet<RuleKey> deprecatedRuleKeys = ImmutableSet.of(
+ RuleKey.of(randomAlphanumeric(50), randomAlphanumeric(50)),
+ RuleKey.of(randomAlphanumeric(50), randomAlphanumeric(50)),
+ RuleKey.of(randomAlphanumeric(50), randomAlphanumeric(50))
+ );
+
+ RulesDefinition.Repository repository = mock(RulesDefinition.Repository.class);
+ when(repository.key()).thenReturn(randomAlphanumeric(50));
+
+ RulesDefinition.Rule rule = mock(RulesDefinition.Rule.class);
+ when(rule.key()).thenReturn(randomAlphanumeric(50));
+ when(rule.deprecatedRuleKeys()).thenReturn(deprecatedRuleKeys);
+ when(rule.repository()).thenReturn(repository);
+
+ Set<SingleDeprecatedRuleKey> singleDeprecatedRuleKeys = SingleDeprecatedRuleKey.from(rule);
+ assertThat(singleDeprecatedRuleKeys).hasSize(deprecatedRuleKeys.size());
+ assertThat(singleDeprecatedRuleKeys)
+ .extracting(SingleDeprecatedRuleKey::getUuid, SingleDeprecatedRuleKey::getOldRepositoryKey, SingleDeprecatedRuleKey::getOldRuleKey,
+ SingleDeprecatedRuleKey::getNewRepositoryKey, SingleDeprecatedRuleKey::getNewRuleKey, SingleDeprecatedRuleKey::getOldRuleKeyAsRuleKey)
+ .containsExactlyInAnyOrder(
+ deprecatedRuleKeys.stream().map(
+ r -> tuple(null, r.repository(), r.rule(), rule.repository().key(), rule.key(), RuleKey.of(r.repository(), r.rule()))
+ ).collect(MoreCollectors.toArrayList(deprecatedRuleKeys.size())).toArray(new Tuple[deprecatedRuleKeys.size()])
+ );
+ }
+
+ @Test
+ public void test_equality() {
+ DeprecatedRuleKeyDto deprecatedRuleKeyDto1 = new DeprecatedRuleKeyDto()
+ .setOldRuleKey(randomAlphanumeric(50))
+ .setOldRepositoryKey(randomAlphanumeric(50))
+ .setUuid(randomAlphanumeric(40))
+ .setRuleId(1);
+
+ DeprecatedRuleKeyDto deprecatedRuleKeyDto1WithoutUuid = new DeprecatedRuleKeyDto()
+ .setOldRuleKey(deprecatedRuleKeyDto1.getOldRuleKey())
+ .setOldRepositoryKey(deprecatedRuleKeyDto1.getOldRepositoryKey());
+
+ DeprecatedRuleKeyDto deprecatedRuleKeyDto2 = new DeprecatedRuleKeyDto()
+ .setOldRuleKey(randomAlphanumeric(50))
+ .setOldRepositoryKey(randomAlphanumeric(50))
+ .setUuid(randomAlphanumeric(40));
+
+ SingleDeprecatedRuleKey singleDeprecatedRuleKey1 = SingleDeprecatedRuleKey.from(deprecatedRuleKeyDto1);
+ SingleDeprecatedRuleKey singleDeprecatedRuleKey2 = SingleDeprecatedRuleKey.from(deprecatedRuleKeyDto2);
+
+ assertThat(singleDeprecatedRuleKey1).isEqualTo(singleDeprecatedRuleKey1);
+ assertThat(singleDeprecatedRuleKey1).isEqualTo(SingleDeprecatedRuleKey.from(deprecatedRuleKeyDto1));
+ assertThat(singleDeprecatedRuleKey1).isEqualTo(SingleDeprecatedRuleKey.from(deprecatedRuleKeyDto1WithoutUuid));
+ assertThat(singleDeprecatedRuleKey2).isEqualTo(SingleDeprecatedRuleKey.from(deprecatedRuleKeyDto2));
+
+ assertThat(singleDeprecatedRuleKey1.hashCode()).isEqualTo(singleDeprecatedRuleKey1.hashCode());
+ assertThat(singleDeprecatedRuleKey1.hashCode()).isEqualTo(SingleDeprecatedRuleKey.from(deprecatedRuleKeyDto1).hashCode());
+ assertThat(singleDeprecatedRuleKey1.hashCode()).isEqualTo(SingleDeprecatedRuleKey.from(deprecatedRuleKeyDto1WithoutUuid).hashCode());
+ assertThat(singleDeprecatedRuleKey2.hashCode()).isEqualTo(SingleDeprecatedRuleKey.from(deprecatedRuleKeyDto2).hashCode());
+
+ assertThat(singleDeprecatedRuleKey1).isNotEqualTo(null);
+ assertThat(singleDeprecatedRuleKey1).isNotEqualTo("");
+ assertThat(singleDeprecatedRuleKey1).isNotEqualTo(singleDeprecatedRuleKey2);
+ assertThat(singleDeprecatedRuleKey2).isNotEqualTo(singleDeprecatedRuleKey1);
+
+ assertThat(singleDeprecatedRuleKey1.hashCode()).isNotEqualTo(singleDeprecatedRuleKey2.hashCode());
+ assertThat(singleDeprecatedRuleKey2.hashCode()).isNotEqualTo(singleDeprecatedRuleKey1.hashCode());
+ }
+}