diff --git a/doc/release_process.md b/doc/release_process.md index 6ac034a1..63dfd3c2 100644 --- a/doc/release_process.md +++ b/doc/release_process.md @@ -21,19 +21,23 @@ Its package and assembly name is `Microsoft.DurableTask.LargePayloadPurge.Abstra standard `Microsoft.DurableTask.*.dll` signing pattern. The existing source traversal, SBOM inclusion, NuGet signing and per-package approval-gated publication steps apply. -Contract publication also waits for successful Client and Abstractions publication. If either prerequisite -fails, including a duplicate-version upload failure, or is skipped or canceled, contract publication is -skipped rather than treating that result as success. +Contract publication also waits for successful Client and Abstractions jobs. Each prerequisite must +either publish successfully or complete an explicit successful no-op because the operator confirmed its +selected artifact version is already on NuGet.org using `alreadyPublishedPackages`. If either job fails, +including a duplicate-version upload failure, or is skipped or canceled, contract +publication is skipped rather than treating that result as success. `Microsoft.DurableTask.Extensions.AzureBlobPayloads` depends on the contract package at every target framework, so its publication job also waits for successful contract publication (in addition to approval). -If contract publication fails for any reason above, including a duplicate-version upload failure, or is -skipped or canceled, Blob publication is skipped rather than treating that result as success. This extends -the same fail-closed chain: approval, then Client and Abstractions, then the contract, then Blob. A -prerequisite that deliberately skips — for example because its exact version is already published — still -skips the dependent job; this is not a general-purpose publication-idempotency mechanism, just the minimum -ordering these two packages require. Other packages retain their own independent publication jobs gated -only on approval. +If the contract job fails for any reason above, including a duplicate-version upload failure, or is +skipped or canceled, Blob publication is skipped rather than treating that result +as success. This extends the same fail-closed chain: approval, then Client and Abstractions, then the +contract, then Blob. An already-published confirmation succeeds without staging or submitting that +package, allowing recovery of a partial release: confirm Client/Abstractions to retry the contract and +Blob. For a Blob-only retry, confirm all selected versions already published, including Client, +Abstractions and the contract; their jobs still follow the dependency chain but complete as no-ops. +The confirmation list defaults to empty and applies only to the selected run. Other packages retain +their own independent publication jobs gated only on approval. Keep its `RELEASENOTES.md`: `eng/targets/Release.targets` reads it into NuGet package metadata, whereas the root `CHANGELOG.md` retains repository release history. The shared target also appends a link using the @@ -117,14 +121,57 @@ After the PR is merged, follow the **Publishing** steps below. ## Publishing (After Release PR is Merged) -1. Kick off [ADO release build](https://dev.azure.com/durabletaskframework/Durable%20Task%20Framework%20CI/_build?definitionId=29) (use the tag as the build target, enter `refs/tags/`) -2. Validate signing, package contents (if build changes were made.) -3. Create ADO release. - - From successful ADO release build, click 3 dots in top right → 'Release'. -4. Release to ADO feed. -5. Release to NuGet once validated (and dependencies are also released to NuGet.) -6. Publish GitHub draft release. -7. Delete contents of all `RELEASENOTES.md` files. +1. Select a successful, signed [official build](https://dev.azure.com/azfunc/internal/_build?definitionId=657). + The publisher uses its `drop` unchanged; it does not rebuild or repack. +2. Validate the selected build's source commit, signatures, package contents, and exact versions. +3. Use [`durabletask-dotnet.publish`](https://dev.azure.com/azfunc/internal/_build?definitionId=1100) + (`eng/publish/publish.yml`) with the reviewed publisher source. Select the signed build separately + through the `officialPipeline` artifact resource; do not rely on "latest" or assume the release tag + contains the current publisher. +4. Supply `nuGetOrganization`, the NuGet.org organization confirmed during ESRP NuGet onboarding. + There is no organization default; an unset or unresolved value fails before any ESRP submission. + Set `alreadyPublishedPackages` to exact public package IDs only after verifying their **selected + artifact versions** already exist on NuGet.org. Those jobs log a successful no-op, without package + staging or an ESRP task, so dependent jobs can proceed. +5. The publisher first stages the signed packages to the existing internal ADO feed. Only after that + succeeds does `nugetApproval` wait for manual approval. The gate displays the selected organization + and confirmed-public IDs. Verify onboarding, the exact selected versions and dependency availability + before approving. Stop at the gate for validation-only runs. + Rejecting or timing out the gate prevents all public publication. +6. After approval, each public package not already confirmed published is copied unchanged into + its own ESRP folder using the exact nuspec ID, then submitted with `EsrpRelease@14` and + `WaitForReleaseCompletion: true`. + Internal-only/test packages and symbol packages are not submitted. Missing or multiple matching + packages fail explicitly. Each package retains its independent job and the dependency gates above; + ESRP does not guarantee ordering within a multi-package submission. +7. Publish GitHub draft release. +8. Delete contents of all `RELEASENOTES.md` files. + +### ESRP NuGet prerequisites + +Follow the [ESRP NuGet onboarding guide](https://eng.ms/docs/microsoft-security/identity/trust-and-security-services/tss-release-distribute/tss-release-esrp-parent/oss-publishing/releasing-open-source/nuget). +Confirm the organization owns the selected packages, the Durable client is allowlisted for +`ESRPRELPACMAN`, and Trusted Publishing covers the package IDs/prefixes and required operations. +The template reuses `dtfx-internal-esrp-prod`; access to that connection and appropriate +[pipeline permissions](https://learn.microsoft.com/azure/devops/pipelines/policies/permissions?view=azure-devops) +are separate prerequisites. Owners/approvers use the individual `Build.RequestedForEmail`, not a group. +This source change does not establish those permissions or onboarding. ESRP failures fail the job; +there is no direct NuGet push fallback. + +For Azure DevOps CLI SDK REST requests, `templateParameters` is a string map: serialize +`alreadyPublishedPackages` as a JSON string rather than a native array. Verify the resolved publisher +source, artifact resource and confirmed-public versions before running. + +### Local publisher checks + +For source-only validation, PowerShell 7 with the `Pester` (5.x) and `powershell-yaml` modules can run: + +```powershell +Invoke-Pester -Path .\eng\publish\publish.Tests.ps1 -CI +``` + +These checks execute local staging/no-op scripts and check pipeline wiring, not Azure's scheduler. +They do not compile server-side templates or validate end-to-end publishing. ## Manual Release Process (Alternative) diff --git a/eng/publish/nuget-release-steps.yml b/eng/publish/nuget-release-steps.yml new file mode 100644 index 00000000..a1f520f0 --- /dev/null +++ b/eng/publish/nuget-release-steps.yml @@ -0,0 +1,97 @@ +parameters: +- name: packageId + type: string +- name: organizationName + type: string +- name: alreadyPublished + type: boolean + default: false + +steps: +- ${{ if parameters.alreadyPublished }}: + - pwsh: | + Write-Host "Operator confirmed the selected version of '$env:PACKAGE_ID' is already published on NuGet.org. No package will be staged or submitted to ESRP." + displayName: Already published (${{ parameters.packageId }}) + env: + PACKAGE_ID: ${{ parameters.packageId }} + +- ${{ else }}: + - pwsh: | + $ErrorActionPreference = 'Stop' + + if ([string]::IsNullOrWhiteSpace($env:NUGET_ORGANIZATION) -or $env:NUGET_ORGANIZATION -match '\$\(|\$\{\{') { + throw 'Set nuGetOrganization to the NuGet.org organization confirmed during ESRP NuGet onboarding before publishing.' + } + + $packages = @( + foreach ($file in Get-ChildItem -LiteralPath $env:SOURCE_FOLDER -Filter '*.nupkg' -File) { + if ($file.Name -like '*.symbols.nupkg') { + continue + } + + $archive = [System.IO.Compression.ZipFile]::OpenRead($file.FullName) + try { + $nuspecs = @($archive.Entries | Where-Object { $_.FullName -notmatch '[/\\]' -and $_.Name -like '*.nuspec' }) + if ($nuspecs.Count -ne 1) { + throw "Expected one root nuspec in '$($file.Name)', found $($nuspecs.Count)." + } + + $reader = [System.IO.StreamReader]::new($nuspecs[0].Open()) + try { + [xml]$nuspec = $reader.ReadToEnd() + } + finally { + $reader.Dispose() + } + + if ([string]::IsNullOrWhiteSpace($nuspec.package.metadata.id)) { + throw "Missing package ID in '$($file.Name)'." + } + + if ($nuspec.package.metadata.id -eq $env:PACKAGE_ID) { + $file + } + } + finally { + $archive.Dispose() + } + } + ) + + if ($packages.Count -ne 1) { + throw "Expected exactly one package for '$env:PACKAGE_ID' in '$env:SOURCE_FOLDER', found $($packages.Count)." + } + + if (Test-Path -LiteralPath $env:STAGING_FOLDER) { + throw "ESRP staging folder '$env:STAGING_FOLDER' already exists; refusing to reuse possibly stale content." + } + + New-Item -ItemType Directory -Path $env:STAGING_FOLDER | Out-Null + Copy-Item -LiteralPath $packages[0].FullName -Destination $env:STAGING_FOLDER + Write-Host "Staged '$($packages[0].Name)' for NuGet organization '$env:NUGET_ORGANIZATION'." + displayName: Stage ${{ parameters.packageId }} for ESRP + env: + PACKAGE_ID: ${{ parameters.packageId }} + NUGET_ORGANIZATION: ${{ parameters.organizationName }} + SOURCE_FOLDER: $(System.DefaultWorkingDirectory)\drop + STAGING_FOLDER: $(System.DefaultWorkingDirectory)\esrp\${{ parameters.packageId }} + + - task: SFP.release-tasks.custom-build-release-task.EsrpRelease@14 + displayName: ESRP NuGet release (${{ parameters.packageId }}) + inputs: + ConnectedServiceName: dtfx-internal-esrp-prod + UseManagedIdentity: true + KeyVaultName: durable-esrp-akv + SignCertName: dts-esrp-cert + ClientId: 0b3ed1a4-0727-4a50-b82a-02c2bd9dec89 + DomainTenantId: 33e01921-4d64-4f8c-a055-5bdaffd5e33d + Intent: PackageDistribution + ContentType: NuGet + OrganizationName: ${{ parameters.organizationName }} + ContentSource: Folder + FolderLocation: $(System.DefaultWorkingDirectory)\esrp\${{ parameters.packageId }} + WaitForReleaseCompletion: true + Owners: $(Build.RequestedForEmail) + Approvers: $(Build.RequestedForEmail) + ServiceEndpointUrl: https://api.esrp.microsoft.com + MainPublisher: ESRPRELPACMAN diff --git a/eng/publish/publish.Tests.ps1 b/eng/publish/publish.Tests.ps1 new file mode 100644 index 00000000..215d9925 --- /dev/null +++ b/eng/publish/publish.Tests.ps1 @@ -0,0 +1,205 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +BeforeAll { + Import-Module powershell-yaml -ErrorAction Stop + $pipeline = ConvertFrom-Yaml (Get-Content "$PSScriptRoot\publish.yml" -Raw) + $template = ConvertFrom-Yaml (Get-Content "$PSScriptRoot\nuget-release-steps.yml" -Raw) + $publishSteps = @($template.steps[1]['${{ else }}']) + $noOpSteps = @($template.steps[0]['${{ if parameters.alreadyPublished }}']) + $stagePackage = [scriptblock]::Create($publishSteps[0].pwsh) + $confirmPublished = [scriptblock]::Create($noOpSteps[0].pwsh) + $jobs = $pipeline.extends.parameters.stages[0].jobs + $publicJobs = @($jobs | Where-Object job -Like 'nugetRelease_*') + + function New-TestPackage { + param( + [string]$Id, + [string]$Version = '1.0.0', + [string]$FileName = "$Id.$Version.nupkg", + [string]$Nuspec = "$Id$Version" + ) + $archive = [IO.Compression.ZipFile]::Open((Join-Path $env:SOURCE_FOLDER $FileName), 'Create') + try { + $writer = [IO.StreamWriter]::new($archive.CreateEntry("$Id.nuspec").Open()) + try { $writer.Write($Nuspec) } + finally { $writer.Dispose() } + } + finally { $archive.Dispose() } + } +} + +Describe 'Publisher wiring' { + It 'retains 17 unique public identities with explicit self templates and per-package confirmations' { + $jobs.Count | Should -Be 19 + $publicJobs.Count | Should -Be 17 + $ids = @($publicJobs | ForEach-Object { $_.steps[0].parameters.packageId }) + @($ids | Select-Object -Unique).Count | Should -Be 17 + $ids | Should -Not -Contain 'Microsoft.DurableTask.InProcessTestHost' + foreach ($job in $publicJobs) { + $id = $job.steps[0].parameters.packageId + $job.job | Should -Be ("nugetRelease_" + $id.Replace('.', '_')) + $job.steps.Count | Should -Be 1 + $job.steps[0].template | Should -Be '/eng/publish/nuget-release-steps.yml@self' + $job.steps[0].parameters.organizationName | Should -Be '${{ parameters.nuGetOrganization }}' + $job.steps[0].parameters.alreadyPublished | Should -Be ("`${{ containsValue(parameters.alreadyPublishedPackages, '$id') }}") + $job.templateContext.inputs[0].pipeline | Should -Be 'officialPipeline' + $job.templateContext.inputs[0].artifactName | Should -Be 'drop' + } + ($pipeline.parameters | Where-Object name -EQ 'nuGetOrganization').default | Should -BeNullOrEmpty + ($pipeline.parameters | Where-Object name -EQ 'alreadyPublishedPackages').default.Count | Should -Be 0 + ($template.parameters | Where-Object name -EQ 'alreadyPublished').default | Should -BeFalse + } + + It 'preserves internal staging, approval and dependency success gates' { + $pipeline.trigger | Should -Be 'none' + $pipeline.pr | Should -Be 'none' + $ado = $jobs | Where-Object job -EQ 'AdoRelease' + $ado.steps[0].task | Should -Be '1ES.PublishNuget@1' + $ado.steps[0].inputs.allowPackageConflicts | Should -BeTrue + $approval = $jobs | Where-Object job -EQ 'nugetApproval' + $approval.dependsOn | Should -Be 'AdoRelease' + $approval.pool | Should -Be 'server' + $approval.steps[0].task | Should -Be 'ManualValidation@1' + $approval.steps[0].inputs.onTimeout | Should -Be 'reject' + $approval.steps[0].inputs.instructions | Should -Match 'validation-only' + $approval.steps[0].inputs.instructions | Should -Match 'real public ESRP' + foreach ($job in $publicJobs) { + @($job.dependsOn) | Should -Contain 'nugetApproval' + $expected = if (@($job.dependsOn).Count -eq 1) { "succeeded('nugetApproval')" } else { 'succeeded()' } + $job.condition | Should -Be $expected + } + $contract = $jobs | Where-Object job -EQ 'nugetRelease_Microsoft_DurableTask_LargePayloadPurge_Abstractions' + $contract.dependsOn -join ',' | Should -Be 'nugetApproval,nugetRelease_Microsoft_DurableTask_Abstractions,nugetRelease_Microsoft_DurableTask_Client' + $blob = $jobs | Where-Object job -EQ 'nugetRelease_Microsoft_DurableTask_Extensions_AzureBlobPayloads' + $blob.dependsOn -join ',' | Should -Be 'nugetApproval,nugetRelease_Microsoft_DurableTask_LargePayloadPurge_Abstractions' + } + + It 'keeps distribution only in the normal branch with the Durable ESRP14 profile' { + $noOpSteps.Count | Should -Be 1 + @($noOpSteps | Where-Object task).Count | Should -Be 0 + $publishSteps.Count | Should -Be 2 + $publishSteps[1].task | Should -Be 'SFP.release-tasks.custom-build-release-task.EsrpRelease@14' + $expected = @{ + ConnectedServiceName = 'dtfx-internal-esrp-prod' + ClientId = '0b3ed1a4-0727-4a50-b82a-02c2bd9dec89' + DomainTenantId = '33e01921-4d64-4f8c-a055-5bdaffd5e33d' + UseManagedIdentity = $true + KeyVaultName = 'durable-esrp-akv' + SignCertName = 'dts-esrp-cert' + Intent = 'PackageDistribution' + ContentType = 'NuGet' + ContentSource = 'Folder' + OrganizationName = '${{ parameters.organizationName }}' + FolderLocation = $publishSteps[0].env.STAGING_FOLDER + MainPublisher = 'ESRPRELPACMAN' + WaitForReleaseCompletion = $true + Owners = '$(Build.RequestedForEmail)' + Approvers = '$(Build.RequestedForEmail)' + } + foreach ($key in $expected.Keys) { + $publishSteps[1].inputs[$key] | Should -Be $expected[$key] + } + } +} + +Describe 'Actual package scripts' { + BeforeAll { + $savedEnvironment = @{} + foreach ($name in 'PACKAGE_ID', 'NUGET_ORGANIZATION', 'SOURCE_FOLDER', 'STAGING_FOLDER') { + $savedEnvironment[$name] = [Environment]::GetEnvironmentVariable($name) + } + } + BeforeEach { + $fixture = Join-Path $TestDrive ([guid]::NewGuid().ToString()) + $env:SOURCE_FOLDER = Join-Path $fixture 'drop' + $env:STAGING_FOLDER = Join-Path $fixture 'esrp' + $env:PACKAGE_ID = 'Microsoft.DurableTask.Client' + $env:NUGET_ORGANIZATION = 'validation-only-organization' + New-Item -ItemType Directory -Path $env:SOURCE_FOLDER | Out-Null + New-TestPackage $env:PACKAGE_ID + } + AfterAll { + foreach ($name in $savedEnvironment.Keys) { + [Environment]::SetEnvironmentVariable($name, $savedEnvironment[$name]) + } + } + + It 'copies only the exact nuspec ID unchanged, excluding prefixes, disguised internal packages and symbols' { + $original = Join-Path $env:SOURCE_FOLDER "$env:PACKAGE_ID.1.0.0.nupkg" + $hash = (Get-FileHash $original).Hash + New-TestPackage 'Microsoft.DurableTask.Client.2.Tools' + New-TestPackage 'Microsoft.DurableTask.InProcessTestHost' -FileName 'Microsoft.DurableTask.Client.100.0.0.nupkg' + New-TestPackage $env:PACKAGE_ID -FileName "$env:PACKAGE_ID.1.0.0.symbols.nupkg" + Set-Content "$env:SOURCE_FOLDER\$env:PACKAGE_ID.1.0.0.snupkg" 'not a product package' + + & $stagePackage 6>$null + + $staged = @(Get-ChildItem $env:STAGING_FOLDER -File) + $staged.Count | Should -Be 1 + $staged[0].Name | Should -Be "$env:PACKAGE_ID.1.0.0.nupkg" + (Get-FileHash $staged[0].FullName).Hash | Should -Be $hash + (Get-FileHash $original).Hash | Should -Be $hash + } + + It 'logs an already-public without reading or staging packages' -TestCases @( + @{ Id = 'Microsoft.DurableTask.Client' } + @{ Id = 'Microsoft.DurableTask.Abstractions' } + @{ Id = 'Microsoft.DurableTask.LargePayloadPurge.Abstractions' } + @{ Id = 'Microsoft.DurableTask.Generators' } + ) { + param($Id) + $env:PACKAGE_ID = $Id + $env:SOURCE_FOLDER = Join-Path $fixture 'not-created' + $output = @(& $confirmPublished 6>&1) -join "`n" + $output | Should -Match ([regex]::Escape("Operator confirmed the selected version of '$Id'")) + $output | Should -Match 'No package will be staged or submitted to ESRP' + Test-Path $env:SOURCE_FOLDER | Should -BeFalse + Test-Path $env:STAGING_FOLDER | Should -BeFalse + } + + It 'stages a new Generator version through the normal branch' { + $env:PACKAGE_ID = 'Microsoft.DurableTask.Generators' + New-TestPackage $env:PACKAGE_ID -Version '2.0.0-preview.1' + & $stagePackage 6>$null + @(Get-ChildItem $env:STAGING_FOLDER -File).Name | Should -Be 'Microsoft.DurableTask.Generators.2.0.0-preview.1.nupkg' + } + + It 'rejects unset or unresolved organization ' -TestCases @( + @{ Organization = '' } + @{ Organization = ' ' } + @{ Organization = '$(NuGetOrganizationName)' } + @{ Organization = '${{ parameters.organizationName }}' } + ) { + param($Organization) + $env:NUGET_ORGANIZATION = $Organization + { & $stagePackage 6>$null } | Should -Throw '*Set nuGetOrganization*' + Test-Path $env:STAGING_FOLDER | Should -BeFalse + } + + It 'rejects packages' -TestCases @( + @{ Problem = 'missing'; Count = 0 } + @{ Problem = 'ambiguous'; Count = 2 } + ) { + param($Problem, $Count) + if ($Problem -eq 'missing') { $env:PACKAGE_ID = 'Microsoft.DurableTask.Missing' } + else { New-TestPackage $env:PACKAGE_ID -Version '1.0.1' } + { & $stagePackage 6>$null } | Should -Throw "*found $Count*" + Test-Path $env:STAGING_FOLDER | Should -BeFalse + } + + It 'rejects missing package metadata' { + New-TestPackage 'Invalid' -Nuspec '' + { & $stagePackage 6>$null } | Should -Throw '*Missing package ID*' + Test-Path $env:STAGING_FOLDER | Should -BeFalse + } + + It 'refuses a stale staging folder without deleting its contents' { + New-Item -ItemType Directory -Path $env:STAGING_FOLDER | Out-Null + $stale = Join-Path $env:STAGING_FOLDER 'stale.nupkg' + Set-Content $stale 'stale content' + { & $stagePackage 6>$null } | Should -Throw '*refusing to reuse*' + Get-Content $stale | Should -Be 'stale content' + @(Get-ChildItem $env:STAGING_FOLDER -File).Count | Should -Be 1 + } +} diff --git a/eng/publish/publish.yml b/eng/publish/publish.yml index 03fa64ba..1f424d7b 100644 --- a/eng/publish/publish.yml +++ b/eng/publish/publish.yml @@ -2,6 +2,16 @@ # When executed, it automatically publishes the output of the 'official pipeline' (the nupkgs) to our internal ADO feed. # It may optionally also publish the packages to NuGet, but that is gated behind a manual approval. +parameters: +- name: nuGetOrganization + displayName: NuGet.org organization confirmed during ESRP onboarding (required) + type: string + default: '' +- name: alreadyPublishedPackages + displayName: Public package IDs whose selected versions are confirmed on NuGet.org (successful no-op) + type: object + default: [] + trigger: none # only trigger is manual pr: none # only trigger is manual @@ -56,46 +66,31 @@ extends: # NuGet approval gate - job: nugetApproval displayName: NuGetApproval + dependsOn: AdoRelease pool: server # This task only works when executed on serverl pools, so this needs to be specified steps: # Wait for manual approval. - task: ManualValidation@1 inputs: - instructions: Confirm you want to push to NuGet + instructions: | + Selected NuGet.org organization: ${{ parameters.nuGetOrganization }} + Confirmed public package IDs: ${{ join(', ', parameters.alreadyPublishedPackages) }} + Verify the signed official artifacts, dependencies and exact selected versions of the confirmed public IDs. + Confirm ESRP NuGet onboarding, ESRPRELPACMAN allowlisting and Trusted Publishing for the selected organization. + Stop here for validation-only runs or any unverified prerequisite. + Approval starts real public ESRP NuGet submissions. onTimeout: 'reject' #================== NuGet publishing section ================== - # Next, we publish the nupkgs to NuGet, one at a time; for good reason. - # - # When publishing to NuGet, the `1ES.PublishNuget@1` will fail the ADO job if we attempt - # to push any package versions that were already uploaded to NuGet. - # For instance, imagine the latest DTFx packages on NuGet are: DTFx.Core@v1.1 and DTFx.AzureStorage@v1.0 - # and that our official pipeline generated these packages: DTFx.Core@v1.1 and DTFx.AzureStorage@v1.1. - # In the end, we want NuGet to have both packages at version v1.1. - # - # In this case, if we try to publish both packages in the same ADO job, it will fail as soon as it detects - # we're trying to push DTFx.Core@v1.1 as that already exists on NuGet, and this could prevent - # DTFx.AzureStorage@v1.1 from being published in the first place. - # - # Unfortunately, skipping duplicate package versions is only supported for publishing to ADO feeds, which explains - # why we did not have this issue when pushing to ADO. - # - # So we split each package upload to a separate job, so they be uploaded independently. In our example, the - # DTFx.Core upload task would fail (as expected, it was already uploaded), - # but the DTFx.AzureStorage upload would succeed. - - # Implementor's note: - # What follows could use some refactoring as there's a lot of repetition, perhaps an ADO template could hide the repeated details. - # Pay close attention to the `packagesToPush` property of each job. We need to make sure the pattern specified there uniquely identifies - # the package we want to push, and this is difficult when the full name of one package is the prefix of another. - # For example: `Microsoft.DurableTask.Client` and `Microsoft.DurableTask.Client.Grpc`. - # The trick is to exclude the `Microsoft.DurableTask.Client.Grpc` in the `packagesToPush` property for `Microsoft.DurableTask.Client` + # Keep one package per ESRP submission: duplicate versions fail independently, and ESRP + # does not guarantee publication order within a submission. Preserve the dependency jobs below. + # The shared steps select the exact nuspec ID, not a filename prefix, from the signed drop. # NuGet release (Microsoft.DurableTask.Abstractions) - job: nugetRelease_Microsoft_DurableTask_Abstractions displayName: NuGet Release (Microsoft.DurableTask.Abstractions) dependsOn: nugetApproval - condition: succeeded('nugetApproval') # nuget packages need to be on ADO first + condition: succeeded('nugetApproval') templateContext: type: releaseJob isProduction: true @@ -105,20 +100,17 @@ extends: artifactName: drop targetPath: $(System.DefaultWorkingDirectory)/drop steps: - - task: 1ES.PublishNuget@1 - displayName: 'NuGet push (Microsoft.DurableTask.Abstractions)' - inputs: - command: push - nuGetFeedType: external - publishFeedCredentials: 'DurableTask org NuGet API Key' - packagesToPush: '$(System.DefaultWorkingDirectory)/drop/Microsoft.DurableTask.Abstractions.*.nupkg;!$(System.DefaultWorkingDirectory)/**/*.symbols.nupkg' # Despite this being a custom command, we need to keep this for 1ES validation - packageParentPath: $(System.DefaultWorkingDirectory) # This needs to be set to some prefix of the `packagesToPush` parameter. Apparently it helps with SDL tooling + - template: /eng/publish/nuget-release-steps.yml@self + parameters: + packageId: Microsoft.DurableTask.Abstractions + organizationName: ${{ parameters.nuGetOrganization }} + alreadyPublished: ${{ containsValue(parameters.alreadyPublishedPackages, 'Microsoft.DurableTask.Abstractions') }} # NuGet release (Microsoft.DurableTask.Client) - job: nugetRelease_Microsoft_DurableTask_Client displayName: NuGet Release (Microsoft.DurableTask.Client) dependsOn: nugetApproval - condition: succeeded('nugetApproval') # nuget packages need to be on ADO first + condition: succeeded('nugetApproval') templateContext: type: releaseJob isProduction: true @@ -128,25 +120,17 @@ extends: artifactName: drop targetPath: $(System.DefaultWorkingDirectory)/drop steps: - - task: 1ES.PublishNuget@1 - displayName: 'NuGet push (Microsoft.DurableTask.Client)' - inputs: - command: push - nuGetFeedType: external - publishFeedCredentials: 'DurableTask org NuGet API Key' - # the packages to push pattern explicitly excludes: - # - 'Microsoft.DurableTask.Client.Grpc' - # - 'Microsoft.DurableTask.Client.OrchestrationServiceClientShim' - # - 'Microsoft.DurableTask.Client.AzureManaged.*' - # which are pushed by their respective jobs - packagesToPush: '$(System.DefaultWorkingDirectory)/drop/Microsoft.DurableTask.Client.*.nupkg;!$(System.DefaultWorkingDirectory)/drop/Microsoft.DurableTask.Client.Grpc.*.nupkg;!$(System.DefaultWorkingDirectory)/drop/Microsoft.DurableTask.Client.OrchestrationServiceClientShim.*.nupkg;!$(System.DefaultWorkingDirectory)/drop/Microsoft.DurableTask.Client.AzureManaged.*.nupkg;!$(System.DefaultWorkingDirectory)/**/*.symbols.nupkg' # Despite this being a custom command, we need to keep this for 1ES validation - packageParentPath: $(System.DefaultWorkingDirectory) # This needs to be set to some prefix of the `packagesToPush` parameter. Apparently it helps with SDL tooling + - template: /eng/publish/nuget-release-steps.yml@self + parameters: + packageId: Microsoft.DurableTask.Client + organizationName: ${{ parameters.nuGetOrganization }} + alreadyPublished: ${{ containsValue(parameters.alreadyPublishedPackages, 'Microsoft.DurableTask.Client') }} # NuGet release (Microsoft.DurableTask.Client.Grpc) - job: nugetRelease_Microsoft_DurableTask_Client_Grpc displayName: NuGet Release (Microsoft.DurableTask.Client.Grpc) dependsOn: nugetApproval - condition: succeeded('nugetApproval') # nuget packages need to be on ADO first + condition: succeeded('nugetApproval') templateContext: type: releaseJob isProduction: true @@ -156,20 +140,17 @@ extends: artifactName: drop targetPath: $(System.DefaultWorkingDirectory)/drop steps: - - task: 1ES.PublishNuget@1 - displayName: 'NuGet push (Microsoft.DurableTask.Client.Grpc)' - inputs: - command: push - nuGetFeedType: external - publishFeedCredentials: 'DurableTask org NuGet API Key' - packagesToPush: '$(System.DefaultWorkingDirectory)/drop/Microsoft.DurableTask.Client.Grpc.*.nupkg;!$(System.DefaultWorkingDirectory)/**/*.symbols.nupkg' # Despite this being a custom command, we need to keep this for 1ES validation - packageParentPath: $(System.DefaultWorkingDirectory) # This needs to be set to some prefix of the `packagesToPush` parameter. Apparently it helps with SDL tooling + - template: /eng/publish/nuget-release-steps.yml@self + parameters: + packageId: Microsoft.DurableTask.Client.Grpc + organizationName: ${{ parameters.nuGetOrganization }} + alreadyPublished: ${{ containsValue(parameters.alreadyPublishedPackages, 'Microsoft.DurableTask.Client.Grpc') }} # NuGet release (Microsoft.DurableTask.Client.OrchestrationServiceClientShim) - job: nugetRelease_Microsoft_DurableTask_Client_OrchestrationServiceClientShim displayName: NuGet Release (Microsoft.DurableTask.Client.OrchestrationServiceClientShim) dependsOn: nugetApproval - condition: succeeded('nugetApproval') # nuget packages need to be on ADO first + condition: succeeded('nugetApproval') templateContext: type: releaseJob isProduction: true @@ -179,20 +160,17 @@ extends: artifactName: drop targetPath: $(System.DefaultWorkingDirectory)/drop steps: - - task: 1ES.PublishNuget@1 - displayName: 'NuGet push (Microsoft.DurableTask.Client.OrchestrationServiceClientShim)' - inputs: - command: push - nuGetFeedType: external - publishFeedCredentials: 'DurableTask org NuGet API Key' - packagesToPush: '$(System.DefaultWorkingDirectory)/drop/Microsoft.DurableTask.Client.OrchestrationServiceClientShim.*.nupkg;!$(System.DefaultWorkingDirectory)/**/*.symbols.nupkg' # Despite this being a custom command, we need to keep this for 1ES validation - packageParentPath: $(System.DefaultWorkingDirectory) # This needs to be set to some prefix of the `packagesToPush` parameter. Apparently it helps with SDL tooling + - template: /eng/publish/nuget-release-steps.yml@self + parameters: + packageId: Microsoft.DurableTask.Client.OrchestrationServiceClientShim + organizationName: ${{ parameters.nuGetOrganization }} + alreadyPublished: ${{ containsValue(parameters.alreadyPublishedPackages, 'Microsoft.DurableTask.Client.OrchestrationServiceClientShim') }} # NuGet release (Microsoft.DurableTask.Generators) - job: nugetRelease_Microsoft_DurableTask_Generators displayName: NuGet Release (Microsoft.DurableTask.Generators) dependsOn: nugetApproval - condition: succeeded('nugetApproval') # nuget packages need to be on ADO first + condition: succeeded('nugetApproval') templateContext: type: releaseJob isProduction: true @@ -202,20 +180,17 @@ extends: artifactName: drop targetPath: $(System.DefaultWorkingDirectory)/drop steps: - - task: 1ES.PublishNuget@1 - displayName: 'NuGet push (Microsoft.DurableTask.Generators)' - inputs: - command: push - nuGetFeedType: external - publishFeedCredentials: 'DurableTask org NuGet API Key' - packagesToPush: '$(System.DefaultWorkingDirectory)/drop/Microsoft.DurableTask.Generators.*.nupkg;!$(System.DefaultWorkingDirectory)/**/*.symbols.nupkg' # Despite this being a custom command, we need to keep this for 1ES validation - packageParentPath: $(System.DefaultWorkingDirectory) # This needs to be set to some prefix of the `packagesToPush` parameter. Apparently it helps with SDL tooling + - template: /eng/publish/nuget-release-steps.yml@self + parameters: + packageId: Microsoft.DurableTask.Generators + organizationName: ${{ parameters.nuGetOrganization }} + alreadyPublished: ${{ containsValue(parameters.alreadyPublishedPackages, 'Microsoft.DurableTask.Generators') }} # NuGet release (Microsoft.DurableTask.Analyzers) - job: nugetRelease_Microsoft_DurableTask_Analyzers displayName: NuGet Release (Microsoft.DurableTask.Analyzers) dependsOn: nugetApproval - condition: succeeded('nugetApproval') # nuget packages need to be on ADO first + condition: succeeded('nugetApproval') templateContext: type: releaseJob isProduction: true @@ -225,20 +200,17 @@ extends: artifactName: drop targetPath: $(System.DefaultWorkingDirectory)/drop steps: - - task: 1ES.PublishNuget@1 - displayName: 'NuGet push (Microsoft.DurableTask.Analyzers)' - inputs: - command: push - nuGetFeedType: external - publishFeedCredentials: 'DurableTask org NuGet API Key' - packagesToPush: '$(System.DefaultWorkingDirectory)/drop/Microsoft.DurableTask.Analyzers.*.nupkg;!$(System.DefaultWorkingDirectory)/**/*.symbols.nupkg' # Despite this being a custom command, we need to keep this for 1ES validation - packageParentPath: $(System.DefaultWorkingDirectory) # This needs to be set to some prefix of the `packagesToPush` parameter. Apparently it helps with SDL tooling + - template: /eng/publish/nuget-release-steps.yml@self + parameters: + packageId: Microsoft.DurableTask.Analyzers + organizationName: ${{ parameters.nuGetOrganization }} + alreadyPublished: ${{ containsValue(parameters.alreadyPublishedPackages, 'Microsoft.DurableTask.Analyzers') }} # NuGet release (Microsoft.DurableTask.Grpc) - job: nugetRelease_Microsoft_DurableTask_Grpc displayName: NuGet Release (Microsoft.DurableTask.Grpc) dependsOn: nugetApproval - condition: succeeded('nugetApproval') # nuget packages need to be on ADO first + condition: succeeded('nugetApproval') templateContext: type: releaseJob isProduction: true @@ -248,20 +220,17 @@ extends: artifactName: drop targetPath: $(System.DefaultWorkingDirectory)/drop steps: - - task: 1ES.PublishNuget@1 - displayName: 'NuGet push (Microsoft.DurableTask.Grpc)' - inputs: - command: push - nuGetFeedType: external - publishFeedCredentials: 'DurableTask org NuGet API Key' - packagesToPush: '$(System.DefaultWorkingDirectory)/drop/Microsoft.DurableTask.Grpc.*.nupkg;!$(System.DefaultWorkingDirectory)/**/*.symbols.nupkg' # Despite this being a custom command, we need to keep this for 1ES validation - packageParentPath: $(System.DefaultWorkingDirectory) # This needs to be set to some prefix of the `packagesToPush` parameter. Apparently it helps with SDL tooling + - template: /eng/publish/nuget-release-steps.yml@self + parameters: + packageId: Microsoft.DurableTask.Grpc + organizationName: ${{ parameters.nuGetOrganization }} + alreadyPublished: ${{ containsValue(parameters.alreadyPublishedPackages, 'Microsoft.DurableTask.Grpc') }} # NuGet release (Microsoft.DurableTask.Worker) - job: nugetRelease_Microsoft_DurableTask_Worker displayName: NuGet Release (Microsoft.DurableTask.Worker) dependsOn: nugetApproval - condition: succeeded('nugetApproval') # nuget packages need to be on ADO first + condition: succeeded('nugetApproval') templateContext: type: releaseJob isProduction: true @@ -271,21 +240,17 @@ extends: artifactName: drop targetPath: $(System.DefaultWorkingDirectory)/drop steps: - - task: 1ES.PublishNuget@1 - displayName: 'NuGet push (Microsoft.DurableTask.Worker)' - inputs: - command: push - nuGetFeedType: external - publishFeedCredentials: 'DurableTask org NuGet API Key' - # the packages to push pattern explicitly excludes 'Microsoft.DurableTask.Worker.Grpc' and 'Microsoft.DurableTask.Worker.AzureManaged', which are pushed by another job in this file - packagesToPush: '$(System.DefaultWorkingDirectory)/drop/Microsoft.DurableTask.Worker.*.nupkg;!$(System.DefaultWorkingDirectory)/drop/Microsoft.DurableTask.Worker.Grpc*.nupkg;!$(System.DefaultWorkingDirectory)/drop/Microsoft.DurableTask.Worker.AzureManaged.*.nupkg;!$(System.DefaultWorkingDirectory)/**/*.symbols.nupkg' # Despite this being a custom command, we need to keep this for 1ES validation - packageParentPath: $(System.DefaultWorkingDirectory) # This needs to be set to some prefix of the `packagesToPush` parameter. Apparently it helps with SDL tooling + - template: /eng/publish/nuget-release-steps.yml@self + parameters: + packageId: Microsoft.DurableTask.Worker + organizationName: ${{ parameters.nuGetOrganization }} + alreadyPublished: ${{ containsValue(parameters.alreadyPublishedPackages, 'Microsoft.DurableTask.Worker') }} # NuGet release (Microsoft.DurableTask.Worker.Grpc) - job: nugetRelease_Microsoft_DurableTask_Worker_Grpc displayName: NuGet Release (Microsoft.DurableTask.Worker.Grpc) dependsOn: nugetApproval - condition: succeeded('nugetApproval') # nuget packages need to be on ADO first + condition: succeeded('nugetApproval') templateContext: type: releaseJob isProduction: true @@ -295,20 +260,17 @@ extends: artifactName: drop targetPath: $(System.DefaultWorkingDirectory)/drop steps: - - task: 1ES.PublishNuget@1 - displayName: 'NuGet push (Microsoft.DurableTask.Worker.Grpc)' - inputs: - command: push - nuGetFeedType: external - publishFeedCredentials: 'DurableTask org NuGet API Key' - packagesToPush: '$(System.DefaultWorkingDirectory)/drop/Microsoft.DurableTask.Worker.Grpc.*.nupkg;!$(System.DefaultWorkingDirectory)/**/*.symbols.nupkg' # Despite this being a custom command, we need to keep this for 1ES validation - packageParentPath: $(System.DefaultWorkingDirectory) # This needs to be set to some prefix of the `packagesToPush` parameter. Apparently it helps with SDL tooling + - template: /eng/publish/nuget-release-steps.yml@self + parameters: + packageId: Microsoft.DurableTask.Worker.Grpc + organizationName: ${{ parameters.nuGetOrganization }} + alreadyPublished: ${{ containsValue(parameters.alreadyPublishedPackages, 'Microsoft.DurableTask.Worker.Grpc') }} # NuGet release (Microsoft.DurableTask.Client.AzureManaged) - job: nugetRelease_Microsoft_DurableTask_Client_AzureManaged displayName: NuGet Release (Microsoft.DurableTask.Client.AzureManaged) dependsOn: nugetApproval - condition: succeeded('nugetApproval') # nuget packages need to be on ADO first + condition: succeeded('nugetApproval') templateContext: type: releaseJob isProduction: true @@ -318,20 +280,17 @@ extends: artifactName: drop targetPath: $(System.DefaultWorkingDirectory)/drop steps: - - task: 1ES.PublishNuget@1 - displayName: 'NuGet push (Microsoft.DurableTask.Client.AzureManaged)' - inputs: - command: push - nuGetFeedType: external - publishFeedCredentials: 'DurableTask org NuGet API Key' - packagesToPush: '$(System.DefaultWorkingDirectory)/drop/Microsoft.DurableTask.Client.AzureManaged.*.nupkg;!$(System.DefaultWorkingDirectory)/drop/Microsoft.DurableTask.Client.AzureManaged.Sandboxes.*.nupkg;!$(System.DefaultWorkingDirectory)/**/*.symbols.nupkg' # Despite this being a custom command, we need to keep this for 1ES validation - packageParentPath: $(System.DefaultWorkingDirectory) # This needs to be set to some prefix of the `packagesToPush` parameter. Apparently it helps with SDL tooling + - template: /eng/publish/nuget-release-steps.yml@self + parameters: + packageId: Microsoft.DurableTask.Client.AzureManaged + organizationName: ${{ parameters.nuGetOrganization }} + alreadyPublished: ${{ containsValue(parameters.alreadyPublishedPackages, 'Microsoft.DurableTask.Client.AzureManaged') }} # NuGet release (Microsoft.DurableTask.Client.AzureManaged.Sandboxes) - job: nugetRelease_Microsoft_DurableTask_Client_AzureManaged_Sandboxes displayName: NuGet Release (Microsoft.DurableTask.Client.AzureManaged.Sandboxes) dependsOn: nugetApproval - condition: succeeded('nugetApproval') # nuget packages need to be on ADO first + condition: succeeded('nugetApproval') templateContext: type: releaseJob isProduction: true @@ -341,20 +300,17 @@ extends: artifactName: drop targetPath: $(System.DefaultWorkingDirectory)/drop steps: - - task: 1ES.PublishNuget@1 - displayName: 'NuGet push (Microsoft.DurableTask.Client.AzureManaged.Sandboxes)' - inputs: - command: push - nuGetFeedType: external - publishFeedCredentials: 'DurableTask org NuGet API Key' - packagesToPush: '$(System.DefaultWorkingDirectory)/drop/Microsoft.DurableTask.Client.AzureManaged.Sandboxes.*.nupkg;!$(System.DefaultWorkingDirectory)/**/*.symbols.nupkg' # Despite this being a custom command, we need to keep this for 1ES validation - packageParentPath: $(System.DefaultWorkingDirectory) # This needs to be set to some prefix of the `packagesToPush` parameter. Apparently it helps with SDL tooling + - template: /eng/publish/nuget-release-steps.yml@self + parameters: + packageId: Microsoft.DurableTask.Client.AzureManaged.Sandboxes + organizationName: ${{ parameters.nuGetOrganization }} + alreadyPublished: ${{ containsValue(parameters.alreadyPublishedPackages, 'Microsoft.DurableTask.Client.AzureManaged.Sandboxes') }} # NuGet release (Microsoft.DurableTask.Worker.AzureManaged) - job: nugetRelease_Microsoft_DurableTask_Worker_AzureManaged displayName: NuGet Release (Microsoft.DurableTask.Worker.AzureManaged) dependsOn: nugetApproval - condition: succeeded('nugetApproval') # nuget packages need to be on ADO first + condition: succeeded('nugetApproval') templateContext: type: releaseJob isProduction: true @@ -364,20 +320,17 @@ extends: artifactName: drop targetPath: $(System.DefaultWorkingDirectory)/drop steps: - - task: 1ES.PublishNuget@1 - displayName: 'NuGet push (Microsoft.DurableTask.Worker.AzureManaged)' - inputs: - command: push - nuGetFeedType: external - publishFeedCredentials: 'DurableTask org NuGet API Key' - packagesToPush: '$(System.DefaultWorkingDirectory)/drop/Microsoft.DurableTask.Worker.AzureManaged.*.nupkg;!$(System.DefaultWorkingDirectory)/drop/Microsoft.DurableTask.Worker.AzureManaged.Sandboxes.*.nupkg;!$(System.DefaultWorkingDirectory)/**/*.symbols.nupkg' # Despite this being a custom command, we need to keep this for 1ES validation - packageParentPath: $(System.DefaultWorkingDirectory) # This needs to be set to some prefix of the `packagesToPush` parameter. Apparently it helps with SDL tooling + - template: /eng/publish/nuget-release-steps.yml@self + parameters: + packageId: Microsoft.DurableTask.Worker.AzureManaged + organizationName: ${{ parameters.nuGetOrganization }} + alreadyPublished: ${{ containsValue(parameters.alreadyPublishedPackages, 'Microsoft.DurableTask.Worker.AzureManaged') }} # NuGet release (Microsoft.DurableTask.Worker.AzureManaged.Sandboxes) - job: nugetRelease_Microsoft_DurableTask_Worker_AzureManaged_Sandboxes displayName: NuGet Release (Microsoft.DurableTask.Worker.AzureManaged.Sandboxes) dependsOn: nugetApproval - condition: succeeded('nugetApproval') # nuget packages need to be on ADO first + condition: succeeded('nugetApproval') templateContext: type: releaseJob isProduction: true @@ -387,20 +340,17 @@ extends: artifactName: drop targetPath: $(System.DefaultWorkingDirectory)/drop steps: - - task: 1ES.PublishNuget@1 - displayName: 'NuGet push (Microsoft.DurableTask.Worker.AzureManaged.Sandboxes)' - inputs: - command: push - nuGetFeedType: external - publishFeedCredentials: 'DurableTask org NuGet API Key' - packagesToPush: '$(System.DefaultWorkingDirectory)/drop/Microsoft.DurableTask.Worker.AzureManaged.Sandboxes.*.nupkg;!$(System.DefaultWorkingDirectory)/**/*.symbols.nupkg' # Despite this being a custom command, we need to keep this for 1ES validation - packageParentPath: $(System.DefaultWorkingDirectory) # This needs to be set to some prefix of the `packagesToPush` parameter. Apparently it helps with SDL tooling + - template: /eng/publish/nuget-release-steps.yml@self + parameters: + packageId: Microsoft.DurableTask.Worker.AzureManaged.Sandboxes + organizationName: ${{ parameters.nuGetOrganization }} + alreadyPublished: ${{ containsValue(parameters.alreadyPublishedPackages, 'Microsoft.DurableTask.Worker.AzureManaged.Sandboxes') }} # NuGet release (Microsoft.DurableTask.ScheduledTasks) - job: nugetRelease_Microsoft_DurableTask_ScheduledTasks displayName: NuGet Release (Microsoft.DurableTask.ScheduledTasks) dependsOn: nugetApproval - condition: succeeded('nugetApproval') # nuget packages need to be on ADO first + condition: succeeded('nugetApproval') templateContext: type: releaseJob isProduction: true @@ -410,20 +360,17 @@ extends: artifactName: drop targetPath: $(System.DefaultWorkingDirectory)/drop steps: - - task: 1ES.PublishNuget@1 - displayName: 'NuGet push (Microsoft.DurableTask.ScheduledTasks)' - inputs: - command: push - nuGetFeedType: external - publishFeedCredentials: 'DurableTask org NuGet API Key' - packagesToPush: '$(System.DefaultWorkingDirectory)/drop/Microsoft.DurableTask.ScheduledTasks.*.nupkg;!$(System.DefaultWorkingDirectory)/**/*.symbols.nupkg' # Despite this being a custom command, we need to keep this for 1ES validation - packageParentPath: $(System.DefaultWorkingDirectory) # This needs to be set to some prefix of the `packagesToPush` parameter. Apparently it helps with SDL tooling + - template: /eng/publish/nuget-release-steps.yml@self + parameters: + packageId: Microsoft.DurableTask.ScheduledTasks + organizationName: ${{ parameters.nuGetOrganization }} + alreadyPublished: ${{ containsValue(parameters.alreadyPublishedPackages, 'Microsoft.DurableTask.ScheduledTasks') }} # NuGet release (Microsoft.DurableTask.ExportHistory) - job: nugetRelease_Microsoft_DurableTask_ExportHistory displayName: NuGet Release (Microsoft.DurableTask.ExportHistory) dependsOn: nugetApproval - condition: succeeded('nugetApproval') # nuget packages need to be on ADO first + condition: succeeded('nugetApproval') templateContext: type: releaseJob isProduction: true @@ -433,14 +380,11 @@ extends: artifactName: drop targetPath: $(System.DefaultWorkingDirectory)/drop steps: - - task: 1ES.PublishNuget@1 - displayName: 'NuGet push (Microsoft.DurableTask.ExportHistory)' - inputs: - command: push - nuGetFeedType: external - publishFeedCredentials: 'DurableTask org NuGet API Key' - packagesToPush: '$(System.DefaultWorkingDirectory)/drop/Microsoft.DurableTask.ExportHistory.*.nupkg;!$(System.DefaultWorkingDirectory)/**/*.symbols.nupkg' # Despite this being a custom command, we need to keep this for 1ES validation - packageParentPath: $(System.DefaultWorkingDirectory) # This needs to be set to some prefix of the `packagesToPush` parameter. Apparently it helps with SDL tooling + - template: /eng/publish/nuget-release-steps.yml@self + parameters: + packageId: Microsoft.DurableTask.ExportHistory + organizationName: ${{ parameters.nuGetOrganization }} + alreadyPublished: ${{ containsValue(parameters.alreadyPublishedPackages, 'Microsoft.DurableTask.ExportHistory') }} # add it for Microsoft.DurableTask.Extensions.AzureBlobPayloads - job: nugetRelease_Microsoft_DurableTask_Extensions_AzureBlobPayloads @@ -448,7 +392,7 @@ extends: dependsOn: - nugetApproval - nugetRelease_Microsoft_DurableTask_LargePayloadPurge_Abstractions - condition: succeeded() # the Blob package depends on the new contract package, which must publish first + condition: succeeded() templateContext: type: releaseJob isProduction: true @@ -458,14 +402,11 @@ extends: artifactName: drop targetPath: $(System.DefaultWorkingDirectory)/drop steps: - - task: 1ES.PublishNuget@1 - displayName: 'NuGet push (Microsoft.DurableTask.Extensions.AzureBlobPayloads)' - inputs: - command: push - nuGetFeedType: external - publishFeedCredentials: 'DurableTask org NuGet API Key' - packagesToPush: '$(System.DefaultWorkingDirectory)/drop/Microsoft.DurableTask.Extensions.AzureBlobPayloads.*.nupkg;!$(System.DefaultWorkingDirectory)/**/*.symbols.nupkg' # Despite this being a custom command, we need to keep this for 1ES validation - packageParentPath: $(System.DefaultWorkingDirectory) # This needs to be set to some prefix of the `packagesToPush` parameter. Apparently it helps with SDL tooling + - template: /eng/publish/nuget-release-steps.yml@self + parameters: + packageId: Microsoft.DurableTask.Extensions.AzureBlobPayloads + organizationName: ${{ parameters.nuGetOrganization }} + alreadyPublished: ${{ containsValue(parameters.alreadyPublishedPackages, 'Microsoft.DurableTask.Extensions.AzureBlobPayloads') }} # NuGet release (Microsoft.DurableTask.LargePayloadPurge.Abstractions) - job: nugetRelease_Microsoft_DurableTask_LargePayloadPurge_Abstractions @@ -484,11 +425,8 @@ extends: artifactName: drop targetPath: $(System.DefaultWorkingDirectory)/drop steps: - - task: 1ES.PublishNuget@1 - displayName: 'NuGet push (Microsoft.DurableTask.LargePayloadPurge.Abstractions)' - inputs: - command: push - nuGetFeedType: external - publishFeedCredentials: 'DurableTask org NuGet API Key' - packagesToPush: '$(System.DefaultWorkingDirectory)/drop/Microsoft.DurableTask.LargePayloadPurge.Abstractions.*.nupkg;!$(System.DefaultWorkingDirectory)/**/*.symbols.nupkg' - packageParentPath: $(System.DefaultWorkingDirectory) \ No newline at end of file + - template: /eng/publish/nuget-release-steps.yml@self + parameters: + packageId: Microsoft.DurableTask.LargePayloadPurge.Abstractions + organizationName: ${{ parameters.nuGetOrganization }} + alreadyPublished: ${{ containsValue(parameters.alreadyPublishedPackages, 'Microsoft.DurableTask.LargePayloadPurge.Abstractions') }} \ No newline at end of file