Skip to content
Merged
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
12 changes: 9 additions & 3 deletions .ado/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ variables:
- name: FailCGOnAlert
value: false
- name: EnableCodesign
value: false
value: true

trigger: none
pr: none
Expand Down Expand Up @@ -145,6 +145,9 @@ extends:
- script: echo NpmDistTag is $(NpmDistTag)
displayName: Show NPM dist tag

- script: copy ".ado\scripts\npmPack.js" "$(Build.StagingDirectory)\versionEnvVars\npmPack.js"
displayName: Include npmPack.js in VersionEnvVars artifact

- task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0
displayName: 📒 Generate Manifest Npm
inputs:
Expand Down Expand Up @@ -351,9 +354,12 @@ extends:
configuration: Debug

# Symbol Publishing for Work Item 59264834 - MSRC Compliance
# continueOnError: Duplicate symbols are expected when the pipeline
# is re-run for the same version. The symbols already exist on the
# server, so it is safe to continue.
- task: PublishSymbols@2
displayName: 'Publish Symbols to Microsoft Symbol Server'
enabled: true
continueOnError: true
inputs:
UseNetCoreClientTool: true
ConnectedServiceName: Office-React-Native-Windows-Bot
Expand All @@ -362,7 +368,7 @@ extends:
SymbolServerType: 'TeamServices'
SymbolsProduct: 'ReactNativeWindows'
SymbolsVersion: '$(Build.BuildNumber)'
SymbolsArtifactName: 'ReactNativeWindows-Symbols'
SymbolsArtifactName: 'ReactNativeWindows-Symbols-$(Build.BuildId)'
DetailedLog: true
TreatNotIndexedAsWarning: false

Expand Down
117 changes: 42 additions & 75 deletions .ado/release.yml
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
#
# The Release pipeline entry point.
# It releases npm packages to npmjs.com and NuGet packages to the public
# ms/react-native and ms/react-native-public ADO feeds and to nuget.org.
#
# The triggers are overridden by the ADO pipeline UI definition.
#

name: RNW NuGet Release $(Date:yyyyMMdd).$(Rev:r)

trigger: none
pr: none

resources:
pipelines:
- pipeline: 'Publish'
project: 'ReactNative'
source: 'Publish'
trigger:
branches:
include:
- -1espublish
trigger: none
repositories:
- repository: 1ESPipelineTemplates
type: git
name: 1ESPipelineTemplates/1ESPipelineTemplates
ref: refs/tags/release

extends:
template: v1/1ES.Official.PipelineTemplate.yml@1ESPipelineTemplates
parameters:
Expand All @@ -28,13 +35,18 @@ extends:
stages:
- stage: Release
displayName: Publish artifacts
# Allow manual runs unconditionally; for build-completion triggers,
# only proceed if the commit message starts with 'RELEASE:'.
condition: or(eq(variables['Build.Reason'], 'Manual'), startsWith(variables['Build.SourceVersionMessage'], 'RELEASE:'))
jobs:
- job: PushNpm
displayName: npmjs.com - Publish npm packages
variables:
- group: RNW Secrets
timeoutInMinutes: 0
timeoutInMinutes: 30
templateContext:
type: releaseJob
isProduction: true
inputs:
- input: pipelineArtifact
pipeline: 'Publish'
Expand All @@ -45,15 +57,13 @@ extends:
artifactName: 'VersionEnvVars'
targetPath: '$(Pipeline.Workspace)/VersionEnvVars'
steps:
- checkout: self
clean: false
- task: CmdLine@2
displayName: Apply version variables
inputs:
script: node $(Pipeline.Workspace)/VersionEnvVars/versionEnvVars.js
- script: dir /s "$(Pipeline.Workspace)\published-packages"
displayName: Show npm packages before cleanup
- script: node .ado/scripts/npmPack.js --no-pack --check-npm --no-color "$(Pipeline.Workspace)\published-packages"
- script: node "$(Pipeline.Workspace)\VersionEnvVars\npmPack.js" --no-pack --check-npm --no-color "$(Pipeline.Workspace)\published-packages"
displayName: Remove already published packages
- script: dir /s "$(Pipeline.Workspace)\published-packages"
displayName: Show npm packages after cleanup
Expand Down Expand Up @@ -82,112 +92,69 @@ extends:

- job: PushPrivateAdo
displayName: ADO - nuget - react-native

timeoutInMinutes: 30
templateContext:
type: releaseJob
isProduction: true
inputs:
- input: pipelineArtifact
pipeline: 'Publish'
artifactName: 'ReactWindows-final-nuget'
targetPath: '$(Pipeline.Workspace)/ReactWindows-final-nuget'

steps:
- checkout: none

- script: dir /S $(Pipeline.Workspace)\ReactWindows-final-nuget
displayName: Show directory contents

- task: AzureCLI@2
displayName: Override NuGet credentials with Managed Identity
inputs:
azureSubscription: 'Office-React-Native-Windows-Bot'
visibleAzLogin: false
scriptType: 'pscore'
scriptLocation: 'inlineScript'
inlineScript: |
$accessToken = az account get-access-token --query accessToken --resource 499b84ac-1321-427f-aa17-267ca6975798 -o tsv
# Set the access token as a secret, so it doesn't get leaked in the logs
Write-Host "##vso[task.setsecret]$accessToken"
# Override the apitoken of the nuget service connection, for the duration of this stage
Write-Host "##vso[task.setendpoint id=a7e33797-4804-4a1d-911d-5bd325e50a85;field=authParameter;key=apitoken]$accessToken"

- task: 1ES.PublishNuGet@1
displayName: NuGet push to ms/react-native-public
inputs:
useDotNetTask: true
- template: .ado/templates/publish-nuget-to-ado-feed.yml@self
parameters:
endpointId: 'a7e33797-4804-4a1d-911d-5bd325e50a85'
nugetFeedUrl: 'https://pkgs.dev.azure.com/ms/_packaging/react-native/nuget/v3/index.json'
packageParentPath: '$(Pipeline.Workspace)/ReactWindows-final-nuget'
packagesToPush: '$(Pipeline.Workspace)/ReactWindows-final-nuget/*.nupkg'
nuGetFeedType: external
publishFeedCredentials: 'ms/react-native ADO Feed'
externalEndpoint: 'ms/react-native ADO Feed'
publishPackageMetadata: true
feedDisplayName: 'ms/react-native'

- job: PushPublicAdo
displayName: ADO - nuget - react-native-public

timeoutInMinutes: 30
templateContext:
type: releaseJob
isProduction: true
inputs:
- input: pipelineArtifact
pipeline: 'Publish'
artifactName: 'ReactWindows-final-nuget'
targetPath: '$(Pipeline.Workspace)/ReactWindows-final-nuget'

steps:
- checkout: none

- script: dir /S $(Pipeline.Workspace)\ReactWindows-final-nuget
displayName: Show directory contents

- task: AzureCLI@2
displayName: Override NuGet credentials with Managed Identity
inputs:
azureSubscription: 'Office-React-Native-Windows-Bot'
visibleAzLogin: false
scriptType: 'pscore'
scriptLocation: 'inlineScript'
inlineScript: |
$accessToken = az account get-access-token --query accessToken --resource 499b84ac-1321-427f-aa17-267ca6975798 -o tsv
# Set the access token as a secret, so it doesn't get leaked in the logs
Write-Host "##vso[task.setsecret]$accessToken"
# Override the apitoken of the nuget service connection, for the duration of this stage
Write-Host "##vso[task.setendpoint id=9a2456d0-c163-405b-be24-c03fd74b155a;field=authParameter;key=apitoken]$accessToken"

- task: 1ES.PublishNuGet@1
displayName: NuGet push to ms/react-native-public
inputs:
useDotNetTask: true
- template: .ado/templates/publish-nuget-to-ado-feed.yml@self
parameters:
endpointId: '9a2456d0-c163-405b-be24-c03fd74b155a'
nugetFeedUrl: 'https://pkgs.dev.azure.com/ms/react-native/_packaging/react-native-public/nuget/v3/index.json'
packageParentPath: '$(Pipeline.Workspace)/ReactWindows-final-nuget'
packagesToPush: '$(Pipeline.Workspace)/ReactWindows-final-nuget/*.nupkg'
nuGetFeedType: external
publishFeedCredentials: 'ms/react-native-public ADO Feed'
externalEndpoint: 'ms/react-native-public ADO Feed'
publishPackageMetadata: true
feedDisplayName: 'ms/react-native-public'

- job: PushNuGetOrg
displayName: nuget.org - Push nuget packages
variables:
- group: RNW Secrets
timeoutInMinutes: 0
timeoutInMinutes: 30
templateContext:
type: releaseJob
isProduction: true
inputs:
- input: pipelineArtifact
pipeline: 'Publish'
artifactName: 'ReactWindows-final-nuget'
targetPath: '$(Pipeline.Workspace)/ReactWindows-final-nuget'
steps:
- checkout: none
- task: NuGetToolInstaller@1
displayName: 'Use NuGet '
displayName: 'Use NuGet'
- task: CmdLine@2
displayName: NuGet SetApiKey (nuget.org)
inputs:
script: nuget.exe SetApiKey $(nugetorg-apiKey-push)
workingDirectory: $(Pipeline.Workspace)/ReactWindows-final-nuget
- task: PowerShell@2
- script: dir /S "$(Pipeline.Workspace)\ReactWindows-final-nuget"
displayName: Show directory contents
- script: nuget.exe push .\Microsoft.ReactNative.*.nupkg -Source https://api.nuget.org/v3/index.json -SkipDuplicate -NoSymbol -NonInteractive -Verbosity Detailed
displayName: NuGet push (nuget.org)
inputs:
targetType: inline
errorActionPreference: silentlyContinue
script: |
if (Get-ChildItem -Path .\ -Filter '*0.0.0-canary*' -ErrorAction SilentlyContinue) { Write-Output "Canary builds found, exiting."; return 0; }
nuget.exe push .\Microsoft.ReactNative.*.nupkg -Source https://api.nuget.org/v3/index.json -SkipDuplicate -NoSymbol -NonInteractive -Verbosity Detailed
workingDirectory: $(Pipeline.Workspace)/ReactWindows-final-nuget
workingDirectory: $(Pipeline.Workspace)/ReactWindows-final-nuget
15 changes: 10 additions & 5 deletions .ado/scripts/npmPack.js
Original file line number Diff line number Diff line change
Expand Up @@ -391,14 +391,19 @@ function main() {
const targetDirArg = args.positionals[0];

try {
// Find repo root
const repoRoot = findEnlistmentRoot();
console.log(`${colorize('Repository root:', colors.bright)} ${repoRoot}`);
// Find repo root (not needed when --no-pack is used with an absolute path)
const repoRoot = (noPackFlag && targetDirArg && path.isAbsolute(targetDirArg))
? null
: findEnlistmentRoot();

if (repoRoot) {
console.log(`${colorize('Repository root:', colors.bright)} ${repoRoot}`);
}

// Determine target directory
const targetDir = targetDirArg
? path.resolve(repoRoot, targetDirArg)
: path.join(repoRoot, 'npm-pkgs');
? (repoRoot ? path.resolve(repoRoot, targetDirArg) : path.resolve(targetDirArg))
: path.join(/** @type {string} */ (repoRoot), 'npm-pkgs');

console.log(`${colorize('Target directory:', colors.bright)} ${targetDir}`);

Expand Down
11 changes: 0 additions & 11 deletions .ado/templates/authenticate-office-react-native-windows-bot.yml

This file was deleted.

106 changes: 106 additions & 0 deletions .ado/templates/publish-nuget-to-ado-feed.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
parameters:
- name: azureSubscription
type: string
default: 'Office-React-Native-Windows-Bot'
- name: endpointId
type: string
- name: nugetFeedUrl
type: string
- name: packageParentPath
type: string
- name: packagesToPush
type: string
- name: publishFeedCredentials
type: string
- name: feedDisplayName
type: string

steps:
- script: dir /S "${{ parameters.packageParentPath }}"
displayName: Show NuGet packages before cleanup

- task: AzureCLI@2
displayName: Override NuGet credentials with Managed Identity
inputs:
azureSubscription: ${{ parameters.azureSubscription }}
visibleAzLogin: false
scriptType: 'pscore'
scriptLocation: 'inlineScript'
inlineScript: |
$accessToken = az account get-access-token --query accessToken --resource 499b84ac-1321-427f-aa17-267ca6975798 -o tsv
# Set the access token as a secret, so it doesn't get leaked in the logs
Write-Host "##vso[task.setsecret]$accessToken"
# Override the apitoken of the nuget service connection, for the duration of this stage
Write-Host "##vso[task.setendpoint id=${{ parameters.endpointId }};field=authParameter;key=apitoken]$accessToken"
# Also expose the token for the pre-push duplicate check
Write-Host "##vso[task.setvariable variable=NuGetAccessToken;issecret=true]$accessToken"

- powershell: |
Add-Type -AssemblyName System.IO.Compression.FileSystem

$feedUrl = "${{ parameters.nugetFeedUrl }}"
$token = "$(NuGetAccessToken)"
$headers = @{ Authorization = "Bearer $token" }

# Discover the flat container (PackageBaseAddress) URL from the V3 index
$index = Invoke-RestMethod -Uri $feedUrl -Headers $headers
$baseAddress = ($index.resources |
Where-Object { $_.'@type' -like 'PackageBaseAddress*' } |
Select-Object -First 1).'@id'
if (-not $baseAddress) { throw "Could not find PackageBaseAddress in NuGet V3 index at $feedUrl" }
if (-not $baseAddress.EndsWith('/')) { $baseAddress += '/' }
Write-Host "PackageBaseAddress: $baseAddress"

$nupkgs = Get-ChildItem -Path "${{ parameters.packageParentPath }}" -Filter "*.nupkg" -Recurse
$removedCount = 0

foreach ($file in $nupkgs) {
# Read the .nuspec from inside the nupkg (zip) to get the exact id and version
$zip = [System.IO.Compression.ZipFile]::OpenRead($file.FullName)
try {
$nuspecEntry = $zip.Entries | Where-Object { $_.FullName -like "*.nuspec" } | Select-Object -First 1
$reader = New-Object System.IO.StreamReader($nuspecEntry.Open())
[xml]$nuspec = $reader.ReadToEnd()
$reader.Close()
} finally { $zip.Dispose() }

$id = $nuspec.package.metadata.id
$version = $nuspec.package.metadata.version

# Query the flat container for all published versions of this package
$versionsUrl = "${baseAddress}$($id.ToLower())/index.json"
try {
$result = Invoke-RestMethod -Uri $versionsUrl -Headers $headers -ErrorAction Stop
if ($version.ToLower() -in $result.versions) {
Write-Host " SKIP $id $version — already on feed"
Remove-Item $file.FullName
$removedCount++
continue
}
} catch {
if ($_.Exception.Response.StatusCode -eq [System.Net.HttpStatusCode]::NotFound) {
# Package has never been published — keep it
} else { throw }
}
Write-Host " PUSH $id $version — new"
}

$remaining = (Get-ChildItem -Path "${{ parameters.packageParentPath }}" -Filter "*.nupkg" -Recurse).Count
Write-Host "Removed $removedCount already-published package(s). $remaining package(s) to push."
Write-Host "##vso[task.setvariable variable=HasNewPackages]$($remaining -gt 0)"
displayName: Remove already-published packages

- script: dir /S "${{ parameters.packageParentPath }}"
displayName: Show NuGet packages after cleanup

- task: 1ES.PublishNuGet@1
displayName: 'NuGet push to ${{ parameters.feedDisplayName }}'
condition: and(succeeded(), eq(variables['HasNewPackages'], 'True'))
inputs:
useDotNetTask: true
packageParentPath: '${{ parameters.packageParentPath }}'
packagesToPush: '${{ parameters.packagesToPush }}'
nuGetFeedType: external
publishFeedCredentials: '${{ parameters.publishFeedCredentials }}'
externalEndpoint: '${{ parameters.publishFeedCredentials }}'
publishPackageMetadata: true
Loading