I just made a quick fix to a perplexing MSBUILD problem easily and quickly and thought I would share it.
Every project we undertake has a series of Continuous Integration builds defined:
Automated Build (builds on check-in to Source Control)
Nightly Build (builds each night)
Deployment Builds: Integration, UAT, Staging, and Release as appropriate.
We use Team Foundation Server 2010 (TFS2010) for Source Control, and Team City for Continuous Integration management.
For the second time in probably a year, I had a set of builds suddenly start failing after the developers changed path structures, with the symptom that MSBUILD complains that a .CSPROJ file does not exist on the specified relative path. On investigation, the path is found to be exactly where it should be. I have had problems with path lengths in the past, so I checked both path lengths and found them to be less than 200, which should be fine. I ran across a Microsoft Reference during my research which pointed to a known issue with MSBUILD where the combined length of the calling project and the relative path of the referenced project equal a specific number (259).
Even though my quick NotePad++ line length count indicated I had not hit the magic number, I made a quick change in the VCS root by adding one character to the root(s) of the impacted builds. Sure enough - problem fixed.
TeamCity makes this easy.
Each project in the build has an associated Version Control Setting Root (VCS Root)
Each VCS Root can have one or more checkout rules defined to change path structures or filter out portions of shared projects not needed for the particular build. One convention I adopted early on was to add a short root name to each VCS root in order to keep relative paths equivalent during the CI Build process. (Short names are key here due to inherent path length issues when dropping down several levels in the project).
Project1 SharedProject1 SharedProject2 SharedProject3
PCProject1 PCSharedProject1 PCSharedProject2 PCSharedProject3
Final paths look like:
C:BuildAgentwork87b81e895d8dab89PCProjectNameSharedProject1Pinnacle.Customer.SharedProject1.FunctionFunctionFunction.csproj C:BuildAgentwork87b81e895d8dab89PCProjectNameSharedProject2Pinnacle.Customer.SharedProject2.FunctionFunctionFunction.csproj C:BuildAgentwork87b81e895d8dab89PCProjectNameSharedProject3Pinnacle.Customer.SharedProject3.FunctionFunctionFunction.csproj
TeamCity automatically adds the random subdirectory name (in this case - 87b81e895d8dab89) to the work folder for each build.
I use a two letter combination to define the TFS Collection in which the VCS Root lives, in this case PC for Pinnacle Collection - our general collection for most projects. We have other collections for DataBase SourceCode (we use RedGate Source Control), collections shared with vendors or customers, etc.
The two letter convention preserves the tree structure found in the development environments, and allows relative paths to walk up and down the structure as needed.
TeamCity allows you to add the pseudo root by transforming the path as code is pulled from SourceControl through the use of VCS Root Checkout Rules.
My original checkout rule looked like:
Which simple says, Add "PCProjectName" to the beginning of the directory structure for everything pulled from SourceControl.
I simply changed the VCS root checkout rule in each referenced root to be:
Making this simple change to the checkout rule changed the total path length of the problem references enough to bypass the MSBUILD path quirk.
Total time to research: 2 hours.
Total time for fix: 5 minutes