From 93731840a1efb22275f15c4779feaa9b61fcadb3 Mon Sep 17 00:00:00 2001 From: Anton Ganhammar Date: Tue, 8 Oct 2024 21:49:53 +0200 Subject: [PATCH] feat: add additional configuration option (#568) * feat: add additional configuration option * chore: add tests for github webhooks azure functions host builder extensions --------- Co-authored-by: Nick Floyd <139819+nickfloyd@users.noreply.github.com> --- Octokit.Webhooks.sln | 13 +++- README.md | 6 +- .../GithubWebhookHostBuilderExtensions.cs | 18 ++++- ...GithubWebhookHostBuilderExtensionsTests.cs | 78 +++++++++++++++++++ ...ctokit.Webhooks.AzureFunctions.Test.csproj | 18 +++++ 5 files changed, 128 insertions(+), 5 deletions(-) create mode 100644 test/Octokit.Webhooks.AzureFunctions.Test/GithubWebhookHostBuilderExtensionsTests.cs create mode 100644 test/Octokit.Webhooks.AzureFunctions.Test/Octokit.Webhooks.AzureFunctions.Test.csproj diff --git a/Octokit.Webhooks.sln b/Octokit.Webhooks.sln index f6f88f5f..a4b1f7b1 100644 --- a/Octokit.Webhooks.sln +++ b/Octokit.Webhooks.sln @@ -31,9 +31,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{E1B24F25-B EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "images", "images", "{26F71F5B-2940-4FB0-9681-A76060CBCEF9}" -ProjectSection(SolutionItems) = preProject - images\Icon.png = images\Icon.png -EndProjectSection + ProjectSection(SolutionItems) = preProject + images\Icon.png = images\Icon.png + EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ISSUE_TEMPLATE", "ISSUE_TEMPLATE", "{566DF0E2-1288-4083-9B55-4C8B69BB1432}" ProjectSection(SolutionItems) = preProject @@ -70,6 +70,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureFunctions", "samples\A EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Octokit.Webhooks.AzureFunctions", "src\Octokit.Webhooks.AzureFunctions\Octokit.Webhooks.AzureFunctions.csproj", "{E7A3E0C8-CE8E-434D-8E97-723F9D5206FA}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Octokit.Webhooks.AzureFunctions.Test", "test\Octokit.Webhooks.AzureFunctions.Test\Octokit.Webhooks.AzureFunctions.Test.csproj", "{7B30ABC3-C016-4EA5-81C1-A51C28580D36}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -104,6 +106,10 @@ Global {E7A3E0C8-CE8E-434D-8E97-723F9D5206FA}.Debug|Any CPU.Build.0 = Debug|Any CPU {E7A3E0C8-CE8E-434D-8E97-723F9D5206FA}.Release|Any CPU.ActiveCfg = Release|Any CPU {E7A3E0C8-CE8E-434D-8E97-723F9D5206FA}.Release|Any CPU.Build.0 = Release|Any CPU + {7B30ABC3-C016-4EA5-81C1-A51C28580D36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7B30ABC3-C016-4EA5-81C1-A51C28580D36}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7B30ABC3-C016-4EA5-81C1-A51C28580D36}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7B30ABC3-C016-4EA5-81C1-A51C28580D36}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -119,6 +125,7 @@ Global {48EB4752-1A23-4DD2-AF86-21ED12475F8B} = {E1B24F25-B8A4-46EE-B7EB-7803DCFC543F} {8731AAA1-8F8D-441A-BD61-6CA3A16A805B} = {174C8B3B-E8D3-4845-AE7C-8C0DEC43354F} {E7A3E0C8-CE8E-434D-8E97-723F9D5206FA} = {719809C2-A551-4C4A-9EFD-B10FB5E35BC0} + {7B30ABC3-C016-4EA5-81C1-A51C28580D36} = {E1B24F25-B8A4-46EE-B7EB-7803DCFC543F} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {73F36209-F8D6-4066-8951-D97729F773CF} diff --git a/README.md b/README.md index 8d0d1b95..b48ef679 100644 --- a/README.md +++ b/README.md @@ -84,10 +84,14 @@ Libraries to handle GitHub Webhooks in .NET applications. .Build(); ``` -`ConfigureGitHubWebhooks()` takes one optional parameter: +`ConfigureGitHubWebhooks()` either takes an optional parameter: * `secret`. The secret you have configured in GitHub, if you have set this up. +or: + +* `configure`. A function that takes an IConfiguration instance and expects the secret you have configured in GitHub in return. + The function is available on the `/api/github/webhooks` endpoint. ## Thanks diff --git a/src/Octokit.Webhooks.AzureFunctions/GithubWebhookHostBuilderExtensions.cs b/src/Octokit.Webhooks.AzureFunctions/GithubWebhookHostBuilderExtensions.cs index 9672e2d3..147095ef 100644 --- a/src/Octokit.Webhooks.AzureFunctions/GithubWebhookHostBuilderExtensions.cs +++ b/src/Octokit.Webhooks.AzureFunctions/GithubWebhookHostBuilderExtensions.cs @@ -1,5 +1,7 @@ -namespace Octokit.Webhooks.AzureFunctions; +namespace Octokit.Webhooks.AzureFunctions; +using System; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -14,4 +16,18 @@ public static class GithubWebhookHostBuilderExtensions public static IHostBuilder ConfigureGitHubWebhooks(this IHostBuilder hostBuilder, string? secret = null) => hostBuilder.ConfigureServices(services => services.AddOptions().Configure(options => options.Secret = secret)); + + /// + /// Configures GitHub webhook function. + /// + /// instance. + /// A function that takes an instance and expects the secret you have configured in GitHub in return. + /// Returns instance. + public static IHostBuilder ConfigureGitHubWebhooks(this IHostBuilder hostBuilder, Func configure) + { + ArgumentNullException.ThrowIfNull(configure); + + return hostBuilder.ConfigureServices((context, services) => + services.AddOptions().Configure(options => options.Secret = configure(context.Configuration))); + } } diff --git a/test/Octokit.Webhooks.AzureFunctions.Test/GithubWebhookHostBuilderExtensionsTests.cs b/test/Octokit.Webhooks.AzureFunctions.Test/GithubWebhookHostBuilderExtensionsTests.cs new file mode 100644 index 00000000..ce80f640 --- /dev/null +++ b/test/Octokit.Webhooks.AzureFunctions.Test/GithubWebhookHostBuilderExtensionsTests.cs @@ -0,0 +1,78 @@ +namespace Octokit.Webhooks.AzureFunctions.Test; + +using System; +using System.Collections.Generic; +using FluentAssertions; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; +using Moq; +using Xunit; + +public class GithubWebhookHostBuilderExtensionsTests +{ + [Fact] + public void CanConfigureSecretUsingPlainText() + { + // Arrange + var mockHostBuilder = new Mock(); + var services = new ServiceCollection(); + var testSecret = "test-secret"; + + mockHostBuilder + .Setup(hb => hb.ConfigureServices(It.IsAny>())) + .Callback>((action) => + { + var context = new HostBuilderContext(new Dictionary()); + action(context, services); + }) + .Returns(mockHostBuilder.Object); + + // Act + mockHostBuilder.Object.ConfigureGitHubWebhooks(testSecret); + + // Assert + var serviceProvider = services.BuildServiceProvider(); + var options = serviceProvider.GetRequiredService>().Value; + Assert.Equal(testSecret, options.Secret); + } + + [Fact] + public void CanConfigureSecretUsingConfigurationInstance() + { + // Arrange + var mockHostBuilder = new Mock(); + var services = new ServiceCollection(); + var testSecret = "test-secret"; + var configuration = new ConfigurationBuilder() + .AddInMemoryCollection(new Dictionary + { + ["GitHubSecret"] = testSecret, + }) + .Build(); + + mockHostBuilder + .Setup(hb => hb.ConfigureServices(It.IsAny>())) + .Callback>((action) => + { + var context = new HostBuilderContext(new Dictionary()) + { + Configuration = configuration, + }; + action(context, services); + }) + .Returns(mockHostBuilder.Object); + + static string Configure(IConfiguration config) => config.GetValue("GitHubSecret") + ?? throw new ArgumentNullException(); + + // Act + mockHostBuilder.Object.ConfigureGitHubWebhooks(Configure); + + // Assert + var serviceProvider = services.BuildServiceProvider(); + var options = serviceProvider.GetRequiredService>().Value; + Assert.Equal(testSecret, options.Secret); + } +} diff --git a/test/Octokit.Webhooks.AzureFunctions.Test/Octokit.Webhooks.AzureFunctions.Test.csproj b/test/Octokit.Webhooks.AzureFunctions.Test/Octokit.Webhooks.AzureFunctions.Test.csproj new file mode 100644 index 00000000..d33200a1 --- /dev/null +++ b/test/Octokit.Webhooks.AzureFunctions.Test/Octokit.Webhooks.AzureFunctions.Test.csproj @@ -0,0 +1,18 @@ + + + + net6.0 + + + + + + + + + + PreserveNewest + + + +