Some checks failed
Build Windows Release / Build Windows x64 Release (MSVC + Qt) (push) Failing after -2s
231 lines
11 KiB
YAML
231 lines
11 KiB
YAML
name: Build Windows Release
|
||
|
||
on:
|
||
push:
|
||
branches:
|
||
- main
|
||
tags:
|
||
- 'v*'
|
||
workflow_dispatch:
|
||
|
||
permissions:
|
||
contents: write
|
||
|
||
jobs:
|
||
build-windows-release:
|
||
name: Build Windows x64 Release (MSVC + Qt)
|
||
# Windows runner 已注册标签:windows-latest、windows-2022、self-hosted;均为 host 模式。
|
||
runs-on: windows-2022
|
||
|
||
env:
|
||
BUILD_TYPE: Release
|
||
QT_VERSION: 6.7.3
|
||
QT_ARCH: win64_msvc2022_64
|
||
QT_DIR_NAME: msvc2022_64
|
||
PACKAGE_BASENAME: chengnan-windows-x64-msvc
|
||
PACKAGE_NAME: chengnan-windows-x64-msvc
|
||
|
||
steps:
|
||
- name: Prepare source
|
||
shell: powershell
|
||
run: |
|
||
$ErrorActionPreference = 'Stop'
|
||
$work = Join-Path $env:RUNNER_TEMP 'chengnan-src'
|
||
$srcFixed = Join-Path $env:RUNNER_TEMP 'chengnan-work'
|
||
$zip = Join-Path $env:RUNNER_TEMP 'chengnan-src.zip'
|
||
if (Test-Path $work) { Remove-Item -Recurse -Force $work }
|
||
if (Test-Path $srcFixed) { Remove-Item -Recurse -Force $srcFixed }
|
||
if (Test-Path $zip) { Remove-Item -Force $zip }
|
||
New-Item -ItemType Directory -Force -Path $work | Out-Null
|
||
|
||
$serverUrl = if ($env:GITHUB_SERVER_URL) { $env:GITHUB_SERVER_URL.TrimEnd('/') } else { 'https://git.luochen570.cn' }
|
||
$archiveUrl = "$serverUrl/$env:GITHUB_REPOSITORY/archive/$env:GITHUB_SHA.zip"
|
||
Write-Host "Downloading source archive from $archiveUrl"
|
||
Invoke-WebRequest -Uri $archiveUrl -OutFile $zip
|
||
Expand-Archive -Path $zip -DestinationPath $work -Force
|
||
|
||
$src = Get-ChildItem -Path $work -Directory | Select-Object -First 1
|
||
if (-not $src) { throw 'Source archive extraction produced no directory' }
|
||
Copy-Item -Path $src.FullName -Destination $srcFixed -Recurse -Force
|
||
Write-Host "Source dir: $srcFixed"
|
||
|
||
- name: Install official Qt for MSVC
|
||
shell: powershell
|
||
run: |
|
||
$ErrorActionPreference = 'Stop'
|
||
$qtRoot = Join-Path $env:RUNNER_TEMP 'qt-msvc'
|
||
$qtPrefix = Join-Path $qtRoot "$env:QT_VERSION\$env:QT_DIR_NAME"
|
||
$windeployqt = Join-Path $qtPrefix 'bin\windeployqt.exe'
|
||
if (Test-Path $windeployqt) {
|
||
Write-Host "Qt already installed: $qtPrefix"
|
||
exit 0
|
||
}
|
||
|
||
$pyLauncher = Get-Command py -ErrorAction SilentlyContinue
|
||
if ($pyLauncher) {
|
||
$pythonExe = $pyLauncher.Source
|
||
$pythonArgs = @('-3')
|
||
} else {
|
||
$python = Get-Command python -ErrorAction SilentlyContinue
|
||
if (-not $python) { throw 'Python is required to install Qt with aqtinstall, but py/python was not found on PATH.' }
|
||
$pythonExe = $python.Source
|
||
$pythonArgs = @()
|
||
}
|
||
|
||
& $pythonExe @pythonArgs -m pip install --user --upgrade aqtinstall
|
||
if ($LASTEXITCODE -ne 0) { throw "pip install aqtinstall failed, exit code: $LASTEXITCODE" }
|
||
|
||
& $pythonExe @pythonArgs -m aqt install-qt windows desktop $env:QT_VERSION $env:QT_ARCH -O $qtRoot -m qtimageformats
|
||
if ($LASTEXITCODE -ne 0) { throw "aqt Qt installation failed, exit code: $LASTEXITCODE" }
|
||
if (-not (Test-Path $windeployqt)) { throw "Qt installation finished but windeployqt was not found: $windeployqt" }
|
||
Write-Host "Qt installed: $qtPrefix"
|
||
|
||
- name: Configure, build, and deploy with MSVC
|
||
shell: powershell
|
||
run: |
|
||
$ErrorActionPreference = 'Stop'
|
||
$src = Join-Path $env:RUNNER_TEMP 'chengnan-work'
|
||
$qtRoot = Join-Path $env:RUNNER_TEMP 'qt-msvc'
|
||
$qtPrefix = Join-Path $qtRoot "$env:QT_VERSION\$env:QT_DIR_NAME"
|
||
|
||
$vswhere = Join-Path ${env:ProgramFiles(x86)} 'Microsoft Visual Studio\Installer\vswhere.exe'
|
||
if (-not (Test-Path $vswhere)) { throw "vswhere not found: $vswhere. Install Visual Studio 2022 Build Tools with Desktop development with C++." }
|
||
$vsPath = & $vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
|
||
if ([string]::IsNullOrWhiteSpace($vsPath)) { throw 'Visual Studio 2022 C++ build tools were not found. Install Desktop development with C++.' }
|
||
$vsDevCmd = Join-Path $vsPath 'Common7\Tools\VsDevCmd.bat'
|
||
if (-not (Test-Path $vsDevCmd)) { throw "VsDevCmd.bat not found: $vsDevCmd" }
|
||
|
||
$vsCmake = Join-Path $vsPath 'Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin'
|
||
if (Test-Path (Join-Path $vsCmake 'cmake.exe')) { $env:PATH = "$vsCmake;$env:PATH" }
|
||
if (-not (Get-Command cmake -ErrorAction SilentlyContinue)) { throw 'cmake was not found on PATH or in Visual Studio bundled CMake.' }
|
||
|
||
$buildDir = Join-Path $src 'build-windows'
|
||
$distDir = Join-Path $src 'dist-windows\chengnan'
|
||
$script = Join-Path $src 'build-windows.ps1'
|
||
$cmd = "`"$vsDevCmd`" -arch=x64 -host_arch=x64 && powershell -NoProfile -ExecutionPolicy Bypass -File `"$script`" -QtPrefix `"$qtPrefix`" -BuildDir `"$buildDir`" -DistDir `"$distDir`" -Generator `"Visual Studio 17 2022`" -Arch x64 -Config Release"
|
||
Write-Host "Building with Visual Studio at: $vsPath"
|
||
Write-Host "Using Qt: $qtPrefix"
|
||
& cmd.exe /c $cmd
|
||
if ($LASTEXITCODE -ne 0) { throw "MSVC build failed, exit code: $LASTEXITCODE" }
|
||
|
||
$readme = Join-Path $distDir 'README.txt'
|
||
@(
|
||
'chengnan Windows x64 package',
|
||
'',
|
||
'Usage:',
|
||
'1. Extract the whole directory.',
|
||
'2. Double-click chengnan.exe to run.',
|
||
'',
|
||
'Note:',
|
||
'- This package is built by Windows Runner with MSVC + official Qt.',
|
||
'- Do not copy chengnan.exe alone; keep DLLs and Qt plugin directories together.'
|
||
) | Out-File -FilePath $readme -Encoding ascii
|
||
|
||
- name: Package
|
||
shell: powershell
|
||
run: |
|
||
$ErrorActionPreference = 'Stop'
|
||
$shortSha = $env:GITHUB_SHA.Substring(0, 10)
|
||
$version = if ($env:GITHUB_REF_TYPE -eq 'tag') { $env:GITHUB_REF_NAME } else { "build-$shortSha" }
|
||
$zipName = "$env:PACKAGE_BASENAME-$version.zip"
|
||
$sourceDir = Join-Path $env:RUNNER_TEMP 'chengnan-work'
|
||
$dist = Join-Path $sourceDir 'dist-windows\chengnan'
|
||
if (-not (Test-Path "$dist\chengnan.exe")) { throw "Missing build output: $dist\chengnan.exe" }
|
||
Push-Location (Split-Path $dist -Parent)
|
||
if (Test-Path (Join-Path $sourceDir $zipName)) { Remove-Item -Force (Join-Path $sourceDir $zipName) }
|
||
Compress-Archive -Path 'chengnan\*' -DestinationPath (Join-Path $sourceDir $zipName) -Force
|
||
Pop-Location
|
||
$zipPath = Join-Path $sourceDir $zipName
|
||
$hash = (Get-FileHash $zipPath -Algorithm SHA256).Hash.ToLowerInvariant()
|
||
"$hash $zipName" | Out-File -FilePath "$zipPath.sha256" -Encoding ascii
|
||
Write-Host "Package: $zipPath"
|
||
Write-Host "SHA256: $hash"
|
||
|
||
- name: Verify package
|
||
shell: powershell
|
||
run: |
|
||
$ErrorActionPreference = 'Stop'
|
||
$shortSha = $env:GITHUB_SHA.Substring(0, 10)
|
||
$version = if ($env:GITHUB_REF_TYPE -eq 'tag') { $env:GITHUB_REF_NAME } else { "build-$shortSha" }
|
||
$zipName = "$env:PACKAGE_BASENAME-$version.zip"
|
||
$sourceDir = Join-Path $env:RUNNER_TEMP 'chengnan-work'
|
||
$zipPath = Join-Path $sourceDir $zipName
|
||
$shaPath = "$zipPath.sha256"
|
||
if (-not (Test-Path $zipPath)) { throw "zip does not exist: $zipPath" }
|
||
if (-not (Test-Path $shaPath)) { throw "sha256 does not exist: $shaPath" }
|
||
if ((Get-Item $zipPath).Length -le 0) { throw "zip file is empty: $zipPath" }
|
||
Write-Host "Verified package: $zipPath"
|
||
|
||
- name: Upload package to repository release
|
||
shell: powershell
|
||
env:
|
||
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||
run: |
|
||
$ErrorActionPreference = 'Stop'
|
||
$token = $env:RELEASE_TOKEN
|
||
if ([string]::IsNullOrWhiteSpace($token)) { $token = $env:GITHUB_TOKEN }
|
||
if ([string]::IsNullOrWhiteSpace($token)) { throw 'Missing release token. Configure RELEASE_TOKEN in repository secrets or ensure GITHUB_TOKEN is available.' }
|
||
|
||
$shortSha = $env:GITHUB_SHA.Substring(0, 10)
|
||
$version = if ($env:GITHUB_REF_TYPE -eq 'tag') { $env:GITHUB_REF_NAME } else { "build-$shortSha" }
|
||
$zipName = "$env:PACKAGE_BASENAME-$version.zip"
|
||
$sourceDir = Join-Path $env:RUNNER_TEMP 'chengnan-work'
|
||
$zipPath = Join-Path $sourceDir $zipName
|
||
$shaPath = "$zipPath.sha256"
|
||
|
||
$serverUrl = if ($env:GITHUB_SERVER_URL) { $env:GITHUB_SERVER_URL.TrimEnd('/') } else { 'https://git.luochen570.cn' }
|
||
$repo = $env:GITHUB_REPOSITORY
|
||
$apiBase = "$serverUrl/api/v1/repos/$repo"
|
||
$tagName = $version
|
||
$releaseName = if ($env:GITHUB_REF_TYPE -eq 'tag') { $env:GITHUB_REF_NAME } else { "chengnan $shortSha" }
|
||
$isPrerelease = if ($env:GITHUB_REF_TYPE -eq 'tag') { $false } else { $true }
|
||
$headers = @{ Authorization = "token $token"; Accept = 'application/json' }
|
||
|
||
$releasePayload = @{
|
||
tag_name = $tagName
|
||
target_commitish = $env:GITHUB_SHA
|
||
name = $releaseName
|
||
body = "Automated Windows x64 MSVC build from Gitea Actions.`n"
|
||
draft = $false
|
||
prerelease = $isPrerelease
|
||
} | ConvertTo-Json -Depth 5
|
||
|
||
try {
|
||
$release = Invoke-RestMethod -Method Post -Uri "$apiBase/releases" -Headers $headers -ContentType 'application/json' -Body $releasePayload
|
||
} catch {
|
||
$release = Invoke-RestMethod -Method Get -Uri "$apiBase/releases/tags/$tagName" -Headers $headers
|
||
}
|
||
|
||
function Remove-ExistingAsset([string]$assetName) {
|
||
$assets = Invoke-RestMethod -Method Get -Uri "$apiBase/releases/$($release.id)/assets" -Headers $headers
|
||
foreach ($asset in @($assets)) {
|
||
if ($asset.name -eq $assetName) {
|
||
Invoke-RestMethod -Method Delete -Uri "$apiBase/releases/assets/$($asset.id)" -Headers $headers | Out-Null
|
||
}
|
||
}
|
||
}
|
||
|
||
function Upload-Asset([string]$path) {
|
||
$name = Split-Path $path -Leaf
|
||
Remove-ExistingAsset $name
|
||
$uploadUrl = "$apiBase/releases/$($release.id)/assets?name=$([uri]::EscapeDataString($name))"
|
||
$responseFile = Join-Path $env:RUNNER_TEMP "gitea-upload-response.json"
|
||
$curl = Join-Path $env:SystemRoot 'System32\curl.exe'
|
||
$status = & $curl --silent --show-error --location `
|
||
--header "Authorization: token $token" `
|
||
--form "attachment=@$path;filename=$name" `
|
||
--write-out '%{http_code}' `
|
||
--output $responseFile `
|
||
$uploadUrl
|
||
if ($status -ne '200' -and $status -ne '201') {
|
||
Write-Error "Upload release asset failed, HTTP ${status}: $name"
|
||
if (Test-Path $responseFile) { Get-Content $responseFile }
|
||
exit 1
|
||
}
|
||
Write-Host "Uploaded release asset: $name"
|
||
}
|
||
|
||
Upload-Asset $zipPath
|
||
Upload-Asset $shaPath
|
||
Write-Host "Release assets uploaded to $serverUrl/$repo/releases/tag/$tagName"
|