Here we are in the second part of the cycle. In the first part I show basic concepts and first, simple build script that allows us to build our project on server. This time I will show how to configure automatic versioning and deploying the application to the test site.
First of all let me explain what I mean by versioning. There are two projects in the solution I have created for purpose of the cycle and both of them have AssemblyInfo.cs files. Good practice is to set correct version numbers both for assembly and file. The default value 220.127.116.11 is a kind of things that screams that developer didn't care about versioning at all. Nevertheless, editing these files every time we are going to build application is even worse way around, especially when an application is built every time we commit sources. And even if not that, we can have a number of projects in a solution so it is just boring work and waste of precious time that can be spend much, much nicer, in pub with friends or so. From the other side, knowing the exact version number is also nice help during bug fixing, when we know in which version which bug has been fixed.
What then we can do, is to force our build server to set the correct content of AssemblyInfo.cs for us. Before we start that, I will add some extra code to our project that will display version of running assembly. So I have to add the following line in my only page in the web application I created so far:
And a bunch of lines in code behind so my code behind looks like below:
Similar code can be added to the library used by the web application, but I will stay on that one. As a result of that we can see version number, build type and build time displayed on the page.
Before we will start doing anything in our build script, let me write a few considerations about versioning.
Basically, version number consists of four part numbers: major, minor, build and revision. The major and the minor numbers are completely up to us and these not change so frequently to bother, whereas the build and the release numbers change every build. One of the popular schemas of setting version number is:
Where YYMMDD means date when the application has been built and Release is a number of the release. These two values can be easily determined during the processing of the build script. First of them, date of the build, need some additional explanation. It's well known problem that when you will try to build application with version number set to something like 1.1.071121 you will get an error CS0647. Reason is that numbers in version are limited to 16 bit, which is pretty silly today. However this is separate problem and as mgrzeg mention on his blog, there are different ways to solve that. Personally I'm using date format ddMMy pattern instead yyMMdd but you can use any pattern you want. I saw also some idea to count the number of days from the project start date, or even distance from start date expressed as the number of full months and days (similar to mmdd). Anyway, in further examples I will use my standard ddMMy pattern.
The release number is much easier as there is no special pattern in common use. Instead of that we will take release number from the source control.
With that introduction we are ready to write target to our build script that will set up correct information for assemblies. MSBuild.Community.Tasks comes with help here with AssemblyInfo task. However, before we will be able to use this task, we need to prepare and gather all data for setting version information.
First let's set up a new property group to store all data in one clear form:
Then, we need to retrieve release number from the source control. We will change existing SvnCheckout task in the Checkout target we created in the first part of the cycle. Here is the snippet:
Only thing I change is one extra line that will take value of task's property "Revision" and insert it into Revision variable in the script.
Now we can create new target named VersionSetup where all information will be written to AssemblyInfo. Whole target code you can see on the snippet below.
We are doing a few things there. First of all we have to set this target depend on the checkout target because we need the actual revision value. Then we have to set up the build number according to the pattern described before using Time.Get task. This task is pretty simple and takes time formatted according to specified pattern and returns that to the script Build variable.
The Time.Get task I used comes from the Microsoft.Sdc.Common.Tasks set. This is another great set of MSBuild tasks. There are some tasks that are the same in both sets, but generally it is good to have both of them installed and included into the build script. You can find these tasks on the same page where the MSBuild.Community.Tasks are located (see resources at the bottom of the article).
Having all the data we can execute the AssemblyInfo task. There is number of attributes that allow us to set every aspect of the AssemblyInfo including COM visibility, the assembly description or all copyright info and other we could want. As the required parameters we have to specify the language we are using (CodeLanguage attribute) and location of AssemblyInfo.cs file (OutputFile attribute). Important is that this task will replace existing AssemblyInfo.cs file, so we have to specify all information we need in the build script. And small hint here, Guid number can be just copied by hand from the original AssemblyInfo.cs file created by Visual Studio. As you can see on the snippet, AssemblyVersion and AssemblyFileVersion attributes are composed of variables defined before in the property group. And finally I'm repeating the same task for second project in the solution. If there will be more projects we will have to add more tasks into this target to serve them all.
When we will place this target in execution order between the checkout and build we will have AssemblyInfo.cs created with information we want. To prove that we should run application on the server but ... we don't have application there. Yes, we have built solution that can be used and deployed manually to virtual server but we are building script to avoid that. So let's deploy now.
Deploying (simple way)
Right, deployment, we have two ways here to deploy application and make it available for testers or whoever we want to be able for. First way is the easy one and I will use that. In the first part of the cycle, when I was describing folder structure on build server I have created myproject\testsite folder. I made this folder as a home directory of the virtual directory on local IIS. In this situation I have to create deployment files and copy them to that folder.
Second, more complicated way is to use tasks to create virtual directory under IIS and configure all web server to point on correct location. If there will be need expressed in comments (*) I will describe that later in the cycle.
Ok, we have to prepare content to deploy before we actually do that. Let's add web deployment project to the solution we have. Then we can create the next target named Deploy that depend on the Build target of course. This target is pretty simple. With a Folder.Copy task (from Microsoft.Sdc.CommonTasks) we can copy all directory content including subdirectories. It's much easier than doing that with tasks included in the MSBuild by default. Only what we have to specify id source and destination locations.
Here, on the snippet above, we are copying content of the deployment project build to deployment directory, which is defined at the beginning by adding the following line to the property group right after the WorkingOutputs.
Putting all together
Now we can put all the pieces together and change the "All" target, which is target we are building, by adding new calls. Finally this target looks like on the snippet below.
After successful build we can browse to the url we have assigned to the deployment directory and see how our build script works. If everything has been done fine, we will page with nice version number and we will have the newest release available online every time build will be successful.
In the next part I will show how to add unit tests to build server. We may have to put some small modification for the tasks that ships with one of the sets. It will be some nice there so stay tuned.
Hope that helps
* – if there will be any comments
03-15-2007 12:32 PM