diff --git a/NGitLab.Mock.Tests/BranchesMockTests.cs b/NGitLab.Mock.Tests/BranchesMockTests.cs new file mode 100644 index 00000000..18c4d03f --- /dev/null +++ b/NGitLab.Mock.Tests/BranchesMockTests.cs @@ -0,0 +1,42 @@ +using System.Linq; +using NGitLab.Mock.Config; +using NUnit.Framework; + +namespace NGitLab.Mock.Tests +{ + public class BranchesMockTests + { + [Test] + public void Test_search_branches() + { + using var server = new GitLabConfig() + .WithUser("user1", isDefault: true) + .WithProject("test-project", id: 1, addDefaultUserAsMaintainer: true, defaultBranch: "main", configure: project => project + .WithCommit("Initial commit") + .WithCommit("Commit for branch_1", sourceBranch: "branch_1")) + .BuildServer(); + + var client = server.CreateClient("user1"); + var branchClient = client.GetRepository(1).Branches; + + var branches = branchClient.Search("main").ToList(); + var expectedBranch = branches.Single(); + Assert.AreEqual("main", expectedBranch.Name); + + branches = branchClient.Search("^main$").ToList(); + expectedBranch = branches.Single(); + Assert.AreEqual("main", expectedBranch.Name); + + branches = branchClient.Search("^branch").ToList(); + expectedBranch = branches.Single(); + Assert.AreEqual("branch_1", expectedBranch.Name); + + branches = branchClient.Search("1$").ToList(); + expectedBranch = branches.Single(); + Assert.AreEqual("branch_1", expectedBranch.Name); + + branches = branchClient.Search("foobar").ToList(); + Assert.IsEmpty(branches); + } + } +} diff --git a/NGitLab.Mock/Clients/BranchClient.cs b/NGitLab.Mock/Clients/BranchClient.cs index 0b793333..194e31c6 100644 --- a/NGitLab.Mock/Clients/BranchClient.cs +++ b/NGitLab.Mock/Clients/BranchClient.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using NGitLab.Mock.Internals; using NGitLab.Models; namespace NGitLab.Mock.Clients @@ -15,6 +16,50 @@ public BranchClient(ClientContext context, int projectId) _projectId = projectId; } + public IEnumerable Search(string search) + { + Func filterBranch; + switch (search) + { + case null: + case "": + filterBranch = _ => true; + break; + + case not null when search[0] == '^' && search[search.Length - 1] == '$': + search = search.Substring(1, search.Length - 1 - 1); + filterBranch = branch => branch.Equals(search, StringComparison.OrdinalIgnoreCase); + break; + + case not null when search[0] == '^': + search = search.Substring(1); + filterBranch = branch => branch.StartsWith(search, StringComparison.OrdinalIgnoreCase); + break; + + case not null when search[search.Length - 1] == '$': + search = search.Substring(0, search.Length - 1); + filterBranch = branch => branch.EndsWith(search, StringComparison.OrdinalIgnoreCase); + break; + + default: + filterBranch = branch => branch.Contains(search, StringComparison.OrdinalIgnoreCase); + break; + } + + using (Context.BeginOperationScope()) + { + var project = GetProject(_projectId, ProjectPermission.View); + return project.Repository.GetAllBranches() + .Where(branch => filterBranch(branch.FriendlyName)) + .Select(branch => branch.ToBranchClient(project)); + } + } + + public GitLabCollectionResponse SearchAsync(string search) + { + return GitLabCollectionResponse.Create(Search(search)); + } + public Branch this[string name] { get diff --git a/NGitLab.Tests/BranchClientTests.cs b/NGitLab.Tests/BranchClientTests.cs index 7bbe65f2..5609eff4 100644 --- a/NGitLab.Tests/BranchClientTests.cs +++ b/NGitLab.Tests/BranchClientTests.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Threading.Tasks; using NGitLab.Tests.Docker; using NUnit.Framework; @@ -43,5 +44,43 @@ public async Task Test_CommitInfoIsCorrectlyDeserialized() Assert.IsTrue(Uri.TryCreate(commit.WebUrl, UriKind.Absolute, out _)); } + + [Test] + [NGitLabRetry] + public async Task Test_search_branches() + { + using var context = await GitLabTestContext.CreateAsync(); + var project = context.CreateProject(initializeWithCommits: true); + var branchClient = context.Client.GetRepository(project.Id).Branches; + + var defaultBranch = project.DefaultBranch; + + var branches = branchClient.Search(defaultBranch); + var expectedBranch = branches.Single(); + Assert.AreEqual(defaultBranch, expectedBranch.Name); + + // This case only worked with GitLab 15.7 and later + // https://gitlab.com/gitlab-org/gitlab/-/merge_requests/104451 + /* + branches = branchClient.Search($"^{defaultBranch}$"); + expectedBranch = branches.Single(); + Assert.AreEqual(defaultBranch, expectedBranch.Name); + */ + + branches = branchClient.Search($"^{defaultBranch[..^1]}"); + expectedBranch = branches.Single(); + Assert.AreEqual(defaultBranch, expectedBranch.Name); + + branches = branchClient.Search($"{defaultBranch[1..]}$"); + expectedBranch = branches.Single(); + Assert.AreEqual(defaultBranch, expectedBranch.Name); + + branches = branchClient.Search(defaultBranch[1..^1]); + expectedBranch = branches.Single(); + Assert.AreEqual(defaultBranch, expectedBranch.Name); + + branches = branchClient.Search("foobar"); + Assert.IsEmpty(branches); + } } } diff --git a/NGitLab/IBranchClient.cs b/NGitLab/IBranchClient.cs index 9a8acb2e..8e691e6a 100644 --- a/NGitLab/IBranchClient.cs +++ b/NGitLab/IBranchClient.cs @@ -7,6 +7,10 @@ public interface IBranchClient { IEnumerable All { get; } + IEnumerable Search(string search); + + GitLabCollectionResponse SearchAsync(string search); + Branch this[string name] { get; } Branch Protect(string name); diff --git a/NGitLab/Impl/BranchClient.cs b/NGitLab/Impl/BranchClient.cs index 889d0a0d..11e40e33 100644 --- a/NGitLab/Impl/BranchClient.cs +++ b/NGitLab/Impl/BranchClient.cs @@ -17,6 +17,12 @@ public BranchClient(API api, string repoPath) public IEnumerable All => _api.Get().GetAll(_repoPath + "/branches"); + public IEnumerable Search(string search) => + _api.Get().GetAll(_repoPath + "/branches?search=" + Uri.EscapeDataString(search)); + + public GitLabCollectionResponse SearchAsync(string search) => + _api.Get().GetAllAsync(_repoPath + "/branches?search=" + Uri.EscapeDataString(search)); + public Branch this[string name] => _api.Get().To(_repoPath + "/branches/" + Uri.EscapeDataString(name)); public Branch Protect(string name) => _api.Put().To(_repoPath + "/branches/" + Uri.EscapeDataString(name) + "/protect"); diff --git a/NGitLab/PublicAPI.Unshipped.txt b/NGitLab/PublicAPI.Unshipped.txt index ca8f18ee..d606cb72 100644 --- a/NGitLab/PublicAPI.Unshipped.txt +++ b/NGitLab/PublicAPI.Unshipped.txt @@ -105,6 +105,8 @@ NGitLab.IBranchClient.All.get -> System.Collections.Generic.IEnumerable NGitLab.Models.Branch NGitLab.IBranchClient.Delete(string name) -> void NGitLab.IBranchClient.Protect(string name) -> NGitLab.Models.Branch +NGitLab.IBranchClient.Search(string search) -> System.Collections.Generic.IEnumerable +NGitLab.IBranchClient.SearchAsync(string search) -> NGitLab.GitLabCollectionResponse NGitLab.IBranchClient.this[string name].get -> NGitLab.Models.Branch NGitLab.IBranchClient.Unprotect(string name) -> NGitLab.Models.Branch NGitLab.IClusterClient @@ -384,6 +386,8 @@ NGitLab.Impl.BranchClient.BranchClient(NGitLab.Impl.API api, string repoPath) -> NGitLab.Impl.BranchClient.Create(NGitLab.Models.BranchCreate branch) -> NGitLab.Models.Branch NGitLab.Impl.BranchClient.Delete(string name) -> void NGitLab.Impl.BranchClient.Protect(string name) -> NGitLab.Models.Branch +NGitLab.Impl.BranchClient.Search(string search) -> System.Collections.Generic.IEnumerable +NGitLab.Impl.BranchClient.SearchAsync(string search) -> NGitLab.GitLabCollectionResponse NGitLab.Impl.BranchClient.this[string name].get -> NGitLab.Models.Branch NGitLab.Impl.BranchClient.Unprotect(string name) -> NGitLab.Models.Branch NGitLab.Impl.ClusterClient