A Django site.
May 16, 2008
» Infragistics use of Teamprise

Infragistics is the world's largest publisher of reusable presentation layer development tools for Windows Forms, ASP.NET, WPF, Tablet PC and Java (JSF) environments.  I think they can count most of the Fortune 2000 as customers of theirs.  They also happen to be a customer of ours. 

I was in an email discussion with fellow MVP Ed Blankenship, when he came out with the following quote which Infragistics have kindly given me permission to share.

“We completely use Microsoft® Team Foundation Server (with Teamprise) for the development of all of our products now.  This was especially challenging with bringing in our Java (JSF) development group into the same development process of our .NET product lines.  By leveraging the Teamprise Eclipse plug-in and the ANT Team Build tasks, we were able to ensure they were using the exact same systems as the other departments in Engineering.  So the JSF team now has access to the same build, version control, work item tracking, and other internal automated software solutions that the rest of our company uses.  Visual Studio® Team System has really enabled us to solidify our internal ALM process, metrics gathering, and reduce overhead from supporting different systems across product teams.”

Ed Blankenship
Infragistics

Thanks for sharing Ed!  On a personal note, I'm glad that the Ant integration is proving so useful to many companies and this is an area that we are going to continue investing in along with everything else.

May 15, 2008
» Increasing the size of a VMWare Disk

I am currently playing with SP1 of VSTS 2008 and TFS 2008 in a Windows Server 2008 VMWare instance I have.   Whenever I created this particular instance I kept the disk space at 16Gb which is normally plenty for these play instances but after installing the service pack of VSTS my disk space was getting low.

I thought I would try extending the size of my virtual disk and it was suprising easy.

  1. First, I had to take a fill clone my image to remove the snapshot history.
  2. The on the new clone's disk I executed the following command:
    "C:\Program Files (x86)\VMware\VMware Workstation\vmware-vdiskmanager.exe" -x 32Gb win2008-000004-cl1.vmdk
  3. This extended the disk size, now I need to extend the size of the partition.  Boot up the virtual Windows 2008 server, right click on "My Computer" and select "Manage".  Go To Storage, Disk Management and then right click on the C: partition and select Extend to extend the partition the the size of the remaining disk.

Tada.  No third party tools (like Partition Magic etc) needed.

April 22, 2008
» Apple - The New Real?

Apple Software Update <rant>Sigh.  Apple are really starting to get on my nerves.  Not only is iTunes on Windows consistently very buggy, slow and foreign looking in the Windows OS - they are now trying to trick Windows users into installing Safari.  On this particular machine I have never installed Safari, and I never want to.  At first I thought the offering of Safari via Apple Update (as a default option) was just a mistake, I figured out how to tell the installer to ignore the update and moved on.  The second time I gave them the benefit of the doubt - but here they are again.  Today I got the following fantastic message from Apple Update.  "WhichDescription()" indeed.  Gives you a wonderful feeling that they've spent a lot of time on this one.  So from today - Apple update is now disabled on my machine and will stay that way until Apple trick me into switching it back on again.

This is incredibly bad form and reminds me of all the rubbish that Real software used to get up to when they were still relevant.  The worse thing is that it will condition people to disable updaters when we live in a time that I would prefer people kept their systems up to date and patched.  I know that people will have said this in other places and in better ways - but if Microsoft pulled this sort of trick, just imagine the reaction.  This kind of move feels like one of desperation or arrogance - possibly both.</rant>

Apologies for the rant - normally I keep this sort of thing off my blog but this one really annoyed me.

April 21, 2008
» TFS Build API by Example #1: Queue a build.

Team Foundation Build API Class Diagram - larger version. As we all know by now - the build system in TFS2008 was substantially improved.  Along with the many improvements came an official API for talking to the build system.  This is the same API that the Team Foundation Build UI in Visual Studio uses, however there are many additional methods that were added that were not for the UI at all but for potential consumers of the Build API.

In talking with folks at community events, and on the MSDN forums I have realized that there isn't a huge awareness of this API.  Having written a parallel implementation of the build API, but in Java for the Teamprise 3.0 release I have spent a great deal of time with the .NET API and have a few examples lying around of how to accomplish certain common tasks - so I thought I would run through a some of them.  If you have an example of something you would like to see with the build API then please leave a comment for this post or drop me a line.

So - let's start with a basic one.  How to queue a build.  This will introduce us to a few concepts with-in the build API that are common across all of the methods.

The Easy Way.

A quick look at the class diagram above will show you that the main interfaces you'll be dealing with in the Build API are the IBuildServer and IBuildDefinition interfaces.  To get started with these you'll need to add references to the Microsoft.TeamFoundation.dll, Microsoft.TeamFoundation.Client.dll and Microsoft.TeamFoundation.Build.Client.dll.

C#

TeamFoundationServer tfs = TeamFoundationServerFactory.GetServer("http://tfsserver:8080”);
IBuildServer buildServer = (IBuildServer)tfs.GetService(typeof(IBuildServer));
IBuildDefinition buildDef = buildServer.GetBuildDefinition("TeamProject", "Build Name");
buildServer.QueueBuild(buildDef);

VB.NET

Dim tfs As TeamFoundationServer = TeamFoundationServerFactory.GetServer("http://tfsserver:8080")
Dim buildServer As IBuildServer = DirectCast(tfs.GetService(GetType(IBuildServer)), IBuildServer)
Dim buildDef As IBuildDefinition = buildServer.GetBuildDefinition("TeamProject", “Build Name")
buildServer.QueueBuild(buildDef)

I'm afraid that's the last example you'll be seeing in VB.NET.  Being a Java developer by day I tend to like my semi-colons.  However if you are a VB developer then hopefully you'll be able to follow along as the rest of the examples are more or less just method calls with the occasional bit of casting.

So - what's going on here.  Well we first get hold of a TeamFoundationServer object.  If this was server side code and we wanted to specify some credentials then we would use a slightly difference mechanism but in this case the constructor works well and this will automatically connect using the credentials of the current thread.

Next we get hold of the build service that implements the IBuildServer interface.  Finally we get a hold of the build definition by specifying a team project and build definition name (build definitions are unique per team project in TFS).  We then queue a build using the defaults for that build definition.  This API call is actually shorthand for the following...

The Hard Way

IBuildRequest interface diagram Supposed you want to queue a build, but you don't want to use the default build agent, priority, drop location etc.  Well in that case you need to look at the IBuildRequest interface.  Here you will find all the options to customize the build request, you can specify a build agent, drop location, priority etc like you can do from the Visual Studio UI.  You will also find other options such as being able to queue the build with a maximum acceptable queue position, pass a custom get version for the build or even queue the build in a postponed status.

In the following example, I am going to find a non-default build agent from the server and then queue a build using it.

        TeamFoundationServer tfs = new TeamFoundationServer("http://tfsserver:8080");
        IBuildServer buildServer = (IBuildServer)tfs.GetService(typeof(IBuildServer));

String teamProject = "TeamProject";
String buildDefinitionName = "MyBuildDefinition";
String buildAgentName = "MyBuildAgent";

// Find our (non default) build agent.
IBuildAgentQueryResult queryResult = buildServer.QueryBuildAgents(buildServer.CreateBuildAgentSpec(teamProject, buildAgentName));
if (queryResult.Failures.Length > 0 || queryResult.Agents.Length != 1)
{
throw new Exception("Invalid Build Agent");
}
IBuildAgent buildAgent = queryResult.Agents[0];

IBuildDefinition buildDefinition = buildServer.GetBuildDefinition(teamProject,buildDefinitionName);

// Create a build request based on our chosen definition.
IBuildRequest buildRequest = buildDefinition.CreateBuildRequest();
// Optionally set command line args, drop location, priority, custom source version etc here
// in this case just overriding default build agent.
buildRequest.BuildAgent = buildAgent;

buildServer.QueueBuild(buildRequest);


Pretty simple really and very powerful.  I encourage you to go take a look at the IBuildServer interface to see some of the stuff that you can do.  If you have any suggestions as to what you would like to see as a build API example then leave a comment to this post.

April 7, 2008
» Radio TFS #4 - Team System 2008 Development Edition

I've just posted the fourth episode of Radio TFS.  In this episode Paul and Mickey talk about Visual Studio Team System 2008 Development Edition while I ask dumb questions and go off on tangents.  Despite this, it is actually one of our better episodes to date.  So if you are interested and have a spare 35 minutes during a commute or something then please take a listen and let us know what you think.

Click here for a direct link to the show.

Don't forget to subscribe in iTunes, or subscribe in Zune if you have either of those applications installed.

April 3, 2008
» IMTC 2008: Automating Builds with Team Foundation Server 2008

Thanks to everyone who attended my session this afternoon at IMTC 2008 in Dublin.  As promised, here is a copy of the slide deck. 

Also, as mentioned - the Build Wallboard project that we did as a demo is also available at the MSDN Code Gallery here:

http://code.msdn.microsoft.com/buildwallboard

April 2, 2008
» CruiseControl 2.7.2 Released

Jeffrey Fredrick just announced that CruiseControl 2.7.2 is now available for download: http://tinyurl.com/2zm9mz.

There are lots of bug fixes, lots of changes to the Dashboard and some new plug-ins, but the bit that is of most interest to me was (from the release notes)

TeamFoundationServer source control
----------------------
* Fix compatibility with Microsoft Visual Studio Team Foundation Server 2008 (CC-735). Submitted by Martin Woodward.

This was to work around an issue that came up when using CruiseControl (java version) to talk to a TFS2008 server (TFS2005 worked fine and still does).  If you are attempting to use CruiseControl with TFS 2008 then you should go with CruiseControl 2.7.2.  For that matter - if you are using CruiseControl.NET with TFS then you should also take a look at the latest release of the integration to TFS - as that contains the same fix allowing you to happily talk to a 2008 version of Team Foundation Server (also using the TFS 2008 client API's).

Anyway, congratulations to the CruiseControl team on the 2.7.2 release!

March 31, 2008
» New Team System 2008 Virtual PC to Download

UPDATE: Just heard from Brian Randell that the VPC is now ready to download.  Updated links are below.

Anthony Borton just pointed out to me that the new version of the Team System evaluation VPC is available.  The Virtual PC is the best way to easily take Team System for a quick spin, as it comes with everything installed.  This release also contains 38 hands-on labs WITH sample data - awesome work.

I am downloading it right now.  For those folks who are fans of the Free Download Manager, here is a list of URL's that you will need to download the Virtual PC.

http://download.microsoft.com/download/d/7/3/d73b91d4-6daa-4da6-8635-3f10a1b918db/en_visual_studio_team_system_2008_team_suite_and_tfs_rtm_vpc_march2008.part0001.exe
http://download.microsoft.com/download/d/7/3/d73b91d4-6daa-4da6-8635-3f10a1b918db/en_visual_studio_team_system_2008_team_suite_and_tfs_rtm_vpc_march2008.part0002.rar 
http://download.microsoft.com/download/d/7/3/d73b91d4-6daa-4da6-8635-3f10a1b918db/en_visual_studio_team_system_2008_team_suite_and_tfs_rtm_vpc_march2008.part0003.rar 
http://download.microsoft.com/download/d/7/3/d73b91d4-6daa-4da6-8635-3f10a1b918db/en_visual_studio_team_system_2008_team_suite_and_tfs_rtm_vpc_march2008.part0004.rar 
http://download.microsoft.com/download/d/7/3/d73b91d4-6daa-4da6-8635-3f10a1b918db/en_visual_studio_team_system_2008_team_suite_and_tfs_rtm_vpc_march2008.part0005.rar 
http://download.microsoft.com/download/d/7/3/d73b91d4-6daa-4da6-8635-3f10a1b918db/en_visual_studio_team_system_2008_team_suite_and_tfs_rtm_vpc_march2008.part0006.rar 
http://download.microsoft.com/download/d/7/3/d73b91d4-6daa-4da6-8635-3f10a1b918db/en_visual_studio_team_system_2008_team_suite_and_tfs_rtm_vpc_march2008.part0007.rar 
http://download.microsoft.com/download/d/7/3/d73b91d4-6daa-4da6-8635-3f10a1b918db/en_visual_studio_team_system_2008_team_suite_and_tfs_rtm_vpc_march2008.part0008.rar 
http://download.microsoft.com/download/d/7/3/d73b91d4-6daa-4da6-8635-3f10a1b918db/en_visual_studio_team_system_2008_team_suite_and_tfs_rtm_vpc_march2008.part0009.rar 
http://download.microsoft.com/download/d/7/3/d73b91d4-6daa-4da6-8635-3f10a1b918db/VSTS 2008 Hands-on Labs March 2008 Release.msi

Or you can simply visit the download page and download them in your browser if you prefer

http://www.microsoft.com/downloads/details.aspx?FamilyID=c7a809d8-8c9f-439f-8147-948bc6957812&DisplayLang=en

March 27, 2008
» Team System Chat - April 9th

The Team System Chat's are a great way for you to talk direct to very influential members of the product group - the people that actually write the code behind team system.  If you have a query or there is a feature that you would really like then this is a great way of talking to the people direct and getting your feedback heard.

So, join members of the Visual Studio Team System product group to discuss features available in Team Foundation Server, Team Suite, Architecture Edition, Development Edition, Database Edition, and Test Edition. In addition, discuss what's new for these editions for Visual Studio 2008.

Add to Calendar

April 9, 2008, 10am Pacific, 6pm BST
Additional Time Zones

March 18, 2008
» Teamprise 3.0 Ships!

At EclipseCon 2008 this morning, we just announced that Teamprise 3.0 has been released!  If you've been wondering why I have been quiet on the blog lately - but also why anything I have been talking about is Team Foundation Build related, then you are about to find out why :-)  First of all, I'd encourage you to go visit the shiny new website at http://www.teamprise.com.  Our marketing team had too much fun putting that together, including getting a real, live, massive Teamprise power button made up and shipped in a huge crate from New York to be photographed and used as the new site/icon image.

The full release notes are available here, but as has been the tradition for the past few Teamprise releases, I thought I would give you a run down of my favourite new features in the 3.0 release.

At a high level, the features in 3.0 can be summarised as:-

  • Full Team Foundation Build integration (including ability to execute Ant based builds)
  • Check-in policy support
  • Recursive folder compare
  • Single sign-on (from Microsoft Windows machines)
  • "Destroy" command for version control
  • Show deleted items and undelete from Source Control Explorer UI
  • much much more (see release notes)

While it is not my area, I should also mention that we've taken this opportunity to make our licensing more affordable for smaller teams.  We have been very pleasantly surprised by the number of people buying 1 to 20 licenses at a time.  Originally, Teamprise pricing was skewed to the Enterprise customers (i.e. simple, all inclusive and with steep volume discounts).  So we have done a couple of things to help out the smaller companies:-

  • You can now purchase the various components (Teamprise Plug-in for Eclipse, Teamprise Explorer, Teamprise Command Line Client) individually as well as the Teamprise Client Suite which gives you the lot.
  • We have lowered the initial prices for a single seat, meaning that people buying one or two licenses can now get the same discounts that used to only be available to folks purchasing 100.

If you have any licensing issues / queries then feel free to contact me, or you can talk to the sales team direct at sales@teamprise.com.  Anyway - back to the part of this release that I do know about - the technology. 

The first feature I want to talk about is one that I had no involvement with.  It's one of those features that many people will not notice because it just works but anyone who has done any Java to .NET web service interop work will instantly recognise as being a little bit clever.

Single Sign-On

New Teamprise Login Dialog

The initial log-in screen has undergone a big overhaul.  On Windows machines you are given the option to use "default credentials", i.e. the username and password that you are logged onto windows with.  It obviously doesn't know your password, but does some JNI magic to get the native Windows API's to handle the authentication logic with Team Foundation Server.  While you are also on the login screen, you may notice the Profile feature.  This is an area that many people probably won't use, but we added for our power users and for ourselves.  Basically, the profiles feature allows you to store sets of servers/credentials that you commonly use to connect to Team Foundation Server and then you can bring up the details using a simple drop down.  Makes it much easier to switch between your production TFS instance and your CodePlex project for example - or switch credentials if you are a TFS administrator.

Check-in Policy Support

In Visual Studio, check-in policies are implemented as a .NET assembly runs every time a policy is evaluated or configured.  The policy also has full access to the .NET API's, the Visual Studio API's as well as anything it might want to pinvoke out to on the Win32 API side.  As you can imagine, this presented us some problems when we wanted to have check-in policies that ran the same in Eclipse on Windows Vista as Teamprise Explorer on the Mac or Aptana on Ubuntu - therefore we have had to develop a parallel Teamprise check-in policy framework.

Teamprise Check-in Policies

As we were doing this, we took the opportunity to learn from some of the feedback folks have been having with the Visual Studio check-in policies.  While our framework and SDK will look very familiar to anyone that has developed a custom check-in policy for Visual Studio, you will notice some differences.

Firstly, we supply different policies out of the box.  The vast majority of custom check-in polices that people deploy are things like "Check for Comments" etc, so we just shipped the common ones our customers wanted to prevent them from having to write their own.

Secondly, we make use of the Eclipse plug-in framework to implement our policies as extension points.  This means that they are easy to deploy (using the Eclipse update site mechanisms built in to the IDE).  We have also separated the configuration (stored as a blob of XML data in our framework) from the implementation - represented by the plug-in deployed.  The again makes it easier to deploy, especially when it comes to version 2 of a policy...

Thirdly, all of our policies can be scoped by the path in version control to which they correspond - you are not limited to per Team Project scoping and you do not have to wrap your policies in a custom policy to get more detailed scoping like you do with the current Visual Studio framework.

Team Foundation Build Integration

Anyone that has been following this blog for a while, or who attended the Team Build talk I did at TechEd with Brian Randell, will notice that I have been increasingly involved in the inner workings of Team Foundation Build.  Now you can see the fruits of that labour.

Teamprise Build Explorer on Widows Vista

In Teamprise we now have full integration with the shiny new build functionality in TFS 2008 as well as support for TFS 2005.  Backwards compatibility with the TFS 2005 server is very similar to if you were using a Visual Studio 2008 client, accept that ours is slightly more backwards compatible (you can create new builds on a TFS 2005 server as well as manage build qualities etc).  However it is with TFS 2008 that you get to see the majority of the features.  I could go on about this aspect all day as their are so small things that I am proud of, but at a high level you can:

  • View existing build definitions
  • Manage builds in Build Explorer
  • Queue new builds
  • View build report
  • Edit Build Quality
  • Delete build
  • Manage Build Qualities
  • Open Drop Folder
  • New/Edit Build Definition
The following features are only available against a TFS2008 server:
  • Edit Retention Policies
  • Keep Build
  • Set Queue Priority
  • Postpone Build
  • Stop/Cancel Build
  • Delete Build Definition

One of the smaller features I will call out is that from the build definition in the Team Explorer, you can right click and do a "View Build Configuration" that will open the Source Control Explorer at the place in which the TFSBuild.proj file is stored so that you can check it out and edit it.  A feature that I added solely for my own sanity during dogfooding :-). 

Build Explorer on Mac OS 10.5 - click for a higher res image All this would be fairly academic, if you didn't have some way to do a cross-platform build using Team Foundation Build.  In the current release, we provide a the Teamprise Extensions for Team Foundation Build which basically Ant enables the Team Foundation build server.  The Teamprise extensions are a set of MSBuild targets that insert the Ant build process into the standard Team Build mechanism as well as a custom MSBuild We hope to extend this to support in the near future to some of the other common build/test tool-chains in the cross-platform world.  However, the Ant integration case will help a lot number of people out there.

Best yet, the Teamprise Extensions for Team Foundation Build are available free of charge for everyone - wether or not you are a Teamprise customer.  Also, if you want to see how they work and customize them to meet your own non-standard build system then the source is available under the permissive open source Microsoft Public License (MS-PL).

I would personally like to thank the Team Foundation Build Team (especially Buck Hodges and Aaron Hallberg) who have been incredibly helpful through the development of the build functionality in Teamprise 3.0 while they were also busy working on TFS 2008. 

Hopefully that gives you a quick flavour of Teamprise 3.0 and where we are going with this release.  If you head over to the new site now and take a look at the many improvements we've made, we'd love to hear what you think.

March 13, 2008
» CodePlex Project Stats

The fantastic team at CodePlex have just rolled out yet another great feature - this time it is statistics for your CodePlex project.  I dropped by my TFS Plug-in for CruiseControl.NET to take a look...

codeplex_stats 

The project is currently averaging over 12 downloads a day and has had nearly 5000 downloads since I moved it to CodePlex in August 2006.  Not bad for a chunk of code I originally wrote on a plane..

This is incredibly motivating as a maintainer of an Open Source project.  I've been knowing that I need to give the CC.NET integration some love as there are a few issues and things that I need to address from the excellent feedback I have been receiving.  However - seeing how many people are still interested in the plug-in despite the excellent CI functionality in the 2008 release of TFS has made me realise that I need to get on this ASAP.  Thanks CodePlex!

March 6, 2008
» Radio TFS

radiotfs Paul Hacker, Mickey Gousset and I have recently started a Team System related podcast called Radio TFS.

While it is not going to win any awards any time soon, we've been having a lot of fun so we are going to continue to try and get one or two episodes out a month. If you have 40 or so minutes to kill, then feel free to take a listen and subscribe.

If you have any suggestions for topic or any questions about Team System that you would like answered then please drop us a line at radiotfs@gmail.com or visit the website at http://www.radiotfs.com.

February 21, 2008
» DDD is coming to Ireland

DDDLogo Developer Developer Developer is coming to the beautiful west of Ireland in May with GAMTUG hosting the event on Saturday May 3rd.  If you are in or around Ireland at that time then I would encourage you sign up.  My good friend, and fellow Team System MVP, Mike Azocar will be doing a session on Scrum which should be well worth sitting in on.

There will be no Microsoft speakers presenting, just speakers from the .NET developer community, although I hear our local friendly Platform Evangelists (DPEs) will be on hand to help out and chat to everyone and to take in the atmosphere.

The day promises to be a great learning experience, but also a fantastic way to meet like-minded people - if anything else, you get a trip to the lovely Galway which is never a wasted journey.

February 5, 2008
» Aligning Build Numbers with Assembly Versions in TFS2008.

I like my build numbers to be the same number that my assemblies are versioned with (and my end deliverables).  It just makes things easier to track, that way if I get a bug report in from a customer I can look at the version and easily look at the label in source control to see what code that included. In all deliverables provided to the customer, we always output the version obtained from the current assembly somewhere at the start of any diagnostic information, that way you can easily tell what version they are on and instantly track this back.  This all helps to make it easy for bugs to be filed against the correct version and reported in which version they have been fixed (using the nice integration between Team Build and the Work Item tracking portion of TFS).

People are often surprised that this feature does not work "out the box" with Team Build, so I thought I would just take the time to document how I made this work for us internally.  As you'll be able to see, in TFS2008 all the basic hooks are provided for us to support this way of working.

Firstly, our .NET version numbering uses a slightly different scheme to our Java version numbering.  In our Java products, the "build number" portion of the version number is actually the changeset number of TFS at that point in time.  In .NET there are 4 components to a typical assembly version number (1.0.1234.5678) and the maximum value for each number is 65535.  Our production TFS server is currently at changeset 7698 which means that we would get about 6 years out of such a build numbering scheme for .NET - that would be perfectly satisfactory if you had a changeset epoch after each major release (so you would reset the build number to be current changeset - 7698 if we did a major version today).  However Team Build needs a unique name for each build - using a changeset based approach risks having two builds with the same build number.  So rather than do a changeset based system, I decided to make the .NET build numbers be a straight-forward incrementing number. I rely of the default functionality of Team Build to create a label for that build number to track the number back to version control.  The incrementing number value is stored in a file on the default drop location for the build.

Another thing that I should explain is that I don't personally like the "standard" Microsoft way of versioning assemblies as:-

<Major>.<Minor>.<Build>.<Service>

To me, it reads much easier as:-

<Major>.<Minor>.<Service>.<Build>

Where <Build> is the number that increments every time a build is performed.  As far as I am concerned, this difference is mostly cosmetic as it doesn't change the way the CLR resolves the assembly versions, however feel free to correct me in the comments if I am talking rubbish.

So - onto how we accomplish this.  Firstly, in TFS2008 there is a convenient target for you to override to generate your custom build numbers called "BuildNumberOverrideTarget".  The important thing is that each build number must be unique, therefore a good rule of thumb is to use something like BuildDefinitionName_1.0.0.1234.  Inside the BuildNumberOverrideTarget you simply set "BuildNumber" property to be what you want.  Here is ours:-

<PropertyGroup> 
  <VersionMajor>1</VersionMajor> 
  <VersionMinor>0</VersionMinor> 
  <VersionService>0</VersionService> 
  <VersionBuild>0</VersionBuild> 
</PropertyGroup>
<Target Name="BuildNumberOverrideTarget"> 
  <!-- Create a custom build number, matching the assembly version -->      
  <Message Text="Loading last build number from file &quot;$(DropLocation)\buildnumber.txt&quot;" /> 
  <IncrementingNumber NumberFile="$(DropLocation)\buildnumber.txt"> 
    <Output TaskParameter="NextNumber" PropertyName="VersionBuild" /> 
  </IncrementingNumber> 
  <PropertyGroup> 
    <BuildNumber>$(BuildDefinitionName)_$(VersionMajor).$(VersionMinor).$(VersionService).$(VersionBuild)</BuildNumber> 
  </PropertyGroup> 
  <Message Text="Build number set to &quot;$(BuildNumber)&quot;" />  
</Target>

The first thing I do is call a quick custom task I wrote that increments the build number stored in the passed file.  I wanted to do this while keeping a lock on the file itself in case two builds tried to update the same file at the same time.  We then take this new number and build the BuildNumber based upon that value.  The code for the Incrementing Number task is very simple and is given below:-

using System; 
using System.IO; 
using Microsoft.Build.Framework; 
using Microsoft.Build.Utilities; 

namespace Teamprise.Tasks
{
/// <summary>
/// A simple task to increment the number stored in a passed file.
/// </summary>
public class IncrementingNumber : Task
{
public override bool Execute()
{
NextNumber = IncrementNumber();
return true;
}
public int IncrementNumber()
{
using (FileStream fs = new FileStream(NumberFile, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None))
{
StreamReader reader = new StreamReader(fs);

long pos = 0;
String line = reader.ReadLine();

// Ignore comments in file
while (line != null && line.StartsWith("#"))
{
pos = pos + line.Length + System.Environment.NewLine.Length;
line = reader.ReadLine();
}

int number = -1;
if (line != null)
{
number = Int32.Parse(line);
}
NextNumber = number + 1;

// Rewind the file stream back to the beginning of the number part.
fs.Position = pos;

StreamWriter writer = new StreamWriter(fs);
writer.WriteLine(NextNumber.ToString());
writer.Flush();
writer.Close();
}
return NextNumber;
}
[Required]
public string NumberFile { get; set; }
[Output]
public int NextNumber { get; set; }
}
}


You compile this code into an assembly of your choice that lives alongside the TFSBuild.proj file in the build configuration folder in source control and is this loaded using the UsingTask call at the begging of your MSBuild project, i.e.

<UsingTask TaskName="Teamprise.Tasks.IncrementingNumber" 
           AssemblyFile="Teamprise.Tasks.dll" />

The next thing that we have to do is to take the new version and force this into the assemblyinfo files.  Personally, I prefer the AssemblyInfo files stored in source control to have a certain well defined number for each release branch (i.e. 1.0.0.0), and make it the build server that versions them.  Some people like to check these back into source control - if you do that, be sure to check them in with the special comment of "***NO_CI***" to ensure that the check-in does not trigger any CI builds potentially putting you into an infinite loop of building.

So, we modify our assembly version files after they have been downloaded from source control using a technique borrowed from Richard Banks, our interpretation of this is given below:-

<ItemGroup> 
  <AssemblyInfoFiles Include="$(SolutionRoot)\**\assemblyinfo.cs" /> 
</ItemGroup>   
<Target Name="AfterGet"> 
  <!-- Update all the assembly info files with generated version info --> 
  <Message Text="Modifying AssemblyInfo files under &quot;$(SolutionRoot)&quot;." /> 
  <Attrib Files="@(AssemblyInfoFiles)" Normal="true" /> 
  <FileUpdate Files="@(AssemblyInfoFiles)"                                 
              Regex="AssemblyVersion\(&quot;.*&quot;\)\]"                 
              ReplacementText="AssemblyVersion(&quot;$(VersionMajor).$(VersionMinor).$(VersionService).$(VersionBuild)&quot;)]" /> 
  <FileUpdate Files="@(AssemblyInfoFiles)" 
              Regex="AssemblyFileVersion\(&quot;.*&quot;\)\]" 
              ReplacementText="AssemblyFileVersion(&quot;$(VersionMajor).$(VersionMinor).$(VersionService).$(VersionBuild)&quot;)]" /> 
  <Message Text="AssemblyInfo files updated to version &quot;$(VersionMajor).$(VersionMinor).$(VersionService).$(VersionBuild)&quot;" /> 
</Target>

As you can see, we are making use of the custom Attrib task that is provided by the essential MSBuild Community Tasks to set the files to read/write and then we are calling the MSBuild Community Task FileUpdate to do a couple of regular expression search replaces on the appropriate parts of the files.

And that's about all that needs to be done.  Now our builds have nice incrementing numbers that have the version number included that is the same as the assembly info files.


January 28, 2008
» Upgrading from TFS 2008 Trial to TFS 2008 Full

One of the most frequent questions I get when talking to people about TFS if how to upgrade from the freely downloadable 90-day TFS 2008 trial to a full version of TFS.  Our TFS 2008 license key arrived at the weekend, so I thought I would take the opportunity to record the process.  The first two steps have nothing to do with installing your license key, just purchasing it - but sadly are often the most complicated.  Installing the actual key once received, is pretty trivial as I hope you will see.

Step 1:  Purchase a TFS License Key.

This step is frequently mis-understood.  You have to pay for the full version of TFS.  Just because you are a partner of an MSDN subscriber, doesn't mean that you get TFS included.  As an MSDN Subscriber, depending on your subscription type you do get access to a 5-user limited version of TFS called "Team Foundation Server Workrgoup Edition".  However only Gold Partners or Partners with an ISV Competency get TFS included in their partner fees - everyone else has to purchase it.  When connecting to TFS, you also need to make sure you have enough Team Foundation Server Client Access Licenses (CAL's) to cover your use - if you have a Team Suite flavor of MSDN then that gives you one CAL.

Step 2: Obtain TFS License Key.

The license key for TFS will be printed on a little sticker on the back of the media that it arrives on.  If it didn't (perhaps because you purchased TFS via a volume licensing agreement) then there are ways around this to get the license key out of the media (look for a file called setup.sdb and open it in Notepad, look for [Product Key], usually at the bottom of the file, and you will find it there).

Because getting a TFS License Key usually involves the physical delivery of the media, you should make sure that you factor this time into your purchasing decision.  If (like most people) your purchasing process takes longer than you budgeted for - then you do have the ability to extend your TFS Trial by an additional 30-days.

Step 3: Enter TFS Maintanence Mode

Go to, Control Panel, Add Remove Programs.

 Add / Remove Programs

Then find Microsoft Visual Studio 2008 Team Foundation Server in the list and press Change/Remove

Team Foundation Server Maintanence Mode

Step 4: Enter the Full Key for TFS

At the bottom of the maintenance dialog, you have the option to enter your full license key. 

TFS2008 Maintence Dialog

Note that there was a bug in the RTM version of TFS 2008 that means that workgroup edition doesn't have the ability - see this post for details.  This is TFS 2008 90-day trial, so it works just fine for us.

Enter your license key and press Next.  Note that this will install the license key and fire up a command window for a few seconds while it restarts IIS for the TFS server.  Once you are finished, you will get the following dialog.

License upgrade complete

And you are complete.  If you really want to check that the new license key has taken hold, then you can fire up a copy of Brian Harry's VersionDetection tool to set your mind at rest.

Version Detection tool showing that my TFS has a proper license key installed.

And there you go - running the final release (9.0.21022.8) with no expiry date :-)

January 23, 2008
» Accessing Team Build logs over the WAN

In a previous post, I talked about how Windows file sharing sucks over the WAN. This is particularly annoying for me when trying to view the log of a TFS Build - especially if that build has failed and I want to know why in a hurry. On my computer (sitting on the end of a VPN nearly 4000 miles from my TFS instance), there is a delay of about 50-70 seconds to view the log file depending on the size and the speed of the link at that moment in time.  During that time, Visual Studio is hanging waiting for the file to open.  The issue is compounded by the fact that the rest of the Team Build UI - and in fact the whole of TFS access in general - is so speedy over the same VPN link, that I really notice the time delay accessing build logs.

Therefore - it didn't take too many 70-seconds delays for me to fire up a second instance of Visual Studio to create a work-around.  In Visual Studio 2008 (and in the upcoming Teamprise 3.0 Team Build integration), if the log location provided is not a UNC style path (i.e. \\server\drop\build\BuildLog.txt) but a http:// address, then it will open the file in a browser instead.  Accessing the build log over http helps in two important ways.

  1. HTTP is much less latency sensitive than accessing a file from a Windows share
  2. A browser will display the contents of the file before it has finished loading.  When accessing the build log directly from a file share, the application (i.e. Notepad) will have to wait until it has recieved the whole file before displaying any of it to you.  These log files can get large - so the improvement in perceived speed is significant. (http:// urls are a lot more cross-platform friendly than UNC paths as well, which is nice for us Teamprise folks).

Therefore, I created  a quick and dirty ASP.NET page that accessing the build log for a particular build over the network and streams the contents of a build log to the browser.  I then add a target into my TFSBuild.proj file that sets the log location to be the http url rather than the default UNC address.

LogView ASP.NET Page

I am by no means an ASP.NET expert - so please feel free to highlight any glaring stupidity on my part if you know better.  I know the code below is sub-optimal and presents some security considerations, however it is a quick work-around that I spent a couple of minutes over to solve my issue - so please treat this code as just that.

Create a new Web Application Project, with references to Microsoft.TeamFoundation.Client and Microsoft.TeamFoundation.Build.Client assemblies.  Create a new aspx page - mine is called view.aspx.  In the page mark-up, ensure it only contains the Page tag, and an output caching directive.  Mine (which is in a C# project) looks like this.

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="view.aspx.cs" Inherits="LogViewer._Default" %>
<%@ OutputCache Duration="2592000" Location="Server" VaryByParam="*" %>

Now - the work is performed in the code behind.  

  1 using System;
  2 using System.IO;
  3 using Microsoft.TeamFoundation.Build.Client;
  4 using Microsoft.TeamFoundation.Build.Common;
  5 using Microsoft.TeamFoundation.Client;
  6 
  7 namespace LogViewer
  8 {
  9     public partial class _Default : System.Web.UI.Page
 10     {
 11         protected void Page_Load(object sender, EventArgs e)
 12         {
 13             Response.Write("<html>");
 14             string teamFoundationServerUrl = Request.Params["TeamFoundationServerUrl"];
 15             string buildUri = Request.Params["BuildUri"];
 16 
 17             if (String.IsNullOrEmpty(teamFoundationServerUrl))
 18             {
 19                 teamFoundationServerUrl = "http://localhost:8080";
 20             }
 21 
 22