Compare commits
11 Commits
56964d71fc
...
build-081a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
081a04de90 | ||
|
|
e6405ad09d | ||
|
|
2968dd7caa | ||
|
|
aa18669312 | ||
|
|
cffa806267 | ||
|
|
37ee80e3e7 | ||
|
|
ce5918e4c0 | ||
|
|
a2c9097496 | ||
|
|
1ff605bc91 | ||
|
|
b0f8695a25 | ||
|
|
83ac7ada50 |
@@ -14,48 +14,84 @@ permissions:
|
||||
jobs:
|
||||
build-windows-release:
|
||||
name: Build Windows x64 Release
|
||||
runs-on:
|
||||
- windows
|
||||
# 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_msvc2019_64
|
||||
QT_MODULES: qtimageformats
|
||||
DIST_DIR: dist-windows\chengnan
|
||||
MSYS2_ROOT: C:\msys64
|
||||
MSYSTEM: UCRT64
|
||||
CHERE_INVOKING: 1
|
||||
PACKAGE_BASENAME: chengnan-windows-x64
|
||||
PACKAGE_NAME: chengnan-windows-x64
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup MSVC developer command prompt
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
with:
|
||||
arch: x64
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
- name: Install Qt with aqtinstall
|
||||
- name: Prepare source
|
||||
shell: powershell
|
||||
run: |
|
||||
$ErrorActionPreference = 'Stop'
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install aqtinstall
|
||||
python -m aqt install-qt windows desktop $env:QT_VERSION win64_msvc2019_64 --outputdir C:\Qt --modules $env:QT_MODULES
|
||||
$qtPrefix = "C:\Qt\$env:QT_VERSION\msvc2019_64"
|
||||
if (-not (Test-Path "$qtPrefix\bin\windeployqt.exe")) {
|
||||
throw "Qt 安装不完整,找不到 windeployqt:$qtPrefix\bin\windeployqt.exe"
|
||||
$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 MSYS2 and build dependencies
|
||||
shell: powershell
|
||||
run: |
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$msysRoot = $env:MSYS2_ROOT
|
||||
if (-not (Test-Path "$msysRoot\usr\bin\bash.exe")) {
|
||||
$installer = Join-Path $env:RUNNER_TEMP 'msys2-installer.exe'
|
||||
$installerUrl = 'https://github.com/msys2/msys2-installer/releases/latest/download/msys2-x86_64-latest.exe'
|
||||
Write-Host "Downloading MSYS2 installer from $installerUrl"
|
||||
Invoke-WebRequest -Uri $installerUrl -OutFile $installer
|
||||
& $installer in --confirm-command --accept-messages --root $msysRoot
|
||||
}
|
||||
"QT_PREFIX=$qtPrefix" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
||||
|
||||
$bash = "$msysRoot\usr\bin\bash.exe"
|
||||
& $bash -lc "pacman --noconfirm -Syuu"
|
||||
if ($LASTEXITCODE -ne 0) { Write-Host 'First pacman system update returned non-zero; continuing with second update.' }
|
||||
& $bash -lc "pacman --noconfirm -Syuu"
|
||||
if ($LASTEXITCODE -ne 0) { throw "pacman system update failed, exit code: $LASTEXITCODE" }
|
||||
& $bash -lc "pacman --noconfirm -S --needed git zip unzip p7zip mingw-w64-ucrt-x86_64-toolchain mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-ninja mingw-w64-ucrt-x86_64-qt6-base mingw-w64-ucrt-x86_64-qt6-imageformats"
|
||||
if ($LASTEXITCODE -ne 0) { throw "pacman dependency installation failed, exit code: $LASTEXITCODE" }
|
||||
|
||||
- name: Configure and build
|
||||
shell: powershell
|
||||
run: |
|
||||
$ErrorActionPreference = 'Stop'
|
||||
powershell -ExecutionPolicy Bypass -File .\build-windows.ps1 -QtPrefix "$env:QT_PREFIX" -Config $env:BUILD_TYPE
|
||||
$bash = "$env:MSYS2_ROOT\usr\bin\bash.exe"
|
||||
$srcWin = Join-Path $env:RUNNER_TEMP 'chengnan-work'
|
||||
$src = $srcWin -replace '\\','/'
|
||||
$src = $src -replace '^([A-Za-z]):','/$1'
|
||||
$src = $src.ToLower()
|
||||
$script = @"
|
||||
set -euo pipefail
|
||||
cd '$src'
|
||||
export PATH=/ucrt64/bin:/usr/bin:`$PATH
|
||||
cmake -S . -B build-windows -G Ninja -DCMAKE_BUILD_TYPE=Release
|
||||
cmake --build build-windows --parallel `$(nproc)
|
||||
rm -rf dist-windows
|
||||
mkdir -p dist-windows/chengnan
|
||||
cp build-windows/chengnan.exe dist-windows/chengnan/
|
||||
/ucrt64/bin/windeployqt6.exe --release --no-translations dist-windows/chengnan/chengnan.exe || /ucrt64/bin/windeployqt.exe --release --no-translations dist-windows/chengnan/chengnan.exe
|
||||
printf '%s\n' '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 MSYS2 UCRT64 + Qt.' '- Do not copy chengnan.exe alone; keep DLLs and Qt plugin directories together.' > dist-windows/chengnan/README.txt
|
||||
"@
|
||||
& $bash -lc $script
|
||||
|
||||
- name: Package
|
||||
shell: powershell
|
||||
@@ -63,67 +99,104 @@ jobs:
|
||||
$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 = "chengnan-windows-x64-$version.zip"
|
||||
if (-not (Test-Path $env:DIST_DIR)) {
|
||||
throw "发布目录不存在:$env:DIST_DIR"
|
||||
}
|
||||
Compress-Archive -Path "$env:DIST_DIR\*" -DestinationPath $zipName -Force
|
||||
$hash = (Get-FileHash $zipName -Algorithm SHA256).Hash.ToLowerInvariant()
|
||||
"$hash $zipName" | Out-File -FilePath "$zipName.sha256" -Encoding ascii
|
||||
"PACKAGE_ZIP=$zipName" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
||||
"RELEASE_TAG=$version" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
||||
Write-Host "Package: $zipName"
|
||||
$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: Upload build artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: chengnan-windows-x64
|
||||
path: |
|
||||
${{ env.PACKAGE_ZIP }}
|
||||
${{ env.PACKAGE_ZIP }}.sha256
|
||||
|
||||
- name: Publish to Gitea Release
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
- name: Verify package
|
||||
shell: powershell
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.RELEASE_TOKEN || secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
$ErrorActionPreference = 'Stop'
|
||||
if ([string]::IsNullOrWhiteSpace($env:GITEA_TOKEN)) {
|
||||
throw '缺少发布 Token。请在仓库 Secrets 中配置 RELEASE_TOKEN,或确保 Gitea 提供 GITHUB_TOKEN。'
|
||||
}
|
||||
$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"
|
||||
|
||||
$api = $env:GITHUB_API_URL.TrimEnd('/')
|
||||
- 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
|
||||
$tag = $env:RELEASE_TAG
|
||||
$zip = $env:PACKAGE_ZIP
|
||||
$headers = @{
|
||||
Authorization = "token $env:GITEA_TOKEN"
|
||||
Accept = 'application/json'
|
||||
}
|
||||
$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 build from Gitea Actions.`n"
|
||||
draft = $false
|
||||
prerelease = $isPrerelease
|
||||
} | ConvertTo-Json -Depth 5
|
||||
|
||||
$releaseUrl = "$api/repos/$repo/releases/tags/$tag"
|
||||
try {
|
||||
$release = Invoke-RestMethod -Method Get -Uri $releaseUrl -Headers $headers
|
||||
$release = Invoke-RestMethod -Method Post -Uri "$apiBase/releases" -Headers $headers -ContentType 'application/json' -Body $releasePayload
|
||||
} catch {
|
||||
$body = @{
|
||||
tag_name = $tag
|
||||
target_commitish = $env:GITHUB_SHA
|
||||
name = "chengnan $tag"
|
||||
body = "Windows x64 Release 自动构建产物。`n`n提交:$env:GITHUB_SHA"
|
||||
draft = $false
|
||||
prerelease = ($env:GITHUB_REF_TYPE -ne 'tag')
|
||||
} | ConvertTo-Json -Depth 5
|
||||
$release = Invoke-RestMethod -Method Post -Uri "$api/repos/$repo/releases" -Headers $headers -ContentType 'application/json' -Body $body
|
||||
$release = Invoke-RestMethod -Method Get -Uri "$apiBase/releases/tags/$tagName" -Headers $headers
|
||||
}
|
||||
|
||||
foreach ($asset in @($zip, "$zip.sha256")) {
|
||||
$existing = @($release.assets | Where-Object { $_.name -eq $asset })
|
||||
foreach ($item in $existing) {
|
||||
Invoke-RestMethod -Method Delete -Uri "$api/repos/$repo/releases/assets/$($item.id)" -Headers $headers | Out-Null
|
||||
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
|
||||
}
|
||||
}
|
||||
$uploadUrl = "$api/repos/$repo/releases/$($release.id)/assets?name=$([uri]::EscapeDataString($asset))"
|
||||
Invoke-RestMethod -Method Post -Uri $uploadUrl -Headers $headers -ContentType 'multipart/form-data' -Form @{ attachment = Get-Item $asset } | Out-Null
|
||||
Write-Host "Uploaded release asset: $asset"
|
||||
}
|
||||
|
||||
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"
|
||||
|
||||
Reference in New Issue
Block a user