Implementing Release Notes in TFS Team Build 2010
- by Jakob Ehn
In TFS Team Build (all versions), each build is associated with changesets and work items. To determine which changesets that should be associated with the current build, Team Build finds the label of the “Last Good Build” an then aggregates all changesets up unitl the label for the current build. Basically this means that if your build is failing, every changeset that is checked in will be accumulated in this list until the build is successful. All well, but there uis a dimension missing here, regarding to releases. Often you can run several release builds until you actually deploy the result of the build to a test or production system. When you do this, wouldn’t it be nice to be able to send the customer a nice release note that contain all work items and changeset since the previously deployed version? At our company, we have developed a Release Repository, which basically is a siple web site with a SQL database as storage. Every time we run a Release Build, the resulting installers, zip-files, sql scripts etc, gets pushed into the release repositor together with the relevant build information. This information contains things such as start time, who triggered the build etc. Also, it contains the associated changesets and work items. When deploying the MSI’s for a new version, we mark the build as Deployed in the release repository. The depoyed status is stored in the release repository database, but it could also have been implemented by setting the Build Quality for that build to Deployed. When generating the release notes, the web site simple runs through each release build back to the previous build that was marked as Deplyed, and aggregates the work items and changesets: Here is a sample screenshot on how this looks for a sample build/application The web site is available both for us and also for the customers and testers, which means that they can easily get the latest version of a particular application and at the same time see what changes are included in this version. There is a lot going on in the Release Build Process that drives this in our TFS 2010 server, but in this post I will show how you can access and read the changeset and work item information in a custom activity. Since Team Build associates changesets and work items for each build, this information is (partially) available inside the build process template. The Associate Changesets and Work Items for non-Shelveset Builds activity (located inside the Try Compile, Test, and Associate Changesets and Work Items activity) defines and populates a variable called associatedWorkItems You can see that this variable is an IList containing instances of the Changeset class (from the Microsoft.TeamFoundation.VersionControl.Client namespace). Now, if you want to access this variable later on in the build process template, you need to declare a new variable in the corresponding scope and the assign the value to this variable. In this sample, I declared a variable called assocChangesets in the RunAgent sequence, which basically covers the whol compile, test and drop part of the build process: Now, you need to assign the value from the AssociatedChangesets to this variable. This is done using the Assign workflow activity: Now you can add a custom activity any where inside the RunAgent sequence and use this variable. NB: Of course your activity must place somewhere after the variable has been poplated. To finish off, here is code snippet that shows how you can read the changeset and work item information from the variable. First you add an InArgumet on your activity where you can pass i the variable that we defined. [RequiredArgument]
public InArgument<IList<Changeset>> AssociatedChangesets { get; set; }
Then you can traverse all the changesets in the list, and for each changeset use the WorkItems property to get the work items that were associated in that changeset:
foreach (Changeset ch in associatedChangesets)
{
// Add change
theChangesets.Add(
new AssociatedChangeset(ch.ChangesetId,
ch.ArtifactUri,
ch.Committer,
ch.Comment,
ch.ChangesetId));
foreach (var wi in ch.WorkItems)
{
theWorkItems.Add(
new AssociatedWorkItem(wi["System.AssignedTo"].ToString(),
wi.Id,
wi["System.State"].ToString(),
wi.Title,
wi.Type.Name,
wi.Id,
wi.Uri));
}
}
NB: AssociatedChangeset and AssociatedWorkItem are custom classes that we use internally for storing this information that is eventually pushed to the release repository.