diff --git a/Octokit.Reactive/Clients/IObservableTreesClient.cs b/Octokit.Reactive/Clients/IObservableTreesClient.cs index ac10689a..5bcdf476 100644 --- a/Octokit.Reactive/Clients/IObservableTreesClient.cs +++ b/Octokit.Reactive/Clients/IObservableTreesClient.cs @@ -2,6 +2,12 @@ using System; namespace Octokit.Reactive { + /// + /// A client for GitHub's Git Trees API. + /// + /// + /// See the Git Trees API documentation for more information. + /// public interface IObservableTreesClient { /// @@ -13,10 +19,20 @@ namespace Octokit.Reactive /// The owner of the repository /// The name of the repository /// The SHA that references the tree - /// The for the specified Tree. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Get")] IObservable Get(string owner, string name, string reference); + /// + /// Gets a Tree Response for a given SHA. + /// + /// + /// http://developer.github.com/v3/git/trees/#get-a-tree + /// + /// The ID of the repository + /// The SHA that references the tree + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Get")] + IObservable Get(int repositoryId, string reference); + /// /// Gets a Tree Response for a given SHA. /// @@ -26,9 +42,18 @@ namespace Octokit.Reactive /// The owner of the repository /// The name of the repository /// The SHA that references the tree - /// The for the specified Tree. IObservable GetRecursive(string owner, string name, string reference); + /// + /// Gets a Tree Response for a given SHA. + /// + /// + /// https://developer.github.com/v3/git/trees/#get-a-tree-recursively + /// + /// The ID of the repository + /// The SHA that references the tree + IObservable GetRecursive(int repositoryId, string reference); + /// /// Creates a new Tree in the specified repo /// @@ -38,7 +63,16 @@ namespace Octokit.Reactive /// The owner of the repository /// The name of the repository /// The value of the new tree - /// The that was just created. IObservable Create(string owner, string name, NewTree newTree); + + /// + /// Creates a new Tree in the specified repo + /// + /// + /// http://developer.github.com/v3/git/trees/#create-a-tree + /// + /// The ID of the repository + /// The value of the new tree + IObservable Create(int repositoryId, NewTree newTree); } } \ No newline at end of file diff --git a/Octokit.Reactive/Clients/ObservableTreesClient.cs b/Octokit.Reactive/Clients/ObservableTreesClient.cs index e018b10d..400c6d64 100644 --- a/Octokit.Reactive/Clients/ObservableTreesClient.cs +++ b/Octokit.Reactive/Clients/ObservableTreesClient.cs @@ -3,6 +3,12 @@ using System.Reactive.Threading.Tasks; namespace Octokit.Reactive { + /// + /// A client for GitHub's Git Trees API. + /// + /// + /// See the Git Trees API documentation for more information. + /// public class ObservableTreesClient : IObservableTreesClient { readonly ITreesClient _client; @@ -23,7 +29,6 @@ namespace Octokit.Reactive /// The owner of the repository /// The name of the repository /// The SHA that references the tree - /// The for the specified Tree. public IObservable Get(string owner, string name, string reference) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); @@ -33,6 +38,21 @@ namespace Octokit.Reactive return _client.Get(owner, name, reference).ToObservable(); } + /// + /// Gets a Tree Response for a given SHA. + /// + /// + /// http://developer.github.com/v3/git/trees/#get-a-tree + /// + /// The ID of the repository + /// The SHA that references the tree + public IObservable Get(int repositoryId, string reference) + { + Ensure.ArgumentNotNullOrEmptyString(reference, "reference"); + + return _client.Get(repositoryId, reference).ToObservable(); + } + /// /// Gets a Tree Response for a given SHA. /// @@ -42,7 +62,6 @@ namespace Octokit.Reactive /// The owner of the repository /// The name of the repository /// The SHA that references the tree - /// The for the specified Tree. public IObservable GetRecursive(string owner, string name, string reference) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); @@ -52,6 +71,21 @@ namespace Octokit.Reactive return _client.GetRecursive(owner, name, reference).ToObservable(); } + /// + /// Gets a Tree Response for a given SHA. + /// + /// + /// https://developer.github.com/v3/git/trees/#get-a-tree-recursively + /// + /// The ID of the repository + /// The SHA that references the tree + public IObservable GetRecursive(int repositoryId, string reference) + { + Ensure.ArgumentNotNullOrEmptyString(reference, "reference"); + + return _client.GetRecursive(repositoryId, reference).ToObservable(); + } + /// /// Creates a new Tree in the specified repo /// @@ -61,7 +95,6 @@ namespace Octokit.Reactive /// The owner of the repository /// The name of the repository /// The value of the new tree - /// The that was just created. public IObservable Create(string owner, string name, NewTree newTree) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); @@ -70,5 +103,20 @@ namespace Octokit.Reactive return _client.Create(owner, name, newTree).ToObservable(); } + + /// + /// Creates a new Tree in the specified repo + /// + /// + /// http://developer.github.com/v3/git/trees/#create-a-tree + /// + /// The ID of the repository + /// The value of the new tree + public IObservable Create(int repositoryId, NewTree newTree) + { + Ensure.ArgumentNotNull(newTree, "newTree"); + + return _client.Create(repositoryId, newTree).ToObservable(); + } } } diff --git a/Octokit.Tests.Integration/Clients/TreeClientTests.cs b/Octokit.Tests.Integration/Clients/TreeClientTests.cs index 4522efc5..ea7d2b7e 100644 --- a/Octokit.Tests.Integration/Clients/TreeClientTests.cs +++ b/Octokit.Tests.Integration/Clients/TreeClientTests.cs @@ -2,8 +2,8 @@ using System.Threading.Tasks; using Octokit; using Octokit.Tests.Integration; -using Xunit; using Octokit.Tests.Integration.Helpers; +using Xunit; public class TreeClientTests : IDisposable { @@ -45,6 +45,31 @@ public class TreeClientTests : IDisposable Assert.NotNull(result); } + [IntegrationTest] + public async Task CanCreateATreeWithRepositoryId() + { + var blob = new NewBlob + { + Content = "Hello World!", + Encoding = EncodingType.Utf8 + }; + + var createdBlob = await _github.Git.Blob.Create(_context.RepositoryOwner, _context.RepositoryName, blob); + + var newTree = new NewTree(); + newTree.Tree.Add(new NewTreeItem + { + Type = TreeType.Blob, + Path = "README.md", + Sha = createdBlob.Sha, + Mode = FileMode.File + }); + + var result = await _fixture.Create(_context.Repository.Id, newTree); + + Assert.NotNull(result); + } + [IntegrationTest] public async Task CanGetATree() { @@ -54,6 +79,15 @@ public class TreeClientTests : IDisposable Assert.NotEmpty(result.Tree); } + [IntegrationTest] + public async Task CanGetATreeWithRepositoryId() + { + var result = await _fixture.Get(1, "master"); + + Assert.NotNull(result); + Assert.NotEmpty(result.Tree); + } + [IntegrationTest] public async Task CanGetACreatedTree() { @@ -82,6 +116,34 @@ public class TreeClientTests : IDisposable Assert.Equal(1, result.Tree.Count); } + [IntegrationTest] + public async Task CanGetACreatedTreeWithRepositoryId() + { + var blob = new NewBlob + { + Content = "Hello World!", + Encoding = EncodingType.Utf8 + }; + + var blobResult = await _github.Git.Blob.Create(_context.RepositoryOwner, _context.RepositoryName, blob); + + var newTree = new NewTree(); + newTree.Tree.Add(new NewTreeItem + { + Type = TreeType.Blob, + Path = "README.md", + Sha = blobResult.Sha, + Mode = FileMode.File + }); + + var tree = await _fixture.Create(_context.Repository.Id, newTree); + + var result = await _fixture.Get(_context.Repository.Id, tree.Sha); + + Assert.NotNull(result); + Assert.Equal(1, result.Tree.Count); + } + public void Dispose() { _context.Dispose(); diff --git a/Octokit.Tests/Clients/TreesClientTests.cs b/Octokit.Tests/Clients/TreesClientTests.cs index 458f9a14..b876eeab 100644 --- a/Octokit.Tests/Clients/TreesClientTests.cs +++ b/Octokit.Tests/Clients/TreesClientTests.cs @@ -13,54 +13,86 @@ namespace Octokit.Tests public class TheGetMethod { [Fact] - public void RequestsCorrectUrl() + public async Task RequestsCorrectUrl() { var connection = Substitute.For(); var client = new TreesClient(connection); - client.Get("fake", "repo", "123456ABCD"); + await client.Get("fake", "repo", "123456ABCD"); connection.Received().Get(Arg.Is(u => u.ToString() == "repos/fake/repo/git/trees/123456ABCD")); } + [Fact] + public async Task RequestsCorrectUrlWithRepositoryId() + { + var connection = Substitute.For(); + var client = new TreesClient(connection); + + await client.Get(1, "123456ABCD"); + + connection.Received().Get(Arg.Is(u => u.ToString() == "repositories/1/git/trees/123456ABCD")); + } + [Fact] public async Task EnsuresNonNullArguments() { var client = new TreesClient(Substitute.For()); await Assert.ThrowsAsync(() => client.Get(null, "name", "123456ABCD")); - await Assert.ThrowsAsync(() => client.Get("", "name", "123456ABCD")); await Assert.ThrowsAsync(() => client.Get("owner", null, "123456ABCD")); - await Assert.ThrowsAsync(() => client.Get("owner", "", "123456ABCD")); await Assert.ThrowsAsync(() => client.Get("owner", "name", null)); + + await Assert.ThrowsAsync(() => client.Get(1, null)); + + await Assert.ThrowsAsync(() => client.Get("owner", "", "123456ABCD")); + await Assert.ThrowsAsync(() => client.Get("", "name", "123456ABCD")); await Assert.ThrowsAsync(() => client.Get("owner", "name", "")); + + await Assert.ThrowsAsync(() => client.Get(1, "")); } } public class TheGetRecursiveMethod { [Fact] - public void RequestsCorrectUrl() + public async Task RequestsCorrectUrl() { var connection = Substitute.For(); var client = new TreesClient(connection); - client.GetRecursive("fake", "repo", "123456ABCD"); + await client.GetRecursive("fake", "repo", "123456ABCD"); connection.Received().Get(Arg.Is(u => u.ToString() == "repos/fake/repo/git/trees/123456ABCD?recursive=1")); } + [Fact] + public async Task RequestsCorrectUrlWithRepositoryId() + { + var connection = Substitute.For(); + var client = new TreesClient(connection); + + await client.GetRecursive(1, "123456ABCD"); + + connection.Received().Get(Arg.Is(u => u.ToString() == "repositories/1/git/trees/123456ABCD?recursive=1")); + } + [Fact] public async Task EnsuresNonNullArguments() { var client = new TreesClient(Substitute.For()); await Assert.ThrowsAsync(() => client.GetRecursive(null, "name", "123456ABCD")); - await Assert.ThrowsAsync(() => client.GetRecursive("", "name", "123456ABCD")); await Assert.ThrowsAsync(() => client.GetRecursive("owner", null, "123456ABCD")); - await Assert.ThrowsAsync(() => client.GetRecursive("owner", "", "123456ABCD")); await Assert.ThrowsAsync(() => client.GetRecursive("owner", "name", null)); + + await Assert.ThrowsAsync(() => client.GetRecursive(1, null)); + + await Assert.ThrowsAsync(() => client.GetRecursive("", "name", "123456ABCD")); + await Assert.ThrowsAsync(() => client.GetRecursive("owner", "", "123456ABCD")); await Assert.ThrowsAsync(() => client.GetRecursive("owner", "name", "")); + + await Assert.ThrowsAsync(() => client.GetRecursive(1, "")); } } @@ -79,14 +111,30 @@ namespace Octokit.Tests } [Fact] - public async Task EnsuresArgumentsNotNull() + public void PostsToCorrectUrlWithRepositoryId() + { + var newTree = new NewTree(); + var connection = Substitute.For(); + var client = new TreesClient(connection); + + client.Create(1, newTree); + + connection.Received().Post(Arg.Is(u => u.ToString() == "repositories/1/git/trees"), newTree); + } + + [Fact] + public async Task EnsuresNonNullArguments() { var connection = Substitute.For(); var client = new TreesClient(connection); await Assert.ThrowsAsync(() => client.Create(null, "name", new NewTree())); - await Assert.ThrowsAsync(() => client.Create("", "name", new NewTree())); await Assert.ThrowsAsync(() => client.Create("owner", null, new NewTree())); + await Assert.ThrowsAsync(() => client.Create("owner", "name", null)); + + await Assert.ThrowsAsync(() => client.Create(1, null)); + + await Assert.ThrowsAsync(() => client.Create("", "name", new NewTree())); await Assert.ThrowsAsync(() => client.Create("owner", "", new NewTree())); } @@ -102,6 +150,19 @@ namespace Octokit.Tests await Assert.ThrowsAsync( () => client.Create("fake", "repo", newTree)); } + + [Fact] + public async Task EnsureExceptionIsThrownWhenModeIsNotProvidedWithRepositoryId() + { + var newTree = new NewTree(); + newTree.Tree.Add(new NewTreeItem { Path = "README.md", Type = TreeType.Blob, Sha = "2e1a73d60f004fd842d4bad28aa42392d4f35d28" }); + + var connection = Substitute.For(); + var client = new TreesClient(connection); + + await Assert.ThrowsAsync( + () => client.Create(1, newTree)); + } } public class TheCtor diff --git a/Octokit.Tests/Reactive/ObservableTreesClientTests.cs b/Octokit.Tests/Reactive/ObservableTreesClientTests.cs index d2e0920c..b94e211d 100644 --- a/Octokit.Tests/Reactive/ObservableTreesClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableTreesClientTests.cs @@ -21,7 +21,7 @@ namespace Octokit.Tests public class TheGetMethod { [Fact] - public void GetsFromClientIssueIssue() + public void RequestsCorrectUrl() { var gitHubClient = Substitute.For(); var client = new ObservableTreesClient(gitHubClient); @@ -31,24 +31,40 @@ namespace Octokit.Tests gitHubClient.Git.Tree.Received().Get("fake", "repo", "123456ABCD"); } + [Fact] + public void RequestsCorrectUrlWithRepositoryId() + { + var gitHubClient = Substitute.For(); + var client = new ObservableTreesClient(gitHubClient); + + client.Get(1, "123456ABCD"); + + gitHubClient.Git.Tree.Received().Get(1, "123456ABCD"); + } + [Fact] public async Task EnsuresNonNullArguments() { var client = new ObservableTreesClient(Substitute.For()); - await Assert.ThrowsAsync(() => client.Get(null, "name", "123456ABCD").ToTask()); - await Assert.ThrowsAsync(() => client.Get("", "name", "123456ABCD").ToTask()); - await Assert.ThrowsAsync(() => client.Get("owner", null, "123456ABCD").ToTask()); - await Assert.ThrowsAsync(() => client.Get("owner", "", "123456ABCD").ToTask()); - await Assert.ThrowsAsync(() => client.Get("owner", "name", null).ToTask()); - await Assert.ThrowsAsync(() => client.Get("owner", "name", "").ToTask()); + Assert.Throws(() => client.Get(null, "name", "123456ABCD")); + Assert.Throws(() => client.Get("owner", null, "123456ABCD")); + Assert.Throws(() => client.Get("owner", "name", null)); + + Assert.Throws(() => client.Get(1, null)); + + Assert.Throws(() => client.Get("", "name", "123456ABCD")); + Assert.Throws(() => client.Get("owner", "", "123456ABCD")); + Assert.Throws(() => client.Get("owner", "name", "")); + + Assert.Throws(() => client.Get(1, "")); } } public class TheGetRecursiveMethod { [Fact] - public void GetsFromClientIssueIssue() + public void RequestsCorrectUrl() { var gitHubClient = Substitute.For(); var client = new ObservableTreesClient(gitHubClient); @@ -58,24 +74,40 @@ namespace Octokit.Tests gitHubClient.Git.Tree.Received().GetRecursive("fake", "repo", "123456ABCD"); } + [Fact] + public void RequestsCorrectUrlWithRepositoryId() + { + var gitHubClient = Substitute.For(); + var client = new ObservableTreesClient(gitHubClient); + + client.GetRecursive(1, "123456ABCD"); + + gitHubClient.Git.Tree.Received().GetRecursive(1, "123456ABCD"); + } + [Fact] public async Task EnsuresNonNullArguments() { var client = new ObservableTreesClient(Substitute.For()); - await Assert.ThrowsAsync(() => client.GetRecursive(null, "name", "123456ABCD").ToTask()); - await Assert.ThrowsAsync(() => client.GetRecursive("", "name", "123456ABCD").ToTask()); - await Assert.ThrowsAsync(() => client.GetRecursive("owner", null, "123456ABCD").ToTask()); - await Assert.ThrowsAsync(() => client.GetRecursive("owner", "", "123456ABCD").ToTask()); - await Assert.ThrowsAsync(() => client.GetRecursive("owner", "name", null).ToTask()); - await Assert.ThrowsAsync(() => client.GetRecursive("owner", "name", "").ToTask()); + Assert.Throws(() => client.GetRecursive(null, "name", "123456ABCD")); + Assert.Throws(() => client.GetRecursive("owner", null, "123456ABCD")); + Assert.Throws(() => client.GetRecursive("owner", "name", null)); + + Assert.Throws(() => client.GetRecursive(1, null)); + + Assert.Throws(() => client.GetRecursive("", "name", "123456ABCD")); + Assert.Throws(() => client.GetRecursive("owner", "", "123456ABCD")); + Assert.Throws(() => client.GetRecursive("owner", "name", "")); + + Assert.Throws(() => client.GetRecursive(1, "")); } } public class TheCreateMethod { [Fact] - public void CreatesFromClientIssueIssue() + public void RequestsCorrectUrl() { var newTree = new NewTree(); var gitHubClient = Substitute.For(); @@ -87,16 +119,30 @@ namespace Octokit.Tests } [Fact] - public async Task EnsuresArgumentsNotNull() + public void RequestsCorrectUrlWithRepositoryId() { + var newTree = new NewTree(); var gitHubClient = Substitute.For(); var client = new ObservableTreesClient(gitHubClient); + client.Create(1, newTree); + + gitHubClient.Git.Tree.Received().Create(1, newTree); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new ObservableTreesClient(Substitute.For()); + Assert.Throws(() => client.Create(null, "name", new NewTree())); - Assert.Throws(() => client.Create("", "name", new NewTree())); Assert.Throws(() => client.Create("owner", null, new NewTree())); - Assert.Throws(() => client.Create("owner", "", new NewTree())); Assert.Throws(() => client.Create("owner", "name", null)); + + Assert.Throws(() => client.Create(1, null)); + + Assert.Throws(() => client.Create("", "name", new NewTree())); + Assert.Throws(() => client.Create("owner", "", new NewTree())); } } } diff --git a/Octokit/Clients/ITreesClient.cs b/Octokit/Clients/ITreesClient.cs index 549621a4..b4835661 100644 --- a/Octokit/Clients/ITreesClient.cs +++ b/Octokit/Clients/ITreesClient.cs @@ -19,10 +19,20 @@ namespace Octokit /// The owner of the repository /// The name of the repository /// The SHA that references the tree - /// The for the specified Tree. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Get")] Task Get(string owner, string name, string reference); + /// + /// Gets a Tree Response for a given SHA. + /// + /// + /// http://developer.github.com/v3/git/trees/#get-a-tree + /// + /// The ID of the repository + /// The SHA that references the tree + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Get")] + Task Get(int repositoryId, string reference); + /// /// Gets a Tree Response for a given SHA. /// @@ -32,9 +42,18 @@ namespace Octokit /// The owner of the repository /// The name of the repository /// The SHA that references the tree - /// The for the specified Tree. Task GetRecursive(string owner, string name, string reference); + /// + /// Gets a Tree Response for a given SHA. + /// + /// + /// https://developer.github.com/v3/git/trees/#get-a-tree-recursively + /// + /// The ID of the repository + /// The SHA that references the tree + Task GetRecursive(int repositoryId, string reference); + /// /// Creates a new Tree in the specified repo /// @@ -44,7 +63,16 @@ namespace Octokit /// The owner of the repository /// The name of the repository /// The value of the new tree - /// The that was just created. Task Create(string owner, string name, NewTree newTree); + + /// + /// Creates a new Tree in the specified repo + /// + /// + /// http://developer.github.com/v3/git/trees/#create-a-tree + /// + /// The ID of the repository + /// The value of the new tree + Task Create(int repositoryId, NewTree newTree); } } \ No newline at end of file diff --git a/Octokit/Clients/TreesClient.cs b/Octokit/Clients/TreesClient.cs index 5ac64675..4552b4f6 100644 --- a/Octokit/Clients/TreesClient.cs +++ b/Octokit/Clients/TreesClient.cs @@ -30,7 +30,6 @@ namespace Octokit /// The owner of the repository /// The name of the repository /// The SHA that references the tree - /// The for the specified Tree. public Task Get(string owner, string name, string reference) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); @@ -40,6 +39,21 @@ namespace Octokit return ApiConnection.Get(ApiUrls.Tree(owner, name, reference)); } + /// + /// Gets a Tree Response for a given SHA. + /// + /// + /// http://developer.github.com/v3/git/trees/#get-a-tree + /// + /// The ID of the repository + /// The SHA that references the tree + public Task Get(int repositoryId, string reference) + { + Ensure.ArgumentNotNullOrEmptyString(reference, "reference"); + + return ApiConnection.Get(ApiUrls.Tree(repositoryId, reference)); + } + /// /// Gets a Tree Response for a given SHA. /// @@ -49,7 +63,6 @@ namespace Octokit /// The owner of the repository /// The name of the repository /// The SHA that references the tree - /// The for the specified Tree. public Task GetRecursive(string owner, string name, string reference) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); @@ -59,6 +72,21 @@ namespace Octokit return ApiConnection.Get(ApiUrls.TreeRecursive(owner, name, reference)); } + /// + /// Gets a Tree Response for a given SHA. + /// + /// + /// https://developer.github.com/v3/git/trees/#get-a-tree-recursively + /// + /// The ID of the repository + /// The SHA that references the tree + public Task GetRecursive(int repositoryId, string reference) + { + Ensure.ArgumentNotNullOrEmptyString(reference, "reference"); + + return ApiConnection.Get(ApiUrls.TreeRecursive(repositoryId, reference)); + } + /// /// Creates a new Tree in the specified repo /// @@ -68,7 +96,6 @@ namespace Octokit /// The owner of the repository /// The name of the repository /// The value of the new tree - /// The that was just created. public Task Create(string owner, string name, NewTree newTree) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); @@ -82,5 +109,25 @@ namespace Octokit return ApiConnection.Post(ApiUrls.Tree(owner, name), newTree); } + + /// + /// Creates a new Tree in the specified repo + /// + /// + /// http://developer.github.com/v3/git/trees/#create-a-tree + /// + /// The ID of the repository + /// The value of the new tree + public Task Create(int repositoryId, NewTree newTree) + { + Ensure.ArgumentNotNull(newTree, "newTree"); + + if (newTree.Tree.Any(t => string.IsNullOrWhiteSpace(t.Mode))) + { + throw new ArgumentException("You have specified items in the tree which do not have a Mode value set."); + } + + return ApiConnection.Post(ApiUrls.Tree(repositoryId), newTree); + } } }