Skip to content

Commit 35c0f19

Browse files
committed
- Added validation stage and symbol verification job.
- Added dependsOn to the validation stage so it depends on whichever build stages exist. - Moved polling into the validation step to avoid holding up builds.
1 parent 4e1d0d4 commit 35c0f19

11 files changed

Lines changed: 547 additions & 200 deletions

.github/copilot-instructions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ When a new issue is created, follow these steps:
133133
- All source code is in `src/Microsoft.Data.SqlClient/src/`. Do NOT add code to legacy `netfx/src/` or `netcore/src/` directories.
134134
- Only `ref/` folders in `netcore/ref/` and `netfx/ref/` remain active for defining the public API surface.
135135
- Check for platform-specific differences using file suffixes (`.netfx.cs`, `.netcore.cs`, `.windows.cs`, `.unix.cs`) and conditional compilation (`#if NETFRAMEWORK`, `#if NET`, `#if _WINDOWS`, `#if _UNIX`).
136+
- Lines of code, comments, and other text should be a maximum of 100 characters (see `policy/coding-style.md`).
136137
- Respect API compatibility rules across .NET versions
137138
- Do not introduce breaking changes without proper justification and documentation
138139
- Use the `doc/` directory for any new documentation or updates to existing documentation

eng/pipelines/onebranch/jobs/validate-signed-package-job.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ parameters:
1818
type: boolean
1919

2020
jobs:
21-
- job: validate_nuget_package
22-
displayName: "Validate NuGet package"
21+
- job: validate_signed_package
22+
displayName: Verify SqlClient NuGet Package
2323

2424
pool:
25-
type: windows # read more about custom job pool types at https://aka.ms/obpipelines/yaml/jobs
25+
type: windows # read more about custom job pool types at https://aka.ms/obpipelines/yaml/jobs
2626
isCustom: true
2727
name: ADO-1ES-Pool
28-
vmImage: "ADO-MMS22-SQL19"
28+
vmImage: ADO-Win25
2929

3030
variables: # More settings at https://aka.ms/obpipelines/yaml/jobs
3131
- template: /eng/pipelines/onebranch/variables/sqlclient-validation-variables.yml@self
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#################################################################################
2+
# Licensed to the .NET Foundation under one or more agreements. #
3+
# The .NET Foundation licenses this file to you under the MIT license. #
4+
# See the LICENSE file in the project root for more information. #
5+
#################################################################################
6+
7+
# Validates that symbols (PDBs) for every published package DLL are available on each configured
8+
# symbol server using the symchk tool.
9+
#
10+
# All packages specified in the 'packages' parameter will be checked against all symbol servers
11+
# specified in the 'symbolServers' parameter.
12+
13+
parameters:
14+
# The list of symbol servers to verify against. Each entry has a 'name' (friendly display name)
15+
# and 'url' (the symbol server URL that symchk can query).
16+
- name: symbolServers
17+
type: object
18+
default:
19+
- name: MSDL (Public)
20+
url: https://msdl.microsoft.com/download/symbols
21+
- name: SymWeb (Internal)
22+
url: https://symweb.azurefd.net
23+
24+
# The packages whose symbols should be verified. Each entry has:
25+
# artifactName — pipeline artifact name (from onebranch-variables.yml)
26+
# packageName — NuGet package name prefix used to locate the .nupkg file
27+
# dllPath — relative path to the DLL inside the extracted package
28+
- name: packages
29+
type: object
30+
default: []
31+
32+
jobs:
33+
- job: validate_symbols
34+
displayName: Verify symbols on symbol servers
35+
36+
pool:
37+
type: windows
38+
isCustom: true
39+
name: ADO-1ES-Pool
40+
vmImage: ADO-Win25
41+
42+
variables:
43+
extractRoot: $(Build.SourcesDirectory)\symchk_packages
44+
45+
steps:
46+
- script: SET
47+
displayName: Print Environment Variables
48+
49+
# ── Download, extract, and verify symbols for each package ──────────────
50+
51+
- ${{ each pkg in parameters.packages }}:
52+
- download: current
53+
artifact: ${{ pkg.artifactName }}
54+
patterns: '**/*.nupkg'
55+
displayName: Download ${{ pkg.packageName }}
56+
57+
- ${{ each server in parameters.symbolServers }}:
58+
- powershell: >
59+
$(Build.SourcesDirectory)\eng\pipelines\onebranch\jobs\validate-symbols.ps1
60+
-ArtifactPath "$(Pipeline.Workspace)\${{ pkg.artifactName }}"
61+
-ExtractPath "$(extractRoot)\${{ pkg.packageName }}"
62+
-PackageName "${{ pkg.packageName }}"
63+
-DllPath "${{ pkg.dllPath }}"
64+
-SymbolServerUrl "${{ server.url }}"
65+
-SymbolServerName "${{ server.name }}"
66+
displayName: Verify ${{ pkg.packageName }} on ${{ server.name }}
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
<#
2+
.SYNOPSIS
3+
Verifies that symbols (PDBs) for a single DLL are available on a symbol server.
4+
5+
.DESCRIPTION
6+
This script is called by the validate-symbols-job.yml Azure Pipelines job,
7+
once per package per symbol server. It:
8+
1. Locates the .nupkg file in the downloaded artifact directory.
9+
2. Extracts the package contents (skipped if already extracted).
10+
3. Runs symchk.exe to verify that matching PDBs are available on the
11+
specified symbol server.
12+
13+
The script exits with a non-zero exit code if verification fails.
14+
15+
.PARAMETER ArtifactPath
16+
The directory containing the downloaded pipeline artifact (.nupkg files).
17+
18+
.PARAMETER ExtractPath
19+
The directory where the package will be extracted.
20+
21+
.PARAMETER PackageName
22+
The NuGet package name prefix used to locate the .nupkg file
23+
(e.g. "Microsoft.Data.SqlClient").
24+
25+
.PARAMETER DllPath
26+
The relative path to the DLL inside the extracted package
27+
(e.g. "lib\net8.0\Microsoft.Data.SqlClient.dll").
28+
29+
.PARAMETER SymbolServerUrl
30+
The symbol server URL that symchk can query
31+
(e.g. "https://msdl.microsoft.com/download/symbols").
32+
33+
.PARAMETER SymbolServerName
34+
A friendly display name for the symbol server, used in log output.
35+
36+
.EXAMPLE
37+
.\validate-symbols.ps1 `
38+
-ArtifactPath "C:\agent\_work\1\drop_SqlClient" `
39+
-ExtractPath "C:\agent\_work\1\s\symchk_packages\Microsoft.Data.SqlClient" `
40+
-PackageName "Microsoft.Data.SqlClient" `
41+
-DllPath "lib\net8.0\Microsoft.Data.SqlClient.dll" `
42+
-SymbolServerUrl "https://msdl.microsoft.com/download/symbols" `
43+
-SymbolServerName "MSDL (Public)"
44+
#>
45+
46+
[CmdletBinding()]
47+
param(
48+
[Parameter(Mandatory)]
49+
[string]$ArtifactPath,
50+
51+
[Parameter(Mandatory)]
52+
[string]$ExtractPath,
53+
54+
[Parameter(Mandatory)]
55+
[string]$PackageName,
56+
57+
[Parameter(Mandatory)]
58+
[string]$DllPath,
59+
60+
[Parameter(Mandatory)]
61+
[string]$SymbolServerUrl,
62+
63+
[Parameter(Mandatory)]
64+
[string]$SymbolServerName,
65+
66+
# Maximum number of attempts when symbols are not yet available. The first
67+
# attempt runs immediately; subsequent attempts wait RetryIntervalSeconds
68+
# between them. Defaults to 10 (~5 minutes total with default interval).
69+
[int]$MaxRetries = 10,
70+
71+
# Seconds to wait between retry attempts (default 30).
72+
[int]$RetryIntervalSeconds = 30
73+
)
74+
75+
Set-StrictMode -Version Latest
76+
$ErrorActionPreference = 'Stop'
77+
78+
# ── Extract the package (skip if already done) ────────────────────────────────
79+
80+
$dllFullPath = Join-Path $ExtractPath $DllPath
81+
82+
if (-not (Test-Path $dllFullPath)) {
83+
Write-Host "Extracting $PackageName"
84+
85+
New-Item -ItemType Directory -Force -Path $ExtractPath | Out-Null
86+
87+
$nupkg = Get-ChildItem -Path $ArtifactPath -Filter "$PackageName.*.nupkg" `
88+
| Where-Object { $_.Name -notlike '*.snupkg' } `
89+
| Select-Object -First 1
90+
91+
if (-not $nupkg) {
92+
Write-Host "##vso[task.logissue type=error]No $PackageName nupkg found in $ArtifactPath"
93+
exit 1
94+
}
95+
96+
Write-Host "Found: $($nupkg.FullName)"
97+
98+
$zipPath = Join-Path $ExtractPath 'package.zip'
99+
Copy-Item $nupkg.FullName $zipPath
100+
Expand-Archive -Path $zipPath -DestinationPath $ExtractPath -Force
101+
Remove-Item $zipPath
102+
}
103+
104+
if (-not (Test-Path $dllFullPath)) {
105+
Write-Host "##vso[task.logissue type=error]DLL not found after extraction: $dllFullPath"
106+
exit 1
107+
}
108+
109+
# ── Locate symchk.exe ────────────────────────────────────────────────────────
110+
111+
$symchkCandidates = @(
112+
"${env:ProgramFiles(x86)}\Windows Kits\10\Debuggers\x64\symchk.exe"
113+
"${env:ProgramFiles}\Windows Kits\10\Debuggers\x64\symchk.exe"
114+
)
115+
116+
$symchkPath = $null
117+
foreach ($candidate in $symchkCandidates) {
118+
if (Test-Path $candidate) {
119+
$symchkPath = $candidate
120+
break
121+
}
122+
}
123+
124+
if (-not $symchkPath) {
125+
Write-Host "##vso[task.logissue type=error]symchk.exe not found. Ensure Debugging Tools for Windows are installed."
126+
exit 1
127+
}
128+
129+
# ── Verify symbols (with retries for publishing latency) ──────────────────────
130+
131+
$dllLeaf = Split-Path $dllFullPath -Leaf
132+
133+
Write-Host "Verifying symbols for $dllLeaf on $SymbolServerName ($SymbolServerUrl)"
134+
Write-Host "Using symchk: $symchkPath"
135+
Write-Host "Max attempts: $MaxRetries, interval: ${RetryIntervalSeconds}s"
136+
137+
$symchkArgs = @(
138+
$dllFullPath,
139+
"/s", "srv*$SymbolServerUrl",
140+
"/os"
141+
)
142+
143+
for ($attempt = 1; $attempt -le $MaxRetries; $attempt++) {
144+
Write-Host "Attempt $attempt of $MaxRetries — running: symchk $($symchkArgs -join ' ')"
145+
$output = & $symchkPath @symchkArgs 2>&1 | Out-String
146+
$symchkExit = $LASTEXITCODE
147+
148+
Write-Host $output
149+
150+
$passed = ($symchkExit -eq 0) -and
151+
($output -match "FAILED files = 0") -and
152+
($output -match "PASSED \+ IGNORED files = [1-9]")
153+
154+
if ($passed) {
155+
Write-Host "Symbols verified successfully for $dllLeaf on $SymbolServerName"
156+
exit 0
157+
}
158+
159+
if ($attempt -lt $MaxRetries) {
160+
Write-Host "Symbols not yet available. Retrying in $RetryIntervalSeconds seconds..."
161+
Start-Sleep -Seconds $RetryIntervalSeconds
162+
}
163+
}
164+
165+
Write-Host "##vso[task.logissue type=error]symchk could not verify symbols for $dllLeaf on $SymbolServerName after $MaxRetries attempts."
166+
exit 1

eng/pipelines/onebranch/sqlclient-non-official.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,15 @@ extends:
189189
buildSqlClient: ${{ parameters.buildSqlClient }}
190190
buildAKVProvider: ${{ parameters.buildAKVProvider }}
191191

192-
- template: /eng/pipelines/onebranch/stages/release-stages.yml@self
192+
- template: /eng/pipelines/onebranch/stages/validation-stage.yml@self
193+
parameters:
194+
isPreview: ${{ parameters.isPreview }}
195+
publishSymbols: ${{ parameters.publishSymbols }}
196+
buildSqlServerServer: ${{ parameters.buildSqlServerServer }}
197+
buildSqlClient: ${{ parameters.buildSqlClient }}
198+
buildAKVProvider: ${{ parameters.buildAKVProvider }}
199+
200+
- template: /eng/pipelines/onebranch/stages/release-stage.yml@self
193201
parameters:
194202
debug: ${{ parameters.debug }}
195203
# Non-official pipelines always push to the NuGet Test feed.

eng/pipelines/onebranch/sqlclient-official.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,15 @@ extends:
214214
buildSqlClient: ${{ parameters.buildSqlClient }}
215215
buildAKVProvider: ${{ parameters.buildAKVProvider }}
216216

217-
- template: /eng/pipelines/onebranch/stages/release-stages.yml@self
217+
- template: /eng/pipelines/onebranch/stages/validation-stage.yml@self
218+
parameters:
219+
isPreview: ${{ parameters.isPreview }}
220+
publishSymbols: ${{ parameters.publishSymbols }}
221+
buildSqlServerServer: ${{ parameters.buildSqlServerServer }}
222+
buildSqlClient: ${{ parameters.buildSqlClient }}
223+
buildAKVProvider: ${{ parameters.buildAKVProvider }}
224+
225+
- template: /eng/pipelines/onebranch/stages/release-stage.yml@self
218226
parameters:
219227
debug: ${{ parameters.debug }}
220228
releaseToProduction: ${{ parameters.releaseToProduction }}

0 commit comments

Comments
 (0)