Pre/post-build event
This is a tip for all developers, not for BuildMasters only.
The issue is those pre and post-build events that developers use to add any conceivable code… especially code that assume a developer’s workstation folder structure.
Such code may break in a TeamBuild for many reasons:
- different folder structure — all binaries are produced in the common Binaries folder, no more in a per-project bin;
- missing tools — on a typical build server only the bare minimum tools are present;
- different context — e.g. a developer workstation is 32-bit, while the build server is targeting 64-bit binaries.
There are some different solutions applicable.
The first one, done by developers on their projects, wrap the code in the pre- or post-build event with a condition, like this:
IF NOT "$(TeamBuildConstants)"=="_TEAM_BUILD_" (
gacutil /i $(TargetFile) /f
)
This needs to be done on each project and event but has a very explicit intent; also this is portable to foreseeable versions of Visual Studio and Team Foundation Server.
A second solution is to redefine the CoreBuildDependsOn property via CustomPropertiesForBuild so that PreBuildEvent and PostBuildEvent are left out. Something like this
<PropertyGroup>
<CustomPropertiesForBuild>
CoreBuildDependsOn=
BuildOnlySettings;PrepareForBuild;
ResolveReferences;PrepareResources;ResolveKeySource;
Compile;
UnmanagedUnregistration;GenerateSerializationAssemblies;
CreateSatelliteAssemblies;GenerateManifests;
GetTargetPath;PrepareForRun;UnmanagedRegistration;IncrementalClean
</CustomPropertiesForBuild>
</PropertyGroup>
I think of two scenarios where this approach is especially convenient: when you inherit existing code — so called brown field — and need to start control its behavior; or when the build shows weird behavior and you want to troubleshoot its root cause.
Keep in mind that you are touching a reserved property: this may cause problems with Service Packs or new product releases. It is also dangerous if you already use CustomPropertiesForBuild — could be hard to track what happens in the build.
I suggest to use this approach as last resort and for a limited time.
A third solution, requiring a bit more effort, is to rewrite the action as an MSBuild task and leverage the BeforeBuild and AfterBuild targets with an apt condition, like:
<Target Name="AfterBuild" Condition="'$(TeamBuildConstants)'!='_TEAM_BUILD_'>
<GacUtil Command="Install" Assemblies="$(TargetFile)" Force="true" />
</Target>
using the MSBuild Community Tasks or, using the MSBuild Extension Pack:
<Target Name="AfterBuild" Condition="'$(TeamBuildConstants)'!='_TEAM_BUILD_'>
<Gac TaskAction="AddAssembly" AssemblyPath="$(TargetFile)" Force="true" />
</Target>
As there are lot of built-in and publicly available tasks, this could be an elegant and viable approach.
Happy Building!
UPDATE: the above suggestion works for Visual Studio + Team Foundation Server 2008.
In Visual Studio 2010 and later, the recommended method is to use the predefined property BuildingInsideVisualStudio
IF "$(BuildingInsideVisualStudio)"=="true" ( …your code here… )
Hope this helps.