Enable publish of Windows releases through Azure Pipelines (GH-14720)
This commit is contained in:
parent
fb6c1f8d3b
commit
994a3b88dc
|
@ -1,7 +1,8 @@
|
||||||
name: Release_$(Build.SourceBranchName)_$(SourceTag)_$(Date:yyyyMMdd)$(Rev:.rr)
|
name: Release_$(Build.SourceBranchName)_$(SourceTag)_$(Date:yyyyMMdd)$(Rev:.rr)
|
||||||
|
|
||||||
|
variables:
|
||||||
|
__RealSigningCertificate: 'Python Software Foundation'
|
||||||
# QUEUE TIME VARIABLES
|
# QUEUE TIME VARIABLES
|
||||||
# variables:
|
|
||||||
# GitRemote: python
|
# GitRemote: python
|
||||||
# SourceTag:
|
# SourceTag:
|
||||||
# DoPGO: true
|
# DoPGO: true
|
||||||
|
@ -13,6 +14,9 @@ name: Release_$(Build.SourceBranchName)_$(SourceTag)_$(Date:yyyyMMdd)$(Rev:.rr)
|
||||||
# DoEmbed: true
|
# DoEmbed: true
|
||||||
# DoMSI: true
|
# DoMSI: true
|
||||||
# DoPublish: false
|
# DoPublish: false
|
||||||
|
# PyDotOrgUsername: ''
|
||||||
|
# PyDotOrgServer: ''
|
||||||
|
# BuildToPublish: ''
|
||||||
|
|
||||||
trigger: none
|
trigger: none
|
||||||
pr: none
|
pr: none
|
||||||
|
@ -20,18 +24,21 @@ pr: none
|
||||||
stages:
|
stages:
|
||||||
- stage: Build
|
- stage: Build
|
||||||
displayName: Build binaries
|
displayName: Build binaries
|
||||||
|
condition: and(succeeded(), not(variables['BuildToPublish']))
|
||||||
jobs:
|
jobs:
|
||||||
- template: windows-release/stage-build.yml
|
- template: windows-release/stage-build.yml
|
||||||
|
|
||||||
- stage: Sign
|
- stage: Sign
|
||||||
displayName: Sign binaries
|
displayName: Sign binaries
|
||||||
dependsOn: Build
|
dependsOn: Build
|
||||||
|
condition: and(succeeded(), not(variables['BuildToPublish']))
|
||||||
jobs:
|
jobs:
|
||||||
- template: windows-release/stage-sign.yml
|
- template: windows-release/stage-sign.yml
|
||||||
|
|
||||||
- stage: Layout
|
- stage: Layout
|
||||||
displayName: Generate layouts
|
displayName: Generate layouts
|
||||||
dependsOn: Sign
|
dependsOn: Sign
|
||||||
|
condition: and(succeeded(), not(variables['BuildToPublish']))
|
||||||
jobs:
|
jobs:
|
||||||
- template: windows-release/stage-layout-full.yml
|
- template: windows-release/stage-layout-full.yml
|
||||||
- template: windows-release/stage-layout-embed.yml
|
- template: windows-release/stage-layout-embed.yml
|
||||||
|
@ -39,11 +46,13 @@ stages:
|
||||||
|
|
||||||
- stage: Pack
|
- stage: Pack
|
||||||
dependsOn: Layout
|
dependsOn: Layout
|
||||||
|
condition: and(succeeded(), not(variables['BuildToPublish']))
|
||||||
jobs:
|
jobs:
|
||||||
- template: windows-release/stage-pack-nuget.yml
|
- template: windows-release/stage-pack-nuget.yml
|
||||||
|
|
||||||
- stage: Test
|
- stage: Test
|
||||||
dependsOn: Pack
|
dependsOn: Pack
|
||||||
|
condition: and(succeeded(), not(variables['BuildToPublish']))
|
||||||
jobs:
|
jobs:
|
||||||
- template: windows-release/stage-test-embed.yml
|
- template: windows-release/stage-test-embed.yml
|
||||||
- template: windows-release/stage-test-nuget.yml
|
- template: windows-release/stage-test-nuget.yml
|
||||||
|
@ -51,46 +60,70 @@ stages:
|
||||||
- stage: Layout_MSIX
|
- stage: Layout_MSIX
|
||||||
displayName: Generate MSIX layouts
|
displayName: Generate MSIX layouts
|
||||||
dependsOn: Sign
|
dependsOn: Sign
|
||||||
condition: and(succeeded(), eq(variables['DoMSIX'], 'true'))
|
condition: and(succeeded(), and(eq(variables['DoMSIX'], 'true'), not(variables['BuildToPublish'])))
|
||||||
jobs:
|
jobs:
|
||||||
- template: windows-release/stage-layout-msix.yml
|
- template: windows-release/stage-layout-msix.yml
|
||||||
|
|
||||||
- stage: Pack_MSIX
|
- stage: Pack_MSIX
|
||||||
displayName: Package MSIX
|
displayName: Package MSIX
|
||||||
dependsOn: Layout_MSIX
|
dependsOn: Layout_MSIX
|
||||||
|
condition: and(succeeded(), not(variables['BuildToPublish']))
|
||||||
jobs:
|
jobs:
|
||||||
- template: windows-release/stage-pack-msix.yml
|
- template: windows-release/stage-pack-msix.yml
|
||||||
|
|
||||||
- stage: Build_MSI
|
- stage: Build_MSI
|
||||||
displayName: Build MSI installer
|
displayName: Build MSI installer
|
||||||
dependsOn: Sign
|
dependsOn: Sign
|
||||||
condition: and(succeeded(), eq(variables['DoMSI'], 'true'))
|
condition: and(succeeded(), and(eq(variables['DoMSI'], 'true'), not(variables['BuildToPublish'])))
|
||||||
jobs:
|
jobs:
|
||||||
- template: windows-release/stage-msi.yml
|
- template: windows-release/stage-msi.yml
|
||||||
|
|
||||||
- stage: Test_MSI
|
- stage: Test_MSI
|
||||||
displayName: Test MSI installer
|
displayName: Test MSI installer
|
||||||
dependsOn: Build_MSI
|
dependsOn: Build_MSI
|
||||||
|
condition: and(succeeded(), not(variables['BuildToPublish']))
|
||||||
jobs:
|
jobs:
|
||||||
- template: windows-release/stage-test-msi.yml
|
- template: windows-release/stage-test-msi.yml
|
||||||
|
|
||||||
- stage: PublishPyDotOrg
|
- stage: PublishPyDotOrg
|
||||||
displayName: Publish to python.org
|
displayName: Publish to python.org
|
||||||
dependsOn: ['Test_MSI', 'Test']
|
dependsOn: ['Test_MSI', 'Test']
|
||||||
condition: and(succeeded(), eq(variables['DoPublish'], 'true'))
|
condition: and(succeeded(), and(eq(variables['DoPublish'], 'true'), not(variables['BuildToPublish'])))
|
||||||
jobs:
|
jobs:
|
||||||
- template: windows-release/stage-publish-pythonorg.yml
|
- template: windows-release/stage-publish-pythonorg.yml
|
||||||
|
|
||||||
- stage: PublishNuget
|
- stage: PublishNuget
|
||||||
displayName: Publish to nuget.org
|
displayName: Publish to nuget.org
|
||||||
dependsOn: Test
|
dependsOn: Test
|
||||||
condition: and(succeeded(), eq(variables['DoPublish'], 'true'))
|
condition: and(succeeded(), and(eq(variables['DoPublish'], 'true'), not(variables['BuildToPublish'])))
|
||||||
jobs:
|
jobs:
|
||||||
- template: windows-release/stage-publish-nugetorg.yml
|
- template: windows-release/stage-publish-nugetorg.yml
|
||||||
|
|
||||||
- stage: PublishStore
|
- stage: PublishStore
|
||||||
displayName: Publish to Store
|
displayName: Publish to Store
|
||||||
dependsOn: Pack_MSIX
|
dependsOn: Pack_MSIX
|
||||||
condition: and(succeeded(), eq(variables['DoPublish'], 'true'))
|
condition: and(succeeded(), and(eq(variables['DoPublish'], 'true'), not(variables['BuildToPublish'])))
|
||||||
|
jobs:
|
||||||
|
- template: windows-release/stage-publish-store.yml
|
||||||
|
|
||||||
|
|
||||||
|
- stage: PublishExistingPyDotOrg
|
||||||
|
displayName: Publish existing build to python.org
|
||||||
|
dependsOn: []
|
||||||
|
condition: and(succeeded(), and(eq(variables['DoPublish'], 'true'), variables['BuildToPublish']))
|
||||||
|
jobs:
|
||||||
|
- template: windows-release/stage-publish-pythonorg.yml
|
||||||
|
|
||||||
|
- stage: PublishExistingNuget
|
||||||
|
displayName: Publish existing build to nuget.org
|
||||||
|
dependsOn: []
|
||||||
|
condition: and(succeeded(), and(eq(variables['DoPublish'], 'true'), variables['BuildToPublish']))
|
||||||
|
jobs:
|
||||||
|
- template: windows-release/stage-publish-nugetorg.yml
|
||||||
|
|
||||||
|
- stage: PublishExistingStore
|
||||||
|
displayName: Publish existing build to Store
|
||||||
|
dependsOn: []
|
||||||
|
condition: and(succeeded(), and(eq(variables['DoPublish'], 'true'), variables['BuildToPublish']))
|
||||||
jobs:
|
jobs:
|
||||||
- template: windows-release/stage-publish-store.yml
|
- template: windows-release/stage-publish-store.yml
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
parameters:
|
||||||
|
GPGKeyFile: $(GPGKey)
|
||||||
|
GPGPassphrase: $(GPGPassphrase)
|
||||||
|
Files: '*'
|
||||||
|
WorkingDirectory: $(Build.BinariesDirectory)
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- task: DownloadSecureFile@1
|
||||||
|
name: gpgkey
|
||||||
|
inputs:
|
||||||
|
secureFile: ${{ parameters.GPGKeyFile }}
|
||||||
|
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)"
|
||||||
|
(gci -File ${{ parameters.Files }}).FullName | %{
|
||||||
|
gpg/gpg2.exe -ba --batch --passphrase ${{ parameters.GPGPassphrase }} $_
|
||||||
|
"Made signature for $_"
|
||||||
|
}
|
||||||
|
displayName: 'Generate GPG signatures'
|
||||||
|
workingDirectory: ${{ parameters.WorkingDirectory }}
|
||||||
|
|
||||||
|
- powershell: |
|
||||||
|
$p = gps "gpg-agent" -EA 0
|
||||||
|
if ($p) { $p.Kill() }
|
||||||
|
displayName: 'Kill GPG agent'
|
||||||
|
condition: true
|
|
@ -14,13 +14,26 @@ jobs:
|
||||||
|
|
||||||
- task: DownloadBuildArtifacts@0
|
- task: DownloadBuildArtifacts@0
|
||||||
displayName: 'Download artifact: nuget'
|
displayName: 'Download artifact: nuget'
|
||||||
|
condition: and(succeeded(), not(variables['BuildToPublish']))
|
||||||
inputs:
|
inputs:
|
||||||
artifactName: nuget
|
artifactName: nuget
|
||||||
downloadPath: $(Build.BinariesDirectory)
|
downloadPath: $(Build.BinariesDirectory)
|
||||||
|
|
||||||
|
- task: DownloadBuildArtifacts@0
|
||||||
|
displayName: 'Download artifact: nuget'
|
||||||
|
condition: and(succeeded(), variables['BuildToPublish'])
|
||||||
|
inputs:
|
||||||
|
artifactName: nuget
|
||||||
|
downloadPath: $(Build.BinariesDirectory)
|
||||||
|
buildType: specific
|
||||||
|
project: cpython
|
||||||
|
pipeline: Windows-Release
|
||||||
|
buildVersionToDownload: specific
|
||||||
|
buildId: $(BuildToPublish)
|
||||||
|
|
||||||
- task: NuGetCommand@2
|
- task: NuGetCommand@2
|
||||||
displayName: Push packages
|
displayName: Push packages
|
||||||
condition: and(succeeded(), eq(variables['SigningCertificate'], 'Python Software Foundation'))
|
condition: and(succeeded(), eq(variables['SigningCertificate'], variables['__RealSigningCertificate']))
|
||||||
inputs:
|
inputs:
|
||||||
command: push
|
command: push
|
||||||
packagesToPush: $(Build.BinariesDirectory)\nuget\*.nupkg'
|
packagesToPush: $(Build.BinariesDirectory)\nuget\*.nupkg'
|
||||||
|
|
|
@ -4,31 +4,151 @@ jobs:
|
||||||
condition: and(succeeded(), and(eq(variables['DoMSI'], 'true'), eq(variables['DoEmbed'], 'true')))
|
condition: and(succeeded(), and(eq(variables['DoMSI'], 'true'), eq(variables['DoEmbed'], 'true')))
|
||||||
|
|
||||||
pool:
|
pool:
|
||||||
vmName: win2016-vs2017
|
#vmName: win2016-vs2017
|
||||||
|
name: 'Windows Release'
|
||||||
|
|
||||||
workspace:
|
workspace:
|
||||||
clean: all
|
clean: all
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- checkout: none
|
- template: ./checkout.yml
|
||||||
|
|
||||||
- task: DownloadBuildArtifacts@0
|
- task: UsePythonVersion@0
|
||||||
|
displayName: 'Use Python 3.6 or later'
|
||||||
|
inputs:
|
||||||
|
versionSpec: '>=3.6'
|
||||||
|
|
||||||
|
- task: DownloadPipelineArtifact@1
|
||||||
displayName: 'Download artifact: Doc'
|
displayName: 'Download artifact: Doc'
|
||||||
|
condition: and(succeeded(), not(variables['BuildToPublish']))
|
||||||
inputs:
|
inputs:
|
||||||
artifactName: Doc
|
artifactName: Doc
|
||||||
downloadPath: $(Build.BinariesDirectory)
|
targetPath: $(Build.BinariesDirectory)\Doc
|
||||||
|
|
||||||
- task: DownloadBuildArtifacts@0
|
- task: DownloadPipelineArtifact@1
|
||||||
displayName: 'Download artifact: msi'
|
displayName: 'Download artifact: msi'
|
||||||
|
condition: and(succeeded(), not(variables['BuildToPublish']))
|
||||||
inputs:
|
inputs:
|
||||||
artifactName: msi
|
artifactName: msi
|
||||||
downloadPath: $(Build.BinariesDirectory)
|
targetPath: $(Build.BinariesDirectory)\msi
|
||||||
|
|
||||||
- task: DownloadBuildArtifacts@0
|
- task: DownloadBuildArtifacts@0
|
||||||
displayName: 'Download artifact: embed'
|
displayName: 'Download artifact: embed'
|
||||||
|
condition: and(succeeded(), not(variables['BuildToPublish']))
|
||||||
inputs:
|
inputs:
|
||||||
artifactName: embed
|
artifactName: embed
|
||||||
downloadPath: $(Build.BinariesDirectory)
|
downloadPath: $(Build.BinariesDirectory)
|
||||||
|
|
||||||
# TODO: eq(variables['SigningCertificate'], 'Python Software Foundation')
|
|
||||||
# If we are not real-signed, DO NOT PUBLISH
|
- task: DownloadPipelineArtifact@1
|
||||||
|
displayName: 'Download artifact from $(BuildToPublish): Doc'
|
||||||
|
condition: and(succeeded(), variables['BuildToPublish'])
|
||||||
|
inputs:
|
||||||
|
artifactName: Doc
|
||||||
|
targetPath: $(Build.BinariesDirectory)\Doc
|
||||||
|
buildType: specific
|
||||||
|
project: cpython
|
||||||
|
pipeline: 21
|
||||||
|
buildVersionToDownload: specific
|
||||||
|
buildId: $(BuildToPublish)
|
||||||
|
|
||||||
|
- task: DownloadPipelineArtifact@1
|
||||||
|
displayName: 'Download artifact from $(BuildToPublish): msi'
|
||||||
|
condition: and(succeeded(), variables['BuildToPublish'])
|
||||||
|
inputs:
|
||||||
|
artifactName: msi
|
||||||
|
targetPath: $(Build.BinariesDirectory)\msi
|
||||||
|
buildType: specific
|
||||||
|
project: cpython
|
||||||
|
pipeline: 21
|
||||||
|
buildVersionToDownload: specific
|
||||||
|
buildId: $(BuildToPublish)
|
||||||
|
|
||||||
|
- task: DownloadBuildArtifacts@0
|
||||||
|
displayName: 'Download artifact from $(BuildToPublish): embed'
|
||||||
|
condition: and(succeeded(), variables['BuildToPublish'])
|
||||||
|
inputs:
|
||||||
|
artifactName: embed
|
||||||
|
downloadPath: $(Build.BinariesDirectory)
|
||||||
|
buildType: specific
|
||||||
|
project: cpython
|
||||||
|
pipeline: Windows-Release
|
||||||
|
buildVersionToDownload: specific
|
||||||
|
buildId: $(BuildToPublish)
|
||||||
|
|
||||||
|
|
||||||
|
- template: ./gpg-sign.yml
|
||||||
|
parameters:
|
||||||
|
GPGKeyFile: 'python-signing.key'
|
||||||
|
Files: 'doc\htmlhelp\*.chm, msi\*\*, embed\*.zip'
|
||||||
|
|
||||||
|
- powershell: >
|
||||||
|
$(Build.SourcesDirectory)\Tools\msi\uploadrelease.ps1
|
||||||
|
-build msi
|
||||||
|
-user $(PyDotOrgUsername)
|
||||||
|
-server $(PyDotOrgServer)
|
||||||
|
-doc_htmlhelp doc\htmlhelp
|
||||||
|
-embed embed
|
||||||
|
-skippurge
|
||||||
|
-skiptest
|
||||||
|
-skiphash
|
||||||
|
condition: and(succeeded(), eq(variables['SigningCertificate'], variables['__RealSigningCertificate']))
|
||||||
|
workingDirectory: $(Build.BinariesDirectory)
|
||||||
|
displayName: 'Upload files to python.org'
|
||||||
|
|
||||||
|
- powershell: >
|
||||||
|
python
|
||||||
|
"$(Build.SourcesDirectory)\Tools\msi\purge.py"
|
||||||
|
(gci msi\*\python-*.exe | %{ $_.Name -replace 'python-(.+?)(-|\.exe).+', '$1' } | select -First 1)
|
||||||
|
workingDirectory: $(Build.BinariesDirectory)
|
||||||
|
displayName: 'Purge CDN'
|
||||||
|
|
||||||
|
- powershell: |
|
||||||
|
$failures = 0
|
||||||
|
gci "msi\*\*-webinstall.exe" -File | %{
|
||||||
|
$d = mkdir "tests\$($_.BaseName)" -Force
|
||||||
|
gci $d -r -File | del
|
||||||
|
$ic = copy $_ $d -PassThru
|
||||||
|
"Checking layout for $($ic.Name)"
|
||||||
|
Start-Process -wait $ic "/passive", "/layout", "$d\layout", "/log", "$d\log\install.log"
|
||||||
|
if (-not $?) {
|
||||||
|
Write-Error "Failed to validate layout of $($inst.Name)"
|
||||||
|
$failures += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($failures) {
|
||||||
|
Write-Error "Failed to validate $failures installers"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
#condition: and(succeeded(), eq(variables['SigningCertificate'], variables['__RealSigningCertificate']))
|
||||||
|
workingDirectory: $(Build.BinariesDirectory)
|
||||||
|
displayName: 'Test layouts'
|
||||||
|
|
||||||
|
- powershell: |
|
||||||
|
$hashes = gci doc\htmlhelp\python*.chm, msi\*\*.exe, embed\*.zip | `
|
||||||
|
Sort-Object Name | `
|
||||||
|
Format-Table Name, @{
|
||||||
|
Label="MD5";
|
||||||
|
Expression={(Get-FileHash $_ -Algorithm MD5).Hash}
|
||||||
|
}, Length -AutoSize | `
|
||||||
|
Out-String -Width 4096
|
||||||
|
$d = mkdir "$(Build.ArtifactStagingDirectory)\hashes" -Force
|
||||||
|
$hashes | Out-File "$d\hashes.txt" -Encoding ascii
|
||||||
|
$hashes
|
||||||
|
workingDirectory: $(Build.BinariesDirectory)
|
||||||
|
displayName: 'Generate hashes'
|
||||||
|
|
||||||
|
- powershell: |
|
||||||
|
"Copying:"
|
||||||
|
(gci msi\*\python*.asc, doc\htmlhelp\*.asc, embed\*.asc).FullName
|
||||||
|
$d = mkdir "$(Build.ArtifactStagingDirectory)\hashes" -Force
|
||||||
|
move msi\*\python*.asc, doc\htmlhelp\*.asc, embed\*.asc $d -Force
|
||||||
|
gci msi -Directory | %{ move "msi\$_\*.asc" (mkdir "$d\$_" -Force) }
|
||||||
|
workingDirectory: $(Build.BinariesDirectory)
|
||||||
|
displayName: 'Copy GPG signatures for build'
|
||||||
|
|
||||||
|
- task: PublishPipelineArtifact@0
|
||||||
|
displayName: 'Publish Artifact: hashes'
|
||||||
|
inputs:
|
||||||
|
targetPath: '$(Build.ArtifactStagingDirectory)\hashes'
|
||||||
|
artifactName: hashes
|
||||||
|
|
|
@ -14,9 +14,22 @@ jobs:
|
||||||
|
|
||||||
- task: DownloadBuildArtifacts@0
|
- task: DownloadBuildArtifacts@0
|
||||||
displayName: 'Download artifact: msixupload'
|
displayName: 'Download artifact: msixupload'
|
||||||
|
condition: and(succeeded(), not(variables['BuildToPublish']))
|
||||||
inputs:
|
inputs:
|
||||||
artifactName: msixupload
|
artifactName: msixupload
|
||||||
downloadPath: $(Build.BinariesDirectory)
|
downloadPath: $(Build.BinariesDirectory)
|
||||||
|
|
||||||
# TODO: eq(variables['SigningCertificate'], 'Python Software Foundation')
|
- task: DownloadBuildArtifacts@0
|
||||||
|
displayName: 'Download artifact: msixupload'
|
||||||
|
condition: and(succeeded(), variables['BuildToPublish'])
|
||||||
|
inputs:
|
||||||
|
artifactName: msixupload
|
||||||
|
downloadPath: $(Build.BinariesDirectory)
|
||||||
|
buildType: specific
|
||||||
|
project: cpython
|
||||||
|
pipeline: Windows-Release
|
||||||
|
buildVersionToDownload: specific
|
||||||
|
buildId: $(BuildToPublish)
|
||||||
|
|
||||||
|
# TODO: eq(variables['SigningCertificate'], variables['__RealSigningCertificate'])
|
||||||
# If we are not real-signed, DO NOT PUBLISH
|
# If we are not real-signed, DO NOT PUBLISH
|
||||||
|
|
|
@ -164,5 +164,4 @@ if (-not $skiphash) {
|
||||||
Out-String -Width 4096
|
Out-String -Width 4096
|
||||||
$hashes | clip
|
$hashes | clip
|
||||||
$hashes
|
$hashes
|
||||||
popd
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue