From 12cc6e5d264d7a678991f1911a2524bb63970f3e Mon Sep 17 00:00:00 2001 From: Louis Zanella Date: Wed, 29 Jul 2026 14:04:45 -0400 Subject: [PATCH 1/6] feat: add UnapproveMergeRequest, GetDiffsAsync with unidiff, and draft notes API Three GitLab API gaps that were missing from NGitLab: 1. IMergeRequestApprovalClient.UnapproveMergeRequest() POST /projects/:id/merge_requests/:iid/unapprove Reverses a prior approval by the authenticated user. 2. IMergeRequestClient.GetDiffsAsync(iid, MergeRequestDiffQuery) MergeRequestDiffQuery.Unidiff controls the ?unidiff=true query param (GitLab 16.5+), which returns diffs in standard unified diff format instead of the default GitLab-specific format. 3. IMergeRequestClient.DraftNotes(iid) -> IMergeRequestDraftNoteClient New IMergeRequestDraftNoteClient interface and implementation covering: - All (GET /draft_notes - list draft notes) - CreateAsync (POST /draft_notes) - PublishAllAsync (POST /draft_notes/bulk_publish) All new public symbols are registered in PublicAPI.Unshipped.txt for all TFMs. Mock stubs throw NotImplementedException (consistent with other unimplemented mocks). Co-Authored-By: Claude --- .../Clients/MergeRequestApprovalClient.cs | 5 +++ NGitLab.Mock/Clients/MergeRequestClient.cs | 12 ++++++ .../Clients/MergeRequestDraftNoteClient.cs | 23 +++++++++++ NGitLab/IMergeRequestApprovalClient.cs | 2 + NGitLab/IMergeRequestClient.cs | 4 ++ NGitLab/IMergeRequestDraftNoteClient.cs | 23 +++++++++++ NGitLab/Impl/MergeRequestApprovalClient.cs | 4 ++ NGitLab/Impl/MergeRequestClient.cs | 13 +++++++ NGitLab/Impl/MergeRequestDraftNoteClient.cs | 30 ++++++++++++++ NGitLab/Models/DraftNote.cs | 39 +++++++++++++++++++ NGitLab/Models/MergeRequestDiffQuery.cs | 13 +++++++ .../PublicAPI/net10.0/PublicAPI.Unshipped.txt | 37 ++++++++++++++++++ .../PublicAPI/net472/PublicAPI.Unshipped.txt | 37 ++++++++++++++++++ .../PublicAPI/net8.0/PublicAPI.Unshipped.txt | 37 ++++++++++++++++++ .../netstandard2.0/PublicAPI.Unshipped.txt | 37 ++++++++++++++++++ 15 files changed, 316 insertions(+) create mode 100644 NGitLab.Mock/Clients/MergeRequestDraftNoteClient.cs create mode 100644 NGitLab/IMergeRequestDraftNoteClient.cs create mode 100644 NGitLab/Impl/MergeRequestDraftNoteClient.cs create mode 100644 NGitLab/Models/DraftNote.cs create mode 100644 NGitLab/Models/MergeRequestDiffQuery.cs diff --git a/NGitLab.Mock/Clients/MergeRequestApprovalClient.cs b/NGitLab.Mock/Clients/MergeRequestApprovalClient.cs index 9f4d39e38..c018e2ff4 100644 --- a/NGitLab.Mock/Clients/MergeRequestApprovalClient.cs +++ b/NGitLab.Mock/Clients/MergeRequestApprovalClient.cs @@ -22,6 +22,11 @@ public MergeRequestApprovals ApproveMergeRequest(MergeRequestApproveRequest requ throw new NotImplementedException(); } + public void UnapproveMergeRequest() + { + throw new NotImplementedException(); + } + public void ResetApprovals() { throw new NotImplementedException(); diff --git a/NGitLab.Mock/Clients/MergeRequestClient.cs b/NGitLab.Mock/Clients/MergeRequestClient.cs index 19327748a..ae5a0c620 100644 --- a/NGitLab.Mock/Clients/MergeRequestClient.cs +++ b/NGitLab.Mock/Clients/MergeRequestClient.cs @@ -256,6 +256,13 @@ public IMergeRequestApprovalClient ApprovalClient(long mergeRequestIid) return new MergeRequestApprovalClient(Context, _projectId.GetValueOrDefault(), mergeRequestIid); } + public IMergeRequestDraftNoteClient DraftNotes(long mergeRequestIid) + { + AssertProjectId(); + + return new MergeRequestDraftNoteClient(Context); + } + public Models.MergeRequest Close(long mergeRequestIid) { AssertProjectId(); @@ -729,6 +736,11 @@ public GitLabCollectionResponse GetDiffsAsync(long mergeRequestIid) throw new NotImplementedException(); } + public GitLabCollectionResponse GetDiffsAsync(long mergeRequestIid, MergeRequestDiffQuery query) + { + throw new NotImplementedException(); + } + public Task TimeStatsAsync(long mergeRequestIid, CancellationToken cancellationToken = default) { throw new NotImplementedException(); diff --git a/NGitLab.Mock/Clients/MergeRequestDraftNoteClient.cs b/NGitLab.Mock/Clients/MergeRequestDraftNoteClient.cs new file mode 100644 index 000000000..f1a96b09c --- /dev/null +++ b/NGitLab.Mock/Clients/MergeRequestDraftNoteClient.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using NGitLab.Models; + +namespace NGitLab.Mock.Clients; + +internal sealed class MergeRequestDraftNoteClient : ClientBase, IMergeRequestDraftNoteClient +{ + public MergeRequestDraftNoteClient(ClientContext context) + : base(context) + { + } + + public IEnumerable All => throw new NotImplementedException(); + + public Task CreateAsync(DraftNoteCreate draftNote, CancellationToken cancellationToken = default) + => throw new NotImplementedException(); + + public Task PublishAllAsync(CancellationToken cancellationToken = default) + => throw new NotImplementedException(); +} diff --git a/NGitLab/IMergeRequestApprovalClient.cs b/NGitLab/IMergeRequestApprovalClient.cs index c6e715a3a..75f89eb87 100644 --- a/NGitLab/IMergeRequestApprovalClient.cs +++ b/NGitLab/IMergeRequestApprovalClient.cs @@ -10,6 +10,8 @@ public interface IMergeRequestApprovalClient MergeRequestApprovals ApproveMergeRequest(MergeRequestApproveRequest request = null); + void UnapproveMergeRequest(); + /// /// Available only for bot users based on project or group tokens. /// diff --git a/NGitLab/IMergeRequestClient.cs b/NGitLab/IMergeRequestClient.cs index d17c95526..ba4173e24 100644 --- a/NGitLab/IMergeRequestClient.cs +++ b/NGitLab/IMergeRequestClient.cs @@ -51,6 +51,8 @@ public interface IMergeRequestClient GitLabCollectionResponse GetDiffsAsync(long mergeRequestIid); + GitLabCollectionResponse GetDiffsAsync(long mergeRequestIid, MergeRequestDiffQuery query); + IMergeRequestCommentClient Comments(long mergeRequestIid); IMergeRequestDiscussionClient Discussions(long mergeRequestIid); @@ -61,6 +63,8 @@ public interface IMergeRequestClient IMergeRequestApprovalClient ApprovalClient(long mergeRequestIid); + IMergeRequestDraftNoteClient DraftNotes(long mergeRequestIid); + IEnumerable ClosesIssues(long mergeRequestIid); /// diff --git a/NGitLab/IMergeRequestDraftNoteClient.cs b/NGitLab/IMergeRequestDraftNoteClient.cs new file mode 100644 index 000000000..eff13e2dd --- /dev/null +++ b/NGitLab/IMergeRequestDraftNoteClient.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using NGitLab.Models; + +namespace NGitLab; + +/// +/// Client for the GitLab draft notes API: +/// GET/POST /projects/:id/merge_requests/:iid/draft_notes and +/// POST /projects/:id/merge_requests/:iid/draft_notes/bulk_publish. +/// +public interface IMergeRequestDraftNoteClient +{ + IEnumerable All { get; } + + Task CreateAsync(DraftNoteCreate draftNote, CancellationToken cancellationToken = default); + + /// + /// Publishes all draft notes for the merge request in a single request. + /// + Task PublishAllAsync(CancellationToken cancellationToken = default); +} diff --git a/NGitLab/Impl/MergeRequestApprovalClient.cs b/NGitLab/Impl/MergeRequestApprovalClient.cs index aa30c139b..ca45f5130 100644 --- a/NGitLab/Impl/MergeRequestApprovalClient.cs +++ b/NGitLab/Impl/MergeRequestApprovalClient.cs @@ -13,6 +13,7 @@ public class MergeRequestApprovalClient : IMergeRequestApprovalClient private readonly string _approvalsPath; private readonly string _approversPath; private readonly string _approvePath; + private readonly string _unapprovePath; private readonly string _resetApprovalsPath; private readonly string _approvalStatePath; @@ -23,6 +24,7 @@ public MergeRequestApprovalClient(API api, string projectPath, long mergeRequest _approvalsPath = projectPath + "/merge_requests/" + iid + "/approvals"; _approversPath = projectPath + "/merge_requests/" + iid + "/approvers"; _approvePath = projectPath + "/merge_requests/" + iid + "/approve"; + _unapprovePath = projectPath + "/merge_requests/" + iid + "/unapprove"; _resetApprovalsPath = projectPath + "/merge_requests/" + iid + "/reset_approvals"; _approvalStatePath = projectPath + "/merge_requests/" + iid + "/approval_state"; } @@ -32,6 +34,8 @@ public MergeRequestApprovalClient(API api, string projectPath, long mergeRequest public MergeRequestApprovals ApproveMergeRequest(MergeRequestApproveRequest request = null) => _api.Post().With(request ?? new MergeRequestApproveRequest()).To(_approvePath); + public void UnapproveMergeRequest() => _api.Post().Execute(_unapprovePath); + public void ChangeApprovers(MergeRequestApproversChange approversChange) => _api.Put().With(approversChange).To(_approversPath); public void ResetApprovals() => _api.Put().Execute(_resetApprovalsPath); diff --git a/NGitLab/Impl/MergeRequestClient.cs b/NGitLab/Impl/MergeRequestClient.cs index 2a2b09d96..be5c008e6 100644 --- a/NGitLab/Impl/MergeRequestClient.cs +++ b/NGitLab/Impl/MergeRequestClient.cs @@ -171,6 +171,17 @@ public GitLabCollectionResponse GetDiffsAsync(long mergeRequestIid) return _api.Get().GetAllAsync(_path + "/merge_requests/" + mergeRequestIid.ToString(CultureInfo.InvariantCulture) + "/diffs"); } + public GitLabCollectionResponse GetDiffsAsync(long mergeRequestIid, MergeRequestDiffQuery query) + { + var url = _path + "/merge_requests/" + mergeRequestIid.ToString(CultureInfo.InvariantCulture) + "/diffs"; + if (query?.Unidiff == true) + { + url = Utils.AddParameter(url, "unidiff", "true"); + } + + return _api.Get().GetAllAsync(url); + } + public Task TimeStatsAsync(long mergeRequestIid, CancellationToken cancellationToken = default) { return _api.Get().ToAsync(_path + "/merge_requests/" + mergeRequestIid.ToString(CultureInfo.InvariantCulture) + "/time_stats", cancellationToken); @@ -184,6 +195,8 @@ public Task TimeStatsAsync(long mergeRequestIid, CancellationToken ca public IMergeRequestApprovalClient ApprovalClient(long mergeRequestIid) => new MergeRequestApprovalClient(_api, _path, mergeRequestIid); + public IMergeRequestDraftNoteClient DraftNotes(long mergeRequestIid) => new MergeRequestDraftNoteClient(_api, _path, mergeRequestIid); + public IMergeRequestChangeClient Changes(long mergeRequestIid) => new MergeRequestChangeClient(_api, _path, mergeRequestIid); public GitLabCollectionResponse ResourceLabelEventsAsync(long projectId, long mergeRequestIid) diff --git a/NGitLab/Impl/MergeRequestDraftNoteClient.cs b/NGitLab/Impl/MergeRequestDraftNoteClient.cs new file mode 100644 index 000000000..264cd767d --- /dev/null +++ b/NGitLab/Impl/MergeRequestDraftNoteClient.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using System.Globalization; +using System.Threading; +using System.Threading.Tasks; +using NGitLab.Models; + +namespace NGitLab.Impl; + +public class MergeRequestDraftNoteClient : IMergeRequestDraftNoteClient +{ + private readonly API _api; + private readonly string _draftNotesPath; + private readonly string _bulkPublishPath; + + public MergeRequestDraftNoteClient(API api, string projectPath, long mergeRequestIid) + { + _api = api; + var iid = mergeRequestIid.ToString(CultureInfo.InvariantCulture); + _draftNotesPath = projectPath + "/merge_requests/" + iid + "/draft_notes"; + _bulkPublishPath = _draftNotesPath + "/bulk_publish"; + } + + public IEnumerable All => _api.Get().GetAll(_draftNotesPath); + + public Task CreateAsync(DraftNoteCreate draftNote, CancellationToken cancellationToken = default) + => _api.Post().With(draftNote).ToAsync(_draftNotesPath, cancellationToken); + + public Task PublishAllAsync(CancellationToken cancellationToken = default) + => _api.Post().ExecuteAsync(_bulkPublishPath, cancellationToken); +} diff --git a/NGitLab/Models/DraftNote.cs b/NGitLab/Models/DraftNote.cs new file mode 100644 index 000000000..48451387e --- /dev/null +++ b/NGitLab/Models/DraftNote.cs @@ -0,0 +1,39 @@ +using System.Text.Json.Serialization; + +namespace NGitLab.Models; + +/// +/// A draft (unpublished) note on a merge request. +/// +public class DraftNote +{ + [JsonPropertyName("id")] + public long Id { get; set; } + + [JsonPropertyName("author_id")] + public long AuthorId { get; set; } + + [JsonPropertyName("merge_request_id")] + public long MergeRequestId { get; set; } + + [JsonPropertyName("note")] + public string Note { get; set; } + + [JsonPropertyName("position")] + public Position Position { get; set; } +} + +/// +/// Payload for creating a draft note on a merge request. +/// +public class DraftNoteCreate +{ + [JsonPropertyName("note")] + public string Note { get; set; } + + /// + /// Required for inline (diff) draft notes; omit for general notes. + /// + [JsonPropertyName("position")] + public Position Position { get; set; } +} diff --git a/NGitLab/Models/MergeRequestDiffQuery.cs b/NGitLab/Models/MergeRequestDiffQuery.cs new file mode 100644 index 000000000..e7868dfe2 --- /dev/null +++ b/NGitLab/Models/MergeRequestDiffQuery.cs @@ -0,0 +1,13 @@ +namespace NGitLab.Models; + +/// +/// Query options for GET /projects/:id/merge_requests/:iid/diffs. +/// +public class MergeRequestDiffQuery +{ + /// + /// Present diffs in the unified diff format. Default is . + /// Requires GitLab 16.5 or later. + /// + public bool? Unidiff { get; set; } +} diff --git a/NGitLab/PublicAPI/net10.0/PublicAPI.Unshipped.txt b/NGitLab/PublicAPI/net10.0/PublicAPI.Unshipped.txt index ce3c6c090..ac2a49a4e 100644 --- a/NGitLab/PublicAPI/net10.0/PublicAPI.Unshipped.txt +++ b/NGitLab/PublicAPI/net10.0/PublicAPI.Unshipped.txt @@ -5307,3 +5307,40 @@ NGitLab.Models.ProjectDelete.PermanentlyRemove.get -> bool? NGitLab.Models.ProjectDelete.PermanentlyRemove.set -> void NGitLab.Models.ProjectDelete.ProjectDelete() -> void NGitLab.Impl.ProjectClient.DeleteAsync(NGitLab.Models.ProjectId projectId, NGitLab.Models.ProjectDelete options, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task +NGitLab.IMergeRequestApprovalClient.UnapproveMergeRequest() -> void +NGitLab.IMergeRequestClient.DraftNotes(long mergeRequestIid) -> NGitLab.IMergeRequestDraftNoteClient +NGitLab.IMergeRequestClient.GetDiffsAsync(long mergeRequestIid, NGitLab.Models.MergeRequestDiffQuery query) -> NGitLab.GitLabCollectionResponse +NGitLab.IMergeRequestDraftNoteClient +NGitLab.IMergeRequestDraftNoteClient.All.get -> System.Collections.Generic.IEnumerable +NGitLab.IMergeRequestDraftNoteClient.CreateAsync(NGitLab.Models.DraftNoteCreate draftNote, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task +NGitLab.IMergeRequestDraftNoteClient.PublishAllAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task +NGitLab.Impl.MergeRequestApprovalClient.UnapproveMergeRequest() -> void +NGitLab.Impl.MergeRequestClient.DraftNotes(long mergeRequestIid) -> NGitLab.IMergeRequestDraftNoteClient +NGitLab.Impl.MergeRequestClient.GetDiffsAsync(long mergeRequestIid, NGitLab.Models.MergeRequestDiffQuery query) -> NGitLab.GitLabCollectionResponse +NGitLab.Impl.MergeRequestDraftNoteClient +NGitLab.Impl.MergeRequestDraftNoteClient.All.get -> System.Collections.Generic.IEnumerable +NGitLab.Impl.MergeRequestDraftNoteClient.CreateAsync(NGitLab.Models.DraftNoteCreate draftNote, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task +NGitLab.Impl.MergeRequestDraftNoteClient.MergeRequestDraftNoteClient(NGitLab.Impl.API api, string projectPath, long mergeRequestIid) -> void +NGitLab.Impl.MergeRequestDraftNoteClient.PublishAllAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task +NGitLab.Models.DraftNote +NGitLab.Models.DraftNote.AuthorId.get -> long +NGitLab.Models.DraftNote.AuthorId.set -> void +NGitLab.Models.DraftNote.DraftNote() -> void +NGitLab.Models.DraftNote.Id.get -> long +NGitLab.Models.DraftNote.Id.set -> void +NGitLab.Models.DraftNote.MergeRequestId.get -> long +NGitLab.Models.DraftNote.MergeRequestId.set -> void +NGitLab.Models.DraftNote.Note.get -> string +NGitLab.Models.DraftNote.Note.set -> void +NGitLab.Models.DraftNote.Position.get -> NGitLab.Models.Position +NGitLab.Models.DraftNote.Position.set -> void +NGitLab.Models.DraftNoteCreate +NGitLab.Models.DraftNoteCreate.DraftNoteCreate() -> void +NGitLab.Models.DraftNoteCreate.Note.get -> string +NGitLab.Models.DraftNoteCreate.Note.set -> void +NGitLab.Models.DraftNoteCreate.Position.get -> NGitLab.Models.Position +NGitLab.Models.DraftNoteCreate.Position.set -> void +NGitLab.Models.MergeRequestDiffQuery +NGitLab.Models.MergeRequestDiffQuery.MergeRequestDiffQuery() -> void +NGitLab.Models.MergeRequestDiffQuery.Unidiff.get -> bool? +NGitLab.Models.MergeRequestDiffQuery.Unidiff.set -> void diff --git a/NGitLab/PublicAPI/net472/PublicAPI.Unshipped.txt b/NGitLab/PublicAPI/net472/PublicAPI.Unshipped.txt index f9ee7e119..dd7c21c4b 100644 --- a/NGitLab/PublicAPI/net472/PublicAPI.Unshipped.txt +++ b/NGitLab/PublicAPI/net472/PublicAPI.Unshipped.txt @@ -5308,3 +5308,40 @@ NGitLab.Models.ProjectDelete.PermanentlyRemove.get -> bool? NGitLab.Models.ProjectDelete.PermanentlyRemove.set -> void NGitLab.Models.ProjectDelete.ProjectDelete() -> void NGitLab.Impl.ProjectClient.DeleteAsync(NGitLab.Models.ProjectId projectId, NGitLab.Models.ProjectDelete options, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task +NGitLab.IMergeRequestApprovalClient.UnapproveMergeRequest() -> void +NGitLab.IMergeRequestClient.DraftNotes(long mergeRequestIid) -> NGitLab.IMergeRequestDraftNoteClient +NGitLab.IMergeRequestClient.GetDiffsAsync(long mergeRequestIid, NGitLab.Models.MergeRequestDiffQuery query) -> NGitLab.GitLabCollectionResponse +NGitLab.IMergeRequestDraftNoteClient +NGitLab.IMergeRequestDraftNoteClient.All.get -> System.Collections.Generic.IEnumerable +NGitLab.IMergeRequestDraftNoteClient.CreateAsync(NGitLab.Models.DraftNoteCreate draftNote, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task +NGitLab.IMergeRequestDraftNoteClient.PublishAllAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task +NGitLab.Impl.MergeRequestApprovalClient.UnapproveMergeRequest() -> void +NGitLab.Impl.MergeRequestClient.DraftNotes(long mergeRequestIid) -> NGitLab.IMergeRequestDraftNoteClient +NGitLab.Impl.MergeRequestClient.GetDiffsAsync(long mergeRequestIid, NGitLab.Models.MergeRequestDiffQuery query) -> NGitLab.GitLabCollectionResponse +NGitLab.Impl.MergeRequestDraftNoteClient +NGitLab.Impl.MergeRequestDraftNoteClient.All.get -> System.Collections.Generic.IEnumerable +NGitLab.Impl.MergeRequestDraftNoteClient.CreateAsync(NGitLab.Models.DraftNoteCreate draftNote, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task +NGitLab.Impl.MergeRequestDraftNoteClient.MergeRequestDraftNoteClient(NGitLab.Impl.API api, string projectPath, long mergeRequestIid) -> void +NGitLab.Impl.MergeRequestDraftNoteClient.PublishAllAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task +NGitLab.Models.DraftNote +NGitLab.Models.DraftNote.AuthorId.get -> long +NGitLab.Models.DraftNote.AuthorId.set -> void +NGitLab.Models.DraftNote.DraftNote() -> void +NGitLab.Models.DraftNote.Id.get -> long +NGitLab.Models.DraftNote.Id.set -> void +NGitLab.Models.DraftNote.MergeRequestId.get -> long +NGitLab.Models.DraftNote.MergeRequestId.set -> void +NGitLab.Models.DraftNote.Note.get -> string +NGitLab.Models.DraftNote.Note.set -> void +NGitLab.Models.DraftNote.Position.get -> NGitLab.Models.Position +NGitLab.Models.DraftNote.Position.set -> void +NGitLab.Models.DraftNoteCreate +NGitLab.Models.DraftNoteCreate.DraftNoteCreate() -> void +NGitLab.Models.DraftNoteCreate.Note.get -> string +NGitLab.Models.DraftNoteCreate.Note.set -> void +NGitLab.Models.DraftNoteCreate.Position.get -> NGitLab.Models.Position +NGitLab.Models.DraftNoteCreate.Position.set -> void +NGitLab.Models.MergeRequestDiffQuery +NGitLab.Models.MergeRequestDiffQuery.MergeRequestDiffQuery() -> void +NGitLab.Models.MergeRequestDiffQuery.Unidiff.get -> bool? +NGitLab.Models.MergeRequestDiffQuery.Unidiff.set -> void diff --git a/NGitLab/PublicAPI/net8.0/PublicAPI.Unshipped.txt b/NGitLab/PublicAPI/net8.0/PublicAPI.Unshipped.txt index ce3c6c090..ac2a49a4e 100644 --- a/NGitLab/PublicAPI/net8.0/PublicAPI.Unshipped.txt +++ b/NGitLab/PublicAPI/net8.0/PublicAPI.Unshipped.txt @@ -5307,3 +5307,40 @@ NGitLab.Models.ProjectDelete.PermanentlyRemove.get -> bool? NGitLab.Models.ProjectDelete.PermanentlyRemove.set -> void NGitLab.Models.ProjectDelete.ProjectDelete() -> void NGitLab.Impl.ProjectClient.DeleteAsync(NGitLab.Models.ProjectId projectId, NGitLab.Models.ProjectDelete options, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task +NGitLab.IMergeRequestApprovalClient.UnapproveMergeRequest() -> void +NGitLab.IMergeRequestClient.DraftNotes(long mergeRequestIid) -> NGitLab.IMergeRequestDraftNoteClient +NGitLab.IMergeRequestClient.GetDiffsAsync(long mergeRequestIid, NGitLab.Models.MergeRequestDiffQuery query) -> NGitLab.GitLabCollectionResponse +NGitLab.IMergeRequestDraftNoteClient +NGitLab.IMergeRequestDraftNoteClient.All.get -> System.Collections.Generic.IEnumerable +NGitLab.IMergeRequestDraftNoteClient.CreateAsync(NGitLab.Models.DraftNoteCreate draftNote, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task +NGitLab.IMergeRequestDraftNoteClient.PublishAllAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task +NGitLab.Impl.MergeRequestApprovalClient.UnapproveMergeRequest() -> void +NGitLab.Impl.MergeRequestClient.DraftNotes(long mergeRequestIid) -> NGitLab.IMergeRequestDraftNoteClient +NGitLab.Impl.MergeRequestClient.GetDiffsAsync(long mergeRequestIid, NGitLab.Models.MergeRequestDiffQuery query) -> NGitLab.GitLabCollectionResponse +NGitLab.Impl.MergeRequestDraftNoteClient +NGitLab.Impl.MergeRequestDraftNoteClient.All.get -> System.Collections.Generic.IEnumerable +NGitLab.Impl.MergeRequestDraftNoteClient.CreateAsync(NGitLab.Models.DraftNoteCreate draftNote, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task +NGitLab.Impl.MergeRequestDraftNoteClient.MergeRequestDraftNoteClient(NGitLab.Impl.API api, string projectPath, long mergeRequestIid) -> void +NGitLab.Impl.MergeRequestDraftNoteClient.PublishAllAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task +NGitLab.Models.DraftNote +NGitLab.Models.DraftNote.AuthorId.get -> long +NGitLab.Models.DraftNote.AuthorId.set -> void +NGitLab.Models.DraftNote.DraftNote() -> void +NGitLab.Models.DraftNote.Id.get -> long +NGitLab.Models.DraftNote.Id.set -> void +NGitLab.Models.DraftNote.MergeRequestId.get -> long +NGitLab.Models.DraftNote.MergeRequestId.set -> void +NGitLab.Models.DraftNote.Note.get -> string +NGitLab.Models.DraftNote.Note.set -> void +NGitLab.Models.DraftNote.Position.get -> NGitLab.Models.Position +NGitLab.Models.DraftNote.Position.set -> void +NGitLab.Models.DraftNoteCreate +NGitLab.Models.DraftNoteCreate.DraftNoteCreate() -> void +NGitLab.Models.DraftNoteCreate.Note.get -> string +NGitLab.Models.DraftNoteCreate.Note.set -> void +NGitLab.Models.DraftNoteCreate.Position.get -> NGitLab.Models.Position +NGitLab.Models.DraftNoteCreate.Position.set -> void +NGitLab.Models.MergeRequestDiffQuery +NGitLab.Models.MergeRequestDiffQuery.MergeRequestDiffQuery() -> void +NGitLab.Models.MergeRequestDiffQuery.Unidiff.get -> bool? +NGitLab.Models.MergeRequestDiffQuery.Unidiff.set -> void diff --git a/NGitLab/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt b/NGitLab/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt index f9ee7e119..dd7c21c4b 100644 --- a/NGitLab/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt +++ b/NGitLab/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt @@ -5308,3 +5308,40 @@ NGitLab.Models.ProjectDelete.PermanentlyRemove.get -> bool? NGitLab.Models.ProjectDelete.PermanentlyRemove.set -> void NGitLab.Models.ProjectDelete.ProjectDelete() -> void NGitLab.Impl.ProjectClient.DeleteAsync(NGitLab.Models.ProjectId projectId, NGitLab.Models.ProjectDelete options, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task +NGitLab.IMergeRequestApprovalClient.UnapproveMergeRequest() -> void +NGitLab.IMergeRequestClient.DraftNotes(long mergeRequestIid) -> NGitLab.IMergeRequestDraftNoteClient +NGitLab.IMergeRequestClient.GetDiffsAsync(long mergeRequestIid, NGitLab.Models.MergeRequestDiffQuery query) -> NGitLab.GitLabCollectionResponse +NGitLab.IMergeRequestDraftNoteClient +NGitLab.IMergeRequestDraftNoteClient.All.get -> System.Collections.Generic.IEnumerable +NGitLab.IMergeRequestDraftNoteClient.CreateAsync(NGitLab.Models.DraftNoteCreate draftNote, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task +NGitLab.IMergeRequestDraftNoteClient.PublishAllAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task +NGitLab.Impl.MergeRequestApprovalClient.UnapproveMergeRequest() -> void +NGitLab.Impl.MergeRequestClient.DraftNotes(long mergeRequestIid) -> NGitLab.IMergeRequestDraftNoteClient +NGitLab.Impl.MergeRequestClient.GetDiffsAsync(long mergeRequestIid, NGitLab.Models.MergeRequestDiffQuery query) -> NGitLab.GitLabCollectionResponse +NGitLab.Impl.MergeRequestDraftNoteClient +NGitLab.Impl.MergeRequestDraftNoteClient.All.get -> System.Collections.Generic.IEnumerable +NGitLab.Impl.MergeRequestDraftNoteClient.CreateAsync(NGitLab.Models.DraftNoteCreate draftNote, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task +NGitLab.Impl.MergeRequestDraftNoteClient.MergeRequestDraftNoteClient(NGitLab.Impl.API api, string projectPath, long mergeRequestIid) -> void +NGitLab.Impl.MergeRequestDraftNoteClient.PublishAllAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task +NGitLab.Models.DraftNote +NGitLab.Models.DraftNote.AuthorId.get -> long +NGitLab.Models.DraftNote.AuthorId.set -> void +NGitLab.Models.DraftNote.DraftNote() -> void +NGitLab.Models.DraftNote.Id.get -> long +NGitLab.Models.DraftNote.Id.set -> void +NGitLab.Models.DraftNote.MergeRequestId.get -> long +NGitLab.Models.DraftNote.MergeRequestId.set -> void +NGitLab.Models.DraftNote.Note.get -> string +NGitLab.Models.DraftNote.Note.set -> void +NGitLab.Models.DraftNote.Position.get -> NGitLab.Models.Position +NGitLab.Models.DraftNote.Position.set -> void +NGitLab.Models.DraftNoteCreate +NGitLab.Models.DraftNoteCreate.DraftNoteCreate() -> void +NGitLab.Models.DraftNoteCreate.Note.get -> string +NGitLab.Models.DraftNoteCreate.Note.set -> void +NGitLab.Models.DraftNoteCreate.Position.get -> NGitLab.Models.Position +NGitLab.Models.DraftNoteCreate.Position.set -> void +NGitLab.Models.MergeRequestDiffQuery +NGitLab.Models.MergeRequestDiffQuery.MergeRequestDiffQuery() -> void +NGitLab.Models.MergeRequestDiffQuery.Unidiff.get -> bool? +NGitLab.Models.MergeRequestDiffQuery.Unidiff.set -> void From b552103eef02edd34fb33011a102d8809edf60d9 Mon Sep 17 00:00:00 2001 From: Louis Zanella Date: Wed, 29 Jul 2026 14:43:51 -0400 Subject: [PATCH 2/6] test: add integration tests for UnapproveMergeRequest, GetDiffsAsync, and draft notes Covers the three new APIs added in the previous commit: - MergeRequestApprovalClientTests: approve/unapprove roundtrip, and unapprove-when-not-approved is tolerated (GitLab may return a 401; we accept both outcomes) - MergeRequestDiffsClientTests: GetDiffsAsync returns diffs, unidiff=true returns the same file count, and the unified diff content starts with standard markers - MergeRequestDraftNoteClientTests: create appears in All, All is empty on a fresh MR, PublishAllAsync clears drafts and they surface as regular comments All tests use the Docker integration pattern (GitLabTestContext + [NGitLabRetry]). Co-Authored-By: Claude --- .../MergeRequestApprovalClientTests.cs | 51 ++++++++++++++ .../MergeRequestDiffsClientTests.cs | 60 ++++++++++++++++ .../MergeRequestDraftNoteClientTests.cs | 69 +++++++++++++++++++ 3 files changed, 180 insertions(+) create mode 100644 NGitLab.Tests/MergeRequest/MergeRequestApprovalClientTests.cs create mode 100644 NGitLab.Tests/MergeRequest/MergeRequestDiffsClientTests.cs create mode 100644 NGitLab.Tests/MergeRequest/MergeRequestDraftNoteClientTests.cs diff --git a/NGitLab.Tests/MergeRequest/MergeRequestApprovalClientTests.cs b/NGitLab.Tests/MergeRequest/MergeRequestApprovalClientTests.cs new file mode 100644 index 000000000..6083c2dde --- /dev/null +++ b/NGitLab.Tests/MergeRequest/MergeRequestApprovalClientTests.cs @@ -0,0 +1,51 @@ +using System.Threading.Tasks; +using NGitLab.Models; +using NGitLab.Tests.Docker; +using NUnit.Framework; + +namespace NGitLab.Tests; + +public class MergeRequestApprovalClientTests +{ + [Test] + [NGitLabRetry] + public async Task ApproveMergeRequest_and_UnapproveMergeRequest_roundtrip() + { + using var context = await GitLabTestContext.CreateAsync(); + var (project, mergeRequest) = context.CreateMergeRequest(); + var mrClient = context.Client.GetMergeRequest(project.Id); + var approvalClient = mrClient.ApprovalClient(mergeRequest.Iid); + + // Approve + var approvals = approvalClient.ApproveMergeRequest(); + Assert.That(approvals, Is.Not.Null); + Assert.That(approvals.Approved, Is.True, "MR should be marked as approved after ApproveMergeRequest"); + + // Unapprove — should not throw + Assert.DoesNotThrow((TestDelegate)(() => approvalClient.UnapproveMergeRequest())); + + // After unapproval the approval state should show no approved-by entries + var state = approvalClient.Approvals; + Assert.That(state.ApprovedBy, Is.Empty.Or.Null, "No approvers should remain after unapproving"); + } + + [Test] + [NGitLabRetry] + public async Task UnapproveMergeRequest_on_unapproved_mr_does_not_throw() + { + using var context = await GitLabTestContext.CreateAsync(); + var (project, mergeRequest) = context.CreateMergeRequest(); + var approvalClient = context.Client.GetMergeRequest(project.Id).ApprovalClient(mergeRequest.Iid); + + // Calling unapprove on an already-unapproved MR should be idempotent (GitLab returns 401 if already unapproved, + // but some versions are lenient). We accept both a silent success and a GitLabException. + try + { + approvalClient.UnapproveMergeRequest(); + } + catch (GitLabException) + { + // Acceptable: GitLab may return an error when the MR was not approved + } + } +} diff --git a/NGitLab.Tests/MergeRequest/MergeRequestDiffsClientTests.cs b/NGitLab.Tests/MergeRequest/MergeRequestDiffsClientTests.cs new file mode 100644 index 000000000..bfad56bb1 --- /dev/null +++ b/NGitLab.Tests/MergeRequest/MergeRequestDiffsClientTests.cs @@ -0,0 +1,60 @@ +using System.Linq; +using System.Threading.Tasks; +using NGitLab.Models; +using NGitLab.Tests.Docker; +using NUnit.Framework; + +namespace NGitLab.Tests; + +public class MergeRequestDiffsClientTests +{ + [Test] + [NGitLabRetry] + public async Task GetDiffsAsync_returns_changed_files() + { + using var context = await GitLabTestContext.CreateAsync(); + var (project, mergeRequest) = context.CreateMergeRequest(); + var mrClient = context.Client.GetMergeRequest(project.Id); + + var diffs = await mrClient.GetDiffsAsync(mergeRequest.Iid, query: null).ToListAsync(); + + Assert.That(diffs, Has.Count.GreaterThan(0), "At least one diff should be returned"); + Assert.That(diffs[0].OldPath, Is.Not.Null.And.Not.Empty); + Assert.That(diffs[0].NewPath, Is.Not.Null.And.Not.Empty); + } + + [Test] + [NGitLabRetry] + public async Task GetDiffsAsync_with_unidiff_returns_changed_files() + { + using var context = await GitLabTestContext.CreateAsync(); + var (project, mergeRequest) = context.CreateMergeRequest(); + var mrClient = context.Client.GetMergeRequest(project.Id); + + var query = new MergeRequestDiffQuery { Unidiff = true }; + var diffs = await mrClient.GetDiffsAsync(mergeRequest.Iid, query).ToListAsync(); + + Assert.That(diffs, Has.Count.GreaterThan(0), "At least one diff should be returned with unidiff=true"); + Assert.That(diffs[0].OldPath, Is.Not.Null.And.Not.Empty); + Assert.That(diffs[0].NewPath, Is.Not.Null.And.Not.Empty); + } + + [Test] + [NGitLabRetry] + public async Task GetDiffsAsync_unidiff_format_starts_with_unified_diff_header() + { + using var context = await GitLabTestContext.CreateAsync(); + var (project, mergeRequest) = context.CreateMergeRequest(); + var mrClient = context.Client.GetMergeRequest(project.Id); + + var plainDiffs = await mrClient.GetDiffsAsync(mergeRequest.Iid, query: null).ToListAsync(); + var unifiedDiffs = await mrClient.GetDiffsAsync(mergeRequest.Iid, new MergeRequestDiffQuery { Unidiff = true }).ToListAsync(); + + Assert.That(plainDiffs, Has.Count.EqualTo(unifiedDiffs.Count), "Both queries should return the same number of files"); + + // Unified diff format uses "--- a/..." / "+++ b/..." headers; the plain GitLab format does not. + var firstUnified = unifiedDiffs[0].Difference; + Assert.That(firstUnified, Does.StartWith("---").Or.StartWith("diff --git"), + "Unified diff content should start with standard unified-diff markers"); + } +} diff --git a/NGitLab.Tests/MergeRequest/MergeRequestDraftNoteClientTests.cs b/NGitLab.Tests/MergeRequest/MergeRequestDraftNoteClientTests.cs new file mode 100644 index 000000000..f02fb8eb1 --- /dev/null +++ b/NGitLab.Tests/MergeRequest/MergeRequestDraftNoteClientTests.cs @@ -0,0 +1,69 @@ +using System.Linq; +using System.Threading.Tasks; +using NGitLab.Models; +using NGitLab.Tests.Docker; +using NUnit.Framework; + +namespace NGitLab.Tests; + +public class MergeRequestDraftNoteClientTests +{ + [Test] + [NGitLabRetry] + public async Task CreateAsync_adds_draft_note_visible_in_All() + { + using var context = await GitLabTestContext.CreateAsync(); + var (project, mergeRequest) = context.CreateMergeRequest(); + var draftNoteClient = context.Client.GetMergeRequest(project.Id).DraftNotes(mergeRequest.Iid); + + var created = await draftNoteClient.CreateAsync(new DraftNoteCreate { Note = "Draft review comment" }); + + Assert.That(created, Is.Not.Null); + Assert.That(created.Note, Is.EqualTo("Draft review comment")); + Assert.That(created.Id, Is.GreaterThan(0)); + + var all = draftNoteClient.All.ToList(); + Assert.That(all, Has.Count.EqualTo(1), "The created draft note should appear in All"); + Assert.That(all[0].Id, Is.EqualTo(created.Id)); + } + + [Test] + [NGitLabRetry] + public async Task All_returns_empty_when_no_draft_notes_exist() + { + using var context = await GitLabTestContext.CreateAsync(); + var (project, mergeRequest) = context.CreateMergeRequest(); + var draftNoteClient = context.Client.GetMergeRequest(project.Id).DraftNotes(mergeRequest.Iid); + + var all = draftNoteClient.All.ToList(); + + Assert.That(all, Is.Empty, "No draft notes should exist on a fresh merge request"); + } + + [Test] + [NGitLabRetry] + public async Task PublishAllAsync_publishes_all_draft_notes() + { + using var context = await GitLabTestContext.CreateAsync(); + var (project, mergeRequest) = context.CreateMergeRequest(); + var mrClient = context.Client.GetMergeRequest(project.Id); + var draftNoteClient = mrClient.DraftNotes(mergeRequest.Iid); + + await draftNoteClient.CreateAsync(new DraftNoteCreate { Note = "First draft" }); + await draftNoteClient.CreateAsync(new DraftNoteCreate { Note = "Second draft" }); + + Assert.That(draftNoteClient.All.Count(), Is.EqualTo(2), "Two draft notes should exist before publishing"); + + await draftNoteClient.PublishAllAsync(); + + // After publishing, draft notes should be cleared + var remaining = draftNoteClient.All.ToList(); + Assert.That(remaining, Is.Empty, "Draft notes should be gone after PublishAllAsync"); + + // The notes should now appear as regular MR notes/discussions + var notes = mrClient.Comments(mergeRequest.Iid).All.ToList(); + Assert.That(notes.Any(n => string.Equals(n.Body, "First draft", System.StringComparison.Ordinal) + || string.Equals(n.Body, "Second draft", System.StringComparison.Ordinal)), Is.True, + "Published draft notes should appear as regular comments"); + } +} From 3d1d717d8be8396bbc378244c77563a91e37c06e Mon Sep 17 00:00:00 2001 From: Louis Zanella Date: Wed, 29 Jul 2026 15:41:32 -0400 Subject: [PATCH 3/6] review --- .../MergeRequestApprovalClientTests.cs | 20 +++++++------------ .../MergeRequestDraftNoteClientTests.cs | 13 ------------ 2 files changed, 7 insertions(+), 26 deletions(-) diff --git a/NGitLab.Tests/MergeRequest/MergeRequestApprovalClientTests.cs b/NGitLab.Tests/MergeRequest/MergeRequestApprovalClientTests.cs index 6083c2dde..fdb729b75 100644 --- a/NGitLab.Tests/MergeRequest/MergeRequestApprovalClientTests.cs +++ b/NGitLab.Tests/MergeRequest/MergeRequestApprovalClientTests.cs @@ -1,5 +1,5 @@ +using System; using System.Threading.Tasks; -using NGitLab.Models; using NGitLab.Tests.Docker; using NUnit.Framework; @@ -22,7 +22,7 @@ public async Task ApproveMergeRequest_and_UnapproveMergeRequest_roundtrip() Assert.That(approvals.Approved, Is.True, "MR should be marked as approved after ApproveMergeRequest"); // Unapprove — should not throw - Assert.DoesNotThrow((TestDelegate)(() => approvalClient.UnapproveMergeRequest())); + Assert.DoesNotThrow((Action)(() => approvalClient.UnapproveMergeRequest())); // After unapproval the approval state should show no approved-by entries var state = approvalClient.Approvals; @@ -31,21 +31,15 @@ public async Task ApproveMergeRequest_and_UnapproveMergeRequest_roundtrip() [Test] [NGitLabRetry] - public async Task UnapproveMergeRequest_on_unapproved_mr_does_not_throw() + public async Task UnapproveMergeRequest_on_unapproved_mr_throws() { + // Arrange using var context = await GitLabTestContext.CreateAsync(); var (project, mergeRequest) = context.CreateMergeRequest(); var approvalClient = context.Client.GetMergeRequest(project.Id).ApprovalClient(mergeRequest.Iid); - // Calling unapprove on an already-unapproved MR should be idempotent (GitLab returns 401 if already unapproved, - // but some versions are lenient). We accept both a silent success and a GitLabException. - try - { - approvalClient.UnapproveMergeRequest(); - } - catch (GitLabException) - { - // Acceptable: GitLab may return an error when the MR was not approved - } + // Act/Assert + Assert.That((Action)(() => approvalClient.UnapproveMergeRequest()), Throws.TypeOf(), + "Unapproving an unapproved MR should throw a GitLabException"); } } diff --git a/NGitLab.Tests/MergeRequest/MergeRequestDraftNoteClientTests.cs b/NGitLab.Tests/MergeRequest/MergeRequestDraftNoteClientTests.cs index f02fb8eb1..fb03b55db 100644 --- a/NGitLab.Tests/MergeRequest/MergeRequestDraftNoteClientTests.cs +++ b/NGitLab.Tests/MergeRequest/MergeRequestDraftNoteClientTests.cs @@ -27,19 +27,6 @@ public async Task CreateAsync_adds_draft_note_visible_in_All() Assert.That(all[0].Id, Is.EqualTo(created.Id)); } - [Test] - [NGitLabRetry] - public async Task All_returns_empty_when_no_draft_notes_exist() - { - using var context = await GitLabTestContext.CreateAsync(); - var (project, mergeRequest) = context.CreateMergeRequest(); - var draftNoteClient = context.Client.GetMergeRequest(project.Id).DraftNotes(mergeRequest.Iid); - - var all = draftNoteClient.All.ToList(); - - Assert.That(all, Is.Empty, "No draft notes should exist on a fresh merge request"); - } - [Test] [NGitLabRetry] public async Task PublishAllAsync_publishes_all_draft_notes() From 37765eda95fb19403349026f6e8b78c23f69408b Mon Sep 17 00:00:00 2001 From: Louis Zanella Date: Wed, 29 Jul 2026 17:04:44 -0400 Subject: [PATCH 4/6] Fix timing issues --- NGitLab.Tests/Docker/GitLabTestContext.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/NGitLab.Tests/Docker/GitLabTestContext.cs b/NGitLab.Tests/Docker/GitLabTestContext.cs index ab9a573e2..5fc63f1ee 100644 --- a/NGitLab.Tests/Docker/GitLabTestContext.cs +++ b/NGitLab.Tests/Docker/GitLabTestContext.cs @@ -239,6 +239,11 @@ public Group CreateSubgroup(long parentGroupId, string slug, string name = null, }); public (Project Project, MergeRequest MergeRequest) CreateMergeRequest(Action configure = null, Action configureProject = null) + { + return CreateMergeRequestAsync(configure, configureProject).GetAwaiter().GetResult(); + } + + public async Task<(Project Project, MergeRequest MergeRequest)> CreateMergeRequestAsync(Action configure = null, Action configureProject = null) { var client = Client; var project = CreateProject(configureProject, initializeWithCommits: true); @@ -273,6 +278,16 @@ public Group CreateSubgroup(long parentGroupId, string slug, string name = null, configure?.Invoke(mergeRequestCreate); var mr = client.GetMergeRequest(project.Id).Create(mergeRequestCreate); + // GitLab computes diff data and merge status asynchronously after MR creation. + // Wait until the transient states resolve so callers can immediately query diffs or approvals. + var mrClient = client.GetMergeRequest(project.Id); + mr = await RetryUntilAsync( + () => mrClient[mr.Iid], + result => result.DetailedMergeStatus != DetailedMergeStatus.Checking && + result.DetailedMergeStatus != DetailedMergeStatus.Unchecked && + result.DetailedMergeStatus != DetailedMergeStatus.Preparing, + TimeSpan.FromSeconds(60)).ConfigureAwait(false); + return (project, mr); } From 5cc8a0c64622e654c4eb0435d324d9b97326af5f Mon Sep 17 00:00:00 2001 From: Louis Zanella Date: Thu, 30 Jul 2026 13:28:07 -0400 Subject: [PATCH 5/6] Fix other issues --- .../MergeRequest/MergeRequestCommentsClientTests.cs | 7 ++++--- NGitLab/Models/Position.cs | 4 ++-- NGitLab/PublicAPI/net10.0/PublicAPI.Unshipped.txt | 5 ++--- NGitLab/PublicAPI/net472/PublicAPI.Unshipped.txt | 5 ++--- NGitLab/PublicAPI/net8.0/PublicAPI.Unshipped.txt | 5 ++--- NGitLab/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt | 5 ++--- 6 files changed, 14 insertions(+), 17 deletions(-) diff --git a/NGitLab.Tests/MergeRequest/MergeRequestCommentsClientTests.cs b/NGitLab.Tests/MergeRequest/MergeRequestCommentsClientTests.cs index 328949802..3013bc4cf 100644 --- a/NGitLab.Tests/MergeRequest/MergeRequestCommentsClientTests.cs +++ b/NGitLab.Tests/MergeRequest/MergeRequestCommentsClientTests.cs @@ -56,13 +56,14 @@ public async Task AddEditCommentToMergeRequest() Assert.That(editedComment.Body, Is.EqualTo(commentMessageEdit)); Assert.That(editedComment.CreatedAt, Is.EqualTo(createdAt)); - // Get all - var comments = mergeRequestComments.All.ToArray(); + // 'All' returns all notes, including system notes that GitLab auto-generates (e.g. "changed the merge status to can be merged" or similar state-change events). + // Get all non-system notes + var comments = mergeRequestComments.All.Where(c => !c.System).ToArray(); Assert.That(comments, Is.Not.Empty); // Delete mergeRequestComments.Delete(comment.Id); - comments = mergeRequestComments.All.ToArray(); + comments = mergeRequestComments.All.Where(c => !c.System).ToArray(); Assert.That(comments, Is.Empty); } diff --git a/NGitLab/Models/Position.cs b/NGitLab/Models/Position.cs index 23bb04cb3..7a9461ffe 100644 --- a/NGitLab/Models/Position.cs +++ b/NGitLab/Models/Position.cs @@ -26,8 +26,8 @@ public class Position public Sha1? BaseSha { get; set; } [JsonPropertyName("head_sha")] - public Sha1 HeadSha { get; set; } + public Sha1? HeadSha { get; set; } [JsonPropertyName("start_sha")] - public Sha1 StartSha { get; set; } + public Sha1? StartSha { get; set; } } diff --git a/NGitLab/PublicAPI/net10.0/PublicAPI.Unshipped.txt b/NGitLab/PublicAPI/net10.0/PublicAPI.Unshipped.txt index ac2a49a4e..9a5cb8451 100644 --- a/NGitLab/PublicAPI/net10.0/PublicAPI.Unshipped.txt +++ b/NGitLab/PublicAPI/net10.0/PublicAPI.Unshipped.txt @@ -3580,7 +3580,7 @@ NGitLab.Models.PipelineVariable.VariableType.set -> void NGitLab.Models.Position NGitLab.Models.Position.BaseSha.get -> NGitLab.Sha1? NGitLab.Models.Position.BaseSha.set -> void -NGitLab.Models.Position.HeadSha.get -> NGitLab.Sha1 +NGitLab.Models.Position.HeadSha.get -> NGitLab.Sha1? NGitLab.Models.Position.HeadSha.set -> void NGitLab.Models.Position.LineRange.get -> NGitLab.Models.LineRange NGitLab.Models.Position.LineRange.set -> void @@ -3595,7 +3595,7 @@ NGitLab.Models.Position.OldPath.set -> void NGitLab.Models.Position.Position() -> void NGitLab.Models.Position.PositionType.get -> NGitLab.DynamicEnum NGitLab.Models.Position.PositionType.set -> void -NGitLab.Models.Position.StartSha.get -> NGitLab.Sha1 +NGitLab.Models.Position.StartSha.get -> NGitLab.Sha1? NGitLab.Models.Position.StartSha.set -> void NGitLab.Models.PositionType NGitLab.Models.PositionType.Image = 1 -> NGitLab.Models.PositionType @@ -5249,7 +5249,6 @@ virtual NGitLab.Impl.HttpRequestor.ToAsync(string tailAPIUrl, System.Threadin virtual NGitLab.RequestOptions.GetResponse(System.Net.HttpWebRequest request) -> System.Net.WebResponse virtual NGitLab.RequestOptions.GetResponseAsync(System.Net.HttpWebRequest request, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task virtual NGitLab.RequestOptions.ShouldRetry(System.Exception ex, int retryNumber) -> bool - NGitLab.GitLabClient.GetContainerRegistry(NGitLab.Models.ProjectId projectId) -> NGitLab.IContainerRegistryClient NGitLab.IContainerRegistryClient NGitLab.IContainerRegistryClient.DeleteRepositoryAsync(long repositoryId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task diff --git a/NGitLab/PublicAPI/net472/PublicAPI.Unshipped.txt b/NGitLab/PublicAPI/net472/PublicAPI.Unshipped.txt index dd7c21c4b..476ed4c30 100644 --- a/NGitLab/PublicAPI/net472/PublicAPI.Unshipped.txt +++ b/NGitLab/PublicAPI/net472/PublicAPI.Unshipped.txt @@ -3581,7 +3581,7 @@ NGitLab.Models.PipelineVariable.VariableType.set -> void NGitLab.Models.Position NGitLab.Models.Position.BaseSha.get -> NGitLab.Sha1? NGitLab.Models.Position.BaseSha.set -> void -NGitLab.Models.Position.HeadSha.get -> NGitLab.Sha1 +NGitLab.Models.Position.HeadSha.get -> NGitLab.Sha1? NGitLab.Models.Position.HeadSha.set -> void NGitLab.Models.Position.LineRange.get -> NGitLab.Models.LineRange NGitLab.Models.Position.LineRange.set -> void @@ -3596,7 +3596,7 @@ NGitLab.Models.Position.OldPath.set -> void NGitLab.Models.Position.Position() -> void NGitLab.Models.Position.PositionType.get -> NGitLab.DynamicEnum NGitLab.Models.Position.PositionType.set -> void -NGitLab.Models.Position.StartSha.get -> NGitLab.Sha1 +NGitLab.Models.Position.StartSha.get -> NGitLab.Sha1? NGitLab.Models.Position.StartSha.set -> void NGitLab.Models.PositionType NGitLab.Models.PositionType.Image = 1 -> NGitLab.Models.PositionType @@ -5250,7 +5250,6 @@ virtual NGitLab.Impl.HttpRequestor.ToAsync(string tailAPIUrl, System.Threadin virtual NGitLab.RequestOptions.GetResponse(System.Net.HttpWebRequest request) -> System.Net.WebResponse virtual NGitLab.RequestOptions.GetResponseAsync(System.Net.HttpWebRequest request, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task virtual NGitLab.RequestOptions.ShouldRetry(System.Exception ex, int retryNumber) -> bool - NGitLab.GitLabClient.GetContainerRegistry(NGitLab.Models.ProjectId projectId) -> NGitLab.IContainerRegistryClient NGitLab.IContainerRegistryClient NGitLab.IContainerRegistryClient.DeleteRepositoryAsync(long repositoryId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task diff --git a/NGitLab/PublicAPI/net8.0/PublicAPI.Unshipped.txt b/NGitLab/PublicAPI/net8.0/PublicAPI.Unshipped.txt index ac2a49a4e..9a5cb8451 100644 --- a/NGitLab/PublicAPI/net8.0/PublicAPI.Unshipped.txt +++ b/NGitLab/PublicAPI/net8.0/PublicAPI.Unshipped.txt @@ -3580,7 +3580,7 @@ NGitLab.Models.PipelineVariable.VariableType.set -> void NGitLab.Models.Position NGitLab.Models.Position.BaseSha.get -> NGitLab.Sha1? NGitLab.Models.Position.BaseSha.set -> void -NGitLab.Models.Position.HeadSha.get -> NGitLab.Sha1 +NGitLab.Models.Position.HeadSha.get -> NGitLab.Sha1? NGitLab.Models.Position.HeadSha.set -> void NGitLab.Models.Position.LineRange.get -> NGitLab.Models.LineRange NGitLab.Models.Position.LineRange.set -> void @@ -3595,7 +3595,7 @@ NGitLab.Models.Position.OldPath.set -> void NGitLab.Models.Position.Position() -> void NGitLab.Models.Position.PositionType.get -> NGitLab.DynamicEnum NGitLab.Models.Position.PositionType.set -> void -NGitLab.Models.Position.StartSha.get -> NGitLab.Sha1 +NGitLab.Models.Position.StartSha.get -> NGitLab.Sha1? NGitLab.Models.Position.StartSha.set -> void NGitLab.Models.PositionType NGitLab.Models.PositionType.Image = 1 -> NGitLab.Models.PositionType @@ -5249,7 +5249,6 @@ virtual NGitLab.Impl.HttpRequestor.ToAsync(string tailAPIUrl, System.Threadin virtual NGitLab.RequestOptions.GetResponse(System.Net.HttpWebRequest request) -> System.Net.WebResponse virtual NGitLab.RequestOptions.GetResponseAsync(System.Net.HttpWebRequest request, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task virtual NGitLab.RequestOptions.ShouldRetry(System.Exception ex, int retryNumber) -> bool - NGitLab.GitLabClient.GetContainerRegistry(NGitLab.Models.ProjectId projectId) -> NGitLab.IContainerRegistryClient NGitLab.IContainerRegistryClient NGitLab.IContainerRegistryClient.DeleteRepositoryAsync(long repositoryId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task diff --git a/NGitLab/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt b/NGitLab/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt index dd7c21c4b..476ed4c30 100644 --- a/NGitLab/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt +++ b/NGitLab/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt @@ -3581,7 +3581,7 @@ NGitLab.Models.PipelineVariable.VariableType.set -> void NGitLab.Models.Position NGitLab.Models.Position.BaseSha.get -> NGitLab.Sha1? NGitLab.Models.Position.BaseSha.set -> void -NGitLab.Models.Position.HeadSha.get -> NGitLab.Sha1 +NGitLab.Models.Position.HeadSha.get -> NGitLab.Sha1? NGitLab.Models.Position.HeadSha.set -> void NGitLab.Models.Position.LineRange.get -> NGitLab.Models.LineRange NGitLab.Models.Position.LineRange.set -> void @@ -3596,7 +3596,7 @@ NGitLab.Models.Position.OldPath.set -> void NGitLab.Models.Position.Position() -> void NGitLab.Models.Position.PositionType.get -> NGitLab.DynamicEnum NGitLab.Models.Position.PositionType.set -> void -NGitLab.Models.Position.StartSha.get -> NGitLab.Sha1 +NGitLab.Models.Position.StartSha.get -> NGitLab.Sha1? NGitLab.Models.Position.StartSha.set -> void NGitLab.Models.PositionType NGitLab.Models.PositionType.Image = 1 -> NGitLab.Models.PositionType @@ -5250,7 +5250,6 @@ virtual NGitLab.Impl.HttpRequestor.ToAsync(string tailAPIUrl, System.Threadin virtual NGitLab.RequestOptions.GetResponse(System.Net.HttpWebRequest request) -> System.Net.WebResponse virtual NGitLab.RequestOptions.GetResponseAsync(System.Net.HttpWebRequest request, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task virtual NGitLab.RequestOptions.ShouldRetry(System.Exception ex, int retryNumber) -> bool - NGitLab.GitLabClient.GetContainerRegistry(NGitLab.Models.ProjectId projectId) -> NGitLab.IContainerRegistryClient NGitLab.IContainerRegistryClient NGitLab.IContainerRegistryClient.DeleteRepositoryAsync(long repositoryId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task From f5db31d0e49bb91142563546c6aa1823d82b3752 Mon Sep 17 00:00:00 2001 From: Louis Zanella Date: Fri, 31 Jul 2026 07:37:38 -0400 Subject: [PATCH 6/6] Get rid of CreateMergeRequest() --- NGitLab.Tests/Docker/GitLabTestContext.cs | 5 ---- .../MergeRequestApprovalClientTests.cs | 4 +-- .../MergeRequestChangesClientTests.cs | 2 +- .../MergeRequest/MergeRequestClientTests.cs | 26 +++++++++---------- .../MergeRequestCommentsClientTests.cs | 6 ++--- .../MergeRequestDiffsClientTests.cs | 6 ++--- .../MergeRequestDiscussionsClientTests.cs | 12 ++++----- .../MergeRequestDraftNoteClientTests.cs | 4 +-- .../Milestone/MilestoneClientTests.cs | 4 +-- 9 files changed, 32 insertions(+), 37 deletions(-) diff --git a/NGitLab.Tests/Docker/GitLabTestContext.cs b/NGitLab.Tests/Docker/GitLabTestContext.cs index 5fc63f1ee..cc030b4ed 100644 --- a/NGitLab.Tests/Docker/GitLabTestContext.cs +++ b/NGitLab.Tests/Docker/GitLabTestContext.cs @@ -238,11 +238,6 @@ public Group CreateSubgroup(long parentGroupId, string slug, string name = null, configure?.Invoke(g); }); - public (Project Project, MergeRequest MergeRequest) CreateMergeRequest(Action configure = null, Action configureProject = null) - { - return CreateMergeRequestAsync(configure, configureProject).GetAwaiter().GetResult(); - } - public async Task<(Project Project, MergeRequest MergeRequest)> CreateMergeRequestAsync(Action configure = null, Action configureProject = null) { var client = Client; diff --git a/NGitLab.Tests/MergeRequest/MergeRequestApprovalClientTests.cs b/NGitLab.Tests/MergeRequest/MergeRequestApprovalClientTests.cs index fdb729b75..d3f69a84f 100644 --- a/NGitLab.Tests/MergeRequest/MergeRequestApprovalClientTests.cs +++ b/NGitLab.Tests/MergeRequest/MergeRequestApprovalClientTests.cs @@ -12,7 +12,7 @@ public class MergeRequestApprovalClientTests public async Task ApproveMergeRequest_and_UnapproveMergeRequest_roundtrip() { using var context = await GitLabTestContext.CreateAsync(); - var (project, mergeRequest) = context.CreateMergeRequest(); + var (project, mergeRequest) = await context.CreateMergeRequestAsync(); var mrClient = context.Client.GetMergeRequest(project.Id); var approvalClient = mrClient.ApprovalClient(mergeRequest.Iid); @@ -35,7 +35,7 @@ public async Task UnapproveMergeRequest_on_unapproved_mr_throws() { // Arrange using var context = await GitLabTestContext.CreateAsync(); - var (project, mergeRequest) = context.CreateMergeRequest(); + var (project, mergeRequest) = await context.CreateMergeRequestAsync(); var approvalClient = context.Client.GetMergeRequest(project.Id).ApprovalClient(mergeRequest.Iid); // Act/Assert diff --git a/NGitLab.Tests/MergeRequest/MergeRequestChangesClientTests.cs b/NGitLab.Tests/MergeRequest/MergeRequestChangesClientTests.cs index a29c261c9..484ae1161 100644 --- a/NGitLab.Tests/MergeRequest/MergeRequestChangesClientTests.cs +++ b/NGitLab.Tests/MergeRequest/MergeRequestChangesClientTests.cs @@ -12,7 +12,7 @@ public class MergeRequestChangesClientTests public async Task GetChangesOnMergeRequest() { using var context = await GitLabTestContext.CreateAsync(); - var (project, mergeRequest) = context.CreateMergeRequest(); + var (project, mergeRequest) = await context.CreateMergeRequestAsync(); var mergeRequestClient = context.Client.GetMergeRequest(project.Id); var mergeRequestChanges = mergeRequestClient.Changes(mergeRequest.Iid); diff --git a/NGitLab.Tests/MergeRequest/MergeRequestClientTests.cs b/NGitLab.Tests/MergeRequest/MergeRequestClientTests.cs index 87341b4fa..5ca19c316 100644 --- a/NGitLab.Tests/MergeRequest/MergeRequestClientTests.cs +++ b/NGitLab.Tests/MergeRequest/MergeRequestClientTests.cs @@ -17,7 +17,7 @@ public class MergeRequestClientTests public async Task Test_merge_request_api() { using var context = await GitLabTestContext.CreateAsync(); - var (project, mergeRequest) = context.CreateMergeRequest(); + var (project, mergeRequest) = await context.CreateMergeRequestAsync(); var mergeRequestClient = context.Client.GetMergeRequest(project.Id); Assert.That(mergeRequestClient[mergeRequest.Iid].Id, Is.EqualTo(mergeRequest.Id), "Test we can get a merge request by IId"); @@ -61,7 +61,7 @@ await GitLabTestContext.RetryUntilAsync( public async Task Test_merge_request_rebase() { using var context = await GitLabTestContext.CreateAsync(); - var (project, mergeRequest) = context.CreateMergeRequest(); + var (project, mergeRequest) = await context.CreateMergeRequestAsync(); var mergeRequestClient = context.Client.GetMergeRequest(project.Id); // Additional commit in default branch, to create divergence @@ -102,7 +102,7 @@ public async Task Test_merge_request_rebase() public async Task Test_merge_request_rebaseasync_skip_ci() { using var context = await GitLabTestContext.CreateAsync(); - var (project, mergeRequest) = context.CreateMergeRequest(); + var (project, mergeRequest) = await context.CreateMergeRequestAsync(); var mergeRequestClient = context.Client.GetMergeRequest(project.Id); // Additional commit in default branch, to create divergence @@ -144,7 +144,7 @@ public async Task Test_merge_request_rebaseasync_skip_ci() public async Task Test_merge_request_id_is_not_equal_to_iid() { using var context = await GitLabTestContext.CreateAsync(); - var (_, mergeRequest) = context.CreateMergeRequest(); + var (_, mergeRequest) = await context.CreateMergeRequestAsync(); Assert.That(mergeRequest.Iid, Is.Not.EqualTo(mergeRequest.Id)); } @@ -174,7 +174,7 @@ public async Task Test_gitlab_returns_an_error_when_trying_to_create_a_request_w public async Task Test_merge_request_delete() { using var context = await GitLabTestContext.CreateAsync(); - var (project, mergeRequest) = context.CreateMergeRequest(); + var (project, mergeRequest) = await context.CreateMergeRequestAsync(); var mergeRequestClient = context.Client.GetMergeRequest(project.Id); mergeRequestClient.Delete(mergeRequest.Iid); @@ -194,7 +194,7 @@ public async Task Test_merge_request_approvers() // https://about.gitlab.com/releases/2021/04/22/gitlab-13-11-released/#removal-of-merge-request-approvers-endpoint-in-favor-of-approval-rules-api context.IgnoreTestIfGitLabVersionOutOfRange(VersionRange.Parse("[,13.11)")); - var (project, mergeRequest) = context.CreateMergeRequest(); + var (project, mergeRequest) = await context.CreateMergeRequestAsync(); var mergeRequestClient = context.Client.GetMergeRequest(project.Id); var approvalClient = mergeRequestClient.ApprovalClient(mergeRequest.Iid); @@ -223,7 +223,7 @@ public async Task Test_merge_request_approvers() public async Task Test_get_unassigned_merge_requests() { using var context = await GitLabTestContext.CreateAsync(); - var (project, mergeRequest) = context.CreateMergeRequest(); + var (project, mergeRequest) = await context.CreateMergeRequestAsync(); var mergeRequestClient = context.Client.GetMergeRequest(project.Id); var mergeRequests = mergeRequestClient.Get(new MergeRequestQuery { AssigneeId = QueryAssigneeId.None }).ToList(); @@ -238,7 +238,7 @@ public async Task Test_get_unassigned_merge_requests() public async Task Test_get_assigned_merge_requests() { using var context = await GitLabTestContext.CreateAsync(); - var (project, mergeRequest) = context.CreateMergeRequest(); + var (project, mergeRequest) = await context.CreateMergeRequestAsync(); var mergeRequestClient = context.Client.GetMergeRequest(project.Id); var userId = context.Client.Users.Current.Id; mergeRequestClient.Update(mergeRequest.Iid, new MergeRequestUpdate { AssigneeId = userId }); @@ -255,8 +255,8 @@ public async Task Test_get_assigned_merge_requests() public async Task Test_set_reviewers_merge_requests() { using var context = await GitLabTestContext.CreateAsync(); - var (project, mergeRequest) = context.CreateMergeRequest(); - context.CreateMergeRequest(); // Second MR to verify filter returns only one + var (project, mergeRequest) = await context.CreateMergeRequestAsync(); + await context.CreateMergeRequestAsync(); // Second MR to verify filter returns only one var mergeRequestClient = context.Client.GetMergeRequest(project.Id); var userId = context.Client.Users.Current.Id; mergeRequestClient.Update(mergeRequest.Iid, new MergeRequestUpdate { ReviewerIds = new[] { userId } }); @@ -274,7 +274,7 @@ public async Task Test_set_reviewers_merge_requests() public async Task Test_cancel_merge_when_pipeline_succeeds() { using var context = await GitLabTestContext.CreateAsync(); - var (project, mergeRequest) = context.CreateMergeRequest(); + var (project, mergeRequest) = await context.CreateMergeRequestAsync(); var mergeRequestClient = context.Client.GetMergeRequest(project.Id); mergeRequest.MergeWhenPipelineSucceeds = true; @@ -287,7 +287,7 @@ public async Task Test_cancel_merge_when_pipeline_succeeds() public async Task Test_merge_request_versions() { using var context = await GitLabTestContext.CreateAsync(); - var (project, mergeRequest) = context.CreateMergeRequest(); + var (project, mergeRequest) = await context.CreateMergeRequestAsync(); var mergeRequestClient = context.Client.GetMergeRequest(project.Id); var versions = await GitLabTestContext.RetryUntilAsync( @@ -305,7 +305,7 @@ public async Task Test_merge_request_versions() public async Task Test_merge_request_head_pipeline() { using var context = await GitLabTestContext.CreateAsync(); - var (project, mergeRequest) = context.CreateMergeRequest(); + var (project, mergeRequest) = await context.CreateMergeRequestAsync(); var sourceProjectId = await context.Client.Projects.GetByIdAsync(mergeRequest.SourceProjectId, new SingleProjectQuery()); JobTests.AddGitLabCiFile(context.Client, sourceProjectId, branch: mergeRequest.SourceBranch); var mergeRequestClient = context.Client.GetMergeRequest(project.Id); diff --git a/NGitLab.Tests/MergeRequest/MergeRequestCommentsClientTests.cs b/NGitLab.Tests/MergeRequest/MergeRequestCommentsClientTests.cs index 3013bc4cf..bc7f0de6d 100644 --- a/NGitLab.Tests/MergeRequest/MergeRequestCommentsClientTests.cs +++ b/NGitLab.Tests/MergeRequest/MergeRequestCommentsClientTests.cs @@ -15,7 +15,7 @@ public class MergeRequestCommentsClientTests public async Task AddCommentToMergeRequest_DeprecatedApi() { using var context = await GitLabTestContext.CreateAsync(); - var (project, mergeRequest) = context.CreateMergeRequest(); + var (project, mergeRequest) = await context.CreateMergeRequestAsync(); var mergeRequestClient = context.Client.GetMergeRequest(project.Id); var mergeRequestComments = mergeRequestClient.Comments(mergeRequest.Iid); @@ -33,7 +33,7 @@ public async Task AddCommentToMergeRequest_DeprecatedApi() public async Task AddEditCommentToMergeRequest() { using var context = await GitLabTestContext.CreateAsync(); - var (project, mergeRequest) = context.CreateMergeRequest(); + var (project, mergeRequest) = await context.CreateMergeRequestAsync(); var mergeRequestClient = context.Client.GetMergeRequest(project.Id); var mergeRequestComments = mergeRequestClient.Comments(mergeRequest.Iid); @@ -72,7 +72,7 @@ public async Task AddEditCommentToMergeRequest() public async Task AddCommentToMergeRequestOnArchivedProject() { using var context = await GitLabTestContext.CreateAsync(); - var (project, mergeRequest) = context.CreateMergeRequest(); + var (project, mergeRequest) = await context.CreateMergeRequestAsync(); var mergeRequestClient = context.Client.GetMergeRequest(project.Id); var mergeRequestComments = mergeRequestClient.Comments(mergeRequest.Iid); diff --git a/NGitLab.Tests/MergeRequest/MergeRequestDiffsClientTests.cs b/NGitLab.Tests/MergeRequest/MergeRequestDiffsClientTests.cs index bfad56bb1..16eeade89 100644 --- a/NGitLab.Tests/MergeRequest/MergeRequestDiffsClientTests.cs +++ b/NGitLab.Tests/MergeRequest/MergeRequestDiffsClientTests.cs @@ -13,7 +13,7 @@ public class MergeRequestDiffsClientTests public async Task GetDiffsAsync_returns_changed_files() { using var context = await GitLabTestContext.CreateAsync(); - var (project, mergeRequest) = context.CreateMergeRequest(); + var (project, mergeRequest) = await context.CreateMergeRequestAsync(); var mrClient = context.Client.GetMergeRequest(project.Id); var diffs = await mrClient.GetDiffsAsync(mergeRequest.Iid, query: null).ToListAsync(); @@ -28,7 +28,7 @@ public async Task GetDiffsAsync_returns_changed_files() public async Task GetDiffsAsync_with_unidiff_returns_changed_files() { using var context = await GitLabTestContext.CreateAsync(); - var (project, mergeRequest) = context.CreateMergeRequest(); + var (project, mergeRequest) = await context.CreateMergeRequestAsync(); var mrClient = context.Client.GetMergeRequest(project.Id); var query = new MergeRequestDiffQuery { Unidiff = true }; @@ -44,7 +44,7 @@ public async Task GetDiffsAsync_with_unidiff_returns_changed_files() public async Task GetDiffsAsync_unidiff_format_starts_with_unified_diff_header() { using var context = await GitLabTestContext.CreateAsync(); - var (project, mergeRequest) = context.CreateMergeRequest(); + var (project, mergeRequest) = await context.CreateMergeRequestAsync(); var mrClient = context.Client.GetMergeRequest(project.Id); var plainDiffs = await mrClient.GetDiffsAsync(mergeRequest.Iid, query: null).ToListAsync(); diff --git a/NGitLab.Tests/MergeRequest/MergeRequestDiscussionsClientTests.cs b/NGitLab.Tests/MergeRequest/MergeRequestDiscussionsClientTests.cs index 6e16b27f3..ef15bbb88 100644 --- a/NGitLab.Tests/MergeRequest/MergeRequestDiscussionsClientTests.cs +++ b/NGitLab.Tests/MergeRequest/MergeRequestDiscussionsClientTests.cs @@ -15,7 +15,7 @@ public class MergeRequestDiscussionsClientTests public async Task AddDiscussionToMergeRequest_DiscussionCreated() { using var context = await GitLabTestContext.CreateAsync(); - var (project, mergeRequest) = context.CreateMergeRequest(); + var (project, mergeRequest) = await context.CreateMergeRequestAsync(); var mergeRequestClient = context.Client.GetMergeRequest(project.Id); var mergeRequestDiscussions = mergeRequestClient.Discussions(mergeRequest.Iid); @@ -39,7 +39,7 @@ public async Task AddDiscussionToMergeRequest_DiscussionCreated() public async Task GetDiscussion_DiscussionFound() { using var context = await GitLabTestContext.CreateAsync(); - var (project, mergeRequest) = context.CreateMergeRequest(); + var (project, mergeRequest) = await context.CreateMergeRequestAsync(); var mergeRequestClient = context.Client.GetMergeRequest(project.Id); var mergeRequestDiscussions = mergeRequestClient.Discussions(mergeRequest.Iid); @@ -59,7 +59,7 @@ public async Task GetDiscussion_DiscussionFound() public async Task EditCommentFromDiscussion_CommentEdited() { using var context = await GitLabTestContext.CreateAsync(); - var (project, mergeRequest) = context.CreateMergeRequest(); + var (project, mergeRequest) = await context.CreateMergeRequestAsync(); var mergeRequestClient = context.Client.GetMergeRequest(project.Id); var mergeRequestDiscussions = mergeRequestClient.Discussions(mergeRequest.Iid); @@ -91,7 +91,7 @@ public async Task EditCommentFromDiscussion_CommentEdited() public async Task AddDiscussionToMergeRequestOnArchivedProject() { using var context = await GitLabTestContext.CreateAsync(); - var (project, mergeRequest) = context.CreateMergeRequest(); + var (project, mergeRequest) = await context.CreateMergeRequestAsync(); var mergeRequestClient = context.Client.GetMergeRequest(project.Id); var mergeRequestDiscussions = mergeRequestClient.Discussions(mergeRequest.Iid); @@ -112,7 +112,7 @@ public async Task AddDiscussionToMergeRequestOnArchivedProject() public async Task ResolveDiscussion_AllNotesResolved() { using var context = await GitLabTestContext.CreateAsync(); - var (project, mergeRequest) = context.CreateMergeRequest(); + var (project, mergeRequest) = await context.CreateMergeRequestAsync(); var mergeRequestClient = context.Client.GetMergeRequest(project.Id); var mergeRequestDiscussions = mergeRequestClient.Discussions(mergeRequest.Iid); @@ -138,7 +138,7 @@ public async Task ResolveDiscussion_AllNotesResolved() public async Task DeleteOneNoteFromDiscussion_DiscussionAndNoteDeleted() { using var context = await GitLabTestContext.CreateAsync(); - var (project, mergeRequest) = context.CreateMergeRequest(); + var (project, mergeRequest) = await context.CreateMergeRequestAsync(); var mergeRequestClient = context.Client.GetMergeRequest(project.Id); var mergeRequestDiscussions = mergeRequestClient.Discussions(mergeRequest.Iid); diff --git a/NGitLab.Tests/MergeRequest/MergeRequestDraftNoteClientTests.cs b/NGitLab.Tests/MergeRequest/MergeRequestDraftNoteClientTests.cs index fb03b55db..d179f2f2d 100644 --- a/NGitLab.Tests/MergeRequest/MergeRequestDraftNoteClientTests.cs +++ b/NGitLab.Tests/MergeRequest/MergeRequestDraftNoteClientTests.cs @@ -13,7 +13,7 @@ public class MergeRequestDraftNoteClientTests public async Task CreateAsync_adds_draft_note_visible_in_All() { using var context = await GitLabTestContext.CreateAsync(); - var (project, mergeRequest) = context.CreateMergeRequest(); + var (project, mergeRequest) = await context.CreateMergeRequestAsync(); var draftNoteClient = context.Client.GetMergeRequest(project.Id).DraftNotes(mergeRequest.Iid); var created = await draftNoteClient.CreateAsync(new DraftNoteCreate { Note = "Draft review comment" }); @@ -32,7 +32,7 @@ public async Task CreateAsync_adds_draft_note_visible_in_All() public async Task PublishAllAsync_publishes_all_draft_notes() { using var context = await GitLabTestContext.CreateAsync(); - var (project, mergeRequest) = context.CreateMergeRequest(); + var (project, mergeRequest) = await context.CreateMergeRequestAsync(); var mrClient = context.Client.GetMergeRequest(project.Id); var draftNoteClient = mrClient.DraftNotes(mergeRequest.Iid); diff --git a/NGitLab.Tests/Milestone/MilestoneClientTests.cs b/NGitLab.Tests/Milestone/MilestoneClientTests.cs index 50ca45753..4b29af165 100644 --- a/NGitLab.Tests/Milestone/MilestoneClientTests.cs +++ b/NGitLab.Tests/Milestone/MilestoneClientTests.cs @@ -69,7 +69,7 @@ public async Task Test_group_milestone_api() public async Task Test_project_milestone_merge_requests() { using var context = await GitLabTestContext.CreateAsync(); - var (project, mergeRequest) = context.CreateMergeRequest(); + var (project, mergeRequest) = await context.CreateMergeRequestAsync(); var milestoneClient = context.Client.GetMilestone(project.Id); var milestone = CreateMilestone(context, MilestoneScope.Projects, project.Id, "my-super-milestone"); @@ -87,7 +87,7 @@ public async Task Test_group_milestone_merge_requests() { using var context = await GitLabTestContext.CreateAsync(); var group = context.CreateGroup(); - var (project, mergeRequest) = context.CreateMergeRequest(configureProject: project => project.NamespaceId = group.Id); + var (project, mergeRequest) = await context.CreateMergeRequestAsync(configureProject: project => project.NamespaceId = group.Id); var milestoneClient = context.Client.GetGroupMilestone(group.Id); var milestone = CreateMilestone(context, MilestoneScope.Groups, group.Id, "my-super-milestone");