diff options
author | Julien HENRY <julien.henry@sonarsource.com> | 2017-08-10 10:32:58 +0200 |
---|---|---|
committer | Julien HENRY <julien.henry@sonarsource.com> | 2017-09-07 08:33:31 +0200 |
commit | 4f2c55e5f60c9c8108730a50e59c74344c5c195f (patch) | |
tree | 5968d4acca63292fe78805fd727635448f761dbb | |
parent | 0b0bf09d855d98b14c030b63661d459cff12ad49 (diff) | |
download | sonarqube-4f2c55e5f60c9c8108730a50e59c74344c5c195f.tar.gz sonarqube-4f2c55e5f60c9c8108730a50e59c74344c5c195f.zip |
SONAR-9694 Consider all issue's locations when backdating
2 files changed, 94 insertions, 8 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/IssueCreationDateCalculator.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/IssueCreationDateCalculator.java index 92d4c4b9015..873cd23b3af 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/IssueCreationDateCalculator.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/IssueCreationDateCalculator.java @@ -20,14 +20,22 @@ package org.sonar.server.computation.task.projectanalysis.issue; import java.time.format.DateTimeFormatter; +import java.util.Comparator; import java.util.Date; +import java.util.HashSet; import java.util.Optional; +import java.util.Set; import java.util.function.Supplier; +import java.util.stream.IntStream; import org.sonar.api.utils.DateUtils; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; import org.sonar.core.issue.DefaultIssue; import org.sonar.core.issue.IssueChangeContext; +import org.sonar.db.protobuf.DbCommons.TextRange; +import org.sonar.db.protobuf.DbIssues; +import org.sonar.db.protobuf.DbIssues.Flow; +import org.sonar.db.protobuf.DbIssues.Location; import org.sonar.server.computation.task.projectanalysis.analysis.Analysis; import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolder; import org.sonar.server.computation.task.projectanalysis.analysis.ScannerPlugin; @@ -122,11 +130,21 @@ public class IssueCreationDateCalculator extends IssueVisitor { } private static Optional<Changeset> getChangeset(ScmInfo scmInfo, DefaultIssue issue) { - Integer line = issue.getLine(); - if (line != null) { - Changeset changesetForLine = scmInfo.getChangesetForLine(line); - if (changesetForLine != null) { - return Optional.of(changesetForLine); + Set<Integer> involvedLines = new HashSet<>(); + DbIssues.Locations locations = issue.getLocations(); + if (locations != null) { + if (locations.hasTextRange()) { + addLines(involvedLines, locations.getTextRange()); + } + for (Flow f : locations.getFlowList()) { + for (Location l : f.getLocationList()) { + addLines(involvedLines, l.getTextRange()); + } + } + if (!involvedLines.isEmpty()) { + return involvedLines.stream() + .map(scmInfo::getChangesetForLine) + .max(Comparator.comparingLong(Changeset::getDate)); } } @@ -138,6 +156,10 @@ public class IssueCreationDateCalculator extends IssueVisitor { return Optional.empty(); } + private static void addLines(Set<Integer> involvedLines, TextRange range) { + IntStream.rangeClosed(range.getStartLine(), range.getEndLine()).forEach(involvedLines::add); + } + private static Date getChangeDate(Changeset changesetForLine) { return DateUtils.longToDate(changesetForLine.getDate()); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/IssueCreationDateCalculatorTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/IssueCreationDateCalculatorTest.java index 26103d3462d..f0e84c58a06 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/IssueCreationDateCalculatorTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/IssueCreationDateCalculatorTest.java @@ -27,6 +27,11 @@ import org.junit.Before; import org.junit.Test; import org.sonar.api.rule.RuleKey; import org.sonar.core.issue.DefaultIssue; +import org.sonar.db.protobuf.DbCommons.TextRange; +import org.sonar.db.protobuf.DbIssues; +import org.sonar.db.protobuf.DbIssues.Flow; +import org.sonar.db.protobuf.DbIssues.Location; +import org.sonar.db.protobuf.DbIssues.Locations.Builder; import org.sonar.server.computation.task.projectanalysis.analysis.Analysis; import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolder; import org.sonar.server.computation.task.projectanalysis.analysis.ScannerPlugin; @@ -60,6 +65,7 @@ public class IssueCreationDateCalculatorTest { private IssueCreationDateCalculator calculator; private Analysis baseAnalysis; private Map<String, ScannerPlugin> scannerPlugins; + private ScmInfo scmInfo; @Before public void before() { @@ -218,6 +224,52 @@ public class IssueCreationDateCalculatorTest { assertChangeOfCreationDateTo(1200L); } + @Test + public void should_use_primary_location_when_backdating() { + currentAnalysisIs(3000L); + + newIssue(); + when(issue.getLocations()).thenReturn(DbIssues.Locations.newBuilder().setTextRange(range(2, 3)).build()); + withScmAt(2, 1200L); + withScmAt(3, 1300L); + + run(); + + assertChangeOfCreationDateTo(1300L); + } + + @Test + public void should_use_flows_location_when_backdating() { + currentAnalysisIs(3000L); + + newIssue(); + Builder builder = DbIssues.Locations.newBuilder() + .setTextRange(range(2, 3)); + Flow.Builder secondary = Flow.newBuilder().addLocation(Location.newBuilder().setTextRange(range(4, 5))); + builder.addFlow(secondary).build(); + Flow.Builder flow = Flow.newBuilder() + .addLocation(Location.newBuilder().setTextRange(range(6, 7))) + .addLocation(Location.newBuilder().setTextRange(range(8, 9))); + builder.addFlow(flow).build(); + when(issue.getLocations()).thenReturn(builder.build()); + withScmAt(2, 1200L); + withScmAt(3, 1300L); + withScmAt(4, 1400L); + withScmAt(5, 1500L); + withScmAt(6, 1600L); + withScmAt(7, 1700L); + withScmAt(8, 1800L); + withScmAt(9, 1900L); + + run(); + + assertChangeOfCreationDateTo(1900L); + } + + private org.sonar.db.protobuf.DbCommons.TextRange.Builder range(int startLine, int endLine) { + return TextRange.newBuilder().setStartLine(startLine).setEndLine(endLine); + } + private void previousAnalysisWas(long analysisDate) { when(analysisMetadataHolder.getBaseAnalysis()) .thenReturn(baseAnalysis); @@ -253,13 +305,25 @@ public class IssueCreationDateCalculatorTest { } private void withScm(long blame) { - ScmInfo scmInfo = mock(ScmInfo.class); + createMockScmInfo(); Changeset changeset = Changeset.newChangesetBuilder().setDate(blame).setRevision("1").build(); - when(scmInfoRepository.getScmInfo(component)) - .thenReturn(Optional.of(scmInfo)); when(scmInfo.getLatestChangeset()).thenReturn(changeset); } + private void createMockScmInfo() { + if (scmInfo == null) { + scmInfo = mock(ScmInfo.class); + when(scmInfoRepository.getScmInfo(component)) + .thenReturn(Optional.of(scmInfo)); + } + } + + private void withScmAt(int line, long blame) { + createMockScmInfo(); + Changeset changeset = Changeset.newChangesetBuilder().setDate(blame).setRevision("1").build(); + when(scmInfo.getChangesetForLine(line)).thenReturn(changeset); + } + private void ruleCreatedAt(long createdAt) { when(activeRule.getCreatedAt()).thenReturn(createdAt); } |