Skip to content

Commit 200b9c6

Browse files
[main] Update common Docker engineering infrastructure with latest (#1308)
1 parent 84dcd33 commit 200b9c6

9 files changed

Lines changed: 360 additions & 6 deletions

File tree

eng/docker-tools/DEV-GUIDE.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,8 @@ When you queue a new run, you can override these as runtime parameters:
427427

428428
This avoids the multi-hour rebuild cycle when you just need to retry a failed operation.
429429

430+
When signing is enabled, use `"publish"` by itself only if the images from `sourceBuildPipelineRunId` were already signed and the current run is not building new images. Use `"sign,publish"` when the current run still needs to sign them before publishing.
431+
430432
---
431433

432434
## Troubleshooting

eng/docker-tools/skill-helpers/AzureDevOps.ps1

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ function Invoke-AzDORestMethod {
4141
Request body as a hashtable. Automatically converted to JSON.
4242
.PARAMETER ApiVersion
4343
API version. Defaults to 7.1.
44+
.PARAMETER QueryParams
45+
Optional hashtable of additional query string parameters.
4446
#>
4547
[CmdletBinding()]
4648
param(
@@ -49,7 +51,8 @@ function Invoke-AzDORestMethod {
4951
[Parameter(Mandatory)][string] $Endpoint,
5052
[string] $Method = "GET",
5153
[hashtable] $Body,
52-
[string] $ApiVersion = "7.1"
54+
[string] $ApiVersion = "7.1",
55+
[hashtable] $QueryParams
5356
)
5457

5558
$token = Get-AzDOAccessToken
@@ -58,7 +61,15 @@ function Invoke-AzDORestMethod {
5861
"Content-Type" = "application/json"
5962
}
6063

61-
$uri = "https://dev.azure.com/$Organization/$Project/_apis/$($Endpoint)?api-version=$ApiVersion"
64+
$query = "api-version=$ApiVersion"
65+
if ($QueryParams) {
66+
foreach ($key in $QueryParams.Keys) {
67+
$value = [System.Uri]::EscapeDataString([string]$QueryParams[$key])
68+
$query += "&$key=$value"
69+
}
70+
}
71+
72+
$uri = "https://dev.azure.com/$Organization/$Project/_apis/$($Endpoint)?$query"
6273

6374
$params = @{
6475
Uri = $uri
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#!/usr/bin/env pwsh
2+
# Lists pipeline definitions in a folder whose most recent completed build did not succeed.
3+
# Usage:
4+
# ./Get-FailingPipelines.ps1 -Organization dnceng -Project internal -Folder dotnet/docker-tools
5+
6+
[CmdletBinding()]
7+
param(
8+
[Parameter(Mandatory)][string] $Organization,
9+
[Parameter(Mandatory)][string] $Project,
10+
[Parameter(Mandatory)][string] $Folder,
11+
[switch] $IncludeWarnings
12+
)
13+
14+
$ErrorActionPreference = "Stop"
15+
16+
. "$PSScriptRoot/AzureDevOps.ps1"
17+
18+
# Normalize folder: accept "dotnet/docker-tools" or "\dotnet\docker-tools".
19+
$normalizedFolder = "\" + ($Folder.Trim('\', '/') -replace '/', '\')
20+
21+
$failingResults = @("failed", "canceled")
22+
if ($IncludeWarnings) {
23+
$failingResults += "partiallySucceeded"
24+
}
25+
26+
$definitions = Invoke-AzDORestMethod `
27+
-Organization $Organization `
28+
-Project $Project `
29+
-Endpoint "build/definitions" `
30+
-QueryParams @{
31+
path = $normalizedFolder
32+
includeLatestBuilds = "true"
33+
}
34+
35+
$failing = @()
36+
foreach ($def in $definitions.value) {
37+
$latest = $def.latestCompletedBuild
38+
if (-not $latest) { continue }
39+
if ($failingResults -notcontains $latest.result) { continue }
40+
41+
$failing += [pscustomobject]@{
42+
Definition = $def.name
43+
Result = $latest.result
44+
BuildId = $latest.id
45+
BuildNumber = $latest.buildNumber
46+
Branch = $latest.sourceBranch
47+
FinishTime = $latest.finishTime
48+
Url = "https://dev.azure.com/$Organization/$Project/_build/results?buildId=$($latest.id)"
49+
}
50+
}
51+
52+
Write-Host "## Failing pipelines in $normalizedFolder"
53+
Write-Host ""
54+
Write-Host "Found $($failing.Count) of $($definitions.value.Count) pipeline(s) with a failing latest run."
55+
Write-Host ""
56+
57+
if ($failing.Count -gt 0) {
58+
Write-Host "Pipeline | Result | Build | Branch | Finished | Link"
59+
Write-Host "--- | --- | --- | --- | --- | ---"
60+
foreach ($item in $failing | Sort-Object Definition) {
61+
Write-Host "$($item.Definition) | $($item.Result) | $($item.BuildId) | $($item.Branch) | $($item.FinishTime) | $($item.Url)"
62+
}
63+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#!/usr/bin/env pwsh
2+
# Lists all build runs in the last N hours for pipelines under a given folder.
3+
# Usage:
4+
# ./Get-RecentBuilds.ps1 -Organization dnceng -Project internal -Folder dotnet/docker-tools
5+
# ./Get-RecentBuilds.ps1 -Organization dnceng -Project internal -Folder dotnet/docker-tools -Hours 48
6+
7+
[CmdletBinding()]
8+
param(
9+
[Parameter(Mandatory)][string] $Organization,
10+
[Parameter(Mandatory)][string] $Project,
11+
[Parameter(Mandatory)][string] $Folder,
12+
[int] $Hours = 24
13+
)
14+
15+
$ErrorActionPreference = "Stop"
16+
17+
. "$PSScriptRoot/AzureDevOps.ps1"
18+
19+
$normalizedFolder = "\" + ($Folder.Trim('\', '/') -replace '/', '\')
20+
$minTime = [DateTime]::UtcNow.AddHours(-$Hours).ToString("o")
21+
22+
$definitions = Invoke-AzDORestMethod `
23+
-Organization $Organization `
24+
-Project $Project `
25+
-Endpoint "build/definitions" `
26+
-QueryParams @{ path = $normalizedFolder }
27+
28+
if (-not $definitions.value -or $definitions.value.Count -eq 0) {
29+
Write-Host "## No pipelines found in $normalizedFolder"
30+
return
31+
}
32+
33+
$definitionIds = ($definitions.value | ForEach-Object { $_.id }) -join ","
34+
35+
$builds = Invoke-AzDORestMethod `
36+
-Organization $Organization `
37+
-Project $Project `
38+
-Endpoint "build/builds" `
39+
-QueryParams @{
40+
definitions = $definitionIds
41+
minTime = $minTime
42+
queryOrder = "finishTimeDescending"
43+
}
44+
45+
Write-Host "## Builds in $normalizedFolder (last $Hours hours)"
46+
Write-Host ""
47+
Write-Host "Found $($builds.value.Count) build(s) across $($definitions.value.Count) pipeline(s)."
48+
Write-Host ""
49+
50+
if ($builds.value.Count -gt 0) {
51+
Write-Host "Pipeline | State | Build | Branch | Finished | Link"
52+
Write-Host "--- | --- | --- | --- | --- | ---"
53+
foreach ($build in $builds.value) {
54+
$state = if ($build.status -eq "completed") { $build.result } else { $build.status }
55+
$url = "https://dev.azure.com/$Organization/$Project/_build/results?buildId=$($build.id)"
56+
Write-Host "$($build.definition.name) | $state | $($build.id) | $($build.sourceBranch) | $($build.finishTime) | $url"
57+
}
58+
}

eng/docker-tools/skill-helpers/Show-BuildTimeline.ps1

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ $build = Invoke-AzDORestMethod `
2121
-Project $Project `
2222
-Endpoint "build/builds/$BuildId"
2323

24-
Write-Host "# Build $BuildId - $($build.definition.name)"
24+
Write-Host "## Build $BuildId - $($build.definition.name)"
2525
Write-Host ""
2626
Write-Host "- Status: $($build.status) $(if ($build.result) { "($($build.result))" })"
2727
Write-Host "- Branch: $($build.sourceBranch)"
@@ -71,7 +71,7 @@ function Write-TimelineNode([string] $nodeId, [int] $depth) {
7171
}
7272
}
7373

74-
Write-Host "## Build Timeline"
74+
Write-Host "### Build Timeline"
7575
Write-Host ""
7676
Write-TimelineNode "" 0
7777
Write-Host ""
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
#!/usr/bin/env pwsh
2+
# Shows all PR checks as a summary table, then expands AzDO build timelines for any
3+
# checks that point at Azure Pipelines (https://dev.azure.com/...).
4+
# Requires `gh` CLI authenticated against the target repo.
5+
#
6+
# Usage:
7+
# ./Show-PullRequestBuilds.ps1 -PullRequest 2100
8+
# ./Show-PullRequestBuilds.ps1 -PullRequest 2100 -Repo dotnet/docker-tools
9+
# ./Show-PullRequestBuilds.ps1 -PullRequest 2100 -ShowAllTasks
10+
11+
[CmdletBinding()]
12+
param(
13+
[Parameter(Mandatory)][int] $PullRequest,
14+
[string] $Repo,
15+
[switch] $ShowAllTasks
16+
)
17+
18+
$ErrorActionPreference = "Stop"
19+
20+
$ghArgs = @("pr", "view", $PullRequest, "--json", "statusCheckRollup")
21+
if ($Repo) { $ghArgs += @("--repo", $Repo) }
22+
23+
$checksJson = & gh @ghArgs 2>&1
24+
if ($LASTEXITCODE -ne 0) {
25+
throw "gh pr view failed: $checksJson"
26+
}
27+
28+
$checks = ($checksJson | ConvertFrom-Json).statusCheckRollup
29+
30+
# statusCheckRollup mixes two shapes:
31+
# CheckRun: { name, status, conclusion, detailsUrl, workflowName }
32+
# StatusContext: { context, state, targetUrl, description }
33+
# Normalize them.
34+
$normalized = foreach ($check in $checks) {
35+
if ($check.PSObject.Properties.Name -contains "context") {
36+
[pscustomobject]@{
37+
Name = $check.context
38+
State = $check.state
39+
Url = $check.targetUrl
40+
}
41+
}
42+
else {
43+
$state = if ($check.conclusion) { $check.conclusion } else { $check.status }
44+
[pscustomobject]@{
45+
Name = $check.name
46+
State = $state
47+
Url = $check.detailsUrl
48+
}
49+
}
50+
}
51+
52+
# AzDO build results URLs look like:
53+
# https://dev.azure.com/<org>/<project>/_build/results?buildId=<id>...
54+
$pattern = '^https?://dev\.azure\.com/(?<org>[^/]+)/(?<project>[^/]+)/_build/results\?.*buildId=(?<buildId>\d+)'
55+
56+
$builds = @()
57+
foreach ($check in $normalized) {
58+
if (-not $check.Url) { continue }
59+
$match = [regex]::Match($check.Url, $pattern)
60+
if (-not $match.Success) { continue }
61+
62+
$builds += [pscustomobject]@{
63+
Org = $match.Groups["org"].Value
64+
Project = $match.Groups["project"].Value
65+
BuildId = [int]$match.Groups["buildId"].Value
66+
}
67+
}
68+
69+
# Deduplicate by buildId (a single build can produce multiple check-run rows).
70+
$builds = $builds | Sort-Object BuildId -Unique
71+
72+
$title = if ($Repo) { "$Repo#$PullRequest" } else { "PR #$PullRequest" }
73+
Write-Host "## Checks for $title"
74+
Write-Host ""
75+
Write-Host "$($normalized.Count) check(s); $($builds.Count) Azure Pipelines build(s)."
76+
Write-Host ""
77+
78+
if ($normalized.Count -gt 0) {
79+
Write-Host "Check | State | URL"
80+
Write-Host "--- | --- | ---"
81+
foreach ($check in $normalized | Sort-Object Name) {
82+
Write-Host "$($check.Name) | $($check.State) | $($check.Url)"
83+
}
84+
Write-Host ""
85+
}
86+
87+
if ($builds.Count -eq 0) { return }
88+
89+
$timelineScript = "$PSScriptRoot/Show-BuildTimeline.ps1"
90+
91+
foreach ($build in $builds) {
92+
Write-Host "---"
93+
Write-Host ""
94+
& $timelineScript `
95+
-Organization $build.Org `
96+
-Project $build.Project `
97+
-BuildId $build.BuildId `
98+
-ShowAllTasks:$ShowAllTasks
99+
}

0 commit comments

Comments
 (0)