|
| 1 | +#!/usr/bin/env pwsh |
| 2 | +# Prints the build timeline as an indented tree with result indicators. |
| 3 | +# Usage: |
| 4 | +# ./Show-BuildTimeline.ps1 -Organization dnceng -Project internal -BuildId 12345 |
| 5 | +# ./Show-BuildTimeline.ps1 -Organization dnceng -Project internal -BuildId 12345 -ShowAllTasks |
| 6 | + |
| 7 | +[CmdletBinding()] |
| 8 | +param( |
| 9 | + [Parameter(Mandatory)][string] $Organization, |
| 10 | + [Parameter(Mandatory)][string] $Project, |
| 11 | + [Parameter(Mandatory)][int] $BuildId, |
| 12 | + [switch] $ShowAllTasks |
| 13 | +) |
| 14 | + |
| 15 | +$ErrorActionPreference = "Stop" |
| 16 | + |
| 17 | +. "$PSScriptRoot/AzureDevOps.ps1" |
| 18 | + |
| 19 | +$build = Invoke-AzDORestMethod ` |
| 20 | + -Organization $Organization ` |
| 21 | + -Project $Project ` |
| 22 | + -Endpoint "build/builds/$BuildId" |
| 23 | + |
| 24 | +Write-Host "# Build $BuildId - $($build.definition.name)" |
| 25 | +Write-Host "" |
| 26 | +Write-Host "- Status: $($build.status) $(if ($build.result) { "($($build.result))" })" |
| 27 | +Write-Host "- Branch: $($build.sourceBranch)" |
| 28 | +Write-Host "- Queued: $($build.queueTime)" |
| 29 | +Write-Host "- URL: $($build._links.web.href)" |
| 30 | +Write-Host "" |
| 31 | + |
| 32 | +$timeline = Invoke-AzDORestMethod ` |
| 33 | + -Organization $Organization ` |
| 34 | + -Project $Project ` |
| 35 | + -Endpoint "build/builds/$BuildId/timeline" |
| 36 | + |
| 37 | +$records = $timeline.records |
| 38 | + |
| 39 | +# Build a lookup of children grouped by parentId |
| 40 | +$childrenOf = @{} |
| 41 | +foreach ($record in $records) { |
| 42 | + $parentId = $record.parentId |
| 43 | + if (-not $parentId) { $parentId = "" } |
| 44 | + if (-not $childrenOf.ContainsKey($parentId)) { |
| 45 | + $childrenOf[$parentId] = [System.Collections.Generic.List[object]]::new() |
| 46 | + } |
| 47 | + $childrenOf[$parentId].Add($record) |
| 48 | +} |
| 49 | + |
| 50 | +# Sort children by order within each group |
| 51 | +foreach ($key in @($childrenOf.Keys)) { |
| 52 | + $childrenOf[$key] = $childrenOf[$key] | Sort-Object { $_.order } |
| 53 | +} |
| 54 | + |
| 55 | +function Write-TimelineNode([string] $nodeId, [int] $depth) { |
| 56 | + $children = $childrenOf[$nodeId] |
| 57 | + if (-not $children) { return } |
| 58 | + |
| 59 | + foreach ($child in $children) { |
| 60 | + $isTask = $child.type -eq "Task" |
| 61 | + $isFailing = $child.result -in @("failed", "canceled", "abandoned") -or $child.state -eq "inProgress" |
| 62 | + if ($isTask -and -not $ShowAllTasks -and -not $isFailing) { continue } |
| 63 | + |
| 64 | + $indent = " " * $depth |
| 65 | + $status = if ($child.result) { $child.result } else { $child.state } |
| 66 | + |
| 67 | + $logId = $child.log.id |
| 68 | + $logLabel = if ($logId) { " #$logId" } else { "" } |
| 69 | + Write-Host "${indent}- $($child.type)$logLabel | $($child.name) | $status" |
| 70 | + Write-TimelineNode $child.id ($depth + 1) |
| 71 | + } |
| 72 | +} |
| 73 | + |
| 74 | +Write-Host "## Build Timeline" |
| 75 | +Write-Host "" |
| 76 | +Write-TimelineNode "" 0 |
| 77 | +Write-Host "" |
0 commit comments