From 99b93c12930895ea4c259430ce2a8dffed1071a3 Mon Sep 17 00:00:00 2001 From: Haacked Date: Mon, 29 Dec 2014 22:15:38 -0800 Subject: [PATCH] Add documentation and refactor some types --- .../Clients/RepositoryContentsClientTests.cs | 76 +++++++++++++++- Octokit/Clients/IRepositoryContentsClient.cs | 20 +++-- Octokit/Clients/RepositoryContentsClient.cs | 76 +++++----------- Octokit/Http/Connection.cs | 1 - Octokit/Models/Response/DirectoryContent.cs | 90 ++++++++++++++----- 5 files changed, 176 insertions(+), 87 deletions(-) diff --git a/Octokit.Tests.Integration/Clients/RepositoryContentsClientTests.cs b/Octokit.Tests.Integration/Clients/RepositoryContentsClientTests.cs index ad6654fd..fc596118 100644 --- a/Octokit.Tests.Integration/Clients/RepositoryContentsClientTests.cs +++ b/Octokit.Tests.Integration/Clients/RepositoryContentsClientTests.cs @@ -1,16 +1,18 @@ using System; +using System.IO; using System.Linq; using System.Threading.Tasks; +using Octokit.Models.Request; using Xunit; namespace Octokit.Tests.Integration.Clients { public class RepositoryContentsClientTests { - public class TheGetRootMethod + public class TheGetContentsMethod { [IntegrationTest] - public async Task GetsRootContents() + public async Task GetsFileContent() { var github = new GitHubClient(new ProductHeaderValue("OctokitTests")) { @@ -20,10 +22,78 @@ namespace Octokit.Tests.Integration.Clients var contents = await github .Repository .Content - .GetForPath("octokit", "octokit.net", "Octokit.Reactive/ObservableGitHubClient.cs"); + .GetContents("octokit", "octokit.net", "Octokit.Reactive/ObservableGitHubClient.cs"); + Assert.Equal(1, contents.Count); + Assert.Equal(ContentType.File, contents.First().Type); Assert.Equal(new Uri("https://github.com/octokit/octokit.net/blob/master/Octokit.Reactive/ObservableGitHubClient.cs"), contents.First().HtmlUrl); } + + [IntegrationTest] + public async Task GetsDirectoryContent() + { + var github = new GitHubClient(new ProductHeaderValue("OctokitTests")) + { + Credentials = Helper.Credentials + }; + + var contents = await github + .Repository + .Content + .GetContents("octokit", "octokit.net", "Octokit"); + + Assert.True(contents.Count > 2); + Assert.Equal(ContentType.Dir, contents.First().Type); + } + } + + [IntegrationTest] + public async Task CrudTest() + { + var client = new GitHubClient(new ProductHeaderValue("OctokitTests")) + { + Credentials = Helper.Credentials + }; + Repository repository = null; + try + { + var fixture = client.Repository.Content; + var repoName = Helper.MakeNameWithTimestamp("source-repo"); + repository = await client.Repository.Create(new NewRepository { Name = repoName, AutoInit = true }); + + var file = await fixture.CreateFile( + repository.Owner.Login, + repository.Name, + "somefile.txt", + new CreateFileRequest("Test commit", "Some Content")); + Assert.Equal("Some Content", file.Content.Content); + + var contents = await fixture.GetContents(repository.Owner.Login, repository.Name, "somefile.txt"); + string fileSha = contents.First().Sha; + Assert.Equal("Some Content", contents.First().Content); + + var update = await fixture.UpdateFile( + repository.Owner.Login, + repository.Name, + "somefile.txt", + new UpdateFileRequest("Updating file", "New Content", fileSha)); + string updatedFileSha = update.Commit.Sha; + Assert.Equal("New Content", update.Content.Content); + + await fixture.DeleteFile( + repository.Owner.Login, + repository.Name, + "somefile.txt", + new DeleteFileRequest("Deleted file", updatedFileSha)); + + await Assert.ThrowsAsync( + async () => await fixture.GetContents(repository.Owner.Login, repository.Name, "somefile.txt")); + } + finally + { + Assert.NotNull(repository); + client.Repository.Delete(repository.Owner.Login, repository.Name); + } } } } \ No newline at end of file diff --git a/Octokit/Clients/IRepositoryContentsClient.cs b/Octokit/Clients/IRepositoryContentsClient.cs index dc4dec6f..9c6e6dc9 100644 --- a/Octokit/Clients/IRepositoryContentsClient.cs +++ b/Octokit/Clients/IRepositoryContentsClient.cs @@ -6,9 +6,19 @@ namespace Octokit { public interface IRepositoryContentsClient { - Task> GetRoot(string owner, string name); - - Task> GetForPath(string owner, string name, string path); + /// + /// Returns the contents of a file or directory in a repository. + /// + /// + /// If given a path to a single file, this method returns a collection containing only that file. + /// + /// The owner of the repository + /// The name of the repository + /// The content path + /// + /// A collection of representing the content at the specified path + /// + Task> GetContents(string owner, string name, string path); /// /// Gets the preferred README for the specified repository. @@ -42,7 +52,7 @@ namespace Octokit /// The path to the file /// Information about the file to create /// - Task CreateFile(string owner, string name, string path, CreateFileRequest request); + Task CreateFile(string owner, string name, string path, CreateFileRequest request); /// /// Creates a commit that updates the contents of a file in a repository. @@ -52,7 +62,7 @@ namespace Octokit /// The path to the file /// Information about the file to update /// The updated content - Task UpdateFile(string owner, string name, string path, UpdateFileRequest request); + Task UpdateFile(string owner, string name, string path, UpdateFileRequest request); /// /// Creates a commit that deletes a file in a repository. diff --git a/Octokit/Clients/RepositoryContentsClient.cs b/Octokit/Clients/RepositoryContentsClient.cs index 6af384ae..8f3d30b7 100644 --- a/Octokit/Clients/RepositoryContentsClient.cs +++ b/Octokit/Clients/RepositoryContentsClient.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; +using System.Collections.Generic; using System.Threading.Tasks; using Octokit.Models.Request; @@ -12,45 +10,28 @@ namespace Octokit { } - public Task> GetRoot(string owner, string name) - { - Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); - Ensure.ArgumentNotNullOrEmptyString(name, "name"); - - return ApiConnection.GetAll(ApiUrls.RepositoryContent(owner, name)); - } - - public async Task> GetForPath(string owner, string name, string path) + /// + /// Returns the contents of a file or directory in a repository. + /// + /// + /// If given a path to a single file, this method returns a collection containing only that file. + /// + /// The owner of the repository + /// The name of the repository + /// The content path + /// + /// A collection of representing the content at the specified path + /// + public async Task> GetContents(string owner, string name, string path) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); Ensure.ArgumentNotNullOrEmptyString(name, "name"); Ensure.ArgumentNotNullOrEmptyString(path, "path"); - // First, find content in parent directory. - var content = await FindContent(owner, name, path); - - if (content == null) - { - // We've asked for a file/folder that don't exist. - return new List(); - } - var url = ApiUrls.RepositoryContent(owner, name, path); - // Check which type the content is before fetching/deserializing it. - switch (content.Type) - { - case ContentType.Dir: - return await ApiConnection.GetAll(url); - case ContentType.File: - return new List { await ApiConnection.Get(url) }; - case ContentType.Symlink: - return new List { await ApiConnection.Get(url) }; - case ContentType.Submodule: - return new List { await ApiConnection.Get(url) }; - default: - throw new ArgumentOutOfRangeException(); - } + return await ApiConnection.GetAll(url); + // return new List { await ApiConnection.Get(url) } } /// @@ -100,7 +81,7 @@ namespace Octokit /// The path to the file /// Information about the file to create /// - public Task CreateFile(string owner, string name, string path, CreateFileRequest request) + public Task CreateFile(string owner, string name, string path, CreateFileRequest request) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); Ensure.ArgumentNotNullOrEmptyString(name, "name"); @@ -108,7 +89,7 @@ namespace Octokit Ensure.ArgumentNotNull(request, "request"); var createUrl = ApiUrls.RepositoryContent(owner, name, path); - return ApiConnection.Put(createUrl, request); + return ApiConnection.Put(createUrl, request); } /// @@ -119,7 +100,7 @@ namespace Octokit /// The path to the file /// Information about the file to update /// The updated content - public Task UpdateFile(string owner, string name, string path, UpdateFileRequest request) + public Task UpdateFile(string owner, string name, string path, UpdateFileRequest request) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); Ensure.ArgumentNotNullOrEmptyString(name, "name"); @@ -127,7 +108,7 @@ namespace Octokit Ensure.ArgumentNotNull(request, "request"); var updateUrl = ApiUrls.RepositoryContent(owner, name, path); - return ApiConnection.Put(updateUrl, request); + return ApiConnection.Put(updateUrl, request); } /// @@ -147,22 +128,5 @@ namespace Octokit var deleteUrl = ApiUrls.RepositoryContent(owner, name, path); return ApiConnection.Delete(deleteUrl, request); } - - private async Task FindContent(string owner, string name, string path) - { - var pathParts = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); - - var fileOrDirectoryName = pathParts.Last(); - - var parentPath = string.Join("/", pathParts.TakeWhile(x => x != fileOrDirectoryName)); - - var parentContentsUri = !string.IsNullOrEmpty(parentPath) - ? ApiUrls.RepositoryContent(owner, name, parentPath) - : ApiUrls.RepositoryContent(owner, name); - - var parentContents = await ApiConnection.GetAll(parentContentsUri); - - return parentContents.FirstOrDefault(x => x.Name == fileOrDirectoryName); - } } } \ No newline at end of file diff --git a/Octokit/Http/Connection.cs b/Octokit/Http/Connection.cs index 89051475..a3689bee 100644 --- a/Octokit/Http/Connection.cs +++ b/Octokit/Http/Connection.cs @@ -140,7 +140,6 @@ namespace Octokit Ensure.ArgumentNotNull(uri, "uri"); return SendData(uri.ApplyParameters(parameters), HttpMethod.Get, null, accepts, null, CancellationToken.None); - } public Task> Get(Uri uri, IDictionary parameters, string accepts, CancellationToken cancellationToken) diff --git a/Octokit/Models/Response/DirectoryContent.cs b/Octokit/Models/Response/DirectoryContent.cs index bc661be7..f33be101 100644 --- a/Octokit/Models/Response/DirectoryContent.cs +++ b/Octokit/Models/Response/DirectoryContent.cs @@ -3,43 +3,77 @@ using System.Diagnostics.CodeAnalysis; namespace Octokit { - public class DirectoryContent + /// + /// Represents a piece of content in the repository. This could be a submodule, a symlink, a directory, or a file. + /// Look at the Type property to figure out which one it is. + /// + public class RepositoryContent { + /// + /// Name of the content. + /// public string Name { get; set; } + /// + /// Path to this content. + /// public string Path { get; set; } + /// + /// SHA of the last commit that modified this content. + /// public string Sha { get; set; } - public int? Size { get; set; } + /// + /// Size of the content. + /// + public int Size { get; set; } + /// + /// The encoding of the content if this is a file. Typically "base64". Otherwise it's null. + /// + public string Encoding { get; set; } + + /// + /// The encoded content if this is a file. Otherwise it's null. + /// + public string Content { get; set; } + + /// + /// The type of this content. It might be a File, Directory, Submodule, or Symlink + /// [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification = "Matches the property name used by the API")] public ContentType Type { get; set; } + /// + /// Path to the target file in the repository if this is a symlink. Otherwise it's null. + /// + public string Target { get; set; } + + /// + /// The location of the submodule repository if this is a submodule. Otherwise it's null. + /// + public Uri SubmoduleGitUrl { get; set; } + + /// + /// URL to this content + /// public Uri Url { get; set; } + /// + /// The GIT URL to this content. + /// public Uri GitUrl { get; set; } + /// + /// The URL to view this content on GitHub. + /// public Uri HtmlUrl { get; set; } } - - public class FileContent : DirectoryContent - { - public string Encoding { get; set; } - - public string Content { get; set; } - } - - public class SymlinkContent : DirectoryContent - { - public string Target { get; set; } - } - - public class SubmoduleContent : DirectoryContent - { - public Uri SubmoduleGitUrl { get; set; } - } - + + /// + /// The possible repository content types. + /// public enum ContentType { File, @@ -49,9 +83,21 @@ namespace Octokit Submodule } - public class CreatedContent + /// + /// The response from the Repository Contents API. The API assumes a dynamic client type so we need + /// to model that. + /// + /// https://developer.github.com/v3/repos/contents/ + public class RepositoryContentChangeSet { - public DirectoryContent Content { get; set; } + /// + /// The directory content of the response. + /// + public RepositoryContent Content { get; set; } + + /// + /// The commit information for the content change. + /// public Commit Commit { get; set; } } } \ No newline at end of file