From b36f1ca3e4c94ac3632a2b96b09bde777c716e7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Mon, 25 Mar 2019 12:08:44 +0100 Subject: [PATCH] Mark default branch for git --- .../java/sonia/scm/repository/Branch.java | 3 +- .../repository/spi/GitBranchesCommand.java | 95 ++++++++------ .../spi/GitBranchesCommandTest.java | 118 ++++++++++++++++++ 3 files changed, 175 insertions(+), 41 deletions(-) create mode 100644 scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitBranchesCommandTest.java diff --git a/scm-core/src/main/java/sonia/scm/repository/Branch.java b/scm-core/src/main/java/sonia/scm/repository/Branch.java index d8950c80ac..c0a7289912 100644 --- a/scm-core/src/main/java/sonia/scm/repository/Branch.java +++ b/scm-core/src/main/java/sonia/scm/repository/Branch.java @@ -116,7 +116,8 @@ public final class Branch implements Serializable final Branch other = (Branch) obj; return Objects.equal(name, other.name) - && Objects.equal(revision, other.revision); + && Objects.equal(revision, other.revision) + && Objects.equal(defaultBranch, other.defaultBranch); } /** diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitBranchesCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitBranchesCommand.java index 110e02d431..81b38cab5c 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitBranchesCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitBranchesCommand.java @@ -34,11 +34,15 @@ package sonia.scm.repository.spi; //~--- non-JDK imports -------------------------------------------------------- -import com.google.common.base.Function; -import com.google.common.collect.Lists; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Strings; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.common.value.qual.UnknownVal; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.lib.Ref; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import sonia.scm.repository.Branch; import sonia.scm.repository.GitUtil; import sonia.scm.repository.InternalRepositoryException; @@ -46,6 +50,8 @@ import sonia.scm.repository.Repository; import java.io.IOException; import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; //~--- JDK imports ------------------------------------------------------------ @@ -53,17 +59,10 @@ import java.util.List; * * @author Sebastian Sdorra */ -public class GitBranchesCommand extends AbstractGitCommand - implements BranchesCommand -{ +public class GitBranchesCommand extends AbstractGitCommand implements BranchesCommand { + + private static final Logger LOG = LoggerFactory.getLogger(GitBranchesCommand.class); - /** - * Constructs ... - * - * - * @param context - * @param repository - */ public GitBranchesCommand(GitContext context, Repository repository) { super(context, repository); @@ -73,38 +72,54 @@ public class GitBranchesCommand extends AbstractGitCommand @Override public List getBranches() throws IOException { - List branches = null; + Git git = createGit(); - Git git = new Git(open()); + String defaultBranchName = determineDefaultBranchName(git); - try - { - List refs = git.branchList().call(); - - branches = Lists.transform(refs, new Function() - { - - @Override - public Branch apply(Ref ref) - { - Branch branch = null; - String branchName = GitUtil.getBranch(ref); - - if (branchName != null) - { - branch = Branch.normalBranch(branchName, GitUtil.getId(ref.getObjectId())); - } - - return branch; - } - }); - - } - catch (GitAPIException ex) - { + try { + return git + .branchList() + .call() + .stream() + .map(ref -> createBranchObject(defaultBranchName, ref)) + .collect(Collectors.toList()); + } catch (GitAPIException ex) { throw new InternalRepositoryException(repository, "could not read branches", ex); } + } - return branches; + @VisibleForTesting + Git createGit() throws IOException { + return new Git(open()); + } + + @Nullable + private Branch createBranchObject(String defaultBranchName, Ref ref) { + String branchName = GitUtil.getBranch(ref); + + if (branchName == null) { + LOG.warn("could not determine branch name for branch name {} at revision {}", ref.getName(), ref.getObjectId()); + return null; + } else { + if (branchName.equals(defaultBranchName)) { + return Branch.defaultBranch(branchName, GitUtil.getId(ref.getObjectId())); + } else { + return Branch.normalBranch(branchName, GitUtil.getId(ref.getObjectId())); + } + } + } + + private String determineDefaultBranchName(Git git) { + String defaultBranchName = context.getConfig().getDefaultBranch(); + if (Strings.isNullOrEmpty(defaultBranchName)) { + return getRepositoryHeadRef(git).map(GitUtil::getBranch).orElse(null); + } else { + return defaultBranchName; + } + } + + @UnknownVal + Optional getRepositoryHeadRef(Git git) { + return GitUtil.getRepositoryHeadRef(git.getRepository()); } } diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitBranchesCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitBranchesCommandTest.java new file mode 100644 index 0000000000..af765bc7aa --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitBranchesCommandTest.java @@ -0,0 +1,118 @@ +package sonia.scm.repository.spi; + +import org.checkerframework.common.value.qual.UnknownVal; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.ListBranchCommand; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.Ref; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import sonia.scm.repository.Branch; +import sonia.scm.repository.GitRepositoryConfig; +import sonia.scm.repository.Repository; + +import java.io.IOException; +import java.util.List; +import java.util.Optional; + +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static java.util.Optional.of; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class GitBranchesCommandTest { + + @Mock + GitContext context; + @Mock + Git git; + @Mock + ListBranchCommand listBranchCommand; + @Mock + GitRepositoryConfig gitRepositoryConfig; + + GitBranchesCommand branchesCommand; + private Ref master; + + @BeforeEach + void initContext() { + when(context.getConfig()).thenReturn(gitRepositoryConfig); + } + + @BeforeEach + void initCommand() { + master = createRef("master", "0000"); + branchesCommand = new GitBranchesCommand(context, new Repository("1", "git", "space", "X")) { + @Override + Git createGit() { + return git; + } + + @Override + @UnknownVal Optional getRepositoryHeadRef(Git git) { + return of(master); + } + }; + when(git.branchList()).thenReturn(listBranchCommand); + } + + @Test + void shouldCreateEmptyListWithoutBranches() throws IOException, GitAPIException { + when(listBranchCommand.call()).thenReturn(emptyList()); + + List branches = branchesCommand.getBranches(); + + assertThat(branches).isEmpty(); + } + + @Test + void shouldMapNormalBranch() throws IOException, GitAPIException { + Ref branch = createRef("branch", "1337"); + when(listBranchCommand.call()).thenReturn(asList(branch)); + + List branches = branchesCommand.getBranches(); + + assertThat(branches).containsExactly(Branch.normalBranch("branch", "1337")); + } + + @Test + void shouldMarkMasterBranchWithMasterFromConfig() throws IOException, GitAPIException { + Ref branch = createRef("branch", "1337"); + when(listBranchCommand.call()).thenReturn(asList(branch)); + when(gitRepositoryConfig.getDefaultBranch()).thenReturn("branch"); + + List branches = branchesCommand.getBranches(); + + assertThat(branches).containsExactlyInAnyOrder(Branch.defaultBranch("branch", "1337")); + } + + @Test + void shouldMarkMasterBranchWithMasterFromHead() throws IOException, GitAPIException { + Ref branch = createRef("branch", "1337"); + when(listBranchCommand.call()).thenReturn(asList(branch, master)); + + List branches = branchesCommand.getBranches(); + + assertThat(branches).containsExactlyInAnyOrder( + Branch.normalBranch("branch", "1337"), + Branch.defaultBranch("master", "0000") + ); + } + + private Ref createRef(String branchName, String revision) { + Ref ref = mock(Ref.class); + lenient().when(ref.getName()).thenReturn("refs/heads/" + branchName); + ObjectId objectId = mock(ObjectId.class); + lenient().when(objectId.name()).thenReturn(revision); + lenient().when(ref.getObjectId()).thenReturn(objectId); + return ref; + } +}