diff --git a/Octokit.Reactive/Clients/IObservableOrganizationHooksClient.cs b/Octokit.Reactive/Clients/IObservableOrganizationHooksClient.cs
new file mode 100644
index 0000000000..19ab40a844
--- /dev/null
+++ b/Octokit.Reactive/Clients/IObservableOrganizationHooksClient.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Reactive;
+
+namespace Octokit.Reactive
+{
+ public interface IObservableOrganizationHooksClient
+ {
+ ///
+ /// Gets the list of hooks defined for a organization
+ ///
+ /// See API documentation for more information.
+ ///
+ IObservable GetAll(string org);
+
+ ///
+ /// Gets a single hook defined for a organization by id
+ ///
+ /// 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 org, int hookId);
+
+ ///
+ /// Creates a hook for a organization
+ ///
+ /// See API documentation for more information.
+ ///
+ IObservable Create(string org, NewOrganizationHook hook);
+
+ ///
+ /// Edits a hook for a organization
+ ///
+ /// See API documentation for more information.
+ ///
+ IObservable Edit(string org, int hookId, EditOrganizationHook hook);
+
+ ///
+ /// This will trigger a ping event to be sent to the hook.
+ ///
+ /// See API documentation for more information.
+ ///
+ IObservable Ping(string org, int hookId);
+
+ ///
+ /// Deletes a hook for a organization
+ ///
+ ///
+ ///
+ /// See API documentation for more information.
+ ///
+ IObservable Delete(string org, int hookId);
+ }
+}
\ No newline at end of file
diff --git a/Octokit.Reactive/Clients/IObservableOrganizationsClient.cs b/Octokit.Reactive/Clients/IObservableOrganizationsClient.cs
index f36bb44a67..ac487a6908 100644
--- a/Octokit.Reactive/Clients/IObservableOrganizationsClient.cs
+++ b/Octokit.Reactive/Clients/IObservableOrganizationsClient.cs
@@ -15,6 +15,12 @@ public interface IObservableOrganizationsClient
///
IObservableTeamsClient Team { get; }
+ ///
+ /// A client for GitHub's Organization Hooks API.
+ ///
+ /// See Hooks API documentation for more information.
+ IObservableOrganizationHooksClient Hook { get; }
+
///
/// Returns the specified organization.
///
@@ -42,10 +48,10 @@ public interface IObservableOrganizationsClient
///
/// Update the specified organization with data from .
///
- /// The name of the organization to update.
+ /// The name of the organization to update.
///
/// Thrown if the client is not authenticated.
/// A
- IObservable Update(string organizationName, OrganizationUpdate updateRequest);
+ IObservable Update(string org, OrganizationUpdate updateRequest);
}
}
diff --git a/Octokit.Reactive/Clients/IObservableRepositoryHooksClient.cs b/Octokit.Reactive/Clients/IObservableRepositoryHooksClient.cs
index f3176e0add..f8a9b76c22 100644
--- a/Octokit.Reactive/Clients/IObservableRepositoryHooksClient.cs
+++ b/Octokit.Reactive/Clients/IObservableRepositoryHooksClient.cs
@@ -9,7 +9,7 @@ public interface IObservableRepositoryHooksClient
///
/// Gets the list of hooks defined for a repository
///
- /// See API documentation for more information.
+ /// See API documentation for more information.
///
IObservable GetAll(string owner, string repositoryName);
@@ -47,7 +47,7 @@ public interface IObservableRepositoryHooksClient
///
/// This will trigger a ping event to be sent to the hook.
///
- /// See API documentation for more information.
+ /// See API documentation for more information.
///
IObservable Ping(string owner, string repositoryName, int hookId);
diff --git a/Octokit.Reactive/Clients/ObservableOrganizationHooksClient.cs b/Octokit.Reactive/Clients/ObservableOrganizationHooksClient.cs
new file mode 100644
index 0000000000..792a0860d3
--- /dev/null
+++ b/Octokit.Reactive/Clients/ObservableOrganizationHooksClient.cs
@@ -0,0 +1,98 @@
+using System;
+using System.Reactive;
+using System.Reactive.Threading.Tasks;
+using Octokit.Reactive.Internal;
+
+namespace Octokit.Reactive
+{
+ public class ObservableOrganizationHooksClient : IObservableOrganizationHooksClient
+ {
+ readonly IOrganizationHooksClient _client;
+ readonly IConnection _connection;
+
+ public ObservableOrganizationHooksClient(IGitHubClient client)
+ {
+ Ensure.ArgumentNotNull(client, "client");
+
+ _client = client.Organization.Hook;
+ _connection = client.Connection;
+ }
+
+ ///
+ /// Gets the list of hooks defined for a organization
+ ///
+ /// See API documentation for more information.
+ ///
+ public IObservable GetAll(string org)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(org, "org");
+
+
+ return _connection.GetAndFlattenAllPages(ApiUrls.OrganizationHooks(org));
+ }
+
+ ///
+ /// Gets a single hook defined for a organization by id
+ ///
+ /// See API documentation for more information.
+ ///
+ public IObservable Get(string org, int hookId)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(org, "org");
+
+ return _client.Get(org, hookId).ToObservable();
+ }
+
+ ///
+ /// Creates a hook for a organization
+ ///
+ /// See API documentation for more information.
+ ///
+ public IObservable Create(string org, NewOrganizationHook hook)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(org, "org");
+ Ensure.ArgumentNotNull(hook, "hook");
+
+ return _client.Create(org, hook).ToObservable();
+ }
+
+ ///
+ /// Edits a hook for a organization
+ ///
+ /// See API documentation for more information.
+ ///
+ public IObservable Edit(string org, int hookId, EditOrganizationHook hook)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(org, "org");
+ Ensure.ArgumentNotNull(hook, "hook");
+
+ return _client.Edit(org, hookId, hook).ToObservable();
+ }
+
+ ///
+ /// This will trigger a ping event to be sent to the hook.
+ ///
+ /// See API documentation for more information.
+ ///
+ public IObservable Ping(string org, int hookId)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(org, "org");
+
+ return _client.Ping(org, hookId).ToObservable();
+ }
+
+ ///
+ /// Deletes a hook for a organization
+ ///
+ ///
+ ///
+ /// See API documentation for more information.
+ ///
+ public IObservable Delete(string org, int hookId)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(org, "org");
+
+ return _client.Delete(org, hookId).ToObservable();
+ }
+ }
+}
diff --git a/Octokit.Reactive/Clients/ObservableOrganizationsClient.cs b/Octokit.Reactive/Clients/ObservableOrganizationsClient.cs
index 64afff9d1e..551f2fcdcf 100644
--- a/Octokit.Reactive/Clients/ObservableOrganizationsClient.cs
+++ b/Octokit.Reactive/Clients/ObservableOrganizationsClient.cs
@@ -19,6 +19,7 @@ public ObservableOrganizationsClient(IGitHubClient client)
Member = new ObservableOrganizationMembersClient(client);
Team = new ObservableTeamsClient(client);
+ Hook = new ObservableOrganizationHooksClient(client);
_client = client.Organization;
_connection = client.Connection;
@@ -34,6 +35,12 @@ public ObservableOrganizationsClient(IGitHubClient client)
///
public IObservableTeamsClient Team { get; private set; }
+ ///
+ /// A client for GitHub's Organization Hooks API.
+ ///
+ /// See Hooks API documentation for more information.
+ public IObservableOrganizationHooksClient Hook { get; private set; }
+
///
/// Returns the specified organization.
///
@@ -70,13 +77,14 @@ public IObservable GetAll(string user)
///
/// Update the specified organization with data from .
///
- /// The name of the organization to update.
+ /// The name of the organization to update.
///
/// Thrown if the client is not authenticated.
/// A
- public IObservable Update(string organizationName, OrganizationUpdate updateRequest)
+ public IObservable Update(string org, OrganizationUpdate updateRequest)
{
- return _client.Update(organizationName, updateRequest).ToObservable();
+ return _client.Update(org, updateRequest).ToObservable();
}
+
}
}
diff --git a/Octokit.Reactive/Clients/ObservableRepositoryHooksClient.cs b/Octokit.Reactive/Clients/ObservableRepositoryHooksClient.cs
index 7b229dd282..f8211a9206 100644
--- a/Octokit.Reactive/Clients/ObservableRepositoryHooksClient.cs
+++ b/Octokit.Reactive/Clients/ObservableRepositoryHooksClient.cs
@@ -21,7 +21,7 @@ public ObservableRepositoryHooksClient(IGitHubClient client)
///
/// Gets the list of hooks defined for a repository
///
- /// See API documentation for more information.
+ /// See API documentation for more information.
///
public IObservable GetAll(string owner, string repositoryName)
{
@@ -90,7 +90,7 @@ public IObservable Test(string owner, string repositoryName, int hookId)
///
/// This will trigger a ping event to be sent to the hook.
///
- /// See API documentation for more information.
+ /// See API documentation for more information.
///
public IObservable Ping(string owner, string repositoryName, int hookId)
{
diff --git a/Octokit.Reactive/Octokit.Reactive-Mono.csproj b/Octokit.Reactive/Octokit.Reactive-Mono.csproj
index 6cf3a0262e..ab9496e777 100644
--- a/Octokit.Reactive/Octokit.Reactive-Mono.csproj
+++ b/Octokit.Reactive/Octokit.Reactive-Mono.csproj
@@ -176,6 +176,8 @@
+
+
diff --git a/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj b/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj
index 146e66b0e4..e1382a00c4 100644
--- a/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj
+++ b/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj
@@ -184,6 +184,8 @@
+
+
diff --git a/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj b/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj
index c3d64929d7..094bd86b42 100644
--- a/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj
+++ b/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj
@@ -180,6 +180,8 @@
+
+
diff --git a/Octokit.Reactive/Octokit.Reactive.csproj b/Octokit.Reactive/Octokit.Reactive.csproj
index 8d1d8e9994..6b44269391 100644
--- a/Octokit.Reactive/Octokit.Reactive.csproj
+++ b/Octokit.Reactive/Octokit.Reactive.csproj
@@ -94,6 +94,7 @@
+
@@ -119,6 +120,7 @@
+
diff --git a/Octokit.Tests.Integration/Clients/OrganizationHooksClientTests.cs b/Octokit.Tests.Integration/Clients/OrganizationHooksClientTests.cs
new file mode 100644
index 0000000000..fd8aa25f24
--- /dev/null
+++ b/Octokit.Tests.Integration/Clients/OrganizationHooksClientTests.cs
@@ -0,0 +1,197 @@
+using Octokit.Tests.Integration.Fixtures;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace Octokit.Tests.Integration.Clients
+{
+ public class OrganizationHooksClientTests
+ {
+ [Collection(OrganizationsHooksCollection.Name)]
+ public class TheGetAllMethod
+
+ {
+ OrganizationsHooksFixture _fixture;
+
+ public TheGetAllMethod(OrganizationsHooksFixture fixture)
+ {
+ _fixture = fixture;
+ }
+
+ [IntegrationTest]
+ public async Task ReturnsAllHooksFromOrganization()
+ {
+ var github = Helper.GetAuthenticatedClient();
+
+ var hooks = await github.Organization.Hook.GetAll( _fixture.org);
+
+ Assert.Single(hooks);
+ var actualHook = hooks[0];
+
+ AssertHook(_fixture.ExpectedHook, actualHook);
+ }
+ }
+
+ [Collection(OrganizationsHooksCollection.Name)]
+ public class TheGetMethod
+ {
+ readonly OrganizationsHooksFixture _fixture;
+
+ public TheGetMethod(OrganizationsHooksFixture fixture)
+ {
+ _fixture = fixture;
+ }
+
+ [IntegrationTest]
+ public async Task GetHookByCreatedId()
+ {
+ var github = Helper.GetAuthenticatedClient();
+
+ var actualHook = await github.Organization.Hook.Get(_fixture.org, _fixture.ExpectedHook.Id);
+
+ AssertHook(_fixture.ExpectedHook, actualHook);
+ }
+ }
+
+ [Collection(OrganizationsHooksCollection.Name)]
+ public class TheCreateMethod
+ {
+ readonly OrganizationsHooksFixture _fixture;
+
+ public TheCreateMethod(OrganizationsHooksFixture fixture)
+ {
+ _fixture = fixture;
+ }
+ [IntegrationTest]
+ public async Task CreateAWebHookForTestOrganization()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var url = "http://test.com/example";
+ var contentType = OrgWebHookContentType.Json;
+ //var secret = "53cr37";
+ var config = new Dictionary
+ {
+ { "url", "http://hostname.url" },
+ { "content_type", "json" }
+ };
+ var parameters = new NewOrganizationHook("web", config)
+ {
+ Events = new[] { "push" },
+ Active = false
+ };
+
+ var hook = await github.Organization.Hook.Create(_fixture.org, parameters.ToRequest());
+
+ var baseHookUrl = CreateExpectedBaseHookUrl(_fixture.org, hook.Id);
+ var webHookConfig = CreateExpectedConfigDictionary(config, url, contentType);
+
+ Assert.Equal("web", hook.Name);
+ Assert.Equal(new[] { "push" }.ToList(), hook.Events.ToList());
+ Assert.Equal(baseHookUrl, hook.Url);
+ Assert.Equal(baseHookUrl + "/pings", hook.PingUrl);
+ Assert.NotNull(hook.CreatedAt);
+ Assert.NotNull(hook.UpdatedAt);
+ Assert.Equal(webHookConfig.Keys, hook.Config.Keys);
+ //Assert.Equal(webHookConfig.Values, hook.Config.Values);
+ Assert.Equal(false, hook.Active);
+ }
+
+ Dictionary CreateExpectedConfigDictionary(Dictionary config, string url, OrgWebHookContentType contentType)
+ {
+ return new Dictionary
+ {
+
+ }.Union(config).ToDictionary(k => k.Key, v => v.Value);
+ }
+
+ string CreateExpectedBaseHookUrl(string org, int id)
+ {
+ return "https://api.github.com/orgs/" + org+ "/hooks/" + id;
+ }
+ }
+
+ [Collection(OrganizationsHooksCollection.Name)]
+ public class TheEditMethod
+ {
+ readonly OrganizationsHooksFixture _fixture;
+
+ public TheEditMethod(OrganizationsHooksFixture fixture)
+ {
+ _fixture = fixture;
+ }
+
+ [IntegrationTest]
+ public async Task EditHookTest()
+ {
+ var github = Helper.GetAuthenticatedClient();
+
+ var editOrganizationHook = new EditOrganizationHook
+ {
+ Events = new[] { "pull_request" }
+ };
+
+ var actualHook = await github.Organization.Hook.Edit( _fixture.org, _fixture.ExpectedHook.Id, editOrganizationHook);
+
+ var expectedConfig = new Dictionary { { "content_type", "json" }, { "url", "http://test.com/example" } };
+ Assert.Equal(new[] { "commit_comment", "pull_request" }.ToList(), actualHook.Events.ToList());
+ Assert.Equal(expectedConfig.Keys, actualHook.Config.Keys);
+ Assert.Equal(expectedConfig.Values, actualHook.Config.Values);
+ }
+ }
+
+ [Collection(OrganizationsHooksCollection.Name)]
+ public class ThePingMethod
+ {
+ readonly OrganizationsHooksFixture _fixture;
+
+ public ThePingMethod(OrganizationsHooksFixture fixture)
+ {
+ _fixture = fixture;
+ }
+
+ [IntegrationTest]
+ public async Task PingACreatedHook()
+ {
+ var github = Helper.GetAuthenticatedClient();
+
+ await github.Organization.Hook.Ping( _fixture.org, _fixture.ExpectedHook.Id);
+ }
+ }
+
+ [Collection(OrganizationsHooksCollection.Name)]
+ public class TheDeleteMethod
+ {
+ readonly OrganizationsHooksFixture _fixture;
+
+ public TheDeleteMethod(OrganizationsHooksFixture fixture)
+ {
+ _fixture = fixture;
+ }
+
+ [IntegrationTest]
+ public async Task DeleteCreatedWebHook()
+ {
+ var github = Helper.GetAuthenticatedClient();
+
+ await github.Organization.Hook.Delete(_fixture.org, _fixture.ExpectedHook.Id);
+ var hooks = await github.Organization.Hook.GetAll( _fixture.org);
+
+ Assert.Empty(hooks);
+ }
+ }
+
+ static void AssertHook(OrganizationHook expectedHook, OrganizationHook actualHook)
+ {
+ Assert.Equal(expectedHook.Id, actualHook.Id);
+ Assert.Equal(expectedHook.Active, actualHook.Active);
+ Assert.Equal(expectedHook.Config, actualHook.Config);
+ Assert.Equal(expectedHook.CreatedAt, actualHook.CreatedAt);
+ Assert.Equal(expectedHook.Name, actualHook.Name);
+ Assert.Equal(expectedHook.PingUrl, actualHook.PingUrl);
+ Assert.Equal(expectedHook.TestUrl, actualHook.TestUrl);
+ Assert.Equal(expectedHook.UpdatedAt, actualHook.UpdatedAt);
+ Assert.Equal(expectedHook.Url, actualHook.Url);
+ }
+ }
+}
diff --git a/Octokit.Tests.Integration/Clients/RepositoryHooksClientTests.cs b/Octokit.Tests.Integration/Clients/RepositoryHooksClientTests.cs
index d0fd6c6e4a..ad6ccbc7f1 100644
--- a/Octokit.Tests.Integration/Clients/RepositoryHooksClientTests.cs
+++ b/Octokit.Tests.Integration/Clients/RepositoryHooksClientTests.cs
@@ -1,4 +1,4 @@
-using Octokit.Tests.Integration.fixtures;
+using Octokit.Tests.Integration.Fixtures;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
diff --git a/Octokit.Tests.Integration/Helper.cs b/Octokit.Tests.Integration/Helper.cs
index 52eaeb8cb6..1f9a017aa2 100644
--- a/Octokit.Tests.Integration/Helper.cs
+++ b/Octokit.Tests.Integration/Helper.cs
@@ -149,7 +149,7 @@ public static string MakeNameWithTimestamp(string name)
public static Stream LoadFixture(string fileName)
{
- var key = "Octokit.Tests.Integration.fixtures." + fileName;
+ var key = "Octokit.Tests.Integration.Fixtures." + fileName;
var stream = typeof(Helper).Assembly.GetManifestResourceStream(key);
if (stream == null)
{
diff --git a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj
index 4181ab35f2..f75ddae89b 100644
--- a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj
+++ b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj
@@ -100,6 +100,7 @@
+
@@ -109,8 +110,10 @@
-
-
+
+
+
+
@@ -173,7 +176,7 @@
-
+
Designer
@@ -182,7 +185,7 @@
-
+
diff --git a/Octokit.Tests.Integration/fixtures/OrganizationsHooksCollection.cs b/Octokit.Tests.Integration/fixtures/OrganizationsHooksCollection.cs
new file mode 100644
index 0000000000..a247d7ffbe
--- /dev/null
+++ b/Octokit.Tests.Integration/fixtures/OrganizationsHooksCollection.cs
@@ -0,0 +1,10 @@
+using Xunit;
+
+namespace Octokit.Tests.Integration.Fixtures
+{
+ [CollectionDefinition(Name)]
+ public class OrganizationsHooksCollection : ICollectionFixture
+ {
+ public const string Name = "Organization Hooks Collection";
+ }
+}
diff --git a/Octokit.Tests.Integration/fixtures/OrganizationsHooksFixture.cs b/Octokit.Tests.Integration/fixtures/OrganizationsHooksFixture.cs
new file mode 100644
index 0000000000..a3074077dc
--- /dev/null
+++ b/Octokit.Tests.Integration/fixtures/OrganizationsHooksFixture.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+
+namespace Octokit.Tests.Integration.Fixtures
+{
+ public class OrganizationsHooksFixture : IDisposable
+ {
+ readonly IGitHubClient _github;
+ readonly OrganizationHook _hook;
+ readonly private string _organizationFixture;
+
+ public OrganizationsHooksFixture()
+ {
+ _github = Helper.GetAuthenticatedClient();
+ _organizationFixture = Helper.Organization;
+ _hook = CreateHook(_github, _organizationFixture);
+ }
+
+
+ public string org { get { return _organizationFixture; } }
+
+ public OrganizationHook ExpectedHook { get { return _hook; } }
+
+ public void Dispose()
+ {
+ _github.Organization.Hook.Delete(_organizationFixture,_hook.Id);
+ }
+
+ static OrganizationHook CreateHook(IGitHubClient github, string orgFixture)
+ {
+ var config = new Dictionary { { "content_type", "json" }, { "url", "http://test.com/example" } };
+ var parameters = new NewOrganizationHook("web", config)
+ {
+ Events = new[] { "commit_comment" },
+ Active = false
+ };
+ var createdHook = github.Organization.Hook.Create(orgFixture, parameters);
+
+ return createdHook.Result;
+ }
+ }
+}
diff --git a/Octokit.Tests.Integration/fixtures/RepositoriesHooksCollection.cs b/Octokit.Tests.Integration/fixtures/RepositoriesHooksCollection.cs
index 0d4006f5e7..cff098334b 100644
--- a/Octokit.Tests.Integration/fixtures/RepositoriesHooksCollection.cs
+++ b/Octokit.Tests.Integration/fixtures/RepositoriesHooksCollection.cs
@@ -1,6 +1,6 @@
using Xunit;
-namespace Octokit.Tests.Integration.fixtures
+namespace Octokit.Tests.Integration.Fixtures
{
[CollectionDefinition(Name)]
public class RepositoriesHooksCollection : ICollectionFixture
diff --git a/Octokit.Tests.Integration/fixtures/RepositoriesHooksFixture.cs b/Octokit.Tests.Integration/fixtures/RepositoriesHooksFixture.cs
index cda77a8a87..8a830341e5 100644
--- a/Octokit.Tests.Integration/fixtures/RepositoriesHooksFixture.cs
+++ b/Octokit.Tests.Integration/fixtures/RepositoriesHooksFixture.cs
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
-namespace Octokit.Tests.Integration.fixtures
+namespace Octokit.Tests.Integration.Fixtures
{
public class RepositoriesHooksFixture : IDisposable
{
diff --git a/Octokit.Tests/Clients/OrganizationHooksClientTest.cs b/Octokit.Tests/Clients/OrganizationHooksClientTest.cs
new file mode 100644
index 0000000000..56c7362583
--- /dev/null
+++ b/Octokit.Tests/Clients/OrganizationHooksClientTest.cs
@@ -0,0 +1,216 @@
+using NSubstitute;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace Octokit.Tests.Clients
+{
+ public class OrganizationHooksClientTests
+ {
+ public class TheGetAllMethod
+ {
+ [Fact]
+ public void RequestsCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new OrganizationsClient(connection);
+
+ client.Hook.GetAll("org");
+
+ connection.Received().GetAll(Arg.Is(u => u.ToString() == "orgs/org/hooks"));
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new OrganizationsClient(Substitute.For());
+
+ await Assert.ThrowsAsync(() => client.Hook.GetAll(null));
+ }
+
+ [Fact]
+ public void EnsuresNonEmptyArguments()
+ {
+ var client = new OrganizationsClient(Substitute.For());
+ Assert.ThrowsAsync(() => client.Hook.GetAll(""));
+ }
+ }
+
+ public class TheGetMethod
+ {
+ [Fact]
+ public void RequestsCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new OrganizationsClient(connection);
+
+ client.Hook.Get("org", 12345678);
+
+ connection.Received().Get(Arg.Is(u => u.ToString() == "orgs/org/hooks/12345678"));
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new OrganizationsClient(Substitute.For());
+
+ await Assert.ThrowsAsync(() => client.Hook.Get(null, 123));
+ }
+
+ [Fact]
+ public void EnsuresNonEmptyArguments()
+ {
+ var client = new OrganizationsClient(Substitute.For());
+ Assert.ThrowsAsync(() => client.Hook.Get("",123));
+ }
+ }
+
+ public class TheCreateMethod
+ {
+ [Fact]
+ public void RequestsCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new OrganizationsClient(connection);
+ var hook = new NewOrganizationHook("name", new Dictionary { { "config", "" } });
+
+ client.Hook.Create("org", hook);
+
+ connection.Received().Post(Arg.Is(u => u.ToString() == "orgs/org/hooks"), hook);
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new OrganizationsClient(Substitute.For());
+
+ var config = new Dictionary { { "config", "" } };
+ await Assert.ThrowsAsync(() => client.Hook.Create(null, new NewOrganizationHook("name", config)));
+ await Assert.ThrowsAsync(() => client.Hook.Create("name", null));
+ }
+
+ [Fact]
+ public void EnsuresNonEmptyArguments()
+ {
+ var client = new OrganizationsClient(Substitute.For());
+ var config = new Dictionary { { "url", "" } };
+ Assert.ThrowsAsync(() => client.Hook.Create("", new NewOrganizationHook("name", config)));
+ }
+
+ [Fact]
+ public void UsesTheSuppliedHook()
+ {
+ var connection = Substitute.For();
+ var client = new OrganizationsClient(connection);
+ var newOrganizationHook = new NewOrganizationHook("name", new Dictionary { { "config", "" } });
+
+ client.Hook.Create("org", newOrganizationHook);
+
+ connection.Received().Post(Arg.Any(), newOrganizationHook);
+ }
+ }
+
+ public class TheEditMethod
+ {
+ [Fact]
+ public void RequestsCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new OrganizationsClient(connection);
+ var hook = new EditOrganizationHook();
+
+ client.Hook.Edit("org", 12345678, hook);
+
+ connection.Received().Patch(Arg.Is(u => u.ToString() == "orgs/org/hooks/12345678"), hook);
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new OrganizationsClient(Substitute.For());
+
+ await Assert.ThrowsAsync(() => client.Hook.Edit( null, 12345678, new EditOrganizationHook()));
+ await Assert.ThrowsAsync(() => client.Hook.Edit( "name", 12345678, null));
+ }
+
+ [Fact]
+ public void EnsuresNonEmptyArguments()
+ {
+ var client = new OrganizationsClient(Substitute.For());
+ Assert.ThrowsAsync(() => client.Hook.Edit("", 123, new EditOrganizationHook()));
+ }
+
+ [Fact]
+ public void UsesTheSuppliedHook()
+ {
+ var connection = Substitute.For();
+ var client = new OrganizationsClient(connection);
+ var editOrganizationHook = new EditOrganizationHook() { Active = false };
+
+ client.Hook.Edit("org", 12345678, editOrganizationHook);
+
+ connection.Received().Patch(Arg.Any(), editOrganizationHook);
+ }
+ }
+
+ public class ThePingMethod
+ {
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new OrganizationsClient(Substitute.For());
+
+ await Assert.ThrowsAsync(() => client.Hook.Ping(null, 12345678));
+ }
+
+ [Fact]
+ public void EnsuresNonEmptyArguments()
+ {
+ var client = new OrganizationsClient(Substitute.For());
+ Assert.ThrowsAsync(() => client.Hook.Ping("", 123));
+ }
+
+ [Fact]
+ public void RequestsCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new OrganizationsClient(connection);
+
+ client.Hook.Ping("org", 12345678);
+
+ connection.Received().Post(Arg.Is(u => u.ToString() == "orgs/org/hooks/12345678/pings"));
+ }
+ }
+
+ public class TheDeleteMethod
+ {
+ [Fact]
+ public void RequestsCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new OrganizationsClient(connection);
+
+ client.Hook.Delete("org", 12345678);
+
+ connection.Received().Delete(Arg.Is(u => u.ToString() == "orgs/org/hooks/12345678"));
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new OrganizationsClient(Substitute.For());
+
+ await Assert.ThrowsAsync(() => client.Hook.Delete(null, 12345678));
+ }
+
+ [Fact]
+ public void EnsuresNonEmptyArguments()
+ {
+ var client = new OrganizationsClient(Substitute.For());
+ Assert.ThrowsAsync(() => client.Hook.Delete("", 123));
+ }
+
+ }
+ }
+}
diff --git a/Octokit.Tests/Models/NewOrganizationWebHookTests.cs b/Octokit.Tests/Models/NewOrganizationWebHookTests.cs
new file mode 100644
index 0000000000..1ea1cb167f
--- /dev/null
+++ b/Octokit.Tests/Models/NewOrganizationWebHookTests.cs
@@ -0,0 +1,108 @@
+using System.Collections.Generic;
+using Xunit;
+
+namespace Octokit.Tests.Models
+{
+ public class NewOrganizationWebHookTests
+ {
+ public class TheCtor
+ {
+ string ExpectedOrganizationWebHookConfigExceptionMessage =
+ "Duplicate webhook config values found - these values: Url should not be passed in as part of the config values. Use the properties on the NewOrganizationWebHook class instead.";
+
+ [Fact]
+ public void UsesDefaultValuesForDefaultConfig()
+ {
+ var create = new NewOrganizationWebHook("windowsazure", new Dictionary(), "http://test.com/example");
+ Assert.Equal(create.Url, "http://test.com/example");
+ Assert.Equal(create.ContentType, OrgWebHookContentType.Form);
+ Assert.Empty(create.Secret);
+ Assert.False(create.InsecureSsl);
+
+ var request = create.ToRequest();
+ Assert.Equal(request.Config.Count, 4);
+
+ Assert.True(request.Config.ContainsKey("url"));
+ Assert.True(request.Config.ContainsKey("content_type"));
+ Assert.True(request.Config.ContainsKey("secret"));
+ Assert.True(request.Config.ContainsKey("insecure_ssl"));
+
+ Assert.Equal(request.Config["url"], "http://test.com/example");
+ Assert.Equal(request.Config["content_type"], OrgWebHookContentType.Form.ToParameter());
+ Assert.Equal(request.Config["secret"], "");
+ Assert.Equal(request.Config["insecure_ssl"], "False");
+ }
+
+ [Fact]
+ public void CombinesUserSpecifiedContentTypeWithConfig()
+ {
+ var config = new Dictionary
+ {
+ {"hostname", "http://hostname.url"},
+ {"username", "username"},
+ {"password", "password"}
+ };
+
+ var create = new NewOrganizationWebHook("windowsazure", config, "http://test.com/example")
+ {
+ ContentType = OrgWebHookContentType.Json,
+ Secret = string.Empty,
+ InsecureSsl = true
+ };
+
+ Assert.Equal(create.Url, "http://test.com/example");
+ Assert.Equal(create.ContentType, OrgWebHookContentType.Json);
+ Assert.Empty(create.Secret);
+ Assert.True(create.InsecureSsl);
+
+ var request = create.ToRequest();
+
+ Assert.Equal(request.Config.Count, 7);
+
+ Assert.True(request.Config.ContainsKey("url"));
+ Assert.True(request.Config.ContainsKey("content_type"));
+ Assert.True(request.Config.ContainsKey("secret"));
+ Assert.True(request.Config.ContainsKey("insecure_ssl"));
+
+ Assert.Equal(request.Config["url"], "http://test.com/example");
+ Assert.Equal(request.Config["content_type"], OrgWebHookContentType.Json.ToParameter());
+ Assert.Equal(request.Config["secret"], "");
+ Assert.Equal(request.Config["insecure_ssl"], true.ToString());
+
+ Assert.True(request.Config.ContainsKey("hostname"));
+ Assert.Equal(request.Config["hostname"], config["hostname"]);
+ Assert.True(request.Config.ContainsKey("username"));
+ Assert.Equal(request.Config["username"], config["username"]);
+ Assert.True(request.Config.ContainsKey("password"));
+ Assert.Equal(request.Config["password"], config["password"]);
+ }
+
+ [Fact]
+ public void ShouldThrowOrganizationWebHookConfigExceptionWhenDuplicateKeysExists()
+ {
+ var config = new Dictionary
+ {
+ {"url", "http://example.com/test"},
+ {"hostname", "http://hostname.url"},
+ {"username", "username"},
+ {"password", "password"}
+ };
+
+ var create = new NewOrganizationWebHook("windowsazure", config, "http://test.com/example")
+ {
+ ContentType = OrgWebHookContentType.Json,
+ Secret = string.Empty,
+ InsecureSsl = true
+ };
+
+ Assert.Equal(create.Url, "http://test.com/example");
+ Assert.Equal(create.ContentType, OrgWebHookContentType.Json);
+ Assert.Empty(create.Secret);
+ Assert.True(create.InsecureSsl);
+
+ var ex = Assert.Throws(() => create.ToRequest());
+ Assert.Equal(ExpectedOrganizationWebHookConfigExceptionMessage, ex.Message);
+ }
+ }
+ }
+}
diff --git a/Octokit.Tests/Octokit.Tests.csproj b/Octokit.Tests/Octokit.Tests.csproj
index cb994ec614..1302321154 100644
--- a/Octokit.Tests/Octokit.Tests.csproj
+++ b/Octokit.Tests/Octokit.Tests.csproj
@@ -54,16 +54,16 @@
- False
..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll
+ True
- False
..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll
+ True
- False
..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll
+ True
@@ -98,6 +98,7 @@
+
@@ -178,6 +179,7 @@
+
@@ -248,7 +250,9 @@
-
+
+ Designer
+
diff --git a/Octokit.Tests/app.config b/Octokit.Tests/app.config
index de7151f3e3..7bd2b5611c 100644
--- a/Octokit.Tests/app.config
+++ b/Octokit.Tests/app.config
@@ -4,15 +4,15 @@
-
+
-
+
-
+
diff --git a/Octokit.Tests/packages.Octokit.Tests.config b/Octokit.Tests/packages.Octokit.Tests.config
index 812ea8c4d7..89dd0f6d08 100644
--- a/Octokit.Tests/packages.Octokit.Tests.config
+++ b/Octokit.Tests/packages.Octokit.Tests.config
@@ -2,7 +2,6 @@
-
diff --git a/Octokit/Clients/IOrganizationHooksClient.cs b/Octokit/Clients/IOrganizationHooksClient.cs
new file mode 100644
index 0000000000..6377e60f14
--- /dev/null
+++ b/Octokit/Clients/IOrganizationHooksClient.cs
@@ -0,0 +1,54 @@
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading.Tasks;
+
+namespace Octokit
+{
+ public interface IOrganizationHooksClient
+ {
+ ///
+ /// Gets the list of hooks defined for a organization
+ ///
+ /// See API documentation for more information.
+ ///
+ Task> GetAll(string org);
+
+ ///
+ /// Gets a single hook by Id
+ ///
+ ///
+ ///
+ ///
+ /// See API documentation for more information.
+ [SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Get", Justification = "This is ok; we're matching HTTP verbs not keywords")]
+ Task Get(string org, int hookId);
+
+ ///
+ /// Creates a hook for a organization
+ ///
+ /// See API documentation for more information.
+ ///
+ Task Create(string org, NewOrganizationHook hook);
+
+ ///
+ /// Edits a hook for a organization
+ ///
+ /// See API documentation for more information.
+ ///
+ Task Edit(string org, int hookId, EditOrganizationHook hook);
+
+ ///
+ /// This will trigger a ping event to be sent to the hook.
+ ///
+ /// See API documentation for more information.
+ ///
+ Task Ping(string org, int hookId);
+
+ ///
+ /// Deletes a hook for a organization
+ ///
+ /// See API documentation for more information.
+ ///
+ Task Delete(string org, int hookId);
+ }
+}
diff --git a/Octokit/Clients/IOrganizationsClient.cs b/Octokit/Clients/IOrganizationsClient.cs
index 9d5cf337d1..368bed22b0 100644
--- a/Octokit/Clients/IOrganizationsClient.cs
+++ b/Octokit/Clients/IOrganizationsClient.cs
@@ -24,6 +24,12 @@ public interface IOrganizationsClient
///
ITeamsClient Team { get; }
+ ///
+ /// A client for GitHub's Organization Hooks API.
+ ///
+ /// See Hooks API documentation for more information.
+ IOrganizationHooksClient Hook { get; }
+
///
/// Returns the specified .
///
@@ -53,10 +59,10 @@ public interface IOrganizationsClient
///
/// Update the specified organization with data from .
///
- /// The name of the organization to update.
+ /// The name of the organization to update.
///
/// Thrown if the client is not authenticated.
/// A
- Task Update(string organizationName, OrganizationUpdate updateRequest);
+ Task Update(string org, OrganizationUpdate updateRequest);
}
}
diff --git a/Octokit/Clients/IRepositoryHooksClient.cs b/Octokit/Clients/IRepositoryHooksClient.cs
index c282a3726d..d9f07f148e 100644
--- a/Octokit/Clients/IRepositoryHooksClient.cs
+++ b/Octokit/Clients/IRepositoryHooksClient.cs
@@ -9,7 +9,7 @@ public interface IRepositoryHooksClient
///
/// Gets the list of hooks defined for a repository
///
- /// See API documentation for more information.
+ /// See API documentation for more information.
///
Task> GetAll(string owner, string repositoryName);
@@ -50,7 +50,7 @@ public interface IRepositoryHooksClient
///
/// This will trigger a ping event to be sent to the hook.
///
- /// See API documentation for more information.
+ /// See API documentation for more information.
///
Task Ping(string owner, string repositoryName, int hookId);
diff --git a/Octokit/Clients/OrganizationHooksClient.cs b/Octokit/Clients/OrganizationHooksClient.cs
new file mode 100644
index 0000000000..4dfb17c454
--- /dev/null
+++ b/Octokit/Clients/OrganizationHooksClient.cs
@@ -0,0 +1,95 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Octokit
+{
+ public class OrganizationHooksClient : ApiClient, IOrganizationHooksClient
+ {
+ ///
+ /// Initializes a new GitHub Repos API client.
+ ///
+ /// An API connection.
+ public OrganizationHooksClient(IApiConnection apiConnection)
+ : base(apiConnection)
+ {
+ }
+
+ ///
+ /// Gets the list of hooks defined for a organization
+ ///
+ /// See API documentation for more information.
+ ///
+ public Task> GetAll(string org)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(org, "org");
+
+ return ApiConnection.GetAll(ApiUrls.OrganizationHooks(org));
+ }
+
+ ///
+ /// Gets a single hook by Id
+ ///
+ ///
+ ///
+ ///
+ /// See API documentation for more information.
+ public Task Get(string org, int hookId)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(org, "org");
+ Ensure.ArgumentNotNull(hookId, "HookId");
+
+ return ApiConnection.Get(ApiUrls.OrganizationHookById(org, hookId));
+ }
+
+ ///
+ /// Creates a hook for a organization
+ ///
+ /// See API documentation for more information.
+ ///
+ public Task Create(string org, NewOrganizationHook hook)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(org, "org");
+ Ensure.ArgumentNotNull(hook, "hook");
+
+ return ApiConnection.Post(ApiUrls.OrganizationHooks(org), hook.ToRequest());
+ }
+
+ ///
+ /// Edits a hook for a organization
+ ///
+ /// See API documentation for more information.
+ ///
+ public Task Edit(string org, int hookId, EditOrganizationHook hook)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(org, "org");
+ Ensure.ArgumentNotNull(hook, "hook");
+
+ return ApiConnection.Patch(ApiUrls.OrganizationHookById(org, hookId), hook);
+ }
+
+ ///
+ /// This will trigger a ping event to be sent to the hook.
+ ///
+ /// See API documentation for more information.
+ ///
+ public Task Ping(string org, int hookId)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(org, "org");
+ Ensure.ArgumentNotNull(hookId, "hookId");
+ return ApiConnection.Post(ApiUrls.OrganizationHookPing(org, hookId));
+ }
+
+ ///
+ /// Deletes a hook for a organization
+ ///
+ /// See API documentation for more information.
+ ///
+ public Task Delete(string org, int hookId)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(org, "org");
+ Ensure.ArgumentNotNull(hookId, "hookId");
+
+ return ApiConnection.Delete(ApiUrls.OrganizationHookById(org, hookId));
+ }
+ }
+}
\ No newline at end of file
diff --git a/Octokit/Clients/OrganizationsClient.cs b/Octokit/Clients/OrganizationsClient.cs
index dad301a06c..a74573d587 100644
--- a/Octokit/Clients/OrganizationsClient.cs
+++ b/Octokit/Clients/OrganizationsClient.cs
@@ -22,6 +22,7 @@ public OrganizationsClient(IApiConnection apiConnection) : base(apiConnection)
{
Member = new OrganizationMembersClient(apiConnection);
Team = new TeamsClient(apiConnection);
+ Hook = new OrganizationHooksClient(apiConnection);
}
///
@@ -48,6 +49,12 @@ public Task Get(string org)
return ApiConnection.Get(endpoint);
}
+ ///
+ /// A client for GitHub's Organization Hooks API.
+ ///
+ /// See Hooks API documentation for more information.
+ public IOrganizationHooksClient Hook { get; private set; }
+
///
/// Returns all s for the current user.
///
@@ -73,16 +80,16 @@ public Task> GetAll(string user)
///
/// Update the specified organization with data from .
///
- /// The name of the organization to update.
+ /// The name of the organization to update.
///
/// Thrown if the client is not authenticated.
/// A
- public Task Update(string organizationName, OrganizationUpdate updateRequest)
+ public Task Update(string org, OrganizationUpdate updateRequest)
{
- Ensure.ArgumentNotNullOrEmptyString(organizationName, "organizationName");
+ Ensure.ArgumentNotNullOrEmptyString(org, "org");
Ensure.ArgumentNotNull(updateRequest, "updateRequest");
- var updateUri = new Uri("orgs/" + organizationName, UriKind.Relative);
+ var updateUri = new Uri("orgs/" + org, UriKind.Relative);
return ApiConnection.Patch(updateUri, updateRequest);
}
diff --git a/Octokit/Clients/RepositoryHooksClient.cs b/Octokit/Clients/RepositoryHooksClient.cs
index 458a1596f5..a8cb8f1d59 100644
--- a/Octokit/Clients/RepositoryHooksClient.cs
+++ b/Octokit/Clients/RepositoryHooksClient.cs
@@ -17,7 +17,7 @@ public RepositoryHooksClient(IApiConnection apiConnection)
///
/// Gets the list of hooks defined for a repository
///
- /// See API documentation for more information.
+ /// See API documentation for more information.
///
public Task> GetAll(string owner, string repositoryName)
{
@@ -89,7 +89,7 @@ public Task Test(string owner, string repositoryName, int hookId)
///
/// This will trigger a ping event to be sent to the hook.
///
- /// See API documentation for more information.
+ /// See API documentation for more information.
///
public Task Ping(string owner, string repositoryName, int hookId)
{
diff --git a/Octokit/Exceptions/OrganizationWebHookConfigException.cs b/Octokit/Exceptions/OrganizationWebHookConfigException.cs
new file mode 100644
index 0000000000..4ffa4a3f57
--- /dev/null
+++ b/Octokit/Exceptions/OrganizationWebHookConfigException.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
+using System.Linq;
+using System.Runtime.Serialization;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Octokit
+{
+#if !NETFX_CORE
+ [Serializable]
+#endif
+ [SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors",
+ Justification = "These exceptions are specific to the GitHub API and not general purpose exceptions")]
+ public class OrganizationWebHookConfigException : Exception
+ {
+ readonly string message;
+
+ public OrganizationWebHookConfigException(IEnumerable invalidConfig)
+ {
+ var parameterList = string.Join(", ", invalidConfig.Select(ic => ic.FromRubyCase()));
+ message = string.Format(CultureInfo.InvariantCulture,
+ "Duplicate webhook config values found - these values: {0} should not be passed in as part of the config values. Use the properties on the NewOrganizationWebHook class instead.",
+ parameterList);
+ }
+
+ public override string Message
+ {
+ get { return message; }
+ }
+
+#if !NETFX_CORE
+ ///
+ /// Constructs an instance of OrganizationWebHookConfigException
+ ///
+ ///
+ /// The that holds the
+ /// serialized object data about the exception being thrown.
+ ///
+ ///
+ /// The that contains
+ /// contextual information about the source or destination.
+ ///
+ protected OrganizationWebHookConfigException(SerializationInfo info, StreamingContext context)
+ : base(info, context)
+ {
+ if (info == null) return;
+ message = info.GetString("Message");
+ }
+
+ public override void GetObjectData(SerializationInfo info, StreamingContext context)
+ {
+ base.GetObjectData(info, context);
+ info.AddValue("Message", Message);
+ }
+#endif
+ }
+}
diff --git a/Octokit/Helpers/ApiUrls.cs b/Octokit/Helpers/ApiUrls.cs
index bb34ce4624..25e0afa3fd 100644
--- a/Octokit/Helpers/ApiUrls.cs
+++ b/Octokit/Helpers/ApiUrls.cs
@@ -671,6 +671,38 @@ public static Uri RepositoryHookPing(string owner, string repositoryName, int ho
return "repos/{0}/{1}/hooks/{2}/pings".FormatUri(owner, repositoryName, hookId);
}
+ ///
+ /// Returns the that lists the organization hooks for the specified reference.
+ ///
+ /// The name of the organization
+ ///
+ public static Uri OrganizationHooks(string org)
+ {
+ return "orgs/{0}/hooks".FormatUri(org);
+ }
+
+ ///
+ /// Returns the that gets the organization hook for the specified reference.
+ ///
+ /// The name of the organization
+ /// The identifier of the organization hook
+ ///
+ public static Uri OrganizationHookById(string org, int hookId)
+ {
+ return "orgs/{0}/hooks/{1}".FormatUri(org, hookId);
+ }
+
+ ///
+ /// Returns the that can ping a specified organization hook
+ ///
+ /// The name of the organization
+ /// The identifier of the organization hook
+ ///
+ public static Uri OrganizationHookPing(string org, int hookId)
+ {
+ return "orgs/{0}/hooks/{1}/pings".FormatUri(org, hookId);
+ }
+
///
/// Returns the that lists the commit statuses for the specified reference.
///
diff --git a/Octokit/Models/Request/EditOrganizationHook.cs b/Octokit/Models/Request/EditOrganizationHook.cs
new file mode 100644
index 0000000000..ecfe146eeb
--- /dev/null
+++ b/Octokit/Models/Request/EditOrganizationHook.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using Octokit.Internal;
+
+namespace Octokit
+{
+ ///
+ /// Represents the requested changes to an edit repository hook.
+ ///
+ [DebuggerDisplay("{DebuggerDisplay,nq}")]
+ public class EditOrganizationHook
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public EditOrganizationHook() : this(null)
+ { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The configuration.
+ public EditOrganizationHook(IDictionary config)
+ {
+ Config = config;
+ }
+
+ public IDictionary Config { get; private set; }
+
+ ///
+ /// Gets or sets the events.
+ ///
+ ///
+ /// The events.
+ ///
+ public IEnumerable Events { get; set; }
+
+ ///
+ /// Gets or sets the active.
+ ///
+ ///
+ /// The active.
+ ///
+ public bool? Active { get; set; }
+
+ internal string DebuggerDisplay
+ {
+ get
+ {
+ return string.Format(CultureInfo.InvariantCulture,
+ "Organizaton Hook: Events: {0}", Events == null ? "no" : string.Join(", ", Events));
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Octokit/Models/Request/NewOrganizationHook.cs b/Octokit/Models/Request/NewOrganizationHook.cs
new file mode 100644
index 0000000000..8573e93944
--- /dev/null
+++ b/Octokit/Models/Request/NewOrganizationHook.cs
@@ -0,0 +1,117 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+
+namespace Octokit
+{
+ ///
+ /// Creates a Webhook for the organization.
+ ///
+ ///
+ /// To create a webhook, the following fields are required by the config:
+ ///
+ /// -
+ /// url
+ /// A required string defining the URL to which the payloads will be delivered.
+ ///
+ /// -
+ /// content_type
+ ///
+ /// An optional string defining the media type used to serialize the payloads. Supported values include json and
+ /// form. The default is form.
+ ///
+ ///
+ /// -
+ /// secret
+ ///
+ /// An optional string that’s passed with the HTTP requests as an X-Hub-Signature header. The value of this
+ /// header is computed as the HMAC hex digest of the body, using the secret as the key.
+ ///
+ ///
+ /// -
+ /// insecure_ssl:
+ ///
+ /// An optional string that determines whether the SSL certificate of the host for url will be verified when
+ /// delivering payloads. Supported values include "0" (verification is performed) and "1" (verification is not
+ /// performed). The default is "0".
+ ///
+ ///
+ ///
+ ///
+ /// API: https://developer.github.com/v3/repos/hooks/#create-a-hook
+ ///
+ ///
+ [DebuggerDisplay("{DebuggerDisplay,nq}")]
+ public class NewOrganizationHook
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// Use "web" for a webhook or use the name of a valid service. (See
+ /// https://api.github.com/hooks for the list of valid service
+ /// names.)
+ ///
+ ///
+ /// Key/value pairs to provide settings for this hook. These settings vary between the services and are
+ /// defined in the github-services repository. Booleans are stored internally as “1” for true, and “0” for
+ /// false. Any JSON true/false values will be converted automatically.
+ ///
+ public NewOrganizationHook(string name, IReadOnlyDictionary config)
+ {
+ Name = name;
+ Config = config;
+ }
+
+ ///
+ /// Gets the name of the hook to create. Use "web" for a webhook or use the name of a valid service. (See
+ /// https://api.github.com/hooks for the list of valid service
+ /// names.)
+ ///
+ ///
+ /// The name.
+ ///
+ public string Name { get; private set; }
+
+ ///
+ /// Key/value pairs to provide settings for this hook. These settings vary between the services and are
+ /// defined in the github-services repository. Booleans are stored internally as “1” for true, and “0” for
+ /// false. Any JSON true/false values will be converted automatically.
+ ///
+ ///
+ /// The configuration.
+ ///
+ public IReadOnlyDictionary Config { get; private set; }
+
+ ///
+ /// Determines what events the hook is triggered for. Default: ["push"]
+ ///
+ ///
+ /// The events.
+ ///
+ public IEnumerable Events { get; set; }
+
+ ///
+ /// Determines whether the hook is actually triggered on pushes.
+ ///
+ ///
+ /// true if active; otherwise, false.
+ ///
+ public bool Active { get; set; }
+
+ public virtual NewOrganizationHook ToRequest()
+ {
+ return this;
+ }
+
+ internal string DebuggerDisplay
+ {
+ get
+ {
+ return string.Format(CultureInfo.InvariantCulture,
+ "Organization Hook: Name: {0}, Events: {1}", Name, string.Join(", ", Events));
+ }
+ }
+ }
+}
diff --git a/Octokit/Models/Request/NewOrganizationWebHook.cs b/Octokit/Models/Request/NewOrganizationWebHook.cs
new file mode 100644
index 0000000000..e294ec2bad
--- /dev/null
+++ b/Octokit/Models/Request/NewOrganizationWebHook.cs
@@ -0,0 +1,146 @@
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+
+namespace Octokit
+{
+ ///
+ /// Creates a Webhook for the repository.
+ ///
+ ///
+ /// To create a webhook, the following fields are required by the config:
+ ///
+ /// -
+ /// url
+ /// A required string defining the URL to which the payloads will be delivered.
+ ///
+ /// -
+ /// content_type
+ ///
+ /// An optional string defining the media type used to serialize the payloads. Supported values include json and
+ /// form. The default is form.
+ ///
+ ///
+ /// -
+ /// secret
+ ///
+ /// An optional string that’s passed with the HTTP requests as an X-Hub-Signature header. The value of this
+ /// header is computed as the HMAC hex digest of the body, using the secret as the key.
+ ///
+ ///
+ /// -
+ /// insecure_ssl:
+ ///
+ /// An optional string that determines whether the SSL certificate of the host for url will be verified when
+ /// delivering payloads. Supported values include "0" (verification is performed) and "1" (verification is not
+ /// performed). The default is "0".
+ ///
+ ///
+ ///
+ ///
+ /// API: https://developer.github.com/v3/repos/hooks/#create-a-hook
+ ///
+ ///
+ [DebuggerDisplay("{DebuggerDisplay,nq}")]
+ public class NewOrganizationWebHook : NewOrganizationHook
+ {
+ ///
+ /// Initializes a new instance of the class.
+ /// Using default values for ContentType, Secret and InsecureSsl.
+ ///
+ ///
+ /// Use "web" for a webhook or use the name of a valid service. (See
+ /// https://api.github.com/hooks for the list of valid service
+ /// names.)
+ ///
+ ///
+ /// Key/value pairs to provide settings for this hook. These settings vary between the services and are
+ /// defined in the github-services repository. Booleans are stored internally as “1” for true, and “0” for
+ /// false. Any true/false values will be converted automatically.
+ ///
+ ///
+ /// A required string defining the URL to which the payloads will be delivered.
+ ///
+ public NewOrganizationWebHook(string name, IReadOnlyDictionary config, string url)
+ : base(name, config)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(url, "url");
+
+ Url = url;
+ ContentType = OrgWebHookContentType.Form;
+ Secret = "";
+ InsecureSsl = false;
+ }
+
+ ///
+ /// Gets the URL of the hook to create.
+ ///
+ ///
+ /// The URL.
+ ///
+ public string Url { get; protected set; }
+
+ ///
+ /// Gets the content type used to serialize the payload. The default is `form`.
+ ///
+ ///
+ /// The content type.
+ ///
+ public OrgWebHookContentType ContentType { get; set; }
+
+ ///
+ /// Gets the secret used as the key for the HMAC hex digest
+ /// of the body passed with the HTTP requests as an X-Hub-Signature header.
+ ///
+ ///
+ /// The secret.
+ ///
+ public string Secret { get; set; }
+
+ ///
+ /// Gets whether the SSL certificate of the host will be verified when
+ /// delivering payloads. The default is `false`.
+ ///
+ ///
+ /// true if SSL certificate verification is not performed;
+ /// otherwise, false.
+ ///
+ public bool InsecureSsl { get; set; }
+
+ public override NewOrganizationHook ToRequest()
+ {
+ var webHookConfig = GetWebHookConfig();
+ if (Config.Any(c => webHookConfig.ContainsKey(c.Key)))
+ {
+ var invalidConfigs = Config.Where(c => webHookConfig.ContainsKey(c.Key)).Select(c => c.Key);
+ throw new OrganizationWebHookConfigException(invalidConfigs);
+ }
+
+ var config = webHookConfig
+ .Union(Config, new WebHookConfigComparer())
+ .ToDictionary(k => k.Key, v => v.Value);
+
+ return new NewOrganizationHook(Name, config);
+ }
+
+ Dictionary GetWebHookConfig()
+ {
+ return new Dictionary
+ {
+ { "url", Url },
+ { "content_type", ContentType.ToParameter() },
+ { "secret", Secret },
+ { "insecure_ssl", InsecureSsl.ToString() }
+ };
+ }
+ }
+
+ ///
+ /// The supported content types for payload serialization.
+ ///
+ public enum OrgWebHookContentType
+ {
+ Form,
+ Json
+ }
+}
diff --git a/Octokit/Models/Response/OrganizationHook.cs b/Octokit/Models/Response/OrganizationHook.cs
new file mode 100644
index 0000000000..bc8224d2f5
--- /dev/null
+++ b/Octokit/Models/Response/OrganizationHook.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using Octokit.Internal;
+
+namespace Octokit
+{
+ [DebuggerDisplay("{DebuggerDisplay,nq}")]
+ public class OrganizationHook
+ {
+ public OrganizationHook() { }
+
+ public OrganizationHook(int id, string url, string testUrl, string pingUrl, DateTimeOffset createdAt, DateTimeOffset updatedAt, string name, IReadOnlyList events, bool active, IReadOnlyDictionary config)
+ {
+ Url = url;
+ TestUrl = testUrl;
+ PingUrl = pingUrl;
+ CreatedAt = createdAt;
+ UpdatedAt = updatedAt;
+ Name = name;
+ Events = events;
+ Active = active;
+ Config = config;
+ Id = id;
+ }
+
+ public int Id { get; private set; }
+
+ public string Url { get; private set; }
+
+ [Parameter(Key = "test_url")]
+ public string TestUrl { get; private set; }
+
+ [Parameter(Key = "ping_url")]
+ public string PingUrl { get; private set; }
+
+ public DateTimeOffset CreatedAt { get; private set; }
+
+ public DateTimeOffset UpdatedAt { get; private set; }
+
+ public string Name { get; private set; }
+
+ public IReadOnlyList Events { get; private set; }
+
+ public bool Active { get; private set; }
+
+ public IReadOnlyDictionary Config { get; private set; }
+
+ internal string DebuggerDisplay
+ {
+ get
+ {
+ return string.Format(CultureInfo.InvariantCulture,
+ "Organization Hook: Name: {0} Url: {1}, Events: {2}", Name, Url, string.Join(", ", Events));
+ }
+ }
+ }
+}
diff --git a/Octokit/Octokit-Mono.csproj b/Octokit/Octokit-Mono.csproj
index abbfe34868..741d01223a 100644
--- a/Octokit/Octokit-Mono.csproj
+++ b/Octokit/Octokit-Mono.csproj
@@ -458,6 +458,13 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Octokit/Octokit-MonoAndroid.csproj b/Octokit/Octokit-MonoAndroid.csproj
index 60896d144f..c2688cb750 100644
--- a/Octokit/Octokit-MonoAndroid.csproj
+++ b/Octokit/Octokit-MonoAndroid.csproj
@@ -467,6 +467,13 @@
+
+
+
+
+
+
+
diff --git a/Octokit/Octokit-Monotouch.csproj b/Octokit/Octokit-Monotouch.csproj
index 41d2a7e080..c08b17229c 100644
--- a/Octokit/Octokit-Monotouch.csproj
+++ b/Octokit/Octokit-Monotouch.csproj
@@ -463,6 +463,13 @@
+
+
+
+
+
+
+
diff --git a/Octokit/Octokit-Portable.csproj b/Octokit/Octokit-Portable.csproj
index 0f95001916..ba482813c2 100644
--- a/Octokit/Octokit-Portable.csproj
+++ b/Octokit/Octokit-Portable.csproj
@@ -455,6 +455,13 @@
+
+
+
+
+
+
+
diff --git a/Octokit/Octokit-netcore45.csproj b/Octokit/Octokit-netcore45.csproj
index 3cfdc341b9..851fe01b52 100644
--- a/Octokit/Octokit-netcore45.csproj
+++ b/Octokit/Octokit-netcore45.csproj
@@ -462,6 +462,13 @@
+
+
+
+
+
+
+
diff --git a/Octokit/Octokit.csproj b/Octokit/Octokit.csproj
index f6004fb9c3..293648a732 100644
--- a/Octokit/Octokit.csproj
+++ b/Octokit/Octokit.csproj
@@ -90,6 +90,7 @@
+
@@ -112,6 +113,7 @@
+
@@ -371,6 +373,11 @@
+
+
+
+
+