Browse Source

SONAR-11859, SONAR-11879 Track issues with the target branch

tags/7.8
Julien HENRY 5 years ago
parent
commit
bec219de08
16 changed files with 423 additions and 231 deletions
  1. 136
    0
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/MergeAndTargetBranchComponentUuids.java
  2. 0
    88
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/MergeBranchComponentUuids.java
  3. 4
    4
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/container/ProjectAnalysisTaskContainerPopulator.java
  4. 5
    5
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/IntegrateIssuesVisitor.java
  5. 3
    3
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/MergeBranchTrackerExecution.java
  6. 30
    11
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/ShortBranchOrPullRequestTrackerExecution.java
  7. 33
    19
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/TrackerMergeOrTargetBranchInputFactory.java
  8. 4
    4
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/scm/ScmInfoDbLoader.java
  9. 2
    1
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/api/posttask/PostProjectAnalysisTasksExecutorTest.java
  10. 146
    0
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/MergeAndTargetBranchComponentUuidsTest.java
  11. 0
    79
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/MergeBranchComponentUuidsTest.java
  12. 7
    7
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/IntegrateIssuesVisitorTest.java
  13. 2
    2
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/MergeBranchTrackerExecutionTest.java
  14. 45
    3
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/ShortBranchOrPullRequestTrackerExecutionTest.java
  15. 4
    4
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/scm/ScmInfoDbLoaderTest.java
  16. 2
    1
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java

+ 136
- 0
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/MergeAndTargetBranchComponentUuids.java View File

@@ -0,0 +1,136 @@
/*
* SonarQube
* Copyright (C) 2009-2019 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.component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import javax.annotation.CheckForNull;
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.BranchDto;
import org.sonar.db.component.ComponentDto;

import static com.google.common.base.Preconditions.checkState;
import static org.sonar.db.component.ComponentDto.removeBranchAndPullRequestFromKey;

/**
* Cache a map between component keys and uuids in the merge branch and optionally the target branch (for PR and SLB, and only if this target branch is analyzed)
*/
public class MergeAndTargetBranchComponentUuids {
private final AnalysisMetadataHolder analysisMetadataHolder;
private final DbClient dbClient;
private Map<String, String> mergeBranchComponentsUuidsByKey;
private Map<String, String> targetBranchComponentsUuidsByKey;
private String mergeBranchName;
private boolean hasMergeBranchAnalysis;
private boolean hasTargetBranchAnalysis;
@CheckForNull
private String targetBranchUuid;

public MergeAndTargetBranchComponentUuids(AnalysisMetadataHolder analysisMetadataHolder, DbClient dbClient) {
this.analysisMetadataHolder = analysisMetadataHolder;
this.dbClient = dbClient;
}

private void lazyInit() {
if (mergeBranchComponentsUuidsByKey == null) {
String mergeBranchUuid = analysisMetadataHolder.getBranch().getMergeBranchUuid();

mergeBranchComponentsUuidsByKey = new HashMap<>();
targetBranchComponentsUuidsByKey = new HashMap<>();

try (DbSession dbSession = dbClient.openSession(false)) {

Optional<BranchDto> opt = dbClient.branchDao().selectByUuid(dbSession, mergeBranchUuid);
checkState(opt.isPresent(), "Merge branch '%s' does not exist", mergeBranchUuid);
mergeBranchName = opt.get().getKey();

initForMergeBranch(mergeBranchUuid, dbSession);

if (analysisMetadataHolder.isSLBorPR()) {
initForTargetBranch(mergeBranchUuid, dbSession);
} else {
hasTargetBranchAnalysis = false;
}
}
}
}

private void initForTargetBranch(String mergeBranchUuid, DbSession dbSession) {
Optional<BranchDto> branchDtoOpt = dbClient.branchDao().selectByBranchKey(dbSession, analysisMetadataHolder.getProject().getUuid(),
analysisMetadataHolder.getBranch().getTargetBranchName());
targetBranchUuid = branchDtoOpt.map(BranchDto::getUuid).orElse(null);
hasTargetBranchAnalysis = targetBranchUuid != null && dbClient.snapshotDao().selectLastAnalysisByRootComponentUuid(dbSession, targetBranchUuid).isPresent();
if (hasTargetBranchAnalysis && !targetBranchUuid.equals(mergeBranchUuid)) {
List<ComponentDto> targetComponents = dbClient.componentDao().selectByProjectUuid(targetBranchUuid, dbSession);
for (ComponentDto dto : targetComponents) {
targetBranchComponentsUuidsByKey.put(dto.getKey(), dto.uuid());
}
}
}

private void initForMergeBranch(String mergeBranchUuid, DbSession dbSession) {
hasMergeBranchAnalysis = dbClient.snapshotDao().selectLastAnalysisByRootComponentUuid(dbSession, mergeBranchUuid).isPresent();

if (hasMergeBranchAnalysis) {
List<ComponentDto> components = dbClient.componentDao().selectByProjectUuid(mergeBranchUuid, dbSession);
for (ComponentDto dto : components) {
mergeBranchComponentsUuidsByKey.put(dto.getKey(), dto.uuid());
}
}
}

public boolean hasMergeBranchAnalysis() {
lazyInit();
return hasMergeBranchAnalysis;
}

public boolean hasTargetBranchAnalysis() {
lazyInit();
return hasTargetBranchAnalysis;
}

public String getMergeBranchName() {
lazyInit();
return mergeBranchName;
}

public boolean areTargetAndMergeBranchesDifferent() {
lazyInit();
return targetBranchUuid == null || !analysisMetadataHolder.getBranch().getMergeBranchUuid().equals(targetBranchUuid);
}

@CheckForNull
public String getMergeBranchComponentUuid(String dbKey) {
lazyInit();
String cleanComponentKey = removeBranchAndPullRequestFromKey(dbKey);
return mergeBranchComponentsUuidsByKey.get(cleanComponentKey);
}

@CheckForNull
public String getTargetBranchComponentUuid(String dbKey) {
lazyInit();
String cleanComponentKey = removeBranchAndPullRequestFromKey(dbKey);
return targetBranchComponentsUuidsByKey.get(cleanComponentKey);
}
}

+ 0
- 88
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/MergeBranchComponentUuids.java View File

@@ -1,88 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2019 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.component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import javax.annotation.CheckForNull;
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.BranchDto;
import org.sonar.db.component.ComponentDto;

import static com.google.common.base.Preconditions.checkState;
import static org.sonar.db.component.ComponentDto.removeBranchAndPullRequestFromKey;

/**
* Cache a map between component keys and uuids in the merge branch
*/
public class MergeBranchComponentUuids {
private final AnalysisMetadataHolder analysisMetadataHolder;
private final DbClient dbClient;
private Map<String, String> uuidsByKey;
private String mergeBranchName;
private boolean hasMergeBranchAnalysis;

public MergeBranchComponentUuids(AnalysisMetadataHolder analysisMetadataHolder, DbClient dbClient) {
this.analysisMetadataHolder = analysisMetadataHolder;
this.dbClient = dbClient;
}

private void lazyInit() {
if (uuidsByKey == null) {
String mergeBranchUuid = analysisMetadataHolder.getBranch().getMergeBranchUuid();

uuidsByKey = new HashMap<>();
try (DbSession dbSession = dbClient.openSession(false)) {

List<ComponentDto> components = dbClient.componentDao().selectByProjectUuid(mergeBranchUuid, dbSession);
for (ComponentDto dto : components) {
uuidsByKey.put(dto.getKey(), dto.uuid());
}

Optional<BranchDto> opt = dbClient.branchDao().selectByUuid(dbSession, mergeBranchUuid);
checkState(opt.isPresent(), "Merge branch '%s' does not exist", mergeBranchUuid);
mergeBranchName = opt.get().getKey();

hasMergeBranchAnalysis = dbClient.snapshotDao().selectLastAnalysisByRootComponentUuid(dbSession, mergeBranchUuid).isPresent();
}
}
}

public boolean hasMergeBranchAnalysis() {
lazyInit();
return hasMergeBranchAnalysis;
}

public String getMergeBranchName() {
lazyInit();
return mergeBranchName;
}

@CheckForNull
public String getUuid(String dbKey) {
lazyInit();
String cleanComponentKey = removeBranchAndPullRequestFromKey(dbKey);
return uuidsByKey.get(cleanComponentKey);
}
}

+ 4
- 4
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/container/ProjectAnalysisTaskContainerPopulator.java View File

@@ -34,7 +34,7 @@ import org.sonar.ce.task.projectanalysis.component.BranchPersisterImpl;
import org.sonar.ce.task.projectanalysis.component.ConfigurationRepositoryImpl;
import org.sonar.ce.task.projectanalysis.component.DbIdsRepositoryImpl;
import org.sonar.ce.task.projectanalysis.component.DisabledComponentsHolderImpl;
import org.sonar.ce.task.projectanalysis.component.MergeBranchComponentUuids;
import org.sonar.ce.task.projectanalysis.component.MergeAndTargetBranchComponentUuids;
import org.sonar.ce.task.projectanalysis.component.ReportModulesPath;
import org.sonar.ce.task.projectanalysis.component.SiblingComponentsWithOpenIssues;
import org.sonar.ce.task.projectanalysis.component.TreeRootHolderImpl;
@@ -82,7 +82,7 @@ import org.sonar.ce.task.projectanalysis.issue.SiblingsIssuesLoader;
import org.sonar.ce.task.projectanalysis.issue.ShortBranchOrPullRequestTrackerExecution;
import org.sonar.ce.task.projectanalysis.issue.TrackerBaseInputFactory;
import org.sonar.ce.task.projectanalysis.issue.TrackerExecution;
import org.sonar.ce.task.projectanalysis.issue.TrackerMergeBranchInputFactory;
import org.sonar.ce.task.projectanalysis.issue.TrackerMergeOrTargetBranchInputFactory;
import org.sonar.ce.task.projectanalysis.issue.TrackerRawInputFactory;
import org.sonar.ce.task.projectanalysis.issue.UpdateConflictResolver;
import org.sonar.ce.task.projectanalysis.issue.commonrule.BranchCoverageRule;
@@ -196,7 +196,7 @@ public final class ProjectAnalysisTaskContainerPopulator implements ContainerPop
MeasureComputersHolderImpl.class,
MutableTaskResultHolderImpl.class,
BatchReportReaderImpl.class,
MergeBranchComponentUuids.class,
MergeAndTargetBranchComponentUuids.class,
SiblingComponentsWithOpenIssues.class,

// repositories
@@ -271,7 +271,7 @@ public final class ProjectAnalysisTaskContainerPopulator implements ContainerPop
UpdateConflictResolver.class,
TrackerBaseInputFactory.class,
TrackerRawInputFactory.class,
TrackerMergeBranchInputFactory.class,
TrackerMergeOrTargetBranchInputFactory.class,
ClosedIssuesInputFactory.class,
Tracker.class,
TrackerExecution.class,

+ 5
- 5
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/IntegrateIssuesVisitor.java View File

@@ -27,7 +27,7 @@ import org.sonar.api.rules.RuleType;
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
import org.sonar.ce.task.projectanalysis.component.Component;
import org.sonar.ce.task.projectanalysis.component.CrawlerDepthLimit;
import org.sonar.ce.task.projectanalysis.component.MergeBranchComponentUuids;
import org.sonar.ce.task.projectanalysis.component.MergeAndTargetBranchComponentUuids;
import org.sonar.ce.task.projectanalysis.component.TypeAwareVisitorAdapter;
import org.sonar.ce.task.projectanalysis.util.cache.DiskCache;
import org.sonar.core.issue.DefaultIssue;
@@ -42,11 +42,11 @@ public class IntegrateIssuesVisitor extends TypeAwareVisitorAdapter {
private final IssueTrackingDelegator issueTracking;
private final SiblingsIssueMerger issueStatusCopier;
private final AnalysisMetadataHolder analysisMetadataHolder;
private final MergeBranchComponentUuids mergeBranchComponentUuids;
private final MergeAndTargetBranchComponentUuids mergeAndTargetBranchComponentUuids;

public IntegrateIssuesVisitor(IssueCache issueCache, IssueLifecycle issueLifecycle, IssueVisitors issueVisitors,
AnalysisMetadataHolder analysisMetadataHolder, IssueTrackingDelegator issueTracking, SiblingsIssueMerger issueStatusCopier,
MergeBranchComponentUuids mergeBranchComponentUuids) {
MergeAndTargetBranchComponentUuids mergeAndTargetBranchComponentUuids) {
super(CrawlerDepthLimit.FILE, POST_ORDER);
this.issueCache = issueCache;
this.issueLifecycle = issueLifecycle;
@@ -54,7 +54,7 @@ public class IntegrateIssuesVisitor extends TypeAwareVisitorAdapter {
this.analysisMetadataHolder = analysisMetadataHolder;
this.issueTracking = issueTracking;
this.issueStatusCopier = issueStatusCopier;
this.mergeBranchComponentUuids = mergeBranchComponentUuids;
this.mergeAndTargetBranchComponentUuids = mergeAndTargetBranchComponentUuids;
}

@Override
@@ -97,7 +97,7 @@ public class IntegrateIssuesVisitor extends TypeAwareVisitorAdapter {
for (Map.Entry<DefaultIssue, DefaultIssue> entry : matched.entrySet()) {
DefaultIssue raw = entry.getKey();
DefaultIssue base = entry.getValue();
issueLifecycle.copyExistingOpenIssueFromLongLivingBranch(raw, base, mergeBranchComponentUuids.getMergeBranchName());
issueLifecycle.copyExistingOpenIssueFromLongLivingBranch(raw, base, mergeAndTargetBranchComponentUuids.getMergeBranchName());
process(component, raw, cacheAppender);
}
}

+ 3
- 3
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/MergeBranchTrackerExecution.java View File

@@ -26,10 +26,10 @@ import org.sonar.core.issue.tracking.Tracking;

public class MergeBranchTrackerExecution {
private final TrackerRawInputFactory rawInputFactory;
private final TrackerMergeBranchInputFactory mergeInputFactory;
private final TrackerMergeOrTargetBranchInputFactory mergeInputFactory;
private final Tracker<DefaultIssue, DefaultIssue> tracker;

public MergeBranchTrackerExecution(TrackerRawInputFactory rawInputFactory, TrackerMergeBranchInputFactory mergeInputFactory,
public MergeBranchTrackerExecution(TrackerRawInputFactory rawInputFactory, TrackerMergeOrTargetBranchInputFactory mergeInputFactory,
Tracker<DefaultIssue, DefaultIssue> tracker) {
this.rawInputFactory = rawInputFactory;
this.mergeInputFactory = mergeInputFactory;
@@ -37,6 +37,6 @@ public class MergeBranchTrackerExecution {
}

public Tracking<DefaultIssue, DefaultIssue> track(Component component) {
return tracker.trackNonClosed(rawInputFactory.create(component), mergeInputFactory.create(component));
return tracker.trackNonClosed(rawInputFactory.create(component), mergeInputFactory.createForMergeBranch(component));
}
}

+ 30
- 11
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/ShortBranchOrPullRequestTrackerExecution.java View File

@@ -36,13 +36,12 @@ import org.sonar.core.util.stream.MoreCollectors;
public class ShortBranchOrPullRequestTrackerExecution {
private final TrackerBaseInputFactory baseInputFactory;
private final TrackerRawInputFactory rawInputFactory;
private final TrackerMergeBranchInputFactory mergeInputFactory;
private final TrackerMergeOrTargetBranchInputFactory mergeInputFactory;
private final Tracker<DefaultIssue, DefaultIssue> tracker;
private final NewLinesRepository newLinesRepository;

public ShortBranchOrPullRequestTrackerExecution(TrackerBaseInputFactory baseInputFactory, TrackerRawInputFactory rawInputFactory,
TrackerMergeBranchInputFactory mergeInputFactory,
Tracker<DefaultIssue, DefaultIssue> tracker, NewLinesRepository newLinesRepository) {
TrackerMergeOrTargetBranchInputFactory mergeInputFactory, Tracker<DefaultIssue, DefaultIssue> tracker, NewLinesRepository newLinesRepository) {
this.baseInputFactory = baseInputFactory;
this.rawInputFactory = rawInputFactory;
this.mergeInputFactory = mergeInputFactory;
@@ -52,21 +51,41 @@ public class ShortBranchOrPullRequestTrackerExecution {

public Tracking<DefaultIssue, DefaultIssue> track(Component component) {
Input<DefaultIssue> rawInput = rawInputFactory.create(component);
Input<DefaultIssue> baseInput = baseInputFactory.create(component);
Input<DefaultIssue> previousAnalysisInput = baseInputFactory.create(component);

Input<DefaultIssue> unmatchedRawInput;
// Step 1: track issues with merge branch (= long living)
Input<DefaultIssue> unmatchedRawsAfterMergeBranchTracking;
if (mergeInputFactory.hasMergeBranchAnalysis()) {
Input<DefaultIssue> mergeInput = mergeInputFactory.create(component);
Input<DefaultIssue> mergeInput = mergeInputFactory.createForMergeBranch(component);
Tracking<DefaultIssue, DefaultIssue> mergeTracking = tracker.trackNonClosed(rawInput, mergeInput);
List<DefaultIssue> unmatchedRaws = mergeTracking.getUnmatchedRaws().collect(MoreCollectors.toList());
unmatchedRawInput = new DefaultTrackingInput(unmatchedRaws, rawInput.getLineHashSequence(), rawInput.getBlockHashSequence());
unmatchedRawsAfterMergeBranchTracking = new DefaultTrackingInput(unmatchedRaws, rawInput.getLineHashSequence(), rawInput.getBlockHashSequence());
} else {
List<DefaultIssue> filteredRaws = keepIssuesHavingAtLeastOneLocationOnChangedLines(component, rawInput.getIssues());
unmatchedRawInput = new DefaultTrackingInput(filteredRaws, rawInput.getLineHashSequence(), rawInput.getBlockHashSequence());
unmatchedRawsAfterMergeBranchTracking = rawInput;
}

// do second tracking with base branch using raws issues that are still unmatched
return tracker.trackNonClosed(unmatchedRawInput, baseInput);
// Step 2: track remaining unmatched issues with target branch
Input<DefaultIssue> unmatchedRawsAfterTargetBranchTracking;
if (mergeInputFactory.hasTargetBranchAnalysis() && mergeInputFactory.areTargetAndMergeBranchesDifferent()) {
Input<DefaultIssue> targetInput = mergeInputFactory.createForTargetBranch(component);
Tracking<DefaultIssue, DefaultIssue> mergeTracking = tracker.trackNonClosed(unmatchedRawsAfterMergeBranchTracking, targetInput);
List<DefaultIssue> unmatchedRaws = mergeTracking.getUnmatchedRaws().collect(MoreCollectors.toList());
unmatchedRawsAfterTargetBranchTracking = new DefaultTrackingInput(unmatchedRaws, rawInput.getLineHashSequence(), rawInput.getBlockHashSequence());
} else {
unmatchedRawsAfterTargetBranchTracking = unmatchedRawsAfterMergeBranchTracking;
}

// Step 3: if there is no analysis or merge or target branch, keep only issues on changed lines
Input<DefaultIssue> unmatchedRawsAfterChangedLineFiltering;
if (!mergeInputFactory.hasTargetBranchAnalysis() || !mergeInputFactory.hasMergeBranchAnalysis()) {
List<DefaultIssue> filteredRaws = keepIssuesHavingAtLeastOneLocationOnChangedLines(component, unmatchedRawsAfterTargetBranchTracking.getIssues());
unmatchedRawsAfterChangedLineFiltering = new DefaultTrackingInput(filteredRaws, rawInput.getLineHashSequence(), rawInput.getBlockHashSequence());
} else {
unmatchedRawsAfterChangedLineFiltering = unmatchedRawsAfterTargetBranchTracking;
}

// Step 4: track issues of previous analysis of the current branch/PR
return tracker.trackNonClosed(unmatchedRawsAfterChangedLineFiltering, previousAnalysisInput);
}

private List<DefaultIssue> keepIssuesHavingAtLeastOneLocationOnChangedLines(Component component, Collection<DefaultIssue> issues) {

server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/TrackerMergeBranchInputFactory.java → server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/TrackerMergeOrTargetBranchInputFactory.java View File

@@ -23,7 +23,7 @@ import java.util.Collections;
import java.util.List;
import javax.annotation.Nullable;
import org.sonar.ce.task.projectanalysis.component.Component;
import org.sonar.ce.task.projectanalysis.component.MergeBranchComponentUuids;
import org.sonar.ce.task.projectanalysis.component.MergeAndTargetBranchComponentUuids;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.tracking.Input;
import org.sonar.core.issue.tracking.LazyInput;
@@ -31,46 +31,60 @@ import org.sonar.core.issue.tracking.LineHashSequence;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;

public class TrackerMergeBranchInputFactory {
public class TrackerMergeOrTargetBranchInputFactory {
private static final LineHashSequence EMPTY_LINE_HASH_SEQUENCE = new LineHashSequence(Collections.emptyList());

private final ComponentIssuesLoader mergeIssuesLoader;
private final ComponentIssuesLoader componentIssuesLoader;
private final DbClient dbClient;
private final MergeBranchComponentUuids mergeBranchComponentUuids;
private final MergeAndTargetBranchComponentUuids mergeAndTargetBranchComponentUuids;

public TrackerMergeBranchInputFactory(ComponentIssuesLoader mergeIssuesLoader, MergeBranchComponentUuids mergeBranchComponentUuids, DbClient dbClient) {
this.mergeIssuesLoader = mergeIssuesLoader;
this.mergeBranchComponentUuids = mergeBranchComponentUuids;
public TrackerMergeOrTargetBranchInputFactory(ComponentIssuesLoader componentIssuesLoader, MergeAndTargetBranchComponentUuids mergeAndTargetBranchComponentUuids,
DbClient dbClient) {
this.componentIssuesLoader = componentIssuesLoader;
this.mergeAndTargetBranchComponentUuids = mergeAndTargetBranchComponentUuids;
this.dbClient = dbClient;
// TODO detect file moves?
}

public boolean hasMergeBranchAnalysis() {
return mergeBranchComponentUuids.hasMergeBranchAnalysis();
return mergeAndTargetBranchComponentUuids.hasMergeBranchAnalysis();
}

public Input<DefaultIssue> create(Component component) {
String mergeBranchComponentUuid = mergeBranchComponentUuids.getUuid(component.getDbKey());
return new MergeLazyInput(component.getType(), mergeBranchComponentUuid);
public boolean hasTargetBranchAnalysis() {
return mergeAndTargetBranchComponentUuids.hasTargetBranchAnalysis();
}

private class MergeLazyInput extends LazyInput<DefaultIssue> {
public boolean areTargetAndMergeBranchesDifferent() {
return mergeAndTargetBranchComponentUuids.areTargetAndMergeBranchesDifferent();
}

public Input<DefaultIssue> createForMergeBranch(Component component) {
String mergeBranchComponentUuid = mergeAndTargetBranchComponentUuids.getMergeBranchComponentUuid(component.getDbKey());
return new MergeOrTargetLazyInput(component.getType(), mergeBranchComponentUuid);
}

public Input<DefaultIssue> createForTargetBranch(Component component) {
String targetBranchComponentUuid = mergeAndTargetBranchComponentUuids.getTargetBranchComponentUuid(component.getDbKey());
return new MergeOrTargetLazyInput(component.getType(), targetBranchComponentUuid);
}

private class MergeOrTargetLazyInput extends LazyInput<DefaultIssue> {
private final Component.Type type;
private final String mergeBranchComponentUuid;
private final String mergeOrTargetBranchComponentUuid;

private MergeLazyInput(Component.Type type, @Nullable String mergeBranchComponentUuid) {
private MergeOrTargetLazyInput(Component.Type type, @Nullable String mergeOrTargetBranchComponentUuid) {
this.type = type;
this.mergeBranchComponentUuid = mergeBranchComponentUuid;
this.mergeOrTargetBranchComponentUuid = mergeOrTargetBranchComponentUuid;
}

@Override
protected LineHashSequence loadLineHashSequence() {
if (mergeBranchComponentUuid == null || type != Component.Type.FILE) {
if (mergeOrTargetBranchComponentUuid == null || type != Component.Type.FILE) {
return EMPTY_LINE_HASH_SEQUENCE;
}

try (DbSession session = dbClient.openSession(false)) {
List<String> hashes = dbClient.fileSourceDao().selectLineHashes(session, mergeBranchComponentUuid);
List<String> hashes = dbClient.fileSourceDao().selectLineHashes(session, mergeOrTargetBranchComponentUuid);
if (hashes == null || hashes.isEmpty()) {
return EMPTY_LINE_HASH_SEQUENCE;
}
@@ -80,10 +94,10 @@ public class TrackerMergeBranchInputFactory {

@Override
protected List<DefaultIssue> loadIssues() {
if (mergeBranchComponentUuid == null) {
if (mergeOrTargetBranchComponentUuid == null) {
return Collections.emptyList();
}
return mergeIssuesLoader.loadOpenIssuesWithChanges(mergeBranchComponentUuid);
return componentIssuesLoader.loadOpenIssuesWithChanges(mergeOrTargetBranchComponentUuid);
}
}


+ 4
- 4
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/scm/ScmInfoDbLoader.java View File

@@ -25,7 +25,7 @@ import org.sonar.api.utils.log.Loggers;
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
import org.sonar.ce.task.projectanalysis.analysis.Branch;
import org.sonar.ce.task.projectanalysis.component.Component;
import org.sonar.ce.task.projectanalysis.component.MergeBranchComponentUuids;
import org.sonar.ce.task.projectanalysis.component.MergeAndTargetBranchComponentUuids;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.source.FileSourceDto;
@@ -35,9 +35,9 @@ public class ScmInfoDbLoader {

private final AnalysisMetadataHolder analysisMetadataHolder;
private final DbClient dbClient;
private final MergeBranchComponentUuids mergeBranchComponentUuid;
private final MergeAndTargetBranchComponentUuids mergeBranchComponentUuid;

public ScmInfoDbLoader(AnalysisMetadataHolder analysisMetadataHolder, DbClient dbClient, MergeBranchComponentUuids mergeBranchComponentUuid) {
public ScmInfoDbLoader(AnalysisMetadataHolder analysisMetadataHolder, DbClient dbClient, MergeAndTargetBranchComponentUuids mergeBranchComponentUuid) {
this.analysisMetadataHolder = analysisMetadataHolder;
this.dbClient = dbClient;
this.mergeBranchComponentUuid = mergeBranchComponentUuid;
@@ -67,7 +67,7 @@ public class ScmInfoDbLoader {
// at this point, it's the first analysis but had copyFromPrevious flag true
Branch branch = analysisMetadataHolder.getBranch();
if (!branch.isMain()) {
return Optional.ofNullable(mergeBranchComponentUuid.getUuid(file.getDbKey()));
return Optional.ofNullable(mergeBranchComponentUuid.getMergeBranchComponentUuid(file.getDbKey()));
}

return Optional.empty();

+ 2
- 1
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/api/posttask/PostProjectAnalysisTasksExecutorTest.java View File

@@ -307,7 +307,8 @@ public class PostProjectAnalysisTasksExecutorTest {
throw new UnsupportedOperationException();
}

@Override public String getTargetBranchName() {
@Override
public String getTargetBranchName() {
throw new UnsupportedOperationException();
}


+ 146
- 0
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/MergeAndTargetBranchComponentUuidsTest.java View File

@@ -0,0 +1,146 @@
/*
* SonarQube
* Copyright (C) 2009-2019 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.component;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolderRule;
import org.sonar.ce.task.projectanalysis.analysis.Branch;
import org.sonar.db.DbTester;
import org.sonar.db.component.BranchType;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting;
import org.sonar.server.project.Project;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.sonar.db.component.SnapshotTesting.newAnalysis;

public class MergeAndTargetBranchComponentUuidsTest {
@Rule
public AnalysisMetadataHolderRule analysisMetadataHolder = new AnalysisMetadataHolderRule();

@Rule
public DbTester db = DbTester.create();

private MergeAndTargetBranchComponentUuids underTest;
private Branch branch = mock(Branch.class);

private ComponentDto longBranch1;
private ComponentDto longBranch1File;
private ComponentDto shortBranch1File;
private ComponentDto shortBranch2File;
private Project project;
private ComponentDto shortBranch1;
private ComponentDto shortBranch2;
private ComponentDto longBranch2;
private ComponentDto longBranch2File;

@Before
public void setUp() {
underTest = new MergeAndTargetBranchComponentUuids(analysisMetadataHolder, db.getDbClient());
project = mock(Project.class);
analysisMetadataHolder.setProject(project);
analysisMetadataHolder.setBranch(branch);

ComponentDto projectDto = db.components().insertMainBranch();
when(project.getUuid()).thenReturn(projectDto.uuid());
longBranch1 = db.components().insertProjectBranch(projectDto, b -> b.setKey("longBranch1"));
longBranch2 = db.components().insertProjectBranch(projectDto, b -> b.setKey("longBranch2"));
shortBranch1 = db.components().insertProjectBranch(projectDto, b -> b.setKey("shortBranch1").setBranchType(BranchType.SHORT).setMergeBranchUuid(longBranch1.uuid()));
shortBranch2 = db.components().insertProjectBranch(projectDto, b -> b.setKey("shortBranch2").setBranchType(BranchType.SHORT).setMergeBranchUuid(longBranch1.uuid()));
longBranch1File = ComponentTesting.newFileDto(longBranch1, null, "file").setUuid("long1File");
longBranch2File = ComponentTesting.newFileDto(longBranch2, null, "file").setUuid("long2File");
shortBranch1File = ComponentTesting.newFileDto(shortBranch1, null, "file").setUuid("file1");
shortBranch2File = ComponentTesting.newFileDto(shortBranch2, null, "file").setUuid("file2");
db.components().insertComponents(longBranch1File, shortBranch1File, shortBranch2File, longBranch2File);
}

@Test
public void should_support_db_key_when_looking_for_merge_component() {
when(branch.getMergeBranchUuid()).thenReturn(longBranch1.uuid());
when(branch.getType()).thenReturn(BranchType.SHORT);
when(branch.getTargetBranchName()).thenReturn("notAnalyzedBranch");
db.components().insertSnapshot(newAnalysis(longBranch1));
assertThat(underTest.getMergeBranchComponentUuid(shortBranch1File.getDbKey())).isEqualTo(longBranch1File.uuid());
assertThat(underTest.getTargetBranchComponentUuid(shortBranch1File.getDbKey())).isNull();
assertThat(underTest.hasMergeBranchAnalysis()).isTrue();
assertThat(underTest.hasTargetBranchAnalysis()).isFalse();
assertThat(underTest.areTargetAndMergeBranchesDifferent()).isTrue();
assertThat(underTest.getMergeBranchName()).isEqualTo("longBranch1");
}

@Test
public void should_support_db_key_when_looking_for_target_component() {
when(branch.getMergeBranchUuid()).thenReturn(longBranch1.uuid());
when(branch.getTargetBranchName()).thenReturn("shortBranch2");
when(branch.getType()).thenReturn(BranchType.SHORT);
db.components().insertSnapshot(newAnalysis(longBranch1));
db.components().insertSnapshot(newAnalysis(shortBranch2));
assertThat(underTest.getMergeBranchComponentUuid(shortBranch1File.getDbKey())).isEqualTo(longBranch1File.uuid());
assertThat(underTest.getTargetBranchComponentUuid(shortBranch1File.getDbKey())).isEqualTo(shortBranch2File.uuid());
assertThat(underTest.hasMergeBranchAnalysis()).isTrue();
assertThat(underTest.hasTargetBranchAnalysis()).isTrue();
assertThat(underTest.areTargetAndMergeBranchesDifferent()).isTrue();
}

@Test
public void should_support_key_when_looking_for_merge_component() {
when(branch.getMergeBranchUuid()).thenReturn(longBranch1.uuid());
when(branch.getType()).thenReturn(BranchType.SHORT);
when(branch.getTargetBranchName()).thenReturn("notAnalyzedBranch");
db.components().insertSnapshot(newAnalysis(longBranch1));
assertThat(underTest.getMergeBranchComponentUuid(shortBranch1File.getKey())).isEqualTo(longBranch1File.uuid());
}

@Test
public void return_null_if_file_doesnt_exist() {
when(branch.getMergeBranchUuid()).thenReturn(longBranch1.uuid());
when(branch.getType()).thenReturn(BranchType.SHORT);
when(branch.getTargetBranchName()).thenReturn("notAnalyzedBranch");
db.components().insertSnapshot(newAnalysis(longBranch1));
assertThat(underTest.getMergeBranchComponentUuid("doesnt exist")).isNull();
}

@Test
public void skip_init_if_no_merge_branch_analysis() {
when(branch.getMergeBranchUuid()).thenReturn(longBranch1.uuid());
when(branch.getType()).thenReturn(BranchType.SHORT);
when(branch.getTargetBranchName()).thenReturn("notAnalyzedBranch");
assertThat(underTest.getMergeBranchComponentUuid(shortBranch1File.getDbKey())).isNull();
}

@Test
public void should_skip_target_components_init_on_long_branches() {
when(branch.getMergeBranchUuid()).thenReturn(longBranch1.uuid());
when(branch.getType()).thenReturn(BranchType.LONG);
when(branch.getTargetBranchName()).thenThrow(new IllegalStateException("Unsupported on long branches"));
db.components().insertSnapshot(newAnalysis(longBranch1));

assertThat(underTest.getMergeBranchComponentUuid(longBranch2File.getDbKey())).isEqualTo(longBranch1File.uuid());
assertThat(underTest.getTargetBranchComponentUuid(longBranch2File.getDbKey())).isNull();
assertThat(underTest.hasMergeBranchAnalysis()).isTrue();
assertThat(underTest.hasTargetBranchAnalysis()).isFalse();
assertThat(underTest.areTargetAndMergeBranchesDifferent()).isTrue();
assertThat(underTest.getMergeBranchName()).isEqualTo("longBranch1");
}
}

+ 0
- 79
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/MergeBranchComponentUuidsTest.java View File

@@ -1,79 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2019 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.component;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolderRule;
import org.sonar.ce.task.projectanalysis.analysis.Branch;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class MergeBranchComponentUuidsTest {
@Rule
public AnalysisMetadataHolderRule analysisMetadataHolder = new AnalysisMetadataHolderRule();

@Rule
public DbTester db = DbTester.create();

private MergeBranchComponentUuids underTest;
private Branch branch = mock(Branch.class);

private ComponentDto mergeBranch;
private ComponentDto mergeBranchFile;
private ComponentDto branchFile;

@Before
public void setUp() {
underTest = new MergeBranchComponentUuids(analysisMetadataHolder, db.getDbClient());
analysisMetadataHolder.setBranch(branch);

ComponentDto project = db.components().insertMainBranch();
mergeBranch = db.components().insertProjectBranch(project, b -> b.setKey("mergeBranch"));
ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("branch1"));
mergeBranchFile = ComponentTesting.newFileDto(mergeBranch, null, "file").setUuid("mergeFile");
branchFile = ComponentTesting.newFileDto(branch, null, "file").setUuid("file1");
db.components().insertComponents(mergeBranchFile, branchFile);
}

@Test
public void should_support_db_key() {
when(branch.getMergeBranchUuid()).thenReturn(mergeBranch.uuid());
assertThat(underTest.getUuid(branchFile.getDbKey())).isEqualTo(mergeBranchFile.uuid());
}

@Test
public void should_support_key() {
when(branch.getMergeBranchUuid()).thenReturn(mergeBranch.uuid());
assertThat(underTest.getUuid(branchFile.getKey())).isEqualTo(mergeBranchFile.uuid());
}

@Test
public void return_null_if_file_doesnt_exist() {
when(branch.getMergeBranchUuid()).thenReturn(mergeBranch.uuid());
assertThat(underTest.getUuid("doesnt exist")).isNull();
}
}

+ 7
- 7
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/IntegrateIssuesVisitorTest.java View File

@@ -36,7 +36,7 @@ import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
import org.sonar.ce.task.projectanalysis.analysis.Branch;
import org.sonar.ce.task.projectanalysis.batch.BatchReportReaderRule;
import org.sonar.ce.task.projectanalysis.component.Component;
import org.sonar.ce.task.projectanalysis.component.MergeBranchComponentUuids;
import org.sonar.ce.task.projectanalysis.component.MergeAndTargetBranchComponentUuids;
import org.sonar.ce.task.projectanalysis.component.ReportComponent;
import org.sonar.ce.task.projectanalysis.component.ReportModulesPath;
import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule;
@@ -116,9 +116,9 @@ public class IntegrateIssuesVisitorTest {
private MovedFilesRepository movedFilesRepository = mock(MovedFilesRepository.class);
private IssueLifecycle issueLifecycle = mock(IssueLifecycle.class);
private IssueVisitor issueVisitor = mock(IssueVisitor.class);
private MergeBranchComponentUuids mergeBranchComponentsUuids = mock(MergeBranchComponentUuids.class);
private MergeAndTargetBranchComponentUuids mergeBranchComponentsUuids = mock(MergeAndTargetBranchComponentUuids.class);
private SiblingsIssueMerger issueStatusCopier = mock(SiblingsIssueMerger.class);
private MergeBranchComponentUuids mergeBranchComponentUuids = mock(MergeBranchComponentUuids.class);
private MergeAndTargetBranchComponentUuids mergeAndTargetBranchComponentUuids = mock(MergeAndTargetBranchComponentUuids.class);
private SourceLinesHashRepository sourceLinesHash = mock(SourceLinesHashRepository.class);
private NewLinesRepository newLinesRepository = mock(NewLinesRepository.class);

@@ -145,7 +145,7 @@ public class IntegrateIssuesVisitorTest {
TrackerRawInputFactory rawInputFactory = new TrackerRawInputFactory(treeRootHolder, reportReader, sourceLinesHash, new CommonRuleEngineImpl(),
issueFilter, ruleRepositoryRule, activeRulesHolder);
TrackerBaseInputFactory baseInputFactory = new TrackerBaseInputFactory(issuesLoader, dbClient, movedFilesRepository, mock(ReportModulesPath.class), analysisMetadataHolder, new IssueFieldsSetter(), mock(ComponentsWithUnprocessedIssues.class));
TrackerMergeBranchInputFactory mergeInputFactory = new TrackerMergeBranchInputFactory(issuesLoader, mergeBranchComponentsUuids, dbClient);
TrackerMergeOrTargetBranchInputFactory mergeInputFactory = new TrackerMergeOrTargetBranchInputFactory(issuesLoader, mergeBranchComponentsUuids, dbClient);
ClosedIssuesInputFactory closedIssuesInputFactory = new ClosedIssuesInputFactory(issuesLoader, dbClient, movedFilesRepository);
tracker = new TrackerExecution(baseInputFactory, rawInputFactory, closedIssuesInputFactory, new Tracker<>(), issuesLoader, analysisMetadataHolder);
shortBranchTracker = new ShortBranchOrPullRequestTrackerExecution(baseInputFactory, rawInputFactory, mergeInputFactory, new Tracker<>(), newLinesRepository);
@@ -155,7 +155,7 @@ public class IntegrateIssuesVisitorTest {
treeRootHolder.setRoot(PROJECT);
issueCache = new IssueCache(temp.newFile(), System2.INSTANCE);
when(issueFilter.accept(any(DefaultIssue.class), eq(FILE))).thenReturn(true);
underTest = new IntegrateIssuesVisitor(issueCache, issueLifecycle, issueVisitors, analysisMetadataHolder, trackingDelegator, issueStatusCopier, mergeBranchComponentUuids);
underTest = new IntegrateIssuesVisitor(issueCache, issueLifecycle, issueVisitors, analysisMetadataHolder, trackingDelegator, issueStatusCopier, mergeAndTargetBranchComponentUuids);
}

@Test
@@ -262,8 +262,8 @@ public class IntegrateIssuesVisitorTest {
@Test
public void copy_issues_when_creating_new_long_living_branch() {

when(mergeBranchComponentsUuids.getUuid(FILE_KEY)).thenReturn(FILE_UUID_ON_BRANCH);
when(mergeBranchComponentUuids.getMergeBranchName()).thenReturn("master");
when(mergeBranchComponentsUuids.getMergeBranchComponentUuid(FILE_KEY)).thenReturn(FILE_UUID_ON_BRANCH);
when(mergeAndTargetBranchComponentUuids.getMergeBranchName()).thenReturn("master");

when(analysisMetadataHolder.isLongLivingBranch()).thenReturn(true);
when(analysisMetadataHolder.isFirstAnalysis()).thenReturn(true);

+ 2
- 2
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/MergeBranchTrackerExecutionTest.java View File

@@ -37,7 +37,7 @@ public class MergeBranchTrackerExecutionTest {
@Mock
private TrackerRawInputFactory rawInputFactory;
@Mock
private TrackerMergeBranchInputFactory mergeInputFactory;
private TrackerMergeOrTargetBranchInputFactory mergeInputFactory;
@Mock
private Tracker<DefaultIssue, DefaultIssue> tracker;
@Mock
@@ -57,7 +57,7 @@ public class MergeBranchTrackerExecutionTest {
Input<DefaultIssue> mergeInput = mock(Input.class);
NonClosedTracking<DefaultIssue, DefaultIssue> result = mock(NonClosedTracking.class);
when(rawInputFactory.create(component)).thenReturn(rawInput);
when(mergeInputFactory.create(component)).thenReturn(mergeInput);
when(mergeInputFactory.createForMergeBranch(component)).thenReturn(mergeInput);
when(tracker.trackNonClosed(rawInput, mergeInput)).thenReturn(result);

assertThat(underTest.track(component)).isEqualTo(result);

+ 45
- 3
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/ShortBranchOrPullRequestTrackerExecutionTest.java View File

@@ -62,7 +62,7 @@ public class ShortBranchOrPullRequestTrackerExecutionTest {
@Mock
private TrackerBaseInputFactory baseFactory;
@Mock
private TrackerMergeBranchInputFactory mergeFactory;
private TrackerMergeOrTargetBranchInputFactory mergeFactory;
@Mock
private NewLinesRepository newLinesRepository;

@@ -71,6 +71,7 @@ public class ShortBranchOrPullRequestTrackerExecutionTest {
private List<DefaultIssue> rawIssues = new ArrayList<>();
private List<DefaultIssue> baseIssues = new ArrayList<>();
private List<DefaultIssue> mergeBranchIssues = new ArrayList<>();
private List<DefaultIssue> targetBranchIssues = new ArrayList<>();

@Before
public void setUp() throws Exception {
@@ -78,7 +79,8 @@ public class ShortBranchOrPullRequestTrackerExecutionTest {

when(rawFactory.create(FILE)).thenReturn(createInput(rawIssues));
when(baseFactory.create(FILE)).thenReturn(createInput(baseIssues));
when(mergeFactory.create(FILE)).thenReturn(createInput(mergeBranchIssues));
when(mergeFactory.createForMergeBranch(FILE)).thenReturn(createInput(mergeBranchIssues));
when(mergeFactory.createForTargetBranch(FILE)).thenReturn(createInput(targetBranchIssues));

Tracker<DefaultIssue, DefaultIssue> tracker = new Tracker<>();
underTest = new ShortBranchOrPullRequestTrackerExecution(baseFactory, rawFactory, mergeFactory, tracker, newLinesRepository);
@@ -95,6 +97,7 @@ public class ShortBranchOrPullRequestTrackerExecutionTest {
rawIssues.add(issue2);

when(mergeFactory.hasMergeBranchAnalysis()).thenReturn(false);
when(mergeFactory.hasTargetBranchAnalysis()).thenReturn(true);
when(newLinesRepository.getNewLines(FILE)).thenReturn(Optional.of(new HashSet<>(Arrays.asList(1, 3))));

Tracking<DefaultIssue, DefaultIssue> tracking = underTest.track(FILE);
@@ -132,6 +135,7 @@ public class ShortBranchOrPullRequestTrackerExecutionTest {
rawIssues.add(issueWithALocationOnADifferentFile);

when(mergeFactory.hasMergeBranchAnalysis()).thenReturn(false);
when(mergeFactory.hasTargetBranchAnalysis()).thenReturn(false);
when(newLinesRepository.getNewLines(FILE)).thenReturn(Optional.of(new HashSet<>(Arrays.asList(7, 10))));

Tracking<DefaultIssue, DefaultIssue> tracking = underTest.track(FILE);
@@ -142,12 +146,14 @@ public class ShortBranchOrPullRequestTrackerExecutionTest {
}

@Test
public void tracking_with_all_results() {
public void track_and_ignore_issues_from_merge_branch() {
rawIssues.add(createIssue(1, RuleTesting.XOO_X1));
rawIssues.add(createIssue(2, RuleTesting.XOO_X2));
rawIssues.add(createIssue(3, RuleTesting.XOO_X3));

when(mergeFactory.hasMergeBranchAnalysis()).thenReturn(true);
when(mergeFactory.hasTargetBranchAnalysis()).thenReturn(true);
when(mergeFactory.areTargetAndMergeBranchesDifferent()).thenReturn(true);
mergeBranchIssues.add(rawIssues.get(0));

baseIssues.add(rawIssues.get(0));
@@ -158,6 +164,42 @@ public class ShortBranchOrPullRequestTrackerExecutionTest {
assertThat(tracking.getUnmatchedRaws()).containsOnly(rawIssues.get(2));
}

@Test
public void track_and_ignore_issues_from_target_branch() {
rawIssues.add(createIssue(1, RuleTesting.XOO_X1));
rawIssues.add(createIssue(2, RuleTesting.XOO_X2));
rawIssues.add(createIssue(3, RuleTesting.XOO_X3));

when(mergeFactory.hasMergeBranchAnalysis()).thenReturn(true);
when(mergeFactory.hasTargetBranchAnalysis()).thenReturn(true);
when(mergeFactory.areTargetAndMergeBranchesDifferent()).thenReturn(true);
targetBranchIssues.add(rawIssues.get(0));

baseIssues.add(rawIssues.get(0));
baseIssues.add(rawIssues.get(1));

Tracking<DefaultIssue, DefaultIssue> tracking = underTest.track(FILE);
assertThat(tracking.getMatchedRaws()).isEqualTo(Collections.singletonMap(rawIssues.get(1), rawIssues.get(1)));
assertThat(tracking.getUnmatchedRaws()).containsOnly(rawIssues.get(2));
}

@Test
public void track_and_ignore_issues_from_merge_and_target_branch() {
rawIssues.add(createIssue(1, RuleTesting.XOO_X1));
rawIssues.add(createIssue(2, RuleTesting.XOO_X2));
rawIssues.add(createIssue(3, RuleTesting.XOO_X3));

when(mergeFactory.hasMergeBranchAnalysis()).thenReturn(true);
when(mergeFactory.hasTargetBranchAnalysis()).thenReturn(true);
when(mergeFactory.areTargetAndMergeBranchesDifferent()).thenReturn(true);
mergeBranchIssues.add(rawIssues.get(0));
targetBranchIssues.add(rawIssues.get(1));

Tracking<DefaultIssue, DefaultIssue> tracking = underTest.track(FILE);
assertThat(tracking.getMatchedRaws()).isEmpty();
assertThat(tracking.getUnmatchedRaws()).containsOnly(rawIssues.get(2));
}

private DefaultIssue createIssue(int line, RuleKey ruleKey) {
DefaultIssue issue = new DefaultIssue()
.setRuleKey(ruleKey)

+ 4
- 4
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/scm/ScmInfoDbLoaderTest.java View File

@@ -33,7 +33,7 @@ import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolderRule;
import org.sonar.ce.task.projectanalysis.analysis.Branch;
import org.sonar.ce.task.projectanalysis.batch.BatchReportReaderRule;
import org.sonar.ce.task.projectanalysis.component.Component;
import org.sonar.ce.task.projectanalysis.component.MergeBranchComponentUuids;
import org.sonar.ce.task.projectanalysis.component.MergeAndTargetBranchComponentUuids;
import org.sonar.core.hash.SourceHashComputer;
import org.sonar.db.DbTester;
import org.sonar.db.protobuf.DbFileSources;
@@ -67,9 +67,9 @@ public class ScmInfoDbLoaderTest {
public BatchReportReaderRule reportReader = new BatchReportReaderRule();

private Branch branch = mock(Branch.class);
private MergeBranchComponentUuids mergeBranchComponentUuids = mock(MergeBranchComponentUuids.class);
private MergeAndTargetBranchComponentUuids mergeAndTargetBranchComponentUuids = mock(MergeAndTargetBranchComponentUuids.class);

private ScmInfoDbLoader underTest = new ScmInfoDbLoader(analysisMetadataHolder, dbTester.getDbClient(), mergeBranchComponentUuids);
private ScmInfoDbLoader underTest = new ScmInfoDbLoader(analysisMetadataHolder, dbTester.getDbClient(), mergeAndTargetBranchComponentUuids);

@Test
public void returns_ScmInfo_from_DB() {
@@ -95,7 +95,7 @@ public class ScmInfoDbLoaderTest {
String hash = computeSourceHash(1);
when(branch.getMergeBranchUuid()).thenReturn("mergeBranchUuid");

when(mergeBranchComponentUuids.getUuid(FILE.getDbKey())).thenReturn(mergeFileUuid);
when(mergeAndTargetBranchComponentUuids.getMergeBranchComponentUuid(FILE.getDbKey())).thenReturn(mergeFileUuid);
addFileSourceInDb("henry", DATE_1, "rev-1", hash, mergeFileUuid);

DbScmInfo scmInfo = underTest.getScmInfo(FILE).get();

+ 2
- 1
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java View File

@@ -304,7 +304,8 @@ public class ProjectScanContainer extends ComponentContainer {

BranchConfiguration branchConfig = getComponentByType(BranchConfiguration.class);
if (branchConfig.branchType() == BranchType.PULL_REQUEST) {
LOG.info("Pull request {} for merge into {} from {}", branchConfig.pullRequestKey(), pullRequestBaseToDisplayName(branchConfig.targetBranchName()), branchConfig.branchName());
LOG.info("Pull request {} for merge into {} from {}", branchConfig.pullRequestKey(), pullRequestBaseToDisplayName(branchConfig.targetBranchName()),
branchConfig.branchName());
} else if (branchConfig.branchName() != null) {
LOG.info("Branch name: {}, type: {}", branchConfig.branchName(), branchTypeToDisplayName(branchConfig.branchType()));
}

Loading…
Cancel
Save