Skip to content

Make branch name comparison case insensitive #2261

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
197 changes: 197 additions & 0 deletions src/GitVersionCore.Tests/Core/RepositoryExtensionsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
using GitTools.Testing;
using GitVersion.Logging;
using GitVersion.Extensions;
using GitVersionCore.Tests.Helpers;
using LibGit2Sharp;
using NUnit.Framework;
using System.Linq;
using NSubstitute;
using System;
using System.Collections.Generic;
using GitVersion;

namespace GitVersionCore.Tests
{
[TestFixture]
public class RepositoryExtensionsTests : TestBase
{
[Test]
public void EnsureLocalBranchExistsForCurrentBranch_CaseInsensitivelyMatchesBranches()
{
var log = Substitute.For<ILog>();
var repository = MockRepository();
var remote = MockRemote(repository);

repository.EnsureLocalBranchExistsForCurrentBranch(log, remote, "refs/heads/featurE/feat-test");
}

private IGitRepository MockRepository()
{
var repository = Substitute.For<IGitRepository>();
var commands = Substitute.For<IGitRepositoryCommands>();
repository.Commands.Returns(commands);
return repository;
}

private Remote MockRemote(IGitRepository repository)
{
var branches = new TestableBranchCollection(repository);
var tipId = new ObjectId("c6d8764d20ff16c0df14c73680e52b255b608926");
var tip = new TestableCommit(repository, tipId);
var head = branches.Add("refs/heads/feature/feat-test", tip);
var remote = new TesatbleRemote("origin");
var references = new TestableReferenceCollection();
var reference = references.Add("develop", "refs/heads/develop");

repository.Refs.Returns(references);
repository.Head.Returns(head);
repository.Branches.Returns(branches);
return remote;
}

private class TestableBranchCollection : BranchCollection
{
private readonly IRepository repository;
public TestableBranchCollection(IRepository repository)
{
}

IDictionary<string, Branch> branches = new Dictionary<string, Branch>();

public override Branch this[string name] =>
this.branches.ContainsKey(name)
? this.branches[name]
: null;

public override Branch Add(string name, Commit commit)
{
var branch = new TestableBranch(name, commit);
this.branches.Add(name, branch);
return branch;
}

public override Branch Add(string name, string committish)
{
var id = new ObjectId(committish);
var commit = new TestableCommit(this.repository, id);
return Add(name, commit);
}

public override Branch Add(string name, Commit commit, bool allowOverwrite)
{
return Add(name, commit);
}

public override Branch Add(string name, string committish, bool allowOverwrite)
{
return Add(name, committish);
}

public override IEnumerator<Branch> GetEnumerator()
{
return this.branches.Values.GetEnumerator();
}

public override void Remove(string name)
{
this.branches.Remove(name);
}

public override void Remove(string name, bool isRemote)
{
this.branches.Remove(name);
}

public override void Remove(Branch branch)
{
this.branches.Remove(branch.CanonicalName);
}

public override Branch Update(Branch branch, params Action<BranchUpdater>[] actions)
{
return base.Update(branch, actions);
}
}

private class TestableBranch : Branch
{
private readonly string canonicalName;
private readonly Commit tip;

public TestableBranch(string canonicalName, Commit tip)
{
this.tip = tip;
this.canonicalName = canonicalName;
}

public override string CanonicalName => this.canonicalName;
public override Commit Tip => this.tip;
}

private class TestableCommit : Commit, IBelongToARepository
{
private IRepository repository;
private ObjectId id;

public TestableCommit(IRepository repository, ObjectId id)
{
this.repository = repository;
this.id = id;
}

public override ObjectId Id => this.id;
public IRepository Repository => this.repository;
}

private class TesatbleRemote : Remote
{
private string name;

public TesatbleRemote(string name)
{
this.name = name;
}

public override string Name => this.name;
}

private class TestableReferenceCollection : ReferenceCollection
{
Reference reference;

public override DirectReference Add(string name, ObjectId targetId)
{
throw new InvalidOperationException("Update should be invoked when case-insensitively comparing branches.");
}

public override Reference Add(string name, string canonicalRefNameOrObjectish)
{
return this.reference = new TestableReference(canonicalRefNameOrObjectish);
}

public override Reference UpdateTarget(Reference directRef, ObjectId targetId)
{
return this.reference;
}

public override Reference this[string name] => this.reference;
}

private class TestableReference : Reference
{
private readonly string canonicalName;

public TestableReference(string canonicalName)
{
this.canonicalName = canonicalName;
}

public override string CanonicalName => this.canonicalName;

public override DirectReference ResolveToDirectReference()
{
throw new NotImplementedException();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public BranchConfig GetBranchConfiguration(Branch targetBranch, Commit currentCo
if (matchingBranches.Increment == IncrementStrategy.Inherit)
{
matchingBranches = InheritBranchConfiguration(targetBranch, matchingBranches, currentCommit, configuration, excludedInheritBranches);
if (matchingBranches.Name == FallbackConfigName && matchingBranches.Increment == IncrementStrategy.Inherit)
if (matchingBranches.Name.IsEquivalentTo(FallbackConfigName) && matchingBranches.Increment == IncrementStrategy.Inherit)
{
// We tried, and failed to inherit, just fall back to patch
matchingBranches.Increment = IncrementStrategy.Patch;
Expand Down Expand Up @@ -152,7 +152,7 @@ private BranchConfig InheritBranchConfiguration(Branch targetBranch, BranchConfi

var inheritingBranchConfig = GetBranchConfiguration(chosenBranch, currentCommit, configuration, excludedInheritBranches);
var configIncrement = inheritingBranchConfig.Increment;
if (inheritingBranchConfig.Name == FallbackConfigName && configIncrement == IncrementStrategy.Inherit)
if (inheritingBranchConfig.Name.IsEquivalentTo(FallbackConfigName) && configIncrement == IncrementStrategy.Inherit)
{
log.Warning("Fallback config inherits by default, dropping to patch increment");
configIncrement = IncrementStrategy.Patch;
Expand Down
14 changes: 7 additions & 7 deletions src/GitVersionCore/Core/GitPreparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ private void CloneRepository(string repositoryUrl, string gitDirectory, Authenti
private void NormalizeGitDirectory(string gitDirectory, bool noFetch, string currentBranch, bool isDynamicRepository)
{
var authentication = options.Value.Authentication;
using var repository = new Repository(gitDirectory);
using var repository = new GitRepository(() => gitDirectory);
// Need to ensure the HEAD does not move, this is essentially a BugCheck
var expectedSha = repository.Head.Tip.Sha;
var expectedBranchName = repository.Head.CanonicalName;
Expand All @@ -221,7 +221,7 @@ private void NormalizeGitDirectory(string gitDirectory, bool noFetch, string cur
else
{
log.Info($"Fetching from remote '{remote.Name}' using the following refspecs: {string.Join(", ", remote.FetchRefSpecs.Select(r => r.Specification))}.");
Commands.Fetch(repository, remote.Name, new string[0], authentication.ToFetchOptions(), null);
repository.Commands.Fetch(remote.Name, new string[0], authentication.ToFetchOptions(), null);
}

repository.EnsureLocalBranchExistsForCurrentBranch(log, remote, currentBranch);
Expand Down Expand Up @@ -262,7 +262,7 @@ private void NormalizeGitDirectory(string gitDirectory, bool noFetch, string cur
if (matchingCurrentBranch != null)
{
log.Info($"Checking out local branch '{currentBranch}'.");
Commands.Checkout(repository, matchingCurrentBranch);
repository.Commands.Checkout(matchingCurrentBranch);
}
else if (localBranchesWhereCommitShaIsHead.Count > 1)
{
Expand All @@ -271,11 +271,11 @@ private void NormalizeGitDirectory(string gitDirectory, bool noFetch, string cur
const string moveBranchMsg = "Move one of the branches along a commit to remove warning";

log.Warning($"Found more than one local branch pointing at the commit '{headSha}' ({csvNames}).");
var master = localBranchesWhereCommitShaIsHead.SingleOrDefault(n => n.FriendlyName == "master");
var master = localBranchesWhereCommitShaIsHead.SingleOrDefault(n => n.FriendlyName.IsEquivalentTo("master"));
if (master != null)
{
log.Warning("Because one of the branches is 'master', will build master." + moveBranchMsg);
Commands.Checkout(repository, master);
repository.Commands.Checkout(master);
}
else
{
Expand All @@ -284,7 +284,7 @@ private void NormalizeGitDirectory(string gitDirectory, bool noFetch, string cur
{
var branchWithoutSeparator = branchesWithoutSeparators[0];
log.Warning($"Choosing {branchWithoutSeparator.CanonicalName} as it is the only branch without / or - in it. " + moveBranchMsg);
Commands.Checkout(repository, branchWithoutSeparator);
repository.Commands.Checkout(branchWithoutSeparator);
}
else
{
Expand All @@ -300,7 +300,7 @@ private void NormalizeGitDirectory(string gitDirectory, bool noFetch, string cur
else
{
log.Info($"Checking out local branch 'refs/heads/{localBranchesWhereCommitShaIsHead[0].FriendlyName}'.");
Commands.Checkout(repository, repository.Branches[localBranchesWhereCommitShaIsHead[0].FriendlyName]);
repository.Commands.Checkout(repository.Branches[localBranchesWhereCommitShaIsHead[0].FriendlyName]);
}
}
finally
Expand Down
12 changes: 10 additions & 2 deletions src/GitVersionCore/Core/GitRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,20 @@

namespace GitVersion
{
public class GitRepository : IRepository
public class GitRepository : IGitRepository
{
private Lazy<IRepository> repositoryLazy;
private IRepository repositoryInstance => repositoryLazy.Value;

public GitRepository(IOptions<GitVersionOptions> options)
: this(() => options.Value.DotGitDirectory)
{
repositoryLazy = new Lazy<IRepository>(() => new Repository(options.Value.DotGitDirectory));
}

public GitRepository(Func<string> getDotGitDirectory)
{
repositoryLazy = new Lazy<IRepository>(() => new Repository(getDotGitDirectory()));
Commands = new GitRepositoryCommands(repositoryLazy);
}

public void Dispose()
Expand Down Expand Up @@ -161,5 +167,7 @@ public void RevParse(string revision, out Reference reference, out GitObject obj
public Network Network => repositoryInstance.Network;

public StashCollection Stashes => repositoryInstance.Stashes;

public IGitRepositoryCommands Commands { get; }
}
}
Loading