Skip to content

Commit

Permalink
SONAR-10781 Filter secondary locations that are not in PR
Browse files Browse the repository at this point in the history
Filter secondary locations that are not in the PR/short living branch
  • Loading branch information
henryju authored and SonarTech committed May 25, 2018
1 parent 162162b commit 38218bf
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 11 deletions.
Expand Up @@ -19,6 +19,8 @@
*/ */
package org.sonar.server.computation.task.projectanalysis.component; package org.sonar.server.computation.task.projectanalysis.component;


import java.util.Optional;

/** /**
* The tree of components defined in the scanner report. * The tree of components defined in the scanner report.
*/ */
Expand All @@ -39,4 +41,16 @@ public interface TreeRootHolder {
*/ */
Component getComponentByRef(int ref); Component getComponentByRef(int ref);



/**
* Return a component by its batch reference. Returns {@link Optional#empty()} if there's
* no {@link Component} with the specified reference
*
* @throws IllegalStateException if the holder is empty (ie. there is no root yet)
* @deprecated This method was introduced as a quick fix for SONAR-10781. Ultimately one should never manipulate component
* ref that doesn't exists in the scanner report
*/
@Deprecated
Optional<Component> getOptionalComponentByRef(int ref);

} }
Expand Up @@ -21,9 +21,9 @@


import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import javax.annotation.CheckForNull; import javax.annotation.CheckForNull;


import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
import static org.sonar.server.computation.task.projectanalysis.component.ComponentVisitor.Order.POST_ORDER; import static org.sonar.server.computation.task.projectanalysis.component.ComponentVisitor.Order.POST_ORDER;
Expand Down Expand Up @@ -52,11 +52,15 @@ public Component getRoot() {


@Override @Override
public Component getComponentByRef(int ref) { public Component getComponentByRef(int ref) {
return getOptionalComponentByRef(ref)
.orElseThrow(() -> new IllegalArgumentException(String.format("Component with ref '%s' can't be found", ref)));
}

@Override
public Optional<Component> getOptionalComponentByRef(int ref) {
checkInitialized(); checkInitialized();
ensureComponentByRefIsPopulated(); ensureComponentByRefIsPopulated();
Component component = componentsByRef.get(ref); return Optional.ofNullable(componentsByRef.get(ref));
checkArgument(component != null, "Component with ref '%s' can't be found", ref);
return component;
} }


private void ensureComponentByRefIsPopulated() { private void ensureComponentByRefIsPopulated() {
Expand Down
Expand Up @@ -22,6 +22,7 @@
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional;
import org.sonar.api.issue.Issue; import org.sonar.api.issue.Issue;
import org.sonar.api.rule.RuleKey; import org.sonar.api.rule.RuleKey;
import org.sonar.api.rules.RuleType; import org.sonar.api.rules.RuleType;
Expand Down Expand Up @@ -169,7 +170,7 @@ private DefaultIssue toIssue(LineHashSequence lineHashSeq, ScannerReport.Issue r
if (flow.getLocationCount() > 0) { if (flow.getLocationCount() > 0) {
DbIssues.Flow.Builder dbFlowBuilder = DbIssues.Flow.newBuilder(); DbIssues.Flow.Builder dbFlowBuilder = DbIssues.Flow.newBuilder();
for (ScannerReport.IssueLocation location : flow.getLocationList()) { for (ScannerReport.IssueLocation location : flow.getLocationList()) {
dbFlowBuilder.addLocation(convertLocation(location)); convertLocation(location).ifPresent(dbFlowBuilder::addLocation);
} }
dbLocationsBuilder.addFlow(dbFlowBuilder); dbLocationsBuilder.addFlow(dbFlowBuilder);
} }
Expand Down Expand Up @@ -206,7 +207,7 @@ private DefaultIssue toExternalIssue(LineHashSequence lineHashSeq, ScannerReport
if (flow.getLocationCount() > 0) { if (flow.getLocationCount() > 0) {
DbIssues.Flow.Builder dbFlowBuilder = DbIssues.Flow.newBuilder(); DbIssues.Flow.Builder dbFlowBuilder = DbIssues.Flow.newBuilder();
for (ScannerReport.IssueLocation location : flow.getLocationList()) { for (ScannerReport.IssueLocation location : flow.getLocationList()) {
dbFlowBuilder.addLocation(convertLocation(location)); convertLocation(location).ifPresent(dbFlowBuilder::addLocation);
} }
dbLocationsBuilder.addFlow(dbFlowBuilder); dbLocationsBuilder.addFlow(dbFlowBuilder);
} }
Expand Down Expand Up @@ -251,10 +252,15 @@ private DefaultIssue init(DefaultIssue issue) {
return issue; return issue;
} }


private DbIssues.Location convertLocation(ScannerReport.IssueLocation source) { private Optional<DbIssues.Location> convertLocation(ScannerReport.IssueLocation source) {
DbIssues.Location.Builder target = DbIssues.Location.newBuilder(); DbIssues.Location.Builder target = DbIssues.Location.newBuilder();
if (source.getComponentRef() != 0 && source.getComponentRef() != component.getReportAttributes().getRef()) { if (source.getComponentRef() != 0 && source.getComponentRef() != component.getReportAttributes().getRef()) {
target.setComponentId(treeRootHolder.getComponentByRef(source.getComponentRef()).getUuid()); // SONAR-10781 Component might not exist because on short living branch and PR, only changed components are included in the report
Optional<Component> optionalComponent = treeRootHolder.getOptionalComponentByRef(source.getComponentRef());
if (!optionalComponent.isPresent()) {
return Optional.empty();
}
target.setComponentId(optionalComponent.get().getUuid());
} }
if (isNotEmpty(source.getMsg())) { if (isNotEmpty(source.getMsg())) {
target.setMsg(source.getMsg()); target.setMsg(source.getMsg());
Expand All @@ -264,7 +270,7 @@ private DbIssues.Location convertLocation(ScannerReport.IssueLocation source) {
DbCommons.TextRange.Builder targetRange = convertTextRange(sourceRange); DbCommons.TextRange.Builder targetRange = convertTextRange(sourceRange);
target.setTextRange(targetRange); target.setTextRange(targetRange);
} }
return target.build(); return Optional.of(target.build());
} }


private DbCommons.TextRange.Builder convertTextRange(ScannerReport.TextRange sourceRange) { private DbCommons.TextRange.Builder convertTextRange(ScannerReport.TextRange sourceRange) {
Expand Down
Expand Up @@ -99,6 +99,15 @@ public void getComponentByRef_returns_any_report_component_in_the_tree() {
} }
} }


@Test
public void getOptionalComponentByRef_returns_any_report_component_in_the_tree() {
underTest.setRoot(SOME_REPORT_COMPONENT_TREE);

for (int i = 1; i <= 4; i++) {
assertThat(underTest.getOptionalComponentByRef(i).get().getReportAttributes().getRef()).isEqualTo(i);
}
}

@Test @Test
public void getComponentByRef_throws_IAE_if_holder_does_not_contain_specified_component() { public void getComponentByRef_throws_IAE_if_holder_does_not_contain_specified_component() {
underTest.setRoot(SOME_REPORT_COMPONENT_TREE); underTest.setRoot(SOME_REPORT_COMPONENT_TREE);
Expand All @@ -109,6 +118,13 @@ public void getComponentByRef_throws_IAE_if_holder_does_not_contain_specified_co
underTest.getComponentByRef(6); underTest.getComponentByRef(6);
} }


@Test
public void getOptionalComponentByRef_returns_empty_if_holder_does_not_contain_specified_component() {
underTest.setRoot(SOME_REPORT_COMPONENT_TREE);

assertThat(underTest.getOptionalComponentByRef(6)).isEmpty();
}

@Test @Test
public void getComponentByRef_throws_IAE_if_holder_contains_View_tree() { public void getComponentByRef_throws_IAE_if_holder_contains_View_tree() {
underTest.setRoot(SOME_VIEWS_COMPONENT_TREE); underTest.setRoot(SOME_VIEWS_COMPONENT_TREE);
Expand Down
Expand Up @@ -19,6 +19,7 @@
*/ */
package org.sonar.server.computation.task.projectanalysis.component; package org.sonar.server.computation.task.projectanalysis.component;


import java.util.Optional;
import org.junit.rules.ExternalResource; import org.junit.rules.ExternalResource;


public class TreeRootHolderRule extends ExternalResource implements TreeRootHolder { public class TreeRootHolderRule extends ExternalResource implements TreeRootHolder {
Expand All @@ -44,4 +45,9 @@ public Component getRoot() {
public Component getComponentByRef(int ref) { public Component getComponentByRef(int ref) {
return delegate.getComponentByRef(ref); return delegate.getComponentByRef(ref);
} }

@Override
public Optional<Component> getOptionalComponentByRef(int ref) {
return delegate.getOptionalComponentByRef(ref);
}
} }
Expand Up @@ -30,6 +30,7 @@
import org.sonar.api.utils.Duration; import org.sonar.api.utils.Duration;
import org.sonar.core.issue.DefaultIssue; import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.tracking.Input; import org.sonar.core.issue.tracking.Input;
import org.sonar.db.protobuf.DbIssues;
import org.sonar.scanner.protocol.Constants; import org.sonar.scanner.protocol.Constants;
import org.sonar.scanner.protocol.output.ScannerReport; import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReport.TextRange; import org.sonar.scanner.protocol.output.ScannerReport.TextRange;
Expand All @@ -55,10 +56,15 @@


public class TrackerRawInputFactoryTest { public class TrackerRawInputFactoryTest {


private static final String FILE_UUID = "fake_uuid";
private static final String ANOTHER_FILE_UUID = "another_fake_uuid";
private static int FILE_REF = 2; private static int FILE_REF = 2;
private static int NOT_IN_REPORT_FILE_REF = 3;
private static int ANOTHER_FILE_REF = 4;


private static ReportComponent PROJECT = ReportComponent.builder(Component.Type.PROJECT, 1).build(); private static ReportComponent FILE = ReportComponent.builder(Component.Type.FILE, FILE_REF).setUuid(FILE_UUID).build();
private static ReportComponent FILE = ReportComponent.builder(Component.Type.FILE, FILE_REF).build(); private static ReportComponent ANOTHER_FILE = ReportComponent.builder(Component.Type.FILE, ANOTHER_FILE_REF).setUuid(ANOTHER_FILE_UUID).build();
private static ReportComponent PROJECT = ReportComponent.builder(Component.Type.PROJECT, 1).addChildren(FILE, ANOTHER_FILE).build();


@Rule @Rule
public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule().setRoot(PROJECT); public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule().setRoot(PROJECT);
Expand Down Expand Up @@ -133,6 +139,52 @@ public void load_issues_from_report() {
assertThat(issue.debt()).isNull(); assertThat(issue.debt()).isNull();
} }


// SONAR-10781
@Test
public void load_issues_from_report_missing_secondary_location_component() {
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(TextRange.newBuilder().setStartLine(2).build())
.setMsg("the message")
.setRuleRepository(ruleKey.repository())
.setRuleKey(ruleKey.rule())
.setSeverity(Constants.Severity.BLOCKER)
.setGap(3.14)
.addFlow(ScannerReport.Flow.newBuilder()
.addLocation(ScannerReport.IssueLocation.newBuilder()
.setComponentRef(FILE_REF)
.setMsg("Secondary location in same file")
.setTextRange(TextRange.newBuilder().setStartLine(2).build()))
.addLocation(ScannerReport.IssueLocation.newBuilder()
.setComponentRef(NOT_IN_REPORT_FILE_REF)
.setMsg("Secondary location in a missing file")
.setTextRange(TextRange.newBuilder().setStartLine(3).build()))
.addLocation(ScannerReport.IssueLocation.newBuilder()
.setComponentRef(ANOTHER_FILE_REF)
.setMsg("Secondary location in another file")
.setTextRange(TextRange.newBuilder().setStartLine(3).build()))
.build())
.build();
reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue));
Input<DefaultIssue> input = underTest.create(FILE);

Collection<DefaultIssue> issues = input.getIssues();
assertThat(issues).hasSize(1);
DefaultIssue issue = Iterators.getOnlyElement(issues.iterator());

DbIssues.Locations locations = issue.getLocations();
// fields set by analysis report
assertThat(locations.getFlowList()).hasSize(1);
assertThat(locations.getFlow(0).getLocationList()).hasSize(2);
// Not component id if location is in the same file
assertThat(locations.getFlow(0).getLocation(0).getComponentId()).isEmpty();
assertThat(locations.getFlow(0).getLocation(1).getComponentId()).isEqualTo(ANOTHER_FILE_UUID);
}

@Test @Test
public void load_external_issues_from_report() { public void load_external_issues_from_report() {
when(sourceLinesHash.getLineHashesMatchingDBVersion(FILE)).thenReturn(Collections.singletonList("line")); when(sourceLinesHash.getLineHashesMatchingDBVersion(FILE)).thenReturn(Collections.singletonList("line"));
Expand Down

0 comments on commit 38218bf

Please sign in to comment.