diff --git a/NGitLab.Mock.Tests/GroupsMockTests.cs b/NGitLab.Mock.Tests/GroupsMockTests.cs index d09395ee..13538423 100644 --- a/NGitLab.Mock.Tests/GroupsMockTests.cs +++ b/NGitLab.Mock.Tests/GroupsMockTests.cs @@ -427,4 +427,21 @@ public async Task Test_group_created_at_date() Assert.That(group.CreatedAt, Is.GreaterThanOrEqualTo(t1)); Assert.That(group.CreatedAt, Is.LessThanOrEqualTo(t2)); } + + [Test] + public async Task Test_group_page() + { + using var server = CreateProjectHierarchy(); + var client = server.CreateClient("user1"); + + var result = client.Groups.SearchProjectsAsync("tlg", new GroupProjectsQuery + { + Page = 3, + PerPage = 1, + IncludeSubGroups = true, + }).ToArray(); + + Assert.That(result, Has.Length.EqualTo(1)); + Assert.That(result[0].Name, Is.EqualTo("p3")); + } } diff --git a/NGitLab.Mock.Tests/ProjectSearchTests.cs b/NGitLab.Mock.Tests/ProjectSearchTests.cs index 26224d28..7b726aa2 100644 --- a/NGitLab.Mock.Tests/ProjectSearchTests.cs +++ b/NGitLab.Mock.Tests/ProjectSearchTests.cs @@ -1,5 +1,4 @@ -using System; -using System.Linq; +using System.Linq; using NGitLab.Mock.Config; using NUnit.Framework; diff --git a/NGitLab.Mock/Clients/GroupClient.cs b/NGitLab.Mock/Clients/GroupClient.cs index 33cd7158..fa01b3d0 100644 --- a/NGitLab.Mock/Clients/GroupClient.cs +++ b/NGitLab.Mock/Clients/GroupClient.cs @@ -221,6 +221,9 @@ public async Task RestoreAsync(long id, CancellationToken cancellationToken = de var projects = query?.IncludeSubGroups is true ? group.AllProjects : group.Projects; + var pageIndex = 0; + var perPage = query?.PerPage ?? 20; + if (query != null) { if (query.Archived != null) @@ -238,6 +241,11 @@ public async Task RestoreAsync(long id, CancellationToken cancellationToken = de projects = projects.Where(project => project.Visibility >= query.Visibility.Value); } + if (query.Page.HasValue) + { + pageIndex = query.Page.Value - 1; + } + if (!string.IsNullOrEmpty(query.Search)) throw new NotImplementedException(); @@ -246,6 +254,9 @@ public async Task RestoreAsync(long id, CancellationToken cancellationToken = de } projects = projects.Where(project => project.CanUserViewProject(Context.User)); + var lowerBound = pageIndex * perPage; + + projects = projects.Skip(lowerBound); return GitLabCollectionResponse.Create(projects.Select(project => project.ToClientProject(Context.User)).ToArray()); } } diff --git a/NGitLab.Tests/GroupsTests.cs b/NGitLab.Tests/GroupsTests.cs index 4f79f504..cd249ad8 100644 --- a/NGitLab.Tests/GroupsTests.cs +++ b/NGitLab.Tests/GroupsTests.cs @@ -456,6 +456,28 @@ public async Task Test_group_projects_query_returns_archived() Assert.That(projectResult.Id, Is.EqualTo(project.Id)); Assert.That(projectResult.Archived, Is.True); } + + [Test] + [NGitLabRetry] + public async Task Test_group_projects_query_page() + { + using var context = await GitLabTestContext.CreateAsync(); + var groupClient = context.Client.Groups; + + var group = context.CreateGroup(); + var project1 = context.CreateProject(group.Id); + var project2 = context.CreateProject(group.Id); + + var projects = groupClient.GetProjectsAsync(group.Id, new GroupProjectsQuery + { + Page = 2, + PerPage = 1, + Sort = "asc", + }).ToArray(); + + Assert.That(projects, Has.Length.EqualTo(1)); + Assert.That(projects[0].Id, Is.EqualTo(project2.Id)); + } [Test] [NGitLabRetry] diff --git a/NGitLab/Impl/GroupsClient.cs b/NGitLab/Impl/GroupsClient.cs index 821b2816..21cbb91c 100644 --- a/NGitLab/Impl/GroupsClient.cs +++ b/NGitLab/Impl/GroupsClient.cs @@ -214,7 +214,7 @@ public GitLabCollectionResponse GetProjectsAsync(long groupId, GroupPro public GitLabCollectionResponse SearchProjectsAsync(GroupId groupId, GroupProjectsQuery query) { - var url = CreateGetProjectsUrl(groupId, query); + var url = CreateGetProjectsUrl(groupId, query, page: query?.Page, perPage: query?.PerPage); return _api.Get().GetAllAsync(url); } diff --git a/NGitLab/Models/GroupProjectsQuery.cs b/NGitLab/Models/GroupProjectsQuery.cs index 3e094b11..b3b4df06 100644 --- a/NGitLab/Models/GroupProjectsQuery.cs +++ b/NGitLab/Models/GroupProjectsQuery.cs @@ -76,4 +76,14 @@ public sealed class GroupProjectsQuery /// Return only projects that have security reports artifacts present in any of their builds. This means “projects with security reports enabled”. Default is false /// public bool? WithSecurityReports { get; set; } + + /// + /// Specifies how many records per page (GitLab supports a maximum of 100 items per page and defaults to 20). + /// + public int? PerPage { get; set; } + + /// + /// Specifies the start page. + /// + public int? Page { get; set; } } diff --git a/NGitLab/PublicAPI/net10.0/PublicAPI.Unshipped.txt b/NGitLab/PublicAPI/net10.0/PublicAPI.Unshipped.txt index f62c0a2b..c3213b58 100644 --- a/NGitLab/PublicAPI/net10.0/PublicAPI.Unshipped.txt +++ b/NGitLab/PublicAPI/net10.0/PublicAPI.Unshipped.txt @@ -2287,6 +2287,10 @@ NGitLab.Models.GroupProjectsQuery.OrderBy.get -> string NGitLab.Models.GroupProjectsQuery.OrderBy.set -> void NGitLab.Models.GroupProjectsQuery.Owned.get -> bool? NGitLab.Models.GroupProjectsQuery.Owned.set -> void +NGitLab.Models.GroupProjectsQuery.Page.get -> int? +NGitLab.Models.GroupProjectsQuery.Page.set -> void +NGitLab.Models.GroupProjectsQuery.PerPage.get -> int? +NGitLab.Models.GroupProjectsQuery.PerPage.set -> void NGitLab.Models.GroupProjectsQuery.Search.get -> string NGitLab.Models.GroupProjectsQuery.Search.set -> void NGitLab.Models.GroupProjectsQuery.Simple.get -> bool? diff --git a/NGitLab/PublicAPI/net472/PublicAPI.Unshipped.txt b/NGitLab/PublicAPI/net472/PublicAPI.Unshipped.txt index 0f8bf4a7..70eaeacb 100644 --- a/NGitLab/PublicAPI/net472/PublicAPI.Unshipped.txt +++ b/NGitLab/PublicAPI/net472/PublicAPI.Unshipped.txt @@ -2288,6 +2288,10 @@ NGitLab.Models.GroupProjectsQuery.OrderBy.get -> string NGitLab.Models.GroupProjectsQuery.OrderBy.set -> void NGitLab.Models.GroupProjectsQuery.Owned.get -> bool? NGitLab.Models.GroupProjectsQuery.Owned.set -> void +NGitLab.Models.GroupProjectsQuery.Page.get -> int? +NGitLab.Models.GroupProjectsQuery.Page.set -> void +NGitLab.Models.GroupProjectsQuery.PerPage.get -> int? +NGitLab.Models.GroupProjectsQuery.PerPage.set -> void NGitLab.Models.GroupProjectsQuery.Search.get -> string NGitLab.Models.GroupProjectsQuery.Search.set -> void NGitLab.Models.GroupProjectsQuery.Simple.get -> bool? diff --git a/NGitLab/PublicAPI/net8.0/PublicAPI.Unshipped.txt b/NGitLab/PublicAPI/net8.0/PublicAPI.Unshipped.txt index f62c0a2b..c3213b58 100644 --- a/NGitLab/PublicAPI/net8.0/PublicAPI.Unshipped.txt +++ b/NGitLab/PublicAPI/net8.0/PublicAPI.Unshipped.txt @@ -2287,6 +2287,10 @@ NGitLab.Models.GroupProjectsQuery.OrderBy.get -> string NGitLab.Models.GroupProjectsQuery.OrderBy.set -> void NGitLab.Models.GroupProjectsQuery.Owned.get -> bool? NGitLab.Models.GroupProjectsQuery.Owned.set -> void +NGitLab.Models.GroupProjectsQuery.Page.get -> int? +NGitLab.Models.GroupProjectsQuery.Page.set -> void +NGitLab.Models.GroupProjectsQuery.PerPage.get -> int? +NGitLab.Models.GroupProjectsQuery.PerPage.set -> void NGitLab.Models.GroupProjectsQuery.Search.get -> string NGitLab.Models.GroupProjectsQuery.Search.set -> void NGitLab.Models.GroupProjectsQuery.Simple.get -> bool? diff --git a/NGitLab/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt b/NGitLab/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt index 0f8bf4a7..70eaeacb 100644 --- a/NGitLab/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt +++ b/NGitLab/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt @@ -2288,6 +2288,10 @@ NGitLab.Models.GroupProjectsQuery.OrderBy.get -> string NGitLab.Models.GroupProjectsQuery.OrderBy.set -> void NGitLab.Models.GroupProjectsQuery.Owned.get -> bool? NGitLab.Models.GroupProjectsQuery.Owned.set -> void +NGitLab.Models.GroupProjectsQuery.Page.get -> int? +NGitLab.Models.GroupProjectsQuery.Page.set -> void +NGitLab.Models.GroupProjectsQuery.PerPage.get -> int? +NGitLab.Models.GroupProjectsQuery.PerPage.set -> void NGitLab.Models.GroupProjectsQuery.Search.get -> string NGitLab.Models.GroupProjectsQuery.Search.set -> void NGitLab.Models.GroupProjectsQuery.Simple.get -> bool?