Skip to content

Commit 5c48927

Browse files
MindaugasLaganeckasnmklotas
authored andcommitted
Get commit by SHA. (#52)
* Added commits model * Added nock support * Get commit by its SHA * Deleted * BUG FIX: in appending commit ID * Supported mocking for GitlabFacade. Corrected the unit test. * made the test more restricting * Post review part 1 * Get commits from the branch * fixed warning * BUG FIX: url handling in TagClient * deleted GitLabHttpFacade * fixed imports in test project * implemented tests by mocking HttpClientHandler
1 parent f55166c commit 5c48927

19 files changed

+244
-34
lines changed

src/GitLabApiClient/BranchClient.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.Text;
43
using System.Threading.Tasks;
54
using GitLabApiClient.Internal.Http;
65
using GitLabApiClient.Internal.Queries;

src/GitLabApiClient/CommitsClient.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Threading.Tasks;
4+
using GitLabApiClient.Internal.Http;
5+
using GitLabApiClient.Internal.Queries;
6+
using GitLabApiClient.Models.Commits.Requests;
7+
using GitLabApiClient.Models.Commits.Responses;
8+
9+
namespace GitLabApiClient
10+
{
11+
public sealed class CommitsClient
12+
{
13+
private readonly GitLabHttpFacade _httpFacade;
14+
private readonly CommitQueryBuilder _commitQueryBuilder;
15+
16+
internal CommitsClient(GitLabHttpFacade httpFacade, CommitQueryBuilder commitQueryBuilder)
17+
{
18+
_httpFacade = httpFacade;
19+
_commitQueryBuilder = commitQueryBuilder;
20+
}
21+
22+
public async Task<Commit> GetAsync(string projectId, string sha) =>
23+
await _httpFacade.Get<Commit>(CommitsBaseUrl(projectId) + "/" + sha);
24+
25+
public async Task<IList<Commit>> GetAsync(string projectId, Action<CommitQueryOptions> options)
26+
{
27+
var queryOptions = new CommitQueryOptions(projectId);
28+
options?.Invoke(queryOptions);
29+
30+
string url = _commitQueryBuilder.Build(CommitsBaseUrl(projectId), queryOptions);
31+
return await _httpFacade.GetPagedList<Commit>(url);
32+
}
33+
34+
private static string CommitsBaseUrl(string projectId)
35+
{
36+
return $"projects/{projectId}/repository/commits";
37+
}
38+
}
39+
}

src/GitLabApiClient/GitLabClient.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ public GitLabClient(string hostUrl, string authenticationToken = "")
4545
var branchQueryBuilder = new BranchQueryBuilder();
4646
var releaseQueryBuilder = new ReleaseQueryBuilder();
4747
var tagQueryBuilder = new TagQueryBuilder();
48+
var commitQueryBuilder = new CommitQueryBuilder();
4849

4950
Issues = new IssuesClient(_httpFacade, issuesQueryBuilder, projectIssuesQueryBuilder, projectIssueNotesQueryBuilder);
5051
Uploads = new UploadsClient(_httpFacade);
@@ -55,6 +56,7 @@ public GitLabClient(string hostUrl, string authenticationToken = "")
5556
Branches = new BranchClient(_httpFacade, branchQueryBuilder);
5657
Releases = new ReleaseClient(_httpFacade, releaseQueryBuilder);
5758
Tags = new TagClient(_httpFacade, tagQueryBuilder);
59+
Commits = new CommitsClient(_httpFacade, commitQueryBuilder);
5860
Markdown = new MarkdownClient(_httpFacade);
5961
}
6062

@@ -103,6 +105,11 @@ public GitLabClient(string hostUrl, string authenticationToken = "")
103105
/// </summary>
104106
public TagClient Tags { get; }
105107

108+
/// <summary>
109+
/// Access GitLab's commits API.
110+
/// </summary>
111+
public CommitsClient Commits { get; }
112+
106113
/// <summary>
107114
/// Access GitLab's Markdown API.
108115
/// </summary>

src/GitLabApiClient/GroupsClient.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
using System;
2-
using System.Net.Http;
32
using System.Collections.Generic;
3+
using System.Net.Http;
44
using System.Threading.Tasks;
55
using GitLabApiClient.Internal.Http;
66
using GitLabApiClient.Internal.Queries;
7+
using GitLabApiClient.Internal.Utilities;
8+
using GitLabApiClient.Models;
79
using GitLabApiClient.Models.Groups.Requests;
810
using GitLabApiClient.Models.Groups.Responses;
9-
using GitLabApiClient.Models.Projects.Responses;
10-
using GitLabApiClient.Models.Milestones.Responses;
1111
using GitLabApiClient.Models.Milestones.Requests;
12-
using GitLabApiClient.Internal.Utilities;
13-
using GitLabApiClient.Models;
12+
using GitLabApiClient.Models.Milestones.Responses;
13+
using GitLabApiClient.Models.Projects.Responses;
1414

1515
namespace GitLabApiClient
1616
{
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
using System.Runtime.CompilerServices;
22

3-
[assembly:InternalsVisibleTo("GitLabApiClient.Test")]
3+
[assembly:InternalsVisibleTo("GitLabApiClient.Test")]
4+
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

src/GitLabApiClient/Internal/Http/GitLabHttpFacade.cs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,28 @@ internal sealed class GitLabHttpFacade
1515
private const string PrivateToken = "PRIVATE-TOKEN";
1616

1717
private readonly object _locker = new object();
18-
private readonly HttpClient _httpClient;
19-
private readonly GitLabApiRequestor _requestor;
20-
private readonly GitLabApiPagedRequestor _pagedRequestor;
18+
private HttpClient _httpClient;
19+
private GitLabApiRequestor _requestor;
20+
private GitLabApiPagedRequestor _pagedRequestor;
2121

2222
public GitLabHttpFacade(string hostUrl, RequestsJsonSerializer jsonSerializer, string authenticationToken = "")
2323
{
24-
// allow tls 1.1 and 1.2
25-
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
26-
_httpClient = new HttpClient
24+
var httpClient = new HttpClient
2725
{
2826
BaseAddress = new Uri(hostUrl)
2927
};
28+
httpClient.DefaultRequestHeaders.Add(PrivateToken, authenticationToken);
29+
30+
Setup(jsonSerializer, httpClient);
31+
}
32+
33+
public GitLabHttpFacade(RequestsJsonSerializer jsonSerializer, HttpClient httpClient) => Setup(jsonSerializer, httpClient);
3034

31-
_httpClient.DefaultRequestHeaders.Add(PrivateToken, authenticationToken);
35+
private void Setup(RequestsJsonSerializer jsonSerializer, HttpClient httpClient)
36+
{
37+
// allow tls 1.1 and 1.2
38+
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
39+
_httpClient = httpClient;
3240
_requestor = new GitLabApiRequestor(_httpClient, jsonSerializer);
3341
_pagedRequestor = new GitLabApiPagedRequestor(_requestor);
3442
}
@@ -51,10 +59,10 @@ public Task<Upload> PostFile(string uri, CreateUploadRequest uploadRequest) =>
5159
public Task<T> Put<T>(string uri, object data) =>
5260
_requestor.Put<T>(uri, data);
5361

54-
public Task Put(string uri, object data) =>
55-
_requestor.Put(uri, data);
62+
public Task Put(string uri, object data) =>
63+
_requestor.Put(uri, data);
5664

57-
public Task Delete(string uri) =>
65+
public Task Delete(string uri) =>
5866
_requestor.Delete(uri);
5967

6068
public async Task<Session> LoginAsync(string username, string password)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
using GitLabApiClient.Models.Commits.Requests;
5+
using GitLabApiClient.Models.Tags.Requests;
6+
7+
namespace GitLabApiClient.Internal.Queries
8+
{
9+
internal class CommitQueryBuilder : QueryBuilder<CommitQueryOptions>
10+
{
11+
protected override void BuildCore(CommitQueryOptions options)
12+
{
13+
if (!string.IsNullOrEmpty(options.ProjectId))
14+
Add("id", options.ProjectId);
15+
16+
if (!string.IsNullOrEmpty(options.RefName))
17+
Add("ref_name", options.RefName);
18+
}
19+
}
20+
}

src/GitLabApiClient/MarkdownClient.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Text;
4-
using System.Threading.Tasks;
1+
using System.Threading.Tasks;
52
using GitLabApiClient.Internal.Http;
63
using GitLabApiClient.Models.Markdown.Request;
74
using GitLabApiClient.Models.Markdown.Response;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace GitLabApiClient.Models.Commits.Requests
6+
{
7+
public sealed class CommitQueryOptions
8+
{
9+
public string ProjectId { get; set; }
10+
public string RefName { get; set; }
11+
internal CommitQueryOptions(string projectId = null) => ProjectId = projectId;
12+
}
13+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
using GitLabApiClient.Models.Releases.Responses;
5+
using Newtonsoft.Json;
6+
7+
namespace GitLabApiClient.Models.Commits.Responses
8+
{
9+
public sealed class Commit
10+
{
11+
[JsonProperty("id")]
12+
public string Id { get; set; }
13+
[JsonProperty("short_id")]
14+
public string ShortId { get; set; }
15+
[JsonProperty("title")]
16+
public string Title { get; set; }
17+
[JsonProperty("author_name")]
18+
public string AuthorName { get; set; }
19+
[JsonProperty("author_email")]
20+
public string AuthorEmail { get; set; }
21+
[JsonProperty("authored_date")]
22+
public DateTime AuthoredDate { get; set; }
23+
[JsonProperty("committer_name")]
24+
public string CommitterName { get; set; }
25+
[JsonProperty("committer_email")]
26+
public string CommitterEmail { get; set; }
27+
[JsonProperty("committed_date")]
28+
public DateTime CommittedDate { get; set; }
29+
[JsonProperty("created_at")]
30+
public DateTime CreatedAt { get; set; }
31+
[JsonProperty("message")]
32+
public string Message { get; set; }
33+
[JsonProperty("parent_ids")]
34+
public List<string> ParentIds { get; } = new List<string>();
35+
36+
}
37+
}

src/GitLabApiClient/ReleaseClient.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.Text;
43
using System.Threading.Tasks;
54
using GitLabApiClient.Internal.Http;
65
using GitLabApiClient.Internal.Queries;

src/GitLabApiClient/TagClient.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.Text;
43
using System.Threading.Tasks;
54
using GitLabApiClient.Internal.Http;
65
using GitLabApiClient.Internal.Queries;
@@ -42,8 +41,7 @@ public async Task DeleteAsync(DeleteTagRequest request) =>
4241

4342
public static string TagsBaseUrl(string projectId)
4443
{
45-
string baseUrl = $"projects/{projectId}/repository/tags";
46-
return baseUrl;
44+
return $"projects/{projectId}/repository/tags";
4745
}
4846
}
4947
}

src/GitLabApiClient/UploadsClient.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Text;
4-
using System.Threading.Tasks;
1+
using System.Threading.Tasks;
52
using GitLabApiClient.Internal.Http;
63
using GitLabApiClient.Models.Uploads.Requests;
74
using GitLabApiClient.Models.Uploads.Responses;
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using System;
2+
using System.Diagnostics.CodeAnalysis;
3+
using System.Net;
4+
using System.Net.Http;
5+
using FakeItEasy;
6+
using FluentAssertions;
7+
using GitLabApiClient.Internal.Http;
8+
using GitLabApiClient.Internal.Http.Serialization;
9+
using GitLabApiClient.Internal.Queries;
10+
using GitLabApiClient.Test.TestUtilities;
11+
using Xunit;
12+
13+
namespace GitLabApiClient.Test
14+
{
15+
[ExcludeFromCodeCoverage]
16+
public class CommitsClientTest
17+
{
18+
[Fact]
19+
public async void GetCommitBySha()
20+
{
21+
string gitlabServer = "http://fake-gitlab.com/";
22+
string projectId = "id";
23+
string sha = "6104942438c14ec7bd21c6cd5bd995272b3faff6";
24+
string url = $"/projects/{projectId}/repository/commits/{sha}";
25+
26+
var handler = A.Fake<MockHandler>(opt => opt.CallsBaseMethods());
27+
A.CallTo(() => handler.SendAsync(HttpMethod.Get, url))
28+
.ReturnsLazily(() => HttpResponseMessageProducer.Success(
29+
$"{{\"id\": \"{sha}\", }}"));
30+
using (var client = new HttpClient(handler) {BaseAddress = new Uri(gitlabServer)})
31+
{
32+
var gitlabHttpFacade = new GitLabHttpFacade(new RequestsJsonSerializer(), client);
33+
var commitsClient = new CommitsClient(gitlabHttpFacade, new CommitQueryBuilder());
34+
35+
var commitFromClient = await commitsClient.GetAsync(projectId, sha);
36+
commitFromClient.Id.Should().BeEquivalentTo(sha);
37+
}
38+
}
39+
40+
[Fact]
41+
public async void GetCommitsByRefName()
42+
{
43+
string gitlabServer = "http://fake-gitlab.com/";
44+
string projectId = "id";
45+
string refName = "6104942438c14ec7bd21c6cd5bd995272b3faff6";
46+
string url = $"/projects/id/repository/commits?id=id&ref_name={refName}&per_page=100&page=1";
47+
48+
var handler = A.Fake<MockHandler>(opt => opt.CallsBaseMethods());
49+
A.CallTo(() => handler.SendAsync(HttpMethod.Get, url))
50+
.ReturnsLazily(() => HttpResponseMessageProducer.Success(
51+
$"[ {{ \"id\": \"id1\",}},\n {{\"id\": \"id2\",}}]"));
52+
using (var client = new HttpClient(handler) {BaseAddress = new Uri(gitlabServer)})
53+
{
54+
var gitlabHttpFacade = new GitLabHttpFacade(new RequestsJsonSerializer(), client);
55+
var commitsClient = new CommitsClient(gitlabHttpFacade, new CommitQueryBuilder());
56+
57+
var commitsFromClient = await commitsClient.GetAsync(projectId, o => o.RefName = refName);
58+
commitsFromClient[0].Id.Should().BeEquivalentTo("id1");
59+
commitsFromClient[1].Id.Should().BeEquivalentTo("id2");
60+
}
61+
62+
}
63+
}
64+
}

test/GitLabApiClient.Test/GitLabApiClient.Test.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
<EmbeddedResource Include="Ressources\gitlabtest.png" />
1919
</ItemGroup>
2020
<ItemGroup>
21+
<PackageReference Include="FakeItEasy" Version="5.2.0" />
2122
<PackageReference Include="FluentAssertions" Version="4.19.4" />
2223
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
2324
<PackageReference Include="xunit" Version="2.2.0" />
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System.Net;
2+
using System.Net.Http;
3+
4+
namespace GitLabApiClient.Test.TestUtilities
5+
{
6+
public class HttpResponseMessageProducer
7+
{
8+
public static HttpResponseMessage Success(string content)
9+
{
10+
var response = new HttpResponseMessage(HttpStatusCode.OK) {Content = new StringContent(content)};
11+
return response;
12+
}
13+
}
14+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System.Net.Http;
2+
using System.Threading;
3+
using System.Threading.Tasks;
4+
5+
namespace GitLabApiClient.Test.TestUtilities
6+
{
7+
public abstract class MockHandler : HttpClientHandler
8+
{
9+
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
10+
{
11+
string requestUriPathAndQuery = request.RequestUri.PathAndQuery;
12+
return Task.FromResult(SendAsync(request.Method, requestUriPathAndQuery));
13+
}
14+
15+
public abstract HttpResponseMessage SendAsync(HttpMethod method, string url);
16+
}
17+
}

test/GitLabApiClient.Test/UploadsClientTest.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ public class UploadsClientTest
2424
public async Task UploadFile()
2525
{
2626
var assembly = Assembly.GetExecutingAssembly();
27-
var resourceName = assembly.GetManifestResourceNames()
27+
string resourceName = assembly.GetManifestResourceNames()
2828
.Single(str => str.EndsWith("gitlabtest.png"));
29-
var fileName = $"{Guid.NewGuid()}";
30-
var fileNameWithExtension = $"{fileName}.png";
29+
string fileName = $"{Guid.NewGuid()}";
30+
string fileNameWithExtension = $"{fileName}.png";
3131

3232
using (Stream stream = assembly.GetManifestResourceStream(resourceName))
3333
{

test/GitLabApiClient.Test/Utilities/GitLabContainterFixtureCollection.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
using System;
21
using Xunit;
3-
2+
43
namespace GitLabApiClient.Test.Utilities
54
{
65
[CollectionDefinition("GitLabContainerFixture")]

0 commit comments

Comments
 (0)