Accessing TeamCity properties in recursive MsBuild calls
Would it be possible to add a build property holding the name of the MsBuild arguments file that one could pass on to recursive calls to MsBuild?
We have a pretty complex environment that needs to be configured before our build can be run. The setup is handled by a script which developers use to get a command-line for each project's workspace. The solution we're using with TeamCity, since we cannot set all of the properties inside the MsBuild script itself, is to launch MsBuild via a launcher script which runs the setup first. Since TeamCity doesn't allow one to override the executable of MsBuild, we came up with an alternative solution:
1. Build using Build.bootstrap.proj instead of Build.proj.
2. Build.bootstrap.proj will call Build.proj using an exec task which runs the setup script first.
3. Pass the target(s) we want to build as a property instead of using the target box in TeamCity.
This works rather well. However, TeamCity has a whole lot of very interesting properties that get passed to the initial MsBuild process that we want to utilize in the child process. We found out that TeamCity generates a temporary file holding all of those properties as MsBuild command line switches, so we manually pass that on to any child build. However, since the name of the file (Build.bootstrap.proj.teamcity.msbuild.tcargs) is not exposed in a property we have to hard code it and I would really prefer to have an "official" name for the file instead, to avoid problems should the name change or the location move with future versions of TeamCity.
The alternative would be to pass properties manually for each step, but that would be error prone and require modifications to the build script whenever we add properties to the build, or want to utilize some new TeamCity feature.
Here's the bootstrapper file we use:
<?xml version="1.0" encoding="UTF-8"?>
<Project DefaultTargets="BootStrap" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<PropertyGroup>
<BuildMode Condition="'$(BuildMode)' == ''">ReBuild</BuildMode>
<BuildFile Condition="'$(BuildFile)' == ''">$(_DEVROOT)\Code\Build.proj </BuildFile>
<MSBuildArgs>/noconlog</MSBuildArgs>
<TeamCityArgs>@$(MSBuildProjectDirectory)\TeamCity.BootStrap.proj.teamcity.msbuild.tcargs</TeamCityArgs><!-- It would be nice not having to hard-code this-->
</PropertyGroup>
<Target Name="BootStrap">
<Exec Command="msbuild35.cmd $(MSBuildProjectFullPath) /t:Build $(MSBuildArgs) $(TeamCityArgs)"/>
</Target>
<Target Name="Build">
<Exec Command="$(_COMMONROOT)\msbuild35f.cmd $(BuildFile) /t:$(BuildMode) /p:CCNetLabel=$(build_number) $(MSBuildArgs) $(TeamCityArgs)"/>
</Target>
</Project>
The script normally has more tasks, which require the dual recursive call, but I removed them to isolate the proceedure we use. The msbuildxxx.cmd file are part of the checked out files for each project.
Cheers,
/axl
Please sign in to leave a comment.
I would recommend you using <MSBuild> task in your bootstrup msbuild script if possible to make TeamCity arrach MSBuild listener. All properties will be inherited by the msbuild subprocess in that case.
Another approach is to use 'teamcity_build_properties_file' property or TEAMCITY_BUILD_PROPERTIES_FILE environment variable. On the build agent this properties will contain a path to persisted build configuration properties. You may add '.xml' to the value to have .xml file of the properties.
Please have a look to
http://confluence.jetbrains.net/display/TCD5/Predefined+Properties#PredefinedProperties-AgentBuildProperties
Thanks!
Yes, we use the MsBuild task wherever possible, but in this case I have to interject a script which configures the environment properly and if I just set properties in MsBuild I would have to manually pass those to any tool that relies on environment variables being set as you cannot change the environment for a running MsBuild process. And the logger actually picks things up properly, so that's not a problem.
TeamCity.BuildRunner.MsBuild runs "TeamCity.BootStrap.proj"
TeamCity.BootStrap.proj runs an Exec task "configureEnvironment.bat" which then launches a new MsBuild process which inherits both TeamCity's properties and the new environment and the real build begins.
I found the properties in the generated file that I'm talking about are more convenient than the ant-style properties mentioned in the help as they are properly formatted for MsBuild and I can just pass it straight on to the task itself.
Cheers,
/axl