Copying files into the source code before building a deploy package with MsBuild on TFS - visual-studio

I'm using TFS as a build server to use MsBuild for building and packaging a solution into a web deploy-package.
MSBuild Arguments: /p:CreatePackageOnPublish=true /p:DeployOnBuild=true /p:DeployTarget=Package
Now I want to copy a couple of files into the source-files before building the package, so they will end up in the App_Data-directory when deployed to IIS. I was thinking of doing it as part of the TFS-build, and have created an InvokeProcess-action which calls xcopy and copies the files into the SourcesDirectory, however they don't appear in the built zip-package.
Into what directory should I copy the files, and where in the build-process?
Are there a better way to do this? I was thinking of a Post Build-event in the project-file, however I only want this to be run by specific TFS-build, and not for all builds.

I deploy specific js versionned files with this hook in my project file :
<!--Hook to deploy add files -->
<PropertyGroup>
<CollectFilesFromContentDependsOn>
AddFilesToDeploy;
$(CollectFilesFromContentDependsOn);
</CollectFilesFromContentDependsOn>
</PropertyGroup>
<!--Add files to deploy -->
<Target Name="AddFilesToDeploy">
<GetAssemblyIdentity AssemblyFiles="$(TargetPath)">
<Output TaskParameter="Assemblies" ItemName="CurrentAssembly" />
</GetAssemblyIdentity>
<ItemGroup>
<JsFile Include="script\myApp.min-%(CurrentAssembly.Version).js" />
<FilesForPackagingFromProject Include="%(JsFile.Identity)">
<DestinationRelativePath>%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
If i remember, this doesn't work for a tfs build because CollectFilesFromContent is not executed in this process, so i have copied the files in a post build event:
if not '$(TeamFoundationServerUrl)' == '' (
xcopy "$(ProjectDir)script\myApp.min-#(VersionNumber).js" "$(OutDir)_PublishedWebsites\$(MSBuildProjectName)\script"
)

Related

How to build project in multiple configurations to automate the build process?

I have a solution, which contains a native project. For the main project to properly work, the following steps should be taken:
The native project has to be built in Release/x86 configuration
The native project has to be built in Release/x64 configuration
All .NET projects have to be built
Both binaries from steps 1 and 2 have to be placed in the main project's output folder.
Is there a way to configure project, so that all of those steps happen upon simply choosing "Build | Rebuild all"? I know of the batch build option, but I'd still have to execute step 4 manually.
I think you have to use msbuild script to build your project rather than VS IDE. Scripts are more flexible and can realize your requirements.
1) create a new file called build.proj and then add these on that file:
<Project>
<ItemGroup>
<!--include all c# csproj files to build these projects all at once-->
<NetProjectFile Include="**\*.csproj" />
<!--include the c++ proj files-->
<NativeProjectFile Include="**\*.vcxproj" />
</ItemGroup>
<Target Name="Build">
<MSBuild Projects="#(NetProjectFile)" Targets="Restore;Build" Properties="Configuration=Debug;Platform=AnyCPU"/>
<!--OutDir is the path of the execute file ,pdb.... if you also want the intermediate files to be in the same folder, you should also use IntDir -->
<MSBuild Projects="#(NativeProjectFile)" Targets="Build" Properties="Configuration=Release;Platform=x86;OutDir=xxx\xxx\"/>
<MSBuild Projects="#(NativeProjectFile)" Targets="Build" Properties="Configuration=Release;Platform=x64;OutDir=xxx\xxx\"/>
</Target>
</Project>
3) Just run msbuild build.proj -t:Build to get what you want.

Adding umbraco folders to build with MsBuild

If I use msbuild to build my project, all the folders not included in my solution are not deployed. Is there a way of deploying the umbraco and umbraco_client folders using msbuild?
I have tried using Targets like:
https://gist.github.com/aaronpowell/6695293
How can we include the files created by ajaxmin in the msdeploy package created by MSBuild
https://blog.samstephens.co.nz/2010/10/18/msbuild-including-extra-files-multiple-builds/
But hey are not being copied to the output folder. Am I missing anything?
You can use a msbuild target(run after the build ends) in which it calls the msbuild copy task to copy necessary files or folders to output folder. Use AfterTargets="build" to let the target run after the build.
A target script which works in my machine looks like this:
<Target Name="Copyumbraco" AfterTargets="build">
<ItemGroup>
<UmbracoFiles Include="$(ProjectDir)**\umbraco\**\*" />
<Umbraco_ClientFiles Include="$(ProjectDir)**\umbraco_client\**\*" />
</ItemGroup>
<Copy SourceFiles="#(UmbracoFiles)" DestinationFolder="$(OutputPath)\%(RecursiveDir)"/>
<Copy SourceFiles="#(Umbraco_ClientFiles)" DestinationFolder="$(OutputPath)\%(RecursiveDir)"/>
</Target>
Using $(ProjectDir) property to define the path, so Msbuild can find those two folders if they are in project folder as you mentioned in comment.
The \%(RecursiveDir) set the msbuild copy task to copy the files to destination path with original folder structure. If what you want to just copy all files to Output folder, you don't need to set it, then the script should be:
<Target Name="Copyumbraco" AfterTargets="build">
<ItemGroup>
<UmbracoFiles Include="$(ProjectDir)**\umbraco\**\*" />
<Umbraco_ClientFiles Include="$(ProjectDir)**\umbraco_client\**\*" />
</ItemGroup>
<Copy SourceFiles="#(UmbracoFiles)" DestinationFolder="$(OutputPath)"/>
<Copy SourceFiles="#(Umbraco_ClientFiles)" DestinationFolder="$(OutputPath)"/>
</Target>
Add the target script into the your project's project file(xx.csproj), make sure you place the script in the format below, then it can work when you use msbuild to build the project.
<Project Sdk="Microsoft.NET.Sdk.Web">
...
<Target Name="Copyumbraco" AfterTargets="build">
...
</Target>
</Project>
In addition:
For normal projects like console app, class library, the $(OutputPath) represents the output path. But for web site project, we can use $(WebProjectOutputDir) , hint from Mario!

Visual Studio Publish - Include folder that is not added to Project

Using - VS2013, VS2015, .Net 4.5
I have several Asp.Net projects each of which has an images/books folder that contains 1000's of images. I don't include these folders in the project ( the .csproj file) files so they are always left out when using using Publish.
I want to include these folders when publishing to UAT and LIVE without having to add them to my project as having so many images in your project is problematic.
What do I need to do to make this happen?
You can use this hook in your project file to add files or folder to deploy :
<!--Hook to deploy add files -->
<PropertyGroup>
<CollectFilesFromContentDependsOn>
AddFilesToDeploy;
$(CollectFilesFromContentDependsOn);
</CollectFilesFromContentDependsOn>
</PropertyGroup>
<!--Add files to deploy -->
<Target Name="AddFilesToDeploy">
<GetAssemblyIdentity AssemblyFiles="$(TargetPath)">
<Output TaskParameter="Assemblies" ItemName="CurrentAssembly" />
</GetAssemblyIdentity>
<ItemGroup>
<JsFile Include="App\MyApp.min-%(CurrentAssembly.Version).js" />
<FilesForPackagingFromProject Include="%(JsFile.Identity)">
<DestinationRelativePath>App\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
Warning : this hook work when you publish a web application from visual studio. This doesn't work with the publish task with Team Foundation Server because it's not the task CollectFilesFromContent that is called

Copy built assemblies (including PDB, .config and XML comment files) to folder post build

Is there a generic way I can get a post-build event to copy the built assembly, and any .config and any .xml comments files to a folder (usually solution relative) without having to write a post-build event on each project in a solution?
The goal is to have a folder that contains the last successful build of an entire solution.
It would be nice to use the same build solution over multiple solutions too, possibly enabling/ disabling certain projects (so don't copy unit tests etc).
Thanks,
Kieron
You can set common OutputPath to build all projects in Sln in one temp dir and copy required files to the latest build folder. In copy action you can set a filter to copy all dlls without "test" in its name.
msbuild.exe 1.sln /p:Configuration=Release;Platform=AnyCPU;OutputPath=..\latest-temp
There exists more complicated and more flexible solution. You can setup a hook for build process using CustomAfterMicrosoftCommonTargets. See this post for example.
Sample targets file can be like that:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BuildDependsOn>
$(BuildDependsOn);
PublishToLatest
</BuildDependsOn>
</PropertyGroup>
<Target Name="PreparePublishingToLatest">
<PropertyGroup>
<TargetAssembly>$(TargetPath)</TargetAssembly>
<TargetAssemblyPdb>$(TargetDir)$(TargetName).pdb</TargetAssemblyPdb>
<TargetAssemblyXml>$(TargetDir)$(TargetName).xml</TargetAssemblyXml>
<TargetAssemblyConfig>$(TargetDir)$(TargetName).config</TargetAssemblyConfig>
<TargetAssemblyManifest>$(TargetDir)$(TargetName).manifest</TargetAssemblyManifest>
<IsTestAssembly>$(TargetName.ToUpper().Contains("TEST"))</IsTestAssembly>
</PropertyGroup>
<ItemGroup>
<PublishToLatestFiles Include="$(TargetAssembly)" Condition="Exists('$(TargetAssembly)')" />
<PublishToLatestFiles Include="$(TargetAssemblyPdb)" Condition="Exists('$(TargetAssemblyPdb)')" />
<PublishToLatestFiles Include="$(TargetAssemblyXml)" Condition="Exists('$(TargetAssemblyXml)')" />
<PublishToLatestFiles Include="$(TargetAssemblyConfig)" Condition="Exists('$(TargetAssemblyConfig)')" />
<PublishToLatestFiles Include="$(TargetAssemblyManifest)" Condition="Exists('$(TargetAssemblyManifest)')" />
</ItemGroup>
</Target>
<Target Name="PublishToLatest"
Condition="Exists('$(LatestDir)') AND '$(IsTestAssembly)' == 'False' AND '#(PublishToLatestFiles)' != ''"
DependsOnTargets="PreparePublishingToLatest">
<Copy SourceFiles="#(PublishToLatestFiles)" DestinationFolder="$(LatestDir)" SkipUnchangedFiles="true" />
</Target>
</Project>
In that targets file you can specify any actions you want.
You can place it here "C:\Program Files\MSBuild\v4.0\Custom.After.Microsoft.Common.targets" or here "C:\Program Files\MSBuild\4.0\Microsoft.Common.targets\ImportAfter\PublishToLatest.targets".
And third variant is to add to every project you want to publish import of custom targets. See How to: Use the Same Target in Multiple Project Files

Ignore file from delete during WebDeploy

I'm using TeamCity to build and deploy a collection of MVC Applications via msbuild and WebDeploy.
In a step previous to my solution build/deploy, I copy an app_offline.htm to the deploy directory so that I can perform SQL updates and other web/solution management steps including the build.
One of the setting in the WebDeploy is to delete files that aren't included in the project, or not needed to run the site. This deletes my app_offline.htm file each time. While I understand this is kind of the desired result, is there a way to exclude this file from being deleted from the deployment directory upon the deploy?
I've tried adding an ItemGroup with the ExcludeFromPackageFiles option, with no results.
I had a similar problem, wanting to keep minified javascript files in the deployment package even though they're not part of the project.
I added a custom MSBuild target for this, that works for me:
<!-- ====== Package the minify files ===== -->
<PropertyGroup>
<CopyAllFilesToSingleFolderForPackageDependsOn>
CustomCollectFiles1;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForPackageDependsOn>
</PropertyGroup>
<PropertyGroup>
<AfterAddIisSettingAndFileContentsToSourceManifest>
MakeEmptyFolders
</AfterAddIisSettingAndFileContentsToSourceManifest>
</PropertyGroup>
<Target Name="CustomCollectFiles1">
<ItemGroup>
<!-- =====Controls\Javascript folder ==== -->
<_CustomFilesForRootFolder Include=".\Controls\Javascript\*.min.js">
<DestinationRelativePath>%(RecursiveDir)%(Filename)%(Extension) </DestinationRelativePath>
</_CustomFilesForRootFolder>
<FilesForPackagingFromProject Include="%(_CustomFilesForRootFolder.Identity)">
<DestinationRelativePath>.\Controls\Javascript\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
This other question " Custom app_offline.htm file during publish " suggests one possible way for the final result you describe:
I use my own
app_offline.htm_
file in the solution, which gets
published. My deployment script then
renames it (removing the trailing _)
to make it active.
I can then run my db scripts/do
whatever then rename the file bringing
the site back.

Resources