diff options
author | lukasz-jarocki-sonarsource <77498856+lukasz-jarocki-sonarsource@users.noreply.github.com> | 2021-02-17 16:22:59 +0100 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2021-02-19 20:07:20 +0000 |
commit | 9497e4d9cd1cf62d9f694864e7bc3748f61cb361 (patch) | |
tree | fe7c69a622823809ad0b1245e400de41b8642e23 /sonar-scanner-engine | |
parent | 69481df48a3854bfc1538980b9c74d6810457da4 (diff) | |
download | sonarqube-9497e4d9cd1cf62d9f694864e7bc3748f61cb361.tar.gz sonarqube-9497e4d9cd1cf62d9f694864e7bc3748f61cb361.zip |
SONAR-14461 main branch detection
Diffstat (limited to 'sonar-scanner-engine')
4 files changed, 206 insertions, 4 deletions
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java index 84a0ee85431..adaa253f690 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java @@ -61,6 +61,9 @@ public class MetadataPublisher implements ReportPublisherStep { private final InputComponentStore componentStore; private final ScmConfiguration scmConfiguration; + private ScmProvider scmProvider; + private Path projectBasedir; + public MetadataPublisher(ProjectInfo projectInfo, InputModuleHierarchy moduleHierarchy, QualityProfiles qProfiles, CpdSettings cpdSettings, ScannerPluginRepository pluginRepository, BranchConfiguration branchConfiguration, ScmRevision scmRevision, ForkDateSupplier forkDateSupplier, InputComponentStore componentStore, ScmConfiguration scmConfiguration) { @@ -95,7 +98,6 @@ public class MetadataPublisher implements ReportPublisherStep { addScmInformation(builder); addForkPoint(builder); addNotAnalyzedFileCountsByLanguage(builder); - addMainBranch(builder); for (QProfile qp : qProfiles.findAll()) { builder.putQprofilesPerLanguage(qp.getLanguage(), ScannerReport.Metadata.QProfile.newBuilder() @@ -110,6 +112,9 @@ public class MetadataPublisher implements ReportPublisherStep { .setUpdatedAt(pluginEntry.getValue().getUpdatedAt()).build()); } + scmProvider = scmConfiguration.provider(); + projectBasedir = moduleHierarchy.root().getBaseDir(); + addModulesRelativePaths(builder); addMainBranch(builder); @@ -117,7 +122,16 @@ public class MetadataPublisher implements ReportPublisherStep { } private void addMainBranch(ScannerReport.Metadata.Builder builder) { - builder.setGitDefaultMainBranch(""); + if (scmProvider == null) { + return; + } + String mainBranch = scmProvider.getMainBranch(projectBasedir); + if (mainBranch != null && !mainBranch.isEmpty()) { + LOG.debug("The main branch for '{}' is '{}'", projectBasedir.toString(), mainBranch); + builder.setGitDefaultMainBranch(mainBranch); + } else { + LOG.debug("The main branch for '{}' has not been found", projectBasedir.toString()); + } } private void addForkPoint(ScannerReport.Metadata.Builder builder) { @@ -140,12 +154,10 @@ public class MetadataPublisher implements ReportPublisherStep { } } - ScmProvider scmProvider = scmConfiguration.provider(); if (scmProvider == null) { return; } - Path projectBasedir = moduleHierarchy.root().getBaseDir(); try { builder.setRelativePathFromScmRoot(toSonarQubePath(scmProvider.relativePathFromScmRoot(projectBasedir))); } catch (UnsupportedOperationException e) { 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 c7654504d0b..4303fa222ee 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 @@ -99,6 +99,21 @@ public class GitScmProvider extends ScmProvider { @CheckForNull @Override + public String getMainBranch(Path rootBaseDir) { + try (Repository repo = buildRepo(rootBaseDir)) { + Set<String> branches = repo.getConfig().getSubsections("branch"); + if(!branches.isEmpty()) { + // .git/config file will have the default branch at the time of cloning as its first branch + return branches.iterator().next(); + } + } catch (IOException e) { + LOG.debug("Couldn't build a repo in order to retrieve the default branch name", e); + } + return null; + } + + @CheckForNull + @Override public Set<Path> branchChangedFiles(String targetBranchName, Path rootBaseDir) { try (Repository repo = buildRepo(rootBaseDir)) { Ref targetRef = resolveTargetRef(targetBranchName, repo); diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MetadataPublisherTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MetadataPublisherTest.java index a7bda1c9992..d38a149a668 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MetadataPublisherTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MetadataPublisherTest.java @@ -286,4 +286,49 @@ public class MetadataPublisherTest { ScannerReport.Metadata metadata = reader.readMetadata(); assertThat(metadata.getRelativePathFromScmRoot()).isEmpty(); } + + @Test + public void addMainBranch_givenDefaultMainBranchSet_writeItToMetadata() throws IOException { + ScmProvider scmProvider = mock(ScmProvider.class); + when(scmProvider.getMainBranch(any())).thenReturn("Main"); + when(scmProvider.relativePathFromScmRoot(any())).thenReturn(mock(Path.class)); + when(scmConfiguration.provider()).thenReturn(scmProvider); + + File outputDir = temp.newFolder(); + underTest.publish(new ScannerReportWriter(outputDir)); + + ScannerReportReader reader = new ScannerReportReader(outputDir); + ScannerReport.Metadata metadata = reader.readMetadata(); + assertThat(metadata.getGitDefaultMainBranch()).isEqualTo("Main"); + } + + @Test + public void addMainBranch_givenEmptyDefaultMainBranchSet_emptyDefaultMainBranchInMetadata() throws IOException { + ScmProvider scmProvider = mock(ScmProvider.class); + when(scmProvider.getMainBranch(any())).thenReturn(""); + when(scmProvider.relativePathFromScmRoot(any())).thenReturn(mock(Path.class)); + when(scmConfiguration.provider()).thenReturn(scmProvider); + + File outputDir = temp.newFolder(); + underTest.publish(new ScannerReportWriter(outputDir)); + + ScannerReportReader reader = new ScannerReportReader(outputDir); + ScannerReport.Metadata metadata = reader.readMetadata(); + assertThat(metadata.getGitDefaultMainBranch()).isEmpty(); + } + + @Test + public void addMainBranch_givenNullMainBranchSet_emptyDefaultMainBranchInMetadata() throws IOException { + ScmProvider scmProvider = mock(ScmProvider.class); + when(scmProvider.getMainBranch(any())).thenReturn(null); + when(scmProvider.relativePathFromScmRoot(any())).thenReturn(mock(Path.class)); + when(scmConfiguration.provider()).thenReturn(scmProvider); + + File outputDir = temp.newFolder(); + underTest.publish(new ScannerReportWriter(outputDir)); + + ScannerReportReader reader = new ScannerReportReader(outputDir); + ScannerReport.Metadata metadata = reader.readMetadata(); + assertThat(metadata.getGitDefaultMainBranch()).isEmpty(); + } } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scm/git/GitScmProviderTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scm/git/GitScmProviderTest.java index 4efb0ddcb33..4a9a6121aa9 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scm/git/GitScmProviderTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scm/git/GitScmProviderTest.java @@ -39,15 +39,19 @@ import java.util.Random; import java.util.Set; import java.util.TimeZone; import java.util.concurrent.atomic.AtomicInteger; + +import org.eclipse.jgit.api.CreateBranchCommand; import org.eclipse.jgit.api.DiffCommand; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.RefDatabase; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.storage.file.FileRepositoryBuilder; +import org.eclipse.jgit.transport.URIish; import org.eclipse.jgit.treewalk.AbstractTreeIterator; import org.junit.Before; import org.junit.Rule; @@ -732,6 +736,132 @@ public class GitScmProviderTest { assertThat(provider.revisionId(projectDir)).isNull(); } + @Test + public void getMainBranch_givenRepoWithOneBranchCalledMain_returnMainBranchCalledMain() throws Exception { + //given + worktree = temp.newFolder().toPath(); + Repository repo = FileRepositoryBuilder.create(worktree.resolve(".git").toFile()); + repo.create(); + git = new Git(repo); + + addBranchInConfig("Main"); + + Path projectDir = worktree.resolve("project"); + Files.createDirectory(projectDir); + + GitScmProvider provider = newGitScmProvider(); + + //when + String mainBranch = provider.getMainBranch(projectDir); + + //then + assertThat(mainBranch).isEqualTo("Main"); + } + + @Test + public void getMainBranch_givenRepoWithTwoBranches_returnFirstBranch() throws Exception { + //given + worktree = temp.newFolder().toPath(); + Repository repo = FileRepositoryBuilder.create(worktree.resolve(".git").toFile()); + repo.create(); + git = new Git(repo); + + addBranchInConfig("First"); + addBranchInConfig("Second"); + + Path projectDir = worktree.resolve("project"); + Files.createDirectory(projectDir); + + GitScmProvider provider = newGitScmProvider(); + + //when + String mainBranch = provider.getMainBranch(projectDir); + + //then + assertThat(mainBranch).isEqualTo("First"); + } + + @Test + public void getMainBranch_givenNoBranches_dontThrowException() throws Exception { + //given + worktree = temp.newFolder().toPath(); + Repository repo = FileRepositoryBuilder.create(worktree.resolve(".git").toFile()); + repo.create(); + git = new Git(repo); + + Path projectDir = worktree.resolve("project"); + Files.createDirectory(projectDir); + + GitScmProvider provider = newGitScmProvider(); + + //when + String mainBranch = provider.getMainBranch(projectDir); + + //then no exception + assertThat(mainBranch).isNullOrEmpty(); + } + + @Test + public void getMainBranch_givenRepositoryNotFoundExceptionWhenBuildingRepo_returnNull() throws Exception { + //given + + worktree = temp.newFolder().toPath(); + Repository repo = FileRepositoryBuilder.create(worktree.resolve(".git").toFile()); + repo.create(); + git = new Git(repo); + repo.getObjectDatabase().close(); //This is here to force RepositoryBuilder to throw subclass of IOException + + Path projectDir = worktree.resolve("project"); + Files.createDirectory(projectDir); + + GitScmProvider provider = newGitScmProvider(); + + //when + String mainBranch = provider.getMainBranch(projectDir); + + //then no exception + assertThat(mainBranch).isNullOrEmpty(); + } + + @Test + public void getMainBranch_givenIOExceptionWhenBuildingRepo_returnNull() throws Exception { + //given + + worktree = temp.newFolder().toPath(); + Repository repo = FileRepositoryBuilder.create(worktree.resolve(".git").toFile()); + repo.create(); + git = new Git(repo); + + Path projectDir = worktree.resolve("project"); + Files.createDirectory(projectDir); + + GitScmProvider provider = new GitScmProvider(mockCommand(), analysisWarnings, gitIgnoreCommand, system2) { + @Override + Repository buildRepo(Path basedir) throws IOException { + throw new IOException(); + } + }; + + //when + String mainBranch = provider.getMainBranch(projectDir); + + //then no exception + assertThat(mainBranch).isNullOrEmpty(); + } + + /** + * Normally after cloning the repository we would have at least one + * branch it git config. This method adds these branches without + * cloning any repository (because unit tests ought to be fast) + */ + private void addBranchInConfig(String ... branches) throws IOException { + for(String branch : branches) { + git.getRepository().getConfig().setStringList("branch", branch, "remote", Arrays.asList("origin")); + git.getRepository().getConfig().setStringList("branch", branch, "merge", Arrays.asList("refs/head/" + branch)); + } + git.getRepository().getConfig().save(); + } + private String randomizedContent(String prefix, int numLines) { StringBuilder sb = new StringBuilder(); for (int line = 0; line < numLines; line++) { |