Permalink
Browse files

Adding support for Fog Creek's Kiln

This adds support for Fog Creek's Kiln. It has support for both hosted
and self-hosted sites along with public and private repositories.

The MockDeploymentSettingsManager was also updated to use TryGet which
makes its functionality better match that of DeploymentSettingsManager.
  • Loading branch information...
1 parent 4ec8484 commit 87759de06e9f11883ca990833fefc7584fd96efc @xt0rted xt0rted committed with davidebbo Jan 16, 2013
@@ -27,7 +27,9 @@ public void SetValue(string key, string value)
public string GetValue(string key)
{
- return _settings[key];
+ string value;
+ _settings.TryGetValue(key, out value);
+ return value;
}
public void DeleteValue(string key)
@@ -0,0 +1,248 @@
+using System;
+using System.Web;
+using Kudu.Core.Test;
+using Kudu.Services.ServiceHookHandlers;
+using Moq;
+using Newtonsoft.Json.Linq;
+using Xunit;
+using Xunit.Extensions;
+
+namespace Kudu.Services.Test
+{
+ public class KilnHgHandlerFacts
+ {
+ [Fact]
+ public void KilnHgHandlerIgnoresNonKilnPayloads()
+ {
+ // Arrange
+ var payload = JObject.Parse(@"{ ""repository"":{ ""repourl"":""http://test.codebasehq.com/projects/test-repositories/repositories/git1/commit/840daf31f4f87cb5cafd295ef75de989095f415b"" } }");
+ var httpRequest = new Mock<HttpRequestBase>();
+ var settingsManager = new MockDeploymentSettingsManager();
+ var kilnHandler = new KilnHgHandler(settingsManager);
+
+ // Act
+ DeploymentInfo deploymentInfo;
+ DeployAction result = kilnHandler.TryParseDeploymentInfo(httpRequest.Object, payload: payload, targetBranch: null, deploymentInfo: out deploymentInfo);
+
+ // Assert
+ Assert.Equal(DeployAction.UnknownPayload, result);
+ }
+
+ [Fact]
+ public void KilnHgHandlerReturnsNoOpForCommitsThatAreNotTheTargetBranch()
+ {
+ // Arrange
+ const string payload = @" { ""commits"": [ { ""author"": ""Brian Surowiec <xtorted@optonline.net>"", ""branch"": ""default"", ""id"": ""771363bfb8e6e2b76a3da8d156c6a3db0ea9a9c4"", ""message"": ""did a commit"", ""revision"": 1, ""timestamp"": ""1/7/2013 6:54:25 AM"" } ], ""repository"": { ""url"": ""https://kudutest.kilnhg.com/Code/Test/Group/KuduApp"" } } ";
+ var httpRequest = new Mock<HttpRequestBase>();
+ var settingsManager = new MockDeploymentSettingsManager();
+ var kilnHandler = new KilnHgHandler(settingsManager);
+
+ // Act
+ DeploymentInfo deploymentInfo;
+ DeployAction result = kilnHandler.TryParseDeploymentInfo(httpRequest.Object, payload: JObject.Parse(payload), targetBranch: "not-default", deploymentInfo: out deploymentInfo);
+
+ // Assert
+ Assert.Equal(DeployAction.NoOp, result);
+ Assert.Null(deploymentInfo);
+ }
+
+ [Fact]
+ public void KilnHgHandlerParsesKilnPayloads()
+ {
+ // Arrange
+ const string payload = @"{ ""commits"": [ { ""author"": ""Brian Surowiec <xtorted@optonline.net>"", ""branch"": ""default"", ""id"": ""f1525c29206072f6565e6ba70831afb65b55e9a0"", ""message"": ""Added some content that was missed the last time around"", ""revision"": 14, ""timestamp"": ""1/15/2013 2:23:37 AM"" } ], ""repository"": { ""url"": ""https://kudutest.kilnhg.com:81/Code/Test/Group/KuduApp"" } }";
+ var httpRequest = new Mock<HttpRequestBase>();
+ var settingsManager = new MockDeploymentSettingsManager();
+ var kilnHandler = new KilnHgHandler(settingsManager);
+
+ // Act
+ DeploymentInfo deploymentInfo;
+ DeployAction result = kilnHandler.TryParseDeploymentInfo(httpRequest.Object, payload: JObject.Parse(payload), targetBranch: "default", deploymentInfo: out deploymentInfo);
+
+ // Assert
+ Assert.Equal(DeployAction.ProcessDeployment, result);
+ Assert.Equal("Kiln", deploymentInfo.Deployer);
+ Assert.Equal("https://kudutest.kilnhg.com:81/Code/Test/Group/KuduApp", deploymentInfo.RepositoryUrl);
+ Assert.Equal("Brian Surowiec", deploymentInfo.TargetChangeset.AuthorName);
+ Assert.Equal("xtorted@optonline.net", deploymentInfo.TargetChangeset.AuthorEmail);
+ Assert.Equal("f1525c29206072f6565e6ba70831afb65b55e9a0", deploymentInfo.TargetChangeset.Id);
+ Assert.Equal("Added some content that was missed the last time around", deploymentInfo.TargetChangeset.Message);
+ Assert.Equal(new DateTimeOffset(2013, 1, 15, 2, 23, 37, TimeSpan.Zero), deploymentInfo.TargetChangeset.Timestamp);
+ }
+
+ [Fact]
+ public void KilnHgHandlerParsesKilnPayloadsWithAccessTokenCommit()
+ {
+ // Arrange - in my testing with public repos kiln seems to return https urls using port 81 so this test follows those results
+ const string payload = @"{ ""commits"": [ { ""author"": ""a1444778-8d5d-413d-83f7-6dbf9e2cd77d"", ""branch"": ""default"", ""id"": ""f1525c29206072f6565e6ba70831afb65b55e9a0"", ""message"": ""Added some content that was missed the last time around"", ""revision"": 14, ""timestamp"": ""1/15/2013 2:23:37 AM"" } ], ""repository"": { ""url"": ""https://kudutest.kilnhg.com:81/Code/Test/Group/KuduApp"" } }";
+ var httpRequest = new Mock<HttpRequestBase>();
+ var settingsManager = new MockDeploymentSettingsManager();
+ var kilnHandler = new KilnHgHandler(settingsManager);
+
+ // Act
+ DeploymentInfo deploymentInfo;
+ DeployAction result = kilnHandler.TryParseDeploymentInfo(httpRequest.Object, payload: JObject.Parse(payload), targetBranch: "default", deploymentInfo: out deploymentInfo);
+
+ // Assert
+ Assert.Equal(DeployAction.ProcessDeployment, result);
+ Assert.Equal("Kiln", deploymentInfo.Deployer);
+ Assert.Equal("https://kudutest.kilnhg.com:81/Code/Test/Group/KuduApp", deploymentInfo.RepositoryUrl);
+ Assert.Equal("System Account", deploymentInfo.TargetChangeset.AuthorName);
+ Assert.Null(deploymentInfo.TargetChangeset.AuthorEmail);
+ Assert.Equal("f1525c29206072f6565e6ba70831afb65b55e9a0", deploymentInfo.TargetChangeset.Id);
+ Assert.Equal("Added some content that was missed the last time around", deploymentInfo.TargetChangeset.Message);
+ Assert.Equal(new DateTimeOffset(2013, 1, 15, 2, 23, 37, TimeSpan.Zero), deploymentInfo.TargetChangeset.Timestamp);
+ }
+
+ [Fact]
+ public void KilnHgHandlerParsesKilnPayloadsForPrivateRepositories()
+ {
+ // Arrange
+ const string payload = @" { ""commits"": [ { ""author"": ""Brian Surowiec <xtorted@optonline.net>"", ""branch"": ""default"", ""id"": ""771363bfb8e6e2b76a3da8d156c6a3db0ea9a9c4"", ""message"": ""did a commit"", ""revision"": 1, ""timestamp"": ""1/7/2013 6:54:25 AM"" } ], ""repository"": { ""url"": ""https://kudutest.kilnhg.com/Code/Test/Group/KuduApp"" } } ";
+ var httpRequest = new Mock<HttpRequestBase>();
+ var settingsManager = new MockDeploymentSettingsManager();
+ settingsManager.SetValue("kiln.accesstoken", "hg-user");
+ var kilnHandler = new KilnHgHandler(settingsManager);
+
+ // Act
+ DeploymentInfo deploymentInfo;
+ DeployAction result = kilnHandler.TryParseDeploymentInfo(httpRequest.Object, payload: JObject.Parse(payload), targetBranch: "default", deploymentInfo: out deploymentInfo);
+
+ // Assert
+ Assert.Equal(DeployAction.ProcessDeployment, result);
+ Assert.Equal("Kiln", deploymentInfo.Deployer);
+ Assert.Equal("https://hg-user:kudu@kudutest.kilnhg.com:443/Code/Test/Group/KuduApp", deploymentInfo.RepositoryUrl);
+ Assert.Equal("Brian Surowiec", deploymentInfo.TargetChangeset.AuthorName);
+ Assert.Equal("xtorted@optonline.net", deploymentInfo.TargetChangeset.AuthorEmail);
+ Assert.Equal("771363bfb8e6e2b76a3da8d156c6a3db0ea9a9c4", deploymentInfo.TargetChangeset.Id);
+ Assert.Equal("did a commit", deploymentInfo.TargetChangeset.Message);
+ Assert.Equal(new DateTimeOffset(2013, 1, 7, 6, 54, 25, TimeSpan.Zero), deploymentInfo.TargetChangeset.Timestamp);
+ }
+
+ [Fact]
+ public void KilnHgHandlerParsesKilnPayloadsForRepositoriesWithMultipleCommitsAccrossBranches()
+ {
+ // Arrange
+ const string payload = @"{ ""commits"": ["
+ + @"{ ""author"": ""Brian Surowiec <xtorted@optonline.net>"", ""branch"": ""non-default"", ""id"": ""f1525c29206072f6565e6ba70831afb65b55e9a0"", ""message"": ""Added some content that was missed the last time around"", ""revision"": 14, ""timestamp"": ""1/15/2013 2:23:37 AM"" },"
+ + @"{ ""author"": ""Brian Surowiec <xtorted@optonline.net>"", ""branch"": ""default"", ""id"": ""58df029b9891bed6be1516971b50dc0eda58ce38"", ""message"": ""Added some more content"", ""revision"": 13, ""timestamp"": ""1/15/2013 2:23:20 AM"" },"
+ + @"{ ""author"": ""Brian Surowiec <xtorted@optonline.net>"", ""branch"": ""default"", ""id"": ""cb6ea738f5ec16d53c06a2f5823c34b396922c13"", ""message"": ""Added some content in"", ""revision"": 12, ""timestamp"": ""1/15/2013 2:23:04 AM"" }"
+ + @"], ""repository"": { ""url"": ""https://kudutest.kilnhg.com/Code/Test/Group/KuduApp"" } }";
+ var httpRequest = new Mock<HttpRequestBase>();
+ var settingsManager = new MockDeploymentSettingsManager();
+ settingsManager.SetValue("kiln.accesstoken", "hg-user");
+ var kilnHandler = new KilnHgHandler(settingsManager);
+
+ // Act
+ DeploymentInfo deploymentInfo;
+ DeployAction result = kilnHandler.TryParseDeploymentInfo(httpRequest.Object, payload: JObject.Parse(payload), targetBranch: "default", deploymentInfo: out deploymentInfo);
+
+ // Assert
+ Assert.Equal(DeployAction.ProcessDeployment, result);
+ Assert.Equal("Kiln", deploymentInfo.Deployer);
+ Assert.Equal("https://hg-user:kudu@kudutest.kilnhg.com:443/Code/Test/Group/KuduApp", deploymentInfo.RepositoryUrl);
+ Assert.Equal("Brian Surowiec", deploymentInfo.TargetChangeset.AuthorName);
+ Assert.Equal("xtorted@optonline.net", deploymentInfo.TargetChangeset.AuthorEmail);
+ Assert.Equal("58df029b9891bed6be1516971b50dc0eda58ce38", deploymentInfo.TargetChangeset.Id);
+ Assert.Equal("Added some more content", deploymentInfo.TargetChangeset.Message);
+ Assert.Equal(new DateTimeOffset(2013, 1, 15, 2, 23, 20, TimeSpan.Zero), deploymentInfo.TargetChangeset.Timestamp);
+ }
+
+ [Theory]
+ [InlineData(@"{ ""repo"": { ""repo_url"": ""https://kudutest.kilnhg.com/Code/Test/Group/KuduApp"" } } ")]
+ [InlineData(@"{ ""repository"": { ""repo_url"": ""https://kudutest.kilnhg.com/Code/Test/Group/KuduApp"" } } ")]
+ public void IsKilnRequestWithoutRepositoryUrl(string payloadContent)
+ {
+ // Arrange
+ var settingsManager = new MockDeploymentSettingsManager();
+ var kilnHandler = new KilnHgHandler(settingsManager);
+
+ // Act
+ bool result = kilnHandler.IsKilnRequest(JObject.Parse(payloadContent));
+
+ // Assert
+ Assert.False(result);
+ }
+
+ [Theory]
+ [InlineData(true, @"\.kilnhg\.com")]
+ [InlineData(false, @"\.github\.com")]
+ public void IsKilnRequestWithCustomDomainPatterns(bool expectedResult, string domainPattern)
+ {
+ // Arrange
+ const string payload = @"{ ""repository"": { ""url"": ""https://kudu.kilnhg.com/Code/Test/Group/KuduApp"" } } ";
+
+ var settingsManager = new MockDeploymentSettingsManager();
+ settingsManager.SetValue("kiln.domain", domainPattern);
+
+ var kilnHandler = new KilnHgHandler(settingsManager);
+
+ // Act
+ bool result = kilnHandler.IsKilnRequest(JObject.Parse(payload));
+
+ // Assert
+ Assert.Equal(expectedResult, result);
+ }
+
+ [Theory]
+ [InlineData(true, @"kilnhg.com")]
+ [InlineData(false, @"github.com")]
+ public void IsKilnRequestWithDefaultDomainPatterns(bool expectedResult, string domain)
+ {
+ // Arrange
+ var payload = string.Format(@"{{ ""repository"": {{ ""url"": ""https://kudu.{0}/Code/Test/Group/KuduApp"" }} }} ", domain);
+ var settingsManager = new MockDeploymentSettingsManager();
+ var kilnHandler = new KilnHgHandler(settingsManager);
+
+ // Act
+ bool result = kilnHandler.IsKilnRequest(JObject.Parse(payload));
+
+ // Assert
+ Assert.Equal(expectedResult, result);
+ }
+
+ [Theory]
+ [InlineData("Test User <test@user.com>")] // full, correct, format
+ [InlineData(" <test@user.com>")] // missing first & last name, with spaces
+ [InlineData("Test <test@user.com>")] // only first name
+ [InlineData(" User <test@user.com>")] // only last name, with spaces
+ [InlineData("<test@user.com>")] // only email, no spaces
+ [InlineData("test@user.com")] // only email, no other formatting
+ public void ParseEmailFromAuthorWithEmailAddress(string author)
+ {
+ Assert.Equal("test@user.com", KilnHgHandler.ParseEmailFromAuthor(author));
+ }
+
+ [Theory]
+ [InlineData("Test User")]
+ [InlineData("Test User <>")]
+ [InlineData("Test User <email>")]
+ [InlineData(null)]
+ [InlineData("")]
+ [InlineData("\t")]
+ [InlineData(" ")]
+ public void ParseEmailFromAuthorWithoutEmailAddress(string author)
+ {
+ Assert.Null(KilnHgHandler.ParseEmailFromAuthor(author));
+ }
+
+ [Theory]
+ [InlineData("Test User", "Test User <test@user.com>")] // full, correct, format
+ [InlineData("<test@user.com>", " <test@user.com>")] // missing first & last name, with spaces
+ [InlineData("Test", "Test <test@user.com>")] // only first name
+ [InlineData("User", " User <test@user.com>")] // only last name, with spaces
+ [InlineData("<test@user.com>", "<test@user.com>")] // only email, no spaces
+ [InlineData("test@user.com", "test@user.com")] // only email, no other formatting
+ [InlineData("Test User", " Test User ")]
+ [InlineData("Test User", "Test User <>")]
+ [InlineData("Test User", "Test User <email>")]
+ [InlineData(null, null)]
+ [InlineData(null, "")]
+ [InlineData(null, "\t")]
+ [InlineData(null, " ")]
+ public void ParseNameFromAuthor(string expectedResult, string author)
+ {
+ Assert.Equal(expectedResult, KilnHgHandler.ParseNameFromAuthor(author));
+ }
+ }
+}
@@ -62,11 +62,15 @@
</Reference>
</ItemGroup>
<ItemGroup>
+ <Compile Include="..\Kudu.Core.Test\MockDeploymentSettingsManager.cs">
+ <Link>MockDeploymentSettingsManager.cs</Link>
+ </Compile>
<Compile Include="BitbucketHandlerFacts.cs" />
<Compile Include="CodeBaseHqFacts.cs" />
<Compile Include="CodePlexHandlerFacts.cs" />
<Compile Include="GithubHandlerFacts.cs" />
<Compile Include="Infrastructure\MediaTypeMapTest.cs" />
+ <Compile Include="KilnHgHandlerFacts.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
@@ -176,6 +176,7 @@ private static void RegisterServices(IKernel kernel)
kernel.Bind<IServiceHookHandler>().To<CodebaseHqHandler>().InRequestScope();
kernel.Bind<IServiceHookHandler>().To<GitlabHqHandler>().InRequestScope();
kernel.Bind<IServiceHookHandler>().To<GitHubCompatHandler>().InRequestScope();
+ kernel.Bind<IServiceHookHandler>().To<KilnHgHandler>().InRequestScope();
// Command executor
kernel.Bind<ICommandExecutor>().ToMethod(context => GetCommandExecutor(environment, context))
@@ -153,6 +153,7 @@
<Compile Include="ByteRanges\HttpRequestMessageExtensions.cs" />
<Compile Include="Infrastructure\MediaTypeMap.cs" />
<Compile Include="Infrastructure\VfsControllerBase.cs" />
+ <Compile Include="ServiceHookHandlers\KilnHgHandler.cs" />
<Compile Include="ServiceHookHandlers\ServiceHookHandlerBase.cs" />
<Compile Include="SourceControl\LiveScmEditorController.cs" />
<Compile Include="SSHKey\SSHKeyController.cs" />
Oops, something went wrong.

0 comments on commit 87759de

Please sign in to comment.