Skip to content
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
67 changes: 67 additions & 0 deletions NGitLab.Mock.Tests/TagTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,71 @@ public async Task SearchTags()
Assert.That(tags.Count(), Is.EqualTo(expectedCount), $"Expected search expression '{searchExpression}' to return {expectedCount} results.");
}
}

[Test]
public async Task EnumerateTags_FivePerPageAndWithStartPageSpecified()
{
// Arrange
using var server = new GitLabConfig()
.WithUser("user1", isDefault: true)
.WithProject("test-project", id: 1, addDefaultUserAsMaintainer: true, configure: project =>
{
project.WithCommit("Commit with tags", tags: Enumerable.Range(0, 20).Select(i => $"1.{i}.0").ToArray());
})
.BuildServer();

var client = server.CreateClient();
var tagClient = client.GetRepository(1).Tags;

var perPage = 5;

(int? StartPage, string[] ExpectedTags)[] testCases =
[
(null, ["1.19.0", "1.18.0", "1.17.0", "1.16.0", "1.15.0"]),
(1, ["1.19.0", "1.18.0", "1.17.0", "1.16.0", "1.15.0"]),
(2, ["1.14.0", "1.13.0", "1.12.0", "1.11.0", "1.10.0"]),
(4, ["1.4.0", "1.3.0", "1.2.0", "1.1.0", "1.0.0"]),
(5, []),
];

foreach (var (startPage, expectedTags) in testCases)
{
// Act
var tags = tagClient.GetAsync(new TagQuery { OrderBy = "version", PerPage = perPage, Page = startPage }).AsEnumerable().Take(perPage).ToArray();

// Assert
Assert.That(tags.Select(t => t.Name), Is.EqualTo(expectedTags));
}
}

[Test]
public async Task EnumerateTags_WithPreviousTagSpecified()
{
// Arrange
using var server = new GitLabConfig()
.WithUser("user1", isDefault: true)
.WithProject("test-project", id: 1, addDefaultUserAsMaintainer: true, configure: project =>
{
project.WithCommit("Commit with tags", tags: Enumerable.Range(0, 10).Select(i => $"1.{i}.0").ToArray());
})
.BuildServer();

var client = server.CreateClient();
var tagClient = client.GetRepository(1).Tags;

(string PreviousTag, string[] ExpectedTags)[] testCases =
[
(null, ["1.9.0", "1.8.0", "1.7.0", "1.6.0", "1.5.0", "1.4.0", "1.3.0", "1.2.0", "1.1.0", "1.0.0"]),
("1.3.0", ["1.2.0", "1.1.0", "1.0.0"]),
];

foreach (var (previousTag, expectedTags) in testCases)
{
// Act
var tags = tagClient.GetAsync(new TagQuery { OrderBy = "version", PageToken = previousTag }).AsEnumerable().ToArray();

// Assert
Assert.That(tags.Select(t => t.Name), Is.EqualTo(expectedTags));
}
}
}
15 changes: 14 additions & 1 deletion NGitLab.Mock/Clients/TagClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,12 +141,25 @@ public Tag ToTagClient(LibGit2Sharp.Tag tag)
if (string.IsNullOrEmpty(direction))
direction = "desc";

return direction switch
tags = direction switch
{
"desc" => tags.Reverse(),
"asc" => tags,
_ => throw new NotSupportedException($"Sort direction must be 'asc' or 'desc', got '{direction}' instead"),
};

if (!string.IsNullOrEmpty(query.PageToken))
{
tags = tags.SkipWhile(t => !string.Equals(t.FriendlyName, query.PageToken, StringComparison.Ordinal)).Skip(1);
}

if (query.Page.HasValue)
{
var skip = (query.Page.Value - 1) * (query.PerPage ?? 20);
tags = tags.Skip(skip);
}

return tags;
}
}

Expand Down
72 changes: 72 additions & 0 deletions NGitLab.Tests/TagTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,4 +125,76 @@ public async Task GetTag(string tagNameSought, bool expectExistence)
Assert.That(ex.StatusCode, Is.EqualTo(HttpStatusCode.NotFound));
}
}

[NGitLabRetry]
[Test]
public async Task EnumerateTags_FivePerPageAndWithStartPageSpecified()
{
// Arrange
using var context = await GitLabTestContext.CreateAsync();
var project = context.CreateProject(initializeWithCommits: true);
var tagClient = context.Client.GetRepository(project.Id).Tags;
var perPage = 5;

for (var i = 0; i < 20; i++)
{
tagClient.Create(new TagCreate
{
Name = $"1.{i}.0",
Ref = project.DefaultBranch,
});
}

(int? StartPage, string[] ExpectedTags)[] testCases =
[
(null, ["1.19.0", "1.18.0", "1.17.0", "1.16.0", "1.15.0"]),
(1, ["1.19.0", "1.18.0", "1.17.0", "1.16.0", "1.15.0"]),
(2, ["1.14.0", "1.13.0", "1.12.0", "1.11.0", "1.10.0"]),
(4, ["1.4.0", "1.3.0", "1.2.0", "1.1.0", "1.0.0"]),
(5, []),
];

foreach (var (startPage, expectedTags) in testCases)
{
// Act
var tags = tagClient.GetAsync(new TagQuery { OrderBy = "version", PerPage = perPage, Page = startPage }).AsEnumerable().Take(perPage).ToArray();

// Assert
Assert.That(tags.Select(t => t.Name), Is.EqualTo(expectedTags));
}
}

[NGitLabRetry]
[Test]
public async Task EnumerateTags_WithPreviousTagSpecified()
{
// Arrange
using var context = await GitLabTestContext.CreateAsync();
var project = context.CreateProject(initializeWithCommits: true);
var tagClient = context.Client.GetRepository(project.Id).Tags;

for (var i = 0; i < 10; i++)
{
tagClient.Create(new TagCreate
{
Name = $"1.{i}.0",
Ref = project.DefaultBranch,
});
}

(string PreviousTag, string[] ExpectedTags)[] testCases =
[
(null, ["1.9.0", "1.8.0", "1.7.0", "1.6.0", "1.5.0", "1.4.0", "1.3.0", "1.2.0", "1.1.0", "1.0.0"]),
("1.3.0", ["1.2.0", "1.1.0", "1.0.0"]),
];

foreach (var (previousTag, expectedTags) in testCases)
{
// Act
var tags = tagClient.GetAsync(new TagQuery { OrderBy = "version", PageToken = previousTag }).AsEnumerable().ToArray();

// Assert
Assert.That(tags.Select(t => t.Name), Is.EqualTo(expectedTags));
}
}
}
2 changes: 2 additions & 0 deletions NGitLab/Impl/TagClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ public GitLabCollectionResponse<Tag> GetAsync(TagQuery query)
url = Utils.AddParameter(url, "sort", query.Sort);
url = Utils.AddParameter(url, "per_page", query.PerPage);
url = Utils.AddParameter(url, "search", query.Search);
url = Utils.AddParameter(url, "page", query.Page);
url = Utils.AddParameter(url, "page_token", query.PageToken);
}

return _api.Get().GetAllAsync<Tag>(url);
Expand Down
4 changes: 3 additions & 1 deletion NGitLab/Models/Tag.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System.Text.Json.Serialization;
using System.Diagnostics;
using System.Text.Json.Serialization;

namespace NGitLab.Models;

[DebuggerDisplay("{Name,nq}")]
public class Tag
{
[JsonPropertyName("name")]
Expand Down
26 changes: 26 additions & 0 deletions NGitLab/Models/TagQuery.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,38 @@
namespace NGitLab.Models;

/// <summary>
/// A filter and sort query when <see href="https://docs.gitlab.com/ee/api/tags.html#list-all-project-repository-tags">
/// listing all project repository tags</see>.
/// </summary>
public class TagQuery
{
/// <summary>
/// Specifies how to order tags, i.e. by "name", "updated" or (semantic) "version". Default is "updated".
/// </summary>
public string OrderBy { get; set; }

/// <summary>
/// Sort order, i.e. "asc" or "desc". Default is "desc".
/// </summary>
public string Sort { get; set; }

/// <summary>
/// Number of results to return per page. Default is 20.
/// </summary>
public int? PerPage { get; set; }

/// <summary>
/// Search criteria. You can use "^term" and "term$" to find tags that begin and end with "term". No other regular expressions are supported.
/// </summary>
public string Search { get; set; }

/// <summary>
/// Start page number. Default is 1.
/// </summary>
public int? Page { get; set; }

/// <summary>
/// Previous tag name, i.e. tag to start the pagination from. Used to fetch the next set of results.
/// </summary>
public string PageToken { get; set; }
}
4 changes: 4 additions & 0 deletions NGitLab/PublicAPI/net10.0/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4665,6 +4665,10 @@ NGitLab.Models.TagProtect.TagProtect(string name) -> void
NGitLab.Models.TagQuery
NGitLab.Models.TagQuery.OrderBy.get -> string
NGitLab.Models.TagQuery.OrderBy.set -> void
NGitLab.Models.TagQuery.Page.get -> int?
NGitLab.Models.TagQuery.Page.set -> void
NGitLab.Models.TagQuery.PageToken.get -> string
NGitLab.Models.TagQuery.PageToken.set -> void
NGitLab.Models.TagQuery.PerPage.get -> int?
NGitLab.Models.TagQuery.PerPage.set -> void
NGitLab.Models.TagQuery.Search.get -> string
Expand Down
4 changes: 4 additions & 0 deletions NGitLab/PublicAPI/net472/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4666,6 +4666,10 @@ NGitLab.Models.TagProtect.TagProtect(string name) -> void
NGitLab.Models.TagQuery
NGitLab.Models.TagQuery.OrderBy.get -> string
NGitLab.Models.TagQuery.OrderBy.set -> void
NGitLab.Models.TagQuery.Page.get -> int?
NGitLab.Models.TagQuery.Page.set -> void
NGitLab.Models.TagQuery.PageToken.get -> string
NGitLab.Models.TagQuery.PageToken.set -> void
NGitLab.Models.TagQuery.PerPage.get -> int?
NGitLab.Models.TagQuery.PerPage.set -> void
NGitLab.Models.TagQuery.Search.get -> string
Expand Down
4 changes: 4 additions & 0 deletions NGitLab/PublicAPI/net8.0/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4665,6 +4665,10 @@ NGitLab.Models.TagProtect.TagProtect(string name) -> void
NGitLab.Models.TagQuery
NGitLab.Models.TagQuery.OrderBy.get -> string
NGitLab.Models.TagQuery.OrderBy.set -> void
NGitLab.Models.TagQuery.Page.get -> int?
NGitLab.Models.TagQuery.Page.set -> void
NGitLab.Models.TagQuery.PageToken.get -> string
NGitLab.Models.TagQuery.PageToken.set -> void
NGitLab.Models.TagQuery.PerPage.get -> int?
NGitLab.Models.TagQuery.PerPage.set -> void
NGitLab.Models.TagQuery.Search.get -> string
Expand Down
4 changes: 4 additions & 0 deletions NGitLab/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4666,6 +4666,10 @@ NGitLab.Models.TagProtect.TagProtect(string name) -> void
NGitLab.Models.TagQuery
NGitLab.Models.TagQuery.OrderBy.get -> string
NGitLab.Models.TagQuery.OrderBy.set -> void
NGitLab.Models.TagQuery.Page.get -> int?
NGitLab.Models.TagQuery.Page.set -> void
NGitLab.Models.TagQuery.PageToken.get -> string
NGitLab.Models.TagQuery.PageToken.set -> void
NGitLab.Models.TagQuery.PerPage.get -> int?
NGitLab.Models.TagQuery.PerPage.set -> void
NGitLab.Models.TagQuery.Search.get -> string
Expand Down
Loading