diff options
author | Belen Pruvost <belen.pruvost@sonarsource.com> | 2021-06-29 15:18:15 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2021-06-30 20:03:13 +0000 |
commit | 2b1e236fa390e079bb4277b93b2dc9be25a77c5b (patch) | |
tree | c8d1d423b0ab5675941a410046ed6ca52e2d1cf4 | |
parent | 13737457f2588e71737ddbd5a5b3cb65e3dabb4c (diff) | |
download | sonarqube-2b1e236fa390e079bb4277b93b2dc9be25a77c5b.tar.gz sonarqube-2b1e236fa390e079bb4277b93b2dc9be25a77c5b.zip |
SONAR-14605 - Make rule name consistent
10 files changed, 156 insertions, 5 deletions
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 10a40db90cb..59fab5899b4 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 @@ -60,6 +60,13 @@ public class RuleDao implements Dao { return ofNullable(mapper(session).selectMetadataByKey(key)); } + public List<RuleMetadataDto> selectMetadataByKeys(DbSession session, Collection<RuleKey> keys) { + if (keys.isEmpty()) { + return emptyList(); + } + return executeLargeInputs(keys, mapper(session)::selectMetadataByKeys); + } + public RuleDto selectOrFailByKey(DbSession session, RuleKey key) { RuleDto rule = mapper(session).selectByKey(key); if (rule == null) { 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 d4d61573244..a49cf2e22a5 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 @@ -49,6 +49,8 @@ public interface RuleMapper { RuleMetadataDto selectMetadataByKey(@Param("ruleKey") RuleKey ruleKey); + List<RuleMetadataDto> selectMetadataByKeys(@Param("ruleKeys") List<RuleKey> keys); + List<RuleDto> selectByKeys(@Param("ruleKeys") List<RuleKey> keys); List<RuleDefinitionDto> selectDefinitionByKeys(@Param("ruleKeys") List<RuleKey> keys); 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 fb4c67409a8..ca8ee02db2e 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 @@ -205,6 +205,32 @@ and r.plugin_rule_key=#{ruleKey.rule,jdbcType=VARCHAR} </select> + <select id="selectMetadataByKeys" parameterType="map" resultType="org.sonar.db.rule.RuleMetadataDto"> + select + rm.rule_uuid as "ruleUuid", + rm.note_data as "noteData", + rm.note_user_uuid as "noteUserUuid", + rm.note_created_at as "noteCreatedAt", + rm.note_updated_at as "noteUpdatedAt", + rm.remediation_function as "remediationFunction", + rm.remediation_gap_mult as "remediationGapMultiplier", + rm.remediation_base_effort as "remediationBaseEffort", + rm.tags as "tagsField", + rm.ad_hoc_name as "adHocName", + rm.ad_hoc_description as "adHocDescription", + rm.ad_hoc_severity as "adHocSeverity", + rm.ad_hoc_type as "adHocType", + rm.created_at as "createdAt", + rm.updated_at as "updatedAt" + from + rules_metadata rm + inner join rules r on rm.rule_uuid = r.uuid + where + <foreach collection="ruleKeys" index="index" item="ruleKey" open="" separator=" or " close=""> + (r.plugin_name=#{ruleKey.repository,jdbcType=VARCHAR} and r.plugin_rule_key=#{ruleKey.rule,jdbcType=VARCHAR}) + </foreach> + </select> + <select id="selectByKeys" parameterType="map" resultType="Rule"> select <include refid="selectJoinedTablesColumns"/> 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 5180c858067..13db09b0f52 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 @@ -106,6 +106,20 @@ public class RuleDaoTest { } @Test + public void selectMetadataByKeys() { + RuleDefinitionDto rule1 = db.rules().insert(); + db.rules().insertOrUpdateMetadata(rule1); + + assertThat(underTest.selectMetadataByKeys(db.getSession(), Collections.emptyList())).isEmpty(); + assertThat(underTest.selectMetadataByKeys(db.getSession(), singletonList(RuleKey.of("NOT", "FOUND")))).isEmpty(); + + List<RuleMetadataDto> rulesMetadata = underTest.selectMetadataByKeys(db.getSession(), asList(rule1.getKey(), + RuleKey.of("java", "OTHER"))); + assertThat(rulesMetadata).hasSize(1); + assertThat(rulesMetadata.get(0).getRuleUuid()).isEqualTo(rule1.getUuid()); + } + + @Test public void selectByUuid() { RuleDefinitionDto ruleDefinition = db.rules().insert(); RuleMetadataDto metadata = newRuleMetadata(ruleDefinition); diff --git a/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndex.java b/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndex.java index 36d0663fdfa..295c252659b 100644 --- a/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndex.java +++ b/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndex.java @@ -71,7 +71,6 @@ import org.sonar.api.rules.RuleType; import org.sonar.api.utils.DateUtils; import org.sonar.api.utils.System2; import org.sonar.core.util.stream.MoreCollectors; -import org.sonar.db.rule.RuleDefinitionDto; import org.sonar.server.es.BaseDoc; import org.sonar.server.es.EsClient; import org.sonar.server.es.EsUtils; diff --git a/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueQueryFactory.java b/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueQueryFactory.java index c238c58a6b5..60694e9231a 100644 --- a/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueQueryFactory.java +++ b/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueQueryFactory.java @@ -40,7 +40,6 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; -import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.apache.commons.lang.BooleanUtils; import org.sonar.api.resources.Qualifiers; @@ -54,6 +53,7 @@ import org.sonar.db.DbSession; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.SnapshotDto; import org.sonar.db.rule.RuleDefinitionDto; +import org.sonar.db.rule.RuleMetadataDto; import org.sonar.server.issue.SearchRequest; import org.sonar.server.issue.index.IssueQuery.PeriodStart; import org.sonar.server.user.UserSession; @@ -111,8 +111,11 @@ public class IssueQueryFactory { final ZoneId timeZone = parseTimeZone(request.getTimeZone()).orElse(clock.getZone()); Collection<RuleDefinitionDto> ruleDefinitionDtos = ruleKeysToRuleId(dbSession, request.getRules()); + Collection<RuleMetadataDto> ruleMetadataDtos = ruleKeysToRuleMetadata(dbSession, request.getRules()); Collection<String> ruleUuids = ruleDefinitionDtos.stream().map(RuleDefinitionDto::getUuid).collect(Collectors.toSet()); + ruleDefinitionDtos.stream().forEach(rule -> getRuleName(ruleMetadataDtos, rule)); + if (request.getRules() != null && request.getRules().stream().collect(toSet()).size() != ruleDefinitionDtos.size()) { ruleUuids.add("non-existing-uuid"); } @@ -383,6 +386,13 @@ public class IssueQueryFactory { return Collections.emptyList(); } + private Collection<RuleMetadataDto> ruleKeysToRuleMetadata(DbSession dbSession, @Nullable Collection<String> rules) { + if (rules != null) { + return dbClient.ruleDao().selectMetadataByKeys(dbSession, transform(rules, RuleKey::parse)); + } + return Collections.emptyList(); + } + private static String toProjectUuid(ComponentDto componentDto) { String mainBranchProjectUuid = componentDto.getMainBranchProjectUuid(); return mainBranchProjectUuid == null ? componentDto.projectUuid() : mainBranchProjectUuid; @@ -395,4 +405,14 @@ public class IssueQueryFactory { || (branch != null && !branch.equals(component.getBranch())) || (pullRequest != null && !pullRequest.equals(component.getPullRequest()))); } + + private static void getRuleName(Collection<RuleMetadataDto> ruleMetadataDtos, RuleDefinitionDto rule) { + if (rule.isAdHoc()) { + String name = ruleMetadataDtos.stream() + .filter(m -> m.getRuleUuid().equals(rule.getUuid())).findFirst() + .map(RuleMetadataDto::getAdHocName) + .orElse(null); + rule.setName(name); + } + } } diff --git a/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueQueryFactoryTest.java b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueQueryFactoryTest.java index d2057956dd8..3d5fba1a828 100644 --- a/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueQueryFactoryTest.java +++ b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueQueryFactoryTest.java @@ -26,6 +26,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.Map; +import java.util.Optional; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -73,13 +74,16 @@ public class IssueQueryFactoryTest { @Test public void create_from_parameters() { + String ruleAdHocName = "New Name"; UserDto user = db.users().insertUser(u -> u.setLogin("joanna")); ComponentDto project = db.components().insertPrivateProject(); ComponentDto module = db.components().insertComponent(newModuleDto(project)); ComponentDto file = db.components().insertComponent(newFileDto(project)); - RuleDefinitionDto rule1 = ruleDbTester.insert(); + RuleDefinitionDto rule1 = ruleDbTester.insert(r -> r.setIsAdHoc(true)); RuleDefinitionDto rule2 = ruleDbTester.insert(); + ruleDbTester.insertOrUpdateMetadata(rule1, m -> m.setAdHocName(ruleAdHocName)); + ruleDbTester.insertOrUpdateMetadata(rule2, m -> m.setAdHocName(ruleAdHocName)); newRule(RuleKey.of("findbugs", "NullReference")); SearchRequest request = new SearchRequest() .setIssues(asList("anIssueKey")) @@ -126,6 +130,19 @@ public class IssueQueryFactoryTest { assertThat(query.createdBefore()).isEqualTo(parseDateTime("2013-04-17T09:08:24+0200")); assertThat(query.sort()).isEqualTo(IssueQuery.SORT_BY_CREATION_DATE); assertThat(query.asc()).isTrue(); + + Optional<RuleDefinitionDto> ruleWithMetadata = query.rules().stream() + .filter(r -> r.getUuid().equals(rule1.getUuid())).findFirst(); + assertThat(ruleWithMetadata).isPresent(); + assertThat(ruleWithMetadata.get().getName()).isEqualTo(ruleAdHocName); + assertThat(ruleWithMetadata.get().getName()).isNotEqualTo(rule1.getName()); + + Optional<RuleDefinitionDto> ruleWithMetadata2 = query.rules().stream() + .filter(r -> r.getUuid().equals(rule2.getUuid())).findFirst(); + assertThat(ruleWithMetadata2).isPresent(); + assertThat(ruleWithMetadata2.get().getName()).isNotEqualTo(ruleAdHocName); + assertThat(ruleWithMetadata2.get().getName()).isEqualTo(rule2.getName()); + } @Test diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java index b200d469384..8ed2457a9f6 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java @@ -176,7 +176,13 @@ public class SearchResponseFormat { issueBuilder.setSubProject(subProject.getKey()); } } - issueBuilder.setRule(dto.getRuleKey().toString()); + + String ruleName = data.getRules().stream() + .filter(r -> r.isAdHoc() && r.getName() != null && r.getUuid().equals(dto.getRuleUuid())) + .findFirst() + .map(RuleDefinitionDto::getName) + .orElse(dto.getRuleKey().toString()); + issueBuilder.setRule(ruleName); if (dto.isExternal()) { issueBuilder.setExternalRuleEngine(engineNameFrom(dto.getRuleKey())); } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchResponseLoader.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchResponseLoader.java index f29b1befbbf..cddd95bc4c3 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchResponseLoader.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchResponseLoader.java @@ -31,6 +31,7 @@ import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; import javax.annotation.Nullable; +import org.sonar.api.rule.RuleKey; import org.sonar.api.rules.RuleType; import org.sonar.core.issue.DefaultIssue; import org.sonar.core.util.stream.MoreCollectors; @@ -41,6 +42,7 @@ import org.sonar.db.issue.IssueChangeDto; import org.sonar.db.issue.IssueDto; import org.sonar.db.protobuf.DbIssues; import org.sonar.db.rule.RuleDefinitionDto; +import org.sonar.db.rule.RuleMetadataDto; import org.sonar.db.user.UserDto; import org.sonar.server.es.Facets; import org.sonar.server.issue.TransitionService; @@ -167,7 +169,11 @@ public class SearchResponseLoader { result.addRules(preloadedRules); Set<String> ruleUuidsToLoad = collector.getRuleUuids(); ruleUuidsToLoad.removeAll(preloadedRules.stream().map(RuleDefinitionDto::getUuid).collect(toList(preloadedRules.size()))); - result.addRules(dbClient.ruleDao().selectDefinitionByUuids(dbSession, ruleUuidsToLoad)); + List<RuleDefinitionDto> rules = dbClient.ruleDao().selectDefinitionByUuids(dbSession, ruleUuidsToLoad); + + getRulesMetadata(dbSession, rules); + + result.addRules(rules); } private void loadComments(Collector collector, DbSession dbSession, Set<SearchAdditionalField> fields, SearchResponseData result) { @@ -341,4 +347,22 @@ public class SearchResponseLoader { return map.get(issueKey); } } + + private void getRulesMetadata(DbSession dbSession, List<RuleDefinitionDto> rules) { + List<RuleKey> adHocRuleKeys = rules.stream().filter(RuleDefinitionDto::isAdHoc) + .map(r -> RuleKey.of(r.getRepositoryKey(), r.getRuleKey())) + .collect(toList()); + + List<RuleMetadataDto> adHocRulesMetadata = dbClient.ruleDao().selectMetadataByKeys(dbSession, adHocRuleKeys); + + rules.stream().forEach(r -> { + if (r.isAdHoc()) { + String adHocName = adHocRulesMetadata.stream() + .filter(m -> m.getRuleUuid().equals(r.getUuid())).findFirst(). + map(RuleMetadataDto::getAdHocName) + .orElse(null); + r.setName(adHocName); + } + }); + } } diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java index d4f10af4b72..7b7e33030b3 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java @@ -56,6 +56,7 @@ import org.sonar.db.protobuf.DbCommons; import org.sonar.db.protobuf.DbIssues; import org.sonar.db.rule.RuleDefinitionDto; import org.sonar.db.rule.RuleDto; +import org.sonar.db.rule.RuleMetadataDto; import org.sonar.db.rule.RuleTesting; import org.sonar.db.user.UserDto; import org.sonar.server.es.EsTester; @@ -203,6 +204,41 @@ public class SearchActionTest { } @Test + public void issue_on_external_adhoc_rule_without_metadata() { + ComponentDto project = db.components().insertPublicProject(); + indexPermissions(); + ComponentDto file = db.components().insertComponent(newFileDto(project)); + RuleDefinitionDto rule = db.rules().insertIssueRule(RuleTesting.EXTERNAL_XOO, r -> r.setIsExternal(true).setLanguage("xoo").setIsAdHoc(true)); + IssueDto issue = db.issues().insertIssue(rule, project, file); + indexIssues(); + + SearchWsResponse response = ws.newRequest() + .executeProtobuf(SearchWsResponse.class); + + assertThat(response.getIssuesList()) + .extracting(Issue::getKey, Issue::getRule, Issue::getExternalRuleEngine) + .containsExactlyInAnyOrder(tuple(issue.getKey(), rule.getKey().toString(), "xoo")); + } + + @Test + public void issue_on_external_adhoc_rule_with_metadata() { + ComponentDto project = db.components().insertPublicProject(); + indexPermissions(); + ComponentDto file = db.components().insertComponent(newFileDto(project)); + RuleDefinitionDto rule = db.rules().insertIssueRule(RuleTesting.EXTERNAL_XOO, r -> r.setIsExternal(true).setLanguage("xoo").setIsAdHoc(true)); + RuleMetadataDto ruleMetadata = db.rules().insertOrUpdateMetadata(rule, m -> m.setAdHocName("different_rule_name")); + IssueDto issue = db.issues().insertIssue(rule, project, file); + indexIssues(); + + SearchWsResponse response = ws.newRequest() + .executeProtobuf(SearchWsResponse.class); + + assertThat(response.getIssuesList()) + .extracting(Issue::getKey, Issue::getRule, Issue::getExternalRuleEngine) + .containsExactlyInAnyOrder(tuple(issue.getKey(), ruleMetadata.getAdHocName(), "xoo")); + } + + @Test public void issue_with_cross_file_locations() { ComponentDto project = db.components().insertPublicProject(); indexPermissions(); |