diff options
author | Aurelien Poscia <aurelien.poscia@sonarsource.com> | 2022-07-06 10:39:01 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2022-07-08 20:02:48 +0000 |
commit | 26fde2bdeb8ca2d5b9b76ce1ebc11706c9471cd0 (patch) | |
tree | dfe460821b29459e88197b40d5b251eb7927faa6 /server/sonar-ce-task-projectanalysis | |
parent | 685a8905315ce2fb830c91684ea3c9a3b3ad06a8 (diff) | |
download | sonarqube-26fde2bdeb8ca2d5b9b76ce1ebc11706c9471cd0.tar.gz sonarqube-26fde2bdeb8ca2d5b9b76ce1ebc11706c9471cd0.zip |
SONAR-16614 Read ruleDescriptionContextKey from scanner reports and persist to DB
Diffstat (limited to 'server/sonar-ce-task-projectanalysis')
7 files changed, 181 insertions, 4 deletions
diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/IssueLifecycle.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/IssueLifecycle.java index 373f1dc51fe..b488efe2ffb 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/IssueLifecycle.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/IssueLifecycle.java @@ -194,6 +194,7 @@ public class IssueLifecycle { // fields coming from raw updater.setPastLine(raw, base.getLine()); updater.setPastLocations(raw, base.getLocations()); + updater.setRuleDescriptionContextKey(raw, base.getRuleDescriptionContextKey().orElse(null)); updater.setPastMessage(raw, base.getMessage(), changeContext); updater.setPastGap(raw, base.gap(), changeContext); updater.setPastEffort(raw, base.effort(), changeContext); diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/TrackerRawInputFactory.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/TrackerRawInputFactory.java index d77b4e64bb1..577c15076a2 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/TrackerRawInputFactory.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/TrackerRawInputFactory.java @@ -209,6 +209,7 @@ public class TrackerRawInputFactory { issue.setIsFromExternalRuleEngine(false); issue.setLocations(dbLocationsBuilder.build()); issue.setQuickFixAvailable(reportIssue.getQuickFixAvailable()); + issue.setRuleDescriptionContextKey(reportIssue.hasRuleDescriptionContextKey() ? reportIssue.getRuleDescriptionContextKey() : null); return issue; } diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/util/cache/ProtobufIssueDiskCache.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/util/cache/ProtobufIssueDiskCache.java index 75f8ecc3a84..d7cc18c9076 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/util/cache/ProtobufIssueDiskCache.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/util/cache/ProtobufIssueDiskCache.java @@ -19,6 +19,7 @@ */ package org.sonar.ce.task.projectanalysis.util.cache; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Splitter; import com.google.common.collect.ImmutableSet; import java.io.BufferedOutputStream; @@ -73,7 +74,7 @@ public class ProtobufIssueDiskCache implements DiskCache<DefaultIssue> { @Override public CloseableIterator<DefaultIssue> traverse() { CloseableIterator<IssueCache.Issue> protoIterator = Protobuf.readStream(file, IssueCache.Issue.parser()); - return new CloseableIterator<DefaultIssue>() { + return new CloseableIterator<>() { @CheckForNull @Override protected DefaultIssue doNext() { @@ -90,7 +91,8 @@ public class ProtobufIssueDiskCache implements DiskCache<DefaultIssue> { }; } - private static DefaultIssue toDefaultIssue(IssueCache.Issue next) { + @VisibleForTesting + static DefaultIssue toDefaultIssue(IssueCache.Issue next) { DefaultIssue defaultIssue = new DefaultIssue(); defaultIssue.setKey(next.getKey()); defaultIssue.setType(RuleType.valueOf(next.getRuleType())); @@ -114,6 +116,7 @@ public class ProtobufIssueDiskCache implements DiskCache<DefaultIssue> { defaultIssue.setAuthorLogin(next.hasAuthorLogin() ? next.getAuthorLogin() : null); next.getCommentsList().forEach(c -> defaultIssue.addComment(toDefaultIssueComment(c))); defaultIssue.setTags(ImmutableSet.copyOf(TAGS_SPLITTER.split(next.getTags()))); + defaultIssue.setRuleDescriptionContextKey(next.hasRuleDescriptionContextKey() ? next.getRuleDescriptionContextKey() : null); defaultIssue.setLocations(next.hasLocations() ? next.getLocations() : null); defaultIssue.setIsFromExternalRuleEngine(next.getIsFromExternalRuleEngine()); defaultIssue.setCreationDate(new Date(next.getCreationDate())); @@ -139,7 +142,8 @@ public class ProtobufIssueDiskCache implements DiskCache<DefaultIssue> { return defaultIssue; } - private static IssueCache.Issue toProto(IssueCache.Issue.Builder builder, DefaultIssue defaultIssue) { + @VisibleForTesting + static IssueCache.Issue toProto(IssueCache.Issue.Builder builder, DefaultIssue defaultIssue) { builder.clear(); builder.setKey(defaultIssue.key()); builder.setRuleType(defaultIssue.type().getDbConstant()); @@ -164,6 +168,7 @@ public class ProtobufIssueDiskCache implements DiskCache<DefaultIssue> { defaultIssue.defaultIssueComments().forEach(c -> builder.addComments(toProtoComment(c))); ofNullable(defaultIssue.tags()).ifPresent(t -> builder.setTags(String.join(TAGS_SEPARATOR, t))); ofNullable(defaultIssue.getLocations()).ifPresent(l -> builder.setLocations((DbIssues.Locations) l)); + defaultIssue.getRuleDescriptionContextKey().ifPresent(builder::setRuleDescriptionContextKey); builder.setIsFromExternalRuleEngine(defaultIssue.isFromExternalRuleEngine()); builder.setCreationDate(defaultIssue.creationDate().getTime()); ofNullable(defaultIssue.updateDate()).map(Date::getTime).ifPresent(builder::setUpdateDate); diff --git a/server/sonar-ce-task-projectanalysis/src/main/protobuf/issue_cache.proto b/server/sonar-ce-task-projectanalysis/src/main/protobuf/issue_cache.proto index dd913b0ea50..f4135f33a39 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/protobuf/issue_cache.proto +++ b/server/sonar-ce-task-projectanalysis/src/main/protobuf/issue_cache.proto @@ -79,6 +79,7 @@ message Issue { optional bool isOnChangedLine = 41; optional bool isNewCodeReferenceIssue = 42; optional bool isNoLongerNewCodeReferenceIssue = 43; + optional string ruleDescriptionContextKey = 44; } message Comment { diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/IssueLifecycleTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/IssueLifecycleTest.java index c1f1e06bfff..e5dc9f067b8 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/IssueLifecycleTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/IssueLifecycleTest.java @@ -59,6 +59,7 @@ import static org.sonar.db.rule.RuleTesting.XOO_X1; public class IssueLifecycleTest { private static final Date DEFAULT_DATE = new Date(); private static final Duration DEFAULT_DURATION = Duration.create(10); + private static final String TEST_CONTEXT_KEY = "test_context_key"; private final DumbRule rule = new DumbRule(XOO_X1); @@ -244,7 +245,8 @@ public class IssueLifecycleTest { .setKey("RAW_KEY") .setCreationDate(parseDate("2015-10-01")) .setUpdateDate(parseDate("2015-10-02")) - .setCloseDate(parseDate("2015-10-03")); + .setCloseDate(parseDate("2015-10-03")) + .setRuleDescriptionContextKey(TEST_CONTEXT_KEY); DbIssues.Locations issueLocations = DbIssues.Locations.newBuilder() .setTextRange(DbCommons.TextRange.newBuilder() @@ -297,6 +299,7 @@ public class IssueLifecycleTest { assertThat(raw.selectedAt()).isEqualTo(1000L); assertThat(raw.changes().get(0).get(IssueFieldsSetter.FROM_BRANCH).oldValue()).isEqualTo("master"); assertThat(raw.changes().get(0).get(IssueFieldsSetter.FROM_BRANCH).newValue()).isEqualTo("release-2.x"); + assertThat(raw.getRuleDescriptionContextKey()).contains(TEST_CONTEXT_KEY); verifyNoInteractions(updater); } @@ -316,6 +319,7 @@ public class IssueLifecycleTest { .setNew(true) .setKey("RAW_KEY") .setRuleKey(XOO_X1) + .setRuleDescriptionContextKey("spring") .setCreationDate(parseDate("2015-10-01")) .setUpdateDate(parseDate("2015-10-02")) .setCloseDate(parseDate("2015-10-03")); @@ -341,6 +345,7 @@ public class IssueLifecycleTest { .setLine(10) .setMessage("message") .setGap(15d) + .setRuleDescriptionContextKey("hibernate") .setEffort(Duration.create(15L)) .setManualSeverity(false) .setLocations(issueLocations) @@ -372,6 +377,7 @@ public class IssueLifecycleTest { verify(updater).setPastSeverity(raw, BLOCKER, issueChangeContext); verify(updater).setPastLine(raw, 10); + verify(updater).setRuleDescriptionContextKey(raw, "hibernate"); verify(updater).setPastMessage(raw, "message", issueChangeContext); verify(updater).setPastEffort(raw, Duration.create(15L), issueChangeContext); verify(updater).setPastLocations(raw, issueLocations); @@ -414,4 +420,44 @@ public class IssueLifecycleTest { assertThat(raw.isChanged()).isTrue(); } + + @Test + public void mergeExistingOpenIssue_with_rule_description_context_key_added() { + DefaultIssue raw = new DefaultIssue() + .setNew(true) + .setKey("RAW_KEY") + .setRuleKey(XOO_X1) + .setRuleDescriptionContextKey(TEST_CONTEXT_KEY); + DefaultIssue base = new DefaultIssue() + .setChanged(true) + .setKey("RAW_KEY") + .setResolution(RESOLUTION_FALSE_POSITIVE) + .setStatus(STATUS_RESOLVED) + .setRuleDescriptionContextKey(null); + + underTest.mergeExistingOpenIssue(raw, base); + + assertThat(raw.isChanged()).isTrue(); + assertThat(raw.getRuleDescriptionContextKey()).isEqualTo(raw.getRuleDescriptionContextKey()); + } + + @Test + public void mergeExistingOpenIssue_with_rule_description_context_key_removed() { + DefaultIssue raw = new DefaultIssue() + .setNew(true) + .setKey("RAW_KEY") + .setRuleKey(XOO_X1) + .setRuleDescriptionContextKey(null); + DefaultIssue base = new DefaultIssue() + .setChanged(true) + .setKey("RAW_KEY") + .setResolution(RESOLUTION_FALSE_POSITIVE) + .setStatus(STATUS_RESOLVED) + .setRuleDescriptionContextKey(TEST_CONTEXT_KEY); + + underTest.mergeExistingOpenIssue(raw, base); + + assertThat(raw.isChanged()).isTrue(); + assertThat(raw.getRuleDescriptionContextKey()).isEmpty(); + } } diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/TrackerRawInputFactoryTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/TrackerRawInputFactoryTest.java index f823bebd098..1392fd64f86 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/TrackerRawInputFactoryTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/TrackerRawInputFactoryTest.java @@ -27,6 +27,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; +import java.util.Optional; import java.util.stream.IntStream; import org.apache.commons.codec.digest.DigestUtils; import org.junit.Before; @@ -79,6 +80,7 @@ public class TrackerRawInputFactoryTest { private static final int FILE_REF = 2; private static final int NOT_IN_REPORT_FILE_REF = 3; private static final int ANOTHER_FILE_REF = 4; + private static final String TEST_CONTEXT_KEY = "test_context_key"; @Rule public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule().setRoot(PROJECT); @@ -165,11 +167,36 @@ public class TrackerRawInputFactoryTest { assertThat(issue.tags()).isEmpty(); assertInitializedIssue(issue); assertThat(issue.effort()).isNull(); + assertThat(issue.getRuleDescriptionContextKey()).isEmpty(); assertLocationHashIsMadeOf(input, "intexample=line+of+code+2;"); } @Test + public void load_issues_from_report_with_rule_description_context_key() { + RuleKey ruleKey = RuleKey.of("java", "S001"); + markRuleAsActive(ruleKey); + when(issueFilter.accept(any(), eq(FILE))).thenReturn(true); + + when(sourceLinesHash.getLineHashesMatchingDBVersion(FILE)).thenReturn(Collections.singletonList("line")); + ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder() + .setTextRange(newTextRange(2)) + .setMsg("the message") + .setRuleRepository(ruleKey.repository()) + .setRuleKey(ruleKey.rule()) + .setRuleDescriptionContextKey(TEST_CONTEXT_KEY) + .build(); + reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue)); + Input<DefaultIssue> input = underTest.create(FILE); + + Collection<DefaultIssue> issues = input.getIssues(); + assertThat(issues) + .hasSize(1) + .extracting(DefaultIssue::getRuleDescriptionContextKey) + .containsOnly(Optional.of(TEST_CONTEXT_KEY)); + } + + @Test public void calculateLocationHash_givenIssueOn3Lines_calculateHashOn3Lines() { RuleKey ruleKey = RuleKey.of("java", "S001"); markRuleAsActive(ruleKey); diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/util/cache/ProtobufIssueDiskCacheTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/util/cache/ProtobufIssueDiskCacheTest.java new file mode 100644 index 00000000000..e04a954d580 --- /dev/null +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/util/cache/ProtobufIssueDiskCacheTest.java @@ -0,0 +1,96 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 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.ce.task.projectanalysis.util.cache; + +import java.util.Date; +import org.junit.Test; +import org.sonar.api.rule.RuleKey; +import org.sonar.api.rules.RuleType; +import org.sonar.core.issue.DefaultIssue; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ProtobufIssueDiskCacheTest { + + private static final String TEST_CONTEXT_KEY = "test_context_key"; + + @Test + public void toDefaultIssue_whenRuleDescriptionContextKeyPresent_shouldSetItInDefaultIssue() { + IssueCache.Issue issue = prepareIssueWithCompulsoryFields() + .setRuleDescriptionContextKey(TEST_CONTEXT_KEY) + .build(); + + DefaultIssue defaultIssue = ProtobufIssueDiskCache.toDefaultIssue(issue); + + assertThat(defaultIssue.getRuleDescriptionContextKey()).contains(TEST_CONTEXT_KEY); + } + + @Test + public void toDefaultIssue_whenRuleDescriptionContextKeyAbsent_shouldNotSetItInDefaultIssue() { + IssueCache.Issue issue = prepareIssueWithCompulsoryFields() + .build(); + + DefaultIssue defaultIssue = ProtobufIssueDiskCache.toDefaultIssue(issue); + + assertThat(defaultIssue.getRuleDescriptionContextKey()).isEmpty(); + } + + @Test + public void toProto_whenRuleDescriptionContextKeySet_shouldCopyToIssueProto() { + DefaultIssue defaultIssue = createDefaultIssueWithMandatoryFields(); + defaultIssue.setRuleDescriptionContextKey(TEST_CONTEXT_KEY); + + IssueCache.Issue issue = ProtobufIssueDiskCache.toProto(IssueCache.Issue.newBuilder(), defaultIssue); + + assertThat(issue.hasRuleDescriptionContextKey()).isTrue(); + assertThat(issue.getRuleDescriptionContextKey()).isEqualTo(TEST_CONTEXT_KEY); + } + + @Test + public void toProto_whenRuleDescriptionContextKeyNotSet_shouldCopyToIssueProto() { + DefaultIssue defaultIssue = createDefaultIssueWithMandatoryFields(); + defaultIssue.setRuleDescriptionContextKey(null); + + IssueCache.Issue issue = ProtobufIssueDiskCache.toProto(IssueCache.Issue.newBuilder(), defaultIssue); + + assertThat(issue.hasRuleDescriptionContextKey()).isFalse(); + } + + private static DefaultIssue createDefaultIssueWithMandatoryFields() { + DefaultIssue defaultIssue = new DefaultIssue(); + defaultIssue.setKey("test_issue:key"); + defaultIssue.setType(RuleType.CODE_SMELL); + defaultIssue.setComponentKey("component_key"); + defaultIssue.setProjectUuid("project_uuid"); + defaultIssue.setProjectKey("project_key"); + defaultIssue.setRuleKey(RuleKey.of("ruleRepo", "rule1")); + defaultIssue.setStatus("open"); + defaultIssue.setCreationDate(new Date()); + return defaultIssue; + } + + private static IssueCache.Issue.Builder prepareIssueWithCompulsoryFields() { + return IssueCache.Issue.newBuilder() + .setRuleType(RuleType.CODE_SMELL.getDbConstant()) + .setRuleKey("test_issue:key") + .setStatus("open"); + } + +} |