Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
281 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
using System; | ||
using System.IO; | ||
using System.Reflection; | ||
using System.Web; | ||
using Kudu.Services.ServiceHookHandlers; | ||
using Moq; | ||
using Newtonsoft.Json; | ||
using Newtonsoft.Json.Linq; | ||
using Xunit; | ||
|
||
namespace Kudu.Services.Test | ||
{ | ||
public class VSOHandlerFacts | ||
{ | ||
[Fact] | ||
public void VSOHandlerBasic() | ||
{ | ||
// Arrange | ||
var payload = GetVSOPayload(); | ||
var httpRequest = new Mock<HttpRequestBase>(); | ||
var handler = new VSOHandler(); | ||
|
||
// Act | ||
DeploymentInfo deploymentInfo; | ||
DeployAction result = handler.TryParseDeploymentInfo(httpRequest.Object, payload: payload, targetBranch: "master", deploymentInfo: out deploymentInfo); | ||
|
||
// Assert | ||
Assert.Equal(DeployAction.ProcessDeployment, result); | ||
Assert.NotNull(deploymentInfo); | ||
Assert.Equal("this_is_latest_commit", deploymentInfo.CommitId); | ||
Assert.Equal("this_is_latest_commit", deploymentInfo.TargetChangeset.Id); | ||
Assert.Equal("John Smith", deploymentInfo.TargetChangeset.AuthorName); | ||
Assert.Equal("test01@hotmail.com", deploymentInfo.TargetChangeset.AuthorEmail); | ||
Assert.Equal("commit message", deploymentInfo.TargetChangeset.Message); | ||
Assert.Equal(DateTime.Parse("2015-05-08T00:20:59Z"), deploymentInfo.TargetChangeset.Timestamp); | ||
|
||
var repositoryUri = new Uri(deploymentInfo.RepositoryUrl); | ||
Assert.Equal("https", repositoryUri.Scheme); | ||
Assert.Equal("test01.vsoalm.tfsallin.net", repositoryUri.Host); | ||
Assert.Equal("/DefaultCollection/_git/testgit01", repositoryUri.AbsolutePath); | ||
Assert.Equal("this_is_vso_token", repositoryUri.UserInfo); | ||
} | ||
|
||
[Fact] | ||
public void VSOHandlerMismatchBranch() | ||
{ | ||
// Arrange | ||
var payload = GetVSOPayload(); | ||
var httpRequest = new Mock<HttpRequestBase>(); | ||
var handler = new VSOHandler(); | ||
|
||
// Act | ||
DeploymentInfo deploymentInfo; | ||
DeployAction result = handler.TryParseDeploymentInfo(httpRequest.Object, payload: payload, targetBranch: "foo", deploymentInfo: out deploymentInfo); | ||
|
||
// Assert | ||
Assert.Equal(DeployAction.NoOp, result); | ||
} | ||
|
||
[Fact] | ||
public void VSOHandlerUnknownPayload() | ||
{ | ||
// Arrange | ||
var payload = new JObject(); | ||
var httpRequest = new Mock<HttpRequestBase>(); | ||
var handler = new VSOHandler(); | ||
|
||
// Act | ||
DeploymentInfo deploymentInfo; | ||
DeployAction result = handler.TryParseDeploymentInfo(httpRequest.Object, payload: payload, targetBranch: "master", deploymentInfo: out deploymentInfo); | ||
|
||
// Assert | ||
Assert.Equal(DeployAction.UnknownPayload, result); | ||
} | ||
|
||
private static JObject GetVSOPayload() | ||
{ | ||
Assembly assembly = Assembly.GetExecutingAssembly(); | ||
using (var reader = new StreamReader(assembly.GetManifestResourceStream("Kudu.Services.Test.vsopayload.json"))) | ||
{ | ||
return (JObject)JToken.ReadFrom(new JsonTextReader(reader)); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
{ | ||
"subscriptionId": "5711b3fd-0121-4fcb-8874-40f5a37fc714", | ||
"notificationId": 1, | ||
"id": "4505c95e-bcf6-4354-8b20-769ea5c302d6", | ||
"eventType": "git.push", | ||
"publisherId": "tfs", | ||
"message": null, | ||
"detailedMessage": null, | ||
"resource": { | ||
"commits": [ | ||
{ | ||
"commitId": "this_is_latest_commit", | ||
"author": { | ||
"name": "John Smith", | ||
"email": "test01@hotmail.com", | ||
"date": "2015-05-08T00:20:59Z" | ||
}, | ||
"committer": { | ||
"name": "John Smith", | ||
"email": "test01@hotmail.com", | ||
"date": "2015-05-08T00:20:59Z" | ||
}, | ||
"comment": "commit message", | ||
"url": "https://test01.vsoalm.tfsallin.net/DefaultCollection/_apis/git/repositories/9cd8a073-c67d-4725-8870-ce6fda346771/commits/this_is_latest_commit" | ||
} | ||
], | ||
"refUpdates": [ | ||
{ | ||
"name": "refs/heads/master", | ||
"oldObjectId": "this_is_old_commit", | ||
"newObjectId": "this_is_latest_commit" | ||
} | ||
], | ||
"repository": { | ||
"id": "9cd8a073-c67d-4725-8870-ce6fda346771", | ||
"name": "testgit01", | ||
"url": "https://test01.vsoalm.tfsallin.net/DefaultCollection/_apis/git/repositories/9cd8a073-c67d-4725-8870-ce6fda346771", | ||
"project": { | ||
"id": "5ec775cb-c546-4106-8a62-acd8ffd21339", | ||
"name": "testgit01", | ||
"url": "https://test01.vsoalm.tfsallin.net/DefaultCollection/_apis/projects/5ec775cb-c546-4106-8a62-acd8ffd21339", | ||
"state": "wellFormed" | ||
}, | ||
"defaultBranch": "refs/heads/master", | ||
"remoteUrl": "https://test01.vsoalm.tfsallin.net/DefaultCollection/_git/testgit01" | ||
}, | ||
"pushedBy": { | ||
"id": "c11fa894-cdcd-4da1-84c8-fe06e7aa17f2", | ||
"displayName": "John Smith", | ||
"uniqueName": "test01@hotmail.com", | ||
"url": "https://test01.vsoalmsps.tfsallin.net/_apis/Identities/c11fa894-cdcd-4da1-84c8-fe06e7aa17f2", | ||
"imageUrl": "https://test01.vsoalm.tfsallin.net/DefaultCollection/_api/_common/identityImage?id=c11fa894-cdcd-4da1-84c8-fe06e7aa17f2" | ||
}, | ||
"pushId": 11, | ||
"date": "2015-05-08T00:21:09.7569964Z", | ||
"url": "https://test01.vsoalm.tfsallin.net/DefaultCollection/_apis/git/repositories/9cd8a073-c67d-4725-8870-ce6fda346771/pushes/11", | ||
"_links": { | ||
"self": { | ||
"href": "https://test01.vsoalm.tfsallin.net/DefaultCollection/_apis/git/repositories/9cd8a073-c67d-4725-8870-ce6fda346771/pushes/11" | ||
}, | ||
"repository": { | ||
"href": "https://test01.vsoalm.tfsallin.net/DefaultCollection/_apis/git/repositories/9cd8a073-c67d-4725-8870-ce6fda346771" | ||
}, | ||
"commits": { | ||
"href": "https://test01.vsoalm.tfsallin.net/DefaultCollection/_apis/git/repositories/9cd8a073-c67d-4725-8870-ce6fda346771/pushes/11/commits" | ||
}, | ||
"pusher": { | ||
"href": "https://test01.vsoalmsps.tfsallin.net/_apis/Identities/c11fa894-cdcd-4da1-84c8-fe06e7aa17f2" | ||
}, | ||
"refs": { | ||
"href": "https://test01.vsoalm.tfsallin.net/DefaultCollection/_apis/git/repositories/9cd8a073-c67d-4725-8870-ce6fda346771/refs" | ||
} | ||
} | ||
}, | ||
"resourceVersion": "1.0", | ||
"resourceContainers": { | ||
"collection": { | ||
"id": "586fa11f-e0c2-43dd-9ce9-12f8b8f21b87" | ||
}, | ||
"account": { | ||
"id": "162cc52c-a0f2-42d7-8d80-eb9f10e6cc3d" | ||
}, | ||
"project": { | ||
"id": "5ec775cb-c546-4106-8a62-acd8ffd21339" | ||
} | ||
}, | ||
"createdDate": "2015-05-08T00:21:11.4874535Z", | ||
"sessionToken": { | ||
"hasError": false, | ||
"token": "this_is_vso_token", | ||
"validTo": "2015-05-08T00:51:11.94Z", | ||
"scope": "vso.code_write" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
using System; | ||
using System.Linq; | ||
using System.Web; | ||
using Kudu.Core.SourceControl; | ||
using Newtonsoft.Json.Linq; | ||
|
||
namespace Kudu.Services.ServiceHookHandlers | ||
{ | ||
/// <summary> | ||
/// Default Servicehook Handler, uses VSO format. | ||
/// </summary> | ||
public class VSOHandler : ServiceHookHandlerBase | ||
{ | ||
public override DeployAction TryParseDeploymentInfo(HttpRequestBase request, JObject payload, string targetBranch, out DeploymentInfo deploymentInfo) | ||
{ | ||
deploymentInfo = null; | ||
|
||
var publisherId = payload.Value<string>("publisherId"); | ||
if (String.Equals(publisherId, "tfs", StringComparison.OrdinalIgnoreCase)) | ||
{ | ||
GitDeploymentInfo gitDeploymentInfo = GetDeploymentInfo(request, payload, targetBranch); | ||
deploymentInfo = gitDeploymentInfo; | ||
return deploymentInfo == null || IsDeleteCommit(gitDeploymentInfo.NewRef) ? DeployAction.NoOp : DeployAction.ProcessDeployment; | ||
} | ||
|
||
return DeployAction.UnknownPayload; | ||
} | ||
|
||
protected virtual GitDeploymentInfo GetDeploymentInfo(HttpRequestBase request, JObject payload, string targetBranch) | ||
{ | ||
// the rest must exist or NullRef. | ||
// this allows us to identify the culprit handler | ||
var sessionToken = payload.Value<JObject>("sessionToken"); | ||
var resource = payload.Value<JObject>("resource"); | ||
var refUpdates = resource.Value<JArray>("refUpdates"); | ||
var repository = resource.Value<JObject>("repository"); | ||
|
||
// The format of ref is refs/something/something else | ||
// e.g. refs/head/master or refs/head/foo/bar | ||
string branch = refUpdates.Last.Value<string>("name"); | ||
// Extract the name from refs/head/master notation. | ||
int secondSlashIndex = branch.IndexOf('/', 5); | ||
branch = branch.Substring(secondSlashIndex + 1); | ||
if (!branch.Equals(targetBranch, StringComparison.OrdinalIgnoreCase)) | ||
{ | ||
return null; | ||
} | ||
|
||
var info = new GitDeploymentInfo { RepositoryType = RepositoryType.Git }; | ||
info.Deployer = GetDeployer(request); | ||
info.NewRef = refUpdates.Last.Value<string>("newObjectId"); | ||
|
||
var builder = new UriBuilder(repository.Value<string>("remoteUrl")); | ||
builder.UserName = sessionToken.Value<string>("token"); | ||
builder.Password = String.Empty; | ||
info.RepositoryUrl = builder.Uri.AbsoluteUri; | ||
|
||
var commits = resource.Value<JArray>("commits"); | ||
info.CommitId = refUpdates.Last.Value<string>("newObjectId"); | ||
info.TargetChangeset = ParseChangeSet(info.CommitId, commits); | ||
return info; | ||
} | ||
|
||
protected static ChangeSet ParseChangeSet(string id, JArray commits) | ||
{ | ||
if (commits == null || !commits.HasValues) | ||
{ | ||
return new ChangeSet(id, authorName: null, authorEmail: null, message: null, timestamp: DateTimeOffset.UtcNow); | ||
} | ||
JToken latestCommit = commits.Last; | ||
JObject commitAuthor = latestCommit.Value<JObject>("author"); | ||
return new ChangeSet( | ||
id, | ||
commitAuthor.Value<string>("name"), | ||
commitAuthor.Value<string>("email"), | ||
latestCommit.Value<string>("comment"), | ||
commitAuthor.Value<DateTime>("date") | ||
); | ||
} | ||
|
||
protected virtual string GetDeployer(HttpRequestBase request) | ||
{ | ||
return "VSO"; | ||
} | ||
|
||
protected static bool IsDeleteCommit(string newRef) | ||
{ | ||
return newRef.All(c => c == '0'); | ||
} | ||
} | ||
} |