Way back in 2008, a post on the blogs.msdn site showed how to create a custom MSBuild task to associate changesets and work items only since the last successful build. Recently I needed to write this custom task myself, but for builds that were “PartiallySuccessful” as well as “Successful”, and was pleased to find such a complete target available. However as it is written for TFS 2008 it won't work with TFS 2010 onwards. As the blog appears to be inactive now I've made the changes and put the code below. Hopefully anyone who needs it for TFS 2010 onwards can use the pingback to get here for the up to date code. The rest of the solution works fine.

If you've never created a custom task before then the link below should help.

http://tech.pro/tutorial/934/creating-msbuild-tasks-in-csharp

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Build.Framework;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Build.Client;

namespace BuildTasks
{
public class GetLastSuccessfulBuildLabel : ITask
{

#region Properties

[Required]
public String BuildDefinitionName
{
get
{
return m_buildDefinitionName;
}
set
{
m_buildDefinitionName = value;
}
}

[Output]
public String LastSuccessfulBuildLabel
{
get
{
return m_lastSuccessfulBuildLabel;
}
}

[Required]
public String TeamFoundationServerUrl
{
get
{
return m_teamFoundationServerUrl;
}
set
{
m_teamFoundationServerUrl = value;
}
}

[Required]
public String TeamProject
{
get
{
return m_teamProject;
}
set
{
m_teamProject = value;
}
}

#endregion

#region ITask Members

public bool Execute()
{
TfsTeamProjectCollection tfs = new TfsTeamProjectCollection(new Uri(TeamFoundationServerUrl));
IBuildServer buildServer = (IBuildServer)tfs.GetService(typeof(IBuildServer));

IBuildDetailSpec spec = buildServer.CreateBuildDetailSpec(TeamProject, BuildDefinitionName);
spec.MaxBuildsPerDefinition = 1;
spec.Status = BuildStatus.Succeeded | BuildStatus.PartiallySucceeded;
spec.QueryOrder = BuildQueryOrder.FinishTimeDescending;

IBuildQueryResult queryResult = buildServer.QueryBuilds(spec);

if (queryResult.Builds.Length > 0)
{
m_lastSuccessfulBuildLabel = queryResult.Builds[0].LabelName;
}

return true;
}

public IBuildEngine BuildEngine
{
get
{
return m_buildEngine;
}
set
{
m_buildEngine = value;
}
}

public ITaskHost HostObject
{
get
{
return m_taskHost;
}
set
{
m_taskHost = value;
}
}

#endregion

#region Private Members

private IBuildEngine m_buildEngine;
private ITaskHost m_taskHost;
private String m_teamFoundationServerUrl;
private String m_buildDefinitionName;
private String m_teamProject;
private String m_lastSuccessfulBuildLabel;

#endregion
}
}