Browse Source

SONAR-12802 SONAR-12927 Fix moved file detection for cobol and when calculating new lines

tags/8.2.0.32929
Duarte Meneses 4 years ago
parent
commit
5cb5deb5e5
24 changed files with 117 additions and 104 deletions
  1. 42
    43
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/filemove/FileMoveDetectionStep.java
  2. 2
    16
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/filemove/FileSimilarity.java
  3. 2
    2
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/filemove/MovedFilesRepository.java
  4. 3
    3
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/filemove/MutableMovedFilesRepositoryImpl.java
  5. 1
    1
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/ClosedIssuesInputFactory.java
  6. 1
    1
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/MovedIssueVisitor.java
  7. 1
    1
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/RemoveProcessedComponentsVisitor.java
  8. 1
    1
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/TrackerBaseInputFactory.java
  9. 9
    1
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/scm/ScmInfoDbLoader.java
  10. 10
    1
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/source/DbLineHashVersion.java
  11. 0
    1
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/source/PersistFileSourcesStep.java
  12. 7
    2
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/source/SourceLinesDiffImpl.java
  13. 3
    2
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/source/SourceLinesHashRepositoryImpl.java
  14. 3
    4
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/filemove/MutableMovedFilesRepositoryImplTest.java
  15. 1
    1
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/filemove/MutableMovedFilesRepositoryRule.java
  16. 3
    3
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/ClosedIssuesInputFactoryTest.java
  17. 2
    2
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/IntegrateIssuesVisitorTest.java
  18. 2
    2
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/MovedIssueVisitorTest.java
  19. 2
    2
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/RemoveProcessedComponentsVisitorTest.java
  20. 2
    2
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/TrackerBaseInputFactoryTest.java
  21. 4
    1
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/scm/ScmInfoDbLoaderTest.java
  22. 5
    1
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/source/SourceLinesDiffImplTest.java
  23. 8
    8
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/source/SourceLinesHashRepositoryImplTest.java
  24. 3
    3
      server/sonar-db-dao/src/main/java/org/sonar/db/source/FileSourceDao.java

+ 42
- 43
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/filemove/FileMoveDetectionStep.java View File

@@ -26,6 +26,7 @@ import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
@@ -33,6 +34,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import org.apache.ibatis.session.ResultContext;
@@ -57,7 +59,6 @@ import org.sonar.db.DbSession;
import org.sonar.db.component.FileMoveRowDto;
import org.sonar.db.source.LineHashesWithUuidDto;

import static com.google.common.collect.FluentIterable.from;
import static org.sonar.ce.task.projectanalysis.component.ComponentVisitor.Order.POST_ORDER;

public class FileMoveDetectionStep implements ComputationStep {
@@ -125,7 +126,7 @@ public class FileMoveDetectionStep implements ComputationStep {

Set<String> removedFileUuids = difference(dbFilesByUuid.keySet(), reportFilesByUuid.keySet());

// can find matches if at least one of the added or removed files groups is empty => abort
// can't find matches if at least one of the added or removed files groups is empty => abort
if (addedFileUuids.isEmpty() || removedFileUuids.isEmpty()) {
registerAddedFiles(addedFileUuids, reportFilesByUuid, null);
LOG.debug("Either no files added or no files removed. Do nothing.");
@@ -133,12 +134,12 @@ public class FileMoveDetectionStep implements ComputationStep {
}

// retrieve file data from report
Map<String, File> reportFileSourcesByUuid = getReportFileSourcesByUuid(reportFilesByUuid, addedFileUuids);
Map<String, File> addedFileHashesByUuid = getReportFileHashesByUuid(reportFilesByUuid, addedFileUuids);
p.stopTrace("loaded");

// compute score matrix
p.start();
ScoreMatrix scoreMatrix = computeScoreMatrix(dbFilesByUuid, removedFileUuids, reportFileSourcesByUuid);
ScoreMatrix scoreMatrix = computeScoreMatrix(dbFilesByUuid, removedFileUuids, addedFileHashesByUuid);
p.stopTrace("Score matrix computed");
scoreMatrixDumper.dumpAsCsv(scoreMatrix);

@@ -153,7 +154,7 @@ public class FileMoveDetectionStep implements ComputationStep {
p.start();
MatchesByScore matchesByScore = MatchesByScore.create(scoreMatrix);

ElectedMatches electedMatches = electMatches(removedFileUuids, reportFileSourcesByUuid, matchesByScore);
ElectedMatches electedMatches = electMatches(removedFileUuids, addedFileHashesByUuid, matchesByScore);
p.stopTrace("Matches elected");

context.getStatistics().add("movedFiles", electedMatches.size());
@@ -219,25 +220,21 @@ public class FileMoveDetectionStep implements ComputationStep {
return builder.build();
}

private Map<String, File> getReportFileSourcesByUuid(Map<String, Component> reportFilesByUuid, Set<String> addedFileUuids) {
ImmutableMap.Builder<String, File> builder = ImmutableMap.builder();
for (String fileUuid : addedFileUuids) {
private Map<String, File> getReportFileHashesByUuid(Map<String, Component> reportFilesByUuid, Set<String> addedFileUuids) {
return addedFileUuids.stream().collect(Collectors.toMap(fileUuid -> fileUuid, fileUuid -> {
Component component = reportFilesByUuid.get(fileUuid);
File file = new LazyFileImpl(
component.getName(),
() -> getReportFileLineHashes(component),
component.getFileAttributes().getLines());
builder.put(fileUuid, file);
}
return builder.build();
return new LazyFileImpl(() -> getReportFileLineHashes(component), component.getFileAttributes().getLines());
}));
}

private List<String> getReportFileLineHashes(Component component) {
// this is not ideal because if the file moved, this component won't exist in DB with the same UUID.
// Assuming that the file also had significant code before the move, it will be fine.
return sourceLinesHash.getLineHashesMatchingDBVersion(component);
}

private ScoreMatrix computeScoreMatrix(Map<String, DbComponent> dtosByUuid, Set<String> removedFileUuids, Map<String, File> newFileSourcesByUuid) {
ScoreMatrix.ScoreFile[] newFiles = newFileSourcesByUuid.entrySet().stream()
private ScoreMatrix computeScoreMatrix(Map<String, DbComponent> dtosByUuid, Set<String> removedFileUuids, Map<String, File> addedFileHashesByUuid) {
ScoreMatrix.ScoreFile[] addedFiles = addedFileHashesByUuid.entrySet().stream()
.map(e -> new ScoreMatrix.ScoreFile(e.getKey(), e.getValue().getLineCount()))
.toArray(ScoreMatrix.ScoreFile[]::new);
ScoreMatrix.ScoreFile[] removedFiles = removedFileUuids.stream()
@@ -246,48 +243,50 @@ public class FileMoveDetectionStep implements ComputationStep {
return new ScoreMatrix.ScoreFile(dbComponent.getUuid(), dbComponent.getLineCount());
})
.toArray(ScoreMatrix.ScoreFile[]::new);

// sort by highest line count first
Arrays.sort(newFiles, SCORE_FILE_COMPARATOR);
Arrays.sort(addedFiles, SCORE_FILE_COMPARATOR);
Arrays.sort(removedFiles, SCORE_FILE_COMPARATOR);
int[][] scoreMatrix = new int[removedFiles.length][newFiles.length];
int lastNewFileIndex = newFiles.length - 1;
int[][] scoreMatrix = new int[removedFiles.length][addedFiles.length];
int smallestAddedFileSize = addedFiles[0].getLineCount();
int largestAddedFileSize = addedFiles[addedFiles.length - 1].getLineCount();

Map<String, Integer> removedFilesIndexes = new HashMap<>(removedFileUuids.size());
Map<String, Integer> removedFilesIndexesByUuid = new HashMap<>(removedFileUuids.size());
for (int removeFileIndex = 0; removeFileIndex < removedFiles.length; removeFileIndex++) {
ScoreMatrix.ScoreFile removedFile = removedFiles[removeFileIndex];
int lowerBound = (int) Math.floor(removedFile.getLineCount() * LOWER_BOUND_RATIO);
int upperBound = (int) Math.ceil(removedFile.getLineCount() * UPPER_BOUND_RATIO);
// no need to compute score if all files are out of bound, so no need to load line hashes from DB
if (newFiles[0].getLineCount() <= lowerBound || newFiles[lastNewFileIndex].getLineCount() >= upperBound) {
if (smallestAddedFileSize <= lowerBound || largestAddedFileSize >= upperBound) {
continue;
}
removedFilesIndexes.put(removedFile.getFileUuid(), removeFileIndex);
removedFilesIndexesByUuid.put(removedFile.getFileUuid(), removeFileIndex);
}

LineHashesWithKeyDtoResultHandler rowHandler = new LineHashesWithKeyDtoResultHandler(removedFilesIndexes, removedFiles,
newFiles, newFileSourcesByUuid, scoreMatrix);
LineHashesWithKeyDtoResultHandler rowHandler = new LineHashesWithKeyDtoResultHandler(removedFilesIndexesByUuid, removedFiles,
addedFiles, addedFileHashesByUuid, scoreMatrix);
try (DbSession dbSession = dbClient.openSession(false)) {
dbClient.fileSourceDao().scrollLineHashes(dbSession, removedFilesIndexes.keySet(), rowHandler);
dbClient.fileSourceDao().scrollLineHashes(dbSession, removedFilesIndexesByUuid.keySet(), rowHandler);
}

return new ScoreMatrix(removedFiles, newFiles, scoreMatrix, rowHandler.getMaxScore());
return new ScoreMatrix(removedFiles, addedFiles, scoreMatrix, rowHandler.getMaxScore());
}

private final class LineHashesWithKeyDtoResultHandler implements ResultHandler<LineHashesWithUuidDto> {
private final Map<String, Integer> removedFilesIndexes;
private final Map<String, Integer> removedFileIndexesByUuid;
private final ScoreMatrix.ScoreFile[] removedFiles;
private final ScoreMatrix.ScoreFile[] newFiles;
private final Map<String, File> newFileSourcesByKey;
private final Map<String, File> newFilesByUuid;
private final int[][] scoreMatrix;
private int maxScore;

private LineHashesWithKeyDtoResultHandler(Map<String, Integer> removedFilesIndexes, ScoreMatrix.ScoreFile[] removedFiles,
ScoreMatrix.ScoreFile[] newFiles, Map<String, File> newFileSourcesByKey,
private LineHashesWithKeyDtoResultHandler(Map<String, Integer> removedFileIndexesByUuid, ScoreMatrix.ScoreFile[] removedFiles,
ScoreMatrix.ScoreFile[] newFiles, Map<String, File> newFilesByUuid,
int[][] scoreMatrix) {
this.removedFilesIndexes = removedFilesIndexes;
this.removedFileIndexesByUuid = removedFileIndexesByUuid;
this.removedFiles = removedFiles;
this.newFiles = newFiles;
this.newFileSourcesByKey = newFileSourcesByKey;
this.newFilesByUuid = newFilesByUuid;
this.scoreMatrix = scoreMatrix;
}

@@ -297,8 +296,8 @@ public class FileMoveDetectionStep implements ComputationStep {
if (lineHashesDto.getPath() == null) {
return;
}
int removeFileIndex = removedFilesIndexes.get(lineHashesDto.getUuid());
ScoreMatrix.ScoreFile removedFile = removedFiles[removeFileIndex];
int removedFileIndex = removedFileIndexesByUuid.get(lineHashesDto.getUuid());
ScoreMatrix.ScoreFile removedFile = removedFiles[removedFileIndex];
int lowerBound = (int) Math.floor(removedFile.getLineCount() * LOWER_BOUND_RATIO);
int upperBound = (int) Math.ceil(removedFile.getLineCount() * UPPER_BOUND_RATIO);

@@ -311,10 +310,10 @@ public class FileMoveDetectionStep implements ComputationStep {
break;
}

File fileInDb = new FileImpl(lineHashesDto.getPath(), lineHashesDto.getLineHashes());
File unmatchedFile = newFileSourcesByKey.get(newFile.getFileUuid());
int score = fileSimilarity.score(fileInDb, unmatchedFile);
scoreMatrix[removeFileIndex][newFileIndex] = score;
File fileHashesInDb = new FileImpl(lineHashesDto.getLineHashes());
File unmatchedFile = newFilesByUuid.get(newFile.getFileUuid());
int score = fileSimilarity.score(fileHashesInDb, unmatchedFile);
scoreMatrix[removedFileIndex][newFileIndex] = score;
if (score > maxScore) {
maxScore = score;
}
@@ -408,9 +407,9 @@ public class FileMoveDetectionStep implements ComputationStep {
private final List<Match> matches;
private final Set<String> matchedFileUuids;

public ElectedMatches(MatchesByScore matchesByScore, Set<String> dbFileUuids, Map<String, File> reportFileSourcesByUuid) {
public ElectedMatches(MatchesByScore matchesByScore, Set<String> dbFileUuids, Map<String, File> reportFileHashesByUuid) {
this.matches = new ArrayList<>(matchesByScore.getSize());
this.matchedFileUuids = new HashSet<>(dbFileUuids.size() + reportFileSourcesByUuid.size());
this.matchedFileUuids = new HashSet<>(dbFileUuids.size() + reportFileHashesByUuid.size());
}

public void add(Match match) {
@@ -419,8 +418,8 @@ public class FileMoveDetectionStep implements ComputationStep {
matchedFileUuids.add(match.getReportUuid());
}

public List<Match> filter(Iterable<Match> matches) {
return from(matches).filter(this::notAlreadyMatched).toList();
public List<Match> filter(Collection<Match> matches) {
return matches.stream().filter(this::notAlreadyMatched).collect(Collectors.toList());
}

private boolean notAlreadyMatched(Match input) {

+ 2
- 16
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/filemove/FileSimilarity.java View File

@@ -29,28 +29,20 @@ import static java.util.Objects.requireNonNull;
public interface FileSimilarity {

interface File {
String getPath();

List<String> getLineHashes();

int getLineCount();
}

final class FileImpl implements File {
private final String path;
private final List<String> lineHashes;
private final int lineCount;

FileImpl(String path, List<String> lineHashes) {
this.path = requireNonNull(path, "path can not be null");
FileImpl(List<String> lineHashes) {
this.lineHashes = requireNonNull(lineHashes, "lineHashes can not be null");
this.lineCount = lineHashes.size();
}

public String getPath() {
return path;
}

/**
* List of hash of each line. An empty list is returned
* if file content is empty.
@@ -65,21 +57,15 @@ public interface FileSimilarity {
}

final class LazyFileImpl implements File {
private final String path;
private final Supplier<List<String>> supplier;
private final int lineCount;
private List<String> lineHashes;

LazyFileImpl(String path, Supplier<List<String>> supplier, int lineCount) {
this.path = requireNonNull(path, "path can not be null");
LazyFileImpl(Supplier<List<String>> supplier, int lineCount) {
this.supplier = requireNonNull(supplier, "supplier can not be null");
this.lineCount = lineCount;
}

public String getPath() {
return path;
}

/**
* List of hash of each line. An empty list is returned
* if file content is empty.

+ 2
- 2
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/filemove/MovedFilesRepository.java View File

@@ -19,7 +19,7 @@
*/
package org.sonar.ce.task.projectanalysis.filemove;

import com.google.common.base.Optional;
import java.util.Optional;
import javax.annotation.Nullable;
import org.sonar.ce.task.projectanalysis.component.Component;

@@ -29,7 +29,7 @@ public interface MovedFilesRepository {
/**
* The original file for the specified component if it was registered as a moved file in the repository.
* <p>
* Calling this method with a Component which is not a file, will always return {@link Optional#absent()}.
* Calling this method with a Component which is not a file, will always return {@link Optional#empty()}.
* </p>
*/
Optional<OriginalFile> getOriginalFile(Component file);

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

@@ -19,9 +19,9 @@
*/
package org.sonar.ce.task.projectanalysis.filemove;

import com.google.common.base.Optional;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import org.sonar.ce.task.projectanalysis.component.Component;

import static com.google.common.base.Preconditions.checkArgument;
@@ -49,9 +49,9 @@ public class MutableMovedFilesRepositoryImpl implements MutableMovedFilesReposit
public Optional<OriginalFile> getOriginalFile(Component file) {
requireNonNull(file, "file can't be null");
if (file.getType() != Component.Type.FILE) {
return Optional.absent();
return Optional.empty();
}

return Optional.fromNullable(originalFiles.get(file.getDbKey()));
return Optional.ofNullable(originalFiles.get(file.getDbKey()));
}
}

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

@@ -39,7 +39,7 @@ public class ClosedIssuesInputFactory extends BaseInputFactory {
}

public Input<DefaultIssue> create(Component component) {
return new ClosedIssuesLazyInput(dbClient, component, movedFilesRepository.getOriginalFile(component).orNull());
return new ClosedIssuesLazyInput(dbClient, component, movedFilesRepository.getOriginalFile(component).orElse(null));
}

private class ClosedIssuesLazyInput extends BaseLazyInput {

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

@@ -19,8 +19,8 @@
*/
package org.sonar.ce.task.projectanalysis.issue;

import com.google.common.base.Optional;
import java.util.Date;
import java.util.Optional;
import org.sonar.ce.task.projectanalysis.component.Component;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.IssueChangeContext;

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

@@ -19,7 +19,7 @@
*/
package org.sonar.ce.task.projectanalysis.issue;

import com.google.common.base.Optional;
import java.util.Optional;
import org.sonar.ce.task.projectanalysis.component.Component;
import org.sonar.ce.task.projectanalysis.filemove.MovedFilesRepository;


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

@@ -63,7 +63,7 @@ public class TrackerBaseInputFactory extends BaseInputFactory {
// Folders have no issues
return new EmptyTrackerBaseLazyInput(dbClient, component);
}
return new FileTrackerBaseLazyInput(dbClient, component, movedFilesRepository.getOriginalFile(component).orNull());
return new FileTrackerBaseLazyInput(dbClient, component, movedFilesRepository.getOriginalFile(component).orElse(null));
}

private class FileTrackerBaseLazyInput extends BaseLazyInput {

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

@@ -26,6 +26,7 @@ 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.ReferenceBranchComponentUuids;
import org.sonar.ce.task.projectanalysis.filemove.MovedFilesRepository;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.source.FileSourceDto;
@@ -34,11 +35,14 @@ public class ScmInfoDbLoader {
private static final Logger LOGGER = Loggers.get(ScmInfoDbLoader.class);

private final AnalysisMetadataHolder analysisMetadataHolder;
private final MovedFilesRepository movedFilesRepository;
private final DbClient dbClient;
private final ReferenceBranchComponentUuids referenceBranchComponentUuid;

public ScmInfoDbLoader(AnalysisMetadataHolder analysisMetadataHolder, DbClient dbClient, ReferenceBranchComponentUuids referenceBranchComponentUuid) {
public ScmInfoDbLoader(AnalysisMetadataHolder analysisMetadataHolder, MovedFilesRepository movedFilesRepository, DbClient dbClient,
ReferenceBranchComponentUuids referenceBranchComponentUuid) {
this.analysisMetadataHolder = analysisMetadataHolder;
this.movedFilesRepository = movedFilesRepository;
this.dbClient = dbClient;
this.referenceBranchComponentUuid = referenceBranchComponentUuid;
}
@@ -61,6 +65,10 @@ public class ScmInfoDbLoader {

private Optional<String> getFileUUid(Component file) {
if (!analysisMetadataHolder.isFirstAnalysis() && !analysisMetadataHolder.isPullRequest()) {
Optional<MovedFilesRepository.OriginalFile> originalFile = movedFilesRepository.getOriginalFile(file);
if (originalFile.isPresent()) {
return originalFile.map(MovedFilesRepository.OriginalFile::getUuid);
}
return Optional.of(file.getUuid());
}


+ 10
- 1
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/source/DbLineHashVersion.java View File

@@ -42,7 +42,7 @@ public class DbLineHashVersion {
}

/**
* Reads from DB the version of line hashes for a component and returns if it was generated taking into account the ranges of significant code.
* Reads from DB the version of line hashes for a component and returns whether it was generated taking into account the ranges of significant code.
* The response is cached.
* Returns false if the component is not in the DB.
*/
@@ -50,6 +50,15 @@ public class DbLineHashVersion {
return lineHashVersionPerComponent.computeIfAbsent(component, this::compute) == LineHashVersion.WITH_SIGNIFICANT_CODE;
}

/**
* Reads from DB the version of line hashes for a component and returns whether it was generated taking into account the ranges of significant code.
* The response is cached.
* Returns false if the component is not in the DB.
*/
public boolean hasLineHashesWithoutSignificantCode(Component component) {
return lineHashVersionPerComponent.computeIfAbsent(component, this::compute) == LineHashVersion.WITHOUT_SIGNIFICANT_CODE;
}

@CheckForNull
private LineHashVersion compute(Component component) {
try (DbSession session = dbClient.openSession(false)) {

+ 0
- 1
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/source/PersistFileSourcesStep.java View File

@@ -113,7 +113,6 @@ public class PersistFileSourcesStep implements ComputationStep {
Changeset latestChangeWithRevision = fileSourceData.getLatestChangeWithRevision();
int lineHashesVersion = sourceLinesHash.getLineHashesVersion(file);
FileSourceDto previousDto = previousFileSourcesByUuid.get(file.getUuid());

if (previousDto == null) {
FileSourceDto dto = new FileSourceDto()
.setProjectUuid(projectUuid)

+ 7
- 2
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/source/SourceLinesDiffImpl.java View File

@@ -21,9 +21,11 @@ package org.sonar.ce.task.projectanalysis.source;

import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
import org.sonar.ce.task.projectanalysis.component.Component;
import org.sonar.ce.task.projectanalysis.component.ReferenceBranchComponentUuids;
import org.sonar.ce.task.projectanalysis.filemove.MovedFilesRepository;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.source.FileSourceDao;
@@ -34,14 +36,16 @@ public class SourceLinesDiffImpl implements SourceLinesDiff {
private final FileSourceDao fileSourceDao;
private final SourceLinesHashRepository sourceLinesHash;
private final ReferenceBranchComponentUuids referenceBranchComponentUuids;
private final MovedFilesRepository movedFilesRepository;
private final AnalysisMetadataHolder analysisMetadataHolder;

public SourceLinesDiffImpl(DbClient dbClient, FileSourceDao fileSourceDao, SourceLinesHashRepository sourceLinesHash,
ReferenceBranchComponentUuids referenceBranchComponentUuids, AnalysisMetadataHolder analysisMetadataHolder) {
ReferenceBranchComponentUuids referenceBranchComponentUuids, MovedFilesRepository movedFilesRepository, AnalysisMetadataHolder analysisMetadataHolder) {
this.dbClient = dbClient;
this.fileSourceDao = fileSourceDao;
this.sourceLinesHash = sourceLinesHash;
this.referenceBranchComponentUuids = referenceBranchComponentUuids;
this.movedFilesRepository = movedFilesRepository;
this.analysisMetadataHolder = analysisMetadataHolder;
}

@@ -59,7 +63,8 @@ public class SourceLinesDiffImpl implements SourceLinesDiff {
if (analysisMetadataHolder.isPullRequest()) {
uuid = referenceBranchComponentUuids.getComponentUuid(component.getDbKey());
} else {
uuid = component.getUuid();
Optional<MovedFilesRepository.OriginalFile> originalFile = movedFilesRepository.getOriginalFile(component);
uuid = originalFile.map(MovedFilesRepository.OriginalFile::getUuid).orElse(component.getUuid());
}

if (uuid == null) {

+ 3
- 2
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/source/SourceLinesHashRepositoryImpl.java View File

@@ -61,7 +61,7 @@ public class SourceLinesHashRepositoryImpl implements SourceLinesHashRepository
boolean cacheHit = cache.contains(component);

// check if line hashes are cached and if we can use it
if (cacheHit && dbLineHashesVersion.hasLineHashesWithSignificantCode(component)) {
if (cacheHit && !dbLineHashesVersion.hasLineHashesWithoutSignificantCode(component)) {
return new CachedLineHashesComputer(cache.get(component));
}

@@ -75,10 +75,11 @@ public class SourceLinesHashRepositoryImpl implements SourceLinesHashRepository
}

private List<String> createLineHashesMatchingDBVersion(Component component) {
if (!dbLineHashesVersion.hasLineHashesWithSignificantCode(component)) {
if (dbLineHashesVersion.hasLineHashesWithoutSignificantCode(component)) {
return createLineHashes(component, Optional.empty());
}

// if the file is not in the DB, this will be used too
Optional<LineRange[]> significantCodePerLine = significantCodeRepository.getRangesPerLine(component);
return createLineHashes(component, significantCodePerLine);
}

+ 3
- 4
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/filemove/MutableMovedFilesRepositoryImplTest.java View File

@@ -28,7 +28,6 @@ import org.sonar.ce.task.projectanalysis.component.ViewsComponent;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import static org.assertj.guava.api.Assertions.assertThat;
import static org.sonar.ce.task.projectanalysis.component.ReportComponent.builder;

public class MutableMovedFilesRepositoryImplTest {
@@ -113,9 +112,9 @@ public class MutableMovedFilesRepositoryImplTest {

@Test
public void getOriginalFile_returns_absent_for_any_component_type_when_empty() {
assertThat(underTest.getOriginalFile(SOME_FILE)).isAbsent();
assertThat(underTest.getOriginalFile(SOME_FILE)).isEmpty();
for (Component component : COMPONENTS_EXCEPT_FILE) {
assertThat(underTest.getOriginalFile(component)).isAbsent();
assertThat(underTest.getOriginalFile(component)).isEmpty();
}
}

@@ -124,7 +123,7 @@ public class MutableMovedFilesRepositoryImplTest {
underTest.setOriginalFile(SOME_FILE, SOME_ORIGINAL_FILE);

for (Component component : COMPONENTS_EXCEPT_FILE) {
assertThat(underTest.getOriginalFile(component)).isAbsent();
assertThat(underTest.getOriginalFile(component)).isEmpty();
}
assertThat(underTest.getOriginalFile(SOME_FILE)).contains(SOME_ORIGINAL_FILE);
}

+ 1
- 1
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/filemove/MutableMovedFilesRepositoryRule.java View File

@@ -19,8 +19,8 @@
*/
package org.sonar.ce.task.projectanalysis.filemove;

import com.google.common.base.Optional;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import javax.annotation.CheckForNull;
import org.junit.rules.ExternalResource;

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

@@ -19,9 +19,9 @@
*/
package org.sonar.ce.task.projectanalysis.issue;

import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import java.util.List;
import java.util.Optional;
import org.junit.Test;
import org.sonar.ce.task.projectanalysis.component.Component;
import org.sonar.ce.task.projectanalysis.component.ReportComponent;
@@ -47,7 +47,7 @@ public class ClosedIssuesInputFactoryTest {
public void underTest_returns_inputFactory_loading_closed_issues_only_when_getIssues_is_called() {
String componentUuid = randomAlphanumeric(12);
ReportComponent component = ReportComponent.builder(Component.Type.FILE, 1).setUuid(componentUuid).build();
when(movedFilesRepository.getOriginalFile(component)).thenReturn(Optional.absent());
when(movedFilesRepository.getOriginalFile(component)).thenReturn(Optional.empty());

Input<DefaultIssue> input = underTest.create(component);

@@ -81,7 +81,7 @@ public class ClosedIssuesInputFactoryTest {
public void underTest_returns_inputFactory_which_caches_loaded_issues() {
String componentUuid = randomAlphanumeric(12);
ReportComponent component = ReportComponent.builder(Component.Type.FILE, 1).setUuid(componentUuid).build();
when(movedFilesRepository.getOriginalFile(component)).thenReturn(Optional.absent());
when(movedFilesRepository.getOriginalFile(component)).thenReturn(Optional.empty());

Input<DefaultIssue> input = underTest.create(component);


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

@@ -19,8 +19,8 @@
*/
package org.sonar.ce.task.projectanalysis.issue;

import com.google.common.base.Optional;
import java.util.List;
import java.util.Optional;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -140,7 +140,7 @@ public class IntegrateIssuesVisitorTest {
IssueVisitors issueVisitors = new IssueVisitors(new IssueVisitor[] {issueVisitor});

defaultIssueCaptor = ArgumentCaptor.forClass(DefaultIssue.class);
when(movedFilesRepository.getOriginalFile(any(Component.class))).thenReturn(Optional.absent());
when(movedFilesRepository.getOriginalFile(any(Component.class))).thenReturn(Optional.empty());

DbClient dbClient = dbTester.getDbClient();
TrackerRawInputFactory rawInputFactory = new TrackerRawInputFactory(treeRootHolder, reportReader, sourceLinesHash, new CommonRuleEngineImpl(),

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

@@ -19,8 +19,8 @@
*/
package org.sonar.ce.task.projectanalysis.issue;

import com.google.common.base.Optional;
import java.util.Date;
import java.util.Optional;
import org.junit.Before;
import org.junit.Test;
import org.junit.rules.ExpectedException;
@@ -63,7 +63,7 @@ public class MovedIssueVisitorTest {
public void setUp() {
analysisMetadataHolder.setAnalysisDate(ANALYSIS_DATE);
when(movedFilesRepository.getOriginalFile(any(Component.class)))
.thenReturn(Optional.absent());
.thenReturn(Optional.empty());
}

@Test

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

@@ -19,7 +19,7 @@
*/
package org.sonar.ce.task.projectanalysis.issue;

import com.google.common.base.Optional;
import java.util.Optional;
import org.junit.Before;
import org.junit.Test;
import org.sonar.ce.task.projectanalysis.component.Component;
@@ -46,7 +46,7 @@ public class RemoveProcessedComponentsVisitorTest {

@Test
public void remove_processed_files() {
when(movedFilesRepository.getOriginalFile(any(Component.class))).thenReturn(Optional.absent());
when(movedFilesRepository.getOriginalFile(any(Component.class))).thenReturn(Optional.empty());
underTest.afterComponent(component);

verify(movedFilesRepository).getOriginalFile(component);

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

@@ -19,7 +19,7 @@
*/
package org.sonar.ce.task.projectanalysis.issue;

import com.google.common.base.Optional;
import java.util.Optional;
import org.junit.Before;
import org.junit.Test;
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolderRule;
@@ -65,7 +65,7 @@ public class TrackerBaseInputFactoryTest {
when(dbClient.openSession(false)).thenReturn(dbSession);
when(dbClient.fileSourceDao()).thenReturn(fileSourceDao);
when(movedFilesRepository.getOriginalFile(any(Component.class)))
.thenReturn(Optional.absent());
.thenReturn(Optional.empty());
}

@Test

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

@@ -35,6 +35,7 @@ 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.ReferenceBranchComponentUuids;
import org.sonar.ce.task.projectanalysis.filemove.MutableMovedFilesRepositoryRule;
import org.sonar.core.hash.SourceHashComputer;
import org.sonar.db.DbTester;
import org.sonar.db.component.BranchType;
@@ -67,11 +68,13 @@ public class ScmInfoDbLoaderTest {
public DbTester dbTester = DbTester.create(System2.INSTANCE);
@Rule
public BatchReportReaderRule reportReader = new BatchReportReaderRule();
@Rule
public MutableMovedFilesRepositoryRule movedFiles = new MutableMovedFilesRepositoryRule();

private Branch branch = mock(Branch.class);
private ReferenceBranchComponentUuids referenceBranchComponentUuids = mock(ReferenceBranchComponentUuids.class);

private ScmInfoDbLoader underTest = new ScmInfoDbLoader(analysisMetadataHolder, dbTester.getDbClient(), referenceBranchComponentUuids);
private ScmInfoDbLoader underTest = new ScmInfoDbLoader(analysisMetadataHolder, movedFiles, dbTester.getDbClient(), referenceBranchComponentUuids);

@Test
public void returns_ScmInfo_from_DB() {

+ 5
- 1
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/source/SourceLinesDiffImplTest.java View File

@@ -21,10 +21,12 @@ package org.sonar.ce.task.projectanalysis.source;

import java.util.Arrays;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
import org.sonar.ce.task.projectanalysis.component.Component;
import org.sonar.ce.task.projectanalysis.component.ReferenceBranchComponentUuids;
import org.sonar.ce.task.projectanalysis.filemove.MutableMovedFilesRepositoryRule;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDao;
@@ -45,9 +47,11 @@ public class SourceLinesDiffImplTest {
private SourceLinesHashRepository sourceLinesHash = mock(SourceLinesHashRepository.class);
private AnalysisMetadataHolder analysisMetadataHolder = mock(AnalysisMetadataHolder.class);
private ReferenceBranchComponentUuids referenceBranchComponentUuids = mock(ReferenceBranchComponentUuids.class);
@Rule
public MutableMovedFilesRepositoryRule movedFiles = new MutableMovedFilesRepositoryRule();

private SourceLinesDiffImpl underTest = new SourceLinesDiffImpl(dbClient, fileSourceDao, sourceLinesHash,
referenceBranchComponentUuids, analysisMetadataHolder);
referenceBranchComponentUuids, movedFiles, analysisMetadataHolder);

private static final int FILE_REF = 1;


+ 8
- 8
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/source/SourceLinesHashRepositoryImplTest.java View File

@@ -88,24 +88,24 @@ public class SourceLinesHashRepositoryImplTest {

@Test
public void should_create_hash_without_significant_code_if_db_has_no_significant_code() {
when(dbLineHashVersion.hasLineHashesWithSignificantCode(file)).thenReturn(false);
when(dbLineHashVersion.hasLineHashesWithoutSignificantCode(file)).thenReturn(true);
List<String> lineHashes = underTest.getLineHashesMatchingDBVersion(file);

assertLineHashes(lineHashes, "line1", "line2", "line3");
verify(dbLineHashVersion).hasLineHashesWithSignificantCode(file);
verify(dbLineHashVersion).hasLineHashesWithoutSignificantCode(file);
verifyNoMoreInteractions(dbLineHashVersion);
verifyZeroInteractions(significantCodeRepository);
}

@Test
public void should_create_hash_without_significant_code_if_report_has_no_significant_code() {
when(dbLineHashVersion.hasLineHashesWithSignificantCode(file)).thenReturn(true);
when(dbLineHashVersion.hasLineHashesWithoutSignificantCode(file)).thenReturn(false);
when(significantCodeRepository.getRangesPerLine(file)).thenReturn(Optional.empty());

List<String> lineHashes = underTest.getLineHashesMatchingDBVersion(file);

assertLineHashes(lineHashes, "line1", "line2", "line3");
verify(dbLineHashVersion).hasLineHashesWithSignificantCode(file);
verify(dbLineHashVersion).hasLineHashesWithoutSignificantCode(file);
verifyNoMoreInteractions(dbLineHashVersion);
verify(significantCodeRepository).getRangesPerLine(file);
verifyNoMoreInteractions(significantCodeRepository);
@@ -121,7 +121,7 @@ public class SourceLinesHashRepositoryImplTest {
List<String> lineHashes = underTest.getLineHashesMatchingDBVersion(file);

assertLineHashes(lineHashes, "l", "", "ine3");
verify(dbLineHashVersion).hasLineHashesWithSignificantCode(file);
verify(dbLineHashVersion).hasLineHashesWithoutSignificantCode(file);
verifyNoMoreInteractions(dbLineHashVersion);
verify(significantCodeRepository).getRangesPerLine(file);
verifyNoMoreInteractions(significantCodeRepository);
@@ -154,7 +154,7 @@ public class SourceLinesHashRepositoryImplTest {
LineRange[] lineRanges = {new LineRange(0, 1), null, new LineRange(1, 5)};
sourceLinesHashCache.computeIfAbsent(file, c -> lineHashes);

when(dbLineHashVersion.hasLineHashesWithSignificantCode(file)).thenReturn(true);
when(dbLineHashVersion.hasLineHashesWithoutSignificantCode(file)).thenReturn(false);
when(significantCodeRepository.getRangesPerLine(file)).thenReturn(Optional.of(lineRanges));

LineHashesComputer hashesComputer = underTest.getLineHashesComputerToPersist(file);
@@ -168,7 +168,7 @@ public class SourceLinesHashRepositoryImplTest {
List<String> lineHashes = Lists.newArrayList("line1", "line2", "line3");
sourceLinesHashCache.computeIfAbsent(file, c -> lineHashes);

when(dbLineHashVersion.hasLineHashesWithSignificantCode(file)).thenReturn(false);
when(dbLineHashVersion.hasLineHashesWithoutSignificantCode(file)).thenReturn(true);
when(significantCodeRepository.getRangesPerLine(file)).thenReturn(Optional.empty());

LineHashesComputer hashesComputer = underTest.getLineHashesComputerToPersist(file);
@@ -185,7 +185,7 @@ public class SourceLinesHashRepositoryImplTest {
sourceLinesHashCache.computeIfAbsent(file, c -> lineHashes);

// DB has line hashes without significant code and significant code is available in the report, so we need to generate new line hashes
when(dbLineHashVersion.hasLineHashesWithSignificantCode(file)).thenReturn(false);
when(dbLineHashVersion.hasLineHashesWithoutSignificantCode(file)).thenReturn(true);
when(significantCodeRepository.getRangesPerLine(file)).thenReturn(Optional.of(lineRanges));

LineHashesComputer hashesComputer = underTest.getLineHashesComputerToPersist(file);

+ 3
- 3
server/sonar-db-dao/src/main/java/org/sonar/db/source/FileSourceDao.java View File

@@ -50,7 +50,7 @@ public class FileSourceDao implements Dao {
@CheckForNull
public LineHashVersion selectLineHashesVersion(DbSession dbSession, String fileUuid) {
Integer version = mapper(dbSession).selectLineHashesVersion(fileUuid);
return version == null ? LineHashVersion.WITHOUT_SIGNIFICANT_CODE : LineHashVersion.valueOf(version);
return version == null ? null : LineHashVersion.valueOf(version);
}

@CheckForNull
@@ -82,8 +82,8 @@ public class FileSourceDao implements Dao {
* uuids in no specific order with 'SOURCE' source and a non null path.
*/
public void scrollLineHashes(DbSession dbSession, Collection<String> fileUUids, ResultHandler<LineHashesWithUuidDto> rowHandler) {
for (List<String> partition : toUniqueAndSortedPartitions(fileUUids)) {
mapper(dbSession).scrollLineHashes(partition, rowHandler);
for (List<String> fileUuidsPartition : toUniqueAndSortedPartitions(fileUUids)) {
mapper(dbSession).scrollLineHashes(fileUuidsPartition, rowHandler);
}
}


Loading…
Cancel
Save