Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SebastianSchuetze/83b7320b77e829b0164af776d0b939e6 to your computer and use it in GitHub Desktop.
Save SebastianSchuetze/83b7320b77e829b0164af776d0b939e6 to your computer and use it in GitHub Desktop.
Gets the timeline of given build definition Ids for a project and exports them into a CSV file.
#In this script I expect that the user is already logged in into Azure DevOps with the VSTeam module
$projectName = "Pipeline Artifacts vs Build Artifacts"
$buildDefinitionIds = @(15,16,17,19)
$csvStatsFilePath = "C:\temp\BuildStats.csv"
#function to convert the flat timeline logs to a parent child tree, since the timeline has
#pipeline, phases and tasks which follow a hierarchy
Function ConvertTo-TreeArray($flatArray,$parentKey,$childKey){
$groupedByDefinition = $flatArray | Group-Object -Property $parentKey
foreach($flatObj in $flatArray){
$children = $groupedByDefinition | Where-Object {
$_.Name -eq $flatObj.$childKey
}
if($null -ne $children){
$children = $children | Sort-Object order
Add-Member -InputObject $flatObj -MemberType NoteProperty -Name Children -Value $children.Group
}
}
return $flatArray | Where-Object { $_.name -eq "__default"}
}
# Get Build Stats
$builds = Get-VSTeamBuild -ProjectName $projectName -StatusFilter completed -Definitions $buildDefinitionIds | Sort-Object -Property queueTime,definitionName
$InformationPreference = "continue"
$ErrorActionPreference = "stop"
$buildTimelines = @()
foreach($build in $builds){
Write-Information -MessageData "Checking build $($build.buildNumber) for definition $($build.definitionName)"
$url = "$($build._links.timeline.href)?api-version=5.1-preview.2"
$json = Invoke-RestMethod -Method Get -Uri $url
$buildTimeline = $json.records
$selectedTimeline = $buildTimeline #| Select-Object -Property id,parentId,type,Name,startTime,finishTime,order
#$selectedTimeline | Out-GridView
$treeArray = ConvertTo-TreeArray -flatArray $selectedTimeline -parentKey "parentId" -childKey "Id"
Add-Member -InputObject $treeArray -MemberType NoteProperty -Name BuildName -Value $build.definitionName
Add-Member -InputObject $treeArray -MemberType NoteProperty -Name BuildNumber -Value $build.buildNumber
Add-Member -InputObject $treeArray -MemberType NoteProperty -Name BuildId -Value $build.id
$buildTimelines = $buildTimelines + $treeArray
}
# build the csv to be exported
$exportedBuildStats = @()
foreach($timeline in $buildTimelines){
$exportStatInfo = @{}
foreach($phase in $timeline.Children){
if($null -eq $phase.children){
continue
}
$job = $phase.Children[0]
foreach($task in $job.Children){
[datetime]$endTimeDt = [datetime]$task.finishTime
[datetime]$startTimeDt = [datetime]$task.startTime
#rounding time to milliseconds by deducting it's ticks down to the current second
$endTimeDt = $endTimeDt.Ticks - ($endTimeDt.Ticks % [TimeSpan]::TicksPerSecond)
$startTimeDt = $startTimeDt.Ticks - ($startTimeDt.Ticks % [TimeSpan]::TicksPerSecond)
$exportStatInfo = [ordered] @{
"BuildName" = $timeline.BuildName
"BuildNumber" = $timeline.BuildNumber
"BuildId" = $timeline.BuildId
"Phase" = $phase.name
"TaskName" = $task.name
"TaskStartTime" = $startTimeDt
"TaskFinishTime" = $endTimeDt
"TaskOrder" = $task.order
"TaskRuntimeSpan" = $endTimeDt - $startTimeDt
"TaskResult" = $task.result
}
$exportStat = New-Object -TypeName PSObject -Property $exportStatInfo
$exportedBuildStats = $exportedBuildStats + $exportStat
}
}
}
#$exportedBuildStats | Out-GridView
$exportedBuildStats | ConvertTo-Csv -Delimiter ";" -NoTypeInformation | Out-File -FilePath $csvStatsFilePath -Encoding utf8
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment