16

I have a scenario where I want to call one TFS build from another, the first one does the build and the second one does staging. This will allow me do multiple custom staging for the same solution.

I know, I can pull this off with an exec task in the second build and call tfsbuild.exe to queue a build from the first build definition. But was wondering if someone knew of a better way?

Daniel Mann
  • 57,011
  • 13
  • 100
  • 120
user22242
  • 432
  • 3
  • 13

4 Answers4

7

It depends what you are trying to do.

1) Do you want the build + staging to run as one operation? So that you end up with one consolidated build report, one log file, one job in the server's build queue, every step executed sequentially by the same Build Agent that executed the previous step?

If so, then you are on basically the right path. I wouldn't <Exec> out to tfsbuild.exe though -- running an entire new build has a lot of overhead, and I'm not sure what the potential side effects are. Instead, I would use the <Call> task to execute msbuild tasks defined in your staging script(s).

2) Do you want the "build build" to actually queue a separate "staging build"? Separate reports, log files, & spots in the queue? Opportunity to be executed in parallel if you have multiple Build Agents?

If so, then:

  • create a new build definition(s) for staging
  • add some code to your original build definition that queues [one/several] of the new build definitions using the Team Build API. Sample code.
  • remove anything not related to the core build from the original build definition
  • make sure the new "staging" definitions don't have any automatic triggers (time intervals, checkin events, etc)
Richard Berg
  • 20,629
  • 2
  • 66
  • 86
  • Preferably step 1, but task cannot be used as you suggest. The staging build needs to be driver of the build in this case. It calls the core build and then does its custom staging. The problem with using a Minimal tfsbuild proj file is that, TFSBuild definition file created via the UI sets all path properties based on the solution picked to be built.(as we agree, staging build definition should not rebuild the solution) So is a pain to get the paths configured to call the right core TFSBuild.proj file without hardcoding them. – user22242 Jul 27 '09 at 03:50
  • I don't understand the problem. Why not store your staging scripts in the same directory as your build scripts? Actually, even that is not necessary -- just ensure the relative paths stay the same. ///// If that doesn't help, please give more detail on what you're trying to do. What are the exact things you expect to happen in the "first build" and "second build?" What tasks do they have in common, and what needs to be customized? – Richard Berg Jul 31 '09 at 19:37
  • BTW, depending on what you're trying to do, Team Build might not be the right approach at all. For instance, my test environments are setup on a "pull" model instead of "push". Each machine subscribes to the TFS notification system. When a BuildCompletion event is raised, a service on the machine checks against various criteria configured for that box and redeploys a test environment as appropriate. – Richard Berg Jul 31 '09 at 19:49
5

Here is how I accomplished this (http://sajojacob.com/2009/08/how-to-chain-tfs-builds/)

How to Chain TFS Builds? Posted on August 5, 2009 by Sajo — No Comments ↓

One of my colleagues @gdurzi recently asked me this question. Sounds straightforward enough to be supported out of the box with TFS right? Too many quirks with this. And I recommended using the ever faithful MSBuild task to make a call to TFSBuild.exe to queue a new build from the first TFSBuild.proj with something like this

TFSBuild.exe start /queue %TFSSVR% %TEAMPROJECT% %BUILDTYPE%

An issue with using TFSBuild.exe is that you cannot pass Build agents as a command line argument which was a deal breaker for us.

There are several approaches that you can take based on your particular scenario so let’s define the scenario here, you have a Main_Build TFS build definition that builds your core project and you want the ability to have multiple staging builds running the same Main_Build for compilation/building, but be custom staged for deployment based on who calls Main_Build. Very useful when you have a product which rolls out to multiple clients with a need for custom pre-build and post-build actions per client. So here is one way to do Build Chaining with TFS 2008.

Step 1: Let’s create a custom MSBuild task using the Team Foundation object model which queues a build using the default build agent associated with the Build definition file.

Sample code for Queuing: QueueTFS.cs

using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Build.Client;

// Get the team foundation server. 
TeamFoundationServer _tfsServer = TeamFoundationServerFactory.GetServer(_tfs); 

// Get the IBuildServer 
IBuildServer buildServer = (IBuildServer)_tfsServer.GetService(typeof(IBuildServer)); 

// Get the build definition for which a build is to be queued. 
IBuildDefinition definition = buildServer.GetBuildDefinition(teamProject, buildDefinition); 

// Create a build request for the build definition. 
IBuildRequest request = definition.CreateBuildRequest(); 
request.CommandLineArguments = "Pass any custom command line args here"; // Ex: Custom Targets file

// Queue the build. 
buildServer.QueueBuild(request, QueueOptions.None);

Step 2: Now copy the QueueTFS.dll to a new folder in TFS where you want to create the staging Build definition file.

Now let’s create a minimal TFSBuild.proj file which uses our new MSBuild task and overrides the EndToEndIteration target. This will be our Staging build definition which will trigger the Main_Build build. Note that you will have to create this TFSBuild.proj by hand and simply point the project file location from the Build definition UI to the new folder.

Sample code for a minimal TFSBuild.proj:

<?xml version="1.0" encoding="utf-8"?> 
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5"> 
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\TeamBuild\Microsoft.TeamFoundation.Build.targets" /> 
  <UsingTask TaskName="MyNewCustomTFSTask" AssemblyFile="QueueTFS.dll"/> 
  <Target Name="EndToEndIteration"> 
    <Message Text="About to trigger main build" Importance="high"/> 
    < MyNewCustomTFSTask TFS="http://TFSServer.com:8080/" TeamProject="TeamProject" BuildDefinition="Main_Build" TargetsFile="Custom.Target" XYZ="XYZ" /> 
    <!-- When everything is done, change the status of the task to "Succeeded" --> 
    <SetBuildProperties TeamFoundationServerUrl="$(TeamFoundationServerUrl)" BuildUri="$(BuildUri)" TestStatus="Succeeded" CompilationStatus="Succeeded"/> 
  </Target> 
</Project>

Step 3: Edit your Main_Build TFSBuild.proj file with the pre-build and post-build target calls.

  <Target Name=“BeforeCompile“>

    <CallTarget Targets=“Custom_PreBuild“/>    

  </Target>

  <Target Name=“AfterDropBuild“ Condition=“‘$(BuildBreak)’!=’true’“>    

    <CallTarget Targets=“Custom_PostBuild“/>

  </Target>

We wanted the ability to run Main_Build by itself as well, to support this we add conditional imports in our Main_Build TFSBuild.proj to import a default targets file with empty Custom_PreBuild and Custom_PostBuild targets. $(CustomTarget) is what you would pass as a command line argument in Step 1 for request.CommandLineArguments

<Import Project="$(CustomTarget)" Condition="'$(CustomTarget)'!=''"/>
<!--Import CustomContoso.Target if no partner is passed in—>
<Import Project="EmptyCustom.Target" Condition="'$(CustomTarget)'==''"/> 

Step 4: Now create your targets file Custom.Target and EmptyCustom.Target with Custom_PreBuild and Custom_PostBuild targets and you are done.

I added support for updating build steps and a few other minor things which outside the scope of this blog post, but this should hopefully get you started.

DeanOC
  • 7,142
  • 6
  • 42
  • 56
user22242
  • 432
  • 3
  • 13
1

Here are other helpful links. It might help others.

Create another Build Definition and call other build definitions to be triggered.

http://blogs.objectsharp.com/post/2012/02/04/Create-a-Master-Build-that-calls-other-Builds.aspx

http://blog.stangroome.com/2011/09/06/queue-another-team-build-when-one-team-build-succeeds/

Passing Arguments to Child Builds.

http://blog.stangroome.com/2014/02/19/queue-a-team-build-from-another-and-pass-parameters/

TFS Build Extension to Queue another Build Definition

http://tfsbuildextensions.codeplex.com/

Sai
  • 1,376
  • 2
  • 15
  • 25
0

Are you trying to deploy your solution to your staging environment? If so a good method is to use TFSDeployer from codeplex which will run a diferent PowerShell script based on the build quality that you select...

  • 1
    I can rather do it in CC instead of dealing with learning curve for TFSDeployer for a rather simple task like this. Why should it be that difficult to do something so straightforward in TFS that you need to rely on other tools? I'm surprised not many people are even talking about chained TFS builds – user22242 Jul 28 '09 at 16:58
  • 3
    Chained build would knock my version numbering out. I use a single build to build all of the "Artifacts" and then I need to deploy it to DEV then System Test then QA then Beta and finaly Live. This is done so there is absolutly no posability of a contaminated build (developer checkin). If there is a problem then we go back to DEV. This is done on every feature branch untill it is passed QA/UAT before being merged into main and the Branched for a release. :) – MrHinsh - Martin Hinshelwood Jul 29 '09 at 07:22
  • @MrHinsh-MartinHinshelwood This is correct approach. Build once deploy many – SoftwareCarpenter Mar 28 '19 at 13:32