Configure a CI build for each commit

February 5, 2018

By default in TFS/VSTS, the CI build configuration is used to trigger a build after each push. Additionally there is a option to “batch changes” (queue a build with all the changes since the last build instead of queue a build for each push).

However there are some cases where you want to build each introduced commit separately. It’s true that there is no way to do it automatically OOB, but in this post I want to share a way to achieve it with a little creativity (and code).


The Idea


Create two different build definitions:

– Listener Definition: Catch every push, retrieve the commits related to the push and trigger a build for each one of them.

– Build Definition: contains the build configuration to be executed for each commit.


Build Definition

Configure the build definition:


(In my case I created a very basic build definition that print its source commit and its source branch. However you can configure the build to do whatever you want)


Listener Definition

1.- Create the build definition



2.- Set the build as continuous integration (no batch changes)



3.- Set the branch trigger filter (dev branch in my case)



4.- Create the “Credential” parameter (as secret parameter)



5.- Create the “TargetBuildDefinitionName” parameter



6.- Add the listener job script


(Note the parameters passed to the script as arguments)


7.- Save the definition


Listener Job

(You can find the listener job script in GitHub)

The first step in the script is get the push that contains the commit that triggered the build:

$PushId = Get-PushIdByCommitId -BranchName $BranchName -CommitId $SourceVerison -CollectionUrl $CollectionUrl -TeamProject $TeamProject -GitRepository $GitRepository -Credentials $Credentials


Then, all the commit associated to the push are retrieved:

$Commits = Get-CommitsInPush -PushId $PushId -CollectionUrl $CollectionUrl -TeamProject $TeamProject -GitRepository $GitRepository -Credentials $Credentials


Next, get all the history for the branch (to know which commits inside the push are related to the branch):

$CommitsnBranch = (Get-CommitsByBranch -BranchName $BranchName -CollectionUrl $CollectionUrl -TeamProject $TeamProject -GitRepository $GitRepository -Credentials $Credentials).commitId


Then, create a list with all the commits introduced in the push that are related to the branch:

$CommitsInfo = @()

# Fill the list with all the commits introduced in the push
foreach($CommitId in ($Commits | Select commitId).commitId)
    # Filter only the commits for the branch
    if($CommitsnBranch -contains $CommitId)
        $CommitInfo = Get-CommitById -CommitId $CommitId -CollectionUrl $CollectionUrl -TeamProject $TeamProject -GitRepository $GitRepository -Credentials $Credentials
        $CommitsInfo += $CommitInfo


Now that we have the commits that we want to use, we need to order them in chronological order:

$CommitsInfo = $CommitsInfo | Select commitId,committer

foreach($value in $CommitsInfo) 
    $value.committer = $ 

$OrderedCommits = $CommitsInfo | Sort committer


Finally a build is triggered for each commit in the list:

foreach($Commit in $OrderedCommits)
    # Create queue body (build parameters) and trigger build definition
    $CommitSha1 = $Commit.commitId
    $TargetDefinitionId = Get-BuildDefinitionId -BuildDefinitionName $TargetBuildDefinitionName -CollectionUrl $CollectionUrl -TeamProject $TeamProject -Credentials $Credentials
    $QueueBody = @{ definition = @{id = $TargetDefinitionId}; sourceBranch = "refs/heads/$BranchName"; sourceVersion = $CommitSha1 }
    $Response = Start-BuildCustomBody -Body $QueueBody -CollectionUrl $CollectionUrl -TeamProject $TeamProject -Credentials $Credentials
    # Print build trigger request response
    if($Response -ne $null)
        $BuildNumber = $Response.buildNumber
        Write-Host "Build [$BuildNumber] successfully trigger from commit [$CommitSha1]"
        Start-Sleep -Seconds 5
        Write-Host "Error Triggering build from commit [$CommitSha1]" 


Putting All Together


1.- Checkout the dev branch

$ git checkout dev


2.- Create new commits

$ echo content >> file.txt && git add -A && git commit -m "commit 1"
$ echo content >> file.txt && git add -A && git commit -m "commit 2"
$ echo content >> file.txt && git add -A && git commit -m "commit 3"
$ echo content >> file.txt && git add -A && git commit -m "commit 4"
$ echo content >> file.txt && git add -A && git commit -m "commit 5"


3.- Get commit id’s of created commits

$ git log --oneline -n 5



4.- Push the new commits

$ git push


5.- Check the listener job log



6.- Verify the builds were triggered



Add comment
facebook linkedin twitter email

Leave a Reply