diff --git a/Octokit.Reactive/Clients/IObservableIssueReactionsClient.cs b/Octokit.Reactive/Clients/IObservableIssueReactionsClient.cs index 3cfc109b..91f0bb6e 100644 --- a/Octokit.Reactive/Clients/IObservableIssueReactionsClient.cs +++ b/Octokit.Reactive/Clients/IObservableIssueReactionsClient.cs @@ -2,8 +2,31 @@ namespace Octokit.Reactive { + /// + /// A client for GitHub's Reactions API. + /// + /// + /// See the Reactions API documentation for more information. + /// public interface IObservableIssueReactionsClient { + /// + /// List reactions for a specified Issue. + /// + /// https://developer.github.com/v3/reactions/#list-reactions-for-an-issue + /// The owner of the repository + /// The name of the repository + /// The issue id + IObservable GetAll(string owner, string name, int number); + + /// + /// List reactions for a specified Issue. + /// + /// https://developer.github.com/v3/reactions/#list-reactions-for-an-issue + /// The ID of the repository + /// The issue id + IObservable GetAll(int repositoryId, int number); + /// /// Creates a reaction for a specified Issue. /// @@ -12,17 +35,15 @@ namespace Octokit.Reactive /// The name of the repository /// The issue id /// The reaction to create - /// IObservable Create(string owner, string name, int number, NewReaction reaction); /// - /// List reactions for a specified Issue. + /// Creates a reaction for a specified Issue. /// - /// https://developer.github.com/v3/reactions/#list-reactions-for-an-issue - /// The owner of the repository - /// The name of the repository - /// The issue id - /// - IObservable GetAll(string owner, string name, int number); + /// https://developer.github.com/v3/reactions/#create-reaction-for-an-issue + /// The ID of the repository + /// The issue id + /// The reaction to create + IObservable Create(int repositoryId, int number, NewReaction reaction); } } diff --git a/Octokit.Reactive/Clients/ObservableIssueReactionsClient.cs b/Octokit.Reactive/Clients/ObservableIssueReactionsClient.cs index 305e2408..2f7acc34 100644 --- a/Octokit.Reactive/Clients/ObservableIssueReactionsClient.cs +++ b/Octokit.Reactive/Clients/ObservableIssueReactionsClient.cs @@ -1,9 +1,15 @@ -using Octokit.Reactive.Internal; -using System; +using System; using System.Reactive.Threading.Tasks; +using Octokit.Reactive.Internal; namespace Octokit.Reactive { + /// + /// A client for GitHub's Reactions API. + /// + /// + /// See the Reactions API documentation for more information. + /// public class ObservableIssueReactionsClient : IObservableIssueReactionsClient { readonly IIssueReactionsClient _client; @@ -17,6 +23,32 @@ namespace Octokit.Reactive _connection = client.Connection; } + /// + /// List reactions for a specified Issue + /// + /// https://developer.github.com/v3/reactions/#list-reactions-for-an-issue + /// The owner of the repository + /// The name of the repository + /// The issue id + public IObservable GetAll(string owner, string name, int number) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + return _connection.GetAndFlattenAllPages(ApiUrls.IssueReactions(owner, name, number), null, AcceptHeaders.ReactionsPreview); + } + + /// + /// List reactions for a specified Issue. + /// + /// https://developer.github.com/v3/reactions/#list-reactions-for-an-issue + /// The ID of the repository + /// The issue id + public IObservable GetAll(int repositoryId, int number) + { + return _connection.GetAndFlattenAllPages(ApiUrls.IssueReactions(repositoryId, number), null, AcceptHeaders.ReactionsPreview); + } + /// /// Creates a reaction for a specified Issue /// @@ -25,7 +57,6 @@ namespace Octokit.Reactive /// The name of the repository /// The issue id /// The reaction to create - /// public IObservable Create(string owner, string name, int number, NewReaction reaction) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); @@ -36,19 +67,17 @@ namespace Octokit.Reactive } /// - /// List reactions for a specified Issue + /// Creates a reaction for a specified Issue. /// - /// https://developer.github.com/v3/reactions/#list-reactions-for-an-issue - /// The owner of the repository - /// The name of the repository - /// The issue id - /// - public IObservable GetAll(string owner, string name, int number) + /// https://developer.github.com/v3/reactions/#create-reaction-for-an-issue + /// The ID of the repository + /// The issue id + /// The reaction to create + public IObservable Create(int repositoryId, int number, NewReaction reaction) { - Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); - Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(reaction, "reaction"); - return _connection.GetAndFlattenAllPages(ApiUrls.IssueReactions(owner, name, number), null, AcceptHeaders.ReactionsPreview); + return _client.Create(repositoryId, number, reaction).ToObservable(); } } } diff --git a/Octokit.Tests.Integration/Clients/IssueReactionsClientTests.cs b/Octokit.Tests.Integration/Clients/IssueReactionsClientTests.cs index e6b9b806..cb684dbb 100644 --- a/Octokit.Tests.Integration/Clients/IssueReactionsClientTests.cs +++ b/Octokit.Tests.Integration/Clients/IssueReactionsClientTests.cs @@ -1,8 +1,8 @@ -using Octokit; +using System; +using System.Threading.Tasks; +using Octokit; using Octokit.Tests.Integration; using Octokit.Tests.Integration.Helpers; -using System; -using System.Threading.Tasks; using Xunit; public class IssueReactionsClientTests @@ -16,11 +16,49 @@ public class IssueReactionsClientTests public TheCreateReactionMethod() { _github = Helper.GetAuthenticatedClient(); - var repoName = Helper.MakeNameWithTimestamp("public-repo"); + _issuesClient = _github.Issue; + + var repoName = Helper.MakeNameWithTimestamp("public-repo"); _context = _github.CreateRepositoryContext(new NewRepository(repoName)).Result; } + [IntegrationTest] + public async Task CanListReactions() + { + var newIssue = new NewIssue("a test issue") { Body = "A new unassigned issue" }; + var issue = await _issuesClient.Create(_context.RepositoryOwner, _context.RepositoryName, newIssue); + + Assert.NotNull(issue); + + var issueReaction = await _github.Reaction.Issue.Create(_context.RepositoryOwner, _context.RepositoryName, issue.Number, new NewReaction(ReactionType.Heart)); + + var issueReactions = await _github.Reaction.Issue.GetAll(_context.RepositoryOwner, _context.RepositoryName, issue.Number); + + Assert.NotEmpty(issueReactions); + + Assert.Equal(issueReaction.Id, issueReactions[0].Id); + Assert.Equal(issueReaction.Content, issueReactions[0].Content); + } + + [IntegrationTest] + public async Task CanListReactionsWithRepositoryId() + { + var newIssue = new NewIssue("a test issue") { Body = "A new unassigned issue" }; + var issue = await _issuesClient.Create(_context.RepositoryOwner, _context.RepositoryName, newIssue); + + Assert.NotNull(issue); + + var issueReaction = await _github.Reaction.Issue.Create(_context.RepositoryOwner, _context.RepositoryName, issue.Number, new NewReaction(ReactionType.Heart)); + + var issueReactions = await _github.Reaction.Issue.GetAll(_context.Repository.Id, issue.Number); + + Assert.NotEmpty(issueReactions); + + Assert.Equal(issueReaction.Id, issueReactions[0].Id); + Assert.Equal(issueReaction.Content, issueReactions[0].Content); + } + [IntegrationTest] public async Task CanCreateReaction() { @@ -41,10 +79,28 @@ public class IssueReactionsClientTests } } + [IntegrationTest] + public async Task CanCreateReactionWithRepositoryId() + { + var newIssue = new NewIssue("a test issue") { Body = "A new unassigned issue" }; + var issue = await _issuesClient.Create(_context.RepositoryOwner, _context.RepositoryName, newIssue); + + Assert.NotNull(issue); + + var issueReaction = await _github.Reaction.Issue.Create(_context.Repository.Id, issue.Number, new NewReaction(ReactionType.Heart)); + + Assert.NotNull(issueReaction); + + Assert.IsType(issueReaction); + + Assert.Equal(ReactionType.Heart, issueReaction.Content); + + Assert.Equal(issue.User.Id, issueReaction.User.Id); + } + public void Dispose() { _context.Dispose(); } } } - diff --git a/Octokit.Tests/Clients/IssueReactionsClientTests.cs b/Octokit.Tests/Clients/IssueReactionsClientTests.cs index 43c86aa3..3c0ab6be 100644 --- a/Octokit.Tests/Clients/IssueReactionsClientTests.cs +++ b/Octokit.Tests/Clients/IssueReactionsClientTests.cs @@ -1,6 +1,6 @@ -using NSubstitute; -using System; +using System; using System.Threading.Tasks; +using NSubstitute; using Xunit; namespace Octokit.Tests.Clients @@ -22,24 +22,35 @@ namespace Octokit.Tests.Clients public async Task RequestsCorrectUrl() { var connection = Substitute.For(); - var client = new ReactionsClient(connection); + var client = new IssueReactionsClient(connection); - client.Issue.GetAll("fake", "repo", 42); + await client.GetAll("fake", "repo", 42); connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/issues/42/reactions"), "application/vnd.github.squirrel-girl-preview"); } [Fact] - public async Task EnsuresArgumentsNotNull() + public async Task RequestsCorrectUrlWithRepositoryId() + { + var connection = Substitute.For(); + var client = new IssueReactionsClient(connection); + + await client.GetAll(1, 42); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "repositories/1/issues/42/reactions"), "application/vnd.github.squirrel-girl-preview"); + } + + [Fact] + public async Task EnsuresNonNullArguments() { var connection = Substitute.For(); var client = new ReactionsClient(connection); - await Assert.ThrowsAsync(() => client.Issue.Create(null, "name", 1, new NewReaction(ReactionType.Heart))); - await Assert.ThrowsAsync(() => client.Issue.Create("", "name", 1, new NewReaction(ReactionType.Heart))); - await Assert.ThrowsAsync(() => client.Issue.Create("owner", null, 1, new NewReaction(ReactionType.Heart))); - await Assert.ThrowsAsync(() => client.Issue.Create("owner", "", 1, new NewReaction(ReactionType.Heart))); - await Assert.ThrowsAsync(() => client.Issue.Create("owner", "name", 1, null)); + await Assert.ThrowsAsync(() => client.Issue.GetAll(null, "name", 1)); + await Assert.ThrowsAsync(() => client.Issue.GetAll("owner", null, 1)); + + await Assert.ThrowsAsync(() => client.Issue.GetAll("", "name", 1)); + await Assert.ThrowsAsync(() => client.Issue.GetAll("owner", "", 1)); } } @@ -50,12 +61,41 @@ namespace Octokit.Tests.Clients { NewReaction newReaction = new NewReaction(ReactionType.Heart); + var connection = Substitute.For(); + var client = new IssueReactionsClient(connection); + + client.Create("fake", "repo", 1, newReaction); + + connection.Received().Post(Arg.Is(u => u.ToString() == "repos/fake/repo/issues/1/reactions"), newReaction, "application/vnd.github.squirrel-girl-preview"); + } + + [Fact] + public void RequestsCorrectUrlWithRepositoryId() + { + NewReaction newReaction = new NewReaction(ReactionType.Heart); + + var connection = Substitute.For(); + var client = new IssueReactionsClient(connection); + + client.Create(1, 1, newReaction); + + connection.Received().Post(Arg.Is(u => u.ToString() == "repositories/1/issues/1/reactions"), newReaction, "application/vnd.github.squirrel-girl-preview"); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { var connection = Substitute.For(); var client = new ReactionsClient(connection); - client.Issue.Create("fake", "repo", 1, newReaction); + await Assert.ThrowsAsync(() => client.Issue.Create(null, "name", 1, new NewReaction(ReactionType.Heart))); + await Assert.ThrowsAsync(() => client.Issue.Create("owner", null, 1, new NewReaction(ReactionType.Heart))); + await Assert.ThrowsAsync(() => client.Issue.Create("owner", "name", 1, null)); - connection.Received().Post(Arg.Is(u => u.ToString() == "repos/fake/repo/issues/1/reactions"), Arg.Any(), "application/vnd.github.squirrel-girl-preview"); + await Assert.ThrowsAsync(() => client.Issue.Create(1, 1, null)); + + await Assert.ThrowsAsync(() => client.Issue.Create("", "name", 1, new NewReaction(ReactionType.Heart))); + await Assert.ThrowsAsync(() => client.Issue.Create("owner", "", 1, new NewReaction(ReactionType.Heart))); } } } diff --git a/Octokit.Tests/Reactive/ObservableIssueReactionsClientTests.cs b/Octokit.Tests/Reactive/ObservableIssueReactionsClientTests.cs index 08d51994..1e476494 100644 --- a/Octokit.Tests/Reactive/ObservableIssueReactionsClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableIssueReactionsClientTests.cs @@ -1,6 +1,6 @@ -using NSubstitute; +using System; +using NSubstitute; using Octokit.Reactive; -using System; using Xunit; namespace Octokit.Tests.Reactive @@ -18,33 +18,37 @@ namespace Octokit.Tests.Reactive public class TheGetAllMethod { - private readonly IGitHubClient _githubClient; - private readonly IObservableReactionsClient _client; - private const string owner = "owner"; - private const string name = "name"; - - public TheGetAllMethod() - { - _githubClient = Substitute.For(); - _client = new ObservableReactionsClient(_githubClient); - } - [Fact] public void RequestsCorrectUrl() { - _client.Issue.GetAll("fake", "repo", 42); - _githubClient.Received().Reaction.Issue.GetAll("fake", "repo", 42); + var gitHubClient = Substitute.For(); + var client = new ObservableIssueReactionsClient(gitHubClient); + + client.GetAll("fake", "repo", 42); + gitHubClient.Received().Reaction.Issue.GetAll("fake", "repo", 42); } [Fact] - public void EnsuresArgumentsNotNull() + public void RequestsCorrectUrlWithRepositoryId() { + var gitHubClient = Substitute.For(); + var client = new ObservableIssueReactionsClient(gitHubClient); - Assert.Throws(() => _client.Issue.Create(null, "name", 1, new NewReaction(ReactionType.Heart))); - Assert.Throws(() => _client.Issue.Create("", "name", 1, new NewReaction(ReactionType.Heart))); - Assert.Throws(() => _client.Issue.Create("owner", null, 1, new NewReaction(ReactionType.Heart))); - Assert.Throws(() => _client.Issue.Create("owner", "", 1, new NewReaction(ReactionType.Heart))); - Assert.Throws(() => _client.Issue.Create("owner", "name", 1, null)); + client.GetAll(1, 42); + gitHubClient.Received().Reaction.Issue.GetAll(1, 42); + } + + [Fact] + public void EnsuresNonNullArguments() + { + var gitHubClient = Substitute.For(); + var client = new ObservableIssueReactionsClient(gitHubClient); + + Assert.Throws(() => client.GetAll(null, "name", 1)); + Assert.Throws(() => client.GetAll("owner", null, 1)); + + Assert.Throws(() => client.GetAll("", "name", 1)); + Assert.Throws(() => client.GetAll("owner", "", 1)); } } @@ -58,8 +62,37 @@ namespace Octokit.Tests.Reactive var newReaction = new NewReaction(ReactionType.Confused); client.Issue.Create("fake", "repo", 1, newReaction); + githubClient.Received().Reaction.Issue.Create("fake", "repo", 1, newReaction); } + + [Fact] + public void RequestsCorrectUrlWithRepositoryId() + { + var githubClient = Substitute.For(); + var client = new ObservableReactionsClient(githubClient); + var newReaction = new NewReaction(ReactionType.Confused); + + client.Issue.Create(1, 1, newReaction); + + githubClient.Received().Reaction.Issue.Create(1, 1, newReaction); + } + + [Fact] + public void EnsuresNonNullArguments() + { + var gitHubClient = Substitute.For(); + var client = new ObservableIssueReactionsClient(gitHubClient); + + Assert.Throws(() => client.Create(null, "name", 1, new NewReaction(ReactionType.Heart))); + Assert.Throws(() => client.Create("owner", null, 1, new NewReaction(ReactionType.Heart))); + Assert.Throws(() => client.Create("owner", "name", 1, null)); + + Assert.Throws(() => client.Create(1, 1, null)); + + Assert.Throws(() => client.Create("", "name", 1, new NewReaction(ReactionType.Heart))); + Assert.Throws(() => client.Create("owner", "", 1, new NewReaction(ReactionType.Heart))); + } } } } diff --git a/Octokit/Clients/IIssueReactionsClient.cs b/Octokit/Clients/IIssueReactionsClient.cs index 478e0b2b..81f95479 100644 --- a/Octokit/Clients/IIssueReactionsClient.cs +++ b/Octokit/Clients/IIssueReactionsClient.cs @@ -3,6 +3,12 @@ using System.Threading.Tasks; namespace Octokit { + /// + /// A client for GitHub's Reactions API. + /// + /// + /// See the Reactions API documentation for more information. + /// public interface IIssueReactionsClient { /// @@ -12,9 +18,16 @@ namespace Octokit /// The owner of the repository /// The name of the repository /// The issue id - /// Task> GetAll(string owner, string name, int number); + /// + /// Get all reactions for a specified Issue + /// + /// https://developer.github.com/v3/reactions/#list-reactions-for-an-issue + /// The ID of the repository + /// The issue id + Task> GetAll(int repositoryId, int number); + /// /// Creates a reaction for a specified Issue /// @@ -23,7 +36,15 @@ namespace Octokit /// The name of the repository /// The issue id /// The reaction to create - /// Task Create(string owner, string name, int number, NewReaction reaction); + + /// + /// Creates a reaction for a specified Issue + /// + /// https://developer.github.com/v3/reactions/#create-reaction-for-an-issue + /// The ID of the repository + /// The issue id + /// The reaction to create + Task Create(int repositoryId, int number, NewReaction reaction); } } diff --git a/Octokit/Clients/IssueReactionsClient.cs b/Octokit/Clients/IssueReactionsClient.cs index d630bfce..e3652a04 100644 --- a/Octokit/Clients/IssueReactionsClient.cs +++ b/Octokit/Clients/IssueReactionsClient.cs @@ -1,9 +1,14 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading.Tasks; namespace Octokit { + /// + /// A client for GitHub's Reactions API. + /// + /// + /// See the Reactions API documentation for more information. + /// public class IssueReactionsClient : ApiClient, IIssueReactionsClient { public IssueReactionsClient(IApiConnection apiConnection) @@ -11,15 +16,40 @@ namespace Octokit { } + /// + /// Get all reactions for a specified Issue + /// + /// https://developer.github.com/v3/reactions/#list-reactions-for-an-issue + /// The owner of the repository + /// The name of the repository + /// The issue id + public Task> GetAll(string owner, string name, int number) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + return ApiConnection.GetAll(ApiUrls.IssueReactions(owner, name, number), AcceptHeaders.ReactionsPreview); + } + + /// + /// Get all reactions for a specified Issue + /// + /// https://developer.github.com/v3/reactions/#list-reactions-for-an-issue + /// The ID of the repository + /// The issue id + public Task> GetAll(int repositoryId, int number) + { + return ApiConnection.GetAll(ApiUrls.IssueReactions(repositoryId, number), AcceptHeaders.ReactionsPreview); + } + /// /// Creates a reaction for a specified Issue /// - /// https://developer.github.com/v3/reactions/#create-reactions-for-an-issue + /// https://developer.github.com/v3/reactions/#create-reaction-for-an-issue /// The owner of the repository /// The name of the repository /// The issue id /// The reaction to create - /// public Task Create(string owner, string name, int number, NewReaction reaction) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); @@ -30,19 +60,17 @@ namespace Octokit } /// - /// Get all reactions for a specified Issue + /// Creates a reaction for a specified Issue /// - /// https://developer.github.com/v3/reactions/#list-reactions-for-an-issue - /// The owner of the repository - /// The name of the repository - /// The issue id - /// - public Task> GetAll(string owner, string name, int number) + /// https://developer.github.com/v3/reactions/#create-reaction-for-an-issue + /// The ID of the repository + /// The issue id + /// The reaction to create + public Task Create(int repositoryId, int number, NewReaction reaction) { - Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); - Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(reaction, "reaction"); - return ApiConnection.GetAll(ApiUrls.IssueReactions(owner, name, number), AcceptHeaders.ReactionsPreview); + return ApiConnection.Post(ApiUrls.IssueReactions(repositoryId, number), reaction, AcceptHeaders.ReactionsPreview); } } } diff --git a/Octokit/Helpers/ApiUrls.cs b/Octokit/Helpers/ApiUrls.cs index 789849f0..d4c151f9 100644 --- a/Octokit/Helpers/ApiUrls.cs +++ b/Octokit/Helpers/ApiUrls.cs @@ -330,6 +330,17 @@ namespace Octokit return "repos/{0}/{1}/issues/{2}/reactions".FormatUri(owner, name, number); } + /// + /// Returns the for the reaction of a specified issue. + /// + /// The ID of the repository + /// The issue number + /// + public static Uri IssueReactions(int repositoryId, int number) + { + return "repositories/{0}/issues/{1}/reactions".FormatUri(repositoryId, number); + } + /// /// Returns the for the comments for all issues in a specific repo. ///