Added VTFS webhooks project with basic modeling of payload

This commit is contained in:
Jenya Y 2016-05-03 01:09:07 +03:00 коммит произвёл Henrik Frystyk Nielsen
Родитель 1a213d7b9c
Коммит 51b364553d
82 изменённых файлов: 4112 добавлений и 1 удалений

Просмотреть файл

@ -8,6 +8,7 @@
<Word>apis</Word>
<Word>awaitable</Word>
<Word>bitbucket</Word>
<Word>changeset</Word>
<Word>deployer</Word>
<Word>dequeueing</Word>
<Word>dequeues</Word>
@ -17,12 +18,14 @@
<Word>git</Word>
<Word>instagram</Word>
<Word>kudu</Word>
<Word>kanban</Word>
<Word>mvc</Word>
<Word>nuget</Word>
<Word>paypal</Word>
<Word>salesforce</Word>
<Word>trello</Word>
<Word>ver</Word>
<Word>vsts</Word>
<Word>zapier</Word>
<Word>zendesk</Word>
<Word>你好</Word>
@ -42,6 +45,7 @@
<CasingExceptions>
<Acronym>CRM</Acronym>
<Acronym>SSO</Acronym>
<Acronym>VSTS</Acronym>
</CasingExceptions>
</Acronyms>
</Dictionary>

Просмотреть файл

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.24720.0
VisualStudioVersion = 14.0.25123.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Src", "Src", "{929F44D0-A040-4DC3-A22F-4C5829C05D44}"
EndProject
@ -152,6 +152,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.WebHooks.R
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.WebHooks.Receivers.Zendesk.Test", "test\Microsoft.AspNet.WebHooks.Receivers.Zendesk.Test\Microsoft.AspNet.WebHooks.Receivers.Zendesk.Test.csproj", "{D4AE6D4C-004F-4392-9EE1-772444719449}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.WebHooks.Receivers.VSTS", "src\Microsoft.AspNet.WebHooks.Receivers.VSTS\Microsoft.AspNet.WebHooks.Receivers.VSTS.csproj", "{6B501D55-2AA3-4757-A185-1277BB881DE8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.WebHooks.Receivers.VSTS.Test", "test\Microsoft.AspNet.WebHooks.Receivers.VSTS.Test\Microsoft.AspNet.WebHooks.Receivers.VSTS.Test.csproj", "{B27CC8B5-BF38-434B-B5CE-42ACEC40624C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VstsReceiver", "samples\VstsReceiver\VstsReceiver.csproj", "{88FB9535-BBC9-48FE-AC34-4C3E9A4073F3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
CodeAnalysis|Any CPU = CodeAnalysis|Any CPU
@ -555,6 +561,24 @@ Global
{D4AE6D4C-004F-4392-9EE1-772444719449}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D4AE6D4C-004F-4392-9EE1-772444719449}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D4AE6D4C-004F-4392-9EE1-772444719449}.Release|Any CPU.Build.0 = Release|Any CPU
{6B501D55-2AA3-4757-A185-1277BB881DE8}.CodeAnalysis|Any CPU.ActiveCfg = CodeAnalysis|Any CPU
{6B501D55-2AA3-4757-A185-1277BB881DE8}.CodeAnalysis|Any CPU.Build.0 = CodeAnalysis|Any CPU
{6B501D55-2AA3-4757-A185-1277BB881DE8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6B501D55-2AA3-4757-A185-1277BB881DE8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6B501D55-2AA3-4757-A185-1277BB881DE8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6B501D55-2AA3-4757-A185-1277BB881DE8}.Release|Any CPU.Build.0 = Release|Any CPU
{B27CC8B5-BF38-434B-B5CE-42ACEC40624C}.CodeAnalysis|Any CPU.ActiveCfg = CodeAnalysis|Any CPU
{B27CC8B5-BF38-434B-B5CE-42ACEC40624C}.CodeAnalysis|Any CPU.Build.0 = CodeAnalysis|Any CPU
{B27CC8B5-BF38-434B-B5CE-42ACEC40624C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B27CC8B5-BF38-434B-B5CE-42ACEC40624C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B27CC8B5-BF38-434B-B5CE-42ACEC40624C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B27CC8B5-BF38-434B-B5CE-42ACEC40624C}.Release|Any CPU.Build.0 = Release|Any CPU
{88FB9535-BBC9-48FE-AC34-4C3E9A4073F3}.CodeAnalysis|Any CPU.ActiveCfg = Release|Any CPU
{88FB9535-BBC9-48FE-AC34-4C3E9A4073F3}.CodeAnalysis|Any CPU.Build.0 = Release|Any CPU
{88FB9535-BBC9-48FE-AC34-4C3E9A4073F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{88FB9535-BBC9-48FE-AC34-4C3E9A4073F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{88FB9535-BBC9-48FE-AC34-4C3E9A4073F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{88FB9535-BBC9-48FE-AC34-4C3E9A4073F3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -626,6 +650,9 @@ Global
{BD0AB018-7229-42BF-B607-5D46E9F1F2EA} = {E957C8D9-B4A0-488B-838F-BAB4DE080A76}
{DCD550FB-FE5E-4684-AA52-C09FE5F8FDDA} = {929F44D0-A040-4DC3-A22F-4C5829C05D44}
{D4AE6D4C-004F-4392-9EE1-772444719449} = {9575CB90-BC4B-43BB-8AEA-82C53FDA4187}
{6B501D55-2AA3-4757-A185-1277BB881DE8} = {929F44D0-A040-4DC3-A22F-4C5829C05D44}
{B27CC8B5-BF38-434B-B5CE-42ACEC40624C} = {9575CB90-BC4B-43BB-8AEA-82C53FDA4187}
{88FB9535-BBC9-48FE-AC34-4C3E9A4073F3} = {E957C8D9-B4A0-488B-838F-BAB4DE080A76}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EnterpriseLibraryConfigurationToolBinariesPathV6 = packages\EnterpriseLibrary.TransientFaultHandling.6.0.1304.0\lib\portable-net45+win+wp8;packages\EnterpriseLibrary.TransientFaultHandling.Data.6.0.1304.1\lib\NET45

Просмотреть файл

@ -0,0 +1,24 @@
using System.Web.Http;
namespace VstsReceiver
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
// Initialize Vsts WebHook receiver
config.InitializeReceiveVstsWebHooks();
}
}
}

Просмотреть файл

@ -0,0 +1 @@
<%@ Application Codebehind="Global.asax.cs" Inherits="VstsReceiver.WebApiApplication" Language="C#" %>

Просмотреть файл

@ -0,0 +1,12 @@
using System.Web.Http;
namespace VstsReceiver
{
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
}
}
}

Просмотреть файл

@ -0,0 +1,34 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("VstsReceivers")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("VststReceivers")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("3f9f62dd-c365-4fec-a10e-5314d111ebf5")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

Просмотреть файл

@ -0,0 +1,161 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.0\build\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props" Condition="Exists('..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.0\build\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props')" />
<Import Project="..\..\packages\Microsoft.Net.Compilers.1.0.0\build\Microsoft.Net.Compilers.props" Condition="Exists('..\..\packages\Microsoft.Net.Compilers.1.0.0\build\Microsoft.Net.Compilers.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>
</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{88FB9535-BBC9-48FE-AC34-4C3E9A4073F3}</ProjectGuid>
<ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>VstsReceiver</RootNamespace>
<AssemblyName>VstsReceiver</AssemblyName>
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
<UseIISExpress>true</UseIISExpress>
<IISExpressSSLPort />
<IISExpressAnonymousAuthentication />
<IISExpressWindowsAuthentication />
<IISExpressUseClassicPipelineMode />
<UseGlobalApplicationHostFile />
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.AspNet.WebHooks.Receivers.VSTS">
<HintPath>..\..\bin\CodeAnalysis\Microsoft.AspNet.WebHooks.Receivers.VSTS.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.0\lib\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Net.Http.Formatting, Version=5.2.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.AspNet.WebApi.Client.5.2.2\lib\net45\System.Net.Http.Formatting.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Web.DynamicData" />
<Reference Include="System.Web.Entity" />
<Reference Include="System.Web.ApplicationServices" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Web.Extensions" />
<Reference Include="System.Web.Http, Version=5.2.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.AspNet.WebApi.Core.5.2.2\lib\net45\System.Web.Http.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Web.Http.WebHost, Version=5.2.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.2\lib\net45\System.Web.Http.WebHost.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Drawing" />
<Reference Include="System.Web" />
<Reference Include="System.Xml" />
<Reference Include="System.Configuration" />
<Reference Include="System.Web.Services" />
<Reference Include="System.EnterpriseServices" />
<Reference Include="System.Xml.Linq" />
</ItemGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json">
<HintPath>..\..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Content Include="Global.asax" />
<Content Include="index.html" />
<Content Include="Web.config" />
</ItemGroup>
<ItemGroup>
<Compile Include="App_Start\WebApiConfig.cs" />
<Compile Include="Global.asax.cs">
<DependentUpon>Global.asax</DependentUpon>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="WebHooks\VstsWebHookHandler.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="packages.config" />
<None Include="Web.Debug.config">
<DependentUpon>Web.config</DependentUpon>
</None>
<None Include="Web.Release.config">
<DependentUpon>Web.config</DependentUpon>
</None>
</ItemGroup>
<ItemGroup />
<ItemGroup>
<ProjectReference Include="..\..\Src\Microsoft.AspNet.WebHooks.Common\Microsoft.AspNet.WebHooks.Common.csproj">
<Project>{f7dd0935-6320-4efc-9464-d5a2d2b8c2f7}</Project>
<Name>Microsoft.AspNet.WebHooks.Common</Name>
</ProjectReference>
<ProjectReference Include="..\..\Src\Microsoft.AspNet.WebHooks.Receivers\Microsoft.AspNet.WebHooks.Receivers.csproj">
<Project>{8ced31fb-32f2-4ffb-9997-452fb9728577}</Project>
<Name>Microsoft.AspNet.WebHooks.Receivers</Name>
</ProjectReference>
</ItemGroup>
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" Condition="false" />
<ProjectExtensions>
<VisualStudio>
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
<WebProjectProperties>
<UseIIS>True</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>15572</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:50009</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>
</CustomServerUrl>
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
</WebProjectProperties>
</FlavorProperties>
</VisualStudio>
</ProjectExtensions>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Microsoft.Net.Compilers.1.0.0\build\Microsoft.Net.Compilers.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Net.Compilers.1.0.0\build\Microsoft.Net.Compilers.props'))" />
<Error Condition="!Exists('..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.0\build\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.0\build\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

Просмотреть файл

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- For more information on using web.config transformation visit http://go.microsoft.com/fwlink/?LinkId=125889 -->
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<!--
In the example below, the "SetAttributes" transform will change the value of
"connectionString" to use "ReleaseSQLServer" only when the "Match" locator
finds an attribute "name" that has a value of "MyDB".
<connectionStrings>
<add name="MyDB"
connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True"
xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
</connectionStrings>
-->
<system.web>
<!--
In the example below, the "Replace" transform will replace the entire
<customErrors> section of your web.config file.
Note that because there is only one customErrors section under the
<system.web> node, there is no need to use the "xdt:Locator" attribute.
<customErrors defaultRedirect="GenericError.htm"
mode="RemoteOnly" xdt:Transform="Replace">
<error statusCode="500" redirect="InternalError.htm"/>
</customErrors>
-->
</system.web>
</configuration>

Просмотреть файл

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- For more information on using web.config transformation visit http://go.microsoft.com/fwlink/?LinkId=125889 -->
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<!--
In the example below, the "SetAttributes" transform will change the value of
"connectionString" to use "ReleaseSQLServer" only when the "Match" locator
finds an attribute "name" that has a value of "MyDB".
<connectionStrings>
<add name="MyDB"
connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True"
xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
</connectionStrings>
-->
<system.web>
<compilation xdt:Transform="RemoveAttributes(debug)" />
<!--
In the example below, the "Replace" transform will replace the entire
<customErrors> section of your web.config file.
Note that because there is only one customErrors section under the
<system.web> node, there is no need to use the "xdt:Locator" attribute.
<customErrors defaultRedirect="GenericError.htm"
mode="RemoteOnly" xdt:Transform="Replace">
<error statusCode="500" redirect="InternalError.htm"/>
</customErrors>
-->
</system.web>
</configuration>

Просмотреть файл

@ -0,0 +1,58 @@
<?xml version="1.0"?>
<!--
For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=301879
-->
<configuration>
<appSettings>
<add key="MS_WebHookReceiverSecret_VSTS" value="83699ec7c1d794c0c780e49a5c72972590571fd8"/>
</appSettings>
<!--
For a description of web.config changes see http://go.microsoft.com/fwlink/?LinkId=235367.
The following attributes can be set on the <httpRuntime> tag.
<system.Web>
<httpRuntime targetFramework="4.5.1" />
</system.Web>
-->
<system.web>
<compilation debug="true" targetFramework="4.5.1"/>
<httpRuntime targetFramework="4.5.1"/>
</system.web>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35"/>
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35"/>
<bindingRedirect oldVersion="1.0.0.0-5.2.2.0" newVersion="5.2.2.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35"/>
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-5.2.2.0" newVersion="5.2.2.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-5.2.2.0" newVersion="5.2.2.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
<system.webServer>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0"/>
<remove name="OPTIONSVerbHandler"/>
<remove name="TRACEVerbHandler"/>
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0"/>
</handlers>
</system.webServer>
</configuration>

Просмотреть файл

@ -0,0 +1,95 @@
using Microsoft.AspNet.WebHooks;
using Microsoft.AspNet.WebHooks.Payloads;
using Newtonsoft.Json.Linq;
using System.Threading.Tasks;
namespace VstsReceiver.WebHooks
{
/// <summary>
/// This handler processes WebHooks from Visual Studio Team Services and leverages the <see cref="VstsWebHookHandlerBase"/> base handler.
/// For details about Visual Studio Team Services WebHooks, see <c>https://www.visualstudio.com/en-us/get-started/integrate/service-hooks/webhooks-and-vso-vs</c>.
/// </summary>
public class VstsWebHookHandler : VstsWebHookHandlerBase
{
/// <summary>
/// We use <see cref="VstsWebHookHandlerBase"/> so just have to override the methods we want to process WebHooks for.
/// This one processes the <see cref="BuildCompletedPayload"/> WebHook.
/// </summary>
public override Task ExecuteAsync(WebHookHandlerContext context, BuildCompletedPayload payload)
{
return Task.FromResult(true);
}
/// <summary>
/// We use <see cref="VstsWebHookHandlerBase"/> so just have to override the methods we want to process WebHooks for.
/// This one processes the <see cref="TeamRoomMessagePostedPayload"/> WebHook.
/// </summary>
public override Task ExecuteAsync(WebHookHandlerContext context, TeamRoomMessagePostedPayload payload)
{
return Task.FromResult(true);
}
/// <summary>
/// We use <see cref="VstsWebHookHandlerBase"/> so just have to override the methods we want to process WebHooks for.
/// This one processes the <see cref="WorkItemCreatedPayload"/> WebHook.
/// </summary>
public override Task ExecuteAsync(WebHookHandlerContext context, WorkItemCreatedPayload payload)
{
return Task.FromResult(true);
}
/// <summary>
/// We use <see cref="VstsWebHookHandlerBase"/> so just have to override the methods we want to process WebHooks for.
/// This one processes the <see cref="WorkItemCommentedOnPayload"/> WebHook.
/// </summary>
public override Task ExecuteAsync(WebHookHandlerContext context, WorkItemCommentedOnPayload payload)
{
return Task.FromResult(true);
}
/// <summary>
/// We use <see cref="VstsWebHookHandlerBase"/> so just have to override the methods we want to process WebHooks for.
/// This one processes the <see cref="CodeCheckedInPayload"/> WebHook.
/// </summary>
public override Task ExecuteAsync(WebHookHandlerContext context, CodeCheckedInPayload payload)
{
return Task.FromResult(true);
}
/// <summary>
/// We use <see cref="VstsWebHookHandlerBase"/> so just have to override the methods we want to process WebHooks for.
/// This one processes the <see cref="WorkItemDeletedPayload"/> WebHook.
/// </summary>
public override Task ExecuteAsync(WebHookHandlerContext context, WorkItemDeletedPayload payload)
{
return Task.FromResult(true);
}
/// <summary>
/// We use <see cref="VstsWebHookHandlerBase"/> so just have to override the methods we want to process WebHooks for.
/// This one processes the <see cref="WorkItemRestoredPayload"/> WebHook.
/// </summary>
public override Task ExecuteAsync(WebHookHandlerContext context, WorkItemRestoredPayload payload)
{
return Task.FromResult(true);
}
/// <summary>
/// We use <see cref="VstsWebHookHandlerBase"/> so just have to override the methods we want to process WebHooks for.
/// This one processes the <see cref="WorkItemUpdatedPayload"/> WebHook.
/// </summary>
public override Task ExecuteAsync(WebHookHandlerContext context, WorkItemUpdatedPayload payload)
{
return Task.FromResult(true);
}
/// <summary>
/// We use <see cref="VstsWebHookHandlerBase"/> so just have to override the methods we want to process WebHooks for.
/// This one processes the payload for unknown <c>eventType</c>.
/// </summary>
public override Task ExecuteAsync(WebHookHandlerContext context, JObject payload)
{
return Task.FromResult(true);
}
}
}

Просмотреть файл

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>
<head>
<title>Microsoft ASP.NET WebHooks Visual Studio Team Services Receiver</title>
<meta charset="utf-8" />
</head>
<body>
<h1>Microsoft ASP.NET WebHooks Visual Studio Team Services Receiver</h1>
<p>
The VSTS WebHook Receiver provides support for receiving WebHooks from Visual Studio Team Services. A sample WebHook URI is:</p>
<pre>https://&lt;host&gt;/api/webhooks/incoming/vsts?code=83699ec7c1d794c0c780e49a5c72972590571fd8</pre>
<p>
For security reasons the WebHook URI must be an <c>https</c> URI and contain a 'code' query parameter with the
same value as configured in the <b>MS_WebHookReceiverSecret_VSTS</b> application setting.
The 'code' parameter must be between 32 and 128 characters long. Optionally you can use IDs
to differentiate between multiple WebHooks, for example '<c>code0, id1=code1, id2=code2</c>'.
</p>
<p>
Please see <a href="https://www.visualstudio.com/en-us/get-started/integrate/service-hooks/webhooks-and-vso-vs">Visual Studio Team Services WebHooks</a>
for more information.
</p>
</body>
</html>

Просмотреть файл

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.AspNet.WebApi" version="5.2.2" targetFramework="net452" />
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.2" targetFramework="net452" />
<package id="Microsoft.AspNet.WebApi.Core" version="5.2.2" targetFramework="net452" />
<package id="Microsoft.AspNet.WebApi.WebHost" version="5.2.2" targetFramework="net452" />
<package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="1.0.0" targetFramework="net452" />
<package id="Microsoft.Net.Compilers" version="1.0.0" targetFramework="net452" developmentDependency="true" />
<package id="Newtonsoft.Json" version="6.0.4" targetFramework="net452" />
</packages>

Просмотреть файл

@ -0,0 +1,30 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.ComponentModel;
using Microsoft.AspNet.WebHooks.Config;
namespace System.Web.Http
{
/// <summary>
/// Extension methods for <see cref="HttpConfiguration"/>.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public static class HttpConfigurationExtensions
{
/// <summary>
/// Initializes support for receiving WebHooks generated by Visual Studio Team Services.
///
/// A sample WebHook URI is '<c>https://&lt;host&gt;/api/webhooks/incoming/vsts/{id}?code={code}</c>'.
/// For security reasons the WebHook URI must be an <c>https</c> URI and contain a 'code' query parameter with the
/// same value as configured in the '<c>MS_WebHookReceiverSecret_Tfs</c>' application setting, optionally using IDs
/// to differentiate between multiple WebHooks, for example '<c>secret0, id1=secret1, id2=secret2</c>'.
/// The 'code' parameter must be between 32 and 128 characters long.
/// </summary>
/// <param name="config">The current <see cref="HttpConfiguration"/>config.</param>
public static void InitializeReceiveVstsWebHooks(this HttpConfiguration config)
{
WebHooksConfig.Initialize(config);
}
}
}

Просмотреть файл

@ -0,0 +1,147 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.WebHooks.Payloads;
using Microsoft.AspNet.WebHooks.Properties;
using Newtonsoft.Json.Linq;
namespace Microsoft.AspNet.WebHooks
{
/// <summary>
/// Provides a base <see cref="IWebHookHandler" /> implementation which can be used to for handling Visual Studio Team Services WebHook
/// using strongly-typed payloads. For details about MyGet WebHooks, see <c>https://www.visualstudio.com/en-us/get-started/integrate/service-hooks/webhooks-and-vso-vs</c>.
/// </summary>
public abstract class VstsWebHookHandlerBase : WebHookHandler
{
/// <summary>
/// Initializes a new instance of the <see cref="VstsWebHookHandlerBase"/> class.
/// </summary>
protected VstsWebHookHandlerBase()
{
this.Receiver = VstsWebHookReceiver.ReceiverName;
}
/// <inheritdoc />
public override Task ExecuteAsync(string receiver, WebHookHandlerContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
string action = context.Actions.First();
JObject data = context.GetDataOrDefault<JObject>();
// map eventType to corresponding payload
switch (action)
{
case "workitem.updated": return ExecuteAsync(context, data.ToObject<WorkItemUpdatedPayload>());
case "workitem.restored": return ExecuteAsync(context, data.ToObject<WorkItemRestoredPayload>());
case "workitem.deleted": return ExecuteAsync(context, data.ToObject<WorkItemDeletedPayload>());
case "workitem.created": return ExecuteAsync(context, data.ToObject<WorkItemCreatedPayload>());
case "workitem.commented": return ExecuteAsync(context, data.ToObject<WorkItemCommentedOnPayload>());
case "message.posted": return ExecuteAsync(context, data.ToObject<TeamRoomMessagePostedPayload>());
case "tfvc.checkin": return ExecuteAsync(context, data.ToObject<CodeCheckedInPayload>());
case "build.complete": return ExecuteAsync(context, data.ToObject<BuildCompletedPayload>());
default:
string msg = string.Format(CultureInfo.CurrentCulture, VstsReceiverResources.Handler_NonMappedEventType, action);
context.RequestContext.Configuration.DependencyResolver.GetLogger().Warn(msg);
return ExecuteAsync(context, data);
}
}
/// <summary>
/// Executes the incoming WebHook request for event '<c>workitem.updated</c>'.
/// </summary>
/// <param name="context">Provides context for the <see cref="IWebHookHandler"/> for further processing the incoming WebHook.</param>
/// <param name="payload">Strong-typed WebHook payload.</param>
public virtual Task ExecuteAsync(WebHookHandlerContext context, WorkItemUpdatedPayload payload)
{
return Task.FromResult(true);
}
/// <summary>
/// Executes the incoming WebHook request for event '<c>workitem.restored</c>'.
/// </summary>
/// <param name="context">Provides context for the <see cref="IWebHookHandler"/> for further processing the incoming WebHook.</param>
/// <param name="payload">Strong-typed WebHook payload.</param>
public virtual Task ExecuteAsync(WebHookHandlerContext context, WorkItemRestoredPayload payload)
{
return Task.FromResult(true);
}
/// <summary>
/// Executes the incoming WebHook request for event '<c>workitem.deleted</c>'.
/// </summary>
/// <param name="context">Provides context for the <see cref="IWebHookHandler"/> for further processing the incoming WebHook.</param>
/// <param name="payload">Strong-typed WebHook payload.</param>
public virtual Task ExecuteAsync(WebHookHandlerContext context, WorkItemDeletedPayload payload)
{
return Task.FromResult(true);
}
/// <summary>
/// Executes the incoming WebHook request for event '<c>workitem.created</c>'.
/// </summary>
/// <param name="context">Provides context for the <see cref="IWebHookHandler"/> for further processing the incoming WebHook.</param>
/// <param name="payload">Strong-typed WebHook payload.</param>
public virtual Task ExecuteAsync(WebHookHandlerContext context, WorkItemCreatedPayload payload)
{
return Task.FromResult(true);
}
/// <summary>
/// Executes the incoming WebHook request for event '<c>workitem.commented</c>'.
/// </summary>
/// <param name="context">Provides context for the <see cref="IWebHookHandler"/> for further processing the incoming WebHook.</param>
/// <param name="payload">Strong-typed WebHook payload.</param>
public virtual Task ExecuteAsync(WebHookHandlerContext context, WorkItemCommentedOnPayload payload)
{
return Task.FromResult(true);
}
/// <summary>
/// Executes the incoming WebHook request for event '<c>message.posted</c>'.
/// </summary>
/// <param name="context">Provides context for the <see cref="IWebHookHandler"/> for further processing the incoming WebHook.</param>
/// <param name="payload">Strong-typed WebHook payload.</param>
public virtual Task ExecuteAsync(WebHookHandlerContext context, TeamRoomMessagePostedPayload payload)
{
return Task.FromResult(true);
}
/// <summary>
/// Executes the incoming WebHook request for event '<c>tfvc.checkin</c>'.
/// </summary>
/// <param name="context">Provides context for the <see cref="IWebHookHandler"/> for further processing the incoming WebHook.</param>
/// <param name="payload">Strong-typed WebHook payload.</param>
public virtual Task ExecuteAsync(WebHookHandlerContext context, CodeCheckedInPayload payload)
{
return Task.FromResult(true);
}
/// <summary>
/// Executes the incoming WebHook request for event '<c>build.complete</c>'.
/// </summary>
/// <param name="context">Provides context for the <see cref="IWebHookHandler"/> for further processing the incoming WebHook.</param>
/// <param name="payload">Strong-typed WebHook payload.</param>
public virtual Task ExecuteAsync(WebHookHandlerContext context, BuildCompletedPayload payload)
{
return Task.FromResult(true);
}
/// <summary>
/// Executes the incoming WebHook request for unknown event.
/// </summary>
/// <param name="context">Provides context for the <see cref="IWebHookHandler"/> for further processing the incoming WebHook.</param>
/// <param name="payload">JSON payload.</param>
public virtual Task ExecuteAsync(WebHookHandlerContext context, JObject payload)
{
return Task.FromResult(true);
}
}
}

Просмотреть файл

@ -0,0 +1,137 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory),WebHooks.sln))\tools\WebHooks.settings.targets" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>
</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{6B501D55-2AA3-4757-A185-1277BB881DE8}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Microsoft.AspNet.WebHooks</RootNamespace>
<AssemblyName>Microsoft.AspNet.WebHooks.Receivers.VSTS</AssemblyName>
<DocumentationFile>$(OutputPath)$(AssemblyName).xml</DocumentationFile>
<RunCodeAnalysis>$(CodeAnalysis)</RunCodeAnalysis>
<CodeAnalysisAdditionalOptions>/assemblyCompareMode:StrongNameIgnoringVersion</CodeAnalysisAdditionalOptions>
<CodeAnalysisRuleSet>..\..\FxCop.ruleset</CodeAnalysisRuleSet>
<DefineConstants>$(DefineConstants);ASPNETWEBHOOKS</DefineConstants>
<SignAssembly>true</SignAssembly>
<NuGetPackageImportStamp>b718ef60</NuGetPackageImportStamp>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Net.Http.Formatting, Version=5.2.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.AspNet.WebApi.Client.5.2.2\lib\net45\System.Net.Http.Formatting.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Web.Http, Version=5.2.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.AspNet.WebApi.Core.5.2.2\lib\net45\System.Web.Http.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Common\CommonAssemblyInfo.cs">
<Link>Properties\CommonAssemblyInfo.cs</Link>
</Compile>
<Compile Include="Extensions\HttpConfigurationExtensions.cs" />
<Compile Include="Handlers\VstsWebHookHandlerBase.cs" />
<Compile Include="Payloads\BuildCompletedDefinition.cs" />
<Compile Include="Payloads\BuildCompletedDrop.cs" />
<Compile Include="Payloads\BuildCompletedLog.cs" />
<Compile Include="Payloads\BuildCompletedQueueDefinition.cs" />
<Compile Include="Payloads\BuildCompletedRequest.cs" />
<Compile Include="Payloads\BuildCompletedResource.cs" />
<Compile Include="Payloads\CodeCheckedInResource.cs" />
<Compile Include="Payloads\PayloadMessage.cs" />
<Compile Include="Payloads\PayloadResourceContainer.cs" />
<Compile Include="Payloads\PayloadResourceContainers.cs" />
<Compile Include="Payloads\TeamRoomMessagePostedResource.cs" />
<Compile Include="Payloads\WorkItemCommentedOnResource.cs" />
<Compile Include="Payloads\WorkItemCreatedResource.cs" />
<Compile Include="Payloads\WorkItemDeletedResource.cs" />
<Compile Include="Payloads\WorkItemFields.cs" />
<Compile Include="Payloads\WorkItemLink.cs" />
<Compile Include="Payloads\WorkItemLinks.cs" />
<Compile Include="Payloads\WorkItemRestoredResource.cs" />
<Compile Include="Payloads\WorkItemUpdatedFieldValue.cs" />
<Compile Include="Payloads\WorkItemUpdatedRevision.cs" />
<Compile Include="Payloads\WorkItemUpdatedFields.cs" />
<Compile Include="Payloads\WorkItemUpdatedResource.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Properties\VstsReceiverResources.Designer.cs">
<DependentUpon>VstsReceiverResources.resx</DependentUpon>
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
</Compile>
<Compile Include="Payloads\BuildCompletedPayload.cs" />
<Compile Include="Payloads\CodeCheckedInPayload.cs" />
<Compile Include="Payloads\TeamRoomMessagePostedPayload.cs" />
<Compile Include="Payloads\BasePayload.cs" />
<Compile Include="Payloads\BaseResource.cs" />
<Compile Include="Payloads\BaseWorkItemResource.cs" />
<Compile Include="Payloads\ResourceUser.cs" />
<Compile Include="Payloads\WorkItemCommentedOnPayload.cs" />
<Compile Include="Payloads\WorkItemCreatedPayload.cs" />
<Compile Include="Payloads\WorkItemRestoredPayload.cs" />
<Compile Include="Payloads\WorkItemUpdatedPayload.cs" />
<Compile Include="Payloads\WorkItemDeletedPayload.cs" />
<Compile Include="WebHooks\VstsWebHookReceiver.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Microsoft.AspNet.WebHooks.Receivers.VSTS.nuspec">
<SubType>Designer</SubType>
</None>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Microsoft.AspNet.WebHooks.Common\Microsoft.AspNet.WebHooks.Common.csproj">
<Project>{f7dd0935-6320-4efc-9464-d5a2d2b8c2f7}</Project>
<Name>Microsoft.AspNet.WebHooks.Common</Name>
</ProjectReference>
<ProjectReference Include="..\Microsoft.AspNet.WebHooks.Receivers\Microsoft.AspNet.WebHooks.Receivers.csproj">
<Project>{8CED31FB-32F2-4FFB-9997-452FB9728577}</Project>
<Name>Microsoft.AspNet.WebHooks.Receivers</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<CodeAnalysisDictionary Include="..\..\CustomDictionary.xml">
<Link>CustomDictionary.xml</Link>
<SubType>Designer</SubType>
</CodeAnalysisDictionary>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Properties\VstsReceiverResources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>VstsReceiverResources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\..\packages\StyleCop.MSBuild.4.7.49.1\build\StyleCop.MSBuild.Targets" Condition="Exists('..\packages\StyleCop.MSBuild.4.7.49.1\build\StyleCop.MSBuild.Targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\StyleCop.MSBuild.4.7.49.1\build\StyleCop.MSBuild.Targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\StyleCop.MSBuild.4.7.49.1\build\StyleCop.MSBuild.Targets'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

Просмотреть файл

@ -0,0 +1,20 @@
<?xml version="1.0"?>
<package >
<metadata>
<id>$id$</id>
<version>$symversion$</version>
<title>Microsoft ASP.NET WebHooks Receiver for Visual Studio Team Services</title>
<authors>Microsoft</authors>
<owners>Microsoft, aspnet</owners>
<licenseUrl>http://www.microsoft.com/web/webpi/eula/net_library_eula_ENU.htm</licenseUrl>
<projectUrl>http://go.microsoft.com/fwlink/?LinkId=690277</projectUrl>
<iconUrl>http://go.microsoft.com/fwlink/?LinkID=288859</iconUrl>
<requireLicenseAcceptance>true</requireLicenseAcceptance>
<description>
This package provides support for receiving WebHooks from Visual Studio Team Services. For information about Visual Studio Team Services WebHooks, see "https://www.visualstudio.com/en-us/get-started/integrate/service-hooks/webhooks-and-vso-vs".
</description>
<releaseNotes></releaseNotes>
<copyright>&#169; Microsoft Corporation. All rights reserved.</copyright>
<tags>Microsoft AspNet WebApi AspNetWebApi WebHooks TFS VSTS Visual Studio Team Services</tags>
</metadata>
</package>

Просмотреть файл

@ -0,0 +1,81 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Newtonsoft.Json;
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Root object of payload sent for all types of events.
/// </summary>
/// <typeparam name="T">Type of resource within payload which differs depending on '<c>eventType</c>' field</typeparam>
public abstract class BasePayload<T> where T : BaseResource
{
/// <summary>
/// Gets the subscription identifier which triggered the event.
/// </summary>
[JsonProperty("subscriptionId")]
public string SubscriptionId { get; set; }
/// <summary>
/// Gets the notification identifier within subscription.
/// </summary>
[JsonProperty("notificationId")]
public int NotificationId { get; set; }
/// <summary>
/// Gets the identifier of HTTP request.
/// </summary>
[JsonProperty("id")]
public string Id { get; set; }
/// <summary>
/// Gets the type of the event.
/// </summary>
[JsonProperty("eventType")]
public string EventType { get; set; }
/// <summary>
/// Gets the publisher identifier.
/// </summary>
[JsonProperty("publisherId")]
public string PublisherId { get; set; }
/// <summary>
/// Gets the message which describes the event.
/// </summary>
[JsonProperty("message")]
public PayloadMessage Message { get; set; }
/// <summary>
/// Gets the detailed message which describes the event.
/// </summary>
[JsonProperty("detailedMessage")]
public PayloadMessage DetailedMessage { get; set; }
/// <summary>
/// Gets the resource itself - data associated with corresponding event.
/// </summary>
[JsonProperty("resource")]
public T Resource { get; set; }
/// <summary>
/// Gets the resource version.
/// </summary>
[JsonProperty("resourceVersion")]
public string ResourceVersion { get; set; }
/// <summary>
/// Gets the resource containers.
/// </summary>
[JsonProperty("resourceContainers")]
public PayloadResourceContainers ResourceContainers { get; set; }
/// <summary>
/// Gets the date when HTTP request was created.
/// </summary>
[JsonProperty("createdDate")]
public DateTime CreatedDate { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,13 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Base class for resource object which describes
/// a specific event type.
/// </summary>
public abstract class BaseResource
{
}
}

Просмотреть файл

@ -0,0 +1,45 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Newtonsoft.Json;
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Base class for resource object which describes WorkItem event types.
/// </summary>
/// <typeparam name="T">Type which describes fields associated with this kind of WorkItem change</typeparam>
public abstract class BaseWorkItemResource<T> : BaseResource
{
/// <summary>
/// Gets the identifier of WorkItem.
/// </summary>
[JsonProperty("id")]
public int Id { get; set; }
/// <summary>
/// Gets the revision number.
/// </summary>
[JsonProperty("rev")]
public int RevisionNumber { get; set; }
/// <summary>
/// Gets fields associated with the WorkItem.
/// </summary>
[JsonProperty("fields")]
public T Fields { get; set; }
/// <summary>
/// Gets links associated with the WorkItem.
/// </summary>
[JsonProperty("_links")]
public WorkItemLinks Links { get; set; }
/// <summary>
/// Gets the URL of the WorkItem.
/// </summary>
[JsonProperty("url")]
public Uri Url { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,50 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Newtonsoft.Json;
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Describes build definition
/// </summary>
public class BuildCompletedDefinition
{
/// <summary>
/// Gets the size of the batch.
/// </summary>
[JsonProperty("batchSize")]
public int BatchSize { get; set; }
/// <summary>
/// Gets the trigger type.
/// </summary>
[JsonProperty("triggerType")]
public string TriggerType { get; set; }
/// <summary>
/// Gets the trigger type.
/// </summary>
[JsonProperty("definitionType")]
public string DefinitionType { get; set; }
/// <summary>
/// Gets the identifier of the build definition.
/// </summary>
[JsonProperty("id")]
public int Id { get; set; }
/// <summary>
/// Gets the name of the build definition.
/// </summary>
[JsonProperty("name")]
public string Name { get; set; }
/// <summary>
/// Gets the URL of the build definition.
/// </summary>
[JsonProperty("url")]
public Uri Url { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,38 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Newtonsoft.Json;
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Describes build drop
/// </summary>
public class BuildCompletedDrop
{
/// <summary>
/// Gets drop location.
/// </summary>
[JsonProperty("location")]
public string Location { get; set; }
/// <summary>
/// Gets drop type.
/// </summary>
[JsonProperty("type")]
public string DropType { get; set; }
/// <summary>
/// Gets drop location URL.
/// </summary>
[JsonProperty("url")]
public Uri Url { get; set; }
/// <summary>
/// Gets drop location download URL.
/// </summary>
[JsonProperty("downloadUrl")]
public Uri DownloadUrl { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,32 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Newtonsoft.Json;
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Describes build log
/// </summary>
public class BuildCompletedLog
{
/// <summary>
/// Gets the log type.
/// </summary>
[JsonProperty("type")]
public string LogType { get; set; }
/// <summary>
/// Gets the log URL.
/// </summary>
[JsonProperty("url")]
public Uri Url { get; set; }
/// <summary>
/// Gets the log download URL.
/// </summary>
[JsonProperty("downloadUrl")]
public Uri DownloadUrl { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Describes the entire payload of event '<c>build.complete</c>'.
/// </summary>
public class BuildCompletedPayload : BasePayload<BuildCompletedResource>
{
}
}

Просмотреть файл

@ -0,0 +1,38 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Newtonsoft.Json;
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Describes the queue of the build.
/// </summary>
public class BuildCompletedQueueDefinition
{
/// <summary>
/// Gets the type of the queue.
/// </summary>
[JsonProperty("queueType")]
public string QueueType { get; set; }
/// <summary>
/// Gets the identifier of the queue.
/// </summary>
[JsonProperty("id")]
public int Id { get; set; }
/// <summary>
/// Gets the name of the queue.
/// </summary>
[JsonProperty("name")]
public string Name { get; set; }
/// <summary>
/// Gets the URL of the queue.
/// </summary>
[JsonProperty("url")]
public Uri Url { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,32 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Newtonsoft.Json;
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Describes the request of the build.
/// </summary>
public class BuildCompletedRequest
{
/// <summary>
/// Gets the identifier of the request.
/// </summary>
[JsonProperty("id")]
public int Id { get; set; }
/// <summary>
/// Gets the URL of the request.
/// </summary>
[JsonProperty("url")]
public Uri Url { get; set; }
/// <summary>
/// Gets the user associated with the request.
/// </summary>
[JsonProperty("requestedFor")]
public ResourceUser RequestedFor { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,128 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.ObjectModel;
using Newtonsoft.Json;
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Describes the resource that associated with <see cref="BuildCompletedPayload"/>
/// </summary>
public class BuildCompletedResource : BaseResource
{
private readonly Collection<BuildCompletedRequest> _requests = new Collection<BuildCompletedRequest>();
/// <summary>
/// Gets the build URI.
/// </summary>
[JsonProperty("uri")]
public Uri Uri { get; set; }
/// <summary>
/// Gets the build identifier.
/// </summary>
[JsonProperty("id")]
public int Id { get; set; }
/// <summary>
/// Gets the build number.
/// </summary>
[JsonProperty("buildNumber")]
public string BuildNumber { get; set; }
/// <summary>
/// Gets the build URL.
/// </summary>
[JsonProperty("url")]
public Uri Url { get; set; }
/// <summary>
/// Gets the start time of the build.
/// </summary>
[JsonProperty("startTime")]
public DateTime StartTime { get; set; }
/// <summary>
/// Gets the finish time of the build.
/// </summary>
[JsonProperty("finishTime")]
public DateTime FinishTime { get; set; }
/// <summary>
/// Gets the reason which triggered the build.
/// </summary>
[JsonProperty("reason")]
public string Reason { get; set; }
/// <summary>
/// Gets the outcome status of the build.
/// </summary>
[JsonProperty("status")]
public string Status { get; set; }
/// <summary>
/// Gets the build drop location.
/// </summary>
[JsonProperty("dropLocation")]
public string DropLocation { get; set; }
/// <summary>
/// Gets the build drop.
/// </summary>
[JsonProperty("drop")]
public BuildCompletedDrop Drop { get; set; }
/// <summary>
/// Gets the build log.
/// </summary>
[JsonProperty("log")]
public BuildCompletedLog Log { get; set; }
/// <summary>
/// Gets the source version for the build.
/// </summary>
[JsonProperty("sourceGetVersion")]
public string SourceGetVersion { get; set; }
/// <summary>
/// Gets the user which last changed the source.
/// </summary>
[JsonProperty("lastChangedBy")]
public ResourceUser LastChangedBy { get; set; }
/// <summary>
/// Gets value indicating whether this build retain indefinitely.
/// </summary>
[JsonProperty("retainIndefinitely")]
public bool RetainIndefinitely { get; set; }
/// <summary>
/// Gets value indicating whether this build has diagnostics.
/// </summary>
[JsonProperty("hasDiagnostics")]
public bool HasDiagnostics { get; set; }
/// <summary>
/// Gets the definition of the build.
/// </summary>
[JsonProperty("definition")]
public BuildCompletedDefinition Definition { get; set; }
/// <summary>
/// Gets the build queue.
/// </summary>
[JsonProperty("queue")]
public BuildCompletedQueueDefinition Queue { get; set; }
/// <summary>
/// Gets build requests.
/// </summary>
[JsonProperty("requests")]
public Collection<BuildCompletedRequest> Requests
{
get { return _requests; }
}
}
}

Просмотреть файл

@ -0,0 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Describes the entire payload of event '<c>tfvc.checkin</c>'.
/// </summary>
public class CodeCheckedInPayload : BasePayload<CodeCheckedInResource>
{
}
}

Просмотреть файл

@ -0,0 +1,50 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Newtonsoft.Json;
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Describes the resource that associated with <see cref="CodeCheckedInPayload"/>
/// </summary>
public class CodeCheckedInResource : BaseResource
{
/// <summary>
/// Gets the changeset identifier.
/// </summary>
[JsonProperty("changesetId")]
public int ChangesetId { get; set; }
/// <summary>
/// Gets the changeset URL.
/// </summary>
[JsonProperty("url")]
public Uri Url { get; set; }
/// <summary>
/// Gets the changeset author.
/// </summary>
[JsonProperty("author")]
public ResourceUser Author { get; set; }
/// <summary>
/// Gets the user that checked in the changeset.
/// </summary>
[JsonProperty("checkedInBy")]
public ResourceUser CheckedInBy { get; set; }
/// <summary>
/// Gets the changeset creation date.
/// </summary>
[JsonProperty("createdDate")]
public DateTime CreatedDate { get; set; }
/// <summary>
/// Gets the changeset comment.
/// </summary>
[JsonProperty("comment")]
public string Comment { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,31 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Newtonsoft.Json;
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Describes payload message.
/// </summary>
public class PayloadMessage
{
/// <summary>
/// Gets the message in plain text.
/// </summary>
[JsonProperty("text")]
public string Text { get; set; }
/// <summary>
/// Gets the message in HTML format.
/// </summary>
[JsonProperty("html")]
public string Html { get; set; }
/// <summary>
/// Gets the message in markdown format.
/// </summary>
[JsonProperty("markdown")]
public string Markdown { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,19 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Newtonsoft.Json;
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Describes container
/// </summary>
public class PayloadResourceContainer
{
/// <summary>
/// Gets the identifier of container.
/// </summary>
[JsonProperty("id")]
public string Id { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,31 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Newtonsoft.Json;
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Describes containers containing the resource
/// </summary>
public class PayloadResourceContainers
{
/// <summary>
/// Gets the collection.
/// </summary>
[JsonProperty("collection")]
public PayloadResourceContainer Collection { get; set; }
/// <summary>
/// Gets the account.
/// </summary>
[JsonProperty("account")]
public PayloadResourceContainer Account { get; set; }
/// <summary>
/// Gets the project.
/// </summary>
[JsonProperty("project")]
public PayloadResourceContainer Project { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,44 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Newtonsoft.Json;
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Describes user entity
/// </summary>
public class ResourceUser
{
/// <summary>
/// Gets the identifier of the user.
/// </summary>
[JsonProperty("id")]
public string Id { get; set; }
/// <summary>
/// Gets the user display name.
/// </summary>
[JsonProperty("displayName")]
public string DisplayName { get; set; }
/// <summary>
/// Gets the user unique name.
/// </summary>
[JsonProperty("uniqueName")]
public string UniqueName { get; set; }
/// <summary>
/// Gets the user URL.
/// </summary>
[JsonProperty("url")]
public Uri Url { get; set; }
/// <summary>
/// Gets the user image URL.
/// </summary>
[JsonProperty("imageUrl")]
public Uri ImageUrl { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Describes the entire payload of event '<c>message.posted</c>'.
/// </summary>
public class TeamRoomMessagePostedPayload : BasePayload<TeamRoomMessagePostedResource>
{
}
}

Просмотреть файл

@ -0,0 +1,50 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Newtonsoft.Json;
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Describes the resource that associated with <see cref="TeamRoomMessagePostedPayload"/>
/// </summary>
public class TeamRoomMessagePostedResource : BaseResource
{
/// <summary>
/// Gets the identifier.
/// </summary>
[JsonProperty("id")]
public int Id { get; set; }
/// <summary>
/// Gets the content of the message.
/// </summary>
[JsonProperty("content")]
public string Content { get; set; }
/// <summary>
/// Gets the type of the message.
/// </summary>
[JsonProperty("messageType")]
public string MessageType { get; set; }
/// <summary>
/// Gets the posted time of the message.
/// </summary>
[JsonProperty("postedTime")]
public DateTime PostedTime { get; set; }
/// <summary>
/// Gets the room identifier where message was posted.
/// </summary>
[JsonProperty("postedRoomId")]
public int PostedRoomId { get; set; }
/// <summary>
/// Gets the user who posted the message.
/// </summary>
[JsonProperty("postedBy")]
public ResourceUser PostedBy { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Describes the entire payload of event '<c>workitem.commented</c>'.
/// </summary>
public class WorkItemCommentedOnPayload : BasePayload<WorkItemCommentedOnResource>
{
}
}

Просмотреть файл

@ -0,0 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Describes the resource that associated with <see cref="WorkItemCommentedOnPayload"/>
/// </summary>
public class WorkItemCommentedOnResource : BaseWorkItemResource<WorkItemFields>
{
}
}

Просмотреть файл

@ -0,0 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Describes the entire payload of event '<c>workitem.created</c>'.
/// </summary>
public class WorkItemCreatedPayload : BasePayload<WorkItemCreatedResource>
{
}
}

Просмотреть файл

@ -0,0 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Describes the resource that associated with <see cref="WorkItemCreatedPayload"/>
/// </summary>
public class WorkItemCreatedResource : BaseWorkItemResource<WorkItemFields>
{
}
}

Просмотреть файл

@ -0,0 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Describes the entire payload of event '<c>workitem.deleted</c>'.
/// </summary>
public class WorkItemDeletedPayload : BasePayload<WorkItemDeletedResource>
{
}
}

Просмотреть файл

@ -0,0 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Describes the resource that associated with <see cref="WorkItemDeletedPayload"/>
/// </summary>
public class WorkItemDeletedResource : BaseWorkItemResource<WorkItemFields>
{
}
}

Просмотреть файл

@ -0,0 +1,98 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Newtonsoft.Json;
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Describes fields of the WorkItem
/// </summary>
public class WorkItemFields
{
/// <summary>
/// Gets the value of field <c>System.AreaPath</c>.
/// </summary>
[JsonProperty("System.AreaPath")]
public string SystemAreaPath { get; set; }
/// <summary>
/// Gets the value of field <c>System.TeamProject</c>.
/// </summary>
[JsonProperty("System.TeamProject")]
public string SystemTeamProject { get; set; }
/// <summary>
/// Gets the value of field <c>System.IterationPath</c>.
/// </summary>
[JsonProperty("System.IterationPath")]
public string SystemIterationPath { get; set; }
/// <summary>
/// Gets the value of field <c>System.WorkItemType</c>.
/// </summary>
[JsonProperty("System.WorkItemType")]
public string SystemWorkItemType { get; set; }
/// <summary>
/// Gets the value of field <c>System.State</c>.
/// </summary>
[JsonProperty("System.State")]
public string SystemState { get; set; }
/// <summary>
/// Gets the value of field <c>System.Reason</c>.
/// </summary>
[JsonProperty("System.Reason")]
public string SystemReason { get; set; }
/// <summary>
/// Gets the value of field <c>System.CreatedDate</c>.
/// </summary>
[JsonProperty("System.CreatedDate")]
public DateTime SystemCreatedDate { get; set; }
/// <summary>
/// Gets the value of field <c>System.CreatedBy</c>.
/// </summary>
[JsonProperty("System.CreatedBy")]
public string SystemCreatedBy { get; set; }
/// <summary>
/// Gets the value of field <c>System.ChangedDate</c>.
/// </summary>
[JsonProperty("System.ChangedDate")]
public DateTime SystemChangedDate { get; set; }
/// <summary>
/// Gets the value of field <c>System.ChangedBy</c>.
/// </summary>
[JsonProperty("System.ChangedBy")]
public string SystemChangedBy { get; set; }
/// <summary>
/// Gets the value of field <c>System.Title</c>.
/// </summary>
[JsonProperty("System.Title")]
public string SystemTitle { get; set; }
/// <summary>
/// Gets the value of field <c>Microsoft.VSTS.Common.Severity</c>.
/// </summary>
[JsonProperty("Microsoft.VSTS.Common.Severity")]
public string MicrosoftCommonSeverity { get; set; }
/// <summary>
/// Gets the value of field <c>WEF_EB329F44FE5F4A94ACB1DA153FDF38BA_Kanban.Column</c>.
/// </summary>
[JsonProperty("WEF_EB329F44FE5F4A94ACB1DA153FDF38BA_Kanban.Column")]
public string KanbanColumn { get; set; }
/// <summary>
/// Gets the value of field <c>System.History</c>.
/// </summary>
[JsonProperty("System.History")]
public string SystemHistory { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,19 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Newtonsoft.Json;
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Describes the WorkItem's link.
/// </summary>
public class WorkItemLink
{
/// <summary>
/// Gets the URL of WorkItem's link.
/// </summary>
[JsonProperty("href")]
public string Href { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,61 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Newtonsoft.Json;
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Describes links of the WorkItem.
/// </summary>
public class WorkItemLinks
{
/// <summary>
/// Gets the link to the WorkItem itself.
/// </summary>
[JsonProperty("self")]
public WorkItemLink Self { get; set; }
/// <summary>
/// Gets the link to the parent WorkItem if exists.
/// </summary>
[JsonProperty("parent")]
public WorkItemLink Parent { get; set; }
/// <summary>
/// Gets the link to the WorkItem' updates.
/// </summary>
[JsonProperty("workItemUpdates")]
public WorkItemLink WorkItemUpdates { get; set; }
/// <summary>
/// Gets the link to the WorkItem's revisions.
/// </summary>
[JsonProperty("workItemRevisions")]
public WorkItemLink WorkItemRevisions { get; set; }
/// <summary>
/// Gets the link to the WorkItem's type.
/// </summary>
[JsonProperty("workItemType")]
public WorkItemLink WorkItemType { get; set; }
/// <summary>
/// Gets the link to the WorkItem's fields.
/// </summary>
[JsonProperty("fields")]
public WorkItemLink Fields { get; set; }
/// <summary>
/// Gets the link to the WorkItem's HTML.
/// </summary>
[JsonProperty("html")]
public WorkItemLink Html { get; set; }
/// <summary>
/// Gets the link to the WorkItem's history.
/// </summary>
[JsonProperty("workItemHistory")]
public WorkItemLink WorkItemHistory { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Describes the entire payload of event '<c>workitem.restored</c>'.
/// </summary>
public class WorkItemRestoredPayload : BasePayload<WorkItemRestoredResource>
{
}
}

Просмотреть файл

@ -0,0 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Describes the resource that associated with <see cref="WorkItemRestoredPayload"/>
/// </summary>
public class WorkItemRestoredResource : BaseWorkItemResource<WorkItemFields>
{
}
}

Просмотреть файл

@ -0,0 +1,26 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Newtonsoft.Json;
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Describes change of specific field
/// </summary>
/// <typeparam name="T">The string-type of the field that is being changed</typeparam>
public class WorkItemUpdatedFieldValue<T>
{
/// <summary>
/// Gets the value of the field before the change.
/// </summary>
[JsonProperty("oldValue")]
public T OldValue { get; set; }
/// <summary>
/// Gets the value of the field after the change.
/// </summary>
[JsonProperty("newValue")]
public T NewValue { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,68 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Newtonsoft.Json;
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Describes fields of the WorkItem that was updated
/// </summary>
public class WorkItemUpdatedFields
{
/// <summary>
/// Gets the change information for the field '<c>System.Rev</c>'.
/// </summary>
[JsonProperty("System.Rev")]
public WorkItemUpdatedFieldValue<string> SystemRev { get; set; }
/// <summary>
/// Gets the change information for the field '<c>System.AuthorizedDate</c>'.
/// </summary>
[JsonProperty("System.AuthorizedDate")]
public WorkItemUpdatedFieldValue<DateTime> SystemAuthorizedDate { get; set; }
/// <summary>
/// Gets the change information for the field '<c>System.RevisedDate</c>'.
/// </summary>
[JsonProperty("System.RevisedDate")]
public WorkItemUpdatedFieldValue<DateTime> SystemRevisedDate { get; set; }
/// <summary>
/// Gets the change information for the field '<c>System.State</c>'.
/// </summary>
[JsonProperty("System.State")]
public WorkItemUpdatedFieldValue<string> SystemState { get; set; }
/// <summary>
/// Gets the change information for the field '<c>System.Reason</c>'.
/// </summary>
[JsonProperty("System.Reason")]
public WorkItemUpdatedFieldValue<string> SystemReason { get; set; }
/// <summary>
/// Gets the change information for the field '<c>System.AssignedTo</c>'.
/// </summary>
[JsonProperty("System.AssignedTo")]
public WorkItemUpdatedFieldValue<string> SystemAssignedTo { get; set; }
/// <summary>
/// Gets the change information for the field '<c>System.ChangedDate</c>'.
/// </summary>
[JsonProperty("System.ChangedDate")]
public WorkItemUpdatedFieldValue<DateTime> SystemChangedDate { get; set; }
/// <summary>
/// Gets the change information for the field '<c>System.Watermark</c>'.
/// </summary>
[JsonProperty("System.Watermark")]
public WorkItemUpdatedFieldValue<string> SystemWatermark { get; set; }
/// <summary>
/// Gets the change information for the field '<c>Microsoft.VSTS.Common.Severity</c>'.
/// </summary>
[JsonProperty("Microsoft.Vsts.Common.Severity")]
public WorkItemUpdatedFieldValue<string> MicrosoftCommonSeverity { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Describes the entire payload of event '<c>workitem.updated</c>'.
/// </summary>
public class WorkItemUpdatedPayload : BasePayload<WorkItemUpdatedResource>
{
}
}

Просмотреть файл

@ -0,0 +1,38 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Newtonsoft.Json;
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Describes the resource that associated with <see cref="WorkItemUpdatedPayload"/>
/// </summary>
public class WorkItemUpdatedResource : BaseWorkItemResource<WorkItemUpdatedFields>
{
/// <summary>
/// Gets WorkItem identifier.
/// </summary>
[JsonProperty("workItemId")]
public int WorkItemId { get; set; }
/// <summary>
/// Gets the author of revision.
/// </summary>
[JsonProperty("revisedBy")]
public ResourceUser RevisedBy { get; set; }
/// <summary>
/// Gets the revised date.
/// </summary>
[JsonProperty("revisedDate")]
public DateTime RevisedDate { get; set; }
/// <summary>
/// Gets the revision.
/// </summary>
[JsonProperty("revision")]
public WorkItemUpdatedRevision Revision { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,38 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Newtonsoft.Json;
namespace Microsoft.AspNet.WebHooks.Payloads
{
/// <summary>
/// Describes the revision
/// </summary>
public class WorkItemUpdatedRevision
{
/// <summary>
/// Gets the identifier of the revision.
/// </summary>
[JsonProperty("id")]
public int Id { get; set; }
/// <summary>
/// Gets the revision number.
/// </summary>
[JsonProperty("rev")]
public int Rev { get; set; }
/// <summary>
/// Gets the revision fields.
/// </summary>
[JsonProperty("fields")]
public WorkItemFields Fields { get; set; }
/// <summary>
/// Gets the revision URL.
/// </summary>
[JsonProperty("url")]
public Uri Url { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,6 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Microsoft.AspNet.WebHooks.Receivers.TFS.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")]

Просмотреть файл

@ -0,0 +1,81 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Microsoft.AspNet.WebHooks.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class VstsReceiverResources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal VstsReceiverResources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.AspNet.WebHooks.Properties.VstsReceiverResources", typeof(VstsReceiverResources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to The property &apos;eventType&apos; contains unmapped value &apos;{0}&apos;..
/// </summary>
internal static string Handler_NonMappedEventType {
get {
return ResourceManager.GetString("Handler_NonMappedEventType", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to No property &apos;eventType&apos; was found in root of the object..
/// </summary>
internal static string Receiver_NoEventType {
get {
return ResourceManager.GetString("Receiver_NoEventType", resourceCulture);
}
}
}
}

Просмотреть файл

@ -0,0 +1,126 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Handler_NonMappedEventType" xml:space="preserve">
<value>The property 'eventType' contains unmapped value '{0}'.</value>
</data>
<data name="Receiver_NoEventType" xml:space="preserve">
<value>No property 'eventType' was found in root of the object.</value>
</data>
</root>

Просмотреть файл

@ -0,0 +1,87 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http.Controllers;
using Microsoft.AspNet.WebHooks.Properties;
using Newtonsoft.Json.Linq;
namespace Microsoft.AspNet.WebHooks
{
/// <summary>
/// Provides an <see cref="IWebHookReceiver"/> implementation which supports WebHooks generated by Visual Studio Team Services.
///
/// The corresponding WebHook URI is of the form '<c>https://&lt;host&gt;/api/webhooks/incoming/vsts/{id}?code={code}</c>'.
/// For security reasons the WebHook URI must be an <c>https</c> URI and contain a 'code' query parameter with the
/// same value as configured in the '<c>MS_WebHookReceiverSecret_Tfs</c>' application setting, optionally using IDs
/// to differentiate between multiple WebHooks, for example '<c>secret0, id1=secret1, id2=secret2</c>'.
/// The 'code' parameter must be between 32 and 128 characters long.
///
/// For details about Visual Studio Team Services WebHooks, see <c>https://www.visualstudio.com/en-us/get-started/integrate/service-hooks/webhooks-and-vso-vs</c>.
/// </summary>
public class VstsWebHookReceiver : WebHookReceiver
{
internal const string RecName = "vsts";
internal const string EventTypeTokenName = "eventType";
/// <summary>
/// Gets the receiver name for this receiver.
/// </summary>
public static string ReceiverName
{
get { return RecName; }
}
/// <inheritdoc />
public override string Name
{
get { return RecName; }
}
/// <inheritdoc />
public override async Task<HttpResponseMessage> ReceiveAsync(string id, HttpRequestContext context, HttpRequestMessage request)
{
if (id == null)
{
throw new ArgumentNullException(nameof(id));
}
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (request == null)
{
throw new ArgumentNullException(nameof(request));
}
if (request.Method != HttpMethod.Post)
{
return CreateBadMethodResponse(request);
}
// Ensure that we use https and have a valid code parameter
await EnsureValidCode(request, id);
// Read the request entity body
JObject jsonBody = await ReadAsJsonAsync(request);
// Read the action from body
JToken action;
string actionAsString;
if (!jsonBody.TryGetValue(EventTypeTokenName, out action))
{
request.GetConfiguration().DependencyResolver.GetLogger().Error(VstsReceiverResources.Receiver_NoEventType);
return request.CreateErrorResponse(HttpStatusCode.BadRequest, VstsReceiverResources.Receiver_NoEventType);
}
else
{
actionAsString = action.Value<string>();
}
return await ExecuteWebHookAsync(id, context, request, new[] { actionAsString }, jsonBody);
}
}
}

Просмотреть файл

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.2" targetFramework="net45" />
<package id="Microsoft.AspNet.WebApi.Core" version="5.2.2" targetFramework="net45" />
<package id="Newtonsoft.Json" version="6.0.4" targetFramework="net45" />
<package id="StyleCop.MSBuild" version="4.7.49.1" targetFramework="net45" developmentDependency="true" />
</packages>

Просмотреть файл

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="xunit.parallelizeAssembly" value="true" />
</appSettings>
<startup>
</startup>
</configuration>

Просмотреть файл

@ -0,0 +1,16 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Globalization;
namespace Microsoft.AspNet.WebHooks
{
internal static class Extensions
{
public static DateTime ToDateTime(this string self)
{
return DateTime.Parse(self, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);
}
}
}

Просмотреть файл

@ -0,0 +1,168 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Controllers;
using Microsoft.AspNet.WebHooks.Payloads;
using Moq;
using Newtonsoft.Json.Linq;
using Xunit;
namespace Microsoft.AspNet.WebHooks.Handlers
{
public class VstsWebHookHandlerBaseTests
{
private readonly Mock<VstsWebHookHandlerBase> _handlerMock;
private readonly VstsWebHookHandlerBase _handler;
private WebHookHandlerContext _context;
public VstsWebHookHandlerBaseTests()
{
_handlerMock = new Mock<VstsWebHookHandlerBase> { CallBase = true };
_handler = _handlerMock.Object;
}
[Fact]
public void VstsWebHookHandlerBase_SetsReceiverName()
{
Assert.Equal(VstsWebHookReceiver.ReceiverName, _handler.Receiver);
}
[Fact]
public async Task ExecuteAsync_Dispatches_BuildCompleted()
{
// Arrange
_context = GetContext("Microsoft.AspNet.WebHooks.Messages.build.complete.json", "build.complete");
// Act
await _handler.ExecuteAsync(VstsWebHookReceiver.ReceiverName, _context);
// Assert
_handlerMock.Verify(h => h.ExecuteAsync(_context, It.IsAny<BuildCompletedPayload>()), Times.Once());
}
[Fact]
public async Task ExecuteAsync_Dispatches_CodeCheckedIn()
{
// Arrange
_context = GetContext("Microsoft.AspNet.WebHooks.Messages.tfvc.checkin.json", "tfvc.checkin");
// Act
await _handler.ExecuteAsync(VstsWebHookReceiver.ReceiverName, _context);
// Assert
_handlerMock.Verify(h => h.ExecuteAsync(_context, It.IsAny<CodeCheckedInPayload>()), Times.Once());
}
[Fact]
public async Task ExecuteAsync_Dispatches_TeamRoomMessagePosted()
{
// Arrange
_context = GetContext("Microsoft.AspNet.WebHooks.Messages.message.posted.json", "message.posted");
// Act
await _handler.ExecuteAsync(VstsWebHookReceiver.ReceiverName, _context);
// Assert
_handlerMock.Verify(h => h.ExecuteAsync(_context, It.IsAny<TeamRoomMessagePostedPayload>()), Times.Once());
}
[Fact]
public async Task ExecuteAsync_Dispatches_WorkItemCommentedOn()
{
// Arrange
_context = GetContext("Microsoft.AspNet.WebHooks.Messages.workitem.commented.json", "workitem.commented");
// Act
await _handler.ExecuteAsync(VstsWebHookReceiver.ReceiverName, _context);
// Assert
_handlerMock.Verify(h => h.ExecuteAsync(_context, It.IsAny<WorkItemCommentedOnPayload>()), Times.Once());
}
[Fact]
public async Task ExecuteAsync_Dispatches_WorkItemCreated()
{
// Arrange
_context = GetContext("Microsoft.AspNet.WebHooks.Messages.workitem.created.json", "workitem.created");
// Act
await _handler.ExecuteAsync(VstsWebHookReceiver.ReceiverName, _context);
// Assert
_handlerMock.Verify(h => h.ExecuteAsync(_context, It.IsAny<WorkItemCreatedPayload>()), Times.Once());
}
[Fact]
public async Task ExecuteAsync_Dispatches_WorkItemDeleted()
{
// Arrange
_context = GetContext("Microsoft.AspNet.WebHooks.Messages.workitem.deleted.json", "workitem.deleted");
// Act
await _handler.ExecuteAsync(VstsWebHookReceiver.ReceiverName, _context);
// Assert
_handlerMock.Verify(h => h.ExecuteAsync(_context, It.IsAny<WorkItemDeletedPayload>()), Times.Once());
}
[Fact]
public async Task ExecuteAsync_Dispatches_WorkItemRestored()
{
// Arrange
_context = GetContext("Microsoft.AspNet.WebHooks.Messages.workitem.restored.json", "workitem.restored");
// Act
await _handler.ExecuteAsync(VstsWebHookReceiver.ReceiverName, _context);
// Assert
_handlerMock.Verify(h => h.ExecuteAsync(_context, It.IsAny<WorkItemRestoredPayload>()), Times.Once());
}
[Fact]
public async Task ExecuteAsync_Dispatches_WorkItemUpdated()
{
// Arrange
_context = GetContext("Microsoft.AspNet.WebHooks.Messages.workitem.updated.json", "workitem.updated");
// Act
await _handler.ExecuteAsync(VstsWebHookReceiver.ReceiverName, _context);
// Assert
_handlerMock.Verify(h => h.ExecuteAsync(_context, It.IsAny<WorkItemUpdatedPayload>()), Times.Once());
}
[Fact]
public async Task ExecuteAsync_Handles_UnknownEventType()
{
// Arrange
_context = GetContext("Microsoft.AspNet.WebHooks.Messages.bad.notMappedEventType.json", "unknown");
// Act
await _handler.ExecuteAsync(VstsWebHookReceiver.ReceiverName, _context);
// Assert
_handlerMock.Verify(h => h.ExecuteAsync(_context, It.IsAny<JObject>()), Times.Once());
}
private static WebHookHandlerContext GetContext(string payload, string action)
{
JObject data = EmbeddedResource.ReadAsJObject(payload);
HttpConfiguration httpConfig = new HttpConfiguration();
HttpRequestContext requestContext = new HttpRequestContext { Configuration = httpConfig };
HttpRequestMessage request = new HttpRequestMessage();
request.SetRequestContext(requestContext);
IEnumerable<string> actions = new[] { action };
return new WebHookHandlerContext(actions)
{
Data = data,
Request = request,
RequestContext = requestContext
};
}
}
}

Просмотреть файл

@ -0,0 +1,3 @@
{
"subscriptionId": "00000000-0000-0000-0000-000000000000"
}

Просмотреть файл

@ -0,0 +1,5 @@
{
"subscriptionId": "00000000-0000-0000-0000-000000000000",
"notificationId": 5,
"eventType": "unknownType"
}

Просмотреть файл

@ -0,0 +1,83 @@
{
"subscriptionId": "00000000-0000-0000-0000-000000000000",
"notificationId": 1,
"id": "4a5d99d6-1c75-4e53-91b9-ee80057d4ce3",
"eventType": "build.complete",
"publisherId": "tfs",
"message": {
"text": "Build ConsumerAddressModule_20150407.2 succeeded",
"html": "Build <a href=\"https://good-company.some.ssl.host/web/build.aspx?id=5023c10b-bef3-41c3-bf53-686c4e34ee9e&amp;builduri=vstfs%3a%2f%2f%2fBuild%2fBuild%2f3\">ConsumerAddressModule_20150407.2</a> succeeded",
"markdown": "Build [ConsumerAddressModule_20150407.2](https://good-company.some.ssl.host/web/build.aspx?id=5023c10b-bef3-41c3-bf53-686c4e34ee9e&builduri=vstfs%3a%2f%2f%2fBuild%2fBuild%2f3) succeeded"
},
"detailedMessage": {
"text": "Build ConsumerAddressModule_20150407.2 succeeded",
"html": "Build <a href=\"https://good-company.some.ssl.host/web/build.aspx?id=5023c10b-bef3-41c3-bf53-686c4e34ee9e&amp;builduri=vstfs%3a%2f%2f%2fBuild%2fBuild%2f3\">ConsumerAddressModule_20150407.2</a> succeeded",
"markdown": "Build [ConsumerAddressModule_20150407.2](https://good-company.some.ssl.host/web/build.aspx?id=5023c10b-bef3-41c3-bf53-686c4e34ee9e&builduri=vstfs%3a%2f%2f%2fBuild%2fBuild%2f3) succeeded"
},
"resource": {
"uri": "vstfs:///Build/Build/2",
"id": 2,
"buildNumber": "ConsumerAddressModule_20150407.1",
"url": "https://good-company.some.ssl.host/DefaultCollection/71777fbc-1cf2-4bd1-9540-128c1c71f766/_apis/build/Builds/2",
"startTime": "2015-04-07T18:04:06.83Z",
"finishTime": "2015-04-07T18:06:10.69Z",
"reason": "manual",
"status": "succeeded",
"dropLocation": "#/3/drop",
"drop": {
"location": "#/3/drop",
"type": "container",
"url": "https://good-company.some.ssl.host/DefaultCollection/_apis/resources/Containers/3/drop",
"downloadUrl": "https://good-company.some.ssl.host/DefaultCollection/_apis/resources/Containers/3/drop?api-version=1.0&$format=zip&downloadFileName=ConsumerAddressModule_20150407.1_drop"
},
"log": {
"type": "container",
"url": "https://good-company.some.ssl.host/DefaultCollection/_apis/resources/Containers/3/logs",
"downloadUrl": "https://good-company.some.ssl.host/_apis/resources/Containers/3/logs?api-version=1.0&$format=zip&downloadFileName=ConsumerAddressModule_20150407.1_logs"
},
"sourceGetVersion": "LG:refs/heads/master:600c52d2d5b655caa111abfd863e5a9bd304bb0e",
"lastChangedBy": {
"id": "d6245f20-2af8-44f4-9451-8107cb2767db",
"displayName": "John Smith",
"uniqueName": "fabrikamfiber16@hotmail.com",
"url": "https://good-company.some.ssl.host/_apis/Identities/d6245f20-2af8-44f4-9451-8107cb2767db",
"imageUrl": "https://good-company.some.ssl.host/DefaultCollection/_api/_common/identityImage?id=d6245f20-2af8-44f4-9451-8107cb2767db"
},
"retainIndefinitely": false,
"hasDiagnostics": true,
"definition": {
"batchSize": 1,
"triggerType": "none",
"definitionType": "xaml",
"id": 2,
"name": "ConsumerAddressModule",
"url": "https://good-company.some.ssl.host/DefaultCollection/71777fbc-1cf2-4bd1-9540-128c1c71f766/_apis/build/Definitions/2"
},
"queue": {
"queueType": "buildController",
"id": 4,
"name": "Hosted Build Controller",
"url": "https://good-company.some.ssl.host/DefaultCollection/_apis/build/Queues/4"
},
"requests": [
{
"id": 1,
"url": "https://good-company.some.ssl.host/DefaultCollection/71777fbc-1cf2-4bd1-9540-128c1c71f766/_apis/build/Requests/1",
"requestedFor": {
"id": "d6245f20-2af8-44f4-9451-8107cb2767db",
"displayName": "John Smith",
"uniqueName": "fabrikamfiber16@hotmail.com",
"url": "https://good-company.some.ssl.host/_apis/Identities/d6245f20-2af8-44f4-9451-8107cb2767db",
"imageUrl": "https://good-company.some.ssl.host/DefaultCollection/_api/_common/identityImage?id=d6245f20-2af8-44f4-9451-8107cb2767db"
}
}
]
},
"resourceVersion": "1.0",
"resourceContainers": {
"collection": { "id": "c12d0eb8-e382-443b-9f9c-c52cba5014c2" },
"account": { "id": "f844ec47-a9db-4511-8281-8b63f4eaf94e" },
"project": { "id": "be9b3917-87e6-42a4-a549-2bc06a7a878f" }
},
"createdDate": "2016-05-02T19:00:39.5893296Z"
}

Просмотреть файл

@ -0,0 +1,36 @@
{
"subscriptionId": "00000000-0000-0000-0000-000000000000",
"notificationId": 3,
"id": "daae438c-296b-4512-b08e-571910874e9b",
"eventType": "message.posted",
"publisherId": "tfs",
"message": {
"text": "Jamal Hartnett posted a message to Northward-Fiber-Git Team Room\r\nHello",
"html": "Jamal Hartnett posted a message to Northward-Fiber-Git Team Room\r\nHello",
"markdown": "Jamal Hartnett posted a message to Northward-Fiber-Git Team Room\r\nHello"
},
"detailedMessage": {
"text": "Jamal Hartnett posted a message to Northward-Fiber-Git Team Room\r\nHello",
"html": "Jamal Hartnett posted a message to Northward-Fiber-Git Team Room<p>Hello</p>",
"markdown": "Jamal Hartnett posted a message to Northward-Fiber-Git Team Room\r\nHello"
},
"resource": {
"id": 0,
"content": "Hello",
"messageType": "normal",
"postedTime": "2014-05-02T19:17:13.3309587Z",
"postedRoomId": 1,
"postedBy": {
"id": "00067FFED5C7AF52@Live.com",
"displayName": "Jamal Hartnett",
"uniqueName": "Windows Live ID\\fabrikamfiber4@hotmail.com"
}
},
"resourceVersion": "1.0",
"resourceContainers": {
"collection": { "id": "c12d0eb8-e382-443b-9f9c-c52cba5014c2" },
"account": { "id": "f844ec47-a9db-4511-8281-8b63f4eaf94e" },
"project": { "id": "be9b3917-87e6-42a4-a549-2bc06a7a878f" }
},
"createdDate": "2016-05-02T19:13:40.8417653Z"
}

Просмотреть файл

@ -0,0 +1,40 @@
{
"subscriptionId": "00000000-0000-0000-0000-000000000000",
"notificationId": 2,
"id": "f9b4c23e-88dd-4516-b04d-849787304e32",
"eventType": "tfvc.checkin",
"publisherId": "tfs",
"message": {
"text": "John Smith checked in changeset 18: Dropping in new Java sample",
"html": "John Smith checked in changeset <a href=\"https://good-company.some.ssl.host/web/cs.aspx?id=d81542e4-cdfa-4333-b082-1ae2d6c3ad16&amp;cs=18\">18</a>: Dropping in new Java sample",
"markdown": "John Smith checked in changeset [18](https://good-company.some.ssl.host/web/cs.aspx?id=d81542e4-cdfa-4333-b082-1ae2d6c3ad16&cs=18): Dropping in new Java sample"
},
"detailedMessage": {
"text": "John Smith checked in changeset 18: Dropping in new Java sample",
"html": "John Smith checked in changeset <a href=\"https://good-company.some.ssl.host/web/cs.aspx?id=d81542e4-cdfa-4333-b082-1ae2d6c3ad16&amp;cs=18\">18</a>: Dropping in new Java sample",
"markdown": "John Smith checked in changeset [18](https://good-company.some.ssl.host/web/cs.aspx?id=d81542e4-cdfa-4333-b082-1ae2d6c3ad16&cs=18): Dropping in new Java sample"
},
"resource": {
"changesetId": 18,
"url": "https://good-company.some.ssl.host/DefaultCollection/_apis/tfvc/changesets/18",
"author": {
"id": "d6245f20-2af8-44f4-9451-8107cb2767db",
"displayName": "John Smith",
"uniqueName": "fabrikamfiber16@hotmail.com"
},
"checkedInBy": {
"id": "d6245f20-2af8-44f4-9451-8107cb2767db",
"displayName": "John Smith",
"uniqueName": "fabrikamfiber16@hotmail.com"
},
"createdDate": "2014-05-12T22:41:16Z",
"comment": "Dropping in new Java sample"
},
"resourceVersion": "1.0",
"resourceContainers": {
"collection": { "id": "c12d0eb8-e382-443b-9f9c-c52cba5014c2" },
"account": { "id": "f844ec47-a9db-4511-8281-8b63f4eaf94e" },
"project": { "id": "be9b3917-87e6-42a4-a549-2bc06a7a878f" }
},
"createdDate": "2016-05-02T19:01:11.7056821Z"
}

Просмотреть файл

@ -0,0 +1,52 @@
{
"subscriptionId": "00000000-0000-0000-0000-000000000000",
"notificationId": 4,
"id": "fb2617ed-60df-4518-81fa-749faa6c5cd6",
"eventType": "workitem.commented",
"publisherId": "tfs",
"message": {
"text": "Bug #5 (Some great new idea!) commented on by Jamal Hartnett.\r\n(http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5)",
"html": "<a href=\"http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&amp;id=5\">Bug #5</a> (Some great new idea!) commented on by Jamal Hartnett.",
"markdown": "[Bug #5](http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5) (Some great new idea!) commented on by Jamal Hartnett."
},
"detailedMessage": {
"text": "Bug #5 (Some great new idea!) commented on by Jamal Hartnett.\r\n(http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5)\r\nThis is a great new idea",
"html": "<a href=\"http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&amp;id=5\">Bug #5</a> (Some great new idea!) commented on by Jamal Hartnett.<br/>This is a great new idea",
"markdown": "[Bug #5](http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5) (Some great new idea!) commented on by Jamal Hartnett.\r\nThis is a great new idea"
},
"resource": {
"id": 5,
"rev": 4,
"fields": {
"System.AreaPath": "GoodCompanyCloud",
"System.TeamProject": "GoodCompanyCloud",
"System.IterationPath": "GoodCompanyCloud\\Release 1\\Sprint 1",
"System.WorkItemType": "Bug",
"System.State": "New",
"System.Reason": "New defect reported",
"System.CreatedDate": "2014-07-15T17:42:44.663Z",
"System.CreatedBy": "Jamal Hartnett",
"System.ChangedDate": "2014-07-15T17:42:44.663Z",
"System.ChangedBy": "Jamal Hartnett",
"System.Title": "Some great new idea!",
"Microsoft.VSTS.Common.Severity": "3 - Medium",
"WEF_EB329F44FE5F4A94ACB1DA153FDF38BA_Kanban.Column": "New",
"System.History": "This is a great new idea"
},
"_links": {
"self": { "href": "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5" },
"workItemUpdates": { "href": "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5/updates" },
"workItemRevisions": { "href": "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5/revisions" },
"workItemType": { "href": "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/ea830882-2a3c-4095-a53f-972f9a376f6e/workItemTypes/Bug" },
"fields": { "href": "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/fields" }
},
"url": "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5"
},
"resourceVersion": "1.0",
"resourceContainers": {
"collection": { "id": "c12d0eb8-e382-443b-9f9c-c52cba5014c2" },
"account": { "id": "f844ec47-a9db-4511-8281-8b63f4eaf94e" },
"project": { "id": "be9b3917-87e6-42a4-a549-2bc06a7a878f" }
},
"createdDate": "2016-05-02T19:15:37.4638247Z"
}

Просмотреть файл

@ -0,0 +1,51 @@
{
"subscriptionId": "00000000-0000-0000-0000-000000000000",
"notificationId": 5,
"id": "d2d46fb1-dba5-403c-9373-427583f19e8c",
"eventType": "workitem.created",
"publisherId": "tfs",
"message": {
"text": "Bug #5 (Some great new idea!) created by Jamal Hartnett.\r\n(http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5)",
"html": "<a href=\"http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&amp;id=5\">Bug #5</a> (Some great new idea!) created by Jamal Hartnett.",
"markdown": "[Bug #5](http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5) (Some great new idea!) created by Jamal Hartnett."
},
"detailedMessage": {
"text": "Bug #5 (Some great new idea!) created by Jamal Hartnett.\r\n(http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5)\r\n\r\n- State: New\r\n- Assigned to: \r\n- Comment: \r\n- Severity: 3 - Medium\r\n",
"html": "<a href=\"http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&amp;id=5\">Bug #5</a> (Some great new idea!) created by Jamal Hartnett.<ul>\r\n<li>State: New</li>\r\n<li>Assigned to: </li>\r\n<li>Comment: </li>\r\n<li>Severity: 3 - Medium</li></ul>",
"markdown": "[Bug #5](http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5) (Some great new idea!) created by Jamal Hartnett.\r\n\r\n* State: New\r\n* Assigned to: \r\n* Comment: \r\n* Severity: 3 - Medium\r\n"
},
"resource": {
"id": 5,
"rev": 1,
"fields": {
"System.AreaPath": "GoodCompanyCloud",
"System.TeamProject": "GoodCompanyCloud",
"System.IterationPath": "GoodCompanyCloud\\Release 1\\Sprint 1",
"System.WorkItemType": "Bug",
"System.State": "New",
"System.Reason": "New defect reported",
"System.CreatedDate": "2014-07-15T17:42:44.663Z",
"System.CreatedBy": "Jamal Hartnett",
"System.ChangedDate": "2014-07-15T17:42:44.663Z",
"System.ChangedBy": "Jamal Hartnett",
"System.Title": "Some great new idea!",
"Microsoft.VSTS.Common.Severity": "3 - Medium",
"WEF_EB329F44FE5F4A94ACB1DA153FDF38BA_Kanban.Column": "New"
},
"_links": {
"self": { "href": "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5" },
"workItemUpdates": { "href": "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5/updates" },
"workItemRevisions": { "href": "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5/revisions" },
"workItemType": { "href": "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/ea830882-2a3c-4095-a53f-972f9a376f6e/workItemTypes/Bug" },
"fields": { "href": "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/fields" }
},
"url": "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5"
},
"resourceVersion": "1.0",
"resourceContainers": {
"collection": { "id": "c12d0eb8-e382-443b-9f9c-c52cba5014c2" },
"account": { "id": "f844ec47-a9db-4511-8281-8b63f4eaf94e" },
"project": { "id": "be9b3917-87e6-42a4-a549-2bc06a7a878f" }
},
"createdDate": "2016-05-02T19:16:25.6251162Z"
}

Просмотреть файл

@ -0,0 +1,49 @@
{
"subscriptionId": "00000000-0000-0000-0000-000000000000",
"notificationId": 6,
"id": "72da0ade-0709-40ee-beb7-104287bf7e84",
"eventType": "workitem.deleted",
"publisherId": "tfs",
"message": {
"text": "Bug #5 (Some great new idea!) deleted by Jamal Hartnett.",
"html": "Bug #5 (Some great new idea!) deleted by Jamal Hartnett.",
"markdown": "[Bug #5] (Some great new idea!) deleted by Jamal Hartnett."
},
"detailedMessage": {
"text": "Bug #5 (Some great new idea!) deleted by Jamal Hartnett.\r\n\r\n- State: New\r\n",
"html": "Bug #5 (Some great new idea!) deleted by Jamal Hartnett.<ul>\r\n<li>State: New</li></ul>",
"markdown": "[Bug #5] (Some great new idea!) deleted by Jamal Hartnett.\r\n\r\n* State: New\r\n"
},
"resource": {
"id": 5,
"rev": 1,
"fields": {
"System.AreaPath": "GoodCompanyCloud",
"System.TeamProject": "GoodCompanyCloud",
"System.IterationPath": "GoodCompanyCloud\\Release 1\\Sprint 1",
"System.WorkItemType": "Bug",
"System.State": "New",
"System.Reason": "New defect reported",
"System.CreatedDate": "2014-07-15T17:42:44.663Z",
"System.CreatedBy": "Jamal Hartnett",
"System.ChangedDate": "2014-07-15T17:42:44.663Z",
"System.ChangedBy": "Jamal Hartnett",
"System.Title": "Some great new idea!",
"Microsoft.VSTS.Common.Severity": "3 - Medium",
"WEF_EB329F44FE5F4A94ACB1DA153FDF38BA_Kanban.Column": "New"
},
"_links": {
"self": { "href": "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/recyclebin/5" },
"workItemType": { "href": "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/ea830882-2a3c-4095-a53f-972f9a376f6e/workItemTypes/Bug" },
"fields": { "href": "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/fields" }
},
"url": "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/recyclebin/5"
},
"resourceVersion": "1.0",
"resourceContainers": {
"collection": { "id": "c12d0eb8-e382-443b-9f9c-c52cba5014c2" },
"account": { "id": "f844ec47-a9db-4511-8281-8b63f4eaf94e" },
"project": { "id": "be9b3917-87e6-42a4-a549-2bc06a7a878f" }
},
"createdDate": "2016-05-02T19:17:28.3644564Z"
}

Просмотреть файл

@ -0,0 +1,53 @@
{
"subscriptionId": "00000000-0000-0000-0000-000000000000",
"notificationId": 7,
"id": "1ca023d6-6cff-49dd-b3d1-302b69311810",
"eventType": "workitem.restored",
"publisherId": "tfs",
"message": {
"text": "Bug #5 (Some great new idea!) restored by Jamal Hartnett.\r\n(http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5)",
"html": "<a href=\"http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&amp;id=5\">Bug #5</a> (Some great new idea!) restored by Jamal Hartnett.",
"markdown": "[Bug #5](http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5) (Some great new idea!) restored by Jamal Hartnett."
},
"detailedMessage": {
"text": "Bug #5 (Some great new idea!) restored by Jamal Hartnett.\r\n(http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5)\r\n\r\n- State: New\r\n- Severity: 3 - Medium\r\n",
"html": "<a href=\"http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&amp;id=5\">Bug #5</a> (Some great new idea!) restored by Jamal Hartnett.<ul>\r\n<li>State: New</li>Severity: 3 - Medium</li></ul>",
"markdown": "[Bug #5](http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5) (Some great new idea!) restored by Jamal Hartnett.\r\n\r\n* State: New\r\n* Severity: 3 - Medium\r\n"
},
"resource": {
"id": 5,
"rev": 1,
"fields": {
"System.AreaPath": "GoodCompanyCloud",
"System.TeamProject": "GoodCompanyCloud",
"System.IterationPath": "GoodCompanyCloud\\Release 1\\Sprint 1",
"System.WorkItemType": "Bug",
"System.State": "New",
"System.Reason": "New defect reported",
"System.CreatedDate": "2014-07-15T17:42:44.663Z",
"System.CreatedBy": "Jamal Hartnett",
"System.ChangedDate": "2014-07-15T17:42:44.663Z",
"System.ChangedBy": "Jamal Hartnett",
"System.Title": "Some great new idea!",
"Microsoft.VSTS.Common.Severity": "3 - Medium",
"WEF_EB329F44FE5F4A94ACB1DA153FDF38BA_Kanban.Column": "New"
},
"_links": {
"self": { "href": "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5" },
"workItemUpdates": { "href": "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5/updates" },
"workItemRevisions": { "href": "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5/revisions" },
"workItemType": { "href": "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/ea830882-2a3c-4095-a53f-972f9a376f6e/workItemTypes/Bug" },
"fields": { "href": "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/fields" },
"html": { "href": "https://good-company.some.ssl.host/web/wi.aspx?id=d81542e4-cdfa-4333-b082-1ae2d6c3ad16&id=5" },
"workItemHistory": { "href": "https://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5/history" }
},
"url": "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5"
},
"resourceVersion": "1.0",
"resourceContainers": {
"collection": { "id": "c12d0eb8-e382-443b-9f9c-c52cba5014c2" },
"account": { "id": "f844ec47-a9db-4511-8281-8b63f4eaf94e" },
"project": { "id": "be9b3917-87e6-42a4-a549-2bc06a7a878f" }
},
"createdDate": "2016-05-02T19:18:15.5707279Z"
}

Просмотреть файл

@ -0,0 +1,92 @@
{
"subscriptionId": "00000000-0000-0000-0000-000000000000",
"notificationId": 8,
"id": "27646e0e-b520-4d2b-9411-bba7524947cd",
"eventType": "workitem.updated",
"publisherId": "tfs",
"message": {
"text": "Bug #5 (Some great new idea!) updated by Jamal Hartnett.\r\n(http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5)",
"html": "<a href=\"http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&amp;id=5\">Bug #5</a> (Some great new idea!) updated by Jamal Hartnett.",
"markdown": "[Bug #5](http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5) (Some great new idea!) updated by Jamal Hartnett."
},
"detailedMessage": {
"text": "Bug #5 (Some great new idea!) updated by Jamal Hartnett.\r\n(http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5)\r\n\r\n- New State: Approved\r\n",
"html": "<a href=\"http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&amp;id=5\">Bug #5</a> (Some great new idea!) updated by Jamal Hartnett.<ul>\r\n<li>New State: Approved</li></ul>",
"markdown": "[Bug #5](http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5) (Some great new idea!) updated by Jamal Hartnett.\r\n\r\n* New State: Approved\r\n"
},
"resource": {
"id": 2,
"workItemId": 0,
"rev": 2,
"revisedBy": null,
"revisedDate": "0001-01-01T00:00:00",
"fields": {
"System.Rev": {
"oldValue": "1",
"newValue": "2"
},
"System.AuthorizedDate": {
"oldValue": "2014-07-15T16:48:44.663Z",
"newValue": "2014-07-15T17:42:44.663Z"
},
"System.RevisedDate": {
"oldValue": "2014-07-15T17:42:44.663Z",
"newValue": "9999-01-01T00:00:00Z"
},
"System.State": {
"oldValue": "New",
"newValue": "Approved"
},
"System.Reason": {
"oldValue": "New defect reported",
"newValue": "Approved by the Product Owner"
},
"System.AssignedTo": { "newValue": "Jamal Hartnet" },
"System.ChangedDate": {
"oldValue": "2014-07-15T16:48:44.663Z",
"newValue": "2014-07-15T17:42:44.663Z"
},
"System.Watermark": {
"oldValue": "2",
"newValue": "5"
},
"Microsoft.VSTS.Common.Severity": {
"oldValue": "3 - Medium",
"newValue": "2 - High"
}
},
"_links": {
"self": { "href": "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5/updates/2" },
"parent": { "href": "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5" },
"workItemUpdates": { "href": "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5/updates" }
},
"url": "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5/updates/2",
"revision": {
"id": 5,
"rev": 2,
"fields": {
"System.AreaPath": "GoodCompanyCloud",
"System.TeamProject": "GoodCompanyCloud",
"System.IterationPath": "GoodCompanyCloud\\Release 1\\Sprint 1",
"System.WorkItemType": "Bug",
"System.State": "New",
"System.Reason": "New defect reported",
"System.CreatedDate": "2014-07-15T16:48:44.663Z",
"System.CreatedBy": "Jamal Hartnett",
"System.ChangedDate": "2014-07-15T16:48:44.663Z",
"System.ChangedBy": "Jamal Hartnett",
"System.Title": "Some great new idea!",
"Microsoft.VSTS.Common.Severity": "3 - Medium",
"WEF_EB329F44FE5F4A94ACB1DA153FDF38BA_Kanban.Column": "New"
},
"url": "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5/revisions/2"
}
},
"resourceVersion": "1.0",
"resourceContainers": {
"collection": { "id": "c12d0eb8-e382-443b-9f9c-c52cba5014c2" },
"account": { "id": "f844ec47-a9db-4511-8281-8b63f4eaf94e" },
"project": { "id": "be9b3917-87e6-42a4-a549-2bc06a7a878f" }
},
"createdDate": "2016-05-02T19:19:12.8836446Z"
}

Просмотреть файл

@ -0,0 +1,139 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\packages\xunit.runner.visualstudio.2.0.1\build\net20\xunit.runner.visualstudio.props" Condition="Exists('..\..\packages\xunit.runner.visualstudio.2.0.1\build\net20\xunit.runner.visualstudio.props')" />
<Import Project="..\..\packages\xunit.core.2.0.0\build\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.props" Condition="Exists('..\..\packages\xunit.core.2.0.0\build\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.props')" />
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory),WebHooks.sln))\tools\WebHooks.settings.targets" />
<PropertyGroup>
<ProjectGuid>{B27CC8B5-BF38-434B-B5CE-42ACEC40624C}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Microsoft.AspNet.WebHooks</RootNamespace>
<AssemblyName>Microsoft.AspNet.WebHooks.Receivers.VSTS.Test</AssemblyName>
<OutputPath>..\..\bin\$(Configuration)\Test\</OutputPath>
<RunCodeAnalysis>$(CodeAnalysis)</RunCodeAnalysis>
<CodeAnalysisAdditionalOptions>/assemblyCompareMode:StrongNameIgnoringVersion</CodeAnalysisAdditionalOptions>
<CodeAnalysisRuleSet>..\..\FxCopTest.ruleset</CodeAnalysisRuleSet>
<DefineConstants>$(DefineConstants);ASPNETWEBHOOKS</DefineConstants>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<ItemGroup>
<Reference Include="Moq, Version=4.2.1502.911, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
<HintPath>..\..\packages\Moq.4.2.1502.0911\lib\net40\Moq.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Net.Http.Formatting, Version=5.2.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.AspNet.WebApi.Client.5.2.2\lib\net45\System.Net.Http.Formatting.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Web.Http, Version=5.2.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.AspNet.WebApi.Core.5.2.2\lib\net45\System.Web.Http.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="xunit.abstractions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<HintPath>..\..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="xunit.assert, Version=2.0.0.2929, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<HintPath>..\..\packages\xunit.assert.2.0.0\lib\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.assert.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="xunit.core, Version=2.0.0.2929, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<HintPath>..\..\packages\xunit.extensibility.core.2.0.0\lib\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.dll</HintPath>
<Private>True</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\common\EmbeddedResource.cs">
<Link>Common\EmbeddedResource.cs</Link>
</Compile>
<Compile Include="Common\Extensions.cs" />
<Compile Include="Handlers\VstsWebHookHandlerBaseTests.cs" />
<Compile Include="Payloads\BuildCompletedPayloadTests.cs" />
<Compile Include="Payloads\CodeCheckedInPayloadTests.cs" />
<Compile Include="Payloads\TeamRoomMessagePostedPayloadTests.cs" />
<Compile Include="Payloads\WorkItemCommentedOnPayloadTests.cs" />
<Compile Include="Payloads\WorkItemCreatedPayloadTests.cs" />
<Compile Include="Payloads\WorkItemDeletedPayloadTests.cs" />
<Compile Include="Payloads\WorkItemRestoredPayloadTests.cs" />
<Compile Include="Payloads\WorkItemUpdatedPayloadTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="WebHooks\VstsWebHookReceiverTests.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="App.config" />
<EmbeddedResource Include="Messages\build.complete.json" />
<EmbeddedResource Include="Messages\tfvc.checkin.json" />
<EmbeddedResource Include="Messages\workitem.updated.json" />
<EmbeddedResource Include="Messages\workitem.restored.json" />
<EmbeddedResource Include="Messages\workitem.deleted.json" />
<EmbeddedResource Include="Messages\workitem.created.json" />
<EmbeddedResource Include="Messages\workitem.commented.json" />
<EmbeddedResource Include="Messages\message.posted.json" />
<EmbeddedResource Include="Messages\bad.noEventType.json" />
<EmbeddedResource Include="Messages\bad.notMappedEventType.json" />
<None Include="packages.config">
<SubType>Designer</SubType>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Src\Microsoft.AspNet.WebHooks.Common\Microsoft.AspNet.WebHooks.Common.csproj">
<Project>{f7dd0935-6320-4efc-9464-d5a2d2b8c2f7}</Project>
<Name>Microsoft.AspNet.WebHooks.Common</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Microsoft.AspNet.WebHooks.Receivers.VSTS\Microsoft.AspNet.WebHooks.Receivers.VSTS.csproj">
<Project>{6b501d55-2aa3-4757-a185-1277bb881de8}</Project>
<Name>Microsoft.AspNet.WebHooks.Receivers.VSTS</Name>
</ProjectReference>
<ProjectReference Include="..\..\Src\Microsoft.AspNet.WebHooks.Receivers\Microsoft.AspNet.WebHooks.Receivers.csproj">
<Project>{8ced31fb-32f2-4ffb-9997-452fb9728577}</Project>
<Name>Microsoft.AspNet.WebHooks.Receivers</Name>
</ProjectReference>
<ProjectReference Include="..\Microsoft.AspNet.WebHooks.Receivers.Test\Microsoft.AspNet.WebHooks.Receivers.Test.csproj">
<Project>{cb965ed1-1e07-4374-a829-c636db09f567}</Project>
<Name>Microsoft.AspNet.WebHooks.Receivers.Test</Name>
</ProjectReference>
<ProjectReference Include="..\Microsoft.TestUtilities\Microsoft.TestUtilities.csproj">
<Project>{608b1d09-e4de-4dba-8dbf-7758003988f0}</Project>
<Name>Microsoft.TestUtilities</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<CodeAnalysisDictionary Include="..\..\CustomDictionary.xml">
<Link>CustomDictionary.xml</Link>
</CodeAnalysisDictionary>
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\xunit.core.2.0.0\build\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\xunit.core.2.0.0\build\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.props'))" />
<Error Condition="!Exists('..\..\packages\StyleCop.MSBuild.4.7.49.1\build\StyleCop.MSBuild.Targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\StyleCop.MSBuild.4.7.49.1\build\StyleCop.MSBuild.Targets'))" />
<Error Condition="!Exists('..\..\packages\xunit.runner.visualstudio.2.0.1\build\net20\xunit.runner.visualstudio.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\xunit.runner.visualstudio.2.0.1\build\net20\xunit.runner.visualstudio.props'))" />
</Target>
<Import Project="..\..\packages\StyleCop.MSBuild.4.7.49.1\build\StyleCop.MSBuild.Targets" Condition="Exists('..\..\packages\StyleCop.MSBuild.4.7.49.1\build\StyleCop.MSBuild.Targets')" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

Просмотреть файл

@ -0,0 +1,124 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.WebHooks.Payloads;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Xunit;
namespace Microsoft.AspNet.WebHooks
{
public class BuildCompletedPayloadTests
{
[Fact]
public void BuildCompletedPayload_Roundtrips()
{
// Arrange
JObject data = EmbeddedResource.ReadAsJObject("Microsoft.AspNet.WebHooks.Messages.build.complete.json");
var expected = new BuildCompletedPayload
{
SubscriptionId = "00000000-0000-0000-0000-000000000000",
NotificationId = 1,
Id = "4a5d99d6-1c75-4e53-91b9-ee80057d4ce3",
EventType = "build.complete",
PublisherId = "tfs",
Message = new PayloadMessage
{
Text = "Build ConsumerAddressModule_20150407.2 succeeded",
Html = "Build <a href=\"https://good-company.some.ssl.host/web/build.aspx?id=5023c10b-bef3-41c3-bf53-686c4e34ee9e&amp;builduri=vstfs%3a%2f%2f%2fBuild%2fBuild%2f3\">ConsumerAddressModule_20150407.2</a> succeeded",
Markdown = "Build [ConsumerAddressModule_20150407.2](https://good-company.some.ssl.host/web/build.aspx?id=5023c10b-bef3-41c3-bf53-686c4e34ee9e&builduri=vstfs%3a%2f%2f%2fBuild%2fBuild%2f3) succeeded"
},
DetailedMessage = new PayloadMessage
{
Text = "Build ConsumerAddressModule_20150407.2 succeeded",
Html = "Build <a href=\"https://good-company.some.ssl.host/web/build.aspx?id=5023c10b-bef3-41c3-bf53-686c4e34ee9e&amp;builduri=vstfs%3a%2f%2f%2fBuild%2fBuild%2f3\">ConsumerAddressModule_20150407.2</a> succeeded",
Markdown = "Build [ConsumerAddressModule_20150407.2](https://good-company.some.ssl.host/web/build.aspx?id=5023c10b-bef3-41c3-bf53-686c4e34ee9e&builduri=vstfs%3a%2f%2f%2fBuild%2fBuild%2f3) succeeded"
},
Resource = new BuildCompletedResource
{
Uri = new Uri("vstfs:///Build/Build/2"),
Id = 2,
BuildNumber = "ConsumerAddressModule_20150407.1",
Url = new Uri("https://good-company.some.ssl.host/DefaultCollection/71777fbc-1cf2-4bd1-9540-128c1c71f766/_apis/build/Builds/2"),
StartTime = "2015-04-07T18:04:06.83Z".ToDateTime(),
FinishTime = "2015-04-07T18:06:10.69Z".ToDateTime(),
Reason = "manual",
Status = "succeeded",
DropLocation = "#/3/drop",
Drop = new BuildCompletedDrop
{
Location = "#/3/drop",
DropType = "container",
Url = new Uri("https://good-company.some.ssl.host/DefaultCollection/_apis/resources/Containers/3/drop"),
DownloadUrl = new Uri("https://good-company.some.ssl.host/DefaultCollection/_apis/resources/Containers/3/drop?api-version=1.0&$format=zip&downloadFileName=ConsumerAddressModule_20150407.1_drop")
},
Log = new BuildCompletedLog
{
LogType = "container",
Url = new Uri("https://good-company.some.ssl.host/DefaultCollection/_apis/resources/Containers/3/logs"),
DownloadUrl = new Uri("https://good-company.some.ssl.host/_apis/resources/Containers/3/logs?api-version=1.0&$format=zip&downloadFileName=ConsumerAddressModule_20150407.1_logs")
},
SourceGetVersion = "LG:refs/heads/master:600c52d2d5b655caa111abfd863e5a9bd304bb0e",
LastChangedBy = new ResourceUser
{
Id = "d6245f20-2af8-44f4-9451-8107cb2767db",
DisplayName = "John Smith",
UniqueName = "fabrikamfiber16@hotmail.com",
Url = new Uri("https://good-company.some.ssl.host/_apis/Identities/d6245f20-2af8-44f4-9451-8107cb2767db"),
ImageUrl = new Uri("https://good-company.some.ssl.host/DefaultCollection/_api/_common/identityImage?id=d6245f20-2af8-44f4-9451-8107cb2767db")
},
RetainIndefinitely = false,
HasDiagnostics = true,
Definition = new BuildCompletedDefinition
{
BatchSize = 1,
TriggerType = "none",
DefinitionType = "xaml",
Id = 2,
Name = "ConsumerAddressModule",
Url = new Uri("https://good-company.some.ssl.host/DefaultCollection/71777fbc-1cf2-4bd1-9540-128c1c71f766/_apis/build/Definitions/2")
},
Queue = new BuildCompletedQueueDefinition
{
QueueType = "buildController",
Id = 4,
Name = "Hosted Build Controller",
Url = new Uri("https://good-company.some.ssl.host/DefaultCollection/_apis/build/Queues/4")
}
},
ResourceVersion = "1.0",
ResourceContainers = new PayloadResourceContainers
{
Collection = new PayloadResourceContainer { Id = "c12d0eb8-e382-443b-9f9c-c52cba5014c2" },
Account = new PayloadResourceContainer { Id = "f844ec47-a9db-4511-8281-8b63f4eaf94e" },
Project = new PayloadResourceContainer { Id = "be9b3917-87e6-42a4-a549-2bc06a7a878f" }
},
CreatedDate = "2016-05-02T19:00:39.5893296Z".ToDateTime()
};
expected.Resource.Requests.Add(new BuildCompletedRequest
{
Id = 1,
Url = new Uri("https://good-company.some.ssl.host/DefaultCollection/71777fbc-1cf2-4bd1-9540-128c1c71f766/_apis/build/Requests/1"),
RequestedFor = new ResourceUser
{
Id = "d6245f20-2af8-44f4-9451-8107cb2767db",
DisplayName = "John Smith",
UniqueName = "fabrikamfiber16@hotmail.com",
Url = new Uri("https://good-company.some.ssl.host/_apis/Identities/d6245f20-2af8-44f4-9451-8107cb2767db"),
ImageUrl = new Uri("https://good-company.some.ssl.host/DefaultCollection/_api/_common/identityImage?id=d6245f20-2af8-44f4-9451-8107cb2767db")
}
});
// Act
var actual = data.ToObject<BuildCompletedPayload>();
// Assert
string expectedJson = JsonConvert.SerializeObject(expected);
string actualJson = JsonConvert.SerializeObject(actual);
Assert.Equal(expectedJson, actualJson);
}
}
}

Просмотреть файл

@ -0,0 +1,76 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.WebHooks.Payloads;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Xunit;
namespace Microsoft.AspNet.WebHooks
{
public class CodeCheckedInPayloadTests
{
[Fact]
public void CodeCheckedInPayload_Roundtrips()
{
// Arrange
JObject data = EmbeddedResource.ReadAsJObject("Microsoft.AspNet.WebHooks.Messages.tfvc.checkin.json");
var expected = new CodeCheckedInPayload
{
SubscriptionId = "00000000-0000-0000-0000-000000000000",
NotificationId = 2,
Id = "f9b4c23e-88dd-4516-b04d-849787304e32",
EventType = "tfvc.checkin",
PublisherId = "tfs",
Message = new PayloadMessage
{
Text = "John Smith checked in changeset 18: Dropping in new Java sample",
Html = "John Smith checked in changeset <a href=\"https://good-company.some.ssl.host/web/cs.aspx?id=d81542e4-cdfa-4333-b082-1ae2d6c3ad16&amp;cs=18\">18</a>: Dropping in new Java sample",
Markdown = "John Smith checked in changeset [18](https://good-company.some.ssl.host/web/cs.aspx?id=d81542e4-cdfa-4333-b082-1ae2d6c3ad16&cs=18): Dropping in new Java sample"
},
DetailedMessage = new PayloadMessage
{
Text = "John Smith checked in changeset 18: Dropping in new Java sample",
Html = "John Smith checked in changeset <a href=\"https://good-company.some.ssl.host/web/cs.aspx?id=d81542e4-cdfa-4333-b082-1ae2d6c3ad16&amp;cs=18\">18</a>: Dropping in new Java sample",
Markdown = "John Smith checked in changeset [18](https://good-company.some.ssl.host/web/cs.aspx?id=d81542e4-cdfa-4333-b082-1ae2d6c3ad16&cs=18): Dropping in new Java sample"
},
Resource = new CodeCheckedInResource
{
ChangesetId = 18,
Url = new Uri("https://good-company.some.ssl.host/DefaultCollection/_apis/tfvc/changesets/18"),
Author = new ResourceUser
{
Id = "d6245f20-2af8-44f4-9451-8107cb2767db",
DisplayName = "John Smith",
UniqueName = "fabrikamfiber16@hotmail.com"
},
CheckedInBy = new ResourceUser
{
Id = "d6245f20-2af8-44f4-9451-8107cb2767db",
DisplayName = "John Smith",
UniqueName = "fabrikamfiber16@hotmail.com"
},
CreatedDate = "2014-05-12T22:41:16Z".ToDateTime(),
Comment = "Dropping in new Java sample"
},
ResourceVersion = "1.0",
ResourceContainers = new PayloadResourceContainers
{
Collection = new PayloadResourceContainer { Id = "c12d0eb8-e382-443b-9f9c-c52cba5014c2" },
Account = new PayloadResourceContainer { Id = "f844ec47-a9db-4511-8281-8b63f4eaf94e" },
Project = new PayloadResourceContainer { Id = "be9b3917-87e6-42a4-a549-2bc06a7a878f" }
},
CreatedDate = "2016-05-02T19:01:11.7056821Z".ToDateTime()
};
// Act
var actual = data.ToObject<CodeCheckedInPayload>();
// Assert
string expectedJson = JsonConvert.SerializeObject(expected);
string actualJson = JsonConvert.SerializeObject(actual);
Assert.Equal(expectedJson, actualJson);
}
}
}

Просмотреть файл

@ -0,0 +1,70 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNet.WebHooks.Payloads;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Xunit;
namespace Microsoft.AspNet.WebHooks
{
public class TeamRoomMessagePostedPayloadTests
{
[Fact]
public void TeamRoomMessagePostedPayload_Roundtrips()
{
// Arrange
JObject data = EmbeddedResource.ReadAsJObject("Microsoft.AspNet.WebHooks.Messages.message.posted.json");
var expected = new TeamRoomMessagePostedPayload
{
SubscriptionId = "00000000-0000-0000-0000-000000000000",
NotificationId = 3,
Id = "daae438c-296b-4512-b08e-571910874e9b",
EventType = "message.posted",
PublisherId = "tfs",
Message = new PayloadMessage
{
Text = "Jamal Hartnett posted a message to Northward-Fiber-Git Team Room\r\nHello",
Html = "Jamal Hartnett posted a message to Northward-Fiber-Git Team Room\r\nHello",
Markdown = "Jamal Hartnett posted a message to Northward-Fiber-Git Team Room\r\nHello"
},
DetailedMessage = new PayloadMessage
{
Text = "Jamal Hartnett posted a message to Northward-Fiber-Git Team Room\r\nHello",
Html = "Jamal Hartnett posted a message to Northward-Fiber-Git Team Room<p>Hello</p>",
Markdown = "Jamal Hartnett posted a message to Northward-Fiber-Git Team Room\r\nHello"
},
Resource = new TeamRoomMessagePostedResource
{
Id = 0,
Content = "Hello",
MessageType = "normal",
PostedTime = "2014-05-02T19:17:13.3309587Z".ToDateTime(),
PostedRoomId = 1,
PostedBy = new ResourceUser
{
Id = "00067FFED5C7AF52@Live.com",
DisplayName = "Jamal Hartnett",
UniqueName = "Windows Live ID\\fabrikamfiber4@hotmail.com"
}
},
ResourceVersion = "1.0",
ResourceContainers = new PayloadResourceContainers
{
Collection = new PayloadResourceContainer { Id = "c12d0eb8-e382-443b-9f9c-c52cba5014c2" },
Account = new PayloadResourceContainer { Id = "f844ec47-a9db-4511-8281-8b63f4eaf94e" },
Project = new PayloadResourceContainer { Id = "be9b3917-87e6-42a4-a549-2bc06a7a878f" }
},
CreatedDate = "2016-05-02T19:13:40.8417653Z".ToDateTime()
};
// Act
var actual = data.ToObject<TeamRoomMessagePostedPayload>();
// Assert
string expectedJson = JsonConvert.SerializeObject(expected);
string actualJson = JsonConvert.SerializeObject(actual);
Assert.Equal(expectedJson, actualJson);
}
}
}

Просмотреть файл

@ -0,0 +1,88 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.WebHooks.Payloads;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Xunit;
namespace Microsoft.AspNet.WebHooks
{
public class WorkItemCommentedOnPayloadTests
{
[Fact]
public void WorkItemCommentedOnPayload_Roundtrips()
{
// Arrange
JObject data = EmbeddedResource.ReadAsJObject("Microsoft.AspNet.WebHooks.Messages.workitem.commented.json");
var expected = new WorkItemCommentedOnPayload
{
SubscriptionId = "00000000-0000-0000-0000-000000000000",
NotificationId = 4,
Id = "fb2617ed-60df-4518-81fa-749faa6c5cd6",
EventType = "workitem.commented",
PublisherId = "tfs",
Message = new PayloadMessage
{
Text = "Bug #5 (Some great new idea!) commented on by Jamal Hartnett.\r\n(http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5)",
Html = "<a href=\"http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&amp;id=5\">Bug #5</a> (Some great new idea!) commented on by Jamal Hartnett.",
Markdown = "[Bug #5](http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5) (Some great new idea!) commented on by Jamal Hartnett."
},
DetailedMessage = new PayloadMessage
{
Text = "Bug #5 (Some great new idea!) commented on by Jamal Hartnett.\r\n(http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5)\r\nThis is a great new idea",
Html = "<a href=\"http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&amp;id=5\">Bug #5</a> (Some great new idea!) commented on by Jamal Hartnett.<br/>This is a great new idea",
Markdown = "[Bug #5](http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5) (Some great new idea!) commented on by Jamal Hartnett.\r\nThis is a great new idea"
},
Resource = new WorkItemCommentedOnResource
{
Id = 5,
RevisionNumber = 4,
Fields = new WorkItemFields
{
SystemAreaPath = "GoodCompanyCloud",
SystemTeamProject = "GoodCompanyCloud",
SystemIterationPath = "GoodCompanyCloud\\Release 1\\Sprint 1",
SystemWorkItemType = "Bug",
SystemState = "New",
SystemReason = "New defect reported",
SystemCreatedDate = "2014-07-15T17:42:44.663Z".ToDateTime(),
SystemCreatedBy = "Jamal Hartnett",
SystemChangedDate = "2014-07-15T17:42:44.663Z".ToDateTime(),
SystemChangedBy = "Jamal Hartnett",
SystemTitle = "Some great new idea!",
MicrosoftCommonSeverity = "3 - Medium",
KanbanColumn = "New",
SystemHistory = "This is a great new idea"
},
Links = new WorkItemLinks
{
Self = new WorkItemLink { Href = "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5" },
WorkItemUpdates = new WorkItemLink { Href = "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5/updates" },
WorkItemRevisions = new WorkItemLink { Href = "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5/revisions" },
WorkItemType = new WorkItemLink { Href = "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/ea830882-2a3c-4095-a53f-972f9a376f6e/workItemTypes/Bug" },
Fields = new WorkItemLink { Href = "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/fields" }
},
Url = new Uri("http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5")
},
ResourceVersion = "1.0",
ResourceContainers = new PayloadResourceContainers
{
Collection = new PayloadResourceContainer { Id = "c12d0eb8-e382-443b-9f9c-c52cba5014c2" },
Account = new PayloadResourceContainer { Id = "f844ec47-a9db-4511-8281-8b63f4eaf94e" },
Project = new PayloadResourceContainer { Id = "be9b3917-87e6-42a4-a549-2bc06a7a878f" }
},
CreatedDate = "2016-05-02T19:15:37.4638247Z".ToDateTime()
};
// Act
var actual = data.ToObject<WorkItemCommentedOnPayload>();
// Assert
string expectedJson = JsonConvert.SerializeObject(expected);
string actualJson = JsonConvert.SerializeObject(actual);
Assert.Equal(expectedJson, actualJson);
}
}
}

Просмотреть файл

@ -0,0 +1,87 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.WebHooks.Payloads;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Xunit;
namespace Microsoft.AspNet.WebHooks
{
public class WorkItemCreatedPayloadTests
{
[Fact]
public void WorkItemCreatedPayload_Roundtrips()
{
// Arrange
JObject data = EmbeddedResource.ReadAsJObject("Microsoft.AspNet.WebHooks.Messages.workitem.created.json");
var expected = new WorkItemCreatedPayload
{
SubscriptionId = "00000000-0000-0000-0000-000000000000",
NotificationId = 5,
Id = "d2d46fb1-dba5-403c-9373-427583f19e8c",
EventType = "workitem.created",
PublisherId = "tfs",
Message = new PayloadMessage
{
Text = "Bug #5 (Some great new idea!) created by Jamal Hartnett.\r\n(http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5)",
Html = "<a href=\"http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&amp;id=5\">Bug #5</a> (Some great new idea!) created by Jamal Hartnett.",
Markdown = "[Bug #5](http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5) (Some great new idea!) created by Jamal Hartnett."
},
DetailedMessage = new PayloadMessage
{
Text = "Bug #5 (Some great new idea!) created by Jamal Hartnett.\r\n(http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5)\r\n\r\n- State: New\r\n- Assigned to: \r\n- Comment: \r\n- Severity: 3 - Medium\r\n",
Html = "<a href=\"http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&amp;id=5\">Bug #5</a> (Some great new idea!) created by Jamal Hartnett.<ul>\r\n<li>State: New</li>\r\n<li>Assigned to: </li>\r\n<li>Comment: </li>\r\n<li>Severity: 3 - Medium</li></ul>",
Markdown = "[Bug #5](http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5) (Some great new idea!) created by Jamal Hartnett.\r\n\r\n* State: New\r\n* Assigned to: \r\n* Comment: \r\n* Severity: 3 - Medium\r\n"
},
Resource = new WorkItemCreatedResource
{
Id = 5,
RevisionNumber = 1,
Fields = new WorkItemFields
{
SystemAreaPath = "GoodCompanyCloud",
SystemTeamProject = "GoodCompanyCloud",
SystemIterationPath = "GoodCompanyCloud\\Release 1\\Sprint 1",
SystemWorkItemType = "Bug",
SystemState = "New",
SystemReason = "New defect reported",
SystemCreatedDate = "2014-07-15T17:42:44.663Z".ToDateTime(),
SystemCreatedBy = "Jamal Hartnett",
SystemChangedDate = "2014-07-15T17:42:44.663Z".ToDateTime(),
SystemChangedBy = "Jamal Hartnett",
SystemTitle = "Some great new idea!",
MicrosoftCommonSeverity = "3 - Medium",
KanbanColumn = "New"
},
Links = new WorkItemLinks
{
Self = new WorkItemLink { Href = "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5" },
WorkItemUpdates = new WorkItemLink { Href = "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5/updates" },
WorkItemRevisions = new WorkItemLink { Href = "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5/revisions" },
WorkItemType = new WorkItemLink { Href = "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/ea830882-2a3c-4095-a53f-972f9a376f6e/workItemTypes/Bug" },
Fields = new WorkItemLink { Href = "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/fields" }
},
Url = new Uri("http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5")
},
ResourceVersion = "1.0",
ResourceContainers = new PayloadResourceContainers
{
Collection = new PayloadResourceContainer { Id = "c12d0eb8-e382-443b-9f9c-c52cba5014c2" },
Account = new PayloadResourceContainer { Id = "f844ec47-a9db-4511-8281-8b63f4eaf94e" },
Project = new PayloadResourceContainer { Id = "be9b3917-87e6-42a4-a549-2bc06a7a878f" }
},
CreatedDate = "2016-05-02T19:16:25.6251162Z".ToDateTime()
};
// Act
var actual = data.ToObject<WorkItemCreatedPayload>();
// Assert
string expectedJson = JsonConvert.SerializeObject(expected);
string actualJson = JsonConvert.SerializeObject(actual);
Assert.Equal(expectedJson, actualJson);
}
}
}

Просмотреть файл

@ -0,0 +1,85 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.WebHooks.Payloads;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Xunit;
namespace Microsoft.AspNet.WebHooks
{
public class WorkItemDeletedPayloadTests
{
[Fact]
public void WorkItemDeletedPayload_Roundtrips()
{
// Arrange
JObject data = EmbeddedResource.ReadAsJObject("Microsoft.AspNet.WebHooks.Messages.workitem.deleted.json");
var expected = new WorkItemDeletedPayload
{
SubscriptionId = "00000000-0000-0000-0000-000000000000",
NotificationId = 6,
Id = "72da0ade-0709-40ee-beb7-104287bf7e84",
EventType = "workitem.deleted",
PublisherId = "tfs",
Message = new PayloadMessage
{
Text = "Bug #5 (Some great new idea!) deleted by Jamal Hartnett.",
Html = "Bug #5 (Some great new idea!) deleted by Jamal Hartnett.",
Markdown = "[Bug #5] (Some great new idea!) deleted by Jamal Hartnett."
},
DetailedMessage = new PayloadMessage
{
Text = "Bug #5 (Some great new idea!) deleted by Jamal Hartnett.\r\n\r\n- State: New\r\n",
Html = "Bug #5 (Some great new idea!) deleted by Jamal Hartnett.<ul>\r\n<li>State: New</li></ul>",
Markdown = "[Bug #5] (Some great new idea!) deleted by Jamal Hartnett.\r\n\r\n* State: New\r\n"
},
Resource = new WorkItemDeletedResource
{
Id = 5,
RevisionNumber = 1,
Fields = new WorkItemFields
{
SystemAreaPath = "GoodCompanyCloud",
SystemTeamProject = "GoodCompanyCloud",
SystemIterationPath = "GoodCompanyCloud\\Release 1\\Sprint 1",
SystemWorkItemType = "Bug",
SystemState = "New",
SystemReason = "New defect reported",
SystemCreatedDate = "2014-07-15T17:42:44.663Z".ToDateTime(),
SystemCreatedBy = "Jamal Hartnett",
SystemChangedDate = "2014-07-15T17:42:44.663Z".ToDateTime(),
SystemChangedBy = "Jamal Hartnett",
SystemTitle = "Some great new idea!",
MicrosoftCommonSeverity = "3 - Medium",
KanbanColumn = "New"
},
Links = new WorkItemLinks
{
Self = new WorkItemLink { Href = "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/recyclebin/5" },
WorkItemType = new WorkItemLink { Href = "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/ea830882-2a3c-4095-a53f-972f9a376f6e/workItemTypes/Bug" },
Fields = new WorkItemLink { Href = "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/fields" }
},
Url = new Uri("http://good-company.some.ssl.host/DefaultCollection/_apis/wit/recyclebin/5")
},
ResourceVersion = "1.0",
ResourceContainers = new PayloadResourceContainers
{
Collection = new PayloadResourceContainer { Id = "c12d0eb8-e382-443b-9f9c-c52cba5014c2" },
Account = new PayloadResourceContainer { Id = "f844ec47-a9db-4511-8281-8b63f4eaf94e" },
Project = new PayloadResourceContainer { Id = "be9b3917-87e6-42a4-a549-2bc06a7a878f" }
},
CreatedDate = "2016-05-02T19:17:28.3644564Z".ToDateTime()
};
// Act
var actual = data.ToObject<WorkItemDeletedPayload>();
// Assert
string expectedJson = JsonConvert.SerializeObject(expected);
string actualJson = JsonConvert.SerializeObject(actual);
Assert.Equal(expectedJson, actualJson);
}
}
}

Просмотреть файл

@ -0,0 +1,89 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.WebHooks.Payloads;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Xunit;
namespace Microsoft.AspNet.WebHooks
{
public class WorkItemRestoredPayloadTests
{
[Fact]
public void WorkItemRestoredPayload_Roundtrips()
{
// Arrange
JObject data = EmbeddedResource.ReadAsJObject("Microsoft.AspNet.WebHooks.Messages.workitem.restored.json");
var expected = new WorkItemRestoredPayload
{
SubscriptionId = "00000000-0000-0000-0000-000000000000",
NotificationId = 7,
Id = "1ca023d6-6cff-49dd-b3d1-302b69311810",
EventType = "workitem.restored",
PublisherId = "tfs",
Message = new PayloadMessage
{
Text = "Bug #5 (Some great new idea!) restored by Jamal Hartnett.\r\n(http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5)",
Html = "<a href=\"http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&amp;id=5\">Bug #5</a> (Some great new idea!) restored by Jamal Hartnett.",
Markdown = "[Bug #5](http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5) (Some great new idea!) restored by Jamal Hartnett."
},
DetailedMessage = new PayloadMessage
{
Text = "Bug #5 (Some great new idea!) restored by Jamal Hartnett.\r\n(http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5)\r\n\r\n- State: New\r\n- Severity: 3 - Medium\r\n",
Html = "<a href=\"http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&amp;id=5\">Bug #5</a> (Some great new idea!) restored by Jamal Hartnett.<ul>\r\n<li>State: New</li>Severity: 3 - Medium</li></ul>",
Markdown = "[Bug #5](http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5) (Some great new idea!) restored by Jamal Hartnett.\r\n\r\n* State: New\r\n* Severity: 3 - Medium\r\n"
},
Resource = new WorkItemRestoredResource
{
Id = 5,
RevisionNumber = 1,
Fields = new WorkItemFields
{
SystemAreaPath = "GoodCompanyCloud",
SystemTeamProject = "GoodCompanyCloud",
SystemIterationPath = "GoodCompanyCloud\\Release 1\\Sprint 1",
SystemWorkItemType = "Bug",
SystemState = "New",
SystemReason = "New defect reported",
SystemCreatedDate = "2014-07-15T17:42:44.663Z".ToDateTime(),
SystemCreatedBy = "Jamal Hartnett",
SystemChangedDate = "2014-07-15T17:42:44.663Z".ToDateTime(),
SystemChangedBy = "Jamal Hartnett",
SystemTitle = "Some great new idea!",
MicrosoftCommonSeverity = "3 - Medium",
KanbanColumn = "New"
},
Links = new WorkItemLinks
{
Self = new WorkItemLink { Href = "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5" },
WorkItemUpdates = new WorkItemLink { Href = "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5/updates" },
WorkItemRevisions = new WorkItemLink { Href = "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5/revisions" },
WorkItemType = new WorkItemLink { Href = "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/ea830882-2a3c-4095-a53f-972f9a376f6e/workItemTypes/Bug" },
Fields = new WorkItemLink { Href = "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/fields" },
Html = new WorkItemLink { Href = "https://good-company.some.ssl.host/web/wi.aspx?id=d81542e4-cdfa-4333-b082-1ae2d6c3ad16&id=5" },
WorkItemHistory = new WorkItemLink { Href = "https://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5/history" }
},
Url = new Uri("http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5")
},
ResourceVersion = "1.0",
ResourceContainers = new PayloadResourceContainers
{
Collection = new PayloadResourceContainer { Id = "c12d0eb8-e382-443b-9f9c-c52cba5014c2" },
Account = new PayloadResourceContainer { Id = "f844ec47-a9db-4511-8281-8b63f4eaf94e" },
Project = new PayloadResourceContainer { Id = "be9b3917-87e6-42a4-a549-2bc06a7a878f" }
},
CreatedDate = "2016-05-02T19:18:15.5707279Z".ToDateTime()
};
// Act
var actual = data.ToObject<WorkItemRestoredPayload>();
// Assert
string expectedJson = JsonConvert.SerializeObject(expected);
string actualJson = JsonConvert.SerializeObject(actual);
Assert.Equal(expectedJson, actualJson);
}
}
}

Просмотреть файл

@ -0,0 +1,141 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.WebHooks.Payloads;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Xunit;
namespace Microsoft.AspNet.WebHooks
{
public class WorkItemUpdatedPayloadTests
{
[Fact]
public void WorkItemUpdatedPayload_Roundtrips()
{
// Arrange
JObject data = EmbeddedResource.ReadAsJObject("Microsoft.AspNet.WebHooks.Messages.workitem.updated.json");
var expected = new WorkItemUpdatedPayload
{
SubscriptionId = "00000000-0000-0000-0000-000000000000",
NotificationId = 8,
Id = "27646e0e-b520-4d2b-9411-bba7524947cd",
EventType = "workitem.updated",
PublisherId = "tfs",
Message = new PayloadMessage
{
Text = "Bug #5 (Some great new idea!) updated by Jamal Hartnett.\r\n(http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5)",
Html = "<a href=\"http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&amp;id=5\">Bug #5</a> (Some great new idea!) updated by Jamal Hartnett.",
Markdown = "[Bug #5](http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5) (Some great new idea!) updated by Jamal Hartnett."
},
DetailedMessage = new PayloadMessage
{
Text = "Bug #5 (Some great new idea!) updated by Jamal Hartnett.\r\n(http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5)\r\n\r\n- New State: Approved\r\n",
Html = "<a href=\"http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&amp;id=5\">Bug #5</a> (Some great new idea!) updated by Jamal Hartnett.<ul>\r\n<li>New State: Approved</li></ul>",
Markdown = "[Bug #5](http://good-company.some.ssl.host/web/wi.aspx?id=74e918bf-3376-436d-bd20-8e8c1287f465&id=5) (Some great new idea!) updated by Jamal Hartnett.\r\n\r\n* New State: Approved\r\n"
},
Resource = new WorkItemUpdatedResource
{
Id = 2,
WorkItemId = 0,
RevisionNumber = 2,
RevisedBy = null,
RevisedDate = "0001-01-01T00:00:00".ToDateTime(),
Fields = new WorkItemUpdatedFields
{
SystemRev = new WorkItemUpdatedFieldValue<string>
{
OldValue = "1",
NewValue = "2"
},
SystemAuthorizedDate = new WorkItemUpdatedFieldValue<DateTime>
{
OldValue = "2014-07-15T16:48:44.663Z".ToDateTime(),
NewValue = "2014-07-15T17:42:44.663Z".ToDateTime()
},
SystemRevisedDate = new WorkItemUpdatedFieldValue<DateTime>
{
OldValue = "2014-07-15T17:42:44.663Z".ToDateTime(),
NewValue = "9999-01-01T00:00:00Z".ToDateTime()
},
SystemState = new WorkItemUpdatedFieldValue<string>
{
OldValue = "New",
NewValue = "Approved"
},
SystemReason = new WorkItemUpdatedFieldValue<string>
{
OldValue = "New defect reported",
NewValue = "Approved by the Product Owner"
},
SystemAssignedTo = new WorkItemUpdatedFieldValue<string>
{
NewValue = "Jamal Hartnet"
},
SystemChangedDate = new WorkItemUpdatedFieldValue<DateTime>
{
OldValue = "2014-07-15T16:48:44.663Z".ToDateTime(),
NewValue = "2014-07-15T17:42:44.663Z".ToDateTime()
},
SystemWatermark = new WorkItemUpdatedFieldValue<string>
{
OldValue = "2",
NewValue = "5"
},
MicrosoftCommonSeverity = new WorkItemUpdatedFieldValue<string>
{
OldValue = "3 - Medium",
NewValue = "2 - High"
}
},
Links = new WorkItemLinks
{
Self = new WorkItemLink { Href = "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5/updates/2" },
Parent = new WorkItemLink { Href = "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5" },
WorkItemUpdates = new WorkItemLink { Href = "http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5/updates" }
},
Url = new Uri("http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5/updates/2"),
Revision = new WorkItemUpdatedRevision
{
Id = 5,
Rev = 2,
Fields = new WorkItemFields
{
SystemAreaPath = "GoodCompanyCloud",
SystemTeamProject = "GoodCompanyCloud",
SystemIterationPath = "GoodCompanyCloud\\Release 1\\Sprint 1",
SystemWorkItemType = "Bug",
SystemState = "New",
SystemReason = "New defect reported",
SystemCreatedDate = "2014-07-15T16:48:44.663Z".ToDateTime(),
SystemCreatedBy = "Jamal Hartnett",
SystemChangedDate = "2014-07-15T16:48:44.663Z".ToDateTime(),
SystemChangedBy = "Jamal Hartnett",
SystemTitle = "Some great new idea!",
MicrosoftCommonSeverity = "3 - Medium",
KanbanColumn = "New"
},
Url = new Uri("http://good-company.some.ssl.host/DefaultCollection/_apis/wit/workItems/5/revisions/2")
}
},
ResourceVersion = "1.0",
ResourceContainers = new PayloadResourceContainers
{
Collection = new PayloadResourceContainer { Id = "c12d0eb8-e382-443b-9f9c-c52cba5014c2" },
Account = new PayloadResourceContainer { Id = "f844ec47-a9db-4511-8281-8b63f4eaf94e" },
Project = new PayloadResourceContainer { Id = "be9b3917-87e6-42a4-a549-2bc06a7a878f" }
},
CreatedDate = "2016-05-02T19:19:12.8836446Z".ToDateTime()
};
// Act
var actual = data.ToObject<WorkItemUpdatedPayload>();
// Assert
string expectedJson = JsonConvert.SerializeObject(expected);
string actualJson = JsonConvert.SerializeObject(actual);
Assert.Equal(expectedJson, actualJson);
}
}
}

Просмотреть файл

@ -0,0 +1,8 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Runtime.InteropServices;
[assembly: CLSCompliant(false)]
[assembly: ComVisible(false)]

Просмотреть файл

@ -0,0 +1,203 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http;
using Moq;
using Moq.Protected;
using Xunit;
namespace Microsoft.AspNet.WebHooks
{
public class VstsWebHookReceiverTests : WebHookReceiverTestsBase<VstsWebHookReceiver>
{
private const string TestAction = "message.posted";
private const string TestId = "";
private const string TestSecret = "12345678901234567890123456789012";
private const string TestAddress = "https://some.ssl.host?code=" + TestSecret;
private HttpRequestMessage _postRequest;
public static TheoryData<string> InvalidCodeQueries
{
get
{
return new TheoryData<string>
{
string.Empty,
"=",
"==",
"invalid",
"code",
"code=",
"k1=v1;k2=v2",
};
}
}
[Fact]
public void ReceiverName_IsConsistent()
{
// Arrange
IWebHookReceiver rec = new VstsWebHookReceiver();
string expected = "vsts";
// Act
string actual1 = rec.Name;
string actual2 = VstsWebHookReceiver.ReceiverName;
// Assert
Assert.Equal(expected, actual1);
Assert.Equal(actual1, actual2);
}
[Fact]
public async Task ReceiveAsync_Throws_IfPostIsNotUsingHttps()
{
// Arrange
Initialize(TestSecret);
_postRequest.RequestUri = new Uri("http://some.no.ssl.host");
// Act
HttpResponseException ex = await Assert.ThrowsAsync<HttpResponseException>(() => ReceiverMock.Object.ReceiveAsync(TestId, RequestContext, _postRequest));
// Assert
HttpError error = await ex.Response.Content.ReadAsAsync<HttpError>();
Assert.Equal("The WebHook receiver 'VstsWebHookReceiverProxy' requires HTTPS in order to be secure. Please register a WebHook URI of type 'https'.", error.Message);
ReceiverMock.Protected()
.Verify<Task<HttpResponseMessage>>("ExecuteWebHookAsync", Times.Never(), TestId, RequestContext, _postRequest, ItExpr.IsAny<IEnumerable<string>>(), ItExpr.IsAny<object>());
}
[Theory]
[MemberData("InvalidCodeQueries")]
public async Task ReceiveAsync_Throws_IfPostHasNoCodeParameter(string query)
{
// Arrange
Initialize(TestSecret);
_postRequest.RequestUri = new Uri("https://some.no.ssl.host?" + query);
// Act
HttpResponseException ex = await Assert.ThrowsAsync<HttpResponseException>(() => ReceiverMock.Object.ReceiveAsync(TestId, RequestContext, _postRequest));
// Assert
HttpError error = await ex.Response.Content.ReadAsAsync<HttpError>();
Assert.Equal("The WebHook verification request must contain a 'code' query parameter.", error.Message);
ReceiverMock.Protected()
.Verify<Task<HttpResponseMessage>>("ExecuteWebHookAsync", Times.Never(), TestId, RequestContext, _postRequest, ItExpr.IsAny<IEnumerable<string>>(), ItExpr.IsAny<object>());
}
[Fact]
public async Task ReceiveAsync_Throws_IfPostHasWrongCodeParameter()
{
// Arrange
Initialize(TestSecret);
_postRequest.RequestUri = new Uri("https://some.no.ssl.host?code=invalid");
// Act
HttpResponseException ex = await Assert.ThrowsAsync<HttpResponseException>(() => ReceiverMock.Object.ReceiveAsync(TestId, RequestContext, _postRequest));
// Assert
HttpError error = await ex.Response.Content.ReadAsAsync<HttpError>();
Assert.Equal("The 'code' query parameter provided in the HTTP request did not match the expected value.", error.Message);
ReceiverMock.Protected()
.Verify<Task<HttpResponseMessage>>("ExecuteWebHookAsync", Times.Never(), TestId, RequestContext, _postRequest, ItExpr.IsAny<IEnumerable<string>>(), ItExpr.IsAny<object>());
}
[Theory]
[MemberData("ValidIdData")]
public async Task ReceiveAsync_Throws_IfPostIsNotJson(string id)
{
// Arrange
Initialize(GetConfigValue(id, TestSecret));
_postRequest.Content = new StringContent("Hello World!", Encoding.UTF8, "text/plain");
// Act
HttpResponseException ex = await Assert.ThrowsAsync<HttpResponseException>(() => ReceiverMock.Object.ReceiveAsync(id, RequestContext, _postRequest));
// Assert
HttpError error = await ex.Response.Content.ReadAsAsync<HttpError>();
Assert.Equal("The WebHook request must contain an entity body formatted as JSON.", error.Message);
ReceiverMock.Protected()
.Verify<Task<HttpResponseMessage>>("ExecuteWebHookAsync", Times.Never(), id, RequestContext, _postRequest, ItExpr.IsAny<IEnumerable<string>>(), ItExpr.IsAny<object>());
}
[Theory]
[MemberData("ValidIdData")]
public async Task ReceiveAsync_ReturnsError_IfPostHasNoEventTypeProperty(string id)
{
// Arrange
Initialize(GetConfigValue(id, TestSecret));
_postRequest.Content = CreateRequestContent("Microsoft.AspNet.WebHooks.Messages.bad.noEventType.json");
// Act
HttpResponseMessage actual = await ReceiverMock.Object.ReceiveAsync(id, RequestContext, _postRequest);
// Assert
HttpError error = await actual.Content.ReadAsAsync<HttpError>();
Assert.Equal("No property 'eventType' was found in root of the object.", error.Message);
ReceiverMock.Protected()
.Verify<Task<HttpResponseMessage>>("ExecuteWebHookAsync", Times.Never(), id, RequestContext, _postRequest, ItExpr.IsAny<IEnumerable<string>>(), ItExpr.IsAny<object>());
}
[Theory]
[MemberData("ValidIdData")]
public async Task ReceiveAsync_Succeeds_IfValidPostRequest(string id)
{
// Arrange
Initialize(GetConfigValue(id, TestSecret));
List<string> actions = new List<string> { TestAction };
ReceiverMock.Protected()
.Setup<Task<HttpResponseMessage>>("ExecuteWebHookAsync", id, RequestContext, _postRequest, actions, ItExpr.IsAny<object>())
.ReturnsAsync(new HttpResponseMessage())
.Verifiable();
// Act
await ReceiverMock.Object.ReceiveAsync(id, RequestContext, _postRequest);
// Assert
ReceiverMock.Verify();
}
[Theory]
[InlineData("GET")]
[InlineData("HEAD")]
[InlineData("PATCH")]
[InlineData("PUT")]
[InlineData("OPTIONS")]
public async Task ReceiveAsync_ReturnsError_IfInvalidMethod(string method)
{
// Arrange
Initialize(TestSecret);
HttpRequestMessage req = new HttpRequestMessage { Method = new HttpMethod(method) };
req.SetRequestContext(RequestContext);
// Act
HttpResponseMessage actual = await ReceiverMock.Object.ReceiveAsync(TestId, RequestContext, req);
// Assert
Assert.Equal(HttpStatusCode.MethodNotAllowed, actual.StatusCode);
ReceiverMock.Protected()
.Verify<Task<HttpResponseMessage>>("ExecuteWebHookAsync", Times.Never(), TestId, RequestContext, req, ItExpr.IsAny<IEnumerable<string>>(), ItExpr.IsAny<object>());
}
public override void Initialize(string config)
{
base.Initialize(config);
HttpConfig.InitializeReceiveVstsWebHooks();
_postRequest = new HttpRequestMessage(HttpMethod.Post, TestAddress);
_postRequest.SetRequestContext(RequestContext);
_postRequest.Content = CreateRequestContent("Microsoft.AspNet.WebHooks.Messages.message.posted.json");
}
private HttpContent CreateRequestContent(string payload)
{
string content = EmbeddedResource.ReadAsString(payload);
return new StringContent(content, Encoding.UTF8, "application/json");
}
}
}

Просмотреть файл

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.2" targetFramework="net45" />
<package id="Microsoft.AspNet.WebApi.Core" version="5.2.2" targetFramework="net45" />
<package id="Moq" version="4.2.1502.0911" targetFramework="net45" />
<package id="Newtonsoft.Json" version="6.0.4" targetFramework="net45" />
<package id="StyleCop.MSBuild" version="4.7.49.1" targetFramework="net45" developmentDependency="true" />
<package id="xunit" version="2.0.0" targetFramework="net45" />
<package id="xunit.abstractions" version="2.0.0" targetFramework="net45" />
<package id="xunit.assert" version="2.0.0" targetFramework="net45" />
<package id="xunit.core" version="2.0.0" targetFramework="net45" />
<package id="xunit.extensibility.core" version="2.0.0" targetFramework="net45" />
<package id="xunit.runner.visualstudio" version="2.0.1" targetFramework="net45" />
</packages>

Просмотреть файл

@ -24,6 +24,7 @@
<assembly name="Microsoft.AspNet.WebHooks.Receivers.Slack"/>
<assembly name="Microsoft.AspNet.WebHooks.Receivers.Stripe"/>
<assembly name="Microsoft.AspNet.WebHooks.Receivers.Trello"/>
<assembly name="Microsoft.AspNet.WebHooks.Receivers.VSTS"/>
<assembly name="Microsoft.AspNet.WebHooks.Receivers.WordPress"/>
<assembly name="Microsoft.AspNet.WebHooks.Receivers.Zendesk"/>
@ -51,6 +52,7 @@
<assembly name="Microsoft.AspNet.WebHooks.Receivers.Stripe.Test"/>
<assembly name="Microsoft.AspNet.WebHooks.Receivers.Test"/>
<assembly name="Microsoft.AspNet.WebHooks.Receivers.Trello.Test"/>
<assembly name="Microsoft.AspNet.WebHooks.Receivers.VSTS.Test"/>
<assembly name="Microsoft.AspNet.WebHooks.Receivers.WordPress.Test"/>
<assembly name="Microsoft.AspNet.WebHooks.Receivers.Zendesk.Test"/>
<assembly name="Microsoft.TestUtilities"/>