aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-ce-task-projectanalysis/src
diff options
context:
space:
mode:
authorAurelien Poscia <aurelien.poscia@sonarsource.com>2022-07-06 10:39:01 +0200
committersonartech <sonartech@sonarsource.com>2022-07-08 20:02:48 +0000
commit26fde2bdeb8ca2d5b9b76ce1ebc11706c9471cd0 (patch)
treedfe460821b29459e88197b40d5b251eb7927faa6 /server/sonar-ce-task-projectanalysis/src
parent685a8905315ce2fb830c91684ea3c9a3b3ad06a8 (diff)
downloadsonarqube-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/src')
-rw-r--r--server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/IssueLifecycle.java1
-rw-r--r--server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/TrackerRawInputFactory.java1
-rw-r--r--server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/util/cache/ProtobufIssueDiskCache.java11
-rw-r--r--server/sonar-ce-task-projectanalysis/src/main/protobuf/issue_cache.proto1
-rw-r--r--server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/IssueLifecycleTest.java48
-rw-r--r--server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/TrackerRawInputFactoryTest.java27
-rw-r--r--server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/util/cache/ProtobufIssueDiskCacheTest.java96
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");
+ }
+
+}