views:

2071

answers:

3

We want to store our overridden build targets in an external file and include that targets file in the TFSBuild.proj. We have a core set steps that happens and would like to get those additional steps by simply adding the import line to the TFSBuild.proj created by the wizard.

<Import Project="$(SolutionRoot)/libs/my.team.build/my.team.build.targets"/>

We cannot have an import on any file in the $(SolutionRoot) because at the time the Import statement is validated, the source has not be fetched from the repository. It looks like TFS is pulling down the TFSBuild.proj first without any other files.

Even if we add a conditional import, the version in source control will not be imported if present. The previous version, already present on disk will be imported.

We can give up storing those build targets with our source, but it is the first dependency to move out of our source tree so we are reluctant to do it.

Is there a way to either:

  1. Tell Team Build to pull down a few more files so those Import statements evaluate correctly?
  2. Override those Team Build targets like AfterCompile in a manner besides the Import?
  3. Ultimately run build targets in Team Build that are kept under the source it's trying to build?
+1  A: 

If the targets should only be run when TFS is running the build and not on your local development machines, you can put your targets file in the folder for the build itself and reference it with:

<Import Project="$(MSBuildProjectDirectory)\my.team.build.targets.proj" />

However, if you want the targets to run for all builds, you can set it up so that the individual projects reference it by adding something like:

<Import Project="$(SolutionRoot)/libs/my.team.build/my.team.build.targets" Condition="Exists('$(SolutionRoot)/libs/my.team.build/my.team.build.targets')" />

On my project we actually use both of these, the first allows us to customize the nightly builds so we can do extra steps before and after running the full solution compile, and the second allows project-by-project customization.

Gregg
The first option requires the targets to be outside of source control and the second will not run the targets of the current build. Only the previous. It still does the Import _before_ the source is pulled down.
Mark
A: 

If you create an overrides target file to import and call it something like TeamBuildOverrides.targets and put it in the same folder in source control where TFSBuild.proj lives for your Build Type, it will be pulled first and be available for import into the TFSBuild.proj file. By default, the TFSBuild.proj file is added to the TeamBuildTypes folder in Source Control directly under the root folder of your project.

use the following import statement in your TFSBuild.proj file:

<Import Project="$(MSBuildProjectDirectory)\TeamBuildOverrides.targets" />

Make sure you don't have any duplicate overrides in your TFSBuild.proj file or the imported overrides will not get fired.

Mr. Kraus
+11  A: 

The Team Build has a "bootstrap" phase where everything in the Team Build Configuration folder (the folder with TFSBuild.proj) is downloaded from version control. This is performed by the build agent before the build agent calls MSBuild.exe telling it to run TFSBuild.proj.

If you move your targets file from under SolutionRoot and place it in your configuration folder alongside the TFSBuild.proj file you will then be able to import it in your TFSBuild.proj file using a relative import statement i.e.

<Import Project="myTeamBuild.targets"/>

If these targets rely on any additional custom MSBuild task assemblies then you can also have them in the same folder as your TFSBuild.proj file and you can reference them easily using a relative path.

Note that in TFS2008, the build configuration folder defaults to being under $/TeamProject/TeamBuildTypes however, it does not have to be there. It can actually live in a folder that is inside your solution - and can even be a project in your solution dedicated to Team Build. This has several advantages including making branching of the build easier. Therefore I typically have my build located in a folder like this:

$/TeamProject/main/MySolution/TeamBuild

Also note that by default, during the bootstrap phase of the build, the build agent will only download files that are in the build configuration folder and will not recurse down into any subfolders. If you wanted it to include files in subfolders during the bootstrap phase then you can set the following property in the appSettings of the tfsbuildserver.exe.config file on the build agent machines (located in %ProgramFiles%\Visual Studio 9.0\Common7\IDE\PrivateAssemblies)

<add key="ConfigurationFolderRecursionType" value="Full" />

Note that if you had multiple build agents you would have to remember to set this setting on all of the machines, and it would affect every build performed by that build agent - so really it is best just to keep the files in the root of the build configuration folder if you can.

Good luck,

Martin.

Martin Woodward
Martin... you are my hero. 2 times I asked questions, 2 times you were the only one with a valid answer. You rock!
Maxim
Is it possible to get TFS to download from other folder paths during bootstrap? I have a Common.targets file that contains all the custom tasks that my TFSBuild.proj should be executing, but given that I several build definitions (one folder per definition), it sits in a separate folder at the same level as the build definitions. Without it, of course, the builds fail immediately.
David Keaveny