chore(release): bump version to 1.3.1-rc.3 #26
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: release | |
| # 推送 v* tag 自动触发:构建三种形态 → 各自打包完整发行包 → 创建 GitHub Release 并上传。 | |
| # 也可在 Actions 页手动触发(仅产出构建工件,不发布 Release)。 | |
| # | |
| # 三种构建版本(均自带 catalog/ configs/ assets/ 数据链): | |
| # 1) with-runtime —— 集成 .NET 运行环境版:自包含、多文件,目标机免装 .NET。 | |
| # 2) framework —— 纯 App 版:依赖框架,体积最小,需目标机安装 .NET 10 桌面运行时。 | |
| # 3) singlefile —— 单文件版:自包含、单个 OwOWinDeployer.exe,目标机免装 .NET。 | |
| on: | |
| push: | |
| tags: ['v*'] | |
| workflow_dispatch: | |
| permissions: | |
| contents: write | |
| jobs: | |
| build: | |
| runs-on: windows-latest | |
| env: | |
| # 可选 Authenticode 代码签名:在仓库 Settings → Secrets 配置后自动启用(彻底解决 SmartScreen/Defender 拦截)。 | |
| SIGN_PFX_BASE64: ${{ secrets.SIGN_PFX_BASE64 }} | |
| SIGN_PFX_PASSWORD: ${{ secrets.SIGN_PFX_PASSWORD }} | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: '10.0.x' | |
| - name: Publish all variants (集成运行环境 / 纯App / 单文件) | |
| shell: pwsh | |
| run: | | |
| $variants = @( | |
| @{ Key = 'with-runtime'; Sc = 'true'; Single = 'false' }, | |
| @{ Key = 'framework'; Sc = 'false'; Single = 'false' }, | |
| @{ Key = 'singlefile'; Sc = 'true'; Single = 'true' } | |
| ) | |
| foreach ($v in $variants) { | |
| $pubArgs = @('-c', 'Release', '-r', 'win-x64', '--self-contained', $v.Sc, | |
| "-p:PublishSingleFile=$($v.Single)", '-p:DebugType=none', '--nologo') | |
| if ($v.Single -eq 'true') { $pubArgs += '-p:IncludeNativeLibrariesForSelfExtract=true' } | |
| Write-Host "== publish [$($v.Key)] GUI ==" | |
| dotnet publish src/OwOWinDeployer.App/OwOWinDeployer.App.csproj @pubArgs -o "dist/$($v.Key)/app" | |
| if ($LASTEXITCODE -ne 0) { throw "GUI publish failed: $($v.Key)" } | |
| Write-Host "== publish [$($v.Key)] CLI ==" | |
| dotnet publish src/OwOWinDeployer.Cli/OwOWinDeployer.Cli.csproj @pubArgs -o "dist/$($v.Key)/cli" | |
| if ($LASTEXITCODE -ne 0) { throw "CLI publish failed: $($v.Key)" } | |
| } | |
| - name: Code sign binaries (only runs if a signing certificate secret is configured) | |
| if: ${{ env.SIGN_PFX_BASE64 != '' }} | |
| shell: pwsh | |
| run: | | |
| $pfx = Join-Path $env:RUNNER_TEMP 'sign.pfx' | |
| [IO.File]::WriteAllBytes($pfx, [Convert]::FromBase64String($env:SIGN_PFX_BASE64)) | |
| $signtool = Get-ChildItem 'C:/Program Files (x86)/Windows Kits/10/bin' -Recurse -Filter signtool.exe -ErrorAction SilentlyContinue | | |
| Where-Object { $_.FullName -like '*x64*' } | Sort-Object FullName | Select-Object -Last 1 | |
| if (-not $signtool) { throw 'signtool.exe not found on runner' } | |
| # Sign every variant's GUI + CLI executable before packaging. | |
| $files = Get-ChildItem dist -Recurse -File | | |
| Where-Object { $_.Name -in @('OwOWinDeployer.exe', 'owowindeployer.exe') } | | |
| Select-Object -ExpandProperty FullName | |
| & $signtool.FullName sign /f $pfx /p $env:SIGN_PFX_PASSWORD /fd SHA256 ` | |
| /tr http://timestamp.digicert.com /td SHA256 @files | |
| Remove-Item $pfx -Force | |
| - name: Assemble release packages (one ZIP per variant) | |
| shell: pwsh | |
| run: | | |
| $tag = '${{ github.ref_name }}' | |
| if ([string]::IsNullOrWhiteSpace($tag)) { $tag = 'dev' } | |
| $variants = @( | |
| @{ Key = 'with-runtime'; Single = $false }, | |
| @{ Key = 'framework'; Single = $false }, | |
| @{ Key = 'singlefile'; Single = $true } | |
| ) | |
| foreach ($v in $variants) { | |
| $appOut = "dist/$($v.Key)/app" | |
| $cliOut = "dist/$($v.Key)/cli" | |
| $name = "OwO-Win-Deployer-$tag-win-x64-$($v.Key)" | |
| $stage = "dist/$name" | |
| New-Item -ItemType Directory -Force -Path "$stage/assets" | Out-Null | |
| if ($v.Single) { | |
| # 单文件:仅一个 exe(运行库已并入)+ CLI 单文件 | |
| Copy-Item "$appOut/OwOWinDeployer.exe" "$stage/OwOWinDeployer.exe" -Force | |
| Copy-Item "$cliOut/owowindeployer.exe" "$stage/owowindeployer-cli.exe" -Force | |
| # CLI 别名:单文件自包含,副本可独立运行(保留已签名字节)。 | |
| Copy-Item "$cliOut/owowindeployer.exe" "$stage/owodeploy.exe" -Force | |
| } else { | |
| # 多文件:GUI 全量输出放根目录;CLI 放 cli/ 子目录(两者运行库 DLL 集不同,分目录避免冲突) | |
| Copy-Item "$appOut/*" "$stage/" -Recurse -Force | |
| New-Item -ItemType Directory -Force -Path "$stage/cli" | Out-Null | |
| Copy-Item "$cliOut/*" "$stage/cli/" -Recurse -Force | |
| # CLI 别名:apphost 副本,与 owowindeployer.dll 同目录即可运行。 | |
| Copy-Item "$stage/cli/owowindeployer.exe" "$stage/cli/owodeploy.exe" -Force | |
| } | |
| # 运行所需数据放在 exe 同级(程序向上查找 catalog/,再据此定位 repoRoot/assets) | |
| Copy-Item catalog "$stage/catalog" -Recurse -Force | |
| Copy-Item assets/icons "$stage/assets/icons" -Recurse -Force | |
| Copy-Item configs "$stage/configs" -Recurse -Force | |
| Copy-Item tools "$stage/tools" -Recurse -Force # bundled smartctl.exe (USB SMART) | |
| Copy-Item LICENSE "$stage/LICENSE" -Force | |
| Copy-Item README.md "$stage/README.md" -Force | |
| Compress-Archive -Path "$stage" -DestinationPath "dist/$name.zip" -Force | |
| Write-Host "packaged: dist/$name.zip" | |
| } | |
| # 供裸机引导 bootstrap.ps1 直链下载的单文件 GUI | |
| Copy-Item "dist/singlefile/app/OwOWinDeployer.exe" "dist/OwOWinDeployer.exe" -Force | |
| - name: Upload build artifacts | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: OwO-Win-Deployer-win-x64 | |
| path: dist/*.zip | |
| # Build the Release body from CHANGELOG.md's section for this tag (新增/调整/删除) + the static download | |
| # table (.github/release-body.md). Falls back to the table alone if the tag has no changelog section. | |
| - name: Compose release notes from CHANGELOG | |
| if: startsWith(github.ref, 'refs/tags/') | |
| shell: pwsh | |
| run: | | |
| $tag = '${{ github.ref_name }}' | |
| $section = '' | |
| if (Test-Path docs/CHANGELOG.md) { | |
| $changelog = Get-Content docs/CHANGELOG.md -Raw | |
| $pattern = "(?ms)^##\s+" + [regex]::Escape($tag) + "\b.*?(?=^##\s+|\z)" | |
| $m = [regex]::Match($changelog, $pattern) | |
| if ($m.Success) { $section = $m.Value.Trim() } | |
| } | |
| if (-not $section) { Write-Host "::warning::docs/CHANGELOG.md has no section for $tag — release notes will omit the changelog." } | |
| $table = if (Test-Path .github/release-body.md) { (Get-Content .github/release-body.md -Raw).Trim() } else { '' } | |
| $parts = @($section, $table) | Where-Object { $_ } | |
| $notes = $parts -join "`n`n---`n`n" | |
| Set-Content -Path release-notes.md -Value $notes -Encoding utf8 | |
| Write-Host "=== release-notes.md ==="; Get-Content release-notes.md | |
| - name: Publish GitHub Release | |
| if: startsWith(github.ref, 'refs/tags/') | |
| uses: softprops/action-gh-release@v3 | |
| with: | |
| name: OwO! Win Deployer ${{ github.ref_name }} | |
| generate_release_notes: true | |
| body_path: release-notes.md | |
| # SemVer convention: a hyphen in the tag marks a pre-release identifier (e.g. v1.3.1-rc.1) → | |
| # publish as a GitHub Pre-release (not marked "Latest"); clean vX.Y.Z tags are full releases. | |
| prerelease: ${{ contains(github.ref_name, '-') }} | |
| files: | | |
| dist/*.zip | |
| dist/OwOWinDeployer.exe |