DefaultLabeller with Date as a prefix in cruise control .net - msbuild

I am working on cruise control .net, i need a variable in ccnet.config that contains current date so i can use it in defaultlabeller that has prifix and postfix both tags. so i can refrence this variable inside my defaultlabeller block as a prefix.
Thanks in advance.

You can use this:
<UsingTask AssemblyFile="MSBuild.Community.Tasks.dll" TaskName="MSBuild.Community.Tasks.Time" />
<MSBuild.Community.Tasks.Time Format="MM.dd.yyyy.HH.mm">
<Output TaskParameter="FormattedTime" PropertyName="CurrentDate" />
</MSBuild.Community.Tasks.Time>
The result of this task will be placed in the property CurrentDate
This is a real life example:
https://github.com/jupaol/NCastor/blob/develop/Solutions/NCastor.AutoBuilder/NCastor.AutoBuilder.Runner/Targets/Labels/FormatLabelNameSufixWhenLabelExists.target
And you need to download the community tasks:
http://msbuildtasks.tigris.org/

Related

How to get Directory name in msbuild configuration file?

Here is the simple code which I am using. Which gets all the folders in the directory and then give me the Folder name.
<TestProjectFolderPath Include="$([System.IO.Directory]::GetDirectories(`$(SolutionDir)`,`*.Tests`))" />
<TestProjectFolderNames Include="#(TestProjectFolderPath->'$([System.IO.Path]::GetDirectoryName(`$([System.IO.Path]::GetFileName(`%(Identity)`))`)',' ')" />
But in TestProjectFolderNames [System.IO.Path] functions are not getting evaluated and returned as just string eg:
$([System.IO.Path]::GetDirectoryName($([System.IO.Path]::GetFileName(C:\Some.Unit.Tests)))
I need help to understand the correct syntax to get this working.
Using property functions on Item Metadata while transforming an Item is not supported I think (maybe it is in the latest MSBuild version but I cannot test that right now). As a workaround add new Metadata yourself and because it acts like a Property things work out ok for recent MSBuild versions:
<ItemGroup>
<TestProjectFolderPath Include="$([System.IO.Directory]::GetDirectories(`$(SolutionDir)`,`*.Tests`))" />
<TestProjectFolderPath>
<FolderName>$([System.IO.Path]::GetFileName(`%(Identity)`))</FolderName>
</TestProjectFolderPath>
</ItemGroup>
<Message Text="#(TestProjectFolderPath->'%(FolderName)', ' ')" />
edit see comments, according to Sherry for older MSBuild versions the equivalent Item code is:
<TestProjectFolderPath Include="$([System.IO.Directory]::GetDirectories($(SolutionDir),*.Tests))">
<FolderName>$([System.IO.Path]::GetFileName(%(Identity)))</FolderName>
</TestProjectFolderPath>
I left out GetDirectoryName because it makes little sense calling that on the result of GetFileName.

MSBUILD - Remove a character from a variable without knowing its position

I read a build number from my TFS Team build which looks like "AB-1.2.3.4-CDE-REV.1". I want to edit this number and remove the last decimal point and make it look like "AB-1.2.3.4-CDE-REV1".
Usually when you want to manipulate strings in msbuild you're looking to use Property Functions. In the documentation of those you'll read you can use String functions so next up is figuring out which methods of System.String you need. In this case: LastIndexOf and Remove should do the trick:
<!-- BuildNumber property is fetched elsewhere -->
<PropertyGroup>
<BuildNumber>AB-1.2.3.4-CDE-REV.1</BuildNumber>
</BuildNumber>
<Target Name="ManipulateBuildNumber">
<PropertyGroup>
<BuildNumber>$(BuildNumber.Remove($(BuildNumber.LastIndexOf('.')),1))</BuildNumber>
</PropertyGroup>
<Message Text="New build number is $(BuildNumber)" />
</Target>
Thanks for the solution stijn. It works. I had figured out another lame and crude way of doing it.
<BuildNumber>AB-1.2.3.4-CDE-REV.1</BuildNumber>
<Part1>$(BuildNumber.Split('.')[0])</Part1>
<Part2>$(BuildNumber.Split('.')[1])</Part2>
<Part3>$(BuildNumber.Split('.')[2])</Part3>
<Part4>$(BuildNumber.Split('.')[3])</Part4>
<Part5>$(BuildNumber.Split('.')[4])</Part5>
<BuildNumber>$(Part1).$(Part2).$(Part3).$(Part4)$(Part5)</BuildNumber>

How to programatically hard code the date of build into an assembly

I want to hard-code the date of build into my assembly.
I can easily do that manually but is there some way it can be achieved by the build process?
See http://social.msdn.microsoft.com/Forums/ar/tfsbuild/thread/7fdeabcc-2ef1-4c4f-9798-b69ebee0c3a3
Once you are able to get the timestamp, you can place it in your property like so:
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>BUILD_TIME=$(Timestamp);%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>

Using MSBuild, how to construct a dynamic string from iterating over files in an ItemGroup?

I need to create multiple /testcontainer: parameters to feed into a task that exec's MsTest.
I have the following :
<ItemGroup>
<TestFiles Include="$(ProjectPath)\**\UnitTest.*.dll" />
</ItemGroup>
for each match in TestFiles I would like to build a string like so:
"/testcontainer:UnitTest.SomeLibrary1.dll"
"/testcontainer:UnitTest.SomeLibrary2.dll"
"/testcontainer:UnitTest.SomeLibrary3.dll"
I am trying to use the internals of MSBuild without having to create a custom task, is this possible ?
TIA
It really depends on the usage of this afterwards. For example the task that you are sending it to, does it accept in an item list and do you want to invoke it once or multiple times?
If you want to invoke it once then you use the #(...) syntax, and if you want to invoke it many times then you do batching with the %(...) syntax.
To invoke once
<Message Text="Test Files: #(TestFiles->'/testcontainer:%(RecursiveDir)%(Filename)%(Extension)')"/>
To invoke many times
<Message Text="Test Files: /testcontainer:%(TestFiles.RecursiveDir)%(TestFiles.Filename)%(TestFiles.Extension)"/>
More info on batching at http://sedotech.com/Resources#batching
Try this:?
<Message Text="TestFiles= #(TestFiles-> '"%(Fullpath)"', ' ')" />
References:
MSBuild transforms
MSBuild: How to display an item list, separated by a comma.

Find MSBuildProjectDirectory Parent Directory

MSBuild 3.5
I have the following project structure:
trunk/MainSolution.sln
trunk/Build/MyBuild.Proj
trunk/Library/...
trunk/etc...
So far, I've been using the following property to find out the project root folder:
<RootFolder>$(MSBuildProjectDirectory)\..\</RootFolder>
Everything was working great, until I tried using a copy task that relied on this path. It is not resolving correctly. I basically end up getting something like this which is not valid:
C:\Projects\MyProject\Trunk\Build\..\CodeAnalysis\myfile.xml
So basically, I need to get the full path for (MSBuildProjectDirectory)'s Parent.
Item metadata is your friend!
<Target Name="GetMSBuildProjectParentDirectory">
<!-- First you create the MSBuildProject Parent directory Item -->
<CreateItem Include="$(MSBuildProjectDirectory)\..\">
<Output ItemName="MSBuildProjectParentDirectory" TaskParameter="Include"/>
</CreateItem>
<!-- You can now retrieve its fullpath using Fullpath metadata -->
<Message Text="%(MSBuildProjectParentDirectory.Fullpath)"/>
<!-- Create a property based on parent fullpath-->
<CreateProperty Value="%(MSBuildProjectParentDirectory.Fullpath)">
<Output PropertyName="CodeFolder" TaskParameter="Value"/>
</CreateProperty>
</Target>
Nowadays with MSBuild 4.0 and above you don't want to use CreateItem or CreateProperty tasks anymore. What you are asking for can be solved easily with msbuild property functions:
<!-- Prints the parent directory's full path. -->
$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)\..'))
If you just want to read the parent directory's folder name you can combine the above statement with the GetFileName property function:
$([System.IO.Path]::GetFileName('$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)\..'))'))
A bit verbose but much better than the other answer as this works outside of targets and can be assigned to a property.
In case someone like me is still interested in this, here is how I did it in 2022 ^_^
<PropertyGroup>
<ParentFolderPath>$([System.IO.Directory]::GetParent($(MSBuildProjectDirectory)))</ParentFolderPath>
<ParentFolder>$([System.IO.Path]::GetFileName($(ParentFolderPath)))</ParentFolder>
...
</PropertyGroup>
I'm using this technique to auto-name the assemblies and default namespaces in the complex solutions.
<AssemblyName>$(ParentFolder).$(MSBuildProjectName)</AssemblyName>
<RootNamespace>$(ParentFolder).$(MSBuildProjectName.Replace(" ", "_"))</RootNamespace>