diff options
author | Klaudio Sinani <klaudio.sinani@sonarsource.com> | 2022-08-10 13:37:31 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2022-10-26 20:03:10 +0000 |
commit | 84f0224faf4e45999e793f8d06b66c065dfc6399 (patch) | |
tree | beb055ee1d93aa0966ca01d8cbed088202ae59ef /sonar-scanner-engine/src | |
parent | 30e6c8d94430d7087f14196032d77e3034262e83 (diff) | |
download | sonarqube-84f0224faf4e45999e793f8d06b66c065dfc6399.tar.gz sonarqube-84f0224faf4e45999e793f8d06b66c065dfc6399.zip |
SONAR-13579 Detect files moves in Pull Request scope
SONAR-13579 Get database files from target branch instead of snapshot
SONAR-13579 Store old relative file path to `FileAttributes` class
Diffstat (limited to 'sonar-scanner-engine/src')
10 files changed, 325 insertions, 25 deletions
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ChangedLinesPublisher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ChangedLinesPublisher.java index 19bb51e1695..56737d1e068 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ChangedLinesPublisher.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ChangedLinesPublisher.java @@ -39,6 +39,7 @@ import org.sonar.scanner.repository.ReferenceBranchSupplier; import org.sonar.scanner.scan.branch.BranchConfiguration; import org.sonar.scanner.scan.filesystem.InputComponentStore; import org.sonar.scanner.scm.ScmConfiguration; +import org.sonar.scm.git.GitScmProvider; import static java.util.Optional.empty; @@ -89,7 +90,7 @@ public class ChangedLinesPublisher implements ReportPublisherStep { Map<Path, DefaultInputFile> changedFiles = StreamSupport.stream(inputComponentStore.allChangedFilesToPublish().spliterator(), false) .collect(Collectors.toMap(DefaultInputFile::path, f -> f)); - Map<Path, Set<Integer>> pathSetMap = provider.branchChangedLines(targetScmBranch, rootBaseDir, changedFiles.keySet()); + Map<Path, Set<Integer>> pathSetMap = ((GitScmProvider) provider).branchChangedLines(targetScmBranch, rootBaseDir, changedFiles); // TODO: Extend ScmProvider abstract int count = 0; if (pathSetMap == null) { diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ComponentsPublisher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ComponentsPublisher.java index 4ca7c8be780..b21da5f2f94 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ComponentsPublisher.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ComponentsPublisher.java @@ -68,6 +68,10 @@ public class ComponentsPublisher implements ReportPublisherStep { fileBuilder.setStatus(convert(file.status())); fileBuilder.setMarkedAsUnchanged(file.isMarkedAsUnchanged()); + if (file.isMovedFile()) { + fileBuilder.setOldRelativeFilePath(file.oldPath()); + } + String lang = getLanguageKey(file); if (lang != null) { fileBuilder.setLanguage(lang); diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java index 7ea8799c855..4653c24d171 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java @@ -43,6 +43,7 @@ import org.sonar.api.utils.log.Loggers; import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader; import org.sonar.scanner.repository.language.Language; import org.sonar.scanner.scan.ScanProperties; +import org.sonar.scanner.scm.ScmChangedFiles; import org.sonar.scanner.util.ProgressReport; import static java.lang.String.format; @@ -66,6 +67,7 @@ public class FileIndexer { private final InputComponentStore componentStore; private final SensorStrategy sensorStrategy; private final LanguageDetection langDetection; + private final ScmChangedFiles scmChangedFiles; private boolean warnInclusionsAlreadyLogged; private boolean warnExclusionsAlreadyLogged; @@ -75,7 +77,7 @@ public class FileIndexer { public FileIndexer(DefaultInputProject project, ScannerComponentIdGenerator scannerComponentIdGenerator, InputComponentStore componentStore, ProjectExclusionFilters projectExclusionFilters, ProjectCoverageAndDuplicationExclusions projectCoverageAndDuplicationExclusions, IssueExclusionsLoader issueExclusionsLoader, MetadataGenerator metadataGenerator, SensorStrategy sensorStrategy, LanguageDetection languageDetection, AnalysisWarnings analysisWarnings, ScanProperties properties, - InputFileFilter[] filters) { + InputFileFilter[] filters, ScmChangedFiles scmChangedFiles) { this.project = project; this.scannerComponentIdGenerator = scannerComponentIdGenerator; this.componentStore = componentStore; @@ -88,6 +90,7 @@ public class FileIndexer { this.properties = properties; this.filters = filters; this.projectExclusionFilters = projectExclusionFilters; + this.scmChangedFiles = scmChangedFiles; } void indexFile(DefaultInputModule module, ModuleExclusionFilters moduleExclusionFilters, ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions, @@ -124,10 +127,18 @@ public class FileIndexer { return; } - DefaultIndexedFile indexedFile = new DefaultIndexedFile(realAbsoluteFile, project.key(), + DefaultIndexedFile indexedFile = new DefaultIndexedFile( + realAbsoluteFile, + project.key(), projectRelativePath.toString(), moduleRelativePath.toString(), - type, language != null ? language.key() : null, scannerComponentIdGenerator.getAsInt(), sensorStrategy); + type, + language != null ? language.key() : null, + scannerComponentIdGenerator.getAsInt(), + sensorStrategy, + scmChangedFiles.getFileOldPath(realAbsoluteFile) + ); + DefaultInputFile inputFile = new DefaultInputFile(indexedFile, f -> metadataGenerator.setMetadata(module.key(), f, module.getEncoding())); if (language != null && language.isPublishAllFiles()) { inputFile.setPublished(true); diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmChangedFiles.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmChangedFiles.java index 0491d6b4281..010f2de4cbf 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmChangedFiles.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmChangedFiles.java @@ -21,17 +21,21 @@ package org.sonar.scanner.scm; import java.nio.file.Path; import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.function.Predicate; import javax.annotation.CheckForNull; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; +import org.sonar.scm.git.ChangedFile; @Immutable public class ScmChangedFiles { @Nullable - private final Collection<Path> fileCollection; + private final Collection<ChangedFile> changedFiles; - public ScmChangedFiles(@Nullable Collection<Path> changedFiles) { - this.fileCollection = changedFiles; + public ScmChangedFiles(@Nullable Collection<ChangedFile> changedFiles) { + this.changedFiles = changedFiles; } public boolean isChanged(Path file) { @@ -39,15 +43,33 @@ public class ScmChangedFiles { throw new IllegalStateException("Scm didn't provide valid data"); } - return fileCollection.contains(file); + return this.findFile(file).isPresent(); } public boolean isValid() { - return fileCollection != null; + return changedFiles != null; } @CheckForNull - Collection<Path> get() { - return fileCollection; + public Collection<ChangedFile> get() { + return changedFiles; + } + + @CheckForNull + public String getFileOldPath(Path absoluteFilePath) { + return this.findFile(absoluteFilePath) + .filter(ChangedFile::isMoved) + .map(ChangedFile::getOldFilePath) + .orElse(null); + } + + private Optional<ChangedFile> findFile(Path absoluteFilePath) { + Predicate<ChangedFile> isTargetFile = file -> file.getAbsolutFilePath().equals(absoluteFilePath); + + return Optional.ofNullable(this.get()) + .orElseGet(List::of) + .stream() + .filter(isTargetFile) + .findFirst(); } } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmChangedFilesProvider.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmChangedFilesProvider.java index 5a46e41a90f..392996d7e74 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmChangedFilesProvider.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmChangedFilesProvider.java @@ -21,14 +21,17 @@ package org.sonar.scanner.scm; import java.nio.file.Path; import java.util.Collection; +import java.util.Set; +import java.util.stream.Collectors; import javax.annotation.CheckForNull; import org.sonar.api.batch.fs.internal.DefaultInputProject; -import org.sonar.api.batch.scm.ScmProvider; import org.sonar.api.impl.utils.ScannerUtils; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; import org.sonar.api.utils.log.Profiler; import org.sonar.scanner.scan.branch.BranchConfiguration; +import org.sonar.scm.git.ChangedFile; +import org.sonar.scm.git.GitScmProvider; import org.springframework.context.annotation.Bean; public class ScmChangedFilesProvider { @@ -38,25 +41,36 @@ public class ScmChangedFilesProvider { @Bean("ScmChangedFiles") public ScmChangedFiles provide(ScmConfiguration scmConfiguration, BranchConfiguration branchConfiguration, DefaultInputProject project) { Path rootBaseDir = project.getBaseDir(); - Collection<Path> changedFiles = loadChangedFilesIfNeeded(scmConfiguration, branchConfiguration, rootBaseDir); - validatePaths(changedFiles); + Collection<ChangedFile> changedFiles = loadChangedFilesIfNeeded(scmConfiguration, branchConfiguration, rootBaseDir); + + if (changedFiles != null) { + validatePaths(getFilePaths(changedFiles)); + } + return new ScmChangedFiles(changedFiles); } - private static void validatePaths(@javax.annotation.Nullable Collection<Path> paths) { - if (paths != null && paths.stream().anyMatch(p -> !p.isAbsolute())) { + private static void validatePaths(Set<Path> changedFilePaths) { + if (changedFilePaths != null && changedFilePaths.stream().anyMatch(p -> !p.isAbsolute())) { throw new IllegalStateException("SCM provider returned a changed file with a relative path but paths must be absolute. Please fix the provider."); } } + private static Set<Path> getFilePaths(Collection<ChangedFile> changedFiles) { + return changedFiles + .stream() + .map(ChangedFile::getAbsolutFilePath) + .collect(Collectors.toSet()); + } + @CheckForNull - private static Collection<Path> loadChangedFilesIfNeeded(ScmConfiguration scmConfiguration, BranchConfiguration branchConfiguration, Path rootBaseDir) { + private static Collection<ChangedFile> loadChangedFilesIfNeeded(ScmConfiguration scmConfiguration, BranchConfiguration branchConfiguration, Path rootBaseDir) { final String targetBranchName = branchConfiguration.targetBranchName(); if (branchConfiguration.isPullRequest() && targetBranchName != null) { - ScmProvider scmProvider = scmConfiguration.provider(); + GitScmProvider scmProvider = (GitScmProvider) scmConfiguration.provider(); if (scmProvider != null) { Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG); - Collection<Path> changedFiles = scmProvider.branchChangedFiles(targetBranchName, rootBaseDir); + Collection<ChangedFile> changedFiles = scmProvider.branchModifiedFiles(targetBranchName, rootBaseDir); profiler.stopInfo(); if (changedFiles != null) { LOG.debug("SCM reported {} {} changed in the branch", changedFiles.size(), ScannerUtils.pluralize("file", changedFiles.size())); diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scm/git/ChangedFile.java b/sonar-scanner-engine/src/main/java/org/sonar/scm/git/ChangedFile.java new file mode 100644 index 00000000000..6f30d24e744 --- /dev/null +++ b/sonar-scanner-engine/src/main/java/org/sonar/scm/git/ChangedFile.java @@ -0,0 +1,59 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 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.scm.git; + +import java.nio.file.Path; +import java.util.Objects; +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; + +public class ChangedFile { + @Nullable + private final String oldFilePath; + private final String filePath; + private final Path absoluteFilePath; + + public ChangedFile(String filePath, Path absoluteFilePath) { + this(filePath, absoluteFilePath, null); + } + + public ChangedFile(String filePath, Path absoluteFilePath, @Nullable String oldFilePath) { + this.filePath = filePath; + this.oldFilePath = oldFilePath; + this.absoluteFilePath = absoluteFilePath; + } + + @CheckForNull + public String getOldFilePath() { + return oldFilePath; + } + + public boolean isMoved() { + return Objects.nonNull(this.getOldFilePath()); + } + + public String getFilePath() { + return filePath; + } + + public Path getAbsolutFilePath() { + return absoluteFilePath; + } +} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scm/git/GitScmProvider.java b/sonar-scanner-engine/src/main/java/org/sonar/scm/git/GitScmProvider.java index bef15b669bc..c51035ee8f1 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scm/git/GitScmProvider.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scm/git/GitScmProvider.java @@ -24,11 +24,17 @@ import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.time.Instant; +import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; import java.util.regex.Pattern; import java.util.stream.Collectors; import javax.annotation.CheckForNull; @@ -36,8 +42,10 @@ import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.diff.DiffAlgorithm; import org.eclipse.jgit.diff.DiffEntry; +import org.eclipse.jgit.diff.DiffEntry.ChangeType; import org.eclipse.jgit.diff.DiffFormatter; import org.eclipse.jgit.diff.RawTextComparator; +import org.eclipse.jgit.diff.RenameDetector; import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.NullProgressMonitor; @@ -52,6 +60,9 @@ import org.eclipse.jgit.treewalk.AbstractTreeIterator; import org.eclipse.jgit.treewalk.CanonicalTreeParser; import org.eclipse.jgit.treewalk.FileTreeIterator; import org.eclipse.jgit.treewalk.filter.PathFilter; +import org.eclipse.jgit.treewalk.filter.PathFilterGroup; +import org.eclipse.jgit.treewalk.filter.TreeFilter; +import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.scm.BlameCommand; import org.sonar.api.batch.scm.ScmProvider; import org.sonar.api.notifications.AnalysisWarnings; @@ -60,6 +71,10 @@ import org.sonar.api.utils.System2; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; +import static org.eclipse.jgit.diff.DiffEntry.ChangeType.ADD; +import static org.eclipse.jgit.diff.DiffEntry.ChangeType.MODIFY; +import static org.eclipse.jgit.diff.DiffEntry.ChangeType.RENAME; + public class GitScmProvider extends ScmProvider { private static final Logger LOG = Loggers.get(GitScmProvider.class); @@ -141,6 +156,87 @@ public class GitScmProvider extends ScmProvider { return null; } + // TODO: Adjust ScmProvider abstract + @CheckForNull + public Collection<ChangedFile> branchModifiedFiles(String targetBranchName, Path rootBaseDir) { + try (Repository repo = buildRepo(rootBaseDir)) { + Ref targetRef = resolveTargetRef(targetBranchName, repo); + if (targetRef == null) { + addWarningTargetNotFound(targetBranchName); + return null; + } + + if (isDiffAlgoInvalid(repo.getConfig())) { + LOG.warn("The diff algorithm configured in git is not supported. " + + "No information regarding changes in the branch will be collected, which can lead to unexpected results."); + return null; + } + + Optional<RevCommit> mergeBaseCommit = findMergeBase(repo, targetRef); + if (mergeBaseCommit.isEmpty()) { + LOG.warn("No merge base found between HEAD and " + targetRef.getName()); + return null; + } + AbstractTreeIterator mergeBaseTree = prepareTreeParser(repo, mergeBaseCommit.get()); + + // we compare a commit with HEAD, so no point ignoring line endings (it will be whatever is committed) + try (Git git = newGit(repo)) { + List<DiffEntry> diffEntries = git.diff() + .setShowNameAndStatusOnly(true) + .setOldTree(mergeBaseTree) + .setNewTree(prepareNewTree(repo)) + .call(); + + return computeChangedFiles(repo, diffEntries); + } + } catch (IOException | GitAPIException e) { + LOG.warn(e.getMessage(), e); + } + return null; + } + + private static List<ChangedFile> computeChangedFiles(Repository repository, List<DiffEntry> diffEntries) throws IOException { + Path workingDirectory = repository.getWorkTree().toPath(); + + Map<String, String> renamedFilePaths = computeRenamedFilePaths(repository, diffEntries); + Set<String> changedFilePaths = computeChangedFilePaths(diffEntries); + + List<ChangedFile> changedFiles = new LinkedList<>(); + + Consumer<String> collectChangedFiles = filePath -> changedFiles.add(new ChangedFile(filePath, workingDirectory.resolve(filePath), renamedFilePaths.getOrDefault(filePath, null))); + changedFilePaths.forEach(collectChangedFiles); + + return changedFiles; + } + + private static Map<String, String> computeRenamedFilePaths(Repository repository, List<DiffEntry> diffEntries) throws IOException { + RenameDetector renameDetector = new RenameDetector(repository); + renameDetector.addAll(diffEntries); + + return renameDetector + .compute() + .stream() + .filter(entry -> RENAME.equals(entry.getChangeType())) + .collect(Collectors.toUnmodifiableMap(DiffEntry::getNewPath, DiffEntry::getOldPath)); + } + + private static Set<String> computeChangedFilePaths(List<DiffEntry> diffEntries) { + return diffEntries + .stream() + .filter(isAllowedChangeType(ADD, MODIFY)) + .map(DiffEntry::getNewPath) + .collect(Collectors.toSet()); + } + + private static Predicate<DiffEntry> isAllowedChangeType(ChangeType ...changeTypes) { + Function<ChangeType, Predicate<DiffEntry>> isChangeType = type -> entry -> type.equals(entry.getChangeType()); + + return Arrays + .stream(changeTypes) + .map(isChangeType) + .reduce(x -> false, Predicate::or); + } + @CheckForNull @Override public Map<Path, Set<Integer>> branchChangedLines(String targetBranchName, Path projectBaseDir, Set<Path> changedFiles) { @@ -177,6 +273,43 @@ public class GitScmProvider extends ScmProvider { return null; } + // TODO: Adjust ScmProvider abstract + public Map<Path, Set<Integer>> branchChangedLines(String targetBranchName, Path projectBaseDir, Map<Path, DefaultInputFile> changedFiles) { + try (Repository repo = buildRepo(projectBaseDir)) { + Ref targetRef = resolveTargetRef(targetBranchName, repo); + if (targetRef == null) { + addWarningTargetNotFound(targetBranchName); + return null; + } + + if (isDiffAlgoInvalid(repo.getConfig())) { + // we already print a warning when branchChangedFiles is called + return null; + } + + // force ignore different line endings when comparing a commit with the workspace + repo.getConfig().setBoolean("core", null, "autocrlf", true); + + Optional<RevCommit> mergeBaseCommit = findMergeBase(repo, targetRef); + + if (mergeBaseCommit.isEmpty()) { + LOG.warn("No merge base found between HEAD and " + targetRef.getName()); + return null; + } + + Map<Path, Set<Integer>> changedLines = new HashMap<>(); + + for (Map.Entry<Path, DefaultInputFile> entry : changedFiles.entrySet()) { + collectChangedLines(repo, mergeBaseCommit.get(), changedLines, entry.getKey(), entry.getValue()); + } + + return changedLines; + } catch (Exception e) { + LOG.warn("Failed to get changed lines from git", e); + } + return null; + } + private void addWarningTargetNotFound(String targetBranchName) { analysisWarnings.addUnique(String.format(COULD_NOT_FIND_REF + ". You may see unexpected issues and changes. " @@ -211,6 +344,36 @@ public class GitScmProvider extends ScmProvider { } } + // TODO: Adjust ScmProvider abstract + private void collectChangedLines(Repository repo, RevCommit mergeBaseCommit, Map<Path, Set<Integer>> changedLines, Path changedFilePath, DefaultInputFile changedFileData) { + ChangedLinesComputer computer = new ChangedLinesComputer(); + + try (DiffFormatter diffFmt = new DiffFormatter(new BufferedOutputStream(computer.receiver()))) { + diffFmt.setRepository(repo); + diffFmt.setProgressMonitor(NullProgressMonitor.INSTANCE); + diffFmt.setDiffComparator(RawTextComparator.WS_IGNORE_ALL); + + diffFmt.setDetectRenames(changedFileData.isMovedFile()); + + Path workTree = repo.getWorkTree().toPath(); + TreeFilter treeFilter = getTreeFilter(changedFileData, workTree); + diffFmt.setPathFilter(treeFilter); + + AbstractTreeIterator mergeBaseTree = prepareTreeParser(repo, mergeBaseCommit); + List<DiffEntry> diffEntries = diffFmt.scan(mergeBaseTree, new FileTreeIterator(repo)); + + diffFmt.format(diffEntries); + diffFmt.flush(); + + diffEntries.stream() + .filter(isAllowedChangeType(ADD, MODIFY, RENAME)) + .findAny() + .ifPresent(diffEntry -> changedLines.put(changedFilePath, computer.changedLines())); + } catch (Exception e) { + LOG.warn("Failed to get changed lines from git for file " + changedFilePath, e); + } + } + @Override @CheckForNull public Instant forkDate(String referenceBranchName, Path projectBaseDir) { @@ -221,6 +384,17 @@ public class GitScmProvider extends ScmProvider { return path.replaceAll(Pattern.quote(File.separator), "/"); } + private TreeFilter getTreeFilter(DefaultInputFile changedFile, Path baseDir) { + String oldPath = toGitPath(changedFile.oldPath()); + String path = toGitPath(relativizeFilePath(baseDir, changedFile.path())); + + if (changedFile.isMovedFile()) { + return PathFilterGroup.createFromStrings(path, oldPath); + } + + return PathFilter.create(path); + } + @CheckForNull private Ref resolveTargetRef(String targetBranchName, Repository repo) throws IOException { String localRef = "refs/heads/" + targetBranchName; @@ -332,6 +506,10 @@ public class GitScmProvider extends ScmProvider { } } + private static String relativizeFilePath(Path baseDirectory, Path filePath) { + return baseDirectory.relativize(filePath).toString(); + } + AbstractTreeIterator prepareTreeParser(Repository repo, RevCommit commit) throws IOException { CanonicalTreeParser treeParser = new CanonicalTreeParser(); try (ObjectReader objectReader = repo.newObjectReader()) { diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/StatusDetectionTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/StatusDetectionTest.java index 73c736b224b..94629f59b60 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/StatusDetectionTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/StatusDetectionTest.java @@ -19,9 +19,11 @@ */ package org.sonar.scanner.scan.filesystem; +import java.nio.file.Path; import java.nio.file.Paths; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.junit.Test; import org.sonar.api.batch.fs.InputFile; @@ -31,6 +33,7 @@ import org.sonar.scanner.repository.FileData; import org.sonar.scanner.repository.ProjectRepositories; import org.sonar.scanner.repository.SingleProjectRepository; import org.sonar.scanner.scm.ScmChangedFiles; +import org.sonar.scm.git.ChangedFile; import static org.assertj.core.api.Assertions.assertThat; @@ -61,9 +64,10 @@ public class StatusDetectionTest { @Test public void detect_status_branches_confirm() { - ScmChangedFiles changedFiles = new ScmChangedFiles(Collections.singletonList(Paths.get("module", "src", "Foo.java"))); - StatusDetection statusDetection = new StatusDetection(projectRepositories, changedFiles); + Path filePath = Paths.get("module", "src", "Foo.java"); + ScmChangedFiles changedFiles = new ScmChangedFiles(List.of(new ChangedFile(filePath.toString(), filePath))); + StatusDetection statusDetection = new StatusDetection(projectRepositories, changedFiles); assertThat(statusDetection.status("foo", createFile("src/Foo.java"), "XXXXX")).isEqualTo(InputFile.Status.CHANGED); } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scm/ScmChangedFilesProviderTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scm/ScmChangedFilesProviderTest.java index ec319e1c931..abbc78a3819 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scm/ScmChangedFilesProviderTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scm/ScmChangedFilesProviderTest.java @@ -30,6 +30,7 @@ import org.sonar.api.batch.fs.internal.DefaultInputProject; import org.sonar.api.batch.scm.ScmProvider; import org.sonar.scanner.fs.InputModuleHierarchy; import org.sonar.scanner.scan.branch.BranchConfiguration; +import org.sonar.scm.git.ChangedFile; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -130,7 +131,9 @@ public class ScmChangedFilesProviderTest { when(scmProvider.branchChangedFiles("target", rootBaseDir)).thenReturn(Collections.singleton(Paths.get("changedFile").toAbsolutePath())); ScmChangedFiles scmChangedFiles = provider.provide(scmConfiguration, branchConfiguration, project); - assertThat(scmChangedFiles.get()).containsOnly(Paths.get("changedFile").toAbsolutePath()); + Path filePath = Paths.get("changedFile").toAbsolutePath(); + ChangedFile changedFile = new ChangedFile(filePath.toString(), filePath); + assertThat(scmChangedFiles.get()).containsOnly(changedFile); verify(scmProvider).branchChangedFiles("target", rootBaseDir); } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scm/ScmChangedFilesTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scm/ScmChangedFilesTest.java index 40d3930713f..856d0573124 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scm/ScmChangedFilesTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scm/ScmChangedFilesTest.java @@ -24,6 +24,7 @@ import java.nio.file.Paths; import java.util.Collection; import java.util.Collections; import org.junit.Test; +import org.sonar.scm.git.ChangedFile; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -33,9 +34,11 @@ public class ScmChangedFilesTest { @Test public void testGetter() { - Collection<Path> files = Collections.singletonList(Paths.get("files")); + Path filePath = Paths.get("files"); + ChangedFile file = new ChangedFile(filePath.toString(), filePath); + Collection<ChangedFile> files = Collections.singletonList(file); scmChangedFiles = new ScmChangedFiles(files); - assertThat(scmChangedFiles.get()).containsOnly(Paths.get("files")); + assertThat(scmChangedFiles.get()).containsOnly(file); } @Test @@ -50,7 +53,8 @@ public class ScmChangedFilesTest { @Test public void testConfirm() { - Collection<Path> files = Collections.singletonList(Paths.get("files")); + Path filePath = Paths.get("files"); + Collection<ChangedFile> files = Collections.singletonList(new ChangedFile(filePath.toString(), filePath)); scmChangedFiles = new ScmChangedFiles(files); assertThat(scmChangedFiles.isValid()).isTrue(); assertThat(scmChangedFiles.isChanged(Paths.get("files"))).isTrue(); |