From 03fb38d947d9be9acba095fe036f4fe29ffb8877 Mon Sep 17 00:00:00 2001 From: helen229 Date: Fri, 23 Oct 2026 11:51:10 -0700 Subject: [PATCH 1/2] Pass optional SDK PRs safely to shared release completion --- eng/common/CHANGELOG.md | 8 ++++++++ .../templates/steps/mark-release-completion.yml | 9 ++++++++- eng/common/scripts/Mark-ReleasePlanCompletion.ps1 | 15 +++++++++++---- 3 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 eng/common/CHANGELOG.md diff --git a/eng/common/CHANGELOG.md b/eng/common/CHANGELOG.md new file mode 100644 index 0000000000000..359f3428d55bc --- /dev/null +++ b/eng/common/CHANGELOG.md @@ -0,0 +1,8 @@ +# Common engineering release history + +## Unreleased + +### Bugs Fixed + +- Release-plan completion uses the job's `AutoReleaseSdkPullRequestUrl` when no explicit `SdkPullRequest` is supplied. An absent or empty variable is initialized to an empty string at runtime before macro expansion, so manual runs do not pass an unresolved variable. Existing runtime values and explicit parameters are preserved. +- Direct calls to the shared completion script supply the current release-run URL from complete Azure Pipelines context when no URL argument is given. Matching the recorded run requires the corresponding CLI update. diff --git a/eng/common/pipelines/templates/steps/mark-release-completion.yml b/eng/common/pipelines/templates/steps/mark-release-completion.yml index 7f6e1c5f2a424..64e4353b75199 100644 --- a/eng/common/pipelines/templates/steps/mark-release-completion.yml +++ b/eng/common/pipelines/templates/steps/mark-release-completion.yml @@ -10,6 +10,13 @@ steps: parameters: SourceRootPath: ${{ parameters.SourceRootPath }} + # Runtime output variables must not be tested at template-expansion time. + # Initialize the optional macro before use on manual runs that have no SDK PR. + - ${{ if eq(parameters.SdkPullRequest, '') }}: + - pwsh: Write-Host '##vso[task.setvariable variable=AutoReleaseSdkPullRequestUrl]' + displayName: Initialize optional auto-release SDK PR + condition: and(succeeded(), ne(variables['Skip.MarkReleaseCompletion'], 'true'), eq(variables['AutoReleaseSdkPullRequestUrl'], '')) + - task: AzureCLI@2 inputs: azureSubscription: opensource-api-connection @@ -19,7 +26,7 @@ steps: arguments: > -PackageInfoFilePath '${{ parameters.ConfigFileDir }}/${{ parameters.PackageArtifactName }}.json' -AzsdkExePath '$(AZSDK)' -ReleasePlanId '${{ parameters.ReleasePlanId }}' - -SdkPullRequest '${{ parameters.SdkPullRequest }}' + -SdkPullRequest '${{ coalesce(parameters.SdkPullRequest, '$(AutoReleaseSdkPullRequestUrl)') }}' -PipelineUrl "$(System.CollectionUri)$(System.TeamProject)/_build/results?buildId=$(Build.BuildId)" workingDirectory: $(Pipeline.Workspace) displayName: Mark package as released diff --git a/eng/common/scripts/Mark-ReleasePlanCompletion.ps1 b/eng/common/scripts/Mark-ReleasePlanCompletion.ps1 index da116172c747c..4900adecd3996 100644 --- a/eng/common/scripts/Mark-ReleasePlanCompletion.ps1 +++ b/eng/common/scripts/Mark-ReleasePlanCompletion.ps1 @@ -24,8 +24,8 @@ param( .DESCRIPTION Uses the requester-supplied release-plan ID for manual releases, or the triggering SDK PR for automatic releases. azsdk resolves the existing ADO plan and validates the language/package. - TRANSITIONAL: when neither is supplied, the original package-name lookup is used and an informational message is logged - so pipelines that do not yet forward the association keep working. Remove once every pipeline forwards one. + When neither is supplied, the current run URL can identify the plan recorded by auto-release preparation. + TRANSITIONAL: without a recorded association, azsdk falls back to the package-name lookup. .PARAMETER PackageInfoFilePath The path to the package information file (required) or path to the directory containing package information files. @@ -40,12 +40,19 @@ param( The unambiguous SDK PR that triggered the automatic release. Not a spec PR or a previous package PR. .PARAMETER PipelineUrl - The current release pipeline URL, recorded for manual and automatic releases. + The current release pipeline URL, recorded for manual and automatic releases. When omitted in Azure Pipelines, + derive it from the current run so direct script callers retain the preparation-stage association. #> Set-StrictMode -Version 4 $ErrorActionPreference = 'Stop' [int]$suppliedPlanId = [int]::Parse($ReleasePlanId, [System.Globalization.CultureInfo]::InvariantCulture) +if ([string]::IsNullOrWhiteSpace($PipelineUrl) -and $env:TF_BUILD -eq 'True' -and + -not [string]::IsNullOrWhiteSpace($env:SYSTEM_COLLECTIONURI) -and + -not [string]::IsNullOrWhiteSpace($env:SYSTEM_TEAMPROJECT) -and $env:BUILD_BUILDID -match '^[1-9][0-9]*$') +{ + $PipelineUrl = "$env:SYSTEM_COLLECTIONURI$env:SYSTEM_TEAMPROJECT/_build/results?buildId=$env:BUILD_BUILDID" +} . (Join-Path $PSScriptRoot common.ps1) #Validate azsdk executable path @@ -78,7 +85,7 @@ function Process-Package([string]$packageInfoPath) return } - $isLegacyLookup = ($suppliedPlanId -eq 0 -and [string]::IsNullOrWhiteSpace($SdkPullRequest)) + $isLegacyLookup = ($suppliedPlanId -eq 0 -and [string]::IsNullOrWhiteSpace($SdkPullRequest) -and [string]::IsNullOrWhiteSpace($PipelineUrl)) if ($isLegacyLookup) { Write-Host "LEGACY_RELEASE_PLAN_LOOKUP: Package '$PackageName' has no release-plan ID or triggering SDK PR; using the legacy package lookup. Forward ReleasePlanId or SdkPullRequest from the release pipeline." From f6612b73023df4af6ad9105b4bc772d6b62123f8 Mon Sep 17 00:00:00 2001 From: helen229 Date: Fri, 23 Oct 2026 13:57:54 -0700 Subject: [PATCH 2/2] Address shared release completion review feedback --- eng/common/CHANGELOG.md | 3 +-- .../templates/steps/mark-release-completion.yml | 4 +++- eng/common/scripts/Mark-ReleasePlanCompletion.ps1 | 15 ++++----------- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/eng/common/CHANGELOG.md b/eng/common/CHANGELOG.md index 359f3428d55bc..1fb3e6ac1e8ee 100644 --- a/eng/common/CHANGELOG.md +++ b/eng/common/CHANGELOG.md @@ -4,5 +4,4 @@ ### Bugs Fixed -- Release-plan completion uses the job's `AutoReleaseSdkPullRequestUrl` when no explicit `SdkPullRequest` is supplied. An absent or empty variable is initialized to an empty string at runtime before macro expansion, so manual runs do not pass an unresolved variable. Existing runtime values and explicit parameters are preserved. -- Direct calls to the shared completion script supply the current release-run URL from complete Azure Pipelines context when no URL argument is given. Matching the recorded run requires the corresponding CLI update. +- Release-plan completion uses the job's `AutoReleaseSdkPullRequestUrl` when no explicit `SdkPullRequest` is supplied. An absent or empty variable is initialized to an empty string at runtime before macro expansion, so manual runs do not pass an unresolved variable. Empty initialization is logged. Existing runtime values and explicit parameters are preserved. diff --git a/eng/common/pipelines/templates/steps/mark-release-completion.yml b/eng/common/pipelines/templates/steps/mark-release-completion.yml index 64e4353b75199..1bb3f01c37be9 100644 --- a/eng/common/pipelines/templates/steps/mark-release-completion.yml +++ b/eng/common/pipelines/templates/steps/mark-release-completion.yml @@ -13,7 +13,9 @@ steps: # Runtime output variables must not be tested at template-expansion time. # Initialize the optional macro before use on manual runs that have no SDK PR. - ${{ if eq(parameters.SdkPullRequest, '') }}: - - pwsh: Write-Host '##vso[task.setvariable variable=AutoReleaseSdkPullRequestUrl]' + - pwsh: | + Write-Host '##vso[task.setvariable variable=AutoReleaseSdkPullRequestUrl]' + Write-Host 'AutoReleaseSdkPullRequestUrl is set to an empty string.' displayName: Initialize optional auto-release SDK PR condition: and(succeeded(), ne(variables['Skip.MarkReleaseCompletion'], 'true'), eq(variables['AutoReleaseSdkPullRequestUrl'], '')) diff --git a/eng/common/scripts/Mark-ReleasePlanCompletion.ps1 b/eng/common/scripts/Mark-ReleasePlanCompletion.ps1 index 4900adecd3996..da116172c747c 100644 --- a/eng/common/scripts/Mark-ReleasePlanCompletion.ps1 +++ b/eng/common/scripts/Mark-ReleasePlanCompletion.ps1 @@ -24,8 +24,8 @@ param( .DESCRIPTION Uses the requester-supplied release-plan ID for manual releases, or the triggering SDK PR for automatic releases. azsdk resolves the existing ADO plan and validates the language/package. - When neither is supplied, the current run URL can identify the plan recorded by auto-release preparation. - TRANSITIONAL: without a recorded association, azsdk falls back to the package-name lookup. + TRANSITIONAL: when neither is supplied, the original package-name lookup is used and an informational message is logged + so pipelines that do not yet forward the association keep working. Remove once every pipeline forwards one. .PARAMETER PackageInfoFilePath The path to the package information file (required) or path to the directory containing package information files. @@ -40,19 +40,12 @@ param( The unambiguous SDK PR that triggered the automatic release. Not a spec PR or a previous package PR. .PARAMETER PipelineUrl - The current release pipeline URL, recorded for manual and automatic releases. When omitted in Azure Pipelines, - derive it from the current run so direct script callers retain the preparation-stage association. + The current release pipeline URL, recorded for manual and automatic releases. #> Set-StrictMode -Version 4 $ErrorActionPreference = 'Stop' [int]$suppliedPlanId = [int]::Parse($ReleasePlanId, [System.Globalization.CultureInfo]::InvariantCulture) -if ([string]::IsNullOrWhiteSpace($PipelineUrl) -and $env:TF_BUILD -eq 'True' -and - -not [string]::IsNullOrWhiteSpace($env:SYSTEM_COLLECTIONURI) -and - -not [string]::IsNullOrWhiteSpace($env:SYSTEM_TEAMPROJECT) -and $env:BUILD_BUILDID -match '^[1-9][0-9]*$') -{ - $PipelineUrl = "$env:SYSTEM_COLLECTIONURI$env:SYSTEM_TEAMPROJECT/_build/results?buildId=$env:BUILD_BUILDID" -} . (Join-Path $PSScriptRoot common.ps1) #Validate azsdk executable path @@ -85,7 +78,7 @@ function Process-Package([string]$packageInfoPath) return } - $isLegacyLookup = ($suppliedPlanId -eq 0 -and [string]::IsNullOrWhiteSpace($SdkPullRequest) -and [string]::IsNullOrWhiteSpace($PipelineUrl)) + $isLegacyLookup = ($suppliedPlanId -eq 0 -and [string]::IsNullOrWhiteSpace($SdkPullRequest)) if ($isLegacyLookup) { Write-Host "LEGACY_RELEASE_PLAN_LOOKUP: Package '$PackageName' has no release-plan ID or triggering SDK PR; using the legacy package lookup. Forward ReleasePlanId or SdkPullRequest from the release pipeline."