From 0678c6fd343e2e0f2b2b1d28b1ee35e11dd76694 Mon Sep 17 00:00:00 2001 From: Thomas Cortes Date: Tue, 24 Feb 2026 17:49:27 -0500 Subject: [PATCH] feat: implement filename/path for project search --- NGitLab.Mock.Tests/ProjectSearchTests.cs | 61 +++++++++++++++++++++ NGitLab.Mock/Clients/ProjectSearchClient.cs | 60 ++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 NGitLab.Mock.Tests/ProjectSearchTests.cs diff --git a/NGitLab.Mock.Tests/ProjectSearchTests.cs b/NGitLab.Mock.Tests/ProjectSearchTests.cs new file mode 100644 index 00000000..26224d28 --- /dev/null +++ b/NGitLab.Mock.Tests/ProjectSearchTests.cs @@ -0,0 +1,61 @@ +using System; +using System.Linq; +using NGitLab.Mock.Config; +using NUnit.Framework; + +namespace NGitLab.Mock.Tests; + +public class ProjectSearchTests +{ + [Test] + public void ShouldSearchInProjectByFilePath() + { + using var server = new GitLabConfig() + .WithUser("user1", isDefault: true) + .WithProject("Test", id: 1) + .BuildServer(); + + var user = server.Users.Single(); + var project = server.AllProjects.Single(); + + project.Repository.Commit(user, "Initial commit", + [ + File.CreateFromText($"subfolder/README.md", "# Title"), + ]); + + var client = server.CreateClient(); + + var searchClient = client.GetProjectSearchClient(project.Id); + var result = searchClient.GetBlobsAsync(new SearchQuery { Search = "path:subfolder/README.md" }); + + var blob = result.Single(); + Assert.That(blob.FileName, Is.EqualTo("README.md")); + Assert.That(blob.Path, Is.EqualTo("subfolder/README.md")); + } + + [Test] + public void ShouldSearchInProjectByFilename() + { + using var server = new GitLabConfig() + .WithUser("user1", isDefault: true) + .WithProject("Test", id: 1) + .BuildServer(); + + var user = server.Users.Single(); + var project = server.AllProjects.Single(); + + project.Repository.Commit(user, "Initial commit", + [ + File.CreateFromText($"subfolder/README.md", "# Title"), + ]); + + var client = server.CreateClient(); + + var searchClient = client.GetProjectSearchClient(project.Id); + var result = searchClient.GetBlobsAsync(new SearchQuery { Search = "filename:README.md" }); + + var blob = result.Single(); + Assert.That(blob.FileName, Is.EqualTo("README.md")); + Assert.That(blob.Path, Is.EqualTo("subfolder/README.md")); + } +} diff --git a/NGitLab.Mock/Clients/ProjectSearchClient.cs b/NGitLab.Mock/Clients/ProjectSearchClient.cs index 637fdff2..aa0bd215 100644 --- a/NGitLab.Mock/Clients/ProjectSearchClient.cs +++ b/NGitLab.Mock/Clients/ProjectSearchClient.cs @@ -1,4 +1,8 @@ using System; +using System.Collections.Generic; +using System.IO; +using NGitLab.Extensions; +using NGitLab.Mock.Internals; using NGitLab.Models; namespace NGitLab.Mock.Clients; @@ -17,6 +21,62 @@ public ProjectSearchClient(ClientContext context, ProjectId projectId) public GitLabCollectionResponse GetBlobsAsync(SearchQuery query) { + if (query.Search.StartsWith("filename:", StringComparison.Ordinal)) + return SearchByFilename(query); + + if (query.Search.StartsWith("path:", StringComparison.Ordinal)) + return SearchByPath(query); + throw new NotImplementedException(); } + + private GitLabCollectionResponse SearchByPath(SearchQuery query) + { + var path = query.Search["path:".Length..]; + var project = _context.Server.AllProjects.FindProject(_projectId.ToStringInvariant()); + var rootUri = new Uri(project.HttpUrl.TrimEnd('/') + '/'); + var expectedUri = new Uri(rootUri, path); + var expectedFilePath = expectedUri.LocalPath; + + if (!System.IO.File.Exists(expectedFilePath)) + return GitLabCollectionResponse.Create(Array.Empty()); + + return GitLabCollectionResponse.Create([ + new SearchBlob + { + FileName = Path.GetFileName(expectedFilePath), + Ref = project.DefaultBranch, + ProjectId = project.Id, + Path = rootUri.MakeRelativeUri(expectedUri).ToString(), + Data = System.IO.File.ReadAllText(expectedFilePath), + }, + ]); + } + + private GitLabCollectionResponse SearchByFilename(SearchQuery query) + { + var filename = query.Search["filename:".Length..]; + var project = _context.Server.AllProjects.FindProject(_projectId.ToStringInvariant()); + var rootUri = new Uri(project.HttpUrl.TrimEnd('/') + '/'); + var files = Directory.GetFiles(rootUri.LocalPath, filename, searchOption: SearchOption.AllDirectories); + + if (files.Length == 0) + return GitLabCollectionResponse.Create(Array.Empty()); + + var blobs = new List(); + foreach (var file in files) + { + var fileUri = new Uri(file); + blobs.Add(new SearchBlob + { + FileName = Path.GetFileName(file), + Ref = project.DefaultBranch, + ProjectId = project.Id, + Path = rootUri.MakeRelativeUri(fileUri).ToString(), + Data = System.IO.File.ReadAllText(file), + }); + } + + return GitLabCollectionResponse.Create(blobs); + } }