diff --git a/eng/pipelines/jobs/publish-npm.yml b/eng/pipelines/jobs/publish-npm.yml index d8ff39baad..5222c35099 100644 --- a/eng/pipelines/jobs/publish-npm.yml +++ b/eng/pipelines/jobs/publish-npm.yml @@ -35,6 +35,13 @@ jobs: - script: ls $(Pipeline.Workspace)/${{ parameters.artifactName }} displayName: List files in artifact + # Publish to the Azure DevOps feed first (bypasses the 7-day npmjs.org quarantine), + # then publish to npmjs.org via ESRP. + - template: /eng/pipelines/templates/release/ado-feed-release.yml + parameters: + tag: ${{ parameters.tag }} + path: "$(Pipeline.Workspace)/${{ parameters.artifactName }}" + - template: /eng/pipelines/templates/release/esrp-release.yml parameters: tag: ${{ parameters.tag }} diff --git a/eng/pipelines/templates/release/ado-feed-release.yml b/eng/pipelines/templates/release/ado-feed-release.yml new file mode 100644 index 0000000000..b53aa59934 --- /dev/null +++ b/eng/pipelines/templates/release/ado-feed-release.yml @@ -0,0 +1,49 @@ +# cspell:ignore EPUBLISHCONFLICT +parameters: + - name: tag + type: string + default: latest + - name: path + type: string + - name: registryUrl + type: string + default: https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-js/npm/registry/ + +steps: + # Publishing the packages directly to the Azure DevOps `azure-sdk-for-js` feed bypasses the + # upstream npmjs.org quarantine (which blocks newly released packages for 7 days) so CI can + # consume freshly released packages immediately. + - template: /eng/common/pipelines/templates/steps/create-authenticated-npmrc.yml + parameters: + npmrcPath: ${{ parameters.path }}/.npmrc + registryUrl: ${{ parameters.registryUrl }} + + - pwsh: | + $packageFiles = Get-ChildItem -Path . -Filter '*.tgz' + $hadError = $false + foreach ($file in $packageFiles.Name) { + Write-Host "npm publish $file --verbose --access public --tag ${{ parameters.tag }}" + $output = npm publish $file --verbose --access public --tag ${{ parameters.tag }} 2>&1 + $output | ForEach-Object { Write-Host $_ } + if ($LASTEXITCODE -ne 0) { + $text = $output -join "`n" + # Treat "version already exists" as a no-op, matching the npm/ESRP behavior of not + # republishing an existing version. Any other failure is a genuine error and must fail. + if ($text -match 'EPUBLISHCONFLICT' -or + $text -match 'cannot publish over the previously published versions' -or + $text -match 'You cannot publish over the previously published versions' -or + $text -match 'previously published version' -or + $text -match '\b409\b') { + Write-Warning "Version for $file already exists in the feed, skipping." + } else { + Write-Error "Failed to publish $file to the DevOps feed." + $hadError = $true + } + } + } + if ($hadError) { + exit 1 + } + displayName: Publish to DevOps feed (${{ parameters.tag }}) + condition: and(succeeded(), ne(variables['SkipPublishing'], 'true')) + workingDirectory: ${{ parameters.path }}