Queue another Team Build when one Team Build succeeds

Update: with Team Build 2013 you can even pass parameters to queued builds.

I have seen several Team Foundation Server environments where multiple build definitions exist in a single project and need to executed in a particular order. Two common techniques to achieve this are:

  • Queue all the builds immediately and rely upon using a single build agent to serialize the builds. This approach prevents parallelization for improved build times and continues to build subsequent builds even when one fails.
  • Check build artifact(s) into source control at the end of the build and let this trigger subsequent builds configured for Continuous Integration. This approach can complicate build definition workspaces and committing build artifacts to the same repository as code is not generally recommended.

As an alternative I have developed a simple customization to TFS 2010’s default build process template (the DefaultTemplate.xaml file in the BuildProcessTemplates source control folder) that allows a build definition to specify the names of subsequent builds to queue upon success. It only requires two minor changes to the Xaml file. The first is a line inserted immediately before the closing </x:Members> element near the top of the file:

    <x:Property Name="BuildChain" Type="InArgument(s:String[])" />

The second is a block inserted immediately before the final closing </Sequence> at the end of the file

    <If Condition="[BuildChain IsNot Nothing AndAlso BuildChain.Length &gt; 0]" DisplayName="If BuildChain defined">
      <If.Then>
        <If Condition="[BuildDetail.CompilationStatus = Microsoft.TeamFoundation.Build.Client.BuildPhaseStatus.Succeeded]" DisplayName="If this build succeeded">
          <If.Then>
            <Sequence>
              <Sequence.Variables>
                <Variable x:TypeArguments="mtbc:IBuildServer" Default="[BuildDetail.BuildDefinition.BuildServer]" Name="BuildServer" />
              </Sequence.Variables>
              <ForEach x:TypeArguments="x:String" DisplayName="For Each build in BuildChain" Values="[BuildChain]">
                <ActivityAction x:TypeArguments="x:String">
                  <ActivityAction.Argument>
                    <DelegateInArgument x:TypeArguments="x:String" Name="buildChainItem" />
                  </ActivityAction.Argument>
                  <Sequence DisplayName="Queue chained build">
                    <Sequence.Variables>
                      <Variable Name="ChainedBuildDefinition" x:TypeArguments="mtbc:IBuildDefinition" Default="[BuildServer.GetBuildDefinition(BuildDetail.TeamProject, buildChainItem)]"/>
                      <Variable  Name="QueuedChainedBuild" x:TypeArguments="mtbc:IQueuedBuild" Default="[BuildServer.QueueBuild(ChainedBuildDefinition)]"/>
                    </Sequence.Variables>
                    <mtbwa:WriteBuildMessage Message="[String.Format(&quot;Queued chained build '{0}'&quot;, buildChainItem)]" Importance="[Microsoft.TeamFoundation.Build.Client.BuildMessageImportance.High]" />
                  </Sequence>
                </ActivityAction>
              </ForEach>
            </Sequence>
          </If.Then>
        </If>
      </If.Then>
    </If>

You can see the resulting DefaultTemplate.xaml file here. After applying these changes and checking-in the build process template file you can specify which builds to queue upon success via the Edit Build Definition windows in Visual Studio:

The new BuildChain build process parameter

You can specify the names of multiple Build Definitions from the same Team Project each on a separate line. When the first build completes successfully, all builds listed in the BuildChain property will then be queued in parallel and processed by the available Build Agents. No checking is currently done for circular dependencies so be careful not to chain a build to itself directly or indirectly and create an endless loop.

2 comments

  1. Nikita Pinchuk (@freed_dimarzio)

    Very Useful and simple! Especially if you want to trigger heavy build with functional testing, lab deployment etc. after initial simple CI build with unit tests is finished. Can you suggest a simple way to reuse artefacts of the first build from the chain one (like binaries, test results, code analysis results..)

  2. Jason Stangroome

    Hi Nikita,

    To propagate artefacts to chained builds I’d consider changing the template to pass an IBuildRequest to the QueueBuild method instead of the IBuildDefinition argument. The build request’s ProcessParameters property could be used to provide the current build number to the newly queued build which could then use that information to locate the drop folder, etc.

    Regards,

    Jason