TypeScript Unit-Testing on VSTS with Continuous Integration in a C# Web Application - node.js

I have a web application with continuous integration via visual studio team services and I want to add unit tests for my typescript code.
First try
At first I tried to create a Blank Node.js Console Application in my solution. I wrote some tests (with 'mocha',etc...) which worked fine locally. But as I commited the solution I noticed the build server not being able to...well...build:
Error : web.config not found in project, to create a project to deploy to Microsoft Azure you must create an Azure Node.js project.
This message suggested that msbuild wanted to create a deployable package of my NodeJS Project even though I only used it for testing purposes. The first thing that came to mind was to add a minimal web.config even though I did not want to publish the NodeJS project:
Error MSB4062: The "TypeScript.Tasks.FormatLocalizedString" task could not be loaded from the assembly C:\xxx\Microsoft.TypeScript.MSBuild.2.3.3\build\\..\tools\net45\TypeScript.Tasks.dll. Confirm that the <UsingTask> declaration is correct, that the assembly and all its dependencies are available, and that the task contains a public class that implements Microsoft.Build.Framework.ITask.
I don't really see any way out of this...
Second try
Then I tried to use a UnitTest Project instead of the NodeJS Project. Surely this will work, or so I thought. With this approach I ran into the problem that VS Test did not recognize my Unit Tests (which worked fine on my NodeJS project) as there was no option to mark my files with the appropriate "Test Framework" attribute which was present on the file properties in the NodeJS Project. Instead there were the default file options for "Custom Tool", etc:
No Problem! I'll just adjust the .csproj file directly!
<TypeScriptCompile Include="main.test.ts">
<SubType>Code</SubType>
<TestFramework>Mocha</TestFramework>
<Publish>False</Publish>
</TypeScriptCompile>
But, alas, no dice...The Tests still could not be found by VS Test
Question
What is the best practices approach here? Is there something I'm not thinking of? Was the 'First try' correct and I just did not find the correct option to disable the publishing of my NodeJS App?
PS
I now think my first approach was the correct one. Just to be clear: A lot of things already worked:
Installed Node Tools for Visual Studio on the Build Server
Compiling typescript via VSTS
Running Tests in VS Test locally
List item
Running npm install on build (in VSTS)
Now all I need is for the build to go through :/
I now notice that I did not write the full error message for the last error in the first approach:
##[error]C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\TypeScript\Microsoft.TypeScript.targets(60,5): Error MSB4062: The "TypeScript.Tasks.FormatLocalizedString" task could not be loaded from the assembly C:\Agent-PaketBuildIntern1\_work\54\s\packages\Microsoft.TypeScript.MSBuild.2.3.3\build\\..\tools\net45\TypeScript.Tasks.dll. Confirm that the <UsingTask> declaration is correct, that the assembly and all its dependencies are available, and that the task contains a public class that implements Microsoft.Build.Framework.ITask.
So we see here that it uses the .targets file under C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\TypeScript\ and not the one under ......\packages\Microsoft.TypeScript.MSBuild.2.3.3\tools
Could this be the problem? How do I go about correcting that?
.njsproj file:
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<VisualStudioVersion>14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<Name>MyProjectName</Name>
<RootNamespace>MyProjectName</RootNamespace>
<SccProjectName>SAK</SccProjectName>
<SccProvider>SAK</SccProvider>
<SccAuxPath>SAK</SccAuxPath>
<SccLocalPath>SAK</SccLocalPath>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>5697a590-d15f-401b-b8d8-138bbd5d3330</ProjectGuid>
<ProjectHome>.</ProjectHome>
<StartupFile>
</StartupFile>
<StartWebBrowser>False</StartWebBrowser>
<SearchPath>
</SearchPath>
<WorkingDirectory>.</WorkingDirectory>
<OutputPath>.</OutputPath>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<ProjectTypeGuids>{3AF33F2E-1136-4D97-BBB7-1795711AC8B8};{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}</ProjectTypeGuids>
<TypeScriptSourceMap>true</TypeScriptSourceMap>
<TypeScriptModuleKind>CommonJS</TypeScriptModuleKind>
<EnableTypeScript>true</EnableTypeScript>
<StartWebBrowser>false</StartWebBrowser>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<Content Include="tsconfig.json">
<SubType>Code</SubType>
</Content>
<Content Include="package.json" />
<Content Include="README.md" />
<Content Include="Web.config" />
<TypeScriptCompile Include="Scripts\typings\node\node.d.ts" />
<TypeScriptCompile Include="bootstrap.test.ts">
<SubType>Code</SubType>
<TestFramework>Mocha</TestFramework>
<Publish>False</Publish>
</TypeScriptCompile>
<TypeScriptCompile Include="util\templates.ts">
<SubType>Code</SubType>
</TypeScriptCompile>
</ItemGroup>
<ItemGroup>
<Folder Include="util\" />
<Folder Include="Scripts\" />
<Folder Include="Scripts\typings\" />
<Folder Include="Scripts\typings\node\" />
</ItemGroup>
<PropertyGroup>
<PreBuildEvent>cd $(ProjectDir)
call npm install
</PreBuildEvent>
</PropertyGroup>
<Import Project="..\..\..\packages\Microsoft.TypeScript.MSBuild.2.3.3\build\Microsoft.TypeScript.MSBuild.targets" Condition="Exists('..\..\..\packages\Microsoft.TypeScript.MSBuild.2.3.3\build\Microsoft.TypeScript.MSBuild.targets')" />
<Import Project="$(VSToolsPath)\Node.js Tools\Microsoft.NodejsTools.targets" />
</Project>

Refer to these steps (vs2015):
Create a new Node.js Console Application
Update package.json dependencies and scripts like this
:
{
"name": "nodejs-console-app-demo",
"version": "0.0.0",
"description": "NodejsConsoleAppDemo",
"main": "app.js",
"author": {
"name": "XXX",
"email": ""
},
"dependencies": {
"#types/mocha": "^2.2.41",
"assert": "^1.4.1",
"mocha": "^3.4.2",
"typescript": "^2.4.1"
},
"scripts": {
"tsc": "tsc"
}
}
Right click the project/folder >Add> New Item> Select TypeScript Mocha UnitTest file
Add your test code
Add a folder to your project (e.g. ntvs)
Copy 1.1 folder in C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\Extensions\Microsoft\Node.js Tools for Visual Studio to that ntvs folder
Right click your project > Add > New Item> Select Json template> add a new json file to project > Rename it to tsconfig.json
:
{
"compilerOptions": {
"noImplicitAny": false,
"noEmitOnError": true,
"removeComments": false,
"sourceMap": true,
"target": "ES6",
"module": "commonjs",
"moduleResolution": "node",
"watch": false
},
"exclude": [
"node_modules"
],
"include": [
"src/**/*",
"test/**/*"
]
}
Right click your project > Unload project
Right click your project > Edit [projectname].njsproj
Change <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion> to <VisualStudioVersion>14.0</VisualStudioVersion>
Save all changes and add files to source control (by default .dll files will be ignored, so make sure all files in ntvs folder have been added to source control, you can right click ntvs folder > add files to source control)
Create a build definition
Npm install task (Command: install; Working folder: [package.json file path, such as $(Build.SourcesDirectory)\NodejsConsoleAppDemo]
Npm install task (Command: custom; Working folder: [tsconfig.json file path, such as $(Build.SourcesDirectory)\NodejsConsoleAppDemo]; Command and arguments: run tsc)
Visual Studio Test task (Test assemblies: [project file path, such as NodejsConsoleAppDemo\NodejsConsoleAppDemo.njsproj; Search folder: $(System.DefaultWorkingDirectory); Test platform version: Visual Studio 2015; Path to custom test adapters: [ntvs folder path, such as NodejsConsoleAppDemo/ntvs]]
Queue build with Hosted agent
There is an article that can help you: nodejstools.
If you are using VS 2017, you can refer to this thread: Running node.js tests locally in vstest.console.exe gives … Error: An exception occurred while invoking executor 'executor://nodejstestexecutor/v1.

After several attempts to make this work I decided to solve the problem at hand by putting the Mocha tests inside the Web Application Project and running them via npm (in the build steps). Inside the CI build definition I published the result of these tests via mocha-junit-reporter (https://www.npmjs.com/package/mocha-junit-reporter - see this answer for details).
This works for my requirements, although I would have liked to have the unit tests in a seperate project.

Related

Visual Studio Online - DevOps

Current client we are setting up CI/CD using VSO => Azure devops and I need some help with the configuration of the releases in the environments. Here's the situation and issue.
I've got the builds all set up and working properly.
I've got 2 Environments set up in the release configuration. Artifact is set up for the drops. Dev environment is set up as well as QA.
In VS2015 I've got the web.config transforms and configurations set up for Debug, Dev, QA, and Release. Dev/QA/Release each have a transformation that is to be applied for their respective enviornment.
Build triggers upon checkin and the release deployment triggers correctly upon successful build.
Dev environment and QA environment both trigger correctly in the release and are released accordingly.
In the task configuration for each I've got the XML Transformation selected as well as the correct deployment slot. The issue is that the only web.config transformation that is being applied is the release transformation not the correct transformation for the respective environment.
I have 4 transformation configs in the environment set up.
web.config
web.Debug.config
web.Dev.config
web.QA.config
web.Release.config
in VSO I have 2 environments set up in the Release Package
Dev & QA
In each of the environment I have the XML Transformation check which the tooltip states that it will apply the web.Release.config and each respective environment config.
The later is not happening.
logs:
the logs state:
Unable to apply transformation for the given package. Verify the following.

1. Whether the Transformation is already applied for the MSBuild generated package during build. If yes, remove the tag for each config in the csproj file and rebuild.

2. Ensure that the config file and transformation files are present in the same folder inside the package.
Both of those states have been confirmed. I've got the transform configs set to copy if newer.
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.8\build\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props" Condition="Exists('..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.8\build\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props')" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.Default.props" Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.Default.props')" />
<Import Project="..\packages\Microsoft.Net.Compilers.2.4.0\build\Microsoft.Net.Compilers.props" Condition="Exists('..\packages\Microsoft.Net.Compilers.2.4.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>{88941EE6-99FC-4DE5-8FE3-9F532FD855F2}</ProjectGuid>
<ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>TripManager</RootNamespace>
<AssemblyName>TripManager</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<MvcBuildViews>false</MvcBuildViews>
<UseIISExpress>true</UseIISExpress>
<IISExpressSSLPort>44385</IISExpressSSLPort>
<IISExpressAnonymousAuthentication>disabled</IISExpressAnonymousAuthentication>
<IISExpressWindowsAuthentication>enabled</IISExpressWindowsAuthentication>
<IISExpressUseClassicPipelineMode />
<UseGlobalApplicationHostFile />
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
<SccProjectName>SAK</SccProjectName>
<SccLocalPath>SAK</SccLocalPath>
<SccAuxPath>SAK</SccAuxPath>
<SccProvider>SAK</SccProvider>
<TargetFrameworkProfile />
<Use64BitIISExpress />
<TypeScriptToolsVersion>1.8</TypeScriptToolsVersion>
<ApplicationInsightsResourceId>/subscriptions/ee4492d7-5913-4e7b-85c0-3915e8c6c5c2/resourcegroups/rg-TripTracker-dev-SC/providers/microsoft.insights/components/TripManager</ApplicationInsightsResourceId>
<WebProject_DirectoryAccessLevelKey>1</WebProject_DirectoryAccessLevelKey>
</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>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Dev|AnyCPU'">
<OutputPath>bin\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'QA|AnyCPU'">
<OutputPath>bin\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
</Project>
The problem is that config transform files are not included in the build result.
Ensure that the config file and transformation files are present in
the same folder inside the package.
Marina Liu's answer could work, but there is a much simpler way to achieve this:
The transform file should not be Dependent upon web.config. Just create a new file in the same directory as the web.config file.
Set the Build Action of the transform file to Content.
Or just change the entry in the .csproj file from this:
<None Include="Web.QA.config">
<DependentUpon>Web.config</DependentUpon>
</None>
To this:
<Content Include="Web.QA.config" />
This makes sure the files are included in the package after build.
No matter whether the transformation is applied for the MSBuild generated package or not, add the config files to the zipped package (as option 2 in release log suggests: Ensure that the config file and transformation files are present in the same folder inside the package) should work.
So you can add the config files in your build definition before the artifacts published. Detail steps as below:
After Visual Studio Build task (and before Publish Build Artifacts) and the following tasks to extract the zip file and add config files in the extract folder, then zip the files again:
1. Extract files task
Archive file patterns: $(Build.ArtifactStagingDirectory)\*.zip
Destination folder: specify the folder for the extract files, such as $(Build.ArtifactStagingDirectory)\test
2. Copy Files task
Source Folder: $(Build.SourcesDirectory)
Contents: **\*.config
Target Folder: Folder for the extract files, such as $(Build.ArtifactStagingDirectory)\test
3. Delete Files task
Source Folder: $(Build.ArtifactStagingDirectory)
Contents: *.zip (delete the zip file which generated by Visual Studio Build task)
4. Archive Files task
Root folder (or file) to archive: Folder for the extract files, such as $(Build.ArtifactStagingDirectory)\test
Archive type: zip
Archive file to create: such as $(Build.ArtifactStagingDirectory)\package.zip
5. Delete Files task
Source Folder: $(Build.ArtifactStagingDirectory)
Contents: delete the extract folder,such as test
Then the package will be deployed to Azure App Service successful in release.

Deploy Function App .csproj from Github

I have a function app project in multi project visual studio solution. I have an ARM template set up with GitHub as the source:
"properties": {
"RepoUrl": "[parameters('funcapp_reponame')]",
"branch": "[parameters('funcapp_branch')]",
"IsManualIntegration": true,
}
I have also added the following to deploy from the function app project:
"siteConfig": {
"appSettings": [
{
"name": "Project",
"value": "ProjectName"
}]
},
The template successfully creates the Function app resource, but not the functions. Looking at the deployment error log in the Azure portal I get:
'D:\home\site\repository\ProjectName\ProjectName.csproj' is not a deployable project
Looking at the files copied to Azure via FTP I can see that the full solution has been copied over and the deployment process looks to be selecting the correct folder. Is the presence of the .csproj causing the issue? The various example ARM templates for deploying functions on github don't appear to use visual studio projects.
In your Function App's csproj, you have:
<ItemGroup>
<PackageReference Include="Microsoft.Azure.WebJobs" Version="2.1.0-beta1" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Http" Version="1.0.0-beta1" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="1.0.0-alpha6" />
</ItemGroup>
So it's referencing a very old Microsoft.NET.Sdk.Functions package. In your project, go to Manage NuGet Packages, and update to the latest, which right now is 1.0.7. Also, make sure to install any relevant VS updates under Tools / Extension and Updates.

Azure web role deploy does not copy non-project files

We are trying to deploy an AngularJs website to azure that is build with gulp. So we develop in a source application and gulp copies the files to the dist project. The dist project is a Azure cloud source Web Role. The "compiled" files are inside of the project folder, though for some reason they are not copied.
We turned on the option Properties -> Package/Publich Web -> All files in this project folder
After deploying I only see the packes.config, web.config and bin folder. Is there anything we need to do to get the rest of the files deployed?
Yep, gulp generated files are not actually part of the project (included in the xx.csproj file) which is why "All files..." does not work. We accomplish this by adding some custom targets for build to the project file - our gulp files are in a folder called "dist".
Unload Project >> Edit... then include something like:
<Target Name="CustomCollectFiles">
<ItemGroup>
<_DistFiles Include="dist\**\*" />
<FilesForPackagingFromProject Include="%(_DistFiles.Identity)">
<DestinationRelativePath>dist\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
<_SrcFiles Include="src\**\*" />
<FilesForPackagingFromProject Include="%(_SrcFiles.Identity)">
<DestinationRelativePath>src\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
<PropertyGroup>
<TypeScriptModuleKind>AMD</TypeScriptModuleKind>
<CopyAllFilesToSingleFolderForPackageDependsOn>
CustomCollectFiles;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForPackageDependsOn>
<CopyAllFilesToSingleFolderForMsdeployDependsOn>
CustomCollectFiles;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForMsdeployDependsOn>
</PropertyGroup>
.
.
.
<Target Name="AfterBuild" DependsOnTargets="CustomCollectFiles">
<Copy SourceFiles="#(_DistFiles)" DestinationFolder="dist" />
</Target>

Include files in MSBuild that are not part of project

I'm trying to create an automated build for my web application project.
We use a standard CMS project and have tweaked some parts of it. Only the tweaked files are part of our project, but I want to include the full CMS in the deployment package.
So I've created a custom .targets file to define a task to include the CMS files during the build:
<Target Name="GetCMSFiles">
<ItemGroup>
<!-- Include the CMS files into the package -->
<_CMSFiles Include="..\packages\CMSFiles\**\*" />
<FilesForPackagingFromProject Include="%(_CMSFiles.Identity)">
<DestinationRelativePath>
%(RecursiveDir)%(Filename)%(Extension)
</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
<!-- VS2010 -->
<CopyAllFilesToSingleFolderForPackageDependsOn>
GetCMSFiles;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForPackageDependsOn>
<!-- VS2012 -->
<CopyAllFilesToSingleFolderForMsdeployDependsOn>
GetCMSFiles;
$(CopyAllFilesToSingleFolderForMsdeployDependsOn);
</CopyAllFilesToSingleFolderForMsdeployDependsOn>
</PropertyGroup>
This works fine, but the problem is that the files from our project do not get copied to the deployment folder. So in other words, it does not overwrite the files that already exist after I copied them with the GetCMSFiles task.
The way I see it there are two options:
Force the CopyAllFilesToSingleFolder to overwrite any existing files in the deployment folder.
Have a condition in the GetCMSFiles task to only include files that don't already exist in the project.
But I'm not sure whether this is possible and how to achieve this. Any ideas?

MSBuild & SQL Server Database Project: bind the deploy and publish desination to the build configuration

Visual Studio 2012. SQL Server Database Project.
Four build configurations were created in solution: Debug, DevDb, TestDb, LocalDb.
Three publish profiles were created in project: DevDb.publish.xml, TestDb.publish.xml, LocalDb.publish.xml
Pushing F5 button (!) I want to:
deploy project with connection string from project properties if
build configuration is Debug.
publish project with connection string
from the corresponding publish profiles if build configuration is
DevDb, TestDb or LocalDb.
To do this I edit project (.sqlproj) xml, trying to catch a call of the Deploy target and replace the standart Deploy target with a custom behavior:
<Target Name="Deploy">
<!-- The first statment is for Debug configuration -->
<MSBuild Condition=" '$(Configuration)' == 'Debug' "
Targets="Deploy"
Projects="$(MSBuildProjectFile)"
Properties="Configuration=$(Configuration);"
/>
<!-- The second statement is for DevDb, TestDb, LocalDb configurations -->
<MSBuild Condition=" '$(Configuration)' != 'Debug' "
Targets="SqlPublish"
Projects="$(MSBuildProjectFile)"
Properties="SqlPublishProfilePath=$(Configuration).publish.xml;
Configuration=$(Configuration);"
/>
</Target>
The second statement works fine and I get deployment to the right destination.
The problem is with the first statement - it produces a circular dependency.
error MSB4006: There is a circular dependency in the target dependency graph involving target "Deploy".
My question is: how to intersect (catch and replace) the standart target and if it's required to invoke the standart target again?
Or am I trying to reinvent the wheel and there is another way to do what I want?
(What I want is described above under words "Pushing F5 button" :)
I think I've got the solution.
So if we put such a PropertyGroup with Condition and a custom Target to the end of database project xml file:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
----------- Skip -----------
<PropertyGroup Condition=" '$(Configuration)' != 'Debug' and Exists('$(Configuration).publish.xml')">
<DeployDependsOn>
PublishDatabase
</DeployDependsOn>
</PropertyGroup>
<Target Name="PublishDatabase"> <!-- Custom Target -->
<Message
Text="Deploy is replaced with SqlPublish for configuration = $(Configuration)"
Importance="high" />
<MSBuild
Targets="SqlPublish"
Projects="$(MSBuildProjectFile)"
Properties="SqlPublishProfilePath=$(Configuration).publish.xml;
Configuration=$(Configuration);" />
</Target>
</Project>
we will get the following behaviour:
If the solution build configuration is differ from Debug and the publish profile *.publish.xml exists, then the Deploy target and
operation will be replaced with SqlPublish target and this publish
operation will get the required configuration such as connection
string from the corresponding publish profile.
If the solution build configuration is Debug, then we preserve the standart Visual Studio behaviour when it take th connection string from the project properties.

Resources