Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add helper class for creating web hooks #917

Merged
merged 8 commits into from
Nov 11, 2015
Merged
30 changes: 23 additions & 7 deletions Octokit.Tests.Integration/Clients/RepositoryHooksClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,35 +63,51 @@ public async Task CreateAWebHookForTestRepository()
var repoName = Helper.MakeNameWithTimestamp("create-hooks-test");
var repository = await github.Repository.Create(new NewRepository(repoName) { AutoInit = true });

var url = "http://test.com/example";
var contentType = WebHookContentType.Json;
var secret = "53cr37";
var config = new Dictionary<string, string>
{
{ "content_type", "json" },
{ "url", "http://test.com/example" },
{ "hostname", "http://hostname.url" },
{ "username", "username" },
{ "password", "password" }
};
var parameters = new NewRepositoryHook("windowsazure", config)
var parameters = new NewRepositoryWebHook("windowsazure", config, url)
{
Events = new[] { "push" },
Active = false
Active = false,
ContentType = contentType,
Secret = secret
};

var hook = await github.Repository.Hooks.Create(Helper.Credentials.Login, repository.Name, parameters);
var hook = await github.Repository.Hooks.Create(Helper.Credentials.Login, repository.Name, parameters.ToRequest());

var baseHookUrl = CreateExpectedBaseHookUrl(repository.Url, hook.Id);
var webHookConfig = CreateExpectedConfigDictionary(config, url, contentType, secret);

Assert.Equal("windowsazure", hook.Name);
Assert.Equal(new[] { "push" }.ToList(), hook.Events.ToList());
Assert.Equal(baseHookUrl, hook.Url);
Assert.Equal(baseHookUrl + "/test", hook.TestUrl);
Assert.Equal(baseHookUrl + "/pings", hook.PingUrl);
Assert.NotNull(hook.CreatedAt);
Assert.NotNull(hook.UpdatedAt);
Assert.Equal(config.Keys, hook.Config.Keys);
Assert.Equal(config.Values, hook.Config.Values);
Assert.Equal(webHookConfig.Keys, hook.Config.Keys);
Assert.Equal(webHookConfig.Values, hook.Config.Values);
Assert.Equal(false, hook.Active);
}

Dictionary<string, string> CreateExpectedConfigDictionary(Dictionary<string, string> config, string url, WebHookContentType contentType, string secret)
{
return config.Union(new Dictionary<string, string>
{
{ "url", url },
{ "content_type", contentType.ToString().ToLowerInvariant() },
{ "secret", secret },
{ "insecure_ssl", "False" }
}).ToDictionary(k => k.Key, v => v.Value);
}

string CreateExpectedBaseHookUrl(string url, int id)
{
return url + "/hooks/" + id;
Expand Down
108 changes: 108 additions & 0 deletions Octokit.Tests/Models/NewRepositoryWebHookTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
using System.Collections.Generic;
using Xunit;

namespace Octokit.Tests.Models
{
public class NewRepositoryWebHookTests
{
public class TheCtor
{
string ExpectedRepositoryWebHookConfigExceptionMessage =
"Duplicate webhook config values found - these values: Url should not be passed in as part of the config values. Use the properties on the NewRepositoryWebHook class instead.";

[Fact]
public void UsesDefaultValuesForDefaultConfig()
{
var create = new NewRepositoryWebHook("windowsazure", new Dictionary<string, string>(), "http://test.com/example");
Assert.Equal(create.Url, "http://test.com/example");
Assert.Equal(create.ContentType, WebHookContentType.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"], WebHookContentType.Form.ToParameter());
Assert.Equal(request.Config["secret"], "");
Assert.Equal(request.Config["insecure_ssl"], "False");
}

[Fact]
public void CombinesUserSpecifiedContentTypeWithConfig()
{
var config = new Dictionary<string, string>
{
{"hostname", "http://hostname.url"},
{"username", "username"},
{"password", "password"}
};

var create = new NewRepositoryWebHook("windowsazure", config, "http://test.com/example")
{
ContentType = WebHookContentType.Json,
Secret = string.Empty,
InsecureSsl = true
};

Assert.Equal(create.Url, "http://test.com/example");
Assert.Equal(create.ContentType, WebHookContentType.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"], WebHookContentType.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 ShouldThrowRepositoryWebHookConfigExceptionWhenDuplicateKeysExists()
{
var config = new Dictionary<string, string>
{
{"url", "http://example.com/test"},
{"hostname", "http://hostname.url"},
{"username", "username"},
{"password", "password"}
};

var create = new NewRepositoryWebHook("windowsazure", config, "http://test.com/example")
{
ContentType = WebHookContentType.Json,
Secret = string.Empty,
InsecureSsl = true
};

Assert.Equal(create.Url, "http://test.com/example");
Assert.Equal(create.ContentType, WebHookContentType.Json);
Assert.Empty(create.Secret);
Assert.True(create.InsecureSsl);

var ex = Assert.Throws<RepositoryWebHookConfigException>(() => create.ToRequest());
Assert.Equal(ExpectedRepositoryWebHookConfigExceptionMessage, ex.Message);
}
}
}
}
1 change: 1 addition & 0 deletions Octokit.Tests/Octokit.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@
<Compile Include="Models\MilestoneRequestTests.cs" />
<Compile Include="Models\IssueRequestTests.cs" />
<Compile Include="Models\ModelExtensionsTests.cs" />
<Compile Include="Models\NewRepositoryWebHookTests.cs" />
<Compile Include="Models\PullRequestRequestTests.cs" />
<Compile Include="Models\PunchCardTests.cs" />
<Compile Include="Models\ReadOnlyPagedCollectionTests.cs" />
Expand Down
2 changes: 1 addition & 1 deletion Octokit/Clients/RepositoryHooksClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public Task<RepositoryHook> Create(string owner, string repositoryName, NewRepos
Ensure.ArgumentNotNullOrEmptyString(repositoryName, "repositoryName");
Ensure.ArgumentNotNull(hook, "hook");

return ApiConnection.Post<RepositoryHook>(ApiUrls.RepositoryHooks(owner, repositoryName), hook);
return ApiConnection.Post<RepositoryHook>(ApiUrls.RepositoryHooks(owner, repositoryName), hook.ToRequest());
}

/// <summary>
Expand Down
60 changes: 60 additions & 0 deletions Octokit/Exceptions/RepositoryWebHookConfigException.cs
Original file line number Diff line number Diff line change
@@ -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 RepositoryWebHookConfigException : Exception
{
readonly string message;

public RepositoryWebHookConfigException(IEnumerable<string> 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 NewRepositoryWebHook class instead.",
parameterList);
}

public override string Message
{
get { return message; }
}

#if !NETFX_CORE
/// <summary>
/// Constructs an instance of RepositoryWebHookConfigException
/// </summary>
/// <param name="info">
/// The <see cref="SerializationInfo"/> that holds the
/// serialized object data about the exception being thrown.
/// </param>
/// <param name="context">
/// The <see cref="StreamingContext"/> that contains
/// contextual information about the source or destination.
/// </param>
protected RepositoryWebHookConfigException(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
}
}
11 changes: 11 additions & 0 deletions Octokit/Helpers/StringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,17 @@ public static string ToRubyCase(this string propertyName)
return string.Join("_", propertyName.SplitUpperCase()).ToLowerInvariant();
}

public static string FromRubyCase(this string propertyName)
{
Ensure.ArgumentNotNullOrEmptyString(propertyName, "s");
return string.Join("", propertyName.Split('_')).ToCapitalizedInvariant();
}

public static string ToCapitalizedInvariant(this string value)
{
Ensure.ArgumentNotNullOrEmptyString(value, "s");
return string.Concat(value[0].ToString().ToUpperInvariant(), value.Substring(1));
}
static IEnumerable<string> SplitUpperCase(this string source)
{
Ensure.ArgumentNotNullOrEmptyString(source, "source");
Expand Down
17 changes: 17 additions & 0 deletions Octokit/Helpers/WebHookConfigComparer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Collections.Generic;

namespace Octokit
{
public class WebHookConfigComparer : IEqualityComparer<KeyValuePair<string, string>>
{
public bool Equals(KeyValuePair<string, string> x, KeyValuePair<string, string> y)
{
return x.Key == y.Key;
}

public int GetHashCode(KeyValuePair<string, string> obj)
{
return obj.Key.GetHashCode();
}
}
}
11 changes: 8 additions & 3 deletions Octokit/Models/Request/NewRepositoryHook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ namespace Octokit
/// <item>
/// <term>content_type</term>
/// <description>
/// An optional string defining the media type used to serialize the payloads.Supported values include json and
/// form.The default is form.
/// An optional string defining the media type used to serialize the payloads. Supported values include json and
/// form. The default is form.
/// </description>
/// </item>
/// <item>
Expand All @@ -33,7 +33,7 @@ namespace Octokit
/// <term>insecure_ssl:</term>
/// <description>
/// 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
/// delivering payloads. Supported values include "0" (verification is performed) and "1" (verification is not
/// performed). The default is "0".
/// </description>
/// </item>
Expand Down Expand Up @@ -100,6 +100,11 @@ public NewRepositoryHook(string name, IReadOnlyDictionary<string, string> config
/// </value>
public bool Active { get; set; }

public virtual NewRepositoryHook ToRequest()
{
return this;
}

internal string DebuggerDisplay
{
get
Expand Down
Loading