Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
197 changes: 197 additions & 0 deletions eng/pipelines/common/templates/steps/Publish-Symbols.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
<#
.SYNOPSIS
Publishes symbols to the Microsoft symbol publishing service (SymWeb/MSDL).

.DESCRIPTION
This script uploads and publishes debug symbols (.pdb files) to internal and/or public
Microsoft symbol servers via the Symbols Publishing Pipeline REST API.

It performs four steps:
1. Acquires a bearer token from Azure CLI for the symbol publishing service.
2. Registers a unique request name with the publishing service.
3. Submits the request to publish symbols to the specified servers.
4. Queries the publishing status for confirmation.

For more details on the Symbols Publishing Pipeline, see:
https://www.osgwiki.com/wiki/Symbols_Publishing_Pipeline_to_SymWeb_and_MSDL

.PARAMETER PublishServer
The hostname prefix of the symbol publishing service. This value is prepended to
'.trafficmanager.net' to construct the service base URL.

.PARAMETER PublishTokenUri
The resource URI used to acquire a bearer token from Azure CLI
(via 'az account get-access-token --resource <uri>').

.PARAMETER PublishProjectName
The project name registered with the symbol publishing service (decided during onboarding).

.PARAMETER ArtifactName
The name of the publishing request. This must match the SymbolsArtifactName used by
the PublishSymbols@2 upload task so that upload and publish reference the same artifact.

.PARAMETER PublishToInternal
Whether to publish symbols to the internal symbol server. Defaults to $true.

.PARAMETER PublishToPublic
Whether to publish symbols to the public symbol server. Defaults to $true.

.EXAMPLE
.\Publish-Symbols.ps1 `
-PublishServer "mysymbolserver" `
-PublishTokenUri "https://login.microsoftonline.com/..." `
-PublishProjectName "Microsoft.Data.SqlClient.SNI" `
-ArtifactName "mds_symbols_MyProject_dotnet-sqlclient_main_6.1.5_abc123_1"

Publishes symbols to both internal and public servers using the specified parameters.

.EXAMPLE
.\Publish-Symbols.ps1 `
-PublishServer "mysymbolserver" `
-PublishTokenUri "https://login.microsoftonline.com/..." `
-PublishProjectName "Microsoft.Data.SqlClient.SNI" `
-ArtifactName "mds_symbols_MyProject_dotnet-sqlclient_main_6.1.5_abc123_2" `
-PublishToPublic $false

Publishes symbols to the internal server only (retry attempt 2).

.NOTES
Licensed to the .NET Foundation under one or more agreements.
The .NET Foundation licenses this file to you under the MIT license.
See the LICENSE file in the project root for more information.

File Name : Publish-Symbols.ps1
Requires : Azure CLI (az) must be installed and authenticated.
Called by : publish-symbols-step.yml (Azure Pipelines template)

Publishing status codes returned by the service:

PublishingStatus:
0 - NotRequested: The request has not been requested to publish.
1 - Submitted: The request is submitted to be published.
2 - Processing: The request is still being processed.
3 - Completed: Processing finished. Check PublishingResult for details.

PublishingResult:
0 - Pending: The request has not completed or has not been requested.
1 - Succeeded: The request published successfully.
2 - Failed: The request failed to publish.
3 - Cancelled: The request was cancelled.
#>

[CmdletBinding()]
param(
[Parameter(Mandatory = $true, HelpMessage = "Hostname prefix of the symbol publishing service (prepended to .trafficmanager.net).")]
[ValidateNotNullOrEmpty()]
[string]$PublishServer,

[Parameter(Mandatory = $true, HelpMessage = "Resource URI for acquiring a bearer token via Azure CLI.")]
[ValidateNotNullOrEmpty()]
[string]$PublishTokenUri,

[Parameter(Mandatory = $true, HelpMessage = "Project name registered with the symbol publishing service.")]
[ValidateNotNullOrEmpty()]
[string]$PublishProjectName,

[Parameter(Mandatory = $true, HelpMessage = "Artifact name for the publishing request (must match PublishSymbols@2 SymbolsArtifactName).")]
[ValidateNotNullOrEmpty()]
[string]$ArtifactName,

[Parameter(Mandatory = $false, HelpMessage = "Publish symbols to the internal symbol server.")]
[bool]$PublishToInternal = $true,

[Parameter(Mandatory = $false, HelpMessage = "Publish symbols to the public symbol server.")]
[bool]$PublishToPublic = $true
)

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

# --- Log input parameters ---
Write-Host "=== Publish Symbols Parameters ==="
Write-Host "PublishServer: ${PublishServer}"
Write-Host "PublishTokenUri: ${PublishTokenUri}"
Write-Host "PublishProjectName: ${PublishProjectName}"
Write-Host "ArtifactName: ${ArtifactName}"
Write-Host "PublishToInternal: ${PublishToInternal}"
Write-Host "PublishToPublic: ${PublishToPublic}"
Write-Host "=================================="

# --- Build request name and URLs ---
$requestName = ${ArtifactName}
$baseUrl = "https://${PublishServer}.trafficmanager.net/projects/${PublishProjectName}"
$registerUrl = "${baseUrl}/requests"
$requestUrl = "${baseUrl}/requests/${requestName}"

Write-Host "=== Constructed URLs ==="
Write-Host "Request Name: ${requestName}"
Write-Host "Base URL: ${baseUrl}"
Write-Host "Register URL: ${registerUrl}"
Write-Host "Request URL: ${requestUrl}"
Write-Host "========================"

# --- Step 1: Acquire token ---
Write-Host "> 1. Acquiring symbol publishing token..."
$symbolPublishingToken = az account get-access-token --resource ${PublishTokenUri} --query accessToken -o tsv
if ($LASTEXITCODE -ne 0) {
throw "Failed to acquire symbol publishing token via Azure CLI (exit code: ${LASTEXITCODE})."
}
if ($null -ne $symbolPublishingToken) {
$symbolPublishingToken = $symbolPublishingToken.Trim()
}
if ([string]::IsNullOrWhiteSpace($symbolPublishingToken)) {
throw "Failed to acquire symbol publishing token via Azure CLI: received an empty or whitespace-only access token."
}
Write-Host "> 1. Symbol publishing token acquired."

$authHeaders = @{ Authorization = "Bearer ${symbolPublishingToken}" }

# --- Step 2: Register request name ---
Write-Host "> 2. Registering request name..."
$requestNameRegistrationBody = @{ requestName = $requestName } | ConvertTo-Json -Compress
try {
Invoke-RestMethod -Method POST -Uri ${registerUrl} -Headers ${authHeaders} -ContentType "application/json" -Body ${requestNameRegistrationBody}
} catch {
throw "Failed to register request name. URI: ${registerUrl} | Body: ${requestNameRegistrationBody} | Error: $_"
}
Write-Host "> 2. Request name registered successfully."

# --- Step 3: Publish symbols ---
Write-Host "> 3. Submitting request to publish symbols..."
$publishSymbolsBody = @{
publishToInternalServer = $PublishToInternal
publishToPublicServer = $PublishToPublic
} | ConvertTo-Json -Compress
Write-Host "Publishing symbols request body: ${publishSymbolsBody}"
try {
Invoke-RestMethod -Method POST -Uri ${requestUrl} -Headers ${authHeaders} -ContentType "application/json" -Body ${publishSymbolsBody}
} catch {
throw "Failed to publish symbols. URI: ${requestUrl} | Body: ${publishSymbolsBody} | Error: $_"
}
Write-Host "> 3. Request to publish symbols submitted successfully."

# --- Step 4: Check status ---
Write-Host "> 4. Checking the status of the request..."
try {
$status = Invoke-RestMethod -Method GET -Uri ${requestUrl} -Headers ${authHeaders} -ContentType "application/json"
$status
} catch {
throw "Failed to check request status. URI: ${requestUrl} | Error: $_"
}

Write-Host ""
Write-Host "Use below tables to interpret the xxxServerStatus and xxxServerResult fields from the response."
Write-Host ""
Write-Host "PublishingStatus"
Write-Host "-----------------"
Write-Host "0 NotRequested - The request has not been requested to publish."
Write-Host "1 Submitted - The request is submitted to be published."
Write-Host "2 Processing - The request is still being processed."
Write-Host "3 Completed - Processing finished. Check PublishingResult for details."
Write-Host ""
Write-Host "PublishingResult"
Write-Host "-----------------"
Write-Host "0 Pending - The request has not completed or has not been requested."
Write-Host "1 Succeeded - The request published successfully."
Write-Host "2 Failed - The request failed to publish."
Write-Host "3 Cancelled - The request was cancelled."
92 changes: 30 additions & 62 deletions eng/pipelines/common/templates/steps/publish-symbols-step.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@
# #
# doc: https://www.osgwiki.com/wiki/Symbols_Publishing_Pipeline_to_SymWeb_and_MSDL #
####################################################################################

# The Symbols* variable defaults (e.g. SymbolsPublishServer, SymbolsUploadAccount) are sourced from
# the 'Symbols Publishing' variable group, imported via eng/pipelines/libraries/mds-variables.yml.

parameters:
- name: SymAccount
type: string
default: 'SqlClientDrivers'
default: '$(SymbolsUploadAccount)'

- name: publishSymbols
type: string
Expand All @@ -20,18 +24,26 @@ parameters:

- name: symbolServer
type: string
default: '$(SymbolServer)'
default: '$(SymbolsPublishServer)'

- name: symbolTokenUri
type: string
default: '$(SymbolTokenUri)'
default: '$(SymbolsPublishTokenUri)'

- name: symbolsArtifactName
type: string


- name: symbolsAzureSubscription
type: string
default: '$(SymbolsAzureSubscription)'

- name: symbolsPublishProjectName
type: string
default: '$(SymbolsPublishProjectName)'

- name: publishToServers
type: object
default:
default:
internal: true
public: true

Expand Down Expand Up @@ -66,66 +78,22 @@ steps:
SymbolExpirationInDays: 1825 # 5 years
SymbolsProduct: Microsoft.Data.SqlClient
SymbolsVersion: ${{parameters.symbolsVersion }}
SymbolsArtifactName: ${{parameters.symbolsArtifactName }}
SymbolsArtifactName: ${{parameters.symbolsArtifactName }}_$(System.JobAttempt)
Pat: $(System.AccessToken)
condition: and(succeeded(), ${{ eq(parameters.publishSymbols, 'true') }})

- task: AzureCLI@2
displayName: 'Publish symbols'
condition: and(succeeded(), ${{ eq(parameters.publishSymbols, 'true') }})
inputs:
azureSubscription: 'Symbols publishing Workload Identity federation service-ADO.Net'
azureSubscription: '${{parameters.symbolsAzureSubscription }}'
scriptType: ps
scriptLocation: inlineScript
inlineScript: |
$publishToInternalServer = "${{parameters.publishToServers.internal }}".ToLower()
$publishToPublicServer = "${{parameters.publishToServers.public }}".ToLower()

echo "Publishing request name: ${{parameters.symbolsArtifactName }}"
echo "Publish to internal server: $publishToInternalServer"
echo "Publish to public server: $publishToPublicServer"

$symbolServer = "${{parameters.symbolServer }}"
$tokenUri = "${{parameters.symbolTokenUri }}"
# Registered project name in the symbol publishing pipeline: https://portal.microsofticm.com/imp/v3/incidents/incident/520844254/summary
$projectName = "Microsoft.Data.SqlClient.SNI"

# Get the access token for the symbol publishing service
$symbolPublishingToken = az account get-access-token --resource $tokenUri --query accessToken -o tsv

echo "> 1.Symbol publishing token acquired."

echo "Registering the request name ..."
$requestName = "${{parameters.symbolsArtifactName }}"
$requestNameRegistrationBody = "{'requestName': '$requestName'}"
Invoke-RestMethod -Method POST -Uri "https://$symbolServer.trafficmanager.net/projects/$projectName/requests" -Headers @{ Authorization = "Bearer $symbolPublishingToken" } -ContentType "application/json" -Body $requestNameRegistrationBody

echo "> 2.Registration of request name succeeded."

echo "Publishing the symbols ..."
$publishSymbolsBody = "{'publishToInternalServer': $publishToInternalServer, 'publishToPublicServer': $publishToPublicServer}"
echo "Publishing symbols request body: $publishSymbolsBody"
Invoke-RestMethod -Method POST -Uri "https://$symbolServer.trafficmanager.net/projects/$projectName/requests/$requestName" -Headers @{ Authorization = "Bearer $symbolPublishingToken" } -ContentType "application/json" -Body $publishSymbolsBody

echo "> 3.Request to publish symbols succeeded."

# The following REST calls are used to check publishing status.
echo "> 4.Checking the status of the request ..."

Invoke-RestMethod -Method GET -Uri "https://$symbolServer.trafficmanager.net/projects/$projectName/requests/$requestName" -Headers @{ Authorization = "Bearer $symbolPublishingToken" } -ContentType "application/json"

echo "Use below tables to interpret the values of xxxServerStatus and xxxServerResult fields from the response."

echo "PublishingStatus"
echo "-----------------"
echo "0 NotRequested; The request has not been requested to publish."
echo "1 Submitted; The request is submitted to be published"
echo "2 Processing; The request is still being processed"
echo "3 Completed; The request has been completed processing. It can be failed or successful. Check PublishingResult to get more details"

echo "PublishingResult"
echo "-----------------"
echo "0 Pending; The request has not completed or has not been requested."
echo "1 Succeeded; The request has published successfully"
echo "2 Failed; The request has failed to publish"
echo "3 Cancelled; The request was cancelled"
scriptLocation: scriptPath
scriptPath: '$(Build.SourcesDirectory)/eng/pipelines/common/templates/steps/Publish-Symbols.ps1'
arguments: >-
-PublishServer "${{parameters.symbolServer }}"
-PublishTokenUri "${{parameters.symbolTokenUri }}"
-PublishProjectName "${{parameters.symbolsPublishProjectName }}"
-ArtifactName "${{parameters.symbolsArtifactName }}_$(System.JobAttempt)"
-PublishToInternal $${{parameters.publishToServers.internal }}
-PublishToPublic $${{parameters.publishToServers.public }}
Loading
Loading