diff --git a/Octokit.Reactive/Clients/IObservableRepositoryContentsClient.cs b/Octokit.Reactive/Clients/IObservableRepositoryContentsClient.cs index 1ab8ab7b..110c0bd6 100644 --- a/Octokit.Reactive/Clients/IObservableRepositoryContentsClient.cs +++ b/Octokit.Reactive/Clients/IObservableRepositoryContentsClient.cs @@ -6,6 +6,9 @@ namespace Octokit.Reactive /// /// Client for accessing contents of files within a repository as base64 encoded content. /// + /// + /// See the Repository Contents API documentation for more information. + /// public interface IObservableRepositoryContentsClient { /// @@ -13,16 +16,26 @@ namespace Octokit.Reactive /// /// The owner of the repository /// The name of the repository - /// IObservable GetReadme(string owner, string name); + /// + /// Returns the HTML rendered README. + /// + /// The ID of the repository + IObservable GetReadme(int repositoryId); + /// /// Returns just the HTML portion of the README without the surrounding HTML document. /// /// The owner of the repository /// The name of the repository - /// IObservable GetReadmeHtml(string owner, string name); + + /// + /// Returns just the HTML portion of the README without the surrounding HTML document. + /// + /// The ID of the repository + IObservable GetReadmeHtml(int repositoryId); /// /// Get an archive of a given repository's contents @@ -30,9 +43,15 @@ namespace Octokit.Reactive /// https://developer.github.com/v3/repos/contents/#get-archive-link /// The owner of the repository /// The name of the repository - /// A promise, containing the binary contents of the archive IObservable GetArchive(string owner, string name); + /// + /// Get an archive of a given repository's contents + /// + /// https://developer.github.com/v3/repos/contents/#get-archive-link + /// The ID of the repository + IObservable GetArchive(int repositoryId); + /// /// Get an archive of a given repository's contents, in a specific format /// @@ -40,9 +59,16 @@ namespace Octokit.Reactive /// The owner of the repository /// The name of the repository /// The format of the archive. Can be either tarball or zipball - /// A promise, containing the binary contents of the archive IObservable GetArchive(string owner, string name, ArchiveFormat archiveFormat); + /// + /// Get an archive of a given repository's contents, in a specific format + /// + /// https://developer.github.com/v3/repos/contents/#get-archive-link + /// The ID of the repository + /// The format of the archive. Can be either tarball or zipball + IObservable GetArchive(int repositoryId, ArchiveFormat archiveFormat); + /// /// Get an archive of a given repository's contents, using a specific format and reference /// @@ -51,9 +77,17 @@ namespace Octokit.Reactive /// The name of the repository /// The format of the archive. Can be either tarball or zipball /// A valid Git reference. - /// A promise, containing the binary contents of the archive IObservable GetArchive(string owner, string name, ArchiveFormat archiveFormat, string reference); + /// + /// Get an archive of a given repository's contents, using a specific format and reference + /// + /// https://developer.github.com/v3/repos/contents/#get-archive-link + /// The ID of the repository + /// The format of the archive. Can be either tarball or zipball + /// A valid Git reference. + IObservable GetArchive(int repositoryId, ArchiveFormat archiveFormat, string reference); + /// /// Get an archive of a given repository's contents, in a specific format /// @@ -63,9 +97,18 @@ namespace Octokit.Reactive /// The format of the archive. Can be either tarball or zipball /// A valid Git reference. /// Time span until timeout - /// The binary contents of the archive IObservable GetArchive(string owner, string name, ArchiveFormat archiveFormat, string reference, TimeSpan timeout); + /// + /// Get an archive of a given repository's contents, in a specific format + /// + /// https://developer.github.com/v3/repos/contents/#get-archive-link + /// The ID of the repository + /// The format of the archive. Can be either tarball or zipball + /// A valid Git reference. + /// Time span until timeout + IObservable GetArchive(int repositoryId, ArchiveFormat archiveFormat, string reference, TimeSpan timeout); + /// /// Returns the contents of a file or directory in a repository. /// @@ -75,21 +118,31 @@ namespace Octokit.Reactive /// The owner of the repository /// The name of the repository /// The content path - /// - /// A collection of representing the content at the specified path - /// IObservable GetAllContents(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 ID of the repository + /// The content path + IObservable GetAllContents(int repositoryId, string path); + /// /// Returns the contents of the root directory in a repository. /// /// The owner of the repository /// The name of the repository - /// - /// A collection of representing the content at the specified path - /// IObservable GetAllContents(string owner, string name); + /// + /// Returns the contents of the root directory in a repository. + /// + /// The ID of the repository + IObservable GetAllContents(int repositoryId); + /// /// Returns the contents of a file or directory in a repository. /// @@ -101,23 +154,35 @@ namespace Octokit.Reactive /// The name of the repository /// The name of the commit/branch/tag. Default: the repository’s default branch (usually master) /// The content path - /// - /// A collection of representing the content at the specified path - /// IObservable GetAllContentsByRef(string owner, string name, string reference, 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. + /// See the API documentation for more information. + /// + /// The ID of the repository + /// The name of the commit/branch/tag. Default: the repository’s default branch (usually master) + /// The content path + IObservable GetAllContentsByRef(int repositoryId, string reference, string path); + /// /// Returns the contents of the home directory in a repository. /// /// The owner of the repository /// The name of the repository /// The name of the commit/branch/tag. Default: the repository’s default branch (usually master) - /// - /// A collection of representing the content at the specified path - /// IObservable GetAllContentsByRef(string owner, string name, string reference); + /// + /// Returns the contents of the home directory in a repository. + /// + /// The ID of the repository + /// The name of the commit/branch/tag. Default: the repository’s default branch (usually master) + IObservable GetAllContentsByRef(int repositoryId, string reference); + /// /// Creates a commit that creates a new file in a repository. /// @@ -125,9 +190,16 @@ namespace Octokit.Reactive /// The name of the repository /// The path to the file /// Information about the file to create - /// IObservable CreateFile(string owner, string name, string path, CreateFileRequest request); + /// + /// Creates a commit that creates a new file in a repository. + /// + /// The ID of the repository + /// The path to the file + /// Information about the file to create + IObservable CreateFile(int repositoryId, string path, CreateFileRequest request); + /// /// Creates a commit that updates the contents of a file in a repository. /// @@ -135,9 +207,16 @@ namespace Octokit.Reactive /// The name of the repository /// The path to the file /// Information about the file to update - /// The updated content IObservable UpdateFile(string owner, string name, string path, UpdateFileRequest request); + /// + /// Creates a commit that updates the contents of a file in a repository. + /// + /// The ID of the repository + /// The path to the file + /// Information about the file to update + IObservable UpdateFile(int repositoryId, string path, UpdateFileRequest request); + /// /// Creates a commit that deletes a file in a repository. /// @@ -146,5 +225,13 @@ namespace Octokit.Reactive /// The path to the file /// Information about the file to delete IObservable DeleteFile(string owner, string name, string path, DeleteFileRequest request); + + /// + /// Creates a commit that deletes a file in a repository. + /// + /// The ID of the repository + /// The path to the file + /// Information about the file to delete + IObservable DeleteFile(int repositoryId, string path, DeleteFileRequest request); } } \ No newline at end of file diff --git a/Octokit.Reactive/Clients/ObservableRepositoryContentsClient.cs b/Octokit.Reactive/Clients/ObservableRepositoryContentsClient.cs index 456ce31b..71625ead 100644 --- a/Octokit.Reactive/Clients/ObservableRepositoryContentsClient.cs +++ b/Octokit.Reactive/Clients/ObservableRepositoryContentsClient.cs @@ -1,4 +1,5 @@ using System; +using System.Reactive; using System.Reactive.Threading.Tasks; using Octokit.Reactive.Internal; @@ -7,6 +8,9 @@ namespace Octokit.Reactive /// /// Client for accessing contents of files within a repository as base64 encoded content. /// + /// + /// See the Repository Contents API documentation for more information. + /// public class ObservableRepositoryContentsClient : IObservableRepositoryContentsClient { readonly IGitHubClient _client; @@ -17,6 +21,8 @@ namespace Octokit.Reactive /// public ObservableRepositoryContentsClient(IGitHubClient client) { + Ensure.ArgumentNotNull(client, "client"); + _client = client; } @@ -25,7 +31,6 @@ namespace Octokit.Reactive /// /// The owner of the repository /// The name of the repository - /// public IObservable GetReadme(string owner, string name) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); @@ -34,12 +39,20 @@ namespace Octokit.Reactive return _client.Repository.Content.GetReadme(owner, name).ToObservable(); } + /// + /// Returns the HTML rendered README. + /// + /// The ID of the repository + public IObservable GetReadme(int repositoryId) + { + return _client.Repository.Content.GetReadme(repositoryId).ToObservable(); + } + /// /// Returns just the HTML portion of the README without the surrounding HTML document. /// /// The owner of the repository /// The name of the repository - /// public IObservable GetReadmeHtml(string owner, string name) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); @@ -48,18 +61,39 @@ namespace Octokit.Reactive return _client.Repository.Content.GetReadmeHtml(owner, name).ToObservable(); } + /// + /// Returns just the HTML portion of the README without the surrounding HTML document. + /// + /// The ID of the repository + public IObservable GetReadmeHtml(int repositoryId) + { + return _client.Repository.Content.GetReadmeHtml(repositoryId).ToObservable(); + } + /// /// Get an archive of a given repository's contents /// /// https://developer.github.com/v3/repos/contents/#get-archive-link /// The owner of the repository /// The name of the repository - /// A promise, containing the binary contents of the archive public IObservable GetArchive(string owner, string name) { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + return GetArchive(owner, name, ArchiveFormat.Tarball); } + /// + /// Get an archive of a given repository's contents + /// + /// https://developer.github.com/v3/repos/contents/#get-archive-link + /// The ID of the repository + public IObservable GetArchive(int repositoryId) + { + return GetArchive(repositoryId, ArchiveFormat.Tarball); + } + /// /// Get an archive of a given repository's contents, in a specific format /// @@ -67,12 +101,25 @@ namespace Octokit.Reactive /// The owner of the repository /// The name of the repository /// The format of the archive. Can be either tarball or zipball - /// A promise, containing the binary contents of the archive public IObservable GetArchive(string owner, string name, ArchiveFormat archiveFormat) { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + return GetArchive(owner, name, archiveFormat, string.Empty); } + /// + /// Get an archive of a given repository's contents, in a specific format + /// + /// https://developer.github.com/v3/repos/contents/#get-archive-link + /// The ID of the repository + /// The format of the archive. Can be either tarball or zipball + public IObservable GetArchive(int repositoryId, ArchiveFormat archiveFormat) + { + return GetArchive(repositoryId, archiveFormat, string.Empty); + } + /// /// Get an archive of a given repository's contents, using a specific format and reference /// @@ -81,12 +128,64 @@ namespace Octokit.Reactive /// The name of the repository /// The format of the archive. Can be either tarball or zipball /// A valid Git reference. - /// A promise, containing the binary contents of the archive public IObservable GetArchive(string owner, string name, ArchiveFormat archiveFormat, string reference) { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(reference, "reference"); + return GetArchive(owner, name, archiveFormat, reference, TimeSpan.FromMinutes(60)); } + /// + /// Get an archive of a given repository's contents, using a specific format and reference + /// + /// https://developer.github.com/v3/repos/contents/#get-archive-link + /// The ID of the repository + /// The format of the archive. Can be either tarball or zipball + /// A valid Git reference. + public IObservable GetArchive(int repositoryId, ArchiveFormat archiveFormat, string reference) + { + Ensure.ArgumentNotNull(reference, "reference"); + + return GetArchive(repositoryId, archiveFormat, reference, TimeSpan.FromMinutes(60)); + } + + /// + /// Get an archive of a given repository's contents, in a specific format + /// + /// https://developer.github.com/v3/repos/contents/#get-archive-link + /// The owner of the repository + /// The name of the repository + /// The format of the archive. Can be either tarball or zipball + /// A valid Git reference. + /// Time span until timeout + public IObservable GetArchive(string owner, string name, ArchiveFormat archiveFormat, string reference, TimeSpan timeout) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(reference, "reference"); + Ensure.GreaterThanZero(timeout, "timeout"); + + return _client.Repository.Content.GetArchive(owner, name, archiveFormat, reference, timeout).ToObservable(); + } + + /// + /// Get an archive of a given repository's contents, in a specific format + /// + /// https://developer.github.com/v3/repos/contents/#get-archive-link + /// The ID of the repository + /// The format of the archive. Can be either tarball or zipball + /// A valid Git reference. + /// Time span until timeout + public IObservable GetArchive(int repositoryId, ArchiveFormat archiveFormat, string reference, TimeSpan timeout) + { + Ensure.GreaterThanZero(timeout, "timeout"); + Ensure.ArgumentNotNull(reference, "reference"); + + return _client.Repository.Content.GetArchive(repositoryId, archiveFormat, reference, timeout).ToObservable(); + } + /// /// Returns the contents of a file or directory in a repository. /// @@ -96,9 +195,6 @@ namespace Octokit.Reactive /// The owner of the repository /// The name of the repository /// The content path - /// - /// A collection of representing the content at the specified path - /// public IObservable GetAllContents(string owner, string name, string path) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); @@ -111,22 +207,20 @@ namespace Octokit.Reactive } /// - /// Get an archive of a given repository's contents, in a specific format + /// Returns the contents of a file or directory in a repository. /// - /// https://developer.github.com/v3/repos/contents/#get-archive-link - /// The owner of the repository - /// The name of the repository - /// The format of the archive. Can be either tarball or zipball - /// A valid Git reference. - /// Time span until timeout - /// The binary contents of the archive - public IObservable GetArchive(string owner, string name, ArchiveFormat archiveFormat, string reference, TimeSpan timeout) + /// + /// If given a path to a single file, this method returns a collection containing only that file. + /// + /// The ID of the repository + /// The content path + public IObservable GetAllContents(int repositoryId, string path) { - Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); - Ensure.ArgumentNotNullOrEmptyString(name, "name"); - Ensure.GreaterThanZero(timeout, "timeout"); + Ensure.ArgumentNotNullOrEmptyString(path, "path"); - return _client.Repository.Content.GetArchive(owner, name, archiveFormat, reference, timeout).ToObservable(); + return _client + .Connection + .GetAndFlattenAllPages(ApiUrls.RepositoryContent(repositoryId, path)); } /// @@ -134,9 +228,6 @@ namespace Octokit.Reactive /// /// The owner of the repository /// The name of the repository - /// - /// A collection of representing the content at the specified path - /// public IObservable GetAllContents(string owner, string name) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); @@ -147,6 +238,17 @@ namespace Octokit.Reactive .GetAndFlattenAllPages(ApiUrls.RepositoryContent(owner, name, string.Empty)); } + /// + /// Returns the contents of the root directory in a repository. + /// + /// The ID of the repository + public IObservable GetAllContents(int repositoryId) + { + return _client + .Connection + .GetAndFlattenAllPages(ApiUrls.RepositoryContent(repositoryId, string.Empty)); + } + /// /// Returns the contents of a file or directory in a repository. /// @@ -158,9 +260,6 @@ namespace Octokit.Reactive /// The name of the repository /// The name of the commit/branch/tag. Default: the repository’s default branch (usually master) /// The content path - /// - /// A collection of representing the content at the specified path - /// public IObservable GetAllContentsByRef(string owner, string name, string reference, string path) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); @@ -171,15 +270,30 @@ namespace Octokit.Reactive return _client.Connection.GetAndFlattenAllPages(ApiUrls.RepositoryContent(owner, name, path, reference)); } + /// + /// 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. + /// See the API documentation for more information. + /// + /// The ID of the repository + /// The name of the commit/branch/tag. Default: the repository’s default branch (usually master) + /// The content path + public IObservable GetAllContentsByRef(int repositoryId, string reference, string path) + { + Ensure.ArgumentNotNullOrEmptyString(reference, "reference"); + Ensure.ArgumentNotNullOrEmptyString(path, "path"); + + return _client.Connection.GetAndFlattenAllPages(ApiUrls.RepositoryContent(repositoryId, path, reference)); + } + /// /// Returns the contents of the home directory in a repository. /// /// The owner of the repository /// The name of the repository /// The name of the commit/branch/tag. Default: the repository’s default branch (usually master) - /// - /// A collection of representing the content at the specified path - /// public IObservable GetAllContentsByRef(string owner, string name, string reference) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); @@ -189,6 +303,18 @@ namespace Octokit.Reactive return _client.Connection.GetAndFlattenAllPages(ApiUrls.RepositoryContent(owner, name, string.Empty, reference)); } + /// + /// Returns the contents of the home directory in a repository. + /// + /// The ID of the repository + /// The name of the commit/branch/tag. Default: the repository’s default branch (usually master) + public IObservable GetAllContentsByRef(int repositoryId, string reference) + { + Ensure.ArgumentNotNullOrEmptyString(reference, "reference"); + + return _client.Connection.GetAndFlattenAllPages(ApiUrls.RepositoryContent(repositoryId, string.Empty, reference)); + } + /// /// Creates a commit that creates a new file in a repository. /// @@ -196,7 +322,6 @@ namespace Octokit.Reactive /// The name of the repository /// The path to the file /// Information about the file to create - /// public IObservable CreateFile(string owner, string name, string path, CreateFileRequest request) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); @@ -207,6 +332,20 @@ namespace Octokit.Reactive return _client.Repository.Content.CreateFile(owner, name, path, request).ToObservable(); } + /// + /// Creates a commit that creates a new file in a repository. + /// + /// The ID of the repository + /// The path to the file + /// Information about the file to create + public IObservable CreateFile(int repositoryId, string path, CreateFileRequest request) + { + Ensure.ArgumentNotNullOrEmptyString(path, "path"); + Ensure.ArgumentNotNull(request, "request"); + + return _client.Repository.Content.CreateFile(repositoryId, path, request).ToObservable(); + } + /// /// Creates a commit that updates the contents of a file in a repository. /// @@ -214,7 +353,6 @@ namespace Octokit.Reactive /// The name of the repository /// The path to the file /// Information about the file to update - /// The updated content public IObservable UpdateFile(string owner, string name, string path, UpdateFileRequest request) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); @@ -225,7 +363,28 @@ namespace Octokit.Reactive return _client.Repository.Content.UpdateFile(owner, name, path, request).ToObservable(); } - public IObservable DeleteFile(string owner, string name, string path, DeleteFileRequest request) + /// + /// Creates a commit that updates the contents of a file in a repository. + /// + /// The ID of the repository + /// The path to the file + /// Information about the file to update + public IObservable UpdateFile(int repositoryId, string path, UpdateFileRequest request) + { + Ensure.ArgumentNotNullOrEmptyString(path, "path"); + Ensure.ArgumentNotNull(request, "request"); + + return _client.Repository.Content.UpdateFile(repositoryId, path, request).ToObservable(); + } + + /// + /// Creates a commit that deletes a file in a repository. + /// + /// The owner of the repository + /// The name of the repository + /// The path to the file + /// Information about the file to delete + public IObservable DeleteFile(string owner, string name, string path, DeleteFileRequest request) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); Ensure.ArgumentNotNullOrEmptyString(name, "name"); @@ -234,5 +393,19 @@ namespace Octokit.Reactive return _client.Repository.Content.DeleteFile(owner, name, path, request).ToObservable(); } + + /// + /// Creates a commit that deletes a file in a repository. + /// + /// The ID of the repository + /// The path to the file + /// Information about the file to delete + public IObservable DeleteFile(int repositoryId, string path, DeleteFileRequest request) + { + Ensure.ArgumentNotNullOrEmptyString(path, "path"); + Ensure.ArgumentNotNull(request, "request"); + + return _client.Repository.Content.DeleteFile(repositoryId, path, request).ToObservable(); + } } } diff --git a/Octokit.Tests.Integration/Clients/RepositoryContentsClientTests.cs b/Octokit.Tests.Integration/Clients/RepositoryContentsClientTests.cs index 91a7716f..2cc8cf70 100644 --- a/Octokit.Tests.Integration/Clients/RepositoryContentsClientTests.cs +++ b/Octokit.Tests.Integration/Clients/RepositoryContentsClientTests.cs @@ -23,6 +23,19 @@ namespace Octokit.Tests.Integration.Clients Assert.Contains("Octokit - GitHub API Client Library for .NET", readMeHtml); } + [IntegrationTest] + public async Task ReturnsReadmeForSeeGitWithRepositoryId() + { + var github = Helper.GetAuthenticatedClient(); + + var readme = await github.Repository.Content.GetReadme(7528679); + Assert.Equal("README.md", readme.Name); + string readMeHtml = await readme.GetHtmlContent(); + Assert.True(readMeHtml.StartsWith("
2); Assert.Equal(ContentType.Dir, contents.First().Type); } + + [IntegrationTest] + public async Task GetsDirectoryContentWithRepositoryId() + { + var github = Helper.GetAuthenticatedClient(); + + var contents = await github + .Repository + .Content + .GetAllContents(7528679, "Octokit"); + + Assert.True(contents.Count > 2); + Assert.Equal(ContentType.Dir, contents.First().Type); + } + + [IntegrationTest] + public async Task GetsFileContentWholeRepo() + { + var github = Helper.GetAuthenticatedClient(); + + var contents = await github + .Repository + .Content + .GetAllContents("octocat", "Spoon-Knife"); + + Assert.Equal(3, contents.Count); + Assert.Equal(ContentType.File, contents.First().Type); + Assert.Equal(new Uri("https://github.com/octocat/Spoon-Knife/blob/master/README.md"), contents.First().HtmlUrl); + } + + [IntegrationTest] + public async Task GetsFileContentWholeRepoWithRepositoryId() + { + var github = Helper.GetAuthenticatedClient(); + + var contents = await github + .Repository + .Content + .GetAllContents(1300192); + + Assert.Equal(3, contents.Count); + Assert.Equal(ContentType.File, contents.First().Type); + Assert.Equal(new Uri("https://github.com/octocat/Spoon-Knife/blob/master/README.md"), contents.First().HtmlUrl); + } + + [IntegrationTest] + public async Task GetsDirectoryContentWholeRepo() + { + var github = Helper.GetAuthenticatedClient(); + + var contents = await github + .Repository + .Content + .GetAllContents("octocat", "octocat.github.io"); + + Assert.NotEmpty(contents); + } + + [IntegrationTest] + public async Task GetsDirectoryContentWholeRepoWithRepositoryId() + { + var github = Helper.GetAuthenticatedClient(); + + var contents = await github + .Repository + .Content + .GetAllContents(17881631); + + Assert.NotEmpty(contents); + } + } + + public class TheGetContentsByRefMethod + { + [IntegrationTest] + public async Task GetsFileContent() + { + var github = Helper.GetAuthenticatedClient(); + + var contents = await github + .Repository + .Content + .GetAllContentsByRef("octokit", "octokit.net", "Octokit.Reactive/ObservableGitHubClient.cs", "master"); + + 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 GetsFileContentWithRepositoryId() + { + var github = Helper.GetAuthenticatedClient(); + + var contents = await github + .Repository + .Content + .GetAllContentsByRef(7528679, "Octokit.Reactive/ObservableGitHubClient.cs", "master"); + + 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 = Helper.GetAuthenticatedClient(); + + var contents = await github + .Repository + .Content + .GetAllContentsByRef("octokit", "octokit.net", "Octokit", "master"); + + Assert.True(contents.Count > 2); + Assert.Equal(ContentType.Dir, contents.First().Type); + } + + [IntegrationTest] + public async Task GetsDirectoryContentWithRepositoryId() + { + var github = Helper.GetAuthenticatedClient(); + + var contents = await github + .Repository + .Content + .GetAllContentsByRef(7528679, "Octokit", "master"); + + Assert.True(contents.Count > 2); + Assert.Equal(ContentType.Dir, contents.First().Type); + } + + [IntegrationTest] + public async Task GetsFileContentWholeRepo() + { + var github = Helper.GetAuthenticatedClient(); + + var contents = await github + .Repository + .Content + .GetAllContentsByRef("octocat", "Spoon-Knife", "master"); + + Assert.Equal(3, contents.Count); + Assert.Equal(ContentType.File, contents.First().Type); + Assert.Equal(new Uri("https://github.com/octocat/Spoon-Knife/blob/master/README.md"), contents.First().HtmlUrl); + } + + [IntegrationTest] + public async Task GetsFileContentWholeRepoWithRepositoryId() + { + var github = Helper.GetAuthenticatedClient(); + + var contents = await github + .Repository + .Content + .GetAllContentsByRef(1300192, "master"); + + Assert.Equal(3, contents.Count); + Assert.Equal(ContentType.File, contents.First().Type); + Assert.Equal(new Uri("https://github.com/octocat/Spoon-Knife/blob/master/README.md"), contents.First().HtmlUrl); + } + + [IntegrationTest] + public async Task GetsDirectoryContentWholeRepo() + { + var github = Helper.GetAuthenticatedClient(); + + var contents = await github + .Repository + .Content + .GetAllContentsByRef("octocat", "octocat.github.io", "master"); + + Assert.NotEmpty(contents); + } + + [IntegrationTest] + public async Task GetsDirectoryContentWholeRepoWithRepositoryId() + { + var github = Helper.GetAuthenticatedClient(); + + var contents = await github + .Repository + .Content + .GetAllContentsByRef(17881631, "master"); + + Assert.NotEmpty(contents); + } } [IntegrationTest] @@ -111,6 +337,47 @@ namespace Octokit.Tests.Integration.Clients } } + [IntegrationTest] + public async Task CrudTestWithRepositoryId() + { + var client = Helper.GetAuthenticatedClient(); + var fixture = client.Repository.Content; + var repoName = Helper.MakeNameWithTimestamp("source-repo"); + + using (var context = await client.CreateRepositoryContext(new NewRepository(repoName) { AutoInit = true })) + { + var repository = context.Repository; + + var file = await fixture.CreateFile( + repository.Id, + "somefile.txt", + new CreateFileRequest("Test commit", "Some Content")); + Assert.Equal("somefile.txt", file.Content.Name); + + var contents = await fixture.GetAllContents(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.Id, + "somefile.txt", + new UpdateFileRequest("Updating file", "New Content", fileSha)); + Assert.Equal("somefile.txt", update.Content.Name); + + contents = await fixture.GetAllContents(repository.Owner.Login, repository.Name, "somefile.txt"); + Assert.Equal("New Content", contents.First().Content); + fileSha = contents.First().Sha; + + await fixture.DeleteFile( + repository.Id, + "somefile.txt", + new DeleteFileRequest("Deleted file", fileSha)); + + await Assert.ThrowsAsync( + () => fixture.GetAllContents(repository.Owner.Login, repository.Name, "somefile.txt")); + } + } + [IntegrationTest] public async Task CrudTestWithNamedBranch() { @@ -158,43 +425,155 @@ namespace Octokit.Tests.Integration.Clients } } - [IntegrationTest(Skip = "this will probably take too long")] - public async Task GetsArchiveAsTarball() + [IntegrationTest] + public async Task CrudTestWithNamedBranchWithRepositoryId() { - var github = Helper.GetAuthenticatedClient(); + var client = Helper.GetAuthenticatedClient(); + var fixture = client.Repository.Content; + var repoName = Helper.MakeNameWithTimestamp("source-repo"); + var branchName = "other-branch"; - var archive = await github - .Repository - .Content - .GetArchive("octokit", "octokit.net"); + using (var context = await client.CreateRepositoryContext(new NewRepository(repoName) { AutoInit = true })) + { + var repository = context.Repository; - Assert.NotEmpty(archive); + var master = await client.Git.Reference.Get(Helper.UserName, repository.Name, "heads/master"); + await client.Git.Reference.Create(Helper.UserName, repository.Name, new NewReference("refs/heads/" + branchName, master.Object.Sha)); + var file = await fixture.CreateFile( + repository.Id, + "somefile.txt", + new CreateFileRequest("Test commit", "Some Content", branchName)); + Assert.Equal("somefile.txt", file.Content.Name); + + var contents = await fixture.GetAllContentsByRef(repository.Owner.Login, repository.Name, "somefile.txt", branchName); + string fileSha = contents.First().Sha; + Assert.Equal("Some Content", contents.First().Content); + + var update = await fixture.UpdateFile( + repository.Id, + "somefile.txt", + new UpdateFileRequest("Updating file", "New Content", fileSha, branchName)); + Assert.Equal("somefile.txt", update.Content.Name); + + contents = await fixture.GetAllContentsByRef(repository.Owner.Login, repository.Name, "somefile.txt", branchName); + Assert.Equal("New Content", contents.First().Content); + fileSha = contents.First().Sha; + + await fixture.DeleteFile( + repository.Id, + "somefile.txt", + new DeleteFileRequest("Deleted file", fileSha, branchName)); + + await Assert.ThrowsAsync( + () => fixture.GetAllContents(repository.Owner.Login, repository.Name, "somefile.txt")); + } } - [IntegrationTest] - public async Task GetsArchiveAsZipball() + public class TheGetArchiveMethod { - var github = Helper.GetAuthenticatedClient(); + [IntegrationTest(Skip = "this will probably take too long")] + public async Task GetsArchiveAsTarball() + { + var github = Helper.GetAuthenticatedClient(); - var archive = await github - .Repository - .Content - .GetArchive("shiftkey", "reactivegit", ArchiveFormat.Zipball); + var archive = await github + .Repository + .Content + .GetArchive("octokit", "octokit.net"); - Assert.NotEmpty(archive); - } + Assert.NotEmpty(archive); + } - [IntegrationTest] - public async Task GetsArchiveForReleaseBranchAsTarball() - { - var github = Helper.GetAuthenticatedClient(); + [IntegrationTest] + public async Task GetsArchiveAsTarballWithRepositoryId() + { + var github = Helper.GetAuthenticatedClient(); - var archive = await github - .Repository - .Content - .GetArchive("alfhenrik", "ScriptCs.OctoKit", ArchiveFormat.Tarball, "master"); + var archive = await github + .Repository + .Content + .GetArchive(1296269); // octocat/Hello-World repo - Assert.NotEmpty(archive); + Assert.NotEmpty(archive); + } + + [IntegrationTest] + public async Task GetsArchiveAsZipball() + { + var github = Helper.GetAuthenticatedClient(); + + var archive = await github + .Repository + .Content + .GetArchive("octocat", "Hello-World", ArchiveFormat.Zipball); + + Assert.NotEmpty(archive); + } + + [IntegrationTest] + public async Task GetsArchiveAsZipballWithRepositoryId() + { + var github = Helper.GetAuthenticatedClient(); + + var archive = await github + .Repository + .Content + .GetArchive(1296269, ArchiveFormat.Zipball); // octocat/Hello-World repo + + Assert.NotEmpty(archive); + } + + [IntegrationTest] + public async Task GetsArchiveForReleaseBranchAsTarball() + { + var github = Helper.GetAuthenticatedClient(); + + var archive = await github + .Repository + .Content + .GetArchive("octocat", "Hello-World", ArchiveFormat.Tarball, "master"); + + Assert.NotEmpty(archive); + } + + [IntegrationTest] + public async Task GetsArchiveForReleaseBranchAsTarballWithRepositoryId() + { + var github = Helper.GetAuthenticatedClient(); + + var archive = await github + .Repository + .Content + .GetArchive(1296269, ArchiveFormat.Tarball, "master"); // octocat/Hello-World repo + + Assert.NotEmpty(archive); + } + + [IntegrationTest] + public async Task GetsArchiveForReleaseBranchAsTarballWithTimeout() + { + var github = Helper.GetAuthenticatedClient(); + + var archive = await github + .Repository + .Content + .GetArchive("octocat", "Hello-World", ArchiveFormat.Tarball, "master", TimeSpan.FromMinutes(60)); + + Assert.NotEmpty(archive); + } + + [IntegrationTest] + public async Task GetsArchiveForReleaseBranchAsTarballWithTimeoutWithRepositoryId() + { + var github = Helper.GetAuthenticatedClient(); + + var archive = await github + .Repository + .Content + .GetArchive(1296269, ArchiveFormat.Tarball, "master", TimeSpan.FromMinutes(60)); // octocat/Hello-World repo + + Assert.NotEmpty(archive); + } } } } \ No newline at end of file diff --git a/Octokit.Tests/Clients/RepositoryContentsClientTests.cs b/Octokit.Tests/Clients/RepositoryContentsClientTests.cs index 11648733..f04ca7da 100644 --- a/Octokit.Tests/Clients/RepositoryContentsClientTests.cs +++ b/Octokit.Tests/Clients/RepositoryContentsClientTests.cs @@ -47,6 +47,46 @@ namespace Octokit.Tests.Clients Assert.Equal("README", htmlReadme); connection.Received().GetHtml(Arg.Is(u => u.ToString() == "https://github.example.com/readme.md"), null); } + + [Fact] + public async Task ReturnsReadmeWithRepositoryId() + { + string encodedContent = Convert.ToBase64String(Encoding.UTF8.GetBytes("Hello world")); + var readmeInfo = new ReadmeResponse( + encodedContent, + "README.md", + "https://github.example.com/readme", + "https://github.example.com/readme.md", + "base64"); + var connection = Substitute.For(); + connection.Get(Args.Uri, null).Returns(Task.FromResult(readmeInfo)); + connection.GetHtml(Args.Uri, null).Returns(Task.FromResult("README")); + var contentsClient = new RepositoryContentsClient(connection); + + var readme = await contentsClient.GetReadme(1); + + Assert.Equal("README.md", readme.Name); + connection.Received().Get(Arg.Is(u => u.ToString() == "repositories/1/readme"), + null); + connection.DidNotReceive().GetHtml(Arg.Is(u => u.ToString() == "https://github.example.com/readme"), + null); + var htmlReadme = await readme.GetHtmlContent(); + Assert.Equal("README", htmlReadme); + connection.Received().GetHtml(Arg.Is(u => u.ToString() == "https://github.example.com/readme.md"), null); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + await Assert.ThrowsAsync(() => client.GetReadme(null, "name")); + await Assert.ThrowsAsync(() => client.GetReadme("owner", null)); + + await Assert.ThrowsAsync(() => client.GetReadme("", "name")); + await Assert.ThrowsAsync(() => client.GetReadme("owner", "")); + } } public class TheGetReadmeHtmlMethod @@ -63,14 +103,126 @@ namespace Octokit.Tests.Clients connection.Received().GetHtml(Arg.Is(u => u.ToString() == "repos/fake/repo/readme"), null); Assert.Equal("README", readme); } + + [Fact] + public async Task ReturnsReadmeHtmlWithRepositoryId() + { + var connection = Substitute.For(); + connection.GetHtml(Args.Uri, null).Returns(Task.FromResult("README")); + var contentsClient = new RepositoryContentsClient(connection); + + var readme = await contentsClient.GetReadmeHtml(1); + + connection.Received().GetHtml(Arg.Is(u => u.ToString() == "repositories/1/readme"), null); + Assert.Equal("README", readme); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + await Assert.ThrowsAsync(() => client.GetReadmeHtml(null, "name")); + await Assert.ThrowsAsync(() => client.GetReadmeHtml("owner", null)); + + await Assert.ThrowsAsync(() => client.GetReadmeHtml("", "name")); + await Assert.ThrowsAsync(() => client.GetReadmeHtml("owner", "")); + } } public class TheGetContentsMethod + { + [Fact] + public async Task ReturnsContents() + { + var result = new List { new RepositoryContent() }; + + var connection = Substitute.For(); + connection.GetAll(Args.Uri).Returns(Task.FromResult(result.AsReadOnly() as IReadOnlyList)); + var contentsClient = new RepositoryContentsClient(connection); + + var contents = await contentsClient.GetAllContents("fake", "repo", "readme.md"); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/contents/readme.md")); + Assert.Equal(1, contents.Count); + } + + [Fact] + public async Task ReturnsContentsWithRepositoryId() + { + var result = new List { new RepositoryContent() }; + + var connection = Substitute.For(); + connection.GetAll(Args.Uri).Returns(Task.FromResult(result.AsReadOnly() as IReadOnlyList)); + var contentsClient = new RepositoryContentsClient(connection); + + var contents = await contentsClient.GetAllContents(1, "readme.md"); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "repositories/1/contents/readme.md")); + Assert.Equal(1, contents.Count); + } + + [Fact] + public async Task ReturnsAllContents() + { + var result = new List { new RepositoryContent() }; + + var connection = Substitute.For(); + connection.GetAll(Args.Uri).Returns(Task.FromResult(result.AsReadOnly() as IReadOnlyList)); + var contentsClient = new RepositoryContentsClient(connection); + + var contents = await contentsClient.GetAllContents("fake", "repo"); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/contents/")); + Assert.Equal(1, contents.Count); + } + + [Fact] + public async Task ReturnsAllContentsWithRepositoryId() + { + var result = new List { new RepositoryContent() }; + + var connection = Substitute.For(); + connection.GetAll(Args.Uri).Returns(Task.FromResult(result.AsReadOnly() as IReadOnlyList)); + var contentsClient = new RepositoryContentsClient(connection); + + var contents = await contentsClient.GetAllContents(1); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "repositories/1/contents/")); + Assert.Equal(1, contents.Count); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + await Assert.ThrowsAsync(() => client.GetAllContents(null, "name")); + await Assert.ThrowsAsync(() => client.GetAllContents("owner", null)); + await Assert.ThrowsAsync(() => client.GetAllContents(null, "name", "path")); + await Assert.ThrowsAsync(() => client.GetAllContents("owner", null, "path")); + await Assert.ThrowsAsync(() => client.GetAllContents("owner", "name", null)); + + await Assert.ThrowsAsync(() => client.GetAllContents(1, null)); + + await Assert.ThrowsAsync(() => client.GetAllContents("", "name")); + await Assert.ThrowsAsync(() => client.GetAllContents("owner", "")); + await Assert.ThrowsAsync(() => client.GetAllContents("", "name", "path")); + await Assert.ThrowsAsync(() => client.GetAllContents("owner", "", "path")); + await Assert.ThrowsAsync(() => client.GetAllContents("owner", "name", "")); + + await Assert.ThrowsAsync(() => client.GetAllContents(1, "")); + } + } + + public class TheGetContentsByRefMethod { [Fact] public async Task ReturnsContentsByRef() { - List result = new List { new RepositoryContent() }; + var result = new List { new RepositoryContent() }; var connection = Substitute.For(); connection.GetAll(Args.Uri).Returns(Task.FromResult(result.AsReadOnly() as IReadOnlyList)); @@ -82,44 +234,132 @@ namespace Octokit.Tests.Clients Assert.Equal(1, contents.Count); } - [Fact] - public async Task ReturnsContents() + public async Task ReturnsContentsByRefWithRepositoryId() { - List result = new List { new RepositoryContent() }; + var result = new List { new RepositoryContent() }; var connection = Substitute.For(); connection.GetAll(Args.Uri).Returns(Task.FromResult(result.AsReadOnly() as IReadOnlyList)); var contentsClient = new RepositoryContentsClient(connection); - var contents = await contentsClient.GetAllContents("fake", "repo", "readme.md"); + var contents = await contentsClient.GetAllContentsByRef(1, "readme.md", "master"); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/contents/readme.md")); + connection.Received().GetAll(Arg.Is(u => u.ToString() == "repositories/1/contents/readme.md?ref=master")); Assert.Equal(1, contents.Count); } + + [Fact] + public async Task ReturnsAllContentsByRef() + { + var result = new List { new RepositoryContent() }; + + var connection = Substitute.For(); + connection.GetAll(Args.Uri).Returns(Task.FromResult(result.AsReadOnly() as IReadOnlyList)); + var contentsClient = new RepositoryContentsClient(connection); + + var contents = await contentsClient.GetAllContentsByRef("fake", "repo", "master"); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/contents/?ref=master")); + Assert.Equal(1, contents.Count); + } + + [Fact] + public async Task ReturnsAllContentsByRefWithRepositoryId() + { + var result = new List { new RepositoryContent() }; + + var connection = Substitute.For(); + connection.GetAll(Args.Uri).Returns(Task.FromResult(result.AsReadOnly() as IReadOnlyList)); + var contentsClient = new RepositoryContentsClient(connection); + + var contents = await contentsClient.GetAllContentsByRef(1, "master"); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "repositories/1/contents/?ref=master")); + Assert.Equal(1, contents.Count); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + await Assert.ThrowsAsync(() => client.GetAllContentsByRef(null, "name", "ref")); + await Assert.ThrowsAsync(() => client.GetAllContentsByRef("owner", null, "ref")); + await Assert.ThrowsAsync(() => client.GetAllContentsByRef("owner", "name", null)); + await Assert.ThrowsAsync(() => client.GetAllContentsByRef(null, "name", "path", "reference")); + await Assert.ThrowsAsync(() => client.GetAllContentsByRef("owner", null, "path", "reference")); + await Assert.ThrowsAsync(() => client.GetAllContentsByRef("owner", "name", null, "reference")); + await Assert.ThrowsAsync(() => client.GetAllContentsByRef("owner", "name", "path", null)); + + await Assert.ThrowsAsync(() => client.GetAllContentsByRef(1, null, "reference")); + await Assert.ThrowsAsync(() => client.GetAllContentsByRef(1, "path", null)); + await Assert.ThrowsAsync(() => client.GetAllContentsByRef(1, null)); + + await Assert.ThrowsAsync(() => client.GetAllContentsByRef("", "name", "ref")); + await Assert.ThrowsAsync(() => client.GetAllContentsByRef("owner", "", "ref")); + await Assert.ThrowsAsync(() => client.GetAllContentsByRef("owner", "name", "")); + await Assert.ThrowsAsync(() => client.GetAllContentsByRef("", "name", "path", "reference")); + await Assert.ThrowsAsync(() => client.GetAllContentsByRef("owner", "", "path", "reference")); + await Assert.ThrowsAsync(() => client.GetAllContentsByRef("owner", "name", "", "reference")); + await Assert.ThrowsAsync(() => client.GetAllContentsByRef("owner", "name", "path", "")); + + await Assert.ThrowsAsync(() => client.GetAllContentsByRef(1, "", "reference")); + await Assert.ThrowsAsync(() => client.GetAllContentsByRef(1, "path", "")); + await Assert.ThrowsAsync(() => client.GetAllContentsByRef(1, "")); + } } public class TheCreateFileMethod { [Fact] - public void RequestsCorrectUrl() + public async Task RequestsCorrectUrl() { var connection = Substitute.For(); var client = new RepositoryContentsClient(connection); string expectedUri = "repos/org/repo/contents/path/to/file"; - client.CreateFile("org", "repo", "path/to/file", new CreateFileRequest("message", "myfilecontents", "mybranch")); + await client.CreateFile("org", "repo", "path/to/file", new CreateFileRequest("message", "myfilecontents", "mybranch")); connection.Received().Put(Arg.Is(u => u.ToString() == expectedUri), Arg.Any()); } [Fact] - public void PassesRequestObject() + public async Task RequestsCorrectUrlWithRepositoryId() { var connection = Substitute.For(); var client = new RepositoryContentsClient(connection); - client.CreateFile("org", "repo", "path/to/file", new CreateFileRequest("message", "myfilecontents", "mybranch")); + string expectedUri = "repositories/1/contents/path/to/file"; + await client.CreateFile(1, "path/to/file", new CreateFileRequest("message", "myfilecontents", "mybranch")); + + connection.Received().Put(Arg.Is(u => u.ToString() == expectedUri), Arg.Any()); + } + + [Fact] + public async Task PassesRequestObject() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + await client.CreateFile("org", "repo", "path/to/file", new CreateFileRequest("message", "myfilecontents", "mybranch")); + + connection.Received().Put( + Arg.Any(), + Arg.Is(a => + a.Message == "message" + && a.Content == "myfilecontents" + && a.Branch == "mybranch")); + } + + [Fact] + public async Task PassesRequestObjectWithRepositoryId() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + await client.CreateFile(1, "path/to/file", new CreateFileRequest("message", "myfilecontents", "mybranch")); connection.Received().Put( Arg.Any(), @@ -139,30 +379,67 @@ namespace Octokit.Tests.Clients await Assert.ThrowsAsync(() => client.CreateFile("org", null, "path/to/file", new CreateFileRequest("message", "myfilecontents", "mybranch"))); await Assert.ThrowsAsync(() => client.CreateFile("org", "repo", null, new CreateFileRequest("message", "myfilecontents", "mybranch"))); await Assert.ThrowsAsync(() => client.CreateFile("org", "repo", "path/to/file", null)); + + await Assert.ThrowsAsync(() => client.CreateFile(1, null, new CreateFileRequest("message", "myfilecontents", "mybranch"))); + await Assert.ThrowsAsync(() => client.CreateFile(1, "path/to/file", null)); + + await Assert.ThrowsAsync(() => client.CreateFile("", "repo", "path/to/file", new CreateFileRequest("message", "myfilecontents", "mybranch"))); + await Assert.ThrowsAsync(() => client.CreateFile("org", "", "path/to/file", new CreateFileRequest("message", "myfilecontents", "mybranch"))); + await Assert.ThrowsAsync(() => client.CreateFile("org", "repo", "", new CreateFileRequest("message", "myfilecontents", "mybranch"))); + + await Assert.ThrowsAsync(() => client.CreateFile(1, "", new CreateFileRequest("message", "myfilecontents", "mybranch"))); } } public class TheDeleteFileMethod { [Fact] - public void RequestsCorrectUrl() + public async Task RequestsCorrectUrl() { var connection = Substitute.For(); var client = new RepositoryContentsClient(connection); string expectedUri = "repos/org/repo/contents/path/to/file"; - client.DeleteFile("org", "repo", "path/to/file", new DeleteFileRequest("message", "1234abc", "mybranch")); + await client.DeleteFile("org", "repo", "path/to/file", new DeleteFileRequest("message", "1234abc", "mybranch")); connection.Received().Delete(Arg.Is(u => u.ToString() == expectedUri), Arg.Any()); } [Fact] - public void PassesRequestObject() + public async Task RequestsCorrectUrlWithRepositoryId() { var connection = Substitute.For(); var client = new RepositoryContentsClient(connection); - client.DeleteFile("org", "repo", "path/to/file", new DeleteFileRequest("message", "1234abc", "mybranch")); + string expectedUri = "repositories/1/contents/path/to/file"; + await client.DeleteFile(1, "path/to/file", new DeleteFileRequest("message", "1234abc", "mybranch")); + + connection.Received().Delete(Arg.Is(u => u.ToString() == expectedUri), Arg.Any()); + } + + [Fact] + public async Task PassesRequestObject() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + await client.DeleteFile("org", "repo", "path/to/file", new DeleteFileRequest("message", "1234abc", "mybranch")); + + connection.Received().Delete( + Arg.Any(), + Arg.Is(a => + a.Message == "message" + && a.Sha == "1234abc" + && a.Branch == "mybranch")); + } + + [Fact] + public async Task PassesRequestObjectWithRepositoryId() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + await client.DeleteFile(1, "path/to/file", new DeleteFileRequest("message", "1234abc", "mybranch")); connection.Received().Delete( Arg.Any(), @@ -182,30 +459,68 @@ namespace Octokit.Tests.Clients await Assert.ThrowsAsync(() => client.DeleteFile("org", null, "path/to/file", new DeleteFileRequest("message", "1234abc", "mybranch"))); await Assert.ThrowsAsync(() => client.DeleteFile("org", "repo", null, new DeleteFileRequest("message", "1234abc", "mybranch"))); await Assert.ThrowsAsync(() => client.DeleteFile("org", "repo", "path/to/file", null)); + + await Assert.ThrowsAsync(() => client.DeleteFile(1, null, new DeleteFileRequest("message", "1234abc", "mybranch"))); + await Assert.ThrowsAsync(() => client.DeleteFile(1, "path/to/file", null)); + + await Assert.ThrowsAsync(() => client.DeleteFile("", "repo", "path/to/file", new DeleteFileRequest("message", "1234abc", "mybranch"))); + await Assert.ThrowsAsync(() => client.DeleteFile("org", "", "path/to/file", new DeleteFileRequest("message", "1234abc", "mybranch"))); + await Assert.ThrowsAsync(() => client.DeleteFile("org", "repo", "", new DeleteFileRequest("message", "1234abc", "mybranch"))); + + await Assert.ThrowsAsync(() => client.DeleteFile(1, "", new DeleteFileRequest("message", "1234abc", "mybranch"))); } } public class TheUpdateFileMethod { [Fact] - public void RequestsCorrectUrl() + public async Task RequestsCorrectUrl() { var connection = Substitute.For(); var client = new RepositoryContentsClient(connection); string expectedUri = "repos/org/repo/contents/path/to/file"; - client.UpdateFile("org", "repo", "path/to/file", new UpdateFileRequest("message", "myfilecontents", "1234abc", "mybranch")); + await client.UpdateFile("org", "repo", "path/to/file", new UpdateFileRequest("message", "myfilecontents", "1234abc", "mybranch")); connection.Received().Put(Arg.Is(u => u.ToString() == expectedUri), Arg.Any()); } [Fact] - public void PassesRequestObject() + public async Task RequestsCorrectUrlWithRepositoryId() { var connection = Substitute.For(); var client = new RepositoryContentsClient(connection); - client.UpdateFile("org", "repo", "path/to/file", new UpdateFileRequest("message", "myfilecontents", "1234abc", "mybranch")); + string expectedUri = "repositories/1/contents/path/to/file"; + await client.UpdateFile(1, "path/to/file", new UpdateFileRequest("message", "myfilecontents", "1234abc", "mybranch")); + + connection.Received().Put(Arg.Is(u => u.ToString() == expectedUri), Arg.Any()); + } + + [Fact] + public async Task PassesRequestObject() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + await client.UpdateFile("org", "repo", "path/to/file", new UpdateFileRequest("message", "myfilecontents", "1234abc", "mybranch")); + + connection.Received().Put( + Arg.Any(), + Arg.Is(a => + a.Message == "message" + && a.Content == "myfilecontents" + && a.Sha == "1234abc" + && a.Branch == "mybranch")); + } + + [Fact] + public async Task PassesRequestObjectWithRepositoriesId() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + await client.UpdateFile(1, "path/to/file", new UpdateFileRequest("message", "myfilecontents", "1234abc", "mybranch")); connection.Received().Put( Arg.Any(), @@ -226,24 +541,165 @@ namespace Octokit.Tests.Clients await Assert.ThrowsAsync(() => client.UpdateFile("org", null, "path/to/file", new UpdateFileRequest("message", "myfilecontents", "1234abc", "mybranch"))); await Assert.ThrowsAsync(() => client.UpdateFile("org", "repo", null, new UpdateFileRequest("message", "myfilecontents", "1234abc", "mybranch"))); await Assert.ThrowsAsync(() => client.UpdateFile("org", "repo", "path/to/file", null)); + + await Assert.ThrowsAsync(() => client.UpdateFile(1, null, new UpdateFileRequest("message", "myfilecontents", "1234abc", "mybranch"))); + await Assert.ThrowsAsync(() => client.UpdateFile(1, "path/to/file", null)); + + await Assert.ThrowsAsync(() => client.UpdateFile("", "repo", "path/to/file", new UpdateFileRequest("message", "myfilecontents", "1234abc", "mybranch"))); + await Assert.ThrowsAsync(() => client.UpdateFile("org", "", "path/to/file", new UpdateFileRequest("message", "myfilecontents", "1234abc", "mybranch"))); + await Assert.ThrowsAsync(() => client.UpdateFile("org", "repo", "", new UpdateFileRequest("message", "myfilecontents", "1234abc", "mybranch"))); + + await Assert.ThrowsAsync(() => client.UpdateFile(1, "", new UpdateFileRequest("message", "myfilecontents", "1234abc", "mybranch"))); } } public class TheGetArchiveMethod { [Fact] - public void EnsurePassingCorrectParameters() + public async Task RequestsCorrectUrl1() { var connection = Substitute.For(); var client = new RepositoryContentsClient(connection); - client.GetArchive("org", "repo", ArchiveFormat.Tarball, "dev"); + await client.GetArchive("org", "repo"); - const string expectedUri = "repos/org/repo/tarball/dev"; + const string expectedUri = "repos/org/repo/tarball/"; var expectedTimeSpan = TimeSpan.FromMinutes(60); connection.Connection.Received().Get(Arg.Is(uri => uri.ToString() == expectedUri), Arg.Is(span => span == expectedTimeSpan)); } + + [Fact] + public async Task RequestsCorrectUrl1WithRepositoryId() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + await client.GetArchive(1); + + const string expectedUri = "repositories/1/tarball/"; + var expectedTimeSpan = TimeSpan.FromMinutes(60); + + connection.Connection.Received().Get(Arg.Is(uri => uri.ToString() == expectedUri), Arg.Is(span => span == expectedTimeSpan)); + } + + [Fact] + public async Task RequestsCorrectUrl2() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + await client.GetArchive("org", "repo", ArchiveFormat.Zipball); + + const string expectedUri = "repos/org/repo/zipball/"; + var expectedTimeSpan = TimeSpan.FromMinutes(60); + + connection.Connection.Received().Get(Arg.Is(uri => uri.ToString() == expectedUri), Arg.Is(span => span == expectedTimeSpan)); + } + + [Fact] + public async Task RequestsCorrectUrl2WithRepositoryId() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + await client.GetArchive(1, ArchiveFormat.Zipball); + + const string expectedUri = "repositories/1/zipball/"; + var expectedTimeSpan = TimeSpan.FromMinutes(60); + + connection.Connection.Received().Get(Arg.Is(uri => uri.ToString() == expectedUri), Arg.Is(span => span == expectedTimeSpan)); + } + + [Fact] + public async Task RequestsCorrectUrl3() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + await client.GetArchive("org", "repo", ArchiveFormat.Zipball, "ref"); + + const string expectedUri = "repos/org/repo/zipball/ref"; + var expectedTimeSpan = TimeSpan.FromMinutes(60); + + connection.Connection.Received().Get(Arg.Is(uri => uri.ToString() == expectedUri), Arg.Is(span => span == expectedTimeSpan)); + } + + [Fact] + public async Task RequestsCorrectUrl3WithRepositoryId() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + await client.GetArchive(1, ArchiveFormat.Zipball, "ref"); + + const string expectedUri = "repositories/1/zipball/ref"; + var expectedTimeSpan = TimeSpan.FromMinutes(60); + + connection.Connection.Received().Get(Arg.Is(uri => uri.ToString() == expectedUri), Arg.Is(span => span == expectedTimeSpan)); + } + + [Fact] + public async Task RequestsCorrectUrl4() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + await client.GetArchive("org", "repo", ArchiveFormat.Zipball, "ref", TimeSpan.FromMinutes(60)); + + const string expectedUri = "repos/org/repo/zipball/ref"; + var expectedTimeSpan = TimeSpan.FromMinutes(60); + + connection.Connection.Received().Get(Arg.Is(uri => uri.ToString() == expectedUri), Arg.Is(span => span == expectedTimeSpan)); + } + + [Fact] + public async Task RequestsCorrectUrl4WithRepositoryId() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + await client.GetArchive(1, ArchiveFormat.Zipball, "ref", TimeSpan.FromMinutes(60)); + + const string expectedUri = "repositories/1/zipball/ref"; + var expectedTimeSpan = TimeSpan.FromMinutes(60); + + connection.Connection.Received().Get(Arg.Is(uri => uri.ToString() == expectedUri), Arg.Is(span => span == expectedTimeSpan)); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + await Assert.ThrowsAsync(() => client.GetArchive(null, "repo")); + await Assert.ThrowsAsync(() => client.GetArchive("org", null)); + await Assert.ThrowsAsync(() => client.GetArchive(null, "repo", ArchiveFormat.Tarball)); + await Assert.ThrowsAsync(() => client.GetArchive("org", null, ArchiveFormat.Tarball)); + await Assert.ThrowsAsync(() => client.GetArchive(null, "repo", ArchiveFormat.Tarball, "ref")); + await Assert.ThrowsAsync(() => client.GetArchive("org", null, ArchiveFormat.Tarball, "ref")); + await Assert.ThrowsAsync(() => client.GetArchive("org", "repo", ArchiveFormat.Tarball, null)); + await Assert.ThrowsAsync(() => client.GetArchive(null, "repo", ArchiveFormat.Tarball, "ref", TimeSpan.MaxValue)); + await Assert.ThrowsAsync(() => client.GetArchive("org", null, ArchiveFormat.Tarball, "ref", TimeSpan.MaxValue)); + await Assert.ThrowsAsync(() => client.GetArchive("org", "repo", ArchiveFormat.Tarball, null, TimeSpan.MaxValue)); + + await Assert.ThrowsAsync(() => client.GetArchive(1, ArchiveFormat.Tarball, null)); + await Assert.ThrowsAsync(() => client.GetArchive(1, ArchiveFormat.Tarball, null, TimeSpan.MaxValue)); + + await Assert.ThrowsAsync(() => client.GetArchive("", "repo")); + await Assert.ThrowsAsync(() => client.GetArchive("org", "")); + await Assert.ThrowsAsync(() => client.GetArchive("", "repo", ArchiveFormat.Tarball)); + await Assert.ThrowsAsync(() => client.GetArchive("org", "", ArchiveFormat.Tarball)); + await Assert.ThrowsAsync(() => client.GetArchive("", "repo", ArchiveFormat.Tarball, "ref")); + await Assert.ThrowsAsync(() => client.GetArchive("org", "", ArchiveFormat.Tarball, "ref")); + await Assert.ThrowsAsync(() => client.GetArchive("", "repo", ArchiveFormat.Tarball, "ref", TimeSpan.MaxValue)); + await Assert.ThrowsAsync(() => client.GetArchive("org", "", ArchiveFormat.Tarball, "ref", TimeSpan.MaxValue)); + + await Assert.ThrowsAsync(() => client.GetArchive("org", "repo", ArchiveFormat.Tarball, "ref", TimeSpan.Zero)); + + await Assert.ThrowsAsync(() => client.GetArchive(1, ArchiveFormat.Tarball, "ref", TimeSpan.Zero)); + } } } } \ No newline at end of file diff --git a/Octokit.Tests/Octokit.Tests.csproj b/Octokit.Tests/Octokit.Tests.csproj index 81bf38c1..a2b3eed4 100644 --- a/Octokit.Tests/Octokit.Tests.csproj +++ b/Octokit.Tests/Octokit.Tests.csproj @@ -239,6 +239,7 @@ + diff --git a/Octokit.Tests/Reactive/ObservableRepositoryContentsClientTests.cs b/Octokit.Tests/Reactive/ObservableRepositoryContentsClientTests.cs new file mode 100644 index 00000000..f374f9b0 --- /dev/null +++ b/Octokit.Tests/Reactive/ObservableRepositoryContentsClientTests.cs @@ -0,0 +1,779 @@ +using System; +using System.Collections.Generic; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; +using NSubstitute; +using Octokit.Internal; +using Octokit.Reactive; +using Xunit; + +namespace Octokit.Tests.Reactive +{ + public class ObservableRepositoryContentsClientTests + { + public class TheCtor + { + [Fact] + public void EnsuresNonNullArguments() + { + Assert.Throws( + () => new ObservableRepositoryContentsClient(null)); + } + } + + public class TheGetReadmeMethod + { + [Fact] + public async Task ReturnsReadme() + { + string encodedContent = Convert.ToBase64String(Encoding.UTF8.GetBytes("Hello world")); + var readmeInfo = new ReadmeResponse( + encodedContent, + "README.md", + "https://github.example.com/readme", + "https://github.example.com/readme.md", + "base64"); + + var gitHubClient = Substitute.For(); + var apiConnection = Substitute.For(); + apiConnection.GetHtml(new Uri(readmeInfo.Url)).Returns(Task.FromResult("README")); + var readmeFake = new Readme(readmeInfo, apiConnection); + var contentsClient = new ObservableRepositoryContentsClient(gitHubClient); + + gitHubClient.Repository.Content.GetReadme("fake", "repo").Returns(Task.FromResult(readmeFake)); + + IApiResponse apiResponse = new ApiResponse(new Response(), "README"); + gitHubClient.Connection.GetHtml(Args.Uri, null) + .Returns(Task.FromResult(apiResponse)); + + var readme = await contentsClient.GetReadme("fake", "repo"); + + Assert.Equal("README.md", readme.Name); + + gitHubClient.Repository.Content.Received(1).GetReadme("fake", "repo"); + gitHubClient.Connection.DidNotReceive().GetHtml(Arg.Is(u => u.ToString() == "https://github.example.com/readme"), + Args.EmptyDictionary); + + var htmlReadme = await readme.GetHtmlContent(); + Assert.Equal("README", htmlReadme); + apiConnection.Received().GetHtml(Arg.Is(u => u.ToString() == "https://github.example.com/readme.md"), null); + } + + [Fact] + public async Task ReturnsReadmeWithRepositoryId() + { + string encodedContent = Convert.ToBase64String(Encoding.UTF8.GetBytes("Hello world")); + var readmeInfo = new ReadmeResponse( + encodedContent, + "README.md", + "https://github.example.com/readme", + "https://github.example.com/readme.md", + "base64"); + + var gitHubClient = Substitute.For(); + var apiConnection = Substitute.For(); + apiConnection.GetHtml(new Uri(readmeInfo.Url)).Returns(Task.FromResult("README")); + var readmeFake = new Readme(readmeInfo, apiConnection); + var contentsClient = new ObservableRepositoryContentsClient(gitHubClient); + + gitHubClient.Repository.Content.GetReadme(1).Returns(Task.FromResult(readmeFake)); + + IApiResponse apiResponse = new ApiResponse(new Response(), "README"); + gitHubClient.Connection.GetHtml(Args.Uri, null) + .Returns(Task.FromResult(apiResponse)); + + var readme = await contentsClient.GetReadme(1); + + Assert.Equal("README.md", readme.Name); + + gitHubClient.Repository.Content.Received(1).GetReadme(1); + gitHubClient.Connection.DidNotReceive().GetHtml(Arg.Is(u => u.ToString() == "https://github.example.com/readme"), + Args.EmptyDictionary); + + var htmlReadme = await readme.GetHtmlContent(); + Assert.Equal("README", htmlReadme); + apiConnection.Received().GetHtml(Arg.Is(u => u.ToString() == "https://github.example.com/readme.md"), null); + } + + [Fact] + public void EnsuresNonNullArguments() + { + var gitHubClient = Substitute.For(); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + Assert.Throws(() => client.GetReadme(null, "name")); + Assert.Throws(() => client.GetReadme("owner", null)); + + Assert.Throws(() => client.GetReadme("", "name")); + Assert.Throws(() => client.GetReadme("owner", "")); + } + } + + public class TheGetReadmeHtmlMethod + { + [Fact] + public async Task ReturnsReadmeHtml() + { + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var contentsClient = new ObservableRepositoryContentsClient(gitHubClient); + IApiResponse apiResponse = new ApiResponse(new Response(), "README"); + + connection.GetHtml(Args.Uri, null).Returns(Task.FromResult(apiResponse)); + + var readme = await contentsClient.GetReadmeHtml("fake", "repo"); + + connection.Received().GetHtml(Arg.Is(u => u.ToString() == "repos/fake/repo/readme"), null); + Assert.Equal("README", readme); + } + + [Fact] + public async Task ReturnsReadmeHtmlWithRepositoryId() + { + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var contentsClient = new ObservableRepositoryContentsClient(gitHubClient); + IApiResponse apiResponse = new ApiResponse(new Response(), "README"); + + connection.GetHtml(Args.Uri, null).Returns(Task.FromResult(apiResponse)); + + var readme = await contentsClient.GetReadmeHtml(1); + + connection.Received().GetHtml(Arg.Is(u => u.ToString() == "repositories/1/readme"), null); + Assert.Equal("README", readme); + } + + [Fact] + public void EnsuresNonNullArguments() + { + var gitHubClient = Substitute.For(); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + Assert.Throws(() => client.GetReadmeHtml(null, "name")); + Assert.Throws(() => client.GetReadmeHtml("owner", null)); + + Assert.Throws(() => client.GetReadmeHtml("", "name")); + Assert.Throws(() => client.GetReadmeHtml("owner", "")); + } + } + + public class TheGetContentsMethod + { + [Fact] + public async Task ReturnsContents() + { + var result = new List { new RepositoryContent() }; + + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var contentsClient = new ObservableRepositoryContentsClient(gitHubClient); + IApiResponse> response = new ApiResponse> + ( + new Response { ApiInfo = new ApiInfo(new Dictionary(), new List(), new List(), "etag", new RateLimit()) }, + result + ); + + connection.Get>(Args.Uri, null, null) + .Returns(Task.FromResult(response)); + + var contents = await contentsClient.GetAllContents("fake", "repo").ToList(); + + connection.Received().Get>(Arg.Is(u => u.ToString() == "repos/fake/repo/contents/"), null, null); + Assert.Equal(1, contents.Count); + } + + [Fact] + public async Task ReturnsContentsWithRepositoryId() + { + var result = new List { new RepositoryContent() }; + + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var contentsClient = new ObservableRepositoryContentsClient(gitHubClient); + IApiResponse> response = new ApiResponse> + ( + new Response { ApiInfo = new ApiInfo(new Dictionary(), new List(), new List(), "etag", new RateLimit()) }, + result + ); + + connection.Get>(Args.Uri, null, null) + .Returns(Task.FromResult(response)); + + var contents = await contentsClient.GetAllContents(1).ToList(); + + connection.Received().Get>(Arg.Is(u => u.ToString() == "repositories/1/contents/"), null, null); + Assert.Equal(1, contents.Count); + } + + [Fact] + public async Task ReturnsAllContents() + { + var result = new List { new RepositoryContent() }; + + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var contentsClient = new ObservableRepositoryContentsClient(gitHubClient); + IApiResponse> response = new ApiResponse> + ( + new Response { ApiInfo = new ApiInfo(new Dictionary(), new List(), new List(), "etag", new RateLimit()) }, + result + ); + connection.Get>(Args.Uri, null, null) + .Returns(Task.FromResult(response)); + + var contents = await contentsClient.GetAllContents("fake", "repo").ToList(); + + connection.Received().Get>(Arg.Is(u => u.ToString() == "repos/fake/repo/contents/"), null, null); + Assert.Equal(1, contents.Count); + } + + [Fact] + public async Task ReturnsAllContentsWithRepositoryId() + { + var result = new List { new RepositoryContent() }; + + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var contentsClient = new ObservableRepositoryContentsClient(gitHubClient); + IApiResponse> response = new ApiResponse> + ( + new Response { ApiInfo = new ApiInfo(new Dictionary(), new List(), new List(), "etag", new RateLimit()) }, + result + ); + connection.Get>(Args.Uri, null, null) + .Returns(Task.FromResult(response)); + + var contents = await contentsClient.GetAllContents(1).ToList(); + + connection.Received().Get>(Arg.Is(u => u.ToString() == "repositories/1/contents/"), null, null); + Assert.Equal(1, contents.Count); + } + + [Fact] + public void EnsuresNonNullArguments() + { + var gitHubClient = Substitute.For(); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + Assert.Throws(() => client.GetAllContents(null, "name")); + Assert.Throws(() => client.GetAllContents("owner", null)); + Assert.Throws(() => client.GetAllContents(null, "name", "path")); + Assert.Throws(() => client.GetAllContents("owner", null, "path")); + Assert.Throws(() => client.GetAllContents("owner", "name", null)); + + Assert.Throws(() => client.GetAllContents(1, null)); + + Assert.Throws(() => client.GetAllContents("", "name")); + Assert.Throws(() => client.GetAllContents("owner", "")); + Assert.Throws(() => client.GetAllContents("", "name", "path")); + Assert.Throws(() => client.GetAllContents("owner", "", "path")); + Assert.Throws(() => client.GetAllContents("owner", "name", "")); + + Assert.Throws(() => client.GetAllContents(1, "")); + } + } + + public class TheGetContentsByRefMethod + { + [Fact] + public async Task ReturnsContentsByRef() + { + var result = new List { new RepositoryContent() }; + + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var contentsClient = new ObservableRepositoryContentsClient(gitHubClient); + IApiResponse> response = new ApiResponse> + ( + new Response { ApiInfo = new ApiInfo(new Dictionary(), new List(), new List(), "etag", new RateLimit()) }, + result + ); + connection.Get>(Args.Uri, null, null) + .Returns(Task.FromResult(response)); + + var contents = await contentsClient.GetAllContentsByRef("fake", "repo", "master", "readme.md").ToList(); + + connection.Received().Get>(Arg.Is(u => u.ToString() == "repos/fake/repo/contents/readme.md?ref=master"), null, null); + Assert.Equal(1, contents.Count); + } + + [Fact] + public async Task ReturnsContentsByRefWithRepositoryId() + { + var result = new List { new RepositoryContent() }; + + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var contentsClient = new ObservableRepositoryContentsClient(gitHubClient); + IApiResponse> response = new ApiResponse> + ( + new Response { ApiInfo = new ApiInfo(new Dictionary(), new List(), new List(), "etag", new RateLimit()) }, + result + ); + connection.Get>(Args.Uri, null, null) + .Returns(Task.FromResult(response)); + + var contents = await contentsClient.GetAllContentsByRef(1, "master", "readme.md").ToList(); + + connection.Received().Get>(Arg.Is(u => u.ToString() == "repositories/1/contents/readme.md?ref=master"), null, null); + Assert.Equal(1, contents.Count); + } + + [Fact] + public async Task ReturnsAllContentsByRef() + { + var result = new List { new RepositoryContent() }; + + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var contentsClient = new ObservableRepositoryContentsClient(gitHubClient); + IApiResponse> response = new ApiResponse> + ( + new Response { ApiInfo = new ApiInfo(new Dictionary(), new List(), new List(), "etag", new RateLimit()) }, + result + ); + connection.Get>(Args.Uri, null, null) + .Returns(Task.FromResult(response)); + + var contents = await contentsClient.GetAllContentsByRef("fake", "repo", "master").ToList(); + + connection.Received().Get>(Arg.Is(u => u.ToString() == "repos/fake/repo/contents/?ref=master"), null, null); + Assert.Equal(1, contents.Count); + } + + [Fact] + public async Task ReturnsAllContentsByRefWithRepositoryId() + { + var result = new List { new RepositoryContent() }; + + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var contentsClient = new ObservableRepositoryContentsClient(gitHubClient); + IApiResponse> response = new ApiResponse> + ( + new Response { ApiInfo = new ApiInfo(new Dictionary(), new List(), new List(), "etag", new RateLimit()) }, + result + ); + connection.Get>(Args.Uri, null, null) + .Returns(Task.FromResult(response)); + + var contents = await contentsClient.GetAllContentsByRef(1, "master").ToList(); + + connection.Received().Get>(Arg.Is(u => u.ToString() == "repositories/1/contents/?ref=master"), null, null); + Assert.Equal(1, contents.Count); + } + + [Fact] + public void EnsuresNonNullArguments() + { + var gitHubClient = Substitute.For(); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + Assert.Throws(() => client.GetAllContentsByRef(null, "name", "ref")); + Assert.Throws(() => client.GetAllContentsByRef("owner", null, "ref")); + Assert.Throws(() => client.GetAllContentsByRef("owner", "name", null)); + Assert.Throws(() => client.GetAllContentsByRef(null, "name", "path", "reference")); + Assert.Throws(() => client.GetAllContentsByRef("owner", null, "path", "reference")); + Assert.Throws(() => client.GetAllContentsByRef("owner", "name", null, "reference")); + Assert.Throws(() => client.GetAllContentsByRef("owner", "name", "path", null)); + + Assert.Throws(() => client.GetAllContentsByRef(1, null, "reference")); + Assert.Throws(() => client.GetAllContentsByRef(1, "path", null)); + Assert.Throws(() => client.GetAllContentsByRef(1, null)); + + Assert.Throws(() => client.GetAllContentsByRef("", "name", "ref")); + Assert.Throws(() => client.GetAllContentsByRef("owner", "", "ref")); + Assert.Throws(() => client.GetAllContentsByRef("owner", "name", "")); + Assert.Throws(() => client.GetAllContentsByRef("", "name", "path", "reference")); + Assert.Throws(() => client.GetAllContentsByRef("owner", "", "path", "reference")); + Assert.Throws(() => client.GetAllContentsByRef("owner", "name", "", "reference")); + Assert.Throws(() => client.GetAllContentsByRef("owner", "name", "path", "")); + + Assert.Throws(() => client.GetAllContentsByRef(1, "", "reference")); + Assert.Throws(() => client.GetAllContentsByRef(1, "path", "")); + Assert.Throws(() => client.GetAllContentsByRef(1, "")); + } + } + + public class TheCreateFileMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + string expectedUri = "repos/org/repo/contents/path/to/file"; + client.CreateFile("org", "repo", "path/to/file", new CreateFileRequest("message", "myfilecontents", "mybranch")); + + gitHubClient.Connection.Received().Put(Arg.Is(u => u.ToString() == expectedUri), Arg.Any()); + } + + [Fact] + public void RequestsCorrectUrlWithRepositoryId() + { + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + string expectedUri = "repositories/1/contents/path/to/file"; + client.CreateFile(1, "path/to/file", new CreateFileRequest("message", "myfilecontents", "mybranch")); + + gitHubClient.Connection.Received().Put(Arg.Is(u => u.ToString() == expectedUri), Arg.Any()); + } + + [Fact] + public void PassesRequestObject() + { + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + client.CreateFile("org", "repo", "path/to/file", new CreateFileRequest("message", "myfilecontents", "mybranch")); + + gitHubClient.Connection.Received().Put( + Arg.Any(), + Arg.Is(a => + a.Message == "message" + && a.Content == "myfilecontents" + && a.Branch == "mybranch")); + } + + [Fact] + public void PassesRequestObjectWithRepositoryId() + { + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + client.CreateFile(1, "path/to/file", new CreateFileRequest("message", "myfilecontents", "mybranch")); + + gitHubClient.Connection.Received().Put( + Arg.Any(), + Arg.Is(a => + a.Message == "message" + && a.Content == "myfilecontents" + && a.Branch == "mybranch")); + } + + [Fact] + public void EnsuresNonNullArguments() + { + var gitHubClient = Substitute.For(); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + Assert.Throws(() => client.CreateFile(null, "repo", "path/to/file", new CreateFileRequest("message", "myfilecontents", "mybranch"))); + Assert.Throws(() => client.CreateFile("org", null, "path/to/file", new CreateFileRequest("message", "myfilecontents", "mybranch"))); + Assert.Throws(() => client.CreateFile("org", "repo", null, new CreateFileRequest("message", "myfilecontents", "mybranch"))); + Assert.Throws(() => client.CreateFile("org", "repo", "path/to/file", null)); + + Assert.Throws(() => client.CreateFile(1, null, new CreateFileRequest("message", "myfilecontents", "mybranch"))); + Assert.Throws(() => client.CreateFile(1, "path/to/file", null)); + + Assert.Throws(() => client.CreateFile("", "repo", "path/to/file", new CreateFileRequest("message", "myfilecontents", "mybranch"))); + Assert.Throws(() => client.CreateFile("org", "", "path/to/file", new CreateFileRequest("message", "myfilecontents", "mybranch"))); + Assert.Throws(() => client.CreateFile("org", "repo", "", new CreateFileRequest("message", "myfilecontents", "mybranch"))); + + Assert.Throws(() => client.CreateFile(1, "", new CreateFileRequest("message", "myfilecontents", "mybranch"))); + } + } + + public class TheDeleteFileMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + string expectedUri = "repos/org/repo/contents/path/to/file"; + client.DeleteFile("org", "repo", "path/to/file", new DeleteFileRequest("message", "1234abc", "mybranch")); + + gitHubClient.Connection.Received().Delete(Arg.Is(u => u.ToString() == expectedUri), Arg.Any()); + } + + [Fact] + public void RequestsCorrectUrlWithRepositoryId() + { + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + string expectedUri = "repositories/1/contents/path/to/file"; + client.DeleteFile(1, "path/to/file", new DeleteFileRequest("message", "1234abc", "mybranch")); + + gitHubClient.Connection.Received().Delete(Arg.Is(u => u.ToString() == expectedUri), Arg.Any()); + } + + [Fact] + public void PassesRequestObject() + { + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + client.DeleteFile("org", "repo", "path/to/file", new DeleteFileRequest("message", "1234abc", "mybranch")); + + gitHubClient.Connection.Received().Delete( + Arg.Any(), + Arg.Is(a => + a.Message == "message" + && a.Sha == "1234abc" + && a.Branch == "mybranch")); + } + + [Fact] + public void PassesRequestObjectWithRepositoryId() + { + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + client.DeleteFile(1, "path/to/file", new DeleteFileRequest("message", "1234abc", "mybranch")); + + gitHubClient.Connection.Received().Delete( + Arg.Any(), + Arg.Is(a => + a.Message == "message" + && a.Sha == "1234abc" + && a.Branch == "mybranch")); + } + + [Fact] + public void EnsuresNonNullArguments() + { + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + Assert.Throws(() => client.DeleteFile(null, "repo", "path/to/file", new DeleteFileRequest("message", "1234abc", "mybranch"))); + Assert.Throws(() => client.DeleteFile("org", null, "path/to/file", new DeleteFileRequest("message", "1234abc", "mybranch"))); + Assert.Throws(() => client.DeleteFile("org", "repo", null, new DeleteFileRequest("message", "1234abc", "mybranch"))); + Assert.Throws(() => client.DeleteFile("org", "repo", "path/to/file", null)); + + Assert.Throws(() => client.DeleteFile(1, null, new DeleteFileRequest("message", "1234abc", "mybranch"))); + Assert.Throws(() => client.DeleteFile(1, "path/to/file", null)); + + Assert.Throws(() => client.DeleteFile("", "repo", "path/to/file", new DeleteFileRequest("message", "1234abc", "mybranch"))); + Assert.Throws(() => client.DeleteFile("org", "", "path/to/file", new DeleteFileRequest("message", "1234abc", "mybranch"))); + Assert.Throws(() => client.DeleteFile("org", "repo", "", new DeleteFileRequest("message", "1234abc", "mybranch"))); + + Assert.Throws(() => client.DeleteFile(1, "", new DeleteFileRequest("message", "1234abc", "mybranch"))); + } + } + + public class TheUpdateFileMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + string expectedUri = "repos/org/repo/contents/path/to/file"; + client.UpdateFile("org", "repo", "path/to/file", new UpdateFileRequest("message", "myfilecontents", "1234abc", "mybranch")); + + gitHubClient.Connection.Received().Put(Arg.Is(u => u.ToString() == expectedUri), Arg.Any()); + } + + [Fact] + public void RequestsCorrectUrlWithRepositoryId() + { + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + string expectedUri = "repositories/1/contents/path/to/file"; + client.UpdateFile(1, "path/to/file", new UpdateFileRequest("message", "myfilecontents", "1234abc", "mybranch")); + + gitHubClient.Connection.Received().Put(Arg.Is(u => u.ToString() == expectedUri), Arg.Any()); + } + + [Fact] + public void PassesRequestObject() + { + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + client.UpdateFile("org", "repo", "path/to/file", new UpdateFileRequest("message", "myfilecontents", "1234abc", "mybranch")); + + gitHubClient.Connection.Received().Put( + Arg.Any(), + Arg.Is(a => + a.Message == "message" + && a.Content == "myfilecontents" + && a.Sha == "1234abc" + && a.Branch == "mybranch")); + } + + [Fact] + public void PassesRequestObjectWithRepositoriesId() + { + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + client.UpdateFile(1, "path/to/file", new UpdateFileRequest("message", "myfilecontents", "1234abc", "mybranch")); + + gitHubClient.Connection.Received().Put( + Arg.Any(), + Arg.Is(a => + a.Message == "message" + && a.Content == "myfilecontents" + && a.Sha == "1234abc" + && a.Branch == "mybranch")); + } + + [Fact] + public void EnsuresNonNullArguments() + { + var gitHubClient = Substitute.For(); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + Assert.Throws(() => client.UpdateFile(null, "repo", "path/to/file", new UpdateFileRequest("message", "myfilecontents", "1234abc", "mybranch"))); + Assert.Throws(() => client.UpdateFile("org", null, "path/to/file", new UpdateFileRequest("message", "myfilecontents", "1234abc", "mybranch"))); + Assert.Throws(() => client.UpdateFile("org", "repo", null, new UpdateFileRequest("message", "myfilecontents", "1234abc", "mybranch"))); + Assert.Throws(() => client.UpdateFile("org", "repo", "path/to/file", null)); + + Assert.Throws(() => client.UpdateFile(1, null, new UpdateFileRequest("message", "myfilecontents", "1234abc", "mybranch"))); + Assert.Throws(() => client.UpdateFile(1, "path/to/file", null)); + + Assert.Throws(() => client.UpdateFile("", "repo", "path/to/file", new UpdateFileRequest("message", "myfilecontents", "1234abc", "mybranch"))); + Assert.Throws(() => client.UpdateFile("org", "", "path/to/file", new UpdateFileRequest("message", "myfilecontents", "1234abc", "mybranch"))); + Assert.Throws(() => client.UpdateFile("org", "repo", "", new UpdateFileRequest("message", "myfilecontents", "1234abc", "mybranch"))); + + Assert.Throws(() => client.UpdateFile(1, "", new UpdateFileRequest("message", "myfilecontents", "1234abc", "mybranch"))); + } + } + + public class TheGetArchiveMethod + { + [Fact] + public void RequestsCorrectUrl1() + { + var gitHubClient = Substitute.For(); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + client.GetArchive("org", "repo"); + + gitHubClient.Received().Repository.Content.GetArchive("org", "repo"); + } + + [Fact] + public void RequestsCorrectUrl1WithRepositoryId() + { + var gitHubClient = Substitute.For(); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + client.GetArchive(1); + + gitHubClient.Received().Repository.Content.GetArchive(1); + } + + [Fact] + public void RequestsCorrectUrl2() + { + var gitHubClient = Substitute.For(); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + client.GetArchive("org", "repo", ArchiveFormat.Zipball); + + gitHubClient.Received().Repository.Content.GetArchive("org", "repo", ArchiveFormat.Zipball); + } + + [Fact] + public void RequestsCorrectUrl2WithRepositoryId() + { + var gitHubClient = Substitute.For(); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + client.GetArchive(1, ArchiveFormat.Zipball); + + gitHubClient.Received().Repository.Content.GetArchive(1, ArchiveFormat.Zipball); + } + + [Fact] + public void RequestsCorrectUrl3() + { + var gitHubClient = Substitute.For(); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + client.GetArchive("org", "repo", ArchiveFormat.Zipball, "ref"); + + gitHubClient.Received().Repository.Content.GetArchive("org", "repo", ArchiveFormat.Zipball, "ref"); + } + + [Fact] + public void RequestsCorrectUrl3WithRepositoryId() + { + var gitHubClient = Substitute.For(); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + client.GetArchive(1, ArchiveFormat.Zipball, "ref"); + + gitHubClient.Received().Repository.Content.GetArchive(1, ArchiveFormat.Zipball, "ref"); + } + + [Fact] + public void RequestsCorrectUrl4() + { + var gitHubClient = Substitute.For(); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + client.GetArchive("org", "repo", ArchiveFormat.Zipball, "ref", TimeSpan.FromMinutes(60)); + + gitHubClient.Received().Repository.Content.GetArchive("org", "repo", ArchiveFormat.Zipball, "ref", TimeSpan.FromMinutes(60)); + } + + [Fact] + public void RequestsCorrectUrl4WithRepositoryId() + { + var gitHubClient = Substitute.For(); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + client.GetArchive(1, ArchiveFormat.Zipball, "ref", TimeSpan.FromMinutes(60)); + + gitHubClient.Received().Repository.Content.GetArchive(1, ArchiveFormat.Zipball, "ref", TimeSpan.FromMinutes(60)); + } + + [Fact] + public void EnsuresNonNullArguments() + { + var gitHubClient = Substitute.For(); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + Assert.Throws(() => client.GetArchive(null, "repo")); + Assert.Throws(() => client.GetArchive("org", null)); + Assert.Throws(() => client.GetArchive(null, "repo", ArchiveFormat.Tarball)); + Assert.Throws(() => client.GetArchive("org", null, ArchiveFormat.Tarball)); + Assert.Throws(() => client.GetArchive(null, "repo", ArchiveFormat.Tarball, "ref")); + Assert.Throws(() => client.GetArchive("org", null, ArchiveFormat.Tarball, "ref")); + Assert.Throws(() => client.GetArchive("org", "repo", ArchiveFormat.Tarball, null)); + Assert.Throws(() => client.GetArchive(null, "repo", ArchiveFormat.Tarball, "ref", TimeSpan.MaxValue)); + Assert.Throws(() => client.GetArchive("org", null, ArchiveFormat.Tarball, "ref", TimeSpan.MaxValue)); + Assert.Throws(() => client.GetArchive("org", "repo", ArchiveFormat.Tarball, null, TimeSpan.MaxValue)); + + Assert.Throws(() => client.GetArchive(1, ArchiveFormat.Tarball, null)); + Assert.Throws(() => client.GetArchive(1, ArchiveFormat.Tarball, null, TimeSpan.MaxValue)); + + Assert.Throws(() => client.GetArchive("", "repo")); + Assert.Throws(() => client.GetArchive("org", "")); + Assert.Throws(() => client.GetArchive("", "repo", ArchiveFormat.Tarball)); + Assert.Throws(() => client.GetArchive("org", "", ArchiveFormat.Tarball)); + Assert.Throws(() => client.GetArchive("", "repo", ArchiveFormat.Tarball, "ref")); + Assert.Throws(() => client.GetArchive("org", "", ArchiveFormat.Tarball, "ref")); + Assert.Throws(() => client.GetArchive("", "repo", ArchiveFormat.Tarball, "ref", TimeSpan.MaxValue)); + Assert.Throws(() => client.GetArchive("org", "", ArchiveFormat.Tarball, "ref", TimeSpan.MaxValue)); + + Assert.Throws(() => client.GetArchive("org", "repo", ArchiveFormat.Tarball, "ref", TimeSpan.Zero)); + + Assert.Throws(() => client.GetArchive(1, ArchiveFormat.Tarball, "ref", TimeSpan.Zero)); + } + } + } +} \ No newline at end of file diff --git a/Octokit/Clients/IRepositoryContentsClient.cs b/Octokit/Clients/IRepositoryContentsClient.cs index 272f3c06..c2da1f57 100644 --- a/Octokit/Clients/IRepositoryContentsClient.cs +++ b/Octokit/Clients/IRepositoryContentsClient.cs @@ -8,6 +8,9 @@ namespace Octokit /// /// Client for accessing contents of files within a repository as base64 encoded content. /// + /// + /// See the Repository Contents API documentation for more information. + /// public interface IRepositoryContentsClient { /// @@ -19,11 +22,18 @@ namespace Octokit /// The owner of the repository /// The name of the repository /// The content path - /// - /// A collection of representing the content at the specified path - /// Task> GetAllContents(string owner, string name, string path); + /// + /// Returns the contents of a file or directory in a repository. + /// + /// + /// See the API documentation for more information. + /// + /// The ID of the repository + /// The content path + Task> GetAllContents(int repositoryId, string path); + /// /// Returns the contents of the root directory in a repository. /// @@ -32,11 +42,17 @@ namespace Octokit /// /// The owner of the repository /// The name of the repository - /// - /// A collection of representing the content at the specified path - /// Task> GetAllContents(string owner, string name); + /// + /// Returns the contents of the root directory in a repository. + /// + /// + /// See the API documentation for more information. + /// + /// The ID of the repository + Task> GetAllContents(int repositoryId); + /// /// Returns the contents of a file or directory in a repository. /// @@ -47,11 +63,19 @@ namespace Octokit /// The name of the repository /// The content path /// The name of the commit/branch/tag. Default: the repository’s default branch (usually master) - /// - /// A collection of representing the content at the specified path - /// Task> GetAllContentsByRef(string owner, string name, string path, string reference); + /// + /// Returns the contents of a file or directory in a repository. + /// + /// + /// See the API documentation for more information. + /// + /// The ID of the repository + /// The content path + /// The name of the commit/branch/tag. Default: the repository’s default branch (usually master) + Task> GetAllContentsByRef(int repositoryId, string path, string reference); + /// /// Returns the contents of the root directory in a repository. /// @@ -62,11 +86,19 @@ namespace Octokit /// The owner of the repository /// The name of the repository /// The name of the commit/branch/tag. Default: the repository’s default branch (usually master) - /// - /// A collection of representing the content at the specified path - /// Task> GetAllContentsByRef(string owner, string name, string reference); + /// + /// Returns the contents of the root directory in a repository. + /// + /// + /// If given a path to a single file, this method returns a collection containing only that file. + /// See the API documentation for more information. + /// + /// The ID of the repository + /// The name of the commit/branch/tag. Default: the repository’s default branch (usually master) + Task> GetAllContentsByRef(int repositoryId, string reference); + /// /// Gets the preferred README for the specified repository. /// @@ -76,9 +108,18 @@ namespace Octokit /// The owner of the repository /// The name of the repository /// Thrown when a general API error occurs. - /// Task GetReadme(string owner, string name); + /// + /// Gets the preferred README for the specified repository. + /// + /// + /// See the API documentation for more information. + /// + /// The ID of the repository + /// Thrown when a general API error occurs. + Task GetReadme(int repositoryId); + /// /// Gets the preferred README's HTML for the specified repository. /// @@ -88,18 +129,33 @@ namespace Octokit /// The owner of the repository /// The name of the repository /// Thrown when a general API error occurs. - /// Task GetReadmeHtml(string owner, string name); + /// + /// Gets the preferred README's HTML for the specified repository. + /// + /// + /// See the API documentation for more information. + /// + /// The ID of the repository + /// Thrown when a general API error occurs. + Task GetReadmeHtml(int repositoryId); + /// /// Get an archive of a given repository's contents /// /// https://developer.github.com/v3/repos/contents/#get-archive-link /// The owner of the repository /// The name of the repository - /// The binary contents of the archive Task GetArchive(string owner, string name); + /// + /// Get an archive of a given repository's contents + /// + /// https://developer.github.com/v3/repos/contents/#get-archive-link + /// The ID of the repository + Task GetArchive(int repositoryId); + /// /// Get an archive of a given repository's contents, in a specific format /// @@ -107,9 +163,16 @@ namespace Octokit /// The owner of the repository /// The name of the repository /// The format of the archive. Can be either tarball or zipball - /// The binary contents of the archive Task GetArchive(string owner, string name, ArchiveFormat archiveFormat); + /// + /// Get an archive of a given repository's contents, in a specific format + /// + /// https://developer.github.com/v3/repos/contents/#get-archive-link + /// The ID of the repository + /// The format of the archive. Can be either tarball or zipball + Task GetArchive(int repositoryId, ArchiveFormat archiveFormat); + /// /// Get an archive of a given repository's contents, using a specific format and reference /// @@ -118,9 +181,17 @@ namespace Octokit /// The name of the repository /// The format of the archive. Can be either tarball or zipball /// A valid Git reference. - /// The binary contents of the archive Task GetArchive(string owner, string name, ArchiveFormat archiveFormat, string reference); + /// + /// Get an archive of a given repository's contents, using a specific format and reference + /// + /// https://developer.github.com/v3/repos/contents/#get-archive-link + /// The ID of the repository + /// The format of the archive. Can be either tarball or zipball + /// A valid Git reference. + Task GetArchive(int repositoryId, ArchiveFormat archiveFormat, string reference); + /// /// Get an archive of a given repository's contents, in a specific format /// @@ -130,9 +201,18 @@ namespace Octokit /// The format of the archive. Can be either tarball or zipball /// A valid Git reference. /// Time span until timeout - /// The binary contents of the archive Task GetArchive(string owner, string name, ArchiveFormat archiveFormat, string reference, TimeSpan timeout); + /// + /// Get an archive of a given repository's contents, in a specific format + /// + /// https://developer.github.com/v3/repos/contents/#get-archive-link + /// The ID of the repository + /// The format of the archive. Can be either tarball or zipball + /// A valid Git reference. + /// Time span until timeout + Task GetArchive(int repositoryId, ArchiveFormat archiveFormat, string reference, TimeSpan timeout); + /// /// Creates a commit that creates a new file in a repository. /// @@ -140,9 +220,16 @@ namespace Octokit /// The name of the repository /// The path to the file /// Information about the file to create - /// Task CreateFile(string owner, string name, string path, CreateFileRequest request); + /// + /// Creates a commit that creates a new file in a repository. + /// + /// The ID of the repository + /// The path to the file + /// Information about the file to create + Task CreateFile(int repositoryId, string path, CreateFileRequest request); + /// /// Creates a commit that updates the contents of a file in a repository. /// @@ -150,9 +237,16 @@ namespace Octokit /// The name of the repository /// The path to the file /// Information about the file to update - /// The updated content Task UpdateFile(string owner, string name, string path, UpdateFileRequest request); + /// + /// Creates a commit that updates the contents of a file in a repository. + /// + /// The ID of the repository + /// The path to the file + /// Information about the file to update + Task UpdateFile(int repositoryId, string path, UpdateFileRequest request); + /// /// Creates a commit that deletes a file in a repository. /// @@ -161,6 +255,14 @@ namespace Octokit /// The path to the file /// Information about the file to delete Task DeleteFile(string owner, string name, string path, DeleteFileRequest request); + + /// + /// Creates a commit that deletes a file in a repository. + /// + /// The ID of the repository + /// The path to the file + /// Information about the file to delete + Task DeleteFile(int repositoryId, string path, DeleteFileRequest request); } /// diff --git a/Octokit/Clients/RepositoryContentsClient.cs b/Octokit/Clients/RepositoryContentsClient.cs index 16c47e35..448db3a9 100644 --- a/Octokit/Clients/RepositoryContentsClient.cs +++ b/Octokit/Clients/RepositoryContentsClient.cs @@ -7,6 +7,9 @@ namespace Octokit /// /// Client for accessing contents of files within a repository as base64 encoded content. /// + /// + /// See the Repository Contents API documentation for more information. + /// public class RepositoryContentsClient : ApiClient, IRepositoryContentsClient { /// @@ -26,19 +29,34 @@ namespace Octokit /// The owner of the repository /// The name of the repository /// The content path - /// - /// A collection of representing the content at the specified path - /// public Task> GetAllContents(string owner, string name, string path) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNullOrEmptyString(path, "path"); var url = ApiUrls.RepositoryContent(owner, name, path); return ApiConnection.GetAll(url); } + /// + /// Returns the contents of a file or directory in a repository. + /// + /// + /// See the API documentation for more information. + /// + /// The ID of the repository + /// The content path + public Task> GetAllContents(int repositoryId, string path) + { + Ensure.ArgumentNotNullOrEmptyString(path, "path"); + + var url = ApiUrls.RepositoryContent(repositoryId, path); + + return ApiConnection.GetAll(url); + } + /// /// Returns the contents of the root directory in a repository. /// @@ -47,9 +65,6 @@ namespace Octokit /// /// The owner of the repository /// The name of the repository - /// - /// A collection of representing the content at the specified path - /// public Task> GetAllContents(string owner, string name) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); @@ -60,6 +75,20 @@ namespace Octokit return ApiConnection.GetAll(url); } + /// + /// Returns the contents of the root directory in a repository. + /// + /// + /// See the API documentation for more information. + /// + /// The ID of the repository + public Task> GetAllContents(int repositoryId) + { + var url = ApiUrls.RepositoryContent(repositoryId, string.Empty); + + return ApiConnection.GetAll(url); + } + /// /// Returns the contents of a file or directory in a repository. /// @@ -71,9 +100,6 @@ namespace Octokit /// The name of the repository /// The content path /// The name of the commit/branch/tag. Default: the repository�s default branch (usually master) - /// - /// A collection of representing the content at the specified path - /// public Task> GetAllContentsByRef(string owner, string name, string path, string reference) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); @@ -86,6 +112,25 @@ namespace Octokit return ApiConnection.GetAll(url); } + /// + /// Returns the contents of a file or directory in a repository. + /// + /// + /// See the API documentation for more information. + /// + /// The ID of the repository + /// The content path + /// The name of the commit/branch/tag. Default: the repository’s default branch (usually master) + public Task> GetAllContentsByRef(int repositoryId, string path, string reference) + { + Ensure.ArgumentNotNullOrEmptyString(path, "path"); + Ensure.ArgumentNotNullOrEmptyString(reference, "reference"); + + var url = ApiUrls.RepositoryContent(repositoryId, path, reference); + + return ApiConnection.GetAll(url); + } + /// /// Returns the contents of the root directory in a repository. /// @@ -95,9 +140,6 @@ namespace Octokit /// The owner of the repository /// The name of the repository /// The name of the commit/branch/tag. Default: the repository�s default branch (usually master) - /// - /// A collection of representing the content at the specified path - /// public Task> GetAllContentsByRef(string owner, string name, string reference) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); @@ -109,6 +151,24 @@ namespace Octokit return ApiConnection.GetAll(url); } + /// + /// Returns the contents of the root directory in a repository. + /// + /// + /// If given a path to a single file, this method returns a collection containing only that file. + /// See the API documentation for more information. + /// + /// The ID of the repository + /// The name of the commit/branch/tag. Default: the repository’s default branch (usually master) + public Task> GetAllContentsByRef(int repositoryId, string reference) + { + Ensure.ArgumentNotNullOrEmptyString(reference, "reference"); + + var url = ApiUrls.RepositoryContent(repositoryId, string.Empty, reference); + + return ApiConnection.GetAll(url); + } + /// /// Gets the preferred README for the specified repository. /// @@ -118,7 +178,6 @@ namespace Octokit /// The owner of the repository /// The name of the repository /// Thrown when a general API error occurs. - /// public async Task GetReadme(string owner, string name) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); @@ -130,6 +189,22 @@ namespace Octokit return new Readme(readmeInfo, ApiConnection); } + /// + /// Gets the preferred README for the specified repository. + /// + /// + /// See the API documentation for more information. + /// + /// The ID of the repository + /// Thrown when a general API error occurs. + public async Task GetReadme(int repositoryId) + { + var endpoint = ApiUrls.RepositoryReadme(repositoryId); + var readmeInfo = await ApiConnection.Get(endpoint, null).ConfigureAwait(false); + + return new Readme(readmeInfo, ApiConnection); + } + /// /// Gets the preferred README's HTML for the specified repository. /// @@ -139,7 +214,6 @@ namespace Octokit /// The owner of the repository /// The name of the repository /// Thrown when a general API error occurs. - /// public Task GetReadmeHtml(string owner, string name) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); @@ -148,18 +222,43 @@ namespace Octokit return ApiConnection.GetHtml(ApiUrls.RepositoryReadme(owner, name), null); } + /// + /// Gets the preferred README's HTML for the specified repository. + /// + /// + /// See the API documentation for more information. + /// + /// The ID of the repository + /// Thrown when a general API error occurs. + public Task GetReadmeHtml(int repositoryId) + { + return ApiConnection.GetHtml(ApiUrls.RepositoryReadme(repositoryId), null); + } + /// /// Get an archive of a given repository's contents /// /// https://developer.github.com/v3/repos/contents/#get-archive-link /// The owner of the repository /// The name of the repository - /// The binary contents of the archive public Task GetArchive(string owner, string name) { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + return GetArchive(owner, name, ArchiveFormat.Tarball, string.Empty); } + /// + /// Get an archive of a given repository's contents + /// + /// https://developer.github.com/v3/repos/contents/#get-archive-link + /// The ID of the repository + public Task GetArchive(int repositoryId) + { + return GetArchive(repositoryId, ArchiveFormat.Tarball, string.Empty); + } + /// /// Get an archive of a given repository's contents, in a specific format /// @@ -167,12 +266,25 @@ namespace Octokit /// The owner of the repository /// The name of the repository /// The format of the archive. Can be either tarball or zipball - /// The binary contents of the archive public Task GetArchive(string owner, string name, ArchiveFormat archiveFormat) { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + return GetArchive(owner, name, archiveFormat, string.Empty); } + /// + /// Get an archive of a given repository's contents, in a specific format + /// + /// https://developer.github.com/v3/repos/contents/#get-archive-link + /// The ID of the repository + /// The format of the archive. Can be either tarball or zipball + public Task GetArchive(int repositoryId, ArchiveFormat archiveFormat) + { + return GetArchive(repositoryId, archiveFormat, string.Empty); + } + /// /// Get an archive of a given repository's contents, using a specific format and reference /// @@ -181,12 +293,29 @@ namespace Octokit /// The name of the repository /// The format of the archive. Can be either tarball or zipball /// A valid Git reference. - /// The binary contents of the archive public Task GetArchive(string owner, string name, ArchiveFormat archiveFormat, string reference) { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(reference, "reference"); + return GetArchive(owner, name, archiveFormat, reference, TimeSpan.FromMinutes(60)); } + /// + /// Get an archive of a given repository's contents, using a specific format and reference + /// + /// https://developer.github.com/v3/repos/contents/#get-archive-link + /// The ID of the repository + /// The format of the archive. Can be either tarball or zipball + /// A valid Git reference. + public Task GetArchive(int repositoryId, ArchiveFormat archiveFormat, string reference) + { + Ensure.ArgumentNotNull(reference, "reference"); + + return GetArchive(repositoryId, archiveFormat, reference, TimeSpan.FromMinutes(60)); + } + /// /// Get an archive of a given repository's contents, in a specific format /// @@ -196,11 +325,11 @@ namespace Octokit /// The format of the archive. Can be either tarball or zipball /// A valid Git reference. /// Time span until timeout - /// The binary contents of the archive public async Task GetArchive(string owner, string name, ArchiveFormat archiveFormat, string reference, TimeSpan timeout) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(reference, "reference"); Ensure.GreaterThanZero(timeout, "timeout"); var endpoint = ApiUrls.RepositoryArchiveLink(owner, name, archiveFormat, reference); @@ -210,6 +339,26 @@ namespace Octokit return response.Body; } + /// + /// Get an archive of a given repository's contents, in a specific format + /// + /// https://developer.github.com/v3/repos/contents/#get-archive-link + /// The ID of the repository + /// The format of the archive. Can be either tarball or zipball + /// A valid Git reference. + /// Time span until timeout + public async Task GetArchive(int repositoryId, ArchiveFormat archiveFormat, string reference, TimeSpan timeout) + { + Ensure.ArgumentNotNull(reference, "reference"); + Ensure.GreaterThanZero(timeout, "timeout"); + + var endpoint = ApiUrls.RepositoryArchiveLink(repositoryId, archiveFormat, reference); + + var response = await Connection.Get(endpoint, timeout).ConfigureAwait(false); + + return response.Body; + } + /// /// Creates a commit that creates a new file in a repository. /// @@ -217,7 +366,6 @@ namespace Octokit /// The name of the repository /// The path to the file /// Information about the file to create - /// public Task CreateFile(string owner, string name, string path, CreateFileRequest request) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); @@ -229,6 +377,21 @@ namespace Octokit return ApiConnection.Put(createUrl, request); } + /// + /// Creates a commit that creates a new file in a repository. + /// + /// The ID of the repository + /// The path to the file + /// Information about the file to create + public Task CreateFile(int repositoryId, string path, CreateFileRequest request) + { + Ensure.ArgumentNotNullOrEmptyString(path, "path"); + Ensure.ArgumentNotNull(request, "request"); + + var createUrl = ApiUrls.RepositoryContent(repositoryId, path); + return ApiConnection.Put(createUrl, request); + } + /// /// Creates a commit that updates the contents of a file in a repository. /// @@ -236,7 +399,6 @@ namespace Octokit /// The name of the repository /// 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) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); @@ -248,6 +410,21 @@ namespace Octokit return ApiConnection.Put(updateUrl, request); } + /// + /// Creates a commit that updates the contents of a file in a repository. + /// + /// The ID of the repository + /// The path to the file + /// Information about the file to update + public Task UpdateFile(int repositoryId, string path, UpdateFileRequest request) + { + Ensure.ArgumentNotNullOrEmptyString(path, "path"); + Ensure.ArgumentNotNull(request, "request"); + + var updateUrl = ApiUrls.RepositoryContent(repositoryId, path); + return ApiConnection.Put(updateUrl, request); + } + /// /// Creates a commit that deletes a file in a repository. /// @@ -265,5 +442,20 @@ namespace Octokit var deleteUrl = ApiUrls.RepositoryContent(owner, name, path); return ApiConnection.Delete(deleteUrl, request); } + + /// + /// Creates a commit that deletes a file in a repository. + /// + /// The ID of the repository + /// The path to the file + /// Information about the file to delete + public Task DeleteFile(int repositoryId, string path, DeleteFileRequest request) + { + Ensure.ArgumentNotNullOrEmptyString(path, "path"); + Ensure.ArgumentNotNull(request, "request"); + + var deleteUrl = ApiUrls.RepositoryContent(repositoryId, path); + return ApiConnection.Delete(deleteUrl, request); + } } } \ No newline at end of file