One small issue with the default layout of the Drop folder in TeamBuild is the lack of a fixed position for the outputs: binaries are written in $(DropLocation)\$(BuildNumber) and the latter is different at each build.

Many times is convenient having a fixed location for the outputs: you may publish that folder as a network share, FTP, HTTP and set its permissions once. It’s also easier for people inside and outside the team to find the most recent bits.

There some issue to be aware of:

  • do you build different flavors, like Release and Debug or x86 and x64, of the same project?
  • do you, even sparingly, use incremental builds?

The answer to such questions determine if you need a hierarchical folder structure, if you need to rename the outputs and so on.

The following snippet is taken from my recent work.

  1:   <Target Name="AfterDropBuild" DependsOnTargets="DropLatestPrevious" />
  2: 
  3:   <PropertyGroup>
  4:     <PreviousRoot>$(DropLocation)\$(BuildDefinition)_PreviousBuild</PreviousRoot>
  5:     <LatestRoot>$(DropLocation)\$(BuildDefinition)_Latest</LatestRoot>
  6:   </PropertyGroup>
  7: 
  8:   <Target Name="DropLatestPrevious" Condition=" '$(SkipDropBuild)'!='true' and '$(IsDesktopBuild)'!='true' and '$(BuildBreak)'!='true'">
  9: 
 10:     <ItemGroup>
 11:       <PreviousBuildFiles Include="$(LatestRoot)\*.*" />
 12:       <!-- this will work for incremental builds -->
 13:       <CurrentBuildFiles Include="$(BinariesRoot)\**\*.msi" />
 14:       <CurrentBuildFiles Include="$(BinariesRoot)\**\*.exe" />
 15:       <CurrentBuildFiles Include="$(BinariesRoot)\**\*.exe.config" />
 16:     </ItemGroup>
 17: 
 18:     <RemoveDir Directories="$(PreviousRoot)" Condition="Exists('$(PreviousRoot)')" />
 19:     <MakeDir Directories="$(PreviousRoot)" Condition="Exists('$(LatestRoot)')" />
 20:     <Move Condition="Exists('$(LatestRoot)')"
 21:               SourceFiles="@(PreviousBuildFiles)"
 22:               DestinationFolder="$(PreviousRoot)" />
 23: 
 24:     <MakeDir Directories="$(LatestRoot)" Condition="!Exists('$(LatestRoot)')" />
 25:     <Copy SourceFiles="@(CurrentBuildFiles)" DestinationFolder="$(LatestRoot)"/>
 26: 
 27:   </Target>

Here I have two fixed folder: Latest and Previous. Not all files are copied to those folders but only some, as I’m interested in Installation packages (MSIs) and some tools. The structure is flattened and implies that file names are unique, so the copy operation has no clashes.

Why Previous? Because it allows to easily roll-back from a broken build.

 

Good build!