Add documentation and refactor some types

This commit is contained in:
Haacked
2014-12-29 22:15:38 -08:00
parent 0d3717208d
commit 99b93c1293
5 changed files with 176 additions and 87 deletions
@@ -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<FileNotFoundException>(
async () => await fixture.GetContents(repository.Owner.Login, repository.Name, "somefile.txt"));
}
finally
{
Assert.NotNull(repository);
client.Repository.Delete(repository.Owner.Login, repository.Name);
}
}
}
}
+15 -5
View File
@@ -6,9 +6,19 @@ namespace Octokit
{
public interface IRepositoryContentsClient
{
Task<IReadOnlyList<DirectoryContent>> GetRoot(string owner, string name);
Task<IReadOnlyList<DirectoryContent>> GetForPath(string owner, string name, string path);
/// <summary>
/// Returns the contents of a file or directory in a repository.
/// </summary>
/// <remarks>
/// If given a path to a single file, this method returns a collection containing only that file.
/// </remarks>
/// <param name="owner">The owner of the repository</param>
/// <param name="name">The name of the repository</param>
/// <param name="path">The content path</param>
/// <returns>
/// A collection of <see cref="RepositoryContent"/> representing the content at the specified path
/// </returns>
Task<IReadOnlyList<RepositoryContent>> GetContents(string owner, string name, string path);
/// <summary>
/// Gets the preferred README for the specified repository.
@@ -42,7 +52,7 @@ namespace Octokit
/// <param name="path">The path to the file</param>
/// <param name="request">Information about the file to create</param>
/// <returns></returns>
Task<CreatedContent> CreateFile(string owner, string name, string path, CreateFileRequest request);
Task<RepositoryContentChangeSet> CreateFile(string owner, string name, string path, CreateFileRequest request);
/// <summary>
/// Creates a commit that updates the contents of a file in a repository.
@@ -52,7 +62,7 @@ namespace Octokit
/// <param name="path">The path to the file</param>
/// <param name="request">Information about the file to update</param>
/// <returns>The updated content</returns>
Task<CreatedContent> UpdateFile(string owner, string name, string path, UpdateFileRequest request);
Task<RepositoryContentChangeSet> UpdateFile(string owner, string name, string path, UpdateFileRequest request);
/// <summary>
/// Creates a commit that deletes a file in a repository.
+20 -56
View File
@@ -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<IReadOnlyList<DirectoryContent>> GetRoot(string owner, string name)
{
Ensure.ArgumentNotNullOrEmptyString(owner, "owner");
Ensure.ArgumentNotNullOrEmptyString(name, "name");
return ApiConnection.GetAll<DirectoryContent>(ApiUrls.RepositoryContent(owner, name));
}
public async Task<IReadOnlyList<DirectoryContent>> GetForPath(string owner, string name, string path)
/// <summary>
/// Returns the contents of a file or directory in a repository.
/// </summary>
/// <remarks>
/// If given a path to a single file, this method returns a collection containing only that file.
/// </remarks>
/// <param name="owner">The owner of the repository</param>
/// <param name="name">The name of the repository</param>
/// <param name="path">The content path</param>
/// <returns>
/// A collection of <see cref="RepositoryContent"/> representing the content at the specified path
/// </returns>
public async Task<IReadOnlyList<RepositoryContent>> 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<DirectoryContent>();
}
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<DirectoryContent>(url);
case ContentType.File:
return new List<DirectoryContent> { await ApiConnection.Get<FileContent>(url) };
case ContentType.Symlink:
return new List<DirectoryContent> { await ApiConnection.Get<SymlinkContent>(url) };
case ContentType.Submodule:
return new List<DirectoryContent> { await ApiConnection.Get<SubmoduleContent>(url) };
default:
throw new ArgumentOutOfRangeException();
}
return await ApiConnection.GetAll<RepositoryContent>(url);
// return new List<RepositoryContent> { await ApiConnection.Get<RepositoryContent>(url) }
}
/// <summary>
@@ -100,7 +81,7 @@ namespace Octokit
/// <param name="path">The path to the file</param>
/// <param name="request">Information about the file to create</param>
/// <returns></returns>
public Task<CreatedContent> CreateFile(string owner, string name, string path, CreateFileRequest request)
public Task<RepositoryContentChangeSet> 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<CreatedContent>(createUrl, request);
return ApiConnection.Put<RepositoryContentChangeSet>(createUrl, request);
}
/// <summary>
@@ -119,7 +100,7 @@ namespace Octokit
/// <param name="path">The path to the file</param>
/// <param name="request">Information about the file to update</param>
/// <returns>The updated content</returns>
public Task<CreatedContent> UpdateFile(string owner, string name, string path, UpdateFileRequest request)
public Task<RepositoryContentChangeSet> 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<CreatedContent>(updateUrl, request);
return ApiConnection.Put<RepositoryContentChangeSet>(updateUrl, request);
}
/// <summary>
@@ -147,22 +128,5 @@ namespace Octokit
var deleteUrl = ApiUrls.RepositoryContent(owner, name, path);
return ApiConnection.Delete(deleteUrl, request);
}
private async Task<DirectoryContent> 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<DirectoryContent>(parentContentsUri);
return parentContents.FirstOrDefault(x => x.Name == fileOrDirectoryName);
}
}
}
-1
View File
@@ -140,7 +140,6 @@ namespace Octokit
Ensure.ArgumentNotNull(uri, "uri");
return SendData<T>(uri.ApplyParameters(parameters), HttpMethod.Get, null, accepts, null, CancellationToken.None);
}
public Task<IResponse<T>> Get<T>(Uri uri, IDictionary<string, string> parameters, string accepts, CancellationToken cancellationToken)
+68 -22
View File
@@ -3,43 +3,77 @@ using System.Diagnostics.CodeAnalysis;
namespace Octokit
{
public class DirectoryContent
/// <summary>
/// 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.
/// </summary>
public class RepositoryContent
{
/// <summary>
/// Name of the content.
/// </summary>
public string Name { get; set; }
/// <summary>
/// Path to this content.
/// </summary>
public string Path { get; set; }
/// <summary>
/// SHA of the last commit that modified this content.
/// </summary>
public string Sha { get; set; }
public int? Size { get; set; }
/// <summary>
/// Size of the content.
/// </summary>
public int Size { get; set; }
/// <summary>
/// The encoding of the content if this is a file. Typically "base64". Otherwise it's null.
/// </summary>
public string Encoding { get; set; }
/// <summary>
/// The encoded content if this is a file. Otherwise it's null.
/// </summary>
public string Content { get; set; }
/// <summary>
/// The type of this content. It might be a File, Directory, Submodule, or Symlink
/// </summary>
[SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification = "Matches the property name used by the API")]
public ContentType Type { get; set; }
/// <summary>
/// Path to the target file in the repository if this is a symlink. Otherwise it's null.
/// </summary>
public string Target { get; set; }
/// <summary>
/// The location of the submodule repository if this is a submodule. Otherwise it's null.
/// </summary>
public Uri SubmoduleGitUrl { get; set; }
/// <summary>
/// URL to this content
/// </summary>
public Uri Url { get; set; }
/// <summary>
/// The GIT URL to this content.
/// </summary>
public Uri GitUrl { get; set; }
/// <summary>
/// The URL to view this content on GitHub.
/// </summary>
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; }
}
/// <summary>
/// The possible repository content types.
/// </summary>
public enum ContentType
{
File,
@@ -49,9 +83,21 @@ namespace Octokit
Submodule
}
public class CreatedContent
/// <summary>
/// The response from the Repository Contents API. The API assumes a dynamic client type so we need
/// to model that.
/// </summary>
/// <remarks>https://developer.github.com/v3/repos/contents/</remarks>
public class RepositoryContentChangeSet
{
public DirectoryContent Content { get; set; }
/// <summary>
/// The directory content of the response.
/// </summary>
public RepositoryContent Content { get; set; }
/// <summary>
/// The commit information for the content change.
/// </summary>
public Commit Commit { get; set; }
}
}