diff --git a/windows-release/README.md b/windows-release/README.md index a8ff8a01..e00dcb5b 100644 --- a/windows-release/README.md +++ b/windows-release/README.md @@ -35,6 +35,24 @@ Azure DevOps no longer has a per-pipeline option for retention, and so the only way to permanently retain a build is to manually select the "Retain" option. Without this, the build records will be lost after 30 days. +## Retrying a partial NuGet publish + +If a publish fails after uploading some packages, use the existing artifacts to +publish the remainder: + +1. Select **Run new** from the original build. +2. Enable **Publish release** and **Produce Nuget packages**. Disable + **Produce PyManager package** and **Produce EXE/MSI installer**. +3. Set **Republish a build (select in Resources)** to `build_to_publish`, and + leave **Repackage and publish a build (select in Resources)** set to `current`. +4. Set **NuGet packages to skip on retry** to filenames or patterns matching only + packages confirmed to have been uploaded. Separate multiple entries with + semicolons, for example + `python-freethreaded.3.16.0-a1.nupkg;pythonx86-freethreaded.3.16.0-a1.nupkg`. + Leave `(none)` for an initial publish. +5. Under **Next: Resources**, select the original run under + **Windows-Release [build_to_publish]**, then select **Run**. + ## Finding/updating certificates For code signing, we use [Azure Trusted Signing](https://learn.microsoft.com/en-us/azure/trusted-signing/overview). diff --git a/windows-release/azure-pipelines.yml b/windows-release/azure-pipelines.yml index 8e24905c..9071b13e 100644 --- a/windows-release/azure-pipelines.yml +++ b/windows-release/azure-pipelines.yml @@ -103,6 +103,10 @@ parameters: displayName: "Produce Nuget packages" type: boolean default: true +- name: SkipNugetPackages + displayName: "NuGet packages to skip on retry (semicolon-separated)" + type: string + default: '(none)' - name: DoEmbed displayName: "Produce embeddable package (w/ PyManager or MSI options)" type: boolean @@ -364,3 +368,4 @@ stages: - template: stage-publish-nugetorg.yml parameters: BuildToPublish: ${{ parameters.BuildToPublish }} + SkipNugetPackages: ${{ parameters.SkipNugetPackages }} diff --git a/windows-release/stage-publish-nugetorg.yml b/windows-release/stage-publish-nugetorg.yml index 0b5db4e4..deae4614 100644 --- a/windows-release/stage-publish-nugetorg.yml +++ b/windows-release/stage-publish-nugetorg.yml @@ -1,5 +1,6 @@ parameters: BuildToPublish: current + SkipNugetPackages: '(none)' jobs: - job: Publish_Nuget @@ -31,6 +32,24 @@ jobs: workingDirectory: '$(Build.BinariesDirectory)\nuget' condition: and(succeeded(), ne(variables['PublishARM64'], 'true')) + - ${{ if ne(parameters.SkipNugetPackages, '(none)') }}: + - powershell: | + $patterns = ($env:SKIP_NUGET_PACKAGES -split ';').Trim() | + Where-Object { $_ } + if (-not $patterns) { + throw 'No NuGet package patterns were provided' + } + Get-ChildItem -Path $patterns -File -ErrorAction Stop | + Sort-Object -Property FullName -Unique | + ForEach-Object { + Write-Host "Not publishing: $($_.Name)" + Remove-Item -LiteralPath $_.FullName + } + displayName: 'Skip already published NuGet packages' + workingDirectory: '$(Build.BinariesDirectory)\nuget' + env: + SKIP_NUGET_PACKAGES: ${{ parameters.SkipNugetPackages }} + - task: NuGetCommand@2 displayName: Push packages condition: and(succeeded(), eq(variables['IsRealSigned'], 'true')) @@ -39,3 +58,4 @@ jobs: packagesToPush: '$(Build.BinariesDirectory)\nuget\*.nupkg' nuGetFeedType: external publishFeedCredentials: 'Python on Nuget' + requestTimeout: 600