Archive for April, 2010

Passing Parameters to a target in MSBuild

Apr 29

On our current project we are using MSBuild to build our application. This is my first time using MSBuild other than just tinkering and I have found it…. challenging to say the least. A lot of my challenges are lack of knowledge but the other half is the language itself.

The most recent challenge I wanted to write about was calling a target multiple times. Our scenario is this: We have to generate a batch file for each environment we are going to install in with environment specific settings. The issue I had was that for each environment we had that we were copying and pasting the steps and changing values for each environments. While this worked, as the number of environments grew the size of the build task grew and got harder to modify as requirements changed.

Ideally what we would have is a task that would generate a batch file based on a set of parameters that we could just call out to so I built this:

   <Target Name=”BuildBatchFile “>
    <Copy SourceFiles=”install.bat”
                 DestinationFiles=”MyApp.Setup\Release\install.$(BATCHENV).bat”
                
ContinueOnError=”false” 
                 SkipUnchangedFiles=”false” />
    <FileUpdate Files=”MyApp.Setup\Release\install.$(BATCHENV).bat”
                           Regex=”{ENV}”
                           ReplacementText=”$(ENV)” />
    <FileUpdate Files=”MyApp.Setup\Release\install.$(BATCHENV).bat”
                           Regex=”{VDIR}”
                           ReplacementText=”$(VDIR)” />
    <FileUpdate Files=”MyApp.Setup\Release\install.$(BATCHENV).bat”
                           Regex=”{INSTALLDIR}”
                           ReplacementText=”$(INSTALLDIR)” />
  </Target>

So this copies my template install.bat to install.[ENVIRONMENT[.bat and then does all the string replacements on it.

The issue is how to invoke this task with different sets of data. My first thought was this:

<CallTarget Targets=”BuildConfigFile” />

Unfortunately, there is no way to pass parameters to a target. The only way to do that is to call MSBuild and set the parameters passed to MSBuild (this does feel wrong but I am not sure of a better way to do it so far)

<Target Name=”BuildDeploymentPackage”>
    <MSBuild Projects=”$(MSBuildProjectFile)”
                      Targets=”BuildBatchFile “  
                      Properties=”BATCHENV=ALPHA;ENV=ALPHA;VDIR=PASIPrep;INSTALLDIR=C:\inetpub\wwwroot\MyApp;” />
    <MSBuild Projects=”$(MSBuildProjectFile)”
                       Targets=”BuildBatchFile ”
                        Properties=”BATCHENV=SYST;ENV=SYST;VDIR=MyApp;INSTALLDIR=C:\inetpub\wwwroot\MyApp;” />
    <MSBuild Projects=”$(MSBuildProjectFile)”
                       Targets=”BuildBatchFile “ 
                       Properties=”BATCHENV=TRAINING;ENV=TEST;VDIR=MyApp;INSTALLDIR=C:\inetpub\wwwroot\MyApp.TEST;” />
  </Target>

The above target calls MSBuild to call its own build file and run the BuildBatchFile target with a set of parameters.

Hope this helps (or someone shows me a better way to do it)!

 

 

 

Filed Under: General

Testing Your Configuration

Apr 16

One common issue of team development is sharing configuration files. If a developer is testing something out and changes a value and then accidentally checks that file in it affects all developers.

There are a few approaches to solving this issue:
1) Be very careful and disciplined.

+Simple
-SImple to forget

2) Have a web.config.template under source control that developers copy to web.config and not include in source control.

+Prevents checkins of web.config files that affect other people
-Developers need to manually update their config files if a new value is added/removed/or the default updated

3) Have a build script task to generate a config file on demand.

+Changes are easily propagated through the script
-If a developer mucks with the build script and checks it in then we have the same problem (but less likely to happen)

4) What we are trying. Unit test the configuration to make sure it is correct.
+web.config is under source control
+changes are caught by a test. If it is meant to be distributed to all developers then the test should be updated as well
-have to write a test for the configuration (not a big minus in my opinion)
-If you have different config settings for the test project than the actual project then this will not work

In order to test a config file though we need to be able to load that config file! In our case we are testing a web.config and nunit is expecting a app.test.dll.config file. The easy way around this was to copy the web.config from our application to the proper folder and name with a pre-build event:

copy $(SolutionDir)\App.Service\web.config $(ProjectDir)\bin\App.Test.dll.config /y

Now my tests use that config file to assert that the settings are proper. The big downside to this approach is that it will overwrite the app.config file that you may already have for your test which may not be desirable.

Alternatives:
1) Parse the XML of the config file you want to test and verify
2) Load and unload and external config file in a test (I started with this and could not get it to work)

Filed Under: General