Note: This entry has been sitting for a long time … I’ve been very, very, very busy managing the builds for over 100 projects. There is more to come as I share the learnings (and code) from this.
I’m aware that this is for the now “legacy” version of TFS. But as we’ve moved our implementation from 2008 to 2010, there are still a couple of things that I’ve done there that, I think, are really cool that I’d like to share before they fade away into the oblivion of previous versions. This is the first of these.
First, some background. We have a pretty well defined and structured deployment process at work. It’s been in place for quite some time and wasn’t anything that was going to change when I came in. Besides that, it made a good deal of sense. Here’s the process as it was when I arrived:
- Development team creates a deployment package. This package includes both the source and the compiled/release files in separate zip files.
- For some deployments, there would also be an associated MSI file.
- A deployment would go through a “dev” environment, then a “test” environment before being (perhaps) approved for production release. The development team would create an item in a Sharepoint list for the deployment. They created one of these for both dev and test environment deployments. Deployment versions were based in the ID of this item. More on this in a future post.
- The deployment manager kept a source safe database of all deployments, as well as copies on a share.
That covers the high points. Note that there were several items common to all deployments – zips for both source and release, ID’s based on a separate tracking item and potentially MSI files. I also implemented a branching strategy based on how projects worked on the team. Again, more on this item in a future post. But the main thing that I want to point out is that there are a bunch of things that are common to each and every build – and things that can be automated. And that’s what I’ll be talking about.
Since TFS Build 2008 is based on MSBuild files, that was where we needed to work. The first step was to download the MSBuild Extension Pack – all of the tasks are useful and some, in particular, were highly applicable to our process. So that did need to be installed on the build server. I certainly didn’t want to do a copy-paste into all of the project build templates (which will eventually be over 100); that wouldn’t allow me to make any changes to all builds and all projects in an efficient, sane manner. Starting with a pre-built template wouldn’t be any better either as I’d have the same problem. But … MSBuild does have a facility to share tasks and targets among multiple MSBuild project files, one that every Visual Studio project (that supports MSBuild – not all do!) uses. This is through the Import element. It’s reminiscent of the “Magical Mystery Includes” from ASP Classic days but that doesn’t negate it’s usefulness. You just need to make sure that you document it!
And that, my friends, is the key to making this work. I created a MSBuild project file that handles all of the common items. It created a custom version number based on the deployment request and the date. It created the zip files for source and release and then copied them to the drop folder. It would also handle calling Visual Studio from the command line and building the MSI file. It also imported the MSBuild Extension Pack tasks. All of these tasks were done in documented extensibility targets for TFS Build. This single MSBuild project file would then be included into every individual build project file; it would do its thing and the project file could also then do a couple of items unique to the project. Tasks that were common, but not in every project (like building the MSI) were controlled by properties that could be set either via the command line or in the project’s build file. The ID of the deployment request was also a property included in the MSBuild command line; this was used to create the version number for the deployment, enabling better auditing and trackability. There is also a command-line switch that runs the build in a “Test Mode” that doesn’t label and creates different build numbers.
But that’s not all. Most of what I described above is provide either out-of-the-box or with tasks from the MSBuild Extension Pack. But … I mentioned the branching strategy and that is a very important part of the entire process. We have both support and development teams working on the same project (at times). They need to work in parallel and to be able to merge their changes together. We have also had cases where both the dev team and the support team were looking to deploy (eventually) to production within a week of each other so we needed to be able to integrate the changes for a single package. I won’t get into the details of that but I wanted to mention it because it has a significant impact on build … we need to be able to build, using the exact same build script, regardless of the source branch. And that is where I found nothing that could help me. So what did I do? I wrote code, of course!
So I wrote a task that changes the workspace mappings based on MSBuild properties – supplied via MSBuild arguments – before the build workspace is created and any files are retrieved from source control. This allows a build to be done from any branch from a single build script … which I like.
At the end of all of this … some of the process described about was implemented completely via MSBuild for TF Build 2008, but not all. I stopped working on further enhancements when I got the go-ahead for migrating to TFS 2010 shortly after RTM - we upgrading within a week of RTM. I’ve been working on a lot of stuff since then, including (but not limited to) build activities that make my life easier. I’ll be sharing some of that in the coming weeks/months, so check back.