Skip to content

Commit c0d9180

Browse files
authored
Add support for querying pipeline commit statuses (#852)
1 parent 3ef67c3 commit c0d9180

11 files changed

+313
-137
lines changed

.editorconfig

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ dotnet_style_collection_initializer = true : suggestion
5757
dotnet_style_explicit_tuple_names = true : warning
5858
dotnet_style_null_propagation = true : suggestion
5959
dotnet_style_object_initializer = true : suggestion
60-
dotnet_style_require_accessibility_modifiers = always : warning
60+
dotnet_style_require_accessibility_modifiers = for_non_interface_members : warning
6161

6262
dotnet_style_prefer_is_null_check_over_reference_equality_method = true : warning
6363
dotnet_style_readonly_field = true : warning

NGitLab.Mock/Clients/CommitStatusClient.cs

+8-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public CommitStatusClient(ClientContext context, ProjectId projectId)
1515
_projectId = Server.AllProjects.FindProject(projectId.ValueAsString()).Id;
1616
}
1717

18-
public CommitStatusCreate AddOrUpdate(CommitStatusCreate status)
18+
CommitStatusCreate ICommitStatusClient.AddOrUpdate(CommitStatusCreate status)
1919
{
2020
using (Context.BeginOperationScope())
2121
{
@@ -34,6 +34,7 @@ public CommitStatusCreate AddOrUpdate(CommitStatusCreate status)
3434
commitStatus.Sha = status.CommitSha;
3535
commitStatus.Status = status.Status;
3636
commitStatus.TargetUrl = status.TargetUrl;
37+
3738
return commitStatus.ToClientCommitStatusCreate();
3839
}
3940

@@ -46,7 +47,7 @@ static bool Equals(CommitStatus a, CommitStatusCreate b)
4647
}
4748
}
4849

49-
public IEnumerable<Models.CommitStatus> AllBySha(string commitSha)
50+
IEnumerable<Models.CommitStatus> ICommitStatusClient.AllBySha(string commitSha)
5051
{
5152
using (Context.BeginOperationScope())
5253
{
@@ -57,4 +58,9 @@ static bool Equals(CommitStatus a, CommitStatusCreate b)
5758
.ToList();
5859
}
5960
}
61+
62+
GitLabCollectionResponse<Models.CommitStatus> ICommitStatusClient.GetAsync(string commitSha, CommitStatusQuery query)
63+
{
64+
throw new NotImplementedException();
65+
}
6066
}

NGitLab.Tests/.editorconfig

-6
This file was deleted.

NGitLab.Tests/CommitStatusTests.cs

+164-121
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Linq;
3+
using System.Net;
34
using System.Threading.Tasks;
45
using NGitLab.Models;
56
using NGitLab.Tests.Docker;
@@ -9,6 +10,155 @@ namespace NGitLab.Tests;
910

1011
public class CommitStatusTests
1112
{
13+
[Test]
14+
[NGitLabRetry]
15+
public async Task Test_get_commit_status()
16+
{
17+
using var context = await CommitStatusTestContext.Create();
18+
var createdCommitStatus = context.AddOrUpdateCommitStatus();
19+
20+
var commitStatus = context.CommitStatusClient.AllBySha(context.Commit.Id.ToString()).ToList();
21+
Assert.That(commitStatus.FirstOrDefault()?.Status, Is.Not.Null);
22+
}
23+
24+
[Test]
25+
[NGitLabRetry]
26+
public async Task Test_post_commit_status_with_no_coverage()
27+
{
28+
using var context = await CommitStatusTestContext.Create();
29+
var createdCommitStatus = context.AddOrUpdateCommitStatus(coverage: null);
30+
31+
Assert.That(createdCommitStatus.Coverage, Is.Null);
32+
}
33+
34+
[Test]
35+
public async Task Test_AddingSameCommitStatusTwice_Throws()
36+
{
37+
// Arrange
38+
using var context = await CommitStatusTestContext.Create();
39+
var commitStatusCreate = context.SetUpCommitStatusCreate("running");
40+
41+
_ = context.CommitStatusClient.AddOrUpdate(commitStatusCreate);
42+
43+
// Act/Assert
44+
var ex = Assert.Throws<GitLabException>(() => _ = context.CommitStatusClient.AddOrUpdate(commitStatusCreate));
45+
Assert.That(ex.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
46+
Assert.That(ex.ErrorMessage, Is.EqualTo("Cannot transition status via :run from :running (Reason(s): Status cannot transition via \"run\")"));
47+
}
48+
49+
[Test]
50+
public async Task Test_AddingCommitStatusesWithDifferentNamesOnSameCommit_Succeeds()
51+
{
52+
// Arrange
53+
using var context = await CommitStatusTestContext.Create();
54+
var commitStatusCreate = context.SetUpCommitStatusCreate("running", "Status 1");
55+
56+
var commitStatus1 = context.CommitStatusClient.AddOrUpdate(commitStatusCreate);
57+
58+
// Act
59+
commitStatusCreate.Name = "Status 2";
60+
var commitStatus2 = context.CommitStatusClient.AddOrUpdate(commitStatusCreate);
61+
62+
// Assert
63+
var properties = typeof(CommitStatusCreate).GetProperties();
64+
65+
// All properties should be the same except 'Name' & 'Id'
66+
foreach (var property in properties)
67+
{
68+
var value1 = property.GetValue(commitStatus1);
69+
var value2 = property.GetValue(commitStatus2);
70+
71+
if (string.Equals(property.Name, nameof(CommitStatus.Name), StringComparison.Ordinal) ||
72+
string.Equals(property.Name, nameof(CommitStatus.Id), StringComparison.Ordinal))
73+
{
74+
Assert.That(value1, Is.Not.EqualTo(value2));
75+
}
76+
else
77+
{
78+
Assert.That(value1, Is.EqualTo(value2));
79+
}
80+
}
81+
}
82+
83+
[TestCase(["pending", "failed"])]
84+
[TestCase(["pending", "canceled"])]
85+
[TestCase(["pending", "success"])]
86+
[TestCase(["canceled", "pending"])]
87+
[TestCase(["success", "pending"])]
88+
[TestCase(["success", "failed"])]
89+
[TestCase(["success", "canceled"])]
90+
[TestCase(["pending", "running", "success"])]
91+
[TestCase(["pending", "running", "failed"])]
92+
[TestCase(["pending", "running", "canceled"])]
93+
public async Task Test_UpdatingCommitStatus_SucceedsIfTransitionSupported(params string[] successiveStates)
94+
{
95+
// Arrange
96+
using var context = await CommitStatusTestContext.Create();
97+
var commitStatusCreate = context.SetUpCommitStatusCreate("unknown");
98+
99+
// Act/Assert
100+
foreach (var state in successiveStates)
101+
{
102+
commitStatusCreate.State = state;
103+
var commitStatus = context.CommitStatusClient.AddOrUpdate(commitStatusCreate);
104+
Assert.That(commitStatus.Status, Is.EqualTo(state));
105+
}
106+
}
107+
108+
[TestCase(["whatever"])]
109+
[TestCase(["running", "pending"])]
110+
public async Task Test_UpdatingCommitStatus_FailsIfStateUnknownOrTransitionUnsupported(params string[] successiveStates)
111+
{
112+
// Arrange
113+
using var context = await CommitStatusTestContext.Create();
114+
var commitStatusCreate = context.SetUpCommitStatusCreate("unknown");
115+
116+
for (var i = 0; i < successiveStates.Length - 1; i++)
117+
{
118+
var validState = successiveStates[i];
119+
commitStatusCreate.State = validState;
120+
var commitStatus = context.CommitStatusClient.AddOrUpdate(commitStatusCreate);
121+
Assert.That(commitStatus.Status, Is.EqualTo(validState));
122+
}
123+
124+
// Act/Assert
125+
var invalidState = successiveStates[successiveStates.Length - 1];
126+
commitStatusCreate.State = invalidState;
127+
128+
var ex = Assert.Throws<GitLabException>(() => _ = context.CommitStatusClient.AddOrUpdate(commitStatusCreate));
129+
Assert.That(ex.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
130+
Assert.That(ex.ErrorMessage, Does.StartWith("state does not have a valid value").Or
131+
.StartWith("Cannot transition status via"));
132+
}
133+
134+
[TestCase("whatever", false)]
135+
[TestCase(null, true)] // Will set 'nameToLookUp' to a dynamically created name
136+
public async Task Test_QueryByName(string nameToLookUp, bool expectToFind)
137+
{
138+
// Arrange
139+
using var context = await CommitStatusTestContext.Create();
140+
141+
string commitStatusName = null;
142+
for (var i = 0; i < 10; i++)
143+
{
144+
commitStatusName = $"Commit Status {Guid.NewGuid().ToString("N")}";
145+
var commitStatusCreate = context.SetUpCommitStatusCreate("running", commitStatusName);
146+
_ = context.CommitStatusClient.AddOrUpdate(commitStatusCreate);
147+
}
148+
149+
// If 'nameToLookUp' is null, use the latest commit status name instead
150+
nameToLookUp ??= commitStatusName;
151+
152+
// Act
153+
var statuses = context.CommitStatusClient.GetAsync(context.Commit.Id.ToString(), new CommitStatusQuery
154+
{
155+
Name = nameToLookUp,
156+
}).ToArray();
157+
158+
// Assert
159+
Assert.That(statuses.Count, Is.EqualTo(expectToFind ? 1 : 0));
160+
}
161+
12162
private sealed class CommitStatusTestContext : IDisposable
13163
{
14164
public GitLabTestContext Context { get; }
@@ -19,7 +169,7 @@ private sealed class CommitStatusTestContext : IDisposable
19169

20170
public ICommitStatusClient CommitStatusClient { get; }
21171

22-
public CommitStatusTestContext(GitLabTestContext context, Project project, Commit commit, ICommitStatusClient commitStatusClient)
172+
private CommitStatusTestContext(GitLabTestContext context, Project project, Commit commit, ICommitStatusClient commitStatusClient)
23173
{
24174
Context = context;
25175
Project = project;
@@ -52,141 +202,34 @@ public static async Task<CommitStatusTestContext> Create()
52202

53203
public CommitStatusCreate AddOrUpdateCommitStatus(string state = "success", int? coverage = null)
54204
{
55-
var commitStatus = SetupCommitStatus(state, coverage);
205+
var commitStatusCreate = SetUpCommitStatusCreate(state, coverage: coverage);
56206

57-
var createdCommitStatus = CommitStatusClient.AddOrUpdate(commitStatus);
207+
var createdCommitStatus = CommitStatusClient.AddOrUpdate(commitStatusCreate);
58208

59-
Assert.That(createdCommitStatus.Ref, Is.EqualTo(commitStatus.Ref));
60-
Assert.That(createdCommitStatus.Coverage, Is.EqualTo(commitStatus.Coverage));
61-
Assert.That(createdCommitStatus.Description, Is.EqualTo(commitStatus.Description));
62-
Assert.That(createdCommitStatus.Status, Is.EqualTo(commitStatus.State));
63-
Assert.That(createdCommitStatus.Name, Is.EqualTo(commitStatus.Name));
64-
Assert.That(createdCommitStatus.TargetUrl, Is.EqualTo(commitStatus.TargetUrl));
65-
Assert.That(string.Equals(commitStatus.CommitSha, createdCommitStatus.CommitSha, StringComparison.OrdinalIgnoreCase), Is.True);
209+
Assert.That(createdCommitStatus.Ref, Is.EqualTo(commitStatusCreate.Ref));
210+
Assert.That(createdCommitStatus.Coverage, Is.EqualTo(commitStatusCreate.Coverage));
211+
Assert.That(createdCommitStatus.Description, Is.EqualTo(commitStatusCreate.Description));
212+
Assert.That(createdCommitStatus.Status, Is.EqualTo(commitStatusCreate.State));
213+
Assert.That(createdCommitStatus.Name, Is.EqualTo(commitStatusCreate.Name));
214+
Assert.That(createdCommitStatus.TargetUrl, Is.EqualTo(commitStatusCreate.TargetUrl));
215+
Assert.That(createdCommitStatus.CommitSha, Is.EqualTo(commitStatusCreate.CommitSha).IgnoreCase);
66216

67217
return createdCommitStatus;
68218
}
69219

70-
private CommitStatusCreate SetupCommitStatus(string state, int? coverage = 100)
220+
public CommitStatusCreate SetUpCommitStatusCreate(string state, string name = null, int? coverage = 100)
71221
{
222+
name ??= "Some Commit Status";
72223
return new CommitStatusCreate
73224
{
74225
Ref = Project.DefaultBranch,
75226
CommitSha = Commit.Id.ToString(),
76-
Name = "Commit for CommitStatusTests",
227+
Name = name,
77228
State = state,
78-
Description = "desc",
229+
Description = "Description for this commit status",
79230
Coverage = coverage,
80231
TargetUrl = "https://google.ca/",
81232
};
82233
}
83234
}
84-
85-
[Test]
86-
[NGitLabRetry]
87-
public async Task Test_get_commit_status()
88-
{
89-
using var context = await CommitStatusTestContext.Create();
90-
var createdCommitStatus = context.AddOrUpdateCommitStatus();
91-
92-
var commitStatus = context.CommitStatusClient.AllBySha(context.Commit.Id.ToString().ToLowerInvariant()).ToList();
93-
Assert.That(commitStatus.FirstOrDefault()?.Status, Is.Not.Null);
94-
}
95-
96-
[Test]
97-
[NGitLabRetry]
98-
public async Task Test_post_commit_status_with_no_coverage()
99-
{
100-
using var context = await CommitStatusTestContext.Create();
101-
var commitStatus = context.AddOrUpdateCommitStatus(coverage: null);
102-
103-
Assert.That(commitStatus.Coverage, Is.Null);
104-
}
105-
106-
[Test]
107-
[NGitLabRetry]
108-
public async Task Test_post_commit_status_and_update_it_from_pending_to_running_to_success()
109-
{
110-
using var context = await CommitStatusTestContext.Create();
111-
var commitStatus = context.AddOrUpdateCommitStatus(state: "pending");
112-
Assert.That(commitStatus.Status, Is.EqualTo("pending"));
113-
114-
commitStatus = context.AddOrUpdateCommitStatus(state: "running");
115-
Assert.That(commitStatus.Status, Is.EqualTo("running"));
116-
117-
commitStatus = context.AddOrUpdateCommitStatus(state: "success");
118-
Assert.That(commitStatus.Status, Is.EqualTo("success"));
119-
}
120-
121-
[Test]
122-
[NGitLabRetry]
123-
public async Task Test_post_commit_status_and_update_it_from_pending_to_failed()
124-
{
125-
using var context = await CommitStatusTestContext.Create();
126-
var commitStatus = context.AddOrUpdateCommitStatus(state: "pending");
127-
Assert.That(commitStatus.Status, Is.EqualTo("pending"));
128-
129-
commitStatus = context.AddOrUpdateCommitStatus(state: "failed");
130-
Assert.That(commitStatus.Status, Is.EqualTo("failed"));
131-
}
132-
133-
[Test]
134-
[NGitLabRetry]
135-
public async Task Test_post_commit_status_and_update_it_from_pending_to_canceled()
136-
{
137-
using var context = await CommitStatusTestContext.Create();
138-
var commitStatus = context.AddOrUpdateCommitStatus(state: "pending");
139-
Assert.That(commitStatus.Status, Is.EqualTo("pending"));
140-
141-
commitStatus = context.AddOrUpdateCommitStatus(state: "canceled");
142-
Assert.That(commitStatus.Status, Is.EqualTo("canceled"));
143-
}
144-
145-
[Test]
146-
[NGitLabRetry]
147-
public async Task Test_post_commit_status_and_update_it_from_success_to_pending()
148-
{
149-
using var context = await CommitStatusTestContext.Create();
150-
var commitStatus = context.AddOrUpdateCommitStatus(state: "success");
151-
Assert.That(commitStatus.Status, Is.EqualTo("success"));
152-
153-
commitStatus = context.AddOrUpdateCommitStatus(state: "pending");
154-
Assert.That(commitStatus.Status, Is.EqualTo("pending"));
155-
}
156-
157-
[Test]
158-
[NGitLabRetry]
159-
public async Task Test_post_commit_status_and_update_it_from_success_to_failed()
160-
{
161-
using var context = await CommitStatusTestContext.Create();
162-
var commitStatus = context.AddOrUpdateCommitStatus(state: "success");
163-
Assert.That(commitStatus.Status, Is.EqualTo("success"));
164-
165-
commitStatus = context.AddOrUpdateCommitStatus(state: "failed");
166-
Assert.That(commitStatus.Status, Is.EqualTo("failed"));
167-
}
168-
169-
[Test]
170-
[NGitLabRetry]
171-
public async Task Test_post_commit_status_and_update_it_from_success_to_canceled()
172-
{
173-
using var context = await CommitStatusTestContext.Create();
174-
var commitStatus = context.AddOrUpdateCommitStatus(state: "success");
175-
Assert.That(commitStatus.Status, Is.EqualTo("success"));
176-
177-
commitStatus = context.AddOrUpdateCommitStatus(state: "canceled");
178-
Assert.That(commitStatus.Status, Is.EqualTo("canceled"));
179-
}
180-
181-
[Test]
182-
[NGitLabRetry]
183-
public async Task Test_post_commit_status_and_update_it_from_canceled_to_pending()
184-
{
185-
using var context = await CommitStatusTestContext.Create();
186-
var commitStatus = context.AddOrUpdateCommitStatus(state: "canceled");
187-
Assert.That(commitStatus.Status, Is.EqualTo("canceled"));
188-
189-
commitStatus = context.AddOrUpdateCommitStatus(state: "pending");
190-
Assert.That(commitStatus.Status, Is.EqualTo("pending"));
191-
}
192235
}

NGitLab.Tests/PipelineTests.cs

-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ public async Task Test_can_get_coverage()
5353
Name = "test",
5454
Coverage = 50,
5555
Description = "descr",
56-
Status = "success",
5756
State = "success",
5857
TargetUrl = "https://example.com",
5958
});

0 commit comments

Comments
 (0)