Skip to content

Commit

Permalink
Publish test symbols on failures
Browse files Browse the repository at this point in the history
When investigating test run failures from Azure Pipelines, symbols from test binaries may be just as important as symbols from product binaries. So publish them as pipeline artifacts as well.

Also index all these symbols even in PR builds, since PR builds may fail and investigations may be required.
  • Loading branch information
AArnott committed Nov 2, 2020
1 parent 05b3324 commit 9c16ae2
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 54 deletions.
67 changes: 67 additions & 0 deletions azure-pipelines/Get-SymbolFiles.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<#
.SYNOPSIS
Collect the list of PDBs built in this repo, after converting them from portable to Windows PDBs.
.PARAMETER Path
The root path to recursively search for PDBs.
.PARAMETER Tests
A switch indicating to find test-related PDBs instead of product-only PDBs.
#>
[CmdletBinding()]
param (
[parameter(Mandatory=$true)]
[string]$Path,
[switch]$Tests
)

$WindowsPdbSubDirName = "symstore"

$ActivityName = "Collecting symbols from $Path"
Write-Progress -Activity $ActivityName -CurrentOperation "Discovery PDB files"
$PDBs = Get-ChildItem -rec "$Path\*.pdb" |? { $_.FullName -notmatch "\W$WindowsPdbSubDirName\W" }

# Filter PDBs to product OR test related.
$testregex = "unittest|tests"
if ($Tests) {
$PDBs = $PDBs |? { $_.FullName -match $testregex }
} else {
$PDBs = $PDBs |? { $_.FullName -notmatch $testregex }
}

Write-Progress -Activity $ActivityName -CurrentOperation "De-duplicating symbols"
$PDBsByHash = @{}
$i = 0
$PDBs |% {
Write-Progress -Activity $ActivityName -CurrentOperation "De-duplicating symbols" -PercentComplete (100 * $i / $PDBs.Length)
$hash = Get-FileHash $_
$i++
Add-Member -InputObject $_ -MemberType NoteProperty -Name Hash -Value $hash.Hash
Write-Output $_
} | Sort-Object CreationTime |% {
# De-dupe based on hash. Prefer the first match so we take the first built copy.
if (-not $PDBsByHash.ContainsKey($_.Hash)) {
$PDBsByHash.Add($_.Hash, $_.FullName)
Write-Output $_
}
} |% {
# Collect the DLLs/EXEs as well.
$dllPath = "$($_.Directory)\$($_.BaseName).dll"
$exePath = "$($_.Directory)\$($_.BaseName).exe"
if (Test-Path $dllPath) {
$BinaryImagePath = $dllPath
} elseif (Test-Path $exePath) {
$BinaryImagePath = $exePath
}

Write-Output $BinaryImagePath

# Convert the PDB to legacy Windows PDBs
Write-Host "Converting PDB for $_" -ForegroundColor DarkGray
$WindowsPdbDir = "$($_.Directory.FullName)\$WindowsPdbSubDirName"
if (!(Test-Path $WindowsPdbDir)) { mkdir $WindowsPdbDir | Out-Null }
& "$PSScriptRoot\Convert-PDB.ps1" -DllPath $BinaryImagePath -PdbPath $_ -OutputPath "$WindowsPdbDir\$($_.BaseName).pdb"
if ($LASTEXITCODE -ne 0) {
Write-Warning "PDB conversion of `"$_`" failed."
}

Write-Output "$WindowsPdbDir\$($_.BaseName).pdb"
}
54 changes: 1 addition & 53 deletions azure-pipelines/artifacts/symbols.ps1
Original file line number Diff line number Diff line change
@@ -1,63 +1,11 @@
Function Get-SymbolFiles {
[CmdletBinding()]
param (
[parameter(Mandatory=$true)]
[string]$Path
)

$WindowsPdbSubDirName = "symstore"

$ActivityName = "Collecting symbols from $Path"
Write-Progress -Activity $ActivityName -CurrentOperation "Discovery PDB files"
$PDBs = Get-ChildItem -rec "$Path\*.pdb" |? { $_.FullName -notmatch "unittest|tests|\W$WindowsPdbSubDirName\W" }
Write-Progress -Activity $ActivityName -CurrentOperation "De-duplicating symbols"
$PDBsByHash = @{}
$i = 0
$PDBs |% {
Write-Progress -Activity $ActivityName -CurrentOperation "De-duplicating symbols" -PercentComplete (100 * $i / $PDBs.Length)
$hash = Get-FileHash $_
$i++
Add-Member -InputObject $_ -MemberType NoteProperty -Name Hash -Value $hash.Hash
Write-Output $_
} | Sort-Object CreationTime |% {
# De-dupe based on hash. Prefer the first match so we take the first built copy.
if (-not $PDBsByHash.ContainsKey($_.Hash)) {
$PDBsByHash.Add($_.Hash, $_.FullName)
Write-Output $_
}
} |% {
# Collect the DLLs/EXEs as well.
$dllPath = "$($_.Directory)\$($_.BaseName).dll"
$exePath = "$($_.Directory)\$($_.BaseName).exe"
if (Test-Path $dllPath) {
$BinaryImagePath = $dllPath
} elseif (Test-Path $exePath) {
$BinaryImagePath = $exePath
}

Write-Output $BinaryImagePath

# Convert the PDB to legacy Windows PDBs
Write-Host "Converting PDB for $_" -ForegroundColor DarkGray
$WindowsPdbDir = "$($_.Directory.FullName)\$WindowsPdbSubDirName"
if (!(Test-Path $WindowsPdbDir)) { mkdir $WindowsPdbDir | Out-Null }
& "$PSScriptRoot\..\Convert-PDB.ps1" -DllPath $BinaryImagePath -PdbPath $_ -OutputPath "$WindowsPdbDir\$($_.BaseName).pdb"
if ($LASTEXITCODE -ne 0) {
Write-Warning "PDB conversion of `"$_`" failed."
}

Write-Output "$WindowsPdbDir\$($_.BaseName).pdb"
}
}

# This doesn't work off Windows, nor do we need to convert symbols on multiple OS agents
if ($IsMacOS -or $IsLinux) {
return;
}

$BinPath = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\bin")
if (!(Test-Path $BinPath)) { return }
$symbolfiles = Get-SymbolFiles -Path $BinPath | Get-Unique
$symbolfiles = & "$PSScriptRoot\..\Get-SymbolFiles.ps1" -Path $BinPath | Get-Unique

@{
"$BinPath" = $SymbolFiles;
Expand Down
12 changes: 12 additions & 0 deletions azure-pipelines/artifacts/test_symbols.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# This doesn't work off Windows, nor do we need to convert symbols on multiple OS agents
if ($IsMacOS -or $IsLinux) {
return;
}

$BinPath = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\bin")
if (!(Test-Path $BinPath)) { return }
$symbolfiles = & "$PSScriptRoot\..\Get-SymbolFiles.ps1" -Path $BinPath -Tests | Get-Unique

@{
"$BinPath" = $SymbolFiles;
}
11 changes: 10 additions & 1 deletion azure-pipelines/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,16 @@ steps:
IndexSources: false
SymbolServerType: TeamServices
displayName: Publish symbols to symbol server
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'), eq(variables['Agent.OS'], 'Windows_NT'))
condition: eq(variables['Agent.OS'], 'Windows_NT') # Execute on failed test runs too. Windows-only till https://github.com/microsoft/azure-pipelines-tasks/issues/13821 is fixed.

- task: PublishSymbols@2
inputs:
SymbolsFolder: $(Build.ArtifactStagingDirectory)/test_symbols-$(Agent.JobName)
SearchPattern: '**/*.pdb'
IndexSources: false
SymbolServerType: TeamServices
displayName: Publish test symbols to symbol server
condition: and(failed(), eq(variables['Agent.OS'], 'Windows_NT')) # Execute on failed test runs only.

- bash: bash <(curl -s https://codecov.io/bash)
displayName: Publish code coverage results to codecov.io
Expand Down

0 comments on commit 9c16ae2

Please sign in to comment.