diff --git a/NGitLab.Mock/Clients/CommitClient.cs b/NGitLab.Mock/Clients/CommitClient.cs
index 4302979f..8b0c248b 100644
--- a/NGitLab.Mock/Clients/CommitClient.cs
+++ b/NGitLab.Mock/Clients/CommitClient.cs
@@ -67,4 +67,9 @@ public JobStatus GetJobStatus(string branchName)
return GitLabCollectionResponse.Create(relatedMerqueRequests);
}
}
+
+ public Commit Revert(CommitRevert revert)
+ {
+ throw new NotImplementedException();
+ }
}
diff --git a/NGitLab.Tests/CommitsTests.cs b/NGitLab.Tests/CommitsTests.cs
index 2e4ebda4..741c1336 100644
--- a/NGitLab.Tests/CommitsTests.cs
+++ b/NGitLab.Tests/CommitsTests.cs
@@ -119,6 +119,54 @@ public async Task Test_can_cherry_pick_commit()
Assert.That(latestCommit.Id, Is.EqualTo(cherryPickedCommit.Id));
}
+ [Test]
+ [NGitLabRetry]
+ public async Task Test_can_revert_commit()
+ {
+ // Arrange
+ using var context = await GitLabTestContext.CreateAsync();
+ var project = context.CreateProject();
+
+ var testBranchName = "revert-test";
+
+ var repositoryClient = context.Client.GetRepository(project.Id);
+ repositoryClient.Branches.Create(new BranchCreate
+ {
+ Name = testBranchName,
+ Ref = project.DefaultBranch,
+ });
+
+ var commitClient = context.Client.GetCommits(project.Id);
+ var testCommit = commitClient.Create(new CommitCreate
+ {
+ Branch = testBranchName,
+ CommitMessage = "This commit will be reverted",
+ Actions =
+ [
+ new()
+ {
+ Action = "update",
+ Content = "Testing commit revert",
+ FilePath = "README.md",
+ },
+ ],
+ });
+
+ var compareResults = repositoryClient.Compare(new CompareQuery(project.DefaultBranch, testBranchName));
+ Assert.That(compareResults.Diff, Has.Length.EqualTo(1));
+
+ // Act
+ var revertedCommit = commitClient.Revert(new CommitRevert
+ {
+ Branch = testBranchName,
+ Sha = testCommit.Id,
+ });
+
+ // Assert
+ compareResults = repositoryClient.Compare(new CompareQuery(project.DefaultBranch, testBranchName));
+ Assert.That(compareResults.Diff, Is.Empty);
+ }
+
[TestCase(false)]
[TestCase(true)]
[NGitLabRetry]
diff --git a/NGitLab.Tests/EventTests.cs b/NGitLab.Tests/EventTests.cs
index 23eeb40d..cef7af6a 100644
--- a/NGitLab.Tests/EventTests.cs
+++ b/NGitLab.Tests/EventTests.cs
@@ -13,33 +13,72 @@ public class EventTests
[NGitLabRetry]
public async Task Test_get_user_events_works()
{
+ // Arrange
using var context = await GitLabTestContext.CreateAsync();
var project = context.CreateProject();
var currentUserId = context.Client.Users.Current.Id;
- var userEvents = context.Client.GetUserEvents(currentUserId);
- var globalEvents = context.Client.GetEvents();
+ var userEventClient = context.Client.GetUserEvents(currentUserId);
- var firstEvent = userEvents.Get(new EventQuery { After = DateTime.UtcNow.AddMonths(-1) }).FirstOrDefault();
+ // Act
+ var firstEvent = userEventClient.Get(new EventQuery { After = DateTime.UtcNow.AddMonths(-1) }).FirstOrDefault();
- if (firstEvent != null)
- {
- Assert.That(firstEvent.AuthorId, Is.EqualTo(currentUserId));
- }
+ // Assert
+ Assert.That(firstEvent, Is.Not.Null);
+ Assert.That(firstEvent.AuthorId, Is.EqualTo(currentUserId));
}
[Test]
[NGitLabRetry]
public async Task Test_get_global_events_works()
{
+ // Arrange
using var context = await GitLabTestContext.CreateAsync();
var project = context.CreateProject();
- var currentUserId = context.Client.Users.Current.Id;
- var globalEvents = context.Client.GetEvents();
+ var globalEventClient = context.Client.GetEvents();
- var firstEvent = globalEvents.Get(new EventQuery { After = DateTime.UtcNow.AddMonths(-1) }).FirstOrDefault();
+ // Act
+ var firstEvent = globalEventClient.Get(new EventQuery { After = DateTime.UtcNow.AddMonths(-1) }).FirstOrDefault();
+ // Assert
Assert.That(firstEvent, Is.Not.Null);
}
+
+ [Test]
+ [NGitLabRetry]
+ public async Task Test_get_events_of_specific_action_type()
+ {
+ // Arrange
+ using var context = await GitLabTestContext.CreateAsync();
+ var project = context.CreateProject();
+
+ var issueClient = context.Client.Issues;
+ var issueTitle = $"Temporary Issue {Guid.NewGuid()}";
+ var issue = issueClient.Create(new IssueCreate
+ {
+ ProjectId = project.Id,
+ Title = issueTitle,
+ });
+
+ issueClient.Edit(new IssueEdit
+ {
+ ProjectId = project.Id,
+ IssueId = issue.IssueId,
+ State = "close",
+ });
+
+ var currentUserId = context.Client.Users.Current.Id;
+ var userEventClient = context.Client.GetUserEvents(currentUserId);
+
+ // Act
+ var closedEvents = userEventClient.Get(new EventQuery { Action = EventAction.Closed }).ToArray();
+
+ // Assert
+ Assert.That(closedEvents.All(e => e.Action.EnumValue is EventAction.Closed), Is.True);
+
+ var issueClosedEvent = closedEvents.SingleOrDefault(e => string.Equals(e.TargetTitle, issueTitle, StringComparison.Ordinal));
+ Assert.That(issueClosedEvent, Is.Not.Null);
+ Assert.That(issueClosedEvent.TargetType.EnumValue, Is.EqualTo(EventTargetType.Issue));
+ }
}
diff --git a/NGitLab.Tests/Impl/UtilsTests.cs b/NGitLab.Tests/Impl/UtilsTests.cs
index f4df615f..b785b25e 100644
--- a/NGitLab.Tests/Impl/UtilsTests.cs
+++ b/NGitLab.Tests/Impl/UtilsTests.cs
@@ -6,7 +6,7 @@ namespace NGitLab.Tests.Impl;
public class UtilsTests
{
[TestCase(EventAction.PushedTo, "pushed+to")]
- [TestCase(EventAction.Accepted, "Accepted")]
+ [TestCase(EventAction.Accepted, "accepted")]
public void AddParameter_ConsidersEnumMemberAttribute(EventAction value, string expectedQueryParamValue)
{
const string basePath = "https://gitlab.org/api/v4/stuff";
diff --git a/NGitLab/ICommitClient.cs b/NGitLab/ICommitClient.cs
index 7f290df1..050777df 100644
--- a/NGitLab/ICommitClient.cs
+++ b/NGitLab/ICommitClient.cs
@@ -27,6 +27,11 @@ public interface ICommitClient
///
Commit CherryPick(CommitCherryPick cherryPick);
+ ///
+ /// Reverts a specific branch commit
+ ///
+ Commit Revert(CommitRevert revert);
+
///
/// Get merge requests related to a commit
///
diff --git a/NGitLab/Impl/CommitClient.cs b/NGitLab/Impl/CommitClient.cs
index 1daf6a49..8f00cf59 100644
--- a/NGitLab/Impl/CommitClient.cs
+++ b/NGitLab/Impl/CommitClient.cs
@@ -55,4 +55,9 @@ public GitLabCollectionResponse GetRelatedMergeRequestsAsync(Relat
{
return _api.Get().GetAllAsync(_repoPath + $"/commits/{query.Sha}/merge_requests");
}
+
+ public Commit Revert(CommitRevert revert)
+ {
+ return _api.Post().With(revert).To($"{_repoPath}/commits/{revert.Sha}/revert");
+ }
}
diff --git a/NGitLab/Models/CommitRevert.cs b/NGitLab/Models/CommitRevert.cs
new file mode 100644
index 00000000..dcc87c14
--- /dev/null
+++ b/NGitLab/Models/CommitRevert.cs
@@ -0,0 +1,18 @@
+using System.ComponentModel.DataAnnotations;
+using System.Text.Json.Serialization;
+
+namespace NGitLab.Models;
+
+public class CommitRevert
+{
+ [Required]
+ [JsonIgnore]
+ public Sha1 Sha { get; set; }
+
+ [Required]
+ [JsonPropertyName("branch")]
+ public string Branch { get; set; }
+
+ [JsonPropertyName("dry_run")]
+ public bool? DryRun { get; set; }
+}
diff --git a/NGitLab/Models/EventAction.cs b/NGitLab/Models/EventAction.cs
index 9457761c..bd76e2f9 100644
--- a/NGitLab/Models/EventAction.cs
+++ b/NGitLab/Models/EventAction.cs
@@ -4,21 +4,37 @@ namespace NGitLab.Models;
public enum EventAction
{
+ [EnumMember(Value = "accepted")]
Accepted,
+ [EnumMember(Value = "approved")]
Approved,
+ [EnumMember(Value = "created")]
Created,
+ [EnumMember(Value = "updated")]
Updated,
+ [EnumMember(Value = "uploaded")]
Uploaded,
+ [EnumMember(Value = "deleted")]
Deleted,
+ [EnumMember(Value = "closed")]
Closed,
+ [EnumMember(Value = "opened")]
Opened,
+ [EnumMember(Value = "reopened")]
Reopened,
+ [EnumMember(Value = "pushed")]
Pushed,
+ [EnumMember(Value = "commented")]
Commented,
+ [EnumMember(Value = "merged")]
Merged,
+ [EnumMember(Value = "joined")]
Joined,
+ [EnumMember(Value = "left")]
Left,
+ [EnumMember(Value = "destroyed")]
Destroyed,
+ [EnumMember(Value = "expired")]
Expired,
[EnumMember(Value = "pushed new")]
PushedNew,
diff --git a/NGitLab/Models/IssueCreate.cs b/NGitLab/Models/IssueCreate.cs
index 92dc888e..212e7258 100644
--- a/NGitLab/Models/IssueCreate.cs
+++ b/NGitLab/Models/IssueCreate.cs
@@ -38,4 +38,7 @@ public class IssueCreate
[JsonPropertyName("epic_id")]
public long? EpicId { get; set; }
+
+ [JsonPropertyName("weight")]
+ public int? Weight { get; set; }
}
diff --git a/NGitLab/Models/IssueEdit.cs b/NGitLab/Models/IssueEdit.cs
index 3a1c4e43..0c69dfa4 100644
--- a/NGitLab/Models/IssueEdit.cs
+++ b/NGitLab/Models/IssueEdit.cs
@@ -41,4 +41,7 @@ public class IssueEdit
[JsonPropertyName("epic_id")]
public long? EpicId { get; set; }
+
+ [JsonPropertyName("weight")]
+ public int? Weight { get; set; }
}
diff --git a/NGitLab/Models/ProjectUpdate.cs b/NGitLab/Models/ProjectUpdate.cs
index e60dde17..2ede3ec4 100644
--- a/NGitLab/Models/ProjectUpdate.cs
+++ b/NGitLab/Models/ProjectUpdate.cs
@@ -22,8 +22,12 @@ public sealed class ProjectUpdate
[Obsolete("Deprecated by GitLab. Use IssuesAccessLevel instead")]
public bool? IssuesEnabled { get; set; }
+ [JsonIgnore]
+ [Obsolete("Use IssuesAccessLevel instead")]
+ public string IssuesAccessLeve { get => IssuesAccessLevel; set => IssuesAccessLevel = value; }
+
[JsonPropertyName("issues_access_level")]
- public string IssuesAccessLeve { get; set; }
+ public string IssuesAccessLevel { get; set; }
[JsonPropertyName("merge_pipelines_enabled")]
public bool MergePipelinesEnabled { get; set; }
@@ -92,6 +96,9 @@ public sealed class ProjectUpdate
[JsonPropertyName("request_access_enabled")]
public bool? RequestAccessEnabled { get; set; }
+ [JsonPropertyName("repository_access_level")]
+ public string RepositoryAccessLevel { get; set; }
+
[JsonPropertyName("packages_enabled")]
public bool? PackagesEnabled { get; set; }
diff --git a/NGitLab/PublicAPI.Unshipped.txt b/NGitLab/PublicAPI.Unshipped.txt
index f3e14d2b..c4c7ece5 100644
--- a/NGitLab/PublicAPI.Unshipped.txt
+++ b/NGitLab/PublicAPI.Unshipped.txt
@@ -132,6 +132,7 @@ NGitLab.ICommitClient.Create(NGitLab.Models.CommitCreate commit) -> NGitLab.Mode
NGitLab.ICommitClient.GetCommit(string ref) -> NGitLab.Models.Commit
NGitLab.ICommitClient.GetJobStatus(string branchName) -> NGitLab.JobStatus
NGitLab.ICommitClient.GetRelatedMergeRequestsAsync(NGitLab.Models.RelatedMergeRequestsQuery query) -> NGitLab.GitLabCollectionResponse
+NGitLab.ICommitClient.Revert(NGitLab.Models.CommitRevert revert) -> NGitLab.Models.Commit
NGitLab.ICommitStatusClient
NGitLab.ICommitStatusClient.AddOrUpdate(NGitLab.Models.CommitStatusCreate status) -> NGitLab.Models.CommitStatusCreate
NGitLab.ICommitStatusClient.AllBySha(string commitSha) -> System.Collections.Generic.IEnumerable
@@ -475,6 +476,7 @@ NGitLab.Impl.CommitClient.Create(NGitLab.Models.CommitCreate commit) -> NGitLab.
NGitLab.Impl.CommitClient.GetCommit(string ref) -> NGitLab.Models.Commit
NGitLab.Impl.CommitClient.GetJobStatus(string branchName) -> NGitLab.JobStatus
NGitLab.Impl.CommitClient.GetRelatedMergeRequestsAsync(NGitLab.Models.RelatedMergeRequestsQuery query) -> NGitLab.GitLabCollectionResponse
+NGitLab.Impl.CommitClient.Revert(NGitLab.Models.CommitRevert revert) -> NGitLab.Models.Commit
NGitLab.Impl.CommitStatusClient
NGitLab.Impl.CommitStatusClient.AddOrUpdate(NGitLab.Models.CommitStatusCreate status) -> NGitLab.Models.CommitStatusCreate
NGitLab.Impl.CommitStatusClient.AllBySha(string commitSha) -> System.Collections.Generic.IEnumerable
@@ -1530,6 +1532,14 @@ NGitLab.Models.CommitRefType
NGitLab.Models.CommitRefType.All = 0 -> NGitLab.Models.CommitRefType
NGitLab.Models.CommitRefType.Branch = 1 -> NGitLab.Models.CommitRefType
NGitLab.Models.CommitRefType.Tag = 2 -> NGitLab.Models.CommitRefType
+NGitLab.Models.CommitRevert
+NGitLab.Models.CommitRevert.Branch.get -> string
+NGitLab.Models.CommitRevert.Branch.set -> void
+NGitLab.Models.CommitRevert.CommitRevert() -> void
+NGitLab.Models.CommitRevert.DryRun.get -> bool?
+NGitLab.Models.CommitRevert.DryRun.set -> void
+NGitLab.Models.CommitRevert.Sha.get -> NGitLab.Sha1
+NGitLab.Models.CommitRevert.Sha.set -> void
NGitLab.Models.CommitStats
NGitLab.Models.CommitStats.Additions.get -> int
NGitLab.Models.CommitStats.Additions.set -> void
@@ -2291,6 +2301,8 @@ NGitLab.Models.IssueCreate.ProjectId.get -> long
NGitLab.Models.IssueCreate.ProjectId.set -> void
NGitLab.Models.IssueCreate.Title.get -> string
NGitLab.Models.IssueCreate.Title.set -> void
+NGitLab.Models.IssueCreate.Weight.get -> int?
+NGitLab.Models.IssueCreate.Weight.set -> void
NGitLab.Models.IssueEdit
NGitLab.Models.IssueEdit.AssigneeId.get -> long?
NGitLab.Models.IssueEdit.AssigneeId.set -> void
@@ -2315,6 +2327,8 @@ NGitLab.Models.IssueEdit.State.get -> string
NGitLab.Models.IssueEdit.State.set -> void
NGitLab.Models.IssueEdit.Title.get -> string
NGitLab.Models.IssueEdit.Title.set -> void
+NGitLab.Models.IssueEdit.Weight.get -> int?
+NGitLab.Models.IssueEdit.Weight.set -> void
NGitLab.Models.IssueEpic
NGitLab.Models.IssueEpic.EpicId.get -> long
NGitLab.Models.IssueEpic.EpicId.set -> void
@@ -3734,6 +3748,8 @@ NGitLab.Models.ProjectUpdate.GroupRunnersEnabled.get -> bool?
NGitLab.Models.ProjectUpdate.GroupRunnersEnabled.set -> void
NGitLab.Models.ProjectUpdate.IssuesAccessLeve.get -> string
NGitLab.Models.ProjectUpdate.IssuesAccessLeve.set -> void
+NGitLab.Models.ProjectUpdate.IssuesAccessLevel.get -> string
+NGitLab.Models.ProjectUpdate.IssuesAccessLevel.set -> void
NGitLab.Models.ProjectUpdate.IssuesEnabled.get -> bool?
NGitLab.Models.ProjectUpdate.IssuesEnabled.set -> void
NGitLab.Models.ProjectUpdate.JobsEnabled.get -> bool?
@@ -3763,6 +3779,8 @@ NGitLab.Models.ProjectUpdate.PublicBuilds.get -> bool?
NGitLab.Models.ProjectUpdate.PublicBuilds.set -> void
NGitLab.Models.ProjectUpdate.RemoveSourceBranchAfterMerge.get -> bool?
NGitLab.Models.ProjectUpdate.RemoveSourceBranchAfterMerge.set -> void
+NGitLab.Models.ProjectUpdate.RepositoryAccessLevel.get -> string
+NGitLab.Models.ProjectUpdate.RepositoryAccessLevel.set -> void
NGitLab.Models.ProjectUpdate.RequestAccessEnabled.get -> bool?
NGitLab.Models.ProjectUpdate.RequestAccessEnabled.set -> void
NGitLab.Models.ProjectUpdate.ResolveOutdatedDiffDiscussions.get -> bool?