In projects in which the workspace has only one working folder, my build scripts work great. Now that I am working with a new project that required 2 working folders, all of the checkout and checkin commands of my previous script fail, with no files found.
Obviously, I'm not understanding a critical part of the implementation of the workspace here... I have a project which is dependant on other projects, the second working folder is basically a 3rd party folder with references to the various published DLL's and headers files needed to compile my project. There are 2 active folders and the local folders are:
$(SourceDir)\TEAM-MAIN\Address Finalizer $(SourceDir)\TEAM-MAIN\HH-CAHPS Project\MAINLINE\3rd Party
The built code works fine, but the custom AfterGet fails on the following entry:
<!-- Check out all of the assemblyInfo files -->
<Exec Command="$(TfCommand) checkout AssemblyInfo.cs /recursive"
WorkingDirectory="$(MSBuildProjectDirectory)\..\sources"
ContinueOnError="false"/>
The project will of course work if I have a single working folder and move the source to a high enough point to get all the needed files, but I don't want to troll through 43 other projects todo what I want, let along mucking with their assembly files...
I have also tried :
<!-- Check out all of the assemblyInfo files -->
<Exec Command="$(TfCommand) checkout AssemblyInfo.cs /recursive"
WorkingDirectory="$(SolutionRoot)"
ContinueOnError="false"/>
Same problem, unable to find any assembly files... I have checked build log and I definately see assembly files check out during the build phase...
Task "Get" Get TeamFoundationServerUrl="http://pgpd-team01:8080/" BuildUri="vstfs:///Build/Build/1430" Force=True Overwrite=False PopulateOutput=False Preview=False Recursive=True Version="C7564" Workspace="SBN01P-TFS03_61" <snip> Getting C:\Users\tfsservice\AppData\Local\Temp\InfoTurn\Address Finalizer\Sources\Address Finalizer\Address Finalizer\Properties\AssemblyInfo.cs;C7525.
If anyone has any ideas or can point me to some article to better explain how mutliple working folders work, I'd appreciate it.
Values for some of the build variables:
MSBuildProjectDirectory: C:\Users\tfsservice\AppData\Local\Temp\InfoTurn\Address Finalizer\BuildType SolutionRoot: C:\Users\tfsservice\AppData\Local\Temp\InfoTurn\Address Finalizer\Sources
To provide more information, I added the following command:
<!-- Report what our working folders are --> <Exec Command='$(TfCommand) workfold' WorkingDirectory="$(SolutionRoot)\TEAM-MAIN\Address Finalizer"/>
The result was:
Task "Exec" Command: "C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\..\tf.exe" workfold =============================================================================== Workspace: SBN01P-TFS03_61 (tfsservice) Server : http://pgpd-team01:8080/ $/InfoTurn/TEAM-MAIN/Address Finalizer: C:\Users\tfsservice\AppData\Local\Temp\InfoTurn\Address Finalizer\Sources\TEAM-MAIN\Address Finalizer $/InfoTurn/TEAM-MAIN/HH-CAHPS Project/MAINLINE/3rd Party: C:\Users\tfsservice\AppData\Local\Temp\InfoTurn\Address Finalizer\Sources\TEAM-MAIN\HH-CAHPS Project\MAINLINE\3rd Party
I have found that the following working directory will work:
WorkingDirectory="$(SolutionRoot)\TEAM-MAIN\Address Finalizer"
But that the following two do not, note that the 2nd is my 2nd working folder:
WorkingDirectory="$(SolutionRoot)" WorkingDirectory="$(SolutionRoot)\TEAM-MAIN\HH-CAHPS Project\MAINLINE\3rd Party"
The error that I get for the label task is the most useful:
Using "Label" task from assembly "C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\Microsoft.TeamFoundation.Build.Tasks.VersionControl.dll". Task "Label" Label TeamFoundationServerUrl="http://pgpd-team01:8080/" BuildUri="vstfs:///Build/Build/1507" Name="Address Finalizer 2.0.1 Build 039" Recursive=True Comments="Automated build: Address Finalizer 2.0.1 Build 039" Version="W" Child="replace" Files="C:\Users\tfsservice\AppData\Local\Temp\InfoTurn\Address Finalizer\Sources" C:\Users\tfsservice\AppData\Local\Temp\InfoTurn\Address Finalizer\BuildType\TFSBuild.proj(310,5,310,5): error : Error: Unable to determine the workspace.
The actual error from the check out, which is not useful, is:
Task "Exec" Command: "C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\..\tf.exe" checkout AssemblyInfo.cs /recursive No matching items found in C:\Users\tfsservice\AppData\Local\Temp\InfoTurn\Address Finalizer\Sources\AssemblyInfo.cs in your workspace. C:\Users\tfsservice\AppData\Local\Temp\InfoTurn\Address Finalizer\BuildType\TFSBuild.proj(280,5): error MSB3073: The command ""C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\..\tf.exe" checkout AssemblyInfo.cs /recursive" exited with code 1.
It is possible to use disjoint workspace mappings + recursion at the same time. You just have to be careful.
This gets all C# files in Foo & Bar:
$/project/dir1/foo -> c:\code\foo
$/project/dir2/bar -> c:\code\bar
tf get c:\code\*.cs -recursive
This usually gets everything under Foo & Bar, but will fail if the working directory cannot be resolved to a workspace unambiguously:
$/project/foo -> c:\code1\foo
$/project/bar -> c:\code2\bar
tf get $/project/* -recursive
This might work (same caveat as above), but it probably doesn't do what you expect!
$/project/foo -> c:\code1\foo
$/project/bar -> c:\code2\bar
tf get c:\code* -recursive
There are more variations; the behavior depends on how your workspace is defined, as well as the presence of other workspaces on the same machine with similar local paths. Can you spell out your build definition exactly? And can you add some debugging statements to verify exactly what $(SolutionRoot) and other MSBuild properties are equal to when your target is being executed?
/ EDIT /
As I said, disjoint mappings + recursion is very tricky to get right. Turns out that behavior varies not only with the subtle details of your filespec vs the workspace definition, but also varies between commands! Unlike my first example, this fails:
$/project/dir1/foo -> c:\code\foo
$/project/dir2/bar -> c:\code\bar
tf checkout c:\code\*.cs -recursive
Confused yet? I am, and I worked on the TFS team for several years!
Let me summarize my recommendations from the various comment threads:
Better still, don't use a disjoint workspace in the first place. Look at all of the local paths being mapped: their common ancestor should itself be a mapped folder. Otherwise (a) commands run from there will be ambiguous, requiring extra parameters, and/or not work at all (b) commands run from individually mapped subfolders won't query across the whole workspace [unless you use server paths]. To avoid all this, pick one mapping to be the "root", then ensure all subsequent mappings point somewhere underneath it. Once you have established a single, unified root, things get much easier. tf commands run from anywhere inside it will function much more predictably (to newbs & experts alike!). There are several ways to setup a unified workspace that meets your goals:
Even better still, don't checkout/checkin files during the build process. Seriously. Common situations that are easy for humans to handle (eg locks, version conflicts) are a nightmare to automate given all the possible edge cases. And god help you if you ever try to use continuous integration... Meanwhile, your all important builds are breaking while you debug functionality that I truly don't see any benefit for. Instead: