From febb1cc34223f92798ba69627fc259570bcf05ef Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Wed, 14 Oct 2026 12:38:21 +0200 Subject: [PATCH 1/2] Remove unnecessary 3.13 installer code --- windows-release/README.md | 11 +- windows-release/azure-pipelines.yml | 20 +-- windows-release/stage-layout-msix.yml | 122 ------------------ windows-release/stage-pack-msix.yml | 134 -------------------- windows-release/stage-publish-pythonorg.yml | 38 ------ 5 files changed, 2 insertions(+), 323 deletions(-) delete mode 100644 windows-release/stage-layout-msix.yml delete mode 100644 windows-release/stage-pack-msix.yml diff --git a/windows-release/README.md b/windows-release/README.md index a8ff8a01..23cf70fd 100644 --- a/windows-release/README.md +++ b/windows-release/README.md @@ -21,16 +21,7 @@ When signing is enabled (any value besides "Unsigned"), authorised approvers wil will need to approve each stage that requires the signing certificate (typically three). This helps prevent "surprise" builds from using the official certificate. -Some additional points to be aware of: - -* packages are not automatically published to the Microsoft Store -* successful builds should be retained by selecting "Retain" under the "..." menu in the top-right - -The `msixupload` artifacts should be uploaded to the Microsoft Store at -https://partner.microsoft.com/en-us/dashboard/apps-and-games/overview. -Access to this site is very limited. -We also usually update the screenshots so that the version information they show matches the release. - +Successful builds should be retained by selecting "Retain" under the "..." menu in the top-right. 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. diff --git a/windows-release/azure-pipelines.yml b/windows-release/azure-pipelines.yml index a20b126b..1565c9ee 100644 --- a/windows-release/azure-pipelines.yml +++ b/windows-release/azure-pipelines.yml @@ -61,17 +61,9 @@ parameters: type: boolean default: true - name: DoJIT - displayName: "Build the JIT compiler (3.14 and later)" + displayName: "Build the JIT compiler" type: boolean default: true -- name: DoGPG - displayName: "Include GPG signatures (only up to 3.13)" - type: boolean - default: false -- name: DoMSIX - displayName: "Produce Store packages (only up to 3.13)" - type: boolean - default: false # Stable version options # The default option matches what we use for all currently releasing versions. @@ -269,11 +261,6 @@ stages: BuildToPackage: ${{ parameters.BuildToPackage }} DoFreethreaded: ${{ parameters.DoFreethreaded }} SigningCertificate: ${{ iif(eq(parameters.SigningCertificate, 'Unsigned'), '', parameters.SigningCertificate) }} - - ${{ if eq(parameters.DoMSIX, 'true') }}: - - template: stage-layout-msix.yml - parameters: - BuildToPackage: ${{ parameters.BuildToPackage }} - SigningCertificate: ${{ iif(eq(parameters.SigningCertificate, 'Unsigned'), '', parameters.SigningCertificate) }} - ${{ if eq(parameters.DoPyManager, 'true') }}: - template: stage-layout-pymanager.yml parameters: @@ -300,10 +287,6 @@ stages: DoFreethreaded: ${{ parameters.DoFreethreaded }} SigningCertificate: ${{ iif(eq(parameters.SigningCertificate, 'Unsigned'), '', parameters.SigningCertificate) }} Post315OutputDir: ${{ parameters.Post315OutputDir }} - - ${{ if eq(parameters.DoMSIX, 'true') }}: - - template: stage-pack-msix.yml - parameters: - SigningCertificate: ${{ iif(eq(parameters.SigningCertificate, 'Unsigned'), '', parameters.SigningCertificate) }} - ${{ if eq(parameters.DoNuget, 'true') }}: - template: stage-pack-nuget.yml parameters: @@ -359,7 +342,6 @@ stages: parameters: BuildToPublish: ${{ parameters.BuildToPublish }} DoEmbed: ${{ parameters.DoEmbed }} - IncludeGPG: ${{ parameters.DoGPG }} - ${{ if eq(parameters.DoNuget, 'true') }}: - template: stage-publish-nugetorg.yml parameters: diff --git a/windows-release/stage-layout-msix.yml b/windows-release/stage-layout-msix.yml deleted file mode 100644 index d5e4cbd8..00000000 --- a/windows-release/stage-layout-msix.yml +++ /dev/null @@ -1,122 +0,0 @@ -parameters: - BuildToPackage: current - SigningCertificate: '' - -jobs: -- job: Make_MSIX_Layout - displayName: Make MSIX layout - - workspace: - clean: all - - variables: - PYTHONHOME: $(Build.SourcesDirectory) - - strategy: - matrix: - #win32: - # Name: win32 - # TclLibrary: tcltk_lib_win32 - # ExtraOptions: --precompile - amd64: - Name: amd64 - Arch: amd64 - TclLibrary: tcltk_lib_amd64 - ExtraOptions: --precompile - arm64: - Name: arm64 - Arch: arm64 - HostArch: amd64 - TclLibrary: tcltk_lib_arm64 - ExtraOptions: --precompile - - steps: - - template: ./checkout.yml - - - task: DownloadPipelineArtifact@2 - displayName: 'Download artifact: bin_$(Name)' - inputs: - ${{ if eq(parameters.BuildToPackage, 'current') }}: - buildType: current - ${{ else }}: - buildType: specific - buildVersionToDownload: specific - project: $(resources.pipeline.build_to_package.projectId) - pipeline: $(resources.pipeline.build_to_package.pipelineId) - runId: $(resources.pipeline.build_to_package.runID) - artifact: bin_$(Name) - targetPath: $(Pipeline.Workspace)\bin_$(Name) - - - task: DownloadPipelineArtifact@2 - displayName: 'Download artifact: $(TclLibrary)' - condition: and(succeeded(), variables['TclLibrary']) - inputs: - ${{ if eq(parameters.BuildToPackage, 'current') }}: - buildType: current - ${{ else }}: - buildType: specific - buildVersionToDownload: specific - project: $(resources.pipeline.build_to_package.projectId) - pipeline: $(resources.pipeline.build_to_package.pipelineId) - runId: $(resources.pipeline.build_to_package.runID) - artifact: $(TclLibrary) - targetPath: $(Pipeline.Workspace)\$(TclLibrary) - - - powershell: | - Write-Host "##vso[task.setvariable variable=TCL_LIBRARY]$(Pipeline.Workspace)\$(TclLibrary)\tcl8" - displayName: 'Update TCL_LIBRARY' - condition: and(succeeded(), variables['TclLibrary']) - - - ${{ if parameters.SigningCertificate }}: - - task: DownloadPipelineArtifact@2 - displayName: 'Download artifact: cert' - inputs: - ${{ if eq(parameters.BuildToPackage, 'current') }}: - buildType: current - ${{ else }}: - buildType: specific - buildVersionToDownload: specific - project: $(resources.pipeline.build_to_package.projectId) - pipeline: $(resources.pipeline.build_to_package.pipelineId) - runId: $(resources.pipeline.build_to_package.runID) - artifact: cert - targetPath: $(Pipeline.Workspace)\cert - - - powershell: | - copy "$(Pipeline.Workspace)\bin_$(Name)\Activate.ps1" Lib\venv\scripts\common\Activate.ps1 -Force -Verbose - displayName: 'Copy signed files into sources' - - - template: ./layout-command.yml - parameters: - BuildToPackage: ${{ parameters.BuildToPackage }} - - - powershell: | - Remove-Item "$(Build.ArtifactStagingDirectory)\appx-store" -Recurse -Force -EA 0 - $(LayoutCmd) --copy "$(Build.ArtifactStagingDirectory)\appx-store" --preset-appx $(ExtraOptions) - displayName: 'Generate store APPX layout' - env: - TCL_LIBRARY: $(TclLibrary) - - - ${{ if parameters.SigningCertificate }}: - # The dotnet sign tool shouldn't need this, but we do because of the sccd file - - powershell: | - $info = (gc "$(Pipeline.Workspace)\cert\certinfo.json" | ConvertFrom-JSON) - Write-Host "Side-loadable APPX must be signed with '$($info.Subject)'" - Write-Host "##vso[task.setvariable variable=APPX_DATA_PUBLISHER]$($info.Subject)" - Write-Host "##vso[task.setvariable variable=APPX_DATA_SHA256]$($info.SHA256)" - displayName: 'Override signing parameters' - - - powershell: | - Remove-Item "$(Build.ArtifactStagingDirectory)\appx" -Recurse -Force -EA 0 - $(LayoutCmd) --copy "$(Build.ArtifactStagingDirectory)\appx" --preset-appx --include-symbols --include-tests $(ExtraOptions) - displayName: 'Generate sideloading APPX layout' - env: - TCL_LIBRARY: $(TclLibrary) - - - publish: '$(Build.ArtifactStagingDirectory)\appx-store' - artifact: layout_appxstore_$(Name) - displayName: 'Publish Artifact: layout_appxstore_$(Name)' - - - publish: '$(Build.ArtifactStagingDirectory)\appx' - artifact: layout_appx_$(Name) - displayName: 'Publish Artifact: layout_appx_$(Name)' diff --git a/windows-release/stage-pack-msix.yml b/windows-release/stage-pack-msix.yml deleted file mode 100644 index cb732b09..00000000 --- a/windows-release/stage-pack-msix.yml +++ /dev/null @@ -1,134 +0,0 @@ -parameters: - SigningCertificate: '' - -jobs: -- job: Pack_MSIX - displayName: Pack MSIX bundles - - workspace: - clean: all - - variables: - SigningCertificate: ${{ parameters.SigningCertificate }} - - strategy: - matrix: - amd64: - Name: amd64 - Artifact: appx - Suffix: - ShouldSign: true - amd64_store: - Name: amd64 - Artifact: appxstore - Suffix: -store - CreateMsixUpload: true - arm64: - Name: arm64 - Artifact: appx - Suffix: - ShouldSign: true - arm64_store: - Name: arm64 - Artifact: appxstore - Suffix: -store - CreateMsixUpload: true - - steps: - - template: ./checkout.yml - - - download: current - artifact: layout_$(Artifact)_$(Name) - displayName: 'Download artifact: layout_$(Artifact)_$(Name)' - - - download: current - artifact: symbols - patterns: $(Name)\* - displayName: 'Download artifact: symbols' - - - powershell: | - $d = (.\PCbuild\build.bat -V) | %{ if($_ -match '\s+(\w+):\s*(.+)\s*$') { @{$Matches[1] = $Matches[2];} }}; - Write-Host "##vso[task.setvariable variable=VersionText]$($d.PythonVersion)" - Write-Host "##vso[task.setvariable variable=VersionNumber]$($d.PythonVersionNumber)" - Write-Host "##vso[task.setvariable variable=VersionHex]$($d.PythonVersionHex)" - Write-Host "##vso[task.setvariable variable=VersionUnique]$($d.PythonVersionUnique)" - Write-Host "##vso[task.setvariable variable=Filename]python-$($d.PythonVersion)-$(Name)$(Suffix)" - displayName: 'Extract version numbers' - - - powershell: | - ./Tools/msi/make_appx.ps1 -layout "$(Pipeline.Workspace)\layout_$(Artifact)_$(Name)" -msix "$(Build.ArtifactStagingDirectory)\msix\$(Filename).msix" - displayName: 'Build msix' - - - powershell: | - 7z a -tzip "$(Build.ArtifactStagingDirectory)\msix\$(Filename).appxsym" *.pdb - displayName: 'Build appxsym' - workingDirectory: $(Pipeline.Workspace)\symbols\$(Name) - - - powershell: | - 7z a -tzip "$(Build.ArtifactStagingDirectory)\msixupload\$(Filename).msixupload" * - displayName: 'Build msixupload' - condition: and(succeeded(), eq(variables['CreateMsixUpload'], 'true')) - workingDirectory: $(Build.ArtifactStagingDirectory)\msix - - - task: PublishBuildArtifacts@1 - displayName: 'Publish Artifact: MSIX' - inputs: - PathtoPublish: '$(Build.ArtifactStagingDirectory)\msix' - ${{ if parameters.SigningCertificate }}: - ArtifactName: unsigned_msix - ${{ else }}: - ArtifactName: msix - - - task: PublishBuildArtifacts@1 - displayName: 'Publish Artifact: MSIXUpload' - condition: and(succeeded(), eq(variables['CreateMsixUpload'], 'true')) - inputs: - PathtoPublish: '$(Build.ArtifactStagingDirectory)\msixupload' - ArtifactName: msixupload - -- ${{ if parameters.SigningCertificate }}: - - job: Sign_MSIX - displayName: Sign side-loadable MSIX bundles - dependsOn: - - Pack_MSIX - - workspace: - clean: all - - variables: - - ${{ if eq(parameters.SigningCertificate, 'PythonSoftwareFoundation') }}: - - group: CPythonSign - - ${{ if eq(parameters.SigningCertificate, 'TestSign') }}: - - group: CPythonTestSign - - steps: - - template: ./checkout.yml - - - powershell: | - $d = (.\PCbuild\build.bat -V) | %{ if($_ -match '\s+(\w+):\s*(.+)\s*$') { @{$Matches[1] = $Matches[2];} }}; - Write-Host "##vso[task.setvariable variable=SigningDescription]Python $($d.PythonVersion)" - displayName: 'Update signing description' - condition: and(succeeded(), not(variables['SigningDescription'])) - - - task: DownloadBuildArtifacts@0 - displayName: 'Download Artifact: unsigned_msix' - inputs: - artifactName: unsigned_msix - downloadPath: $(Build.BinariesDirectory) - - # Getting "Error: SignerSign() failed." (-2147024885/0x8007000b)"? - # It may be that the certificate info collected in stage-sign.yml is wrong. Check that - # you do not have multiple matches for the certificate name you have specified. - - template: sign-files.yml - parameters: - Include: '*.msix' - # Additional filter to avoid recursively signing package contents - Filter: '*.msix' - WorkingDir: $(Build.BinariesDirectory)\unsigned_msix - SigningCertificate: ${{ parameters.SigningCertificate }} - - - task: PublishBuildArtifacts@1 - displayName: 'Publish Artifact: MSIX' - inputs: - PathtoPublish: '$(Build.BinariesDirectory)\unsigned_msix' - ArtifactName: msix diff --git a/windows-release/stage-publish-pythonorg.yml b/windows-release/stage-publish-pythonorg.yml index 58d5fd7c..fed161c4 100644 --- a/windows-release/stage-publish-pythonorg.yml +++ b/windows-release/stage-publish-pythonorg.yml @@ -1,7 +1,6 @@ parameters: BuildToPublish: current DoEmbed: true - IncludeGPG: false HashAlgorithms: ['SHA256', 'MD5'] jobs: @@ -74,32 +73,6 @@ jobs: workingDirectory: '$(Pipeline.Workspace)\embed' condition: and(succeeded(), ne(variables['PublishARM64'], 'true')) - - - ${{ if eq(parameters.IncludeGPG, 'true') }}: - - task: DownloadSecureFile@1 - name: gpgkey - inputs: - secureFile: 'python-signing.key' - displayName: 'Download GPG key' - - - powershell: | - git clone https://github.com/python/cpython-bin-deps --branch gpg --single-branch --depth 1 --progress -v "gpg" - gpg/gpg2.exe --import "$(gpgkey.secureFilePath)" - $files = gci -File "msi\*\*", "embed\*.zip" -EA SilentlyContinue - $files.FullName | %{ - gpg/gpg2.exe -ba --batch --passphrase $(GPGPassphrase) $_ - "Made signature for $_" - } - displayName: 'Generate GPG signatures' - workingDirectory: $(Pipeline.Workspace) - - - powershell: | - $p = gps "gpg-agent" -EA 0 - if ($p) { $p.Kill() } - displayName: 'Kill GPG agent' - condition: true - - - task: DownloadSecureFile@1 name: sshkey inputs: @@ -170,17 +143,6 @@ jobs: workingDirectory: $(Pipeline.Workspace) displayName: 'Generate hashes (${{ alg }})' - - ${{ if eq(parameters.IncludeGPG, 'true') }}: - - powershell: | - "Copying:" - $files = gci -File "msi\*\python*.asc", "embed\*.asc" -EA SilentlyContinue - $files.FullName - $d = mkdir "$(Build.ArtifactStagingDirectory)\hashes" -Force - move $files $d -Force - gci msi -Directory | %{ move "msi\$_\*.asc" (mkdir "$d\$_" -Force) } - workingDirectory: $(Pipeline.Workspace) - displayName: 'Copy GPG signatures for build' - - publish: '$(Build.ArtifactStagingDirectory)\hashes' artifact: hashes displayName: 'Publish Artifact: hashes' From 024517e06fbad807ca2de0a37c7bbff042f293e7 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Mon, 2 Nov 2026 23:06:23 +0200 Subject: [PATCH 2/2] Move from version specific to stable version --- windows-release/azure-pipelines.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/windows-release/azure-pipelines.yml b/windows-release/azure-pipelines.yml index 1565c9ee..99ea6d0a 100644 --- a/windows-release/azure-pipelines.yml +++ b/windows-release/azure-pipelines.yml @@ -46,7 +46,7 @@ parameters: # Version-specific build options # These often need to be changed by the person queuing the build, and should be # clearly labelled with the version range they apply to. -# When a version becomes EOL, its options can either move to the next section or +# When a version becomes security-only, its options can either move to the next section or # be removed if its impact is entirely absent from the source tree. - name: Post315OutputDir displayName: "Separate free-threaded outputs (3.15 and later)" @@ -60,13 +60,13 @@ parameters: displayName: "Produce EXE/MSI installer (only up to 3.15)" type: boolean default: true + +# Stable version options +# The default option matches what we use for all currently releasing versions. - name: DoJIT displayName: "Build the JIT compiler" type: boolean default: true - -# Stable version options -# The default option matches what we use for all currently releasing versions. - name: DoFreethreaded displayName: "Include free-threaded builds" type: boolean