diff --git a/Octokit.Reactive/Clients/IObservableRepositoriesClient.cs b/Octokit.Reactive/Clients/IObservableRepositoriesClient.cs index e8f914b0..83f612de 100644 --- a/Octokit.Reactive/Clients/IObservableRepositoriesClient.cs +++ b/Octokit.Reactive/Clients/IObservableRepositoriesClient.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Reactive; @@ -149,6 +150,18 @@ namespace Octokit.Reactive /// IObservableRepositoryCommentsClient RepositoryComments { get; } + /// + /// A client for GitHub's Repository Hooks API. + /// + /// See Hooks API documentation for more information. + IObservableRepositoryHooksClient Hooks { get; } + + /// + /// A client for GitHub's Repository Forks API. + /// + /// See Forks API documentation for more information. + IObservableRepositoryForksClient Forks { get; } + /// /// Client for GitHub's Repository Contents API. /// diff --git a/Octokit.Reactive/Clients/IObservableRepositoryForksClient.cs b/Octokit.Reactive/Clients/IObservableRepositoryForksClient.cs new file mode 100644 index 00000000..4131b0e5 --- /dev/null +++ b/Octokit.Reactive/Clients/IObservableRepositoryForksClient.cs @@ -0,0 +1,23 @@ +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Octokit.Reactive +{ + public interface IObservableRepositoryForksClient + { + /// + /// Gets the list of forks defined for a repository + /// + /// See API documentation for more information. + /// + [SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Get", Justification = "This is ok; we're matching HTTP verbs not keyworks")] + IObservable Get(string owner, string repositoryName); + + /// + /// Creates a fork for a repository. Specify organization in the fork parameter to create for an organization. + /// + /// See API documentation for more information. + /// + IObservable Create(string owner, string repositoryName, NewRepositoryFork fork); + } +} diff --git a/Octokit.Reactive/Clients/IObservableRepositoryHooksClient.cs b/Octokit.Reactive/Clients/IObservableRepositoryHooksClient.cs new file mode 100644 index 00000000..e8089f61 --- /dev/null +++ b/Octokit.Reactive/Clients/IObservableRepositoryHooksClient.cs @@ -0,0 +1,57 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Reactive; + +namespace Octokit.Reactive +{ + public interface IObservableRepositoryHooksClient + { + /// + /// Gets the list of hooks defined for a repository + /// + /// See API documentation for more information. + /// + [SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Get", Justification = "This is ok; we're matching HTTP verbs not keyworks")] + IObservable Get(string owner, string repositoryName); + + /// + /// Gets a single hook defined for a repository by id + /// + /// See API documentation for more information. + /// + IObservable GetById(string owner, string repositoryName, int hookId); + + /// + /// Creates a hook for a repository + /// + /// See API documentation for more information. + /// + IObservable Create(string owner, string repositoryName, NewRepositoryHook hook); + + /// + /// Edits a hook for a repository + /// + /// See API documentation for more information. + /// + IObservable Edit(string owner, string repositoryName, int hookId, EditRepositoryHook hook); + + /// + /// Tests a hook for a repository + /// + /// See API documentation for more information. + /// This will trigger the hook with the latest push to the current repository if the hook is subscribed to push events. If the hook + /// is not subscribed to push events, the server will respond with 204 but no test POST will be generated. + /// + IObservable Test(string owner, string repositoryName, int hookId); + + /// + /// Deletes a hook for a repository + /// + /// + /// + /// + /// See API documentation for more information. + /// + IObservable Delete(string owner, string repositoryName, int hookId); + } +} \ No newline at end of file diff --git a/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs b/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs index a942c2a8..78c59d27 100644 --- a/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs +++ b/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs @@ -20,6 +20,8 @@ namespace Octokit.Reactive _client = client.Repository; _connection = client.Connection; CommitStatus = new ObservableCommitStatusClient(client); + Hooks = new ObservableRepositoryHooksClient(client); + Forks = new ObservableRepositoryForksClient(client); RepoCollaborators = new ObservableRepoCollaboratorsClient(client); Deployment = new ObservableDeploymentsClient(client); Statistics = new ObservableStatisticsClient(client); @@ -217,6 +219,18 @@ namespace Octokit.Reactive /// public IObservableRepositoryCommentsClient RepositoryComments { get; private set; } + /// + /// A client for GitHub's Repository Hooks API. + /// + /// See Hooks API documentation for more information. + public IObservableRepositoryHooksClient Hooks { get; private set; } + + /// + /// A client for GitHub's Repository Forks API. + /// + /// See Forks API documentation for more information. + public IObservableRepositoryForksClient Forks { get; private set; } + /// /// Client for GitHub's Repository Contents API. /// diff --git a/Octokit.Reactive/Clients/ObservableRepositoryForksClient.cs b/Octokit.Reactive/Clients/ObservableRepositoryForksClient.cs new file mode 100644 index 00000000..bba8e985 --- /dev/null +++ b/Octokit.Reactive/Clients/ObservableRepositoryForksClient.cs @@ -0,0 +1,50 @@ +using System; +using System.Reactive.Threading.Tasks; +using Octokit.Reactive.Internal; + +namespace Octokit.Reactive +{ + public class ObservableRepositoryForksClient : IObservableRepositoryForksClient + { + readonly IRepositoryForksClient _client; + readonly IConnection _connection; + + /// + /// Initializes a new GitHub Repos Fork API client. + /// + /// + public ObservableRepositoryForksClient(IGitHubClient client) + { + Ensure.ArgumentNotNull(client, "client"); + _client = client.Repository.Forks; + _connection = client.Connection; + } + + /// + /// Gets the list of forks defined for a repository + /// + /// See API documentation for more information. + /// + public IObservable Get(string owner, string repositoryName) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(repositoryName, "repositoryName"); + + return _connection.GetAndFlattenAllPages(ApiUrls.RepositoryForks(owner, repositoryName)); + } + + /// + /// Creates a fork for a repository. Specify organization in the fork parameter to create for an organization. + /// + /// See API documentation for more information. + /// + public IObservable Create(string owner, string repositoryName, NewRepositoryFork fork) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(repositoryName, "repositoryName"); + Ensure.ArgumentNotNull(fork, "fork"); + + return _client.Create(owner, repositoryName, fork).ToObservable(); + } + } +} \ No newline at end of file diff --git a/Octokit.Reactive/Clients/ObservableRepositoryHooksClient.cs b/Octokit.Reactive/Clients/ObservableRepositoryHooksClient.cs new file mode 100644 index 00000000..8b8d5fa3 --- /dev/null +++ b/Octokit.Reactive/Clients/ObservableRepositoryHooksClient.cs @@ -0,0 +1,106 @@ +using System; +using System.Reactive; +using System.Reactive.Threading.Tasks; +using Octokit.Reactive.Internal; + +namespace Octokit.Reactive +{ + public class ObservableRepositoryHooksClient : IObservableRepositoryHooksClient + { + readonly IRepositoryHooksClient _client; + readonly IConnection _connection; + + public ObservableRepositoryHooksClient(IGitHubClient client) + { + Ensure.ArgumentNotNull(client, "client"); + + _client = client.Repository.Hooks; + _connection = client.Connection; + } + + /// + /// Gets the list of hooks defined for a repository + /// + /// See API documentation for more information. + /// + public IObservable Get(string owner, string repositoryName) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(repositoryName, "repositoryName"); + + return _connection.GetAndFlattenAllPages(ApiUrls.RepositoryHooks(owner, repositoryName)); + } + + /// + /// Gets a single hook defined for a repository by id + /// + /// See API documentation for more information. + /// + public IObservable GetById(string owner, string repositoryName, int hookId) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(repositoryName, "repositoryName"); + + return _client.GetById(owner, repositoryName, hookId).ToObservable(); + } + + /// + /// Creates a hook for a repository + /// + /// See API documentation for more information. + /// + public IObservable Create(string owner, string repositoryName, NewRepositoryHook hook) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(repositoryName, "repositoryName"); + Ensure.ArgumentNotNull(hook, "hook"); + + return _client.Create(owner, repositoryName, hook).ToObservable(); + } + + /// + /// Edits a hook for a repository + /// + /// See API documentation for more information. + /// + public IObservable Edit(string owner, string repositoryName, int hookId, EditRepositoryHook hook) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(repositoryName, "repositoryName"); + Ensure.ArgumentNotNull(hook, "hook"); + + return _client.Edit(owner, repositoryName, hookId, hook).ToObservable(); + } + + /// + /// Tests a hook for a repository + /// + /// See API documentation for more information. + /// This will trigger the hook with the latest push to the current repository if the hook is subscribed to push events. If the hook + /// is not subscribed to push events, the server will respond with 204 but no test POST will be generated. + /// + public IObservable Test(string owner, string repositoryName, int hookId) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(repositoryName, "repositoryName"); + + return _client.Test(owner, repositoryName, hookId).ToObservable(); + } + + /// + /// Deletes a hook for a repository + /// + /// + /// + /// + /// See API documentation for more information. + /// + public IObservable Delete(string owner, string repositoryName, int hookId) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(repositoryName, "repositoryName"); + + return _client.Delete(owner, repositoryName, hookId).ToObservable(); + } + } +} diff --git a/Octokit.Reactive/Octokit.Reactive-Mono.csproj b/Octokit.Reactive/Octokit.Reactive-Mono.csproj index 25f81385..3fb661c4 100644 --- a/Octokit.Reactive/Octokit.Reactive-Mono.csproj +++ b/Octokit.Reactive/Octokit.Reactive-Mono.csproj @@ -148,6 +148,10 @@ + + + + diff --git a/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj b/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj index e663b82d..52e6fd19 100644 --- a/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj +++ b/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj @@ -157,6 +157,10 @@ + + + + diff --git a/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj b/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj index a1441ae8..66d08a2a 100644 --- a/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj +++ b/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj @@ -152,6 +152,10 @@ + + + + diff --git a/Octokit.Reactive/Octokit.Reactive.csproj b/Octokit.Reactive/Octokit.Reactive.csproj index 19db4fc6..dd48a648 100644 --- a/Octokit.Reactive/Octokit.Reactive.csproj +++ b/Octokit.Reactive/Octokit.Reactive.csproj @@ -85,6 +85,8 @@ + + @@ -145,6 +147,7 @@ + @@ -156,6 +159,7 @@ + diff --git a/Octokit.Tests/Clients/RepositoryForksClientTests.cs b/Octokit.Tests/Clients/RepositoryForksClientTests.cs new file mode 100644 index 00000000..d640ef88 --- /dev/null +++ b/Octokit.Tests/Clients/RepositoryForksClientTests.cs @@ -0,0 +1,71 @@ +using System; +using System.Threading.Tasks; +using NSubstitute; +using Octokit.Tests.Helpers; +using Xunit; + +namespace Octokit.Tests.Clients +{ + public class RepositoryForksClientTests + { + public class TheGetMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new RepositoriesClient(connection); + + client.Forks.Get("fake", "repo"); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/forks")); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new RepositoriesClient(Substitute.For()); + + await AssertEx.Throws(async () => await client.Forks.Get(null, "name")); + await AssertEx.Throws(async () => await client.Forks.Get("owner", null)); + } + } + + public class TheCreateMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new RepositoriesClient(connection); + var newRepositoryFork = new NewRepositoryFork(); + + client.Forks.Create("fake", "repo", newRepositoryFork); + + connection.Received().Post(Arg.Is(u => u.ToString() == "repos/fake/repo/forks"), newRepositoryFork); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new RepositoriesClient(Substitute.For()); + + await AssertEx.Throws(async () => await client.Forks.Create(null, "name", new NewRepositoryFork())); + await AssertEx.Throws(async () => await client.Forks.Create("owner", null, new NewRepositoryFork())); + await AssertEx.Throws(async () => await client.Forks.Create("owner", "name", null)); + } + + [Fact] + public void UsesTheSuppliedHook() + { + var connection = Substitute.For(); + var client = new RepositoriesClient(connection); + var newRepositoryFork = new NewRepositoryFork { Organization = "aName" }; + + client.Forks.Create("owner", "repo", newRepositoryFork); + + connection.Received().Post(Arg.Any(), newRepositoryFork); + } + } + } +} \ No newline at end of file diff --git a/Octokit.Tests/Clients/RepositoryHooksClientTest.cs b/Octokit.Tests/Clients/RepositoryHooksClientTest.cs new file mode 100644 index 00000000..c94dc0a4 --- /dev/null +++ b/Octokit.Tests/Clients/RepositoryHooksClientTest.cs @@ -0,0 +1,188 @@ +using System; +using System.Threading.Tasks; +using NSubstitute; +using Octokit.Tests.Helpers; +using Xunit; + +namespace Octokit.Tests.Clients +{ + public class RepositoryHooksClientTests + { + public class TheGetMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new RepositoriesClient(connection); + + client.Hooks.Get("fake", "repo"); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/hooks")); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new RepositoriesClient(Substitute.For()); + + await AssertEx.Throws(async () => await client.Hooks.Get(null, "name")); + await AssertEx.Throws(async () => await client.Hooks.Get("owner", null)); + } + } + + public class TheGetByIdMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new RepositoriesClient(connection); + + client.Hooks.GetById("fake", "repo", 12345678); + + connection.Received().Get(Arg.Is(u => u.ToString() == "repos/fake/repo/hooks/12345678"), null); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new RepositoriesClient(Substitute.For()); + + await AssertEx.Throws(async () => await client.Hooks.GetById(null, "name", 123)); + await AssertEx.Throws(async () => await client.Hooks.GetById("owner", null, 123)); + } + } + + public class TheCreateMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new RepositoriesClient(connection); + var hook = new NewRepositoryHook(); + + client.Hooks.Create("fake", "repo", hook); + + connection.Received().Post(Arg.Is(u => u.ToString() == "repos/fake/repo/hooks"), hook); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new RepositoriesClient(Substitute.For()); + + await AssertEx.Throws(async () => await client.Hooks.Create(null, "name", new NewRepositoryHook())); + await AssertEx.Throws(async () => await client.Hooks.Create("owner", null, new NewRepositoryHook())); + await AssertEx.Throws(async () => await client.Hooks.Create("owner", "name", null)); + } + + [Fact] + public void UsesTheSuppliedHook() + { + var connection = Substitute.For(); + var client = new RepositoriesClient(connection); + var newRepositoryHook = new NewRepositoryHook { Name = "aName" }; + + client.Hooks.Create("owner", "repo", newRepositoryHook); + + connection.Received().Post(Arg.Any(), newRepositoryHook); + } + } + + public class TheEditMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new RepositoriesClient(connection); + var hook = new EditRepositoryHook(); + + client.Hooks.Edit("fake", "repo", 12345678, hook); + + connection.Received().Patch(Arg.Is(u => u.ToString() == "repos/fake/repo/hooks/12345678"), hook); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new RepositoriesClient(Substitute.For()); + + await AssertEx.Throws(async () => await client.Hooks.Edit(null, "name", 12345678, new EditRepositoryHook())); + await AssertEx.Throws(async () => await client.Hooks.Edit("owner", null, 12345678, new EditRepositoryHook())); + await AssertEx.Throws(async () => await client.Hooks.Edit("owner", "name", 12345678, null)); + } + + [Fact] + public void UsesTheSuppliedHook() + { + var connection = Substitute.For(); + var client = new RepositoriesClient(connection); + var editRepositoryHook = new EditRepositoryHook() { Active = false }; + + client.Hooks.Edit("owner", "repo", 12345678, editRepositoryHook); + + connection.Received().Patch(Arg.Any(), editRepositoryHook); + } + } + + public class TheTestMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new RepositoriesClient(connection); + + client.Hooks.Test("fake", "repo", 12345678); + + connection.Received().Post(Arg.Is(u => u.ToString() == "repos/fake/repo/hooks/12345678/tests"), Arg.Any()); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new RepositoriesClient(Substitute.For()); + + await AssertEx.Throws(async () => await client.Hooks.Test(null, "name", 12345678)); + await AssertEx.Throws(async () => await client.Hooks.Test("owner", null, 12345678)); + } + + [Fact] + public void CallsPost() + { + var connection = Substitute.For(); + var client = new RepositoriesClient(connection); + + client.Hooks.Test("owner", "repo", 12345678); + + connection.Received().Post(Arg.Any(), Arg.Any()); + } + } + + public class TheDeleteMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new RepositoriesClient(connection); + + client.Hooks.Delete("fake", "repo", 12345678); + + connection.Received().Delete(Arg.Is(u => u.ToString() == "repos/fake/repo/hooks/12345678")); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new RepositoriesClient(Substitute.For()); + + await AssertEx.Throws(async () => await client.Hooks.Delete(null, "name", 12345678)); + await AssertEx.Throws(async () => await client.Hooks.Delete("owner", null, 12345678)); + } + } + } +} diff --git a/Octokit.Tests/OctoKit.Tests-NetCore45.csproj b/Octokit.Tests/OctoKit.Tests-NetCore45.csproj index 304e2083..963ae8ea 100644 --- a/Octokit.Tests/OctoKit.Tests-NetCore45.csproj +++ b/Octokit.Tests/OctoKit.Tests-NetCore45.csproj @@ -84,6 +84,8 @@ + + diff --git a/Octokit.Tests/Octokit.Tests.csproj b/Octokit.Tests/Octokit.Tests.csproj index 2984c8ba..b3d33ec2 100644 --- a/Octokit.Tests/Octokit.Tests.csproj +++ b/Octokit.Tests/Octokit.Tests.csproj @@ -102,6 +102,8 @@ + + diff --git a/Octokit/Clients/IRepositoriesClient.cs b/Octokit/Clients/IRepositoriesClient.cs index a6c8cdc0..648e9415 100644 --- a/Octokit/Clients/IRepositoriesClient.cs +++ b/Octokit/Clients/IRepositoriesClient.cs @@ -200,6 +200,18 @@ namespace Octokit /// ICommitStatusClient CommitStatus { get; } + /// + /// A client for GitHub's Repository Hooks API. + /// + /// See Hooks API documentation for more information. + IRepositoryHooksClient Hooks { get; } + + /// + /// A client for GitHub's Repository Forks API. + /// + /// See Forks API documentation for more information. + IRepositoryForksClient Forks { get; } + /// /// A client for GitHub's Repo Collaborators. /// diff --git a/Octokit/Clients/IRepositoryForksClient.cs b/Octokit/Clients/IRepositoryForksClient.cs new file mode 100644 index 00000000..049e2969 --- /dev/null +++ b/Octokit/Clients/IRepositoryForksClient.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Threading.Tasks; + +namespace Octokit +{ + public interface IRepositoryForksClient + { + /// + /// Gets the list of forks defined for a repository + /// + /// See API documentation for more information. + /// + [SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Get", Justification = "This is ok; we're matching HTTP verbs not keyworks")] + Task> Get(string owner, string repositoryName); + + /// + /// Creates a fork for a repository. Specify organization in the fork parameter to create for an organization. + /// + /// See API documentation for more information. + /// + Task Create(string owner, string repositoryName, NewRepositoryFork fork); + } +} diff --git a/Octokit/Clients/IRepositoryHooksClient.cs b/Octokit/Clients/IRepositoryHooksClient.cs new file mode 100644 index 00000000..c9ba580e --- /dev/null +++ b/Octokit/Clients/IRepositoryHooksClient.cs @@ -0,0 +1,60 @@ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Threading.Tasks; + +namespace Octokit +{ + public interface IRepositoryHooksClient + { + /// + /// Gets the list of hooks defined for a repository + /// + /// See API documentation for more information. + /// + [SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Get", Justification = "This is ok; we're matching HTTP verbs not keyworks")] + Task> Get(string owner, string repositoryName); + + /// + /// Gets a single hook by Id + /// + /// + /// + /// + /// + /// See API documentation for more information. + Task GetById(string owner, string repositoryName, int hookId); + + /// + /// Creates a hook for a repository + /// + /// See API documentation for more information. + /// + Task Create(string owner, string repositoryName, NewRepositoryHook hook); + + /// + /// Edits a hook for a repository + /// + /// See API documentation for more information. + /// + Task Edit(string owner, string repositoryName, int hookId, EditRepositoryHook hook); + + /// + /// Tests a hook for a repository + /// + /// See API documentation for more information. + /// This will trigger the hook with the latest push to the current repository if the hook is subscribed to push events. If the hook + /// is not subscribed to push events, the server will respond with 204 but no test POST will be generated. + /// + Task Test(string owner, string repositoryName, int hookId); + + /// + /// Deletes a hook for a repository + /// + /// + /// + /// + /// See API documentation for more information. + /// + Task Delete(string owner, string repositoryName, int hookId); + } +} diff --git a/Octokit/Clients/RepositoriesClient.cs b/Octokit/Clients/RepositoriesClient.cs index b8f68c83..1cb7f0ea 100644 --- a/Octokit/Clients/RepositoriesClient.cs +++ b/Octokit/Clients/RepositoriesClient.cs @@ -23,6 +23,8 @@ namespace Octokit public RepositoriesClient(IApiConnection apiConnection) : base(apiConnection) { CommitStatus = new CommitStatusClient(apiConnection); + Hooks = new RepositoryHooksClient(apiConnection); + Forks = new RepositoryForksClient(apiConnection); RepoCollaborators = new RepoCollaboratorsClient(apiConnection); Statistics = new StatisticsClient(apiConnection); Deployment = new DeploymentsClient(apiConnection); @@ -296,6 +298,25 @@ namespace Octokit /// public ICommitStatusClient CommitStatus { get; private set; } + /// + /// A client for GitHub's Repository Hooks API. + /// + /// See Hooks API documentation for more information. + public IRepositoryHooksClient Hooks + { + get; private set; + } + + /// + /// A client for GitHub's Repository Forks API. + /// + /// See Forks API documentation for more information. + public IRepositoryForksClient Forks + { + get; + private set; + } + /// /// A client for GitHub's Repo Collaborators. /// diff --git a/Octokit/Clients/RepositoryForksClient.cs b/Octokit/Clients/RepositoryForksClient.cs new file mode 100644 index 00000000..aa346aad --- /dev/null +++ b/Octokit/Clients/RepositoryForksClient.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Octokit +{ + public class RepositoryForksClient : ApiClient, IRepositoryForksClient + { + /// + /// Initializes a new GitHub Repos Fork API client. + /// + /// An API connection. + public RepositoryForksClient(IApiConnection apiConnection) : base(apiConnection) + { + } + + /// + /// Gets the list of forks defined for a repository + /// + /// See API documentation for more information. + /// + public Task> Get(string owner, string repositoryName) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(repositoryName, "repositoryName"); + + return ApiConnection.GetAll(ApiUrls.RepositoryForks(owner, repositoryName)); + } + + /// + /// Creates a fork for a repository. Specify organization in the fork parameter to create for an organization. + /// + /// See API documentation for more information. + /// + public Task Create(string owner, string repositoryName, NewRepositoryFork fork) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(repositoryName, "repositoryName"); + Ensure.ArgumentNotNull(fork, "fork"); + + return ApiConnection.Post(ApiUrls.RepositoryForks(owner, repositoryName), fork); + } + } +} \ No newline at end of file diff --git a/Octokit/Clients/RepositoryHooksClient.cs b/Octokit/Clients/RepositoryHooksClient.cs new file mode 100644 index 00000000..b6d98b69 --- /dev/null +++ b/Octokit/Clients/RepositoryHooksClient.cs @@ -0,0 +1,104 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Octokit +{ + public class RepositoryHooksClient : ApiClient, IRepositoryHooksClient + { + /// + /// Initializes a new GitHub Repos API client. + /// + /// An API connection. + public RepositoryHooksClient(IApiConnection apiConnection) : base(apiConnection) + { + } + + /// + /// Gets the list of hooks defined for a repository + /// + /// See API documentation for more information. + /// + public Task> Get(string owner, string repositoryName) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(repositoryName, "repositoryName"); + + return ApiConnection.GetAll(ApiUrls.RepositoryHooks(owner, repositoryName)); + } + + /// + /// Gets a single hook by Id + /// + /// + /// + /// + /// + /// See API documentation for more information. + public Task GetById(string owner, string repositoryName, int hookId) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(repositoryName, "repositoryName"); + + return ApiConnection.Get(ApiUrls.RepositoryHookById(owner, repositoryName, hookId)); + } + + /// + /// Creates a hook for a repository + /// + /// See API documentation for more information. + /// + public Task Create(string owner, string repositoryName, NewRepositoryHook hook) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(repositoryName, "repositoryName"); + Ensure.ArgumentNotNull(hook, "hook"); + + return ApiConnection.Post(ApiUrls.RepositoryHooks(owner, repositoryName), hook); + } + + /// + /// Edits a hook for a repository + /// + /// See API documentation for more information. + /// + public Task Edit(string owner, string repositoryName, int hookId, EditRepositoryHook hook) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(repositoryName, "repositoryName"); + Ensure.ArgumentNotNull(hook, "hook"); + + return ApiConnection.Patch(ApiUrls.RepositoryHookById(owner, repositoryName, hookId), hook); + } + + /// + /// Tests a hook for a repository + /// + /// See API documentation for more information. + /// This will trigger the hook with the latest push to the current repository if the hook is subscribed to push events. If the hook + /// is not subscribed to push events, the server will respond with 204 but no test POST will be generated. + /// + public Task Test(string owner, string repositoryName, int hookId) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(repositoryName, "repositoryName"); + + return ApiConnection.Post(ApiUrls.RepositoryHookTest(owner, repositoryName, hookId), new TestRepositoryHook()); + } + + /// + /// Deletes a hook for a repository + /// + /// + /// + /// + /// See API documentation for more information. + /// + public Task Delete(string owner, string repositoryName, int hookId) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(repositoryName, "repositoryName"); + + return ApiConnection.Delete(ApiUrls.RepositoryHookById(owner, repositoryName, hookId)); + } + } +} \ No newline at end of file diff --git a/Octokit/Helpers/ApiUrls.cs b/Octokit/Helpers/ApiUrls.cs index 192fe138..75604677 100644 --- a/Octokit/Helpers/ApiUrls.cs +++ b/Octokit/Helpers/ApiUrls.cs @@ -556,6 +556,41 @@ namespace Octokit return "repos/{0}/{1}/statuses/{2}".FormatUri(owner, name, reference); } + /// + /// Returns the that lists the repository hooks for the specified reference. + /// + /// The owner of the repository + /// The name of the repository + /// + public static Uri RepositoryHooks(string owner, string repositoryName) + { + return "repos/{0}/{1}/hooks".FormatUri(owner, repositoryName); + } + + /// + /// Returns the that gets the repository hook for the specified reference. + /// + /// The owner of the repository + /// The name of the repository + /// The identifier of the repository hook + /// + public static Uri RepositoryHookById(string owner, string repositoryName, int hookId) + { + return "repos/{0}/{1}/hooks/{2}".FormatUri(owner, repositoryName, hookId); + } + + /// + /// Returns the that can tests a specified repository hook + /// + /// The owner of the repository + /// The name of the repository + /// The identifier of the repository hook + /// + public static Uri RepositoryHookTest(string owner, string repositoryName, int hookId) + { + return "repos/{0}/{1}/hooks/{2}/tests".FormatUri(owner, repositoryName, hookId); + } + /// /// Returns the that lists the commit statuses for the specified reference. /// @@ -580,6 +615,17 @@ namespace Octokit return "repos/{0}/{1}/commits/{2}/status".FormatUri(owner, name, reference); } + /// + /// Returns the that lists the repository forks for the specified reference. + /// + /// The owner of the repository + /// The name of the repository + /// + public static Uri RepositoryForks(string owner, string repositoryName) + { + return "repos/{0}/{1}/forks".FormatUri(owner, repositoryName); + } + /// /// Returns the that lists the watched repositories for the authenticated user. /// diff --git a/Octokit/Models/Request/EditRepositoryHook.cs b/Octokit/Models/Request/EditRepositoryHook.cs new file mode 100644 index 00000000..acff18c0 --- /dev/null +++ b/Octokit/Models/Request/EditRepositoryHook.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class EditRepositoryHook + { + public dynamic Config { get; set; } + public IEnumerable Events { get; set; } + public IEnumerable AddEvents { get; set; } + public IEnumerable RemoveEvents { get; set; } + public bool Active { get; set; } + + internal string DebuggerDisplay + { + get + { + return String.Format(CultureInfo.InvariantCulture, + "Repository Hook: Replacing Events: {0}, Adding Events: {1}, Removing Events: {2}", Events == null ? "no" : string.Join(", ", Events), + AddEvents == null ? "no" : string.Join(", ", AddEvents), + RemoveEvents == null ? "no" : string.Join(", ", RemoveEvents)); + } + } + } +} \ No newline at end of file diff --git a/Octokit/Models/Request/NewRepositoryFork.cs b/Octokit/Models/Request/NewRepositoryFork.cs new file mode 100644 index 00000000..86d97ba8 --- /dev/null +++ b/Octokit/Models/Request/NewRepositoryFork.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class NewRepositoryFork + { + public string Organization { get; set; } + + internal string DebuggerDisplay + { + get + { + return String.Format(CultureInfo.InvariantCulture, + "Repository Hook: Organization: {0}", Organization); + } + } + } +} \ No newline at end of file diff --git a/Octokit/Models/Request/NewRepositoryHook.cs b/Octokit/Models/Request/NewRepositoryHook.cs new file mode 100644 index 00000000..2f9f5ac0 --- /dev/null +++ b/Octokit/Models/Request/NewRepositoryHook.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class NewRepositoryHook + { + public string Name { get; set; } + public dynamic Config { get; set; } + public IEnumerable Events { get; set; } + public bool Active { get; set; } + + internal string DebuggerDisplay + { + get + { + return String.Format(CultureInfo.InvariantCulture, + "Repository Hook: Name: {0}, Events: {1}", Name,string.Join(", ", Events)); + } + } + } +} diff --git a/Octokit/Models/Request/TestRepositoryHook.cs b/Octokit/Models/Request/TestRepositoryHook.cs new file mode 100644 index 00000000..f04f1f70 --- /dev/null +++ b/Octokit/Models/Request/TestRepositoryHook.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Octokit +{ + public class TestRepositoryHook + { + } +} diff --git a/Octokit/Models/Response/RepositoryHook.cs b/Octokit/Models/Response/RepositoryHook.cs new file mode 100644 index 00000000..92e22fdc --- /dev/null +++ b/Octokit/Models/Response/RepositoryHook.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Octokit +{ + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class RepositoryHook + { + public string Url { get; set; } + public DateTimeOffset CreatedAt { get; set; } + public DateTimeOffset UpdatedAt { get; set; } + public string Name { get; set; } + public IEnumerable Events { get; set; } + public bool Active { get; set; } + public dynamic Config { get; set; } + public int Id { get; set; } + + internal string DebuggerDisplay + { + get + { + return String.Format(CultureInfo.InvariantCulture, + "Repository Hook: Name: {0} Url: {1}, Events: {2}", Name, Url, string.Join(", ", Events)); + } + } + } +} diff --git a/Octokit/Models/Response/RepositoryHookConfiguration.cs b/Octokit/Models/Response/RepositoryHookConfiguration.cs new file mode 100644 index 00000000..603967f2 --- /dev/null +++ b/Octokit/Models/Response/RepositoryHookConfiguration.cs @@ -0,0 +1,22 @@ +using System; +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class RepositoryHookConfiguration + { + public string Url { get; set; } + public string ContentType { get; set; } + + internal string DebuggerDisplay + { + get + { + return String.Format(CultureInfo.InvariantCulture, + "Send {0} to {1}", ContentType, Url); + } + } + } +} \ No newline at end of file diff --git a/Octokit/Octokit-Mono.csproj b/Octokit/Octokit-Mono.csproj index 64a01234..a61b2202 100644 --- a/Octokit/Octokit-Mono.csproj +++ b/Octokit/Octokit-Mono.csproj @@ -64,6 +64,8 @@ + + @@ -78,6 +80,8 @@ + + @@ -94,6 +98,7 @@ + @@ -105,6 +110,8 @@ + + @@ -118,6 +125,7 @@ + @@ -164,6 +172,7 @@ + diff --git a/Octokit/Octokit-MonoAndroid.csproj b/Octokit/Octokit-MonoAndroid.csproj index 14f5eae9..eddacf68 100644 --- a/Octokit/Octokit-MonoAndroid.csproj +++ b/Octokit/Octokit-MonoAndroid.csproj @@ -252,6 +252,7 @@ + @@ -275,10 +276,18 @@ + + + + + + + + @@ -392,4 +401,4 @@ - \ No newline at end of file + diff --git a/Octokit/Octokit-Monotouch.csproj b/Octokit/Octokit-Monotouch.csproj index 2becca9b..8266661c 100644 --- a/Octokit/Octokit-Monotouch.csproj +++ b/Octokit/Octokit-Monotouch.csproj @@ -356,6 +356,15 @@ + + + + + + + + + diff --git a/Octokit/Octokit-Portable.csproj b/Octokit/Octokit-Portable.csproj index f4092e19..f8c1579d 100644 --- a/Octokit/Octokit-Portable.csproj +++ b/Octokit/Octokit-Portable.csproj @@ -88,6 +88,8 @@ + + @@ -110,6 +112,8 @@ + + @@ -170,6 +174,7 @@ + @@ -190,6 +195,8 @@ + + @@ -205,6 +212,7 @@ + @@ -260,6 +268,8 @@ + + diff --git a/Octokit/Octokit-netcore45.csproj b/Octokit/Octokit-netcore45.csproj index 077ffd01..e33d7286 100644 --- a/Octokit/Octokit-netcore45.csproj +++ b/Octokit/Octokit-netcore45.csproj @@ -93,6 +93,8 @@ + + @@ -114,6 +116,8 @@ + + @@ -176,6 +180,7 @@ + @@ -193,6 +198,8 @@ + + @@ -209,6 +216,7 @@ + @@ -266,6 +274,8 @@ + + diff --git a/Octokit/Octokit.csproj b/Octokit/Octokit.csproj index ec335c5e..577b7094 100644 --- a/Octokit/Octokit.csproj +++ b/Octokit/Octokit.csproj @@ -229,6 +229,8 @@ + + @@ -238,6 +240,8 @@ + + @@ -247,6 +251,7 @@ + @@ -257,7 +262,10 @@ + + + @@ -286,6 +294,7 @@ +