Adding umbraco folders to build with MsBuild - visual-studio

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!

Related

Copy all TypeScript files to output directory after each build

I have a bunch of TypeScript files in my project, and I want them all to be copied to the output directory on each build, preserving their structure. Here's what I've tried, but it does not work:
<ItemGroup>
<TypeScriptFiles Include="Scripts\*.ts" />
</ItemGroup>
<Target Name="CopyTypeScriptsToOutput">
<Copy SourceFiles="#(TypeScriptFiles)" DestinationFolder="$(OutputDir)\Scripts" />
</Target>
I've also used Include="Scripts\**\*.ts" but no success. What could be wrong?
I've also used Include="Scripts***.ts" but no success. What could be
wrong?
The contents of the Include are the relative path of the files in your project.
The main problem is that you did not specify how the target runs. If you only use the Build UI to build your project, the target will not run. You should add build dependencies to the target, usually like BeforeTargets and AfterTargets, so that you run the target at build time.
Second, you have a problem with the properties of the target generated path like $(OutputDir). I tried to test this property in vs2015,2017,2019, MSBuild does not have this property by default. If the property is not defined by yourself, the value will never be reached. So I recommend that you can use $(OutputPath) and $(OutputDir).
In addition, please place TypeScriptFiles in the target to prevent confusion when the csproj file is first loaded. If you define it globally, it will be recognized by the system and mapped to the project again.
Sample
This is the target that I successfully completed.
<Target Name="CopyTypeScriptsToOutput" AfterTargets="Build">
<ItemGroup>
<TypeScriptFiles Include="Scripts\*.ts" />
</ItemGroup>
<Copy SourceFiles="#(TypeScriptFiles)" DestinationFolder="$(OutputPath)\Scripts" />
</Target>
Hope it could help you.
in my package.json, I ma using cpx to copy files in the dist folder
"scripts": {
"copy-media": "$(npm bin)/cpx media/**/*.* dist/media",
"build": "tsc && yarn copy-media",
},
So it builds first tsc, and then copy all files from folder media to dist

How to copy and rename file to output folder as part of build

I believe this is more of an msbuild-related question.
Have a .net core app and I need to conditionally publish a file and based on the build config selected in Visual Studio 2019, the file should be renamed before publishing to the target.
So Im looking at modifying the csproj file (which is nothing but an msbuild file itself)
I dont see a condition option on the copy task
https://learn.microsoft.com/en-us/visualstudio/msbuild/copy-task?view=vs-2019
The goal Im after, is if I have 3 different files
tester-notes.dev.json
tester-notes.debug.json
tester-notes.prod.json
If prod is selected as a build config, I want the file published to be tester-notes.prod.json, but renamed to tester-notes.json
Assuming you have three files(build action = None) in Solution Explorer when developing:
You can use something similar to this script to rename and copy to publish folder if you're using FileSystem publish mode:
<ItemGroup Condition="$(Configuration)=='Dev'">
<FileToRename Include="$(ProjectDir)\tester-notes.dev.json" />
</ItemGroup>
<ItemGroup Condition="$(Configuration)=='Debug'">
<FileToRename Include="$(ProjectDir)\tester-notes.debug.json" />
</ItemGroup>
<ItemGroup Condition="$(Configuration)=='Prof'">
<FileToRename Include="$(ProjectDir)\tester-notes.prof.json" />
</ItemGroup>
<Target Name="DoSthAfterPublish1" AfterTargets="Publish" Condition="$(Configuration)=='Dev'">
<Copy SourceFiles="#(FileToRename)" DestinationFiles="#(FileToRename->Replace('.dev.json','.json'))"/>
<Move SourceFiles="$(ProjectDir)\tester-notes.json" DestinationFolder="$(PublishDir)" OverwriteReadOnlyFiles="true"/>
</Target>
<Target Name="DoSthAfterPublish2" AfterTargets="Publish" Condition="$(Configuration)=='Debug'">
<Copy SourceFiles="#(FileToRename)" DestinationFiles="#(FileToRename->Replace('.debug.json','.json'))"/>
<Move SourceFiles="$(ProjectDir)\tester-notes.json" DestinationFolder="$(PublishDir)" OverwriteReadOnlyFiles="true"/>
</Target>
<Target Name="DoSthAfterPublish3" AfterTargets="Publish" Condition="$(Configuration)=='Prof'">
<Copy SourceFiles="#(FileToRename)" DestinationFiles="#(FileToRename->Replace('.prof.json','.json'))"/>
<Move SourceFiles="$(ProjectDir)\tester-notes.json" DestinationFolder="$(PublishDir)" OverwriteReadOnlyFiles="true"/>
</Target>
And if you can reset tester-notes.debug.json to tester-notes.Debug.json,, then we may combine the three targets into one by using DestinationFiles="#(FileToRename->Replace('.$(Configuration).json','.json'))". Hope it makes some help :)
In addition:
According to the Intellisense we can find the Copy task supports Condition:

Make visual studio build when output won't change?

In my project I have a json file I use for configuration that I have git set to ignore. When the repository is first cloned, the configuration file that is part of the project and that is copied to the output directory doesn't exist. I've gotten this to work using tasks in the 'BeforeBuild' target in the project that will copy the sample file to the actual config file if it doesn't exist.
<Target Name="BeforeBuild">
<ItemGroup>
<MySourceFiles Include="Configuration.sample.json" />
</ItemGroup>
<ItemGroup>
<MyDestinationFiles Include="Configuration.json" />
</ItemGroup>
<Message Importance="high" Condition="!Exists('#(MyDestinationFiles)')"
Text="Copying #(MySourceFiles) to #(MyDestinationFiles)" />
<Copy Condition="!Exists('#(MyDestinationFiles)')"
SourceFiles="#(MySourceFiles)"
DestinationFiles="#(MyDestinationFiles)" />
</Target>
So if I build the project, then delete the configuration file and do a build, nothing happens because no changes have been made that would change the outputs I think. Is there a way to change the project file so that a build will be flagged as necessary? It shouldn't come up very often and I can always do a 'Clean' or 'Rebuild' manually, but it's nagging at me since I'm just starting to learn MSBuild files.
From the documentation on a Target's Outputs attribute:
The files that form outputs into this target. Multiple files are
separated by semicolons. The timestamps of the files will be compared
with the timestamps of files in Inputs to determine whether the Target
is up to date
So if you add the paths to the outputfiles created by your Beforebuild target to it's Outputs attribute, at the start of every build msbuild will check if those files exist and if not it will start a build because now the project is considered to not be up-to-date anymore. In practice use:
<Target Name="BeforeBuild" Outputs="#(MyDestinationFiles)">

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

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"
)

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

Resources