Skip to content

Commit

Permalink
add files and trees client (nmklotas#77)
Browse files Browse the repository at this point in the history
Co-authored-by: Joseph Petersen <josephp90@gmail.com>
  • Loading branch information
2 people authored and MindaugasLaganeckas committed Mar 9, 2021
1 parent 912cbbd commit 53f2acc
Show file tree
Hide file tree
Showing 11 changed files with 309 additions and 0 deletions.
8 changes: 8 additions & 0 deletions docker/init.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
#!/usr/bin/env ruby
# Turn off auto devops as it not help for integration testing, causes stuck pipelines.
Gitlab::CurrentSettings.current_application_settings.update!(auto_devops_enabled: false)

u = User.first

g = Group.create!(name: 'txxxestgrouxxxp', path: 'txxxestgrouxxxp')
g.add_developer(u)
p = Project.create!(namespace: g, creator: u, path: 'txxxestprojecxxxt', name: 'txxxestprojecxxxt')
p.repository.create_if_not_exists
p.add_maintainer(u)
content = %{# Test project
Hello world
}
p.repository.create_file(u, 'README.md', content, message: 'Add README.md', branch_name: 'master')
c = p.repository.create_dir(u, 'newdir', message: 'Create newdir', branch_name: 'master')

t = PersonalAccessToken.new({ user: u, name: 'gitlab-api-client', scopes: ['api']})
Expand Down
21 changes: 21 additions & 0 deletions src/GitLabApiClient/FilesClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System.Threading.Tasks;
using GitLabApiClient.Internal.Http;
using GitLabApiClient.Internal.Paths;
using GitLabApiClient.Internal.Utilities;
using GitLabApiClient.Models.Files.Responses;
using GitLabApiClient.Models.Projects.Responses;

namespace GitLabApiClient
{
public sealed class FilesClient
{
private readonly GitLabHttpFacade _httpFacade;

internal FilesClient(GitLabHttpFacade httpFacade) => _httpFacade = httpFacade;

public async Task<File> GetAsync(ProjectId projectId, string filePath, string reference = "master")
{
return await _httpFacade.Get<File>($"projects/{projectId}/repository/files/{filePath.UrlEncode()}?ref={reference}");
}
}
}
13 changes: 13 additions & 0 deletions src/GitLabApiClient/GitLabClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public GitLabClient(string hostUrl, string authenticationToken = "")
var commitQueryBuilder = new CommitQueryBuilder();
var commitRefsQueryBuilder = new CommitRefsQueryBuilder();
var pipelineQueryBuilder = new PipelineQueryBuilder();
var treeQueryBuilder = new TreeQueryBuilder();

Issues = new IssuesClient(_httpFacade, issuesQueryBuilder, projectIssuesQueryBuilder, projectIssueNotesQueryBuilder);
Uploads = new UploadsClient(_httpFacade);
Expand All @@ -64,6 +65,8 @@ public GitLabClient(string hostUrl, string authenticationToken = "")
Commits = new CommitsClient(_httpFacade, commitQueryBuilder, commitRefsQueryBuilder);
Markdown = new MarkdownClient(_httpFacade);
Pipelines = new PipelineClient(_httpFacade, pipelineQueryBuilder);
Trees = new TreesClient(_httpFacade, treeQueryBuilder);
Files = new FilesClient(_httpFacade);
}

/// <summary>
Expand Down Expand Up @@ -121,6 +124,16 @@ public GitLabClient(string hostUrl, string authenticationToken = "")
/// </summary>
public CommitsClient Commits { get; }

/// <summary>
/// Access GitLab's trees API.
/// </summary>
public TreesClient Trees { get; }

/// <summary>
/// Access GitLab's files API.
/// </summary>
public FilesClient Files { get; }

/// <summary>
/// Access GitLab's Markdown API.
/// </summary>
Expand Down
24 changes: 24 additions & 0 deletions src/GitLabApiClient/Internal/Queries/TreeQueryBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Text;
using GitLabApiClient.Models.Trees.Requests;
using GitLabApiClient.Models.Tags.Requests;

namespace GitLabApiClient.Internal.Queries
{
internal class TreeQueryBuilder : QueryBuilder<TreeQueryOptions>
{
protected override void BuildCore(TreeQueryOptions options)
{
if (!string.IsNullOrEmpty(options.Reference))
Add("ref", options.Reference);

if (!string.IsNullOrEmpty(options.Path))
Add("path", options.Path);

if (options.Recursive)
Add("recursive", options.Recursive);

}
}
}
40 changes: 40 additions & 0 deletions src/GitLabApiClient/Models/Files/Responses/File.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using Newtonsoft.Json;

namespace GitLabApiClient.Models.Files.Responses
{
public sealed class File
{
[JsonProperty("file_name")]
public string Filename { get; set; }

[JsonProperty("file_path")]
public string FullPath { get; set; }

[JsonProperty("size")]
public int Size { get; set; }

[JsonProperty("encoding")]
public string Encoding { get; set; }

[JsonProperty("content_sha256")]
public string ContentSha256 { get; set; }

[JsonProperty("ref")]
public string Reference { get; set; }

[JsonProperty("blob_id")]
public string BlobId { get; set; }

[JsonProperty("commit_id")]
public string CommitId { get; set; }

[JsonProperty("last_commit_id")]
public string LastCommitId { get; set; }

[JsonProperty("content")]
public string Content { get; set; }

public string ContentDecoded => System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(Content));
}
}
20 changes: 20 additions & 0 deletions src/GitLabApiClient/Models/Trees/Requests/TreeQueryOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace GitLabApiClient.Models.Trees.Requests
{
public sealed class TreeQueryOptions
{
public string Reference { get; set; }
public string Path { get; set; }
public bool Recursive { get; set; }

internal TreeQueryOptions(string reference = null, string path = null, bool recursive = false)
{
Reference = reference;
Path = path;
Recursive = recursive;
}
}
}
26 changes: 26 additions & 0 deletions src/GitLabApiClient/Models/Trees/Responses/Tree.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Text;
using GitLabApiClient.Models.Releases.Responses;
using Newtonsoft.Json;

namespace GitLabApiClient.Models.Trees.Responses
{
public sealed class Tree
{
[JsonProperty("id")]
public string Id { get; set; }

[JsonProperty("name")]
public string Name { get; set; }

[JsonProperty("type")]
public string Type { get; set; }

[JsonProperty("path")]
public string Path { get; set; }

[JsonProperty("mode")]
public string Mode { get; set; }
}
}
32 changes: 32 additions & 0 deletions src/GitLabApiClient/TreesClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using GitLabApiClient.Internal.Http;
using GitLabApiClient.Internal.Paths;
using GitLabApiClient.Internal.Queries;
using GitLabApiClient.Models.Trees.Requests;
using GitLabApiClient.Models.Trees.Responses;

namespace GitLabApiClient
{
public sealed class TreesClient
{
private readonly GitLabHttpFacade _httpFacade;
private readonly TreeQueryBuilder _treeQueryBuilder;

internal TreesClient(GitLabHttpFacade httpFacade, TreeQueryBuilder treeQueryBuilder)
{
_httpFacade = httpFacade;
_treeQueryBuilder = treeQueryBuilder;
}

public async Task<IList<Tree>> GetAsync(ProjectId projectId, Action<TreeQueryOptions> options = null)
{
var queryOptions = new TreeQueryOptions();
options?.Invoke(queryOptions);

string url = _treeQueryBuilder.Build($"projects/{projectId}/repository/tree", queryOptions);
return await _httpFacade.GetPagedList<Tree>(url);
}
}
}
32 changes: 32 additions & 0 deletions test/GitLabApiClient.Test/FilesClientTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System.Threading.Tasks;
using FluentAssertions;
using Xunit;
using static GitLabApiClient.Test.Utilities.GitLabApiHelper;

namespace GitLabApiClient.Test
{
[Trait("Category", "LinuxIntegration")]
[Collection("GitLabContainerFixture")]
public class FilesClientTest
{
private readonly FilesClient _sut = new FilesClient(GetFacade());

[Fact]
public async Task GetFile()
{
var file = await _sut.GetAsync(TestProjectId, "README.md");
file.Content.Should().NotBeNull();
file.Encoding.Should().Be("base64");
file.Reference.Should().Be("master");
file.Filename.Should().Be("README.md");
file.FullPath.Should().Be("README.md");
file.Content.Should().Be("IyBUZXN0IHByb2plY3QKCkhlbGxvIHdvcmxkCg==");
file.Size.Should().Be(28);
file.ContentSha256.Should().Be("b6cb63af62daa14162368903ca4e42350cb1d855446febbdb22fb5c24f9aeedb");
file.BlobId.Should().HaveLength(40);
file.CommitId.Should().HaveLength(40);
file.LastCommitId.Should().HaveLength(40);
file.ContentDecoded.Should().Be("# Test project\n\nHello world\n");
}
}
}
2 changes: 2 additions & 0 deletions test/GitLabApiClient.Test/GitLabClientTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,15 @@ public void CheckClients()
var sut = new GitLabClient("https://gitlab.com/api/v4/");
sut.Branches.Should().BeAssignableTo(typeof(BranchClient));
sut.Commits.Should().BeAssignableTo(typeof(CommitsClient));
sut.Files.Should().BeAssignableTo(typeof(FilesClient));
sut.Groups.Should().BeAssignableTo(typeof(GroupsClient));
sut.Issues.Should().BeAssignableTo(typeof(IssuesClient));
sut.Markdown.Should().BeAssignableTo(typeof(MarkdownClient));
sut.Pipelines.Should().BeAssignableTo(typeof(PipelineClient));
sut.Projects.Should().BeAssignableTo(typeof(ProjectsClient));
sut.Releases.Should().BeAssignableTo(typeof(ReleaseClient));
sut.Tags.Should().BeAssignableTo(typeof(TagClient));
sut.Trees.Should().BeAssignableTo(typeof(TreesClient));
sut.Uploads.Should().BeAssignableTo(typeof(UploadsClient));
sut.Users.Should().BeAssignableTo(typeof(UsersClient));
sut.Webhooks.Should().BeAssignableTo(typeof(WebhookClient));
Expand Down
91 changes: 91 additions & 0 deletions test/GitLabApiClient.Test/TreesClientTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
using System.Threading.Tasks;
using FluentAssertions;
using GitLabApiClient.Internal.Queries;
using Xunit;
using static GitLabApiClient.Test.Utilities.GitLabApiHelper;

namespace GitLabApiClient.Test
{
[Trait("Category", "LinuxIntegration")]
[Collection("GitLabContainerFixture")]
public class TreesClientTest
{
private readonly TreesClient _sut = new TreesClient(GetFacade(), new TreeQueryBuilder());

[Fact]
public async Task GetTrees()
{
var trees = await _sut.GetAsync(TestProjectId);
trees.Should().SatisfyRespectively(
first =>
{
first.Id.Should().HaveLength(40);
first.Mode.Should().Be("040000");
first.Type.Should().Be("tree");
first.Name.Should().Be("newdir");
first.Path.Should().Be("newdir");
},
second =>
{
second.Id.Should().HaveLength(40);
second.Mode.Should().Be("100644");
second.Type.Should().Be("blob");
second.Name.Should().Be("README.md");
second.Path.Should().Be("README.md");
});

var otherTrees = await _sut.GetAsync(TestProjectId, options => options.Reference = "master");
otherTrees.Should().BeEquivalentTo(trees);
}

[Fact]
public async Task GetTreesInFolder()
{
var trees = await _sut.GetAsync(TestProjectId, options => options.Path = "newdir/");
trees.Should().SatisfyRespectively(
first =>
{
first.Id.Should().HaveLength(40);
first.Mode.Should().Be("100644");
first.Type.Should().Be("blob");
first.Name.Should().Be(".gitkeep");
first.Path.Should().Be("newdir/.gitkeep");
});
}

[Fact]
public async Task GetTreesRecursively()
{
var trees = await _sut.GetAsync(TestProjectId, options =>
{
options.Recursive = true;
options.Reference = "master";
});
trees.Should().SatisfyRespectively(
first =>
{
first.Id.Should().HaveLength(40);
first.Mode.Should().Be("040000");
first.Type.Should().Be("tree");
first.Name.Should().Be("newdir");
first.Path.Should().Be("newdir");
},
second =>
{
second.Id.Should().HaveLength(40);
second.Mode.Should().Be("100644");
second.Type.Should().Be("blob");
second.Name.Should().Be("README.md");
second.Path.Should().Be("README.md");
},
third =>
{
third.Id.Should().HaveLength(40);
third.Mode.Should().Be("100644");
third.Type.Should().Be("blob");
third.Name.Should().Be(".gitkeep");
third.Path.Should().Be("newdir/.gitkeep");
});
}
}
}

0 comments on commit 53f2acc

Please sign in to comment.