Skip to content

Commit 9d7aeb0

Browse files
authored
[0.82] New release pipeline file (#15887)
* New release-pipeline.yml file (#15881) * Disable CodeQL in Setup job (#15882)
1 parent 07b2efc commit 9d7aeb0

2 files changed

Lines changed: 351 additions & 0 deletions

File tree

.ado/build-template.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,9 @@ extends:
206206
condition: and(succeeded(), eq('${{ parameters.buildEnvironment }}', 'Continuous'))
207207

208208
templateContext:
209+
sdl:
210+
codeql:
211+
enabled: false
209212
outputs:
210213
- output: pipelineArtifact
211214
displayName: 'Publish version variables'

.ado/release-pipeline.yml

Lines changed: 348 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,348 @@
1+
#
2+
# The Release pipeline entry point.
3+
# It publishes npm packages to npmjs.com, NuGet packages to the public
4+
# ms/react-native and ms/react-native-public ADO feeds and to nuget.org,
5+
# and PDB symbols to the Microsoft Symbol Server.
6+
#
7+
# This file replaces release.yml and references the renamed "CI" pipeline
8+
# (formerly "Publish"). Once all branches use this file, release.yml can
9+
# be deleted.
10+
#
11+
# The pipeline completion trigger is defined below in the pipeline resource.
12+
# Do NOT add a build completion trigger in the ADO UI — UI triggers override
13+
# YAML triggers and cause the pipeline to always run against the default branch
14+
# with incorrect metadata (wrong commit message and branch).
15+
#
16+
17+
name: RNW Release $(Date:yyyyMMdd).$(Rev:r)
18+
19+
trigger: none
20+
pr: none
21+
22+
resources:
23+
pipelines:
24+
- pipeline: 'CI'
25+
project: 'ReactNative'
26+
source: 'CI'
27+
trigger:
28+
branches:
29+
include:
30+
- main
31+
- '0.74-stable'
32+
- '0.81-stable'
33+
- '0.82-stable'
34+
- '0.83-stable'
35+
- '0.84-stable'
36+
repositories:
37+
- repository: 1ESPipelineTemplates
38+
type: git
39+
name: 1ESPipelineTemplates/1ESPipelineTemplates
40+
ref: refs/tags/release
41+
42+
extends:
43+
template: v1/1ES.Official.PipelineTemplate.yml@1ESPipelineTemplates
44+
parameters:
45+
pool:
46+
name: Azure-Pipelines-1ESPT-ExDShared
47+
image: windows-latest
48+
os: windows
49+
stages:
50+
#
51+
# Gate stage — runs unconditionally for every trigger.
52+
# It determines whether the Release stage should proceed and sets a
53+
# descriptive build number so the pipeline history is easy to scan.
54+
#
55+
- stage: Gate
56+
displayName: Evaluate release
57+
jobs:
58+
- job: Evaluate
59+
displayName: Check if release should proceed
60+
steps:
61+
- checkout: none
62+
63+
- pwsh: |
64+
Write-Host "== Build Variables =="
65+
Write-Host "Build.Reason: $env:BUILD_REASON"
66+
Write-Host "Build.SourceBranch: $env:BUILD_SOURCEBRANCH"
67+
Write-Host "Build.SourceVersion: $env:BUILD_SOURCEVERSION"
68+
Write-Host "Build.SourceVersionMessage: $env:BUILD_SOURCEVERSIONMESSAGE"
69+
Write-Host "Build.BuildNumber: $env:BUILD_BUILDNUMBER"
70+
Write-Host "Build.BuildId: $env:BUILD_BUILDID"
71+
Write-Host "Build.DefinitionName: $env:BUILD_DEFINITIONNAME"
72+
Write-Host "Build.Repository.Name: $env:BUILD_REPOSITORY_NAME"
73+
Write-Host "System.TeamProject: $env:SYSTEM_TEAMPROJECT"
74+
Write-Host ""
75+
Write-Host "== Pipeline Resource: CI =="
76+
Write-Host "CI.runName: $env:CI_RUNNAME"
77+
Write-Host "CI.runID: $env:CI_RUNID"
78+
Write-Host "CI.sourceBranch: $env:CI_SOURCEBRANCH"
79+
Write-Host "CI.sourceCommit: $env:CI_SOURCECOMMIT"
80+
Write-Host "CI.pipelineID: $env:CI_PIPELINEID"
81+
Write-Host "CI.requestedFor: $env:CI_REQUESTEDFOR"
82+
Write-Host "CI.requestedForID: $env:CI_REQUESTEDFORID"
83+
displayName: Log all pipeline variables
84+
env:
85+
BUILD_REASON: $(Build.Reason)
86+
BUILD_SOURCEBRANCH: $(Build.SourceBranch)
87+
BUILD_SOURCEVERSION: $(Build.SourceVersion)
88+
BUILD_SOURCEVERSIONMESSAGE: $(Build.SourceVersionMessage)
89+
BUILD_BUILDNUMBER: $(Build.BuildNumber)
90+
BUILD_BUILDID: $(Build.BuildId)
91+
BUILD_DEFINITIONNAME: $(Build.DefinitionName)
92+
BUILD_REPOSITORY_NAME: $(Build.Repository.Name)
93+
SYSTEM_TEAMPROJECT: $(System.TeamProject)
94+
CI_RUNNAME: $(resources.pipeline.CI.runName)
95+
CI_RUNID: $(resources.pipeline.CI.runID)
96+
CI_SOURCEBRANCH: $(resources.pipeline.CI.sourceBranch)
97+
CI_SOURCECOMMIT: $(resources.pipeline.CI.sourceCommit)
98+
CI_PIPELINEID: $(resources.pipeline.CI.pipelineID)
99+
CI_REQUESTEDFOR: $(resources.pipeline.CI.requestedFor)
100+
CI_REQUESTEDFORID: $(resources.pipeline.CI.requestedForID)
101+
102+
- pwsh: |
103+
$buildReason = $env:BUILD_REASON
104+
# Use only the first line of the commit message
105+
$sourceMessage = ($env:SOURCE_MESSAGE -split "`n")[0].Trim()
106+
$ciRunName = $env:CI_RUN_NAME
107+
$sourceBranch = $env:SOURCE_BRANCH -replace '^refs/heads/', ''
108+
109+
# Extract the datestamp (e.g. "20260319.4") from the original build number
110+
# which has the format "RNW Release 20260319.4"
111+
$originalBuildNumber = $env:BUILD_BUILDNUMBER
112+
$dateStamp = if ($originalBuildNumber -match '(\d{8}\.\d+)$') { $Matches[1] } else { "" }
113+
114+
$shouldRelease = $false
115+
$buildNumber = ""
116+
117+
if ($buildReason -eq "Manual") {
118+
$shouldRelease = $true
119+
if ($ciRunName) {
120+
$buildNumber = "$ciRunName ($sourceBranch) - $dateStamp"
121+
} else {
122+
$buildNumber = "Release ($sourceBranch) - $dateStamp"
123+
}
124+
}
125+
elseif ($sourceMessage.StartsWith("RELEASE:")) {
126+
$shouldRelease = $true
127+
$buildNumber = "$ciRunName ($sourceBranch) - $dateStamp"
128+
}
129+
else {
130+
$shouldRelease = $false
131+
# Truncate commit message for readability
132+
$shortMsg = $sourceMessage
133+
if ($shortMsg.Length -gt 60) {
134+
$shortMsg = $shortMsg.Substring(0, 57) + "..."
135+
}
136+
$buildNumber = "Skipped - $shortMsg ($sourceBranch) - $dateStamp"
137+
}
138+
139+
# Sanitize: ADO build numbers cannot contain " / : < > \ | ? @ *
140+
# and cannot end with '.'
141+
$buildNumber = $buildNumber -replace '["/:<>\\|?@*]', '_'
142+
$buildNumber = $buildNumber.TrimEnd('.')
143+
144+
Write-Host "shouldRelease: $shouldRelease"
145+
Write-Host "buildNumber: $buildNumber"
146+
147+
Write-Host "##vso[build.updatebuildnumber]$buildNumber"
148+
Write-Host "##vso[task.setvariable variable=shouldRelease;isOutput=true]$shouldRelease"
149+
name: gate
150+
displayName: Determine release eligibility and set build number
151+
env:
152+
BUILD_REASON: $(Build.Reason)
153+
BUILD_BUILDNUMBER: $(Build.BuildNumber)
154+
SOURCE_MESSAGE: $(Build.SourceVersionMessage)
155+
CI_RUN_NAME: $(resources.pipeline.CI.runName)
156+
SOURCE_BRANCH: $(resources.pipeline.CI.sourceBranch)
157+
158+
- script: echo Proceeding with release
159+
displayName: RELEASING - proceeding to publish
160+
condition: eq(variables['gate.shouldRelease'], 'True')
161+
162+
- script: echo Skipping release
163+
displayName: SKIPPED - not a RELEASE commit
164+
condition: eq(variables['gate.shouldRelease'], 'False')
165+
166+
- stage: Release
167+
displayName: Publish artifacts
168+
dependsOn: Gate
169+
condition: eq(dependencies.Gate.outputs['Evaluate.gate.shouldRelease'], 'True')
170+
jobs:
171+
- job: PushNpm
172+
displayName: npmjs.com - Publish npm packages
173+
variables:
174+
- group: RNW Secrets
175+
timeoutInMinutes: 30
176+
templateContext:
177+
type: releaseJob
178+
isProduction: true
179+
inputs:
180+
- input: pipelineArtifact
181+
pipeline: 'CI'
182+
artifactName: 'NpmPackedTarballs'
183+
targetPath: '$(Pipeline.Workspace)/published-packages'
184+
- input: pipelineArtifact
185+
pipeline: 'CI'
186+
artifactName: 'VersionEnvVars'
187+
targetPath: '$(Pipeline.Workspace)/VersionEnvVars'
188+
steps:
189+
- task: CmdLine@2
190+
displayName: Apply version variables
191+
inputs:
192+
script: node $(Pipeline.Workspace)/VersionEnvVars/versionEnvVars.js
193+
- script: dir /s "$(Pipeline.Workspace)\published-packages"
194+
displayName: Show npm packages before cleanup
195+
- script: node "$(Pipeline.Workspace)\VersionEnvVars\npmPack.js" --no-pack --check-npm --no-color "$(Pipeline.Workspace)\published-packages"
196+
displayName: Remove already published packages
197+
- script: dir /s "$(Pipeline.Workspace)\published-packages"
198+
displayName: Show npm packages after cleanup
199+
- pwsh: |
200+
$tgzFiles = Get-ChildItem -Path "$(Pipeline.Workspace)\published-packages" -Filter "*.tgz" -Recurse
201+
$tgzCount = $tgzFiles.Count
202+
Write-Host "Found $tgzCount .tgz files"
203+
Write-Host "##vso[task.setvariable variable=HasPackagesToPublish]$($tgzCount -gt 0)"
204+
displayName: Check if there are packages to publish
205+
- task: 'EsrpRelease@11'
206+
displayName: 'ESRP Release to npmjs.com'
207+
condition: and(succeeded(), ne(variables['NpmDistTag'], ''), eq(variables['HasPackagesToPublish'], 'true'))
208+
inputs:
209+
connectedservicename: 'ESRP-CodeSigning-OGX-JSHost-RNW'
210+
usemanagedidentity: false
211+
keyvaultname: 'OGX-JSHost-KV'
212+
authcertname: 'OGX-JSHost-Auth4'
213+
signcertname: 'OGX-JSHost-Sign3'
214+
clientid: '0a35e01f-eadf-420a-a2bf-def002ba898d'
215+
domaintenantid: 'cdc5aeea-15c5-4db6-b079-fcadd2505dc2'
216+
contenttype: npm
217+
folderlocation: '$(Pipeline.Workspace)\published-packages'
218+
productstate: '$(NpmDistTag)'
219+
owners: 'vmorozov@microsoft.com'
220+
approvers: 'khosany@microsoft.com'
221+
222+
- job: PushPrivateAdo
223+
displayName: ADO - nuget - react-native
224+
timeoutInMinutes: 30
225+
templateContext:
226+
type: releaseJob
227+
isProduction: true
228+
inputs:
229+
- input: pipelineArtifact
230+
pipeline: 'CI'
231+
artifactName: 'ReactWindows-final-nuget'
232+
targetPath: '$(Pipeline.Workspace)/ReactWindows-final-nuget'
233+
steps:
234+
- template: .ado/templates/publish-nuget-to-ado-feed.yml@self
235+
parameters:
236+
endpointId: 'a7e33797-4804-4a1d-911d-5bd325e50a85'
237+
nugetFeedUrl: 'https://pkgs.dev.azure.com/ms/_packaging/react-native/nuget/v3/index.json'
238+
packageParentPath: '$(Pipeline.Workspace)/ReactWindows-final-nuget'
239+
packagesToPush: '$(Pipeline.Workspace)/ReactWindows-final-nuget/*.nupkg'
240+
publishFeedCredentials: 'ms/react-native ADO Feed'
241+
feedDisplayName: 'ms/react-native'
242+
243+
- job: PushPublicAdo
244+
displayName: ADO - nuget - react-native-public
245+
timeoutInMinutes: 30
246+
templateContext:
247+
type: releaseJob
248+
isProduction: true
249+
inputs:
250+
- input: pipelineArtifact
251+
pipeline: 'CI'
252+
artifactName: 'ReactWindows-final-nuget'
253+
targetPath: '$(Pipeline.Workspace)/ReactWindows-final-nuget'
254+
steps:
255+
- template: .ado/templates/publish-nuget-to-ado-feed.yml@self
256+
parameters:
257+
endpointId: '9a2456d0-c163-405b-be24-c03fd74b155a'
258+
nugetFeedUrl: 'https://pkgs.dev.azure.com/ms/react-native/_packaging/react-native-public/nuget/v3/index.json'
259+
packageParentPath: '$(Pipeline.Workspace)/ReactWindows-final-nuget'
260+
packagesToPush: '$(Pipeline.Workspace)/ReactWindows-final-nuget/*.nupkg'
261+
publishFeedCredentials: 'ms/react-native-public ADO Feed'
262+
feedDisplayName: 'ms/react-native-public'
263+
264+
- job: PushNuGetOrg
265+
displayName: nuget.org - Push nuget packages
266+
variables:
267+
- group: RNW Secrets
268+
timeoutInMinutes: 30
269+
templateContext:
270+
type: releaseJob
271+
isProduction: true
272+
inputs:
273+
- input: pipelineArtifact
274+
pipeline: 'CI'
275+
artifactName: 'ReactWindows-final-nuget'
276+
targetPath: '$(Pipeline.Workspace)/ReactWindows-final-nuget'
277+
steps:
278+
- task: NuGetToolInstaller@1
279+
displayName: 'Use NuGet'
280+
- pwsh: nuget.exe SetApiKey "$env:NUGET_API_KEY"
281+
displayName: NuGet SetApiKey (nuget.org)
282+
workingDirectory: $(Pipeline.Workspace)/ReactWindows-final-nuget
283+
env:
284+
NUGET_API_KEY: $(nugetorg-apiKey-push)
285+
- script: dir /S "$(Pipeline.Workspace)\ReactWindows-final-nuget"
286+
displayName: Show directory contents
287+
- script: nuget.exe push .\Microsoft.ReactNative.*.nupkg -Source https://api.nuget.org/v3/index.json -SkipDuplicate -NoSymbol -NonInteractive -Verbosity Detailed
288+
displayName: NuGet push (nuget.org)
289+
workingDirectory: $(Pipeline.Workspace)/ReactWindows-final-nuget
290+
291+
- job: PublishSymbols
292+
displayName: Publish PDB Symbols to Symbol Server
293+
timeoutInMinutes: 30
294+
templateContext:
295+
type: releaseJob
296+
isProduction: true
297+
inputs:
298+
- input: pipelineArtifact
299+
pipeline: 'CI'
300+
artifactName: 'ReactWindows-final-nuget'
301+
targetPath: '$(Pipeline.Workspace)/ReactWindows-final-nuget'
302+
steps:
303+
- pwsh: |
304+
# Extract PDB files from all NuGet packages (.nupkg are ZIP archives)
305+
$nugetDir = "$(Pipeline.Workspace)/ReactWindows-final-nuget"
306+
$symbolsDir = "$(Pipeline.Workspace)/symbols"
307+
New-Item -ItemType Directory -Path $symbolsDir -Force | Out-Null
308+
309+
$nupkgs = Get-ChildItem "$nugetDir/*.nupkg"
310+
Write-Host "Found $($nupkgs.Count) NuGet packages"
311+
312+
foreach ($nupkg in $nupkgs) {
313+
Write-Host "Extracting PDBs from: $($nupkg.Name)"
314+
$extractDir = "$symbolsDir/$($nupkg.BaseName)"
315+
# Rename to .zip for Expand-Archive compatibility
316+
$zipPath = "$nugetDir/$($nupkg.BaseName).zip"
317+
Copy-Item $nupkg.FullName $zipPath
318+
Expand-Archive -Path $zipPath -DestinationPath $extractDir -Force
319+
Remove-Item $zipPath
320+
}
321+
322+
# Show extracted PDBs
323+
$pdbs = Get-ChildItem "$symbolsDir" -Recurse -Filter "*.pdb"
324+
Write-Host "`nFound $($pdbs.Count) PDB files:"
325+
foreach ($pdb in $pdbs) {
326+
Write-Host " $($pdb.FullName) ($([math]::Round($pdb.Length / 1MB, 2)) MB)"
327+
}
328+
329+
if ($pdbs.Count -eq 0) {
330+
Write-Host "##vso[task.logissue type=warning]No PDB files found in NuGet packages"
331+
}
332+
displayName: Extract PDBs from NuGet packages
333+
334+
- task: PublishSymbols@2
335+
displayName: 'Publish Symbols to Microsoft Symbol Server'
336+
continueOnError: true
337+
inputs:
338+
UseNetCoreClientTool: true
339+
ConnectedServiceName: Office-React-Native-Windows-Bot
340+
SymbolsFolder: '$(Pipeline.Workspace)/symbols'
341+
SearchPattern: '**/*.pdb'
342+
SymbolServerType: 'TeamServices'
343+
IndexSources: false # SourceLink is already embedded in PDBs at compile time
344+
SymbolsProduct: 'ReactNativeWindows'
345+
SymbolsVersion: '$(Build.BuildNumber)'
346+
SymbolsArtifactName: 'ReactNativeWindows-Symbols-$(Build.BuildId)'
347+
DetailedLog: true
348+
TreatNotIndexedAsWarning: false

0 commit comments

Comments
 (0)