Resolve a $ path in TeamBuild

There are some really useful TeamBuild tasks whose purpose or usage is not immediate. Such is WorkspaceItemConverterTask: it allows to transform a $ path — that is the path to a file or folder in TFS Version Control — to the physical path that the file assume during the TeamBuild.

To see how it’s used, you have to look into Microsoft.TeamFoundation.Build.targets (this file is located under %ProgramFiles(x86)%\MSBuild\Microsoft\VisualStudio\TeamBuild), and it simple to use: ServerItems gets an ItemGroup to resolve and LocalItems will held the list of resolved paths. The other parameters are needed but are always the same: they represent the context of evaluation.

I found this task useful when I needed to add some post-processing to my solutions in TeamBuild: I attached some custom metadata to the Items representing the solutions to build and iterated through them in a late build step, like PackagingBinaries.

This sample code may help understand its usage.

   1:   <Target Name="ResolveSolutionPathsForDeploy"
  2:           Condition="'$(IsDesktopBuild)' != 'true'">
  3:     <WorkspaceItemConverterTask
  4:           Condition="'@(SolutionToBuild)' != ''"
  5:           TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
  6:           BuildUri="$(BuildUri)"
  7:           WorkspaceName="$(WorkspaceName)"
  8:           WorkspaceOwner="$(WorkspaceOwner)"
  9:           ServerItems="@(SolutionToBuild)">
 10:       <Output TaskParameter="LocalItems" ItemName="LocalSolutionToBuild" />
 11:     </WorkspaceItemConverterTask>
 12:   </Target>
 13: 
 14: 
 15:   <Target Name="LocalDeploy" DependsOnTargets="ResolveSolutionPathsForDeploy" Condition="'$(DeployLocally)'=='true'">
 16: 
 17:     <PropertyGroup>
 18:       <_DeployScript Condition="'%(LocalSolutionToBuild.PsDeploy)'=='true'">
 19:         %(LocalSolutionToBuild.RootDir)%(LocalSolutionToBuild.Directory)%(LocalSolutionToBuild.Filename).Deployment\%(LocalSolutionToBuild.Filename).Deploy.ps1
 20:       </_DeployScript>
 21:       <_UndeployScript Condition="'%(LocalSolutionToBuild.PsDeploy)'=='true'">
 22:         %(LocalSolutionToBuild.RootDir)%(LocalSolutionToBuild.Directory)%(LocalSolutionToBuild.Filename).Deployment\%(LocalSolutionToBuild.Filename).Undeploy.ps1
 23:       </_UndeployScript>
 24:     </PropertyGroup>
 25: 
 26:     <Powershell ScriptFile="$(_UndeployScript)" Arguments="SolutionName=%(LocalSolutionToBuild.Filename)" Condition="'%(LocalSolutionToBuild.PsDeploy)'=='true'" />
 27:     <Powershell ScriptFile="$(_DeployScript)" Arguments="SolutionName=%(LocalSolutionToBuild.Filename)" Condition="'%(LocalSolutionToBuild.PsDeploy)'=='true'" />
 28: 
 29:   </Target>

The solution has the appropriate metadata to activate the previous code, as follows.

   1:   <ItemGroup>
  2:     <!--  SOLUTIONS -->
  3:     <SolutionToBuild Include="$(BuildProjectFolderPath)/../../Sources/Services/Service1/Service1.sln">
  4:       <PsDeploy>true</PsDeploy>
  5:     </SolutionToBuild>
  6:     <SolutionToBuild Include="$(BuildProjectFolderPath)/../../Sources/Common/Common.sln">
  7:       <MsiDeploy>true</MsiDeploy>
  8:     </SolutionToBuild>
  9:     <SolutionToBuild Include="$(BuildProjectFolderPath)/../../Sources/Web/Site.sln">
 10:       <PsDeploy>true</PsDeploy>
 11:     </SolutionToBuild>
 12:   </ItemGroup>

 

Happy Build!

Comments

  • Anonymous
    September 16, 2010
    The comment has been removed

  • Anonymous
    September 16, 2010
    The comment has been removed

  • Anonymous
    September 16, 2010
    I tried this :    <Target Name="CopyFiles">        <Copy            SourceFiles="@(ConfigurationFiles)"            DestinationFiles="@(ConfigurationFiles->'$(OutDir)%(RecursiveDir)%(Filename)%(Extension)')"        />    </Target> Where : <ItemGroup>        <ConfigurationFiles Include="$(SolutionRoot)Configuration***.*"/>  </ItemGroup> I skimmed the logfile for errors, there were none. No warnings related to this as well. any other thoughts?

  • Anonymous
    September 16, 2010
    I suggest to add some logging to your code so to better understand what is happening, e.g. <Target Name="CopyFiles">       <Message Text="In CopyFiles ConfigurationFiles is @(ConfigurationFiles)" />       <Copy           SourceFiles="@(ConfigurationFiles)"           DestinationFiles="@(ConfigurationFiles->'$(OutDir)%(RecursiveDir)%(Filename)%(Extension)')"       /> </Target> This way you can determine if the target is being called, at what point in the process, and the values it gets.