aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorBelen Pruvost <belen.pruvost@sonarsource.com>2022-01-13 16:42:20 +0100
committersonartech <sonartech@sonarsource.com>2022-01-21 20:03:22 +0000
commit573f47d57bc4cc52235a22066d81b6be7dee4f3c (patch)
tree59444eac11c580e23bf1c22e8a2f2d61428d879a /server
parent3ec97d1a4368fdd3212d524aacfc73403ed709ce (diff)
downloadsonarqube-573f47d57bc4cc52235a22066d81b6be7dee4f3c.tar.gz
sonarqube-573f47d57bc4cc52235a22066d81b6be7dee4f3c.zip
SONAR-14929 - Save a new issue as new on branch using reference branch
Diffstat (limited to 'server')
-rw-r--r--server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/NewIssueClassifier.java5
-rw-r--r--server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PersistIssuesStep.java7
-rw-r--r--server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/util/cache/ProtobufIssueDiskCache.java4
-rw-r--r--server/sonar-ce-task-projectanalysis/src/main/protobuf/issue_cache.proto3
-rw-r--r--server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/NewIssueClassifierTest.java10
-rw-r--r--server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PersistIssuesStepTest.java250
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java2
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueDao.java4
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueMapper.java4
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/issue/NewCodeReferenceIssueDto.java69
-rw-r--r--server/sonar-db-dao/src/main/resources/org/sonar/db/issue/IssueMapper.xml34
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/issue/NewCodeReferenceIssueDtoTest.java48
12 files changed, 321 insertions, 119 deletions
diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/NewIssueClassifier.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/NewIssueClassifier.java
index 3d4506dfae7..9c5aa13e77e 100644
--- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/NewIssueClassifier.java
+++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/NewIssueClassifier.java
@@ -55,7 +55,10 @@ public class NewIssueClassifier {
}
if (periodHolder.getPeriod().getMode().equals(NewCodePeriodType.REFERENCE_BRANCH.name())) {
- return hasAtLeastOneLocationOnChangedLines(component, issue);
+ issue.setIsOnReferencedBranch(true);
+ boolean isOnChangedLine = hasAtLeastOneLocationOnChangedLines(component, issue);
+ issue.setIsOnChangedLine(isOnChangedLine);
+ return isOnChangedLine;
}
}
return false;
diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PersistIssuesStep.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PersistIssuesStep.java
index ba32960616a..c744da8bea6 100644
--- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PersistIssuesStep.java
+++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PersistIssuesStep.java
@@ -36,6 +36,7 @@ import org.sonar.db.DbSession;
import org.sonar.db.issue.IssueChangeMapper;
import org.sonar.db.issue.IssueDto;
import org.sonar.db.issue.IssueMapper;
+import org.sonar.db.issue.NewCodeReferenceIssueDto;
import org.sonar.server.issue.IssueStorage;
import static org.sonar.core.util.FileUtils.humanReadableByteCountSI;
@@ -71,8 +72,7 @@ public class PersistIssuesStep implements ComputationStep {
context.getStatistics().add("cacheSize", humanReadableByteCountSI(protoIssueCache.fileSize()));
IssueStatistics statistics = new IssueStatistics();
try (DbSession dbSession = dbClient.openSession(true);
-
- CloseableIterator<DefaultIssue> issues = protoIssueCache.traverse()) {
+ CloseableIterator<DefaultIssue> issues = protoIssueCache.traverse()) {
List<DefaultIssue> addedIssues = new ArrayList<>(ISSUE_BATCHING_SIZE);
List<DefaultIssue> updatedIssues = new ArrayList<>(ISSUE_BATCHING_SIZE);
@@ -112,6 +112,9 @@ public class PersistIssuesStep implements ComputationStep {
String ruleUuid = ruleRepository.getByKey(i.ruleKey()).getUuid();
IssueDto dto = IssueDto.toDtoForComputationInsert(i, ruleUuid, now);
mapper.insert(dto);
+ if (i.isOnReferencedBranch() && i.isOnChangedLine()) {
+ mapper.insertAsNewOnReferenceBranch(NewCodeReferenceIssueDto.fromIssueDto(dto, now, uuidFactory));
+ }
statistics.inserts++;
});
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 56e3926b353..21c80615e43 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
@@ -123,6 +123,8 @@ public class ProtobufIssueDiskCache implements DiskCache<DefaultIssue> {
defaultIssue.setCloseDate(next.hasCloseDate() ? new Date(next.getCloseDate()) : null);
defaultIssue.setCurrentChangeWithoutAddChange(next.hasCurrentChanges() ? toDefaultIssueChanges(next.getCurrentChanges()) : null);
defaultIssue.setNew(next.getIsNew());
+ defaultIssue.setIsOnReferencedBranch(next.getIsOnReferencedBranch());
+ defaultIssue.setIsOnChangedLine(next.getIsOnChangedLine());
defaultIssue.setCopied(next.getIsCopied());
defaultIssue.setBeingClosed(next.getBeingClosed());
defaultIssue.setOnDisabledRule(next.getOnDisabledRule());
@@ -171,6 +173,8 @@ public class ProtobufIssueDiskCache implements DiskCache<DefaultIssue> {
ofNullable(defaultIssue.closeDate()).map(Date::getTime).ifPresent(builder::setCloseDate);
ofNullable(defaultIssue.currentChange()).ifPresent(c -> builder.setCurrentChanges(toProtoIssueChanges(c)));
builder.setIsNew(defaultIssue.isNew());
+ builder.setIsOnReferencedBranch(defaultIssue.isOnReferencedBranch());
+ builder.setIsOnChangedLine(defaultIssue.isOnChangedLine());
builder.setIsCopied(defaultIssue.isCopied());
builder.setBeingClosed(defaultIssue.isBeingClosed());
builder.setOnDisabledRule(defaultIssue.isOnDisabledRule());
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 6c488ffafd6..a873fefd52b 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
@@ -75,6 +75,9 @@ message Issue {
repeated Comment comments = 38;
optional bool quickFixAvailable = 39;
+
+ optional bool isOnReferencedBranch = 40;
+ optional bool isOnChangedLine = 41;
}
message Comment {
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/NewIssueClassifierTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/NewIssueClassifierTest.java
index 95584a702d3..ed03ba5105d 100644
--- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/NewIssueClassifierTest.java
+++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/NewIssueClassifierTest.java
@@ -38,6 +38,8 @@ import org.sonar.db.protobuf.DbIssues;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
public class NewIssueClassifierTest {
@@ -86,6 +88,8 @@ public class NewIssueClassifierTest {
DefaultIssue issue = mock(DefaultIssue.class);
when(issue.creationDate()).thenReturn(new Date(2000L));
assertThat(newIssueClassifier.isNew(mock(Component.class), issue)).isTrue();
+ verify(issue).creationDate();
+ verifyNoMoreInteractions(issue);
}
@Test
@@ -105,6 +109,8 @@ public class NewIssueClassifierTest {
.build())
.build());
assertThat(newIssueClassifier.isNew(file, issue)).isTrue();
+ verify(issue).setIsOnReferencedBranch(true);
+ verify(issue).setIsOnChangedLine(true);
}
@Test
@@ -124,6 +130,8 @@ public class NewIssueClassifierTest {
.build())
.build());
assertThat(newIssueClassifier.isNew(file, issue)).isFalse();
+ verify(issue).setIsOnReferencedBranch(true);
+ verify(issue).setIsOnChangedLine(false);
}
@Test
@@ -132,6 +140,8 @@ public class NewIssueClassifierTest {
DefaultIssue issue = mock(DefaultIssue.class);
when(issue.creationDate()).thenReturn(new Date(500L));
assertThat(newIssueClassifier.isNew(mock(Component.class), issue)).isFalse();
+ verify(issue).creationDate();
+ verifyNoMoreInteractions(issue);
}
@Test
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PersistIssuesStepTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PersistIssuesStepTest.java
index aeb1761c241..aeeea14ee82 100644
--- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PersistIssuesStepTest.java
+++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PersistIssuesStepTest.java
@@ -42,7 +42,7 @@ import org.sonar.ce.task.step.TestComputationStepContext;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.DefaultIssueComment;
import org.sonar.core.issue.FieldDiffs;
-import org.sonar.core.util.SequenceUuidFactory;
+import org.sonar.core.util.UuidFactoryImpl;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
@@ -100,7 +100,7 @@ public class PersistIssuesStepTest extends BaseStepTest {
reportReader.setMetadata(ScannerReport.Metadata.getDefaultInstance());
underTest = new PersistIssuesStep(dbClient, system2, conflictResolver, new RuleRepositoryImpl(adHocRuleCreator, dbClient), protoIssueCache,
- new IssueStorage(), new SequenceUuidFactory());
+ new IssueStorage(), UuidFactoryImpl.INSTANCE);
}
@After
@@ -115,44 +115,46 @@ public class PersistIssuesStepTest extends BaseStepTest {
ComponentDto project = db.components().insertPrivateProject();
ComponentDto file = db.components().insertComponent(newFileDto(project, null));
when(system2.now()).thenReturn(NOW);
+ String issueKey = "ISSUE-1";
protoIssueCache.newAppender().append(new DefaultIssue()
- .setKey("ISSUE")
- .setType(RuleType.CODE_SMELL)
- .setRuleKey(rule.getKey())
- .setComponentUuid(file.uuid())
- .setComponentKey(file.getKey())
- .setProjectUuid(project.uuid())
- .setProjectKey(project.getKey())
- .setSeverity(BLOCKER)
- .setStatus(STATUS_OPEN)
- .setTags(singletonList("test"))
- .setNew(false)
- .setCopied(true)
- .setType(RuleType.BUG)
- .setCreationDate(new Date(NOW))
- .setSelectedAt(NOW)
- .addComment(new DefaultIssueComment()
- .setKey("COMMENT")
- .setIssueKey("ISSUE")
- .setUserUuid("john_uuid")
- .setMarkdownText("Some text")
- .setCreatedAt(new Date(NOW))
- .setUpdatedAt(new Date(NOW))
- .setNew(true))
- .setCurrentChange(
- new FieldDiffs()
- .setIssueKey("ISSUE")
+ .setKey(issueKey)
+ .setType(RuleType.CODE_SMELL)
+ .setRuleKey(rule.getKey())
+ .setComponentUuid(file.uuid())
+ .setComponentKey(file.getKey())
+ .setProjectUuid(project.uuid())
+ .setProjectKey(project.getKey())
+ .setSeverity(BLOCKER)
+ .setStatus(STATUS_OPEN)
+ .setTags(singletonList("test"))
+ .setNew(false)
+ .setCopied(true)
+ .setType(RuleType.BUG)
+ .setCreationDate(new Date(NOW))
+ .setSelectedAt(NOW)
+ .addComment(new DefaultIssueComment()
+ .setKey("COMMENT")
+ .setIssueKey(issueKey)
.setUserUuid("john_uuid")
- .setDiff("technicalDebt", null, 1L)
- .setCreationDate(new Date(NOW))))
+ .setMarkdownText("Some text")
+ .setCreatedAt(new Date(NOW))
+ .setUpdatedAt(new Date(NOW))
+ .setNew(true))
+ .setCurrentChange(
+ new FieldDiffs()
+ .setIssueKey(issueKey)
+ .setUserUuid("john_uuid")
+ .setDiff("technicalDebt", null, 1L)
+ .setCreationDate(new Date(NOW))))
.close();
TestComputationStepContext context = new TestComputationStepContext();
underTest.execute(context);
- IssueDto result = dbClient.issueDao().selectOrFailByKey(session, "ISSUE");
- assertThat(result.getKey()).isEqualTo("ISSUE");
+ IssueDto result = dbClient.issueDao().selectOrFailByKey(session, issueKey);
+
+ assertThat(result.getKey()).isEqualTo(issueKey);
assertThat(result.getRuleKey()).isEqualTo(rule.getKey());
assertThat(result.getComponentUuid()).isEqualTo(file.uuid());
assertThat(result.getProjectUuid()).isEqualTo(project.uuid());
@@ -161,7 +163,10 @@ public class PersistIssuesStepTest extends BaseStepTest {
assertThat(result.getType()).isEqualTo(RuleType.BUG.getDbConstant());
assertThat(result.getTags()).containsExactlyInAnyOrder("test");
- List<IssueChangeDto> changes = dbClient.issueChangeDao().selectByIssueKeys(session, Arrays.asList("ISSUE"));
+ boolean isNewCodeOnReferencedBranch = dbClient.issueDao().isNewCodeOnReferencedBranch(session, result.getKey());
+ assertThat(isNewCodeOnReferencedBranch).isFalse();
+
+ List<IssueChangeDto> changes = dbClient.issueChangeDao().selectByIssueKeys(session, Arrays.asList(issueKey));
assertThat(changes).extracting(IssueChangeDto::getChangeType).containsExactly(IssueChangeDto.TYPE_COMMENT, IssueChangeDto.TYPE_FIELD_CHANGE);
assertThat(context.getStatistics().getAll()).contains(
entry("inserts", "1"), entry("updates", "0"), entry("merged", "0"));
@@ -174,29 +179,31 @@ public class PersistIssuesStepTest extends BaseStepTest {
ComponentDto project = db.components().insertPrivateProject();
ComponentDto file = db.components().insertComponent(newFileDto(project, null));
when(system2.now()).thenReturn(NOW);
+ String issueKey = "ISSUE-2";
protoIssueCache.newAppender().append(new DefaultIssue()
- .setKey("ISSUE")
- .setType(RuleType.CODE_SMELL)
- .setRuleKey(rule.getKey())
- .setComponentUuid(file.uuid())
- .setComponentKey(file.getKey())
- .setProjectUuid(project.uuid())
- .setProjectKey(project.getKey())
- .setSeverity(BLOCKER)
- .setStatus(STATUS_OPEN)
- .setNew(false)
- .setCopied(true)
- .setType(RuleType.BUG)
- .setCreationDate(new Date(NOW))
- .setSelectedAt(NOW))
+ .setKey(issueKey)
+ .setType(RuleType.CODE_SMELL)
+ .setRuleKey(rule.getKey())
+ .setComponentUuid(file.uuid())
+ .setComponentKey(file.getKey())
+ .setProjectUuid(project.uuid())
+ .setProjectKey(project.getKey())
+ .setSeverity(BLOCKER)
+ .setStatus(STATUS_OPEN)
+ .setNew(false)
+ .setIsOnReferencedBranch(true)
+ .setCopied(true)
+ .setType(RuleType.BUG)
+ .setCreationDate(new Date(NOW))
+ .setSelectedAt(NOW))
.close();
TestComputationStepContext context = new TestComputationStepContext();
underTest.execute(context);
- IssueDto result = dbClient.issueDao().selectOrFailByKey(session, "ISSUE");
- assertThat(result.getKey()).isEqualTo("ISSUE");
+ IssueDto result = dbClient.issueDao().selectOrFailByKey(session, issueKey);
+ assertThat(result.getKey()).isEqualTo(issueKey);
assertThat(result.getRuleKey()).isEqualTo(rule.getKey());
assertThat(result.getComponentUuid()).isEqualTo(file.uuid());
assertThat(result.getProjectUuid()).isEqualTo(project.uuid());
@@ -205,7 +212,10 @@ public class PersistIssuesStepTest extends BaseStepTest {
assertThat(result.getType()).isEqualTo(RuleType.BUG.getDbConstant());
assertThat(result.getTags()).isEmpty();
- assertThat(dbClient.issueChangeDao().selectByIssueKeys(session, Arrays.asList("ISSUE"))).isEmpty();
+ boolean isNewCodeOnReferencedBranch = dbClient.issueDao().isNewCodeOnReferencedBranch(session, result.getKey());
+ assertThat(isNewCodeOnReferencedBranch).isFalse();
+
+ assertThat(dbClient.issueChangeDao().selectByIssueKeys(session, Arrays.asList(issueKey))).isEmpty();
assertThat(context.getStatistics().getAll()).contains(
entry("inserts", "1"), entry("updates", "0"), entry("merged", "0"));
}
@@ -217,42 +227,45 @@ public class PersistIssuesStepTest extends BaseStepTest {
ComponentDto project = db.components().insertPrivateProject();
ComponentDto file = db.components().insertComponent(newFileDto(project, null));
when(system2.now()).thenReturn(NOW);
+ String issueKey = "ISSUE-3";
protoIssueCache.newAppender().append(new DefaultIssue()
- .setKey("ISSUE")
- .setType(RuleType.CODE_SMELL)
- .setRuleKey(rule.getKey())
- .setComponentUuid(file.uuid())
- .setComponentKey(file.getKey())
- .setProjectUuid(project.uuid())
- .setProjectKey(project.getKey())
- .setSeverity(BLOCKER)
- .setStatus(STATUS_OPEN)
- .setNew(true)
- .setCopied(true)
- .setType(RuleType.BUG)
- .setCreationDate(new Date(NOW))
- .setSelectedAt(NOW)
- .addComment(new DefaultIssueComment()
- .setKey("COMMENT")
- .setIssueKey("ISSUE")
- .setUserUuid("john_uuid")
- .setMarkdownText("Some text")
- .setUpdatedAt(new Date(NOW))
- .setCreatedAt(new Date(NOW))
- .setNew(true))
- .setCurrentChange(new FieldDiffs()
- .setIssueKey("ISSUE")
- .setUserUuid("john_uuid")
- .setDiff("technicalDebt", null, 1L)
- .setCreationDate(new Date(NOW))))
+ .setKey(issueKey)
+ .setType(RuleType.CODE_SMELL)
+ .setRuleKey(rule.getKey())
+ .setComponentUuid(file.uuid())
+ .setComponentKey(file.getKey())
+ .setProjectUuid(project.uuid())
+ .setProjectKey(project.getKey())
+ .setSeverity(BLOCKER)
+ .setStatus(STATUS_OPEN)
+ .setNew(true)
+ .setIsOnReferencedBranch(true)
+ .setIsOnChangedLine(true)
+ .setCopied(true)
+ .setType(RuleType.BUG)
+ .setCreationDate(new Date(NOW))
+ .setSelectedAt(NOW)
+ .addComment(new DefaultIssueComment()
+ .setKey("COMMENT")
+ .setIssueKey(issueKey)
+ .setUserUuid("john_uuid")
+ .setMarkdownText("Some text")
+ .setUpdatedAt(new Date(NOW))
+ .setCreatedAt(new Date(NOW))
+ .setNew(true))
+ .setCurrentChange(new FieldDiffs()
+ .setIssueKey(issueKey)
+ .setUserUuid("john_uuid")
+ .setDiff("technicalDebt", null, 1L)
+ .setCreationDate(new Date(NOW))))
.close();
TestComputationStepContext context = new TestComputationStepContext();
underTest.execute(context);
- IssueDto result = dbClient.issueDao().selectOrFailByKey(session, "ISSUE");
- assertThat(result.getKey()).isEqualTo("ISSUE");
+ IssueDto result = dbClient.issueDao().selectOrFailByKey(session, issueKey);
+ assertThat(result.getKey()).isEqualTo(issueKey);
assertThat(result.getRuleKey()).isEqualTo(rule.getKey());
assertThat(result.getComponentUuid()).isEqualTo(file.uuid());
assertThat(result.getProjectUuid()).isEqualTo(project.uuid());
@@ -260,7 +273,10 @@ public class PersistIssuesStepTest extends BaseStepTest {
assertThat(result.getStatus()).isEqualTo(STATUS_OPEN);
assertThat(result.getType()).isEqualTo(RuleType.BUG.getDbConstant());
- List<IssueChangeDto> changes = dbClient.issueChangeDao().selectByIssueKeys(session, Arrays.asList("ISSUE"));
+ boolean isNewCodeOnReferencedBranch = dbClient.issueDao().isNewCodeOnReferencedBranch(session, result.getKey());
+ assertThat(isNewCodeOnReferencedBranch).isTrue();
+
+ List<IssueChangeDto> changes = dbClient.issueChangeDao().selectByIssueKeys(session, Arrays.asList(issueKey));
assertThat(changes).extracting(IssueChangeDto::getChangeType).containsExactly(IssueChangeDto.TYPE_COMMENT, IssueChangeDto.TYPE_FIELD_CHANGE);
assertThat(context.getStatistics().getAll()).contains(
entry("inserts", "1"), entry("updates", "0"), entry("merged", "0"));
@@ -307,9 +323,10 @@ public class PersistIssuesStepTest extends BaseStepTest {
ComponentDto project = db.components().insertPrivateProject();
ComponentDto file = db.components().insertComponent(newFileDto(project, null));
session.commit();
+ String issueKey = "ISSUE-4";
protoIssueCache.newAppender().append(new DefaultIssue()
- .setKey("ISSUE")
+ .setKey(issueKey)
.setType(RuleType.CODE_SMELL)
.setRuleKey(rule.getKey())
.setComponentUuid(file.uuid())
@@ -320,13 +337,15 @@ public class PersistIssuesStepTest extends BaseStepTest {
.setStatus(STATUS_OPEN)
.setCreationDate(new Date(NOW))
.setNew(true)
+ .setIsOnReferencedBranch(true)
+ .setIsOnChangedLine(true)
.setType(RuleType.BUG)).close();
TestComputationStepContext context = new TestComputationStepContext();
underTest.execute(context);
- IssueDto result = dbClient.issueDao().selectOrFailByKey(session, "ISSUE");
- assertThat(result.getKey()).isEqualTo("ISSUE");
+ IssueDto result = dbClient.issueDao().selectOrFailByKey(session, issueKey);
+ assertThat(result.getKey()).isEqualTo(issueKey);
assertThat(result.getRuleKey()).isEqualTo(rule.getKey());
assertThat(result.getComponentUuid()).isEqualTo(file.uuid());
assertThat(result.getProjectUuid()).isEqualTo(project.uuid());
@@ -335,6 +354,9 @@ public class PersistIssuesStepTest extends BaseStepTest {
assertThat(result.getType()).isEqualTo(RuleType.BUG.getDbConstant());
assertThat(context.getStatistics().getAll()).contains(
entry("inserts", "1"), entry("updates", "0"), entry("merged", "0"));
+
+ boolean isNewCodeOnReferencedBranch = dbClient.issueDao().isNewCodeOnReferencedBranch(session, result.getKey());
+ assertThat(isNewCodeOnReferencedBranch).isTrue();
}
@Test
@@ -350,12 +372,12 @@ public class PersistIssuesStepTest extends BaseStepTest {
DiskCache.CacheAppender issueCacheAppender = protoIssueCache.newAppender();
issueCacheAppender.append(
- issue.toDefaultIssue()
- .setStatus(STATUS_CLOSED)
- .setResolution(RESOLUTION_FIXED)
- .setSelectedAt(NOW)
- .setNew(false)
- .setChanged(true))
+ issue.toDefaultIssue()
+ .setStatus(STATUS_CLOSED)
+ .setResolution(RESOLUTION_FIXED)
+ .setSelectedAt(NOW)
+ .setNew(false)
+ .setChanged(true))
.close();
TestComputationStepContext context = new TestComputationStepContext();
@@ -381,20 +403,20 @@ public class PersistIssuesStepTest extends BaseStepTest {
DiskCache.CacheAppender issueCacheAppender = protoIssueCache.newAppender();
issueCacheAppender.append(
- issue.toDefaultIssue()
- .setStatus(STATUS_CLOSED)
- .setResolution(RESOLUTION_FIXED)
- .setSelectedAt(NOW)
- .setNew(false)
- .setChanged(true)
- .addComment(new DefaultIssueComment()
- .setKey("COMMENT")
- .setIssueKey(issue.getKey())
- .setUserUuid("john_uuid")
- .setMarkdownText("Some text")
- .setCreatedAt(new Date(NOW))
- .setUpdatedAt(new Date(NOW))
- .setNew(true)))
+ issue.toDefaultIssue()
+ .setStatus(STATUS_CLOSED)
+ .setResolution(RESOLUTION_FIXED)
+ .setSelectedAt(NOW)
+ .setNew(false)
+ .setChanged(true)
+ .addComment(new DefaultIssueComment()
+ .setKey("COMMENT")
+ .setIssueKey(issue.getKey())
+ .setUserUuid("john_uuid")
+ .setMarkdownText("Some text")
+ .setCreatedAt(new Date(NOW))
+ .setUpdatedAt(new Date(NOW))
+ .setNew(true)))
.close();
TestComputationStepContext context = new TestComputationStepContext();
@@ -422,17 +444,17 @@ public class PersistIssuesStepTest extends BaseStepTest {
DiskCache.CacheAppender issueCacheAppender = protoIssueCache.newAppender();
issueCacheAppender.append(
- issue.toDefaultIssue()
- .setStatus(STATUS_CLOSED)
- .setResolution(RESOLUTION_FIXED)
- .setSelectedAt(NOW)
- .setNew(false)
- .setChanged(true)
- .setCurrentChange(new FieldDiffs()
- .setIssueKey("ISSUE")
- .setUserUuid("john_uuid")
- .setDiff("technicalDebt", null, 1L)
- .setCreationDate(new Date(NOW))))
+ issue.toDefaultIssue()
+ .setStatus(STATUS_CLOSED)
+ .setResolution(RESOLUTION_FIXED)
+ .setSelectedAt(NOW)
+ .setNew(false)
+ .setChanged(true)
+ .setCurrentChange(new FieldDiffs()
+ .setIssueKey("ISSUE")
+ .setUserUuid("john_uuid")
+ .setDiff("technicalDebt", null, 1L)
+ .setCreationDate(new Date(NOW))))
.close();
TestComputationStepContext context = new TestComputationStepContext();
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java b/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java
index 691ce4c137b..19916bb3e24 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java
@@ -73,6 +73,7 @@ import org.sonar.db.issue.IssueChangeDto;
import org.sonar.db.issue.IssueChangeMapper;
import org.sonar.db.issue.IssueDto;
import org.sonar.db.issue.IssueMapper;
+import org.sonar.db.issue.NewCodeReferenceIssueDto;
import org.sonar.db.issue.PrIssueDto;
import org.sonar.db.mapping.ProjectMappingDto;
import org.sonar.db.mapping.ProjectMappingsMapper;
@@ -197,6 +198,7 @@ public class MyBatis implements Startable {
confBuilder.loadAlias("IssueChange", IssueChangeDto.class);
confBuilder.loadAlias("KeyLongValue", KeyLongValue.class);
confBuilder.loadAlias("Issue", IssueDto.class);
+ confBuilder.loadAlias("NewCodeReferenceIssue", NewCodeReferenceIssueDto.class);
confBuilder.loadAlias("Measure", MeasureDto.class);
confBuilder.loadAlias("NotificationQueue", NotificationQueueDto.class);
confBuilder.loadAlias("PermissionTemplateCharacteristic", PermissionTemplateCharacteristicDto.class);
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueDao.java
index 52ef7a4f10c..bb9a136b987 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueDao.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueDao.java
@@ -58,6 +58,10 @@ public class IssueDao implements Dao {
return executeLargeInputs(keys, mapper(session)::selectByKeys);
}
+ public boolean isNewCodeOnReferencedBranch(DbSession session, String issueKey) {
+ return mapper(session).isNewCodeOnReferencedBranch(issueKey);
+ }
+
public Set<String> selectIssueKeysByComponentUuid(DbSession session, String componentUuid) {
return mapper(session).selectIssueKeysByComponentUuid(componentUuid);
}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueMapper.java
index 80ea1be570c..49399d49cf9 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueMapper.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueMapper.java
@@ -37,6 +37,8 @@ public interface IssueMapper {
List<IssueDto> selectByKeys(List<String> keys);
+ boolean isNewCodeOnReferencedBranch(@Param("issueKey") String issueKey);
+
Set<String> selectIssueKeysByComponentUuid(@Param("componentUuid") String componentUuid);
List<IssueDto> selectByComponentUuidPaginated(@Param("componentUuid") String componentUuid,
@@ -50,6 +52,8 @@ public interface IssueMapper {
int update(IssueDto issue);
+ void insertAsNewOnReferenceBranch(NewCodeReferenceIssueDto issue);
+
int updateIfBeforeSelectedDate(IssueDto issue);
void scrollNonClosedByComponentUuid(@Param("componentUuid") String componentUuid, ResultHandler<IssueDto> handler);
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/issue/NewCodeReferenceIssueDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/issue/NewCodeReferenceIssueDto.java
new file mode 100644
index 00000000000..3b870154465
--- /dev/null
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/issue/NewCodeReferenceIssueDto.java
@@ -0,0 +1,69 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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.issue;
+
+import java.io.Serializable;
+import org.sonar.core.util.UuidFactory;
+
+public final class NewCodeReferenceIssueDto implements Serializable {
+ private String uuid;
+ private String issueKey;
+
+ // technical date
+ private Long createdAt;
+
+ public NewCodeReferenceIssueDto() {
+ // nothing to do
+ }
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ public NewCodeReferenceIssueDto setUuid(String uuid) {
+ this.uuid = uuid;
+ return this;
+ }
+
+ public String getIssueKey() {
+ return issueKey;
+ }
+
+ public NewCodeReferenceIssueDto setIssueKey(String issueKey) {
+ this.issueKey = issueKey;
+ return this;
+ }
+
+ public Long getCreatedAt() {
+ return createdAt;
+ }
+
+ public NewCodeReferenceIssueDto setCreatedAt(Long createdAt) {
+ this.createdAt = createdAt;
+ return this;
+ }
+
+ public static NewCodeReferenceIssueDto fromIssueDto(IssueDto issue, long now, UuidFactory uuidFactory) {
+ return new NewCodeReferenceIssueDto()
+ .setUuid(uuidFactory.create())
+ .setIssueKey(issue.getKey())
+ .setCreatedAt(now);
+ }
+}
diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/issue/IssueMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/issue/IssueMapper.xml
index 877acd0fcb7..8e84d87f0f7 100644
--- a/server/sonar-db-dao/src/main/resources/org/sonar/db/issue/IssueMapper.xml
+++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/issue/IssueMapper.xml
@@ -118,6 +118,14 @@
#{quickFixAvailable, jdbcType=BOOLEAN})
</insert>
+ <insert id="insertAsNewOnReferenceBranch" parameterType="NewCodeReferenceIssue" useGeneratedKeys="false">
+ INSERT INTO new_code_reference_issues (uuid, issue_key, created_at)
+ VALUES (
+ #{uuid,jdbcType=VARCHAR},
+ #{issueKey,jdbcType=VARCHAR},
+ #{createdAt,jdbcType=BIGINT})
+ </insert>
+
<!--
IMPORTANT - invariant columns can't be updated. See IssueDto#toDtoForUpdate()
-->
@@ -185,7 +193,29 @@
where i.kee=#{kee,jdbcType=VARCHAR}
</select>
- <select id="scrollNonClosedByComponentUuid" parameterType="String" resultType="Issue" fetchSize="${_scrollFetchSize}" resultSetType="FORWARD_ONLY">
+ <sql id="isNewCodeOnReferencedBranchSql">
+ select
+ case when exists
+ (
+ select i.uuid from new_code_reference_issues i
+ where i.issue_key = #{issueKey,jdbcType=VARCHAR}
+ )
+ then 1
+ else 0
+ end
+ </sql>
+
+ <select id="isNewCodeOnReferencedBranch" parameterType="String" resultType="boolean">
+ <include refid="isNewCodeOnReferencedBranchSql"/>
+ </select>
+
+ <select id="isNewCodeOnReferencedBranch" parameterType="String" resultType="boolean" databaseId="oracle">
+ <include refid="isNewCodeOnReferencedBranchSql"/>
+ from dual
+ </select>
+
+ <select id="scrollNonClosedByComponentUuid" parameterType="String" resultType="Issue" fetchSize="${_scrollFetchSize}"
+ resultSetType="FORWARD_ONLY">
select
<include refid="issueColumns"/>
from issues i
@@ -384,7 +414,7 @@
from
(select
row_number() over(order by i.issue_creation_date ASC) as row_number,
- <include refid="issueColumnsInInnerQuery" />
+ <include refid="issueColumnsInInnerQuery"/>
from issues i
where i.project_uuid=#{componentUuid,jdbcType=VARCHAR}
order by row_number asc
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/issue/NewCodeReferenceIssueDtoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/issue/NewCodeReferenceIssueDtoTest.java
new file mode 100644
index 00000000000..17bf644b99e
--- /dev/null
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/issue/NewCodeReferenceIssueDtoTest.java
@@ -0,0 +1,48 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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.issue;
+
+import org.junit.Test;
+import org.sonar.core.util.UuidFactory;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class NewCodeReferenceIssueDtoTest {
+
+ private static final IssueDto ISSUE_DTO = mock(IssueDto.class);
+ private static final String KEY = "issue-key";
+ private static final String UUID = "uuid";
+ private static final UuidFactory UUID_FACTORY = mock(UuidFactory.class);
+
+ @Test
+ public void create_from_issue_dto() {
+ when(ISSUE_DTO.getKey()).thenReturn(KEY);
+ when(UUID_FACTORY.create()).thenReturn(UUID);
+ long now = System.currentTimeMillis();
+
+ NewCodeReferenceIssueDto dto = NewCodeReferenceIssueDto.fromIssueDto(ISSUE_DTO, now, UUID_FACTORY);
+
+ assertThat(dto.getUuid()).isEqualTo(UUID);
+ assertThat(dto.getIssueKey()).isEqualTo(KEY);
+ assertThat(dto.getCreatedAt()).isNotNull();
+ }
+}