How to chain builds in TFS 2015?
Is there a way in TFS 2015 to have two builds such that the second build gets triggered whenever the first one finishes (successfully)? There are solutions for the old XAML based build system, but nothing for the new script-based system, which is what I'm using.
Solution 1:
I achieved the "chaining" of builds by creating a custom BuildTask which basically just makes the appropriate calls to the TFS REST Api. It allows me then to define a build definition (by name) that I want to trigger and on top add some conditions (for example check if there is a build of this definition already queued or check if the last build of a certain definition was successful).
If there is any interest, I uploaded the source code to github.
Using tfx you can upload the task to your TFS see details here
In short just grab the files from github, install tfx via node and run
tfx build tasks upload --task-path ./triggerbuildtask
After this you can select the Trigger new Build Task and configure it:
Hope this may help some people that try to achieve the same thing.
Edit
I packaged the task and published it on the Marketplace, so it makes it easy to use the task in your environment:
Trigger Build Task
Solution 2:
This question pops up every now and then. The official docs literally say "not yet" (see the last Q&A entry). There's also an ancient suggestion on UserVoice, which is in the Planned state since March this year. That's quite promising and lets me hope this will be implemented in vNext build system the first thing.
Solution 3:
This answer only applies if:
- You use Git with TFS2015
- You want to chain-build submodules under superprojects
- All of the builds in question are Continuous Integration builds.
If this is the case, then you can "chain-build" by cheating (it works for me):
- In each of the submodules add a batch file (committed to source control) with a script that re-adds the latest commit on this submodule's branch (that's being built) to its superproject. The intended (side-)effect of this is to introduce a "change" in the state of the superproject, sufficient to trigger a CI build on that superproject.
- In the build definitions for each submodule, add a "Batch Script" vNext step.
- Point that step at the batch file for the corresponding submodule.
- This build step needs to be the last step of your build to ensure that it only executes if the build is successful, then do its "mod" and trigger the CI build on the superproject.
To get you started, see a sample script below. This particular script only works with submodules that are "nested" inside each other - matreshka-style - in the file system. Otherwise, there will need to be a custom script for each submodule.
Please note that it includes a few work-arounds for some problems I've encountered with getting it to do what I needed it to do (i.e. clone/init submodules on my machine locally before pushing the changes to the server, then doing the tidying-up of the files).
Let me know if more comments are required.
REM Name of your submodule repository...
set subRepo=%1
REM Name of your superproject (with respect to this submodule) repository...
set superRepo=%2
REM Name of the folder into which the content of submodule will be cloned ...
REM Without this alias the folder will be called the same as the repo you are cloning.
set subAlias=%3
REM Branch to link to, given by $(Build.SourceBranchName) in the parameters you pass
REM to the "Run Batch" build step (that will be executing this batch file)...
set branch=%4
REM Repositories' URLs - ONLY SAMPLE URLS - Please use your own !!!
set superUrl="http://<YourTfsServerName>:8080/tfs/DefaultCollection/_git/%superRepo%"
set subUrl="http://<YourTfsServerName>:8080/tfs/DefaultCollection/<YourSuperProjectName>/_git/%subRepo%"
REM Get the latest commit on current branch...
git log -1 --pretty=format:"%%h" > Output.txt
for /f %%i in (Output.txt) do set commit=%%i
IF NOT EXIST %superRepo% GOTO NOWINDIR
cd %superRepo%
REM Handle the .git directory specifically...
cd .git
for /F "delims=" %%i in ('dir /b') do (rmdir "%%i" /s/q || del "%%i" /s/q)
cd ..
rmdir .git
REM Remove the rest of files and folders...
for /F "delims=" %%i in ('dir /b') do (rmdir "%%i" /s/q || del "%%i" /s/q)
cd ..
rmdir %superRepo%
:NOWINDIR
REM Clone superproject and checkout the required branch *********************************************
git clone %superUrl%
cd %superRepo%
git checkout %branch%
git pull origin %branch%
git submodule update --init --recursive -f
cd %subAlias%
git checkout %commit%
cd ..
git add %subAlias%
git commit %subAlias% -m "Updated %subRepo% reference to %commit% as %subAlias%"
git push origin %branch%