When creating MSBuild.proj files for builds in Visual Studio, there are times when you might want some targets called, and other times you don’t want the targets called.In my case, our Production builds compile all the web and windows service solutions as well asthe deployment scripts for databases and our BIDS projects. Essentially everything I would want if I was going to run an entire deployment for a release. However when deploying a dll hotfix, I don’t want the SQL scripts and BIDS stuff built. When we want to deploy a hotfix, speed is of the essence. Our build servers are not fast at running these complete builds, so why waste time executing all targets in a build? Given this scenario, and others very similar to this, we could do the following:
- Open the build file and comment out what we don’t want to run. Effective but messy, plus if you don’t uncomment this stuff the next time someone comes to run a build is sat there thinking “why is half this stuff missing?”
- Copy build.proj file and gut out what you don’t want and create a new build definition for hotfixes. So now you have another build file to manage, another build definition to manage, aso you’ve made more work for yourself. It might be OK for a short while, but it clearly does not scale very well.
- We could compile locally and deploy whatever we want. *shudders* …do I even need to go on why this is a bad idea?
The solution here is to insert a condition next to the targets that we don’t want to build when we wish to run a hotfix. MSBuild supports a specific set of conditions that can be applied wherever a Condition attribute is allowed. You can read more about conditional constructs on the MSDN website;
<Target Name="BeforeCompile" Condition="'$(BuildDefinition)'=='Database Main Sandbox'"> <CallTarget Targets="DoSomething"/> </Target>
The example above uses the build definition to determine whether or not the DoSomething target is called. This is not a bad idea, however this limits where we can use this condition; we might want to point several builds to this one file, for someone might want to rename the build for some arbitrary reason. This makes more work for us in the long run. Using the MSBuild Arguments in the MSBuild process Parameters section of a Visual Studio Build Defintion (see picture 2 below), we can create our own argument and assign it a value. Then we can change the condition to run only when the value of the argument is correct.
Here’s an example:
<Target Name ="BuildMessage" Condition ="'$(RunBuildMessage)'=='1'"> <BuildStep Name="BuildMessage" Message="This is the build message..." TeamFoundationServerUrl="$(TeamFoundationServerUrl)" BuildUri="$(BuildURI)" Condition="'$(IsDesktopBuild)' != 'true'"> <Output TaskParameter="Id" PropertyName="BuildMessageId" /> </BuildStep>
The above is a build message that will occur only when we set the argument RunBuildMessage to 1.
In the Visual Studio Build Definition, let’s set that to 1 by default. Click to see full size image.
Now we kick off our build and we can verify the value:
and we should expect to see the build message appear:
All looking very good. The one small issue here is how we change the value of “RunBuildMessage”.
When you kick off a new build, just switch to the parameters tab and update from 1 to 0. So now the build step won’t run.
The great thing about this method is that unlike the others it’s straightforward to implement and manage, and allows you to have multiple builds pointed to the same build file. It also avoids having to have multiple conditions if you were going to using something like the BuildDefinition.