Filtering the Build Status Change Event (BuildStatusChangeEvent)

In an previous post (long long ago), I described some scenarios around why you would want to subscribe to change the work item tracking subscription to the build completion event. The purpose there was to help users "correct" the subscription that came out of the box. In this post, I would like to answer a question I got from a user about how to subscribe to the other build event - BuildStatusChangeEvent. The question was basically this: How do I get notified when the build quality changes from 'X' to 'Y'?

First, let me say that the name of this event is all wrong. It does not fire when the status of a build changes, but rather when the quality field of the build changes. In the future, it may do more, but not for now. The name aside, it is important to look at the structure of the xml that is sent when the event fires. It is actually very short. Here is an example:

<?xml version="1.0" encoding="utf-16"?><BuildStatusChangeEvent xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="https://www.w3.org/2001/XMLSchema">
  <TeamFoundationServerUrl>https://jpricket-test:8080</TeamFoundationServerUrl>
  <TeamProject>TestProj</TeamProject>
  <Title>TestProj Build CSharp_Tests_20080507.3 Quality Changed To Ready for Deployment</Title>
  <Id>CSharp_Tests_20080507.3</Id>
  <Url>https://jpricket-test:8080/Build/Build.aspx?artifactMoniker=9</Url>
  <TimeZone>Eastern Daylight Time</TimeZone>
  <TimeZoneOffset>-04:00:00</TimeZoneOffset>
  <ChangedTime>5/9/2008 3:05:33 PM</ChangedTime>
  <StatusChange>
    <FieldName>Quality</FieldName>
    <OldValue>Lab Test Passed</OldValue>
    <NewValue>Ready for Deployment</NewValue>
  </StatusChange>
  <ChangedBy>NORTHAMERICA\jpricket</ChangedBy>
</BuildStatusChangeEvent>

The important bit is under the StatusChange node which also makes it a little more interesting than the last post that I did. To filter this event in any useful way requires you to know a little more about XPath. Or at least how the "path" to the OldValue and NewValue fields are formed. It's actually pretty simple. Ignore the root node BuildStatusChangeEvent and then use a slash between each node that you need to reference in the path. For example, if you want to filter on the NewValue field, you might want to use the filter expression 'StatusChange/NewValue'='Ready for Deployment'.

Finally, here are some scenarios that you might find yourself in:

  1. I want to be notified when a build is marked as "Released"
  2. I want to be notified when the build quality is removed (only applies to 2008 and above)
  3. I want to be notified when the build changes from "Rejected" to "Released"

And here are the filters that correspond to those scenarios:

  1. 'StatusChange/NewValue'='Released'
  2. 'StatusChange[count(NewValue) = 0]' <> null AND 'StatusChange[count(OldValue) > 0]' <> null
  3. 'StatusChange/OldValue'='Rejected' AND 'StatusChange/NewValue'='Released'

The first and last are exactly what you might expect. But the second filter was quite a challenge. It turns out that when OldValue or NewValue are null, they are not included in the XML at all. So, to see if NewValue was set to null, we have to get the StatusChange nodes that have a count of NewValue nodes equal to zero. If any StatusChange nodes are returned then that half of the filter is true. The other half is just the opposite. We want to make sure that the StatusChange node has at least 1 OldValue field. The syntax of the xPath query is a little hard to get right, but it does exactly what we want.

Hopefully, this will help you with this and other TFS Events! I have attached the code that I used to add these subscriptions to my server. It is very similar to the code in my previous post.

SubscribeToBuildQualityChanged.zip