Compare commits

...

11 Commits

Author SHA1 Message Date
luochen570
081a04de90 ci: rerun Windows release with token
All checks were successful
Build Windows Release / Build Windows x64 Release (push) Successful in 1m26s
2026-05-30 21:40:03 +08:00
luochen570
e6405ad09d ci: fix PowerShell status interpolation
Some checks failed
Build Windows Release / Build Windows x64 Release (push) Failing after 24s
2026-05-30 21:31:06 +08:00
luochen570
2968dd7caa ci: avoid cross-step env in Windows workflow
Some checks failed
Build Windows Release / Build Windows x64 Release (push) Failing after 25s
2026-05-30 21:29:49 +08:00
luochen570
aa18669312 ci: package from fixed runner temp path
Some checks failed
Build Windows Release / Build Windows x64 Release (push) Failing after 25s
2026-05-30 21:27:23 +08:00
luochen570
cffa806267 ci: use fixed source path across runner steps
Some checks failed
Build Windows Release / Build Windows x64 Release (push) Failing after 24s
2026-05-30 21:16:55 +08:00
luochen570
37ee80e3e7 ci: avoid non-ascii PowerShell literals
Some checks failed
Build Windows Release / Build Windows x64 Release (push) Failing after 15s
2026-05-30 21:02:23 +08:00
luochen570
ce5918e4c0 ci: make Windows workflow PowerShell 5 compatible
Some checks failed
Build Windows Release / Build Windows x64 Release (push) Failing after -3s
2026-05-30 21:01:21 +08:00
luochen570
a2c9097496 ci: build Windows package without JS actions
Some checks failed
Build Windows Release / Build Windows x64 Release (push) Failing after -3s
2026-05-30 20:59:11 +08:00
luochen570
1ff605bc91 ci: target registered Windows runner label
Some checks failed
Build Windows Release / Build Windows x64 Release (push) Failing after 32s
2026-05-30 20:54:29 +08:00
luochen570
b0f8695a25 ci: build release on Windows runner
Some checks failed
Build Windows Release / Build Windows x64 Release (push) Has been cancelled
2026-05-30 20:50:34 +08:00
luochen570
83ac7ada50 ci: use Linux runner for Windows release
Some checks failed
Build Windows Release / Cross build Windows x86_64 Release (push) Has been cancelled
2026-05-30 20:44:24 +08:00

View File

@@ -14,48 +14,84 @@ permissions:
jobs: jobs:
build-windows-release: build-windows-release:
name: Build Windows x64 Release name: Build Windows x64 Release
runs-on: # Windows runner 已注册标签windows-latest、windows-2022、self-hosted均为 host 模式。
- windows runs-on: windows-2022
env: env:
BUILD_TYPE: Release BUILD_TYPE: Release
QT_VERSION: '6.7.3' MSYS2_ROOT: C:\msys64
QT_ARCH: win64_msvc2019_64 MSYSTEM: UCRT64
QT_MODULES: qtimageformats CHERE_INVOKING: 1
DIST_DIR: dist-windows\chengnan PACKAGE_BASENAME: chengnan-windows-x64
PACKAGE_NAME: chengnan-windows-x64
steps: steps:
- name: Checkout - name: Prepare source
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
shell: powershell shell: powershell
run: | run: |
$ErrorActionPreference = 'Stop' $ErrorActionPreference = 'Stop'
python -m pip install --upgrade pip $work = Join-Path $env:RUNNER_TEMP 'chengnan-src'
python -m pip install aqtinstall $srcFixed = Join-Path $env:RUNNER_TEMP 'chengnan-work'
python -m aqt install-qt windows desktop $env:QT_VERSION win64_msvc2019_64 --outputdir C:\Qt --modules $env:QT_MODULES $zip = Join-Path $env:RUNNER_TEMP 'chengnan-src.zip'
$qtPrefix = "C:\Qt\$env:QT_VERSION\msvc2019_64" if (Test-Path $work) { Remove-Item -Recurse -Force $work }
if (-not (Test-Path "$qtPrefix\bin\windeployqt.exe")) { if (Test-Path $srcFixed) { Remove-Item -Recurse -Force $srcFixed }
throw "Qt 安装不完整,找不到 windeployqt$qtPrefix\bin\windeployqt.exe" 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 - name: Configure and build
shell: powershell shell: powershell
run: | run: |
$ErrorActionPreference = 'Stop' $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 - name: Package
shell: powershell shell: powershell
@@ -63,67 +99,104 @@ jobs:
$ErrorActionPreference = 'Stop' $ErrorActionPreference = 'Stop'
$shortSha = $env:GITHUB_SHA.Substring(0, 10) $shortSha = $env:GITHUB_SHA.Substring(0, 10)
$version = if ($env:GITHUB_REF_TYPE -eq 'tag') { $env:GITHUB_REF_NAME } else { "build-$shortSha" } $version = if ($env:GITHUB_REF_TYPE -eq 'tag') { $env:GITHUB_REF_NAME } else { "build-$shortSha" }
$zipName = "chengnan-windows-x64-$version.zip" $zipName = "$env:PACKAGE_BASENAME-$version.zip"
if (-not (Test-Path $env:DIST_DIR)) { $sourceDir = Join-Path $env:RUNNER_TEMP 'chengnan-work'
throw "发布目录不存在:$env:DIST_DIR" $dist = Join-Path $sourceDir 'dist-windows\chengnan'
} if (-not (Test-Path "$dist\chengnan.exe")) { throw "Missing build output: $dist\chengnan.exe" }
Compress-Archive -Path "$env:DIST_DIR\*" -DestinationPath $zipName -Force Push-Location (Split-Path $dist -Parent)
$hash = (Get-FileHash $zipName -Algorithm SHA256).Hash.ToLowerInvariant() if (Test-Path (Join-Path $sourceDir $zipName)) { Remove-Item -Force (Join-Path $sourceDir $zipName) }
"$hash $zipName" | Out-File -FilePath "$zipName.sha256" -Encoding ascii Compress-Archive -Path 'chengnan\*' -DestinationPath (Join-Path $sourceDir $zipName) -Force
"PACKAGE_ZIP=$zipName" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8 Pop-Location
"RELEASE_TAG=$version" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8 $zipPath = Join-Path $sourceDir $zipName
Write-Host "Package: $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" Write-Host "SHA256: $hash"
- name: Upload build artifact - name: Verify package
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' }}
shell: powershell shell: powershell
env:
GITEA_TOKEN: ${{ secrets.RELEASE_TOKEN || secrets.GITHUB_TOKEN }}
run: | run: |
$ErrorActionPreference = 'Stop' $ErrorActionPreference = 'Stop'
if ([string]::IsNullOrWhiteSpace($env:GITEA_TOKEN)) { $shortSha = $env:GITHUB_SHA.Substring(0, 10)
throw '缺少发布 Token。请在仓库 Secrets 中配置 RELEASE_TOKEN或确保 Gitea 提供 GITHUB_TOKEN。' $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 $repo = $env:GITHUB_REPOSITORY
$tag = $env:RELEASE_TAG $apiBase = "$serverUrl/api/v1/repos/$repo"
$zip = $env:PACKAGE_ZIP $tagName = $version
$headers = @{ $releaseName = if ($env:GITHUB_REF_TYPE -eq 'tag') { $env:GITHUB_REF_NAME } else { "chengnan $shortSha" }
Authorization = "token $env:GITEA_TOKEN" $isPrerelease = if ($env:GITHUB_REF_TYPE -eq 'tag') { $false } else { $true }
Accept = 'application/json' $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 { 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 { } catch {
$body = @{ $release = Invoke-RestMethod -Method Get -Uri "$apiBase/releases/tags/$tagName" -Headers $headers
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
} }
foreach ($asset in @($zip, "$zip.sha256")) { function Remove-ExistingAsset([string]$assetName) {
$existing = @($release.assets | Where-Object { $_.name -eq $asset }) $assets = Invoke-RestMethod -Method Get -Uri "$apiBase/releases/$($release.id)/assets" -Headers $headers
foreach ($item in $existing) { foreach ($asset in @($assets)) {
Invoke-RestMethod -Method Delete -Uri "$api/repos/$repo/releases/assets/$($item.id)" -Headers $headers | Out-Null 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"