diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..252932b --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,345 @@ +# GitHub Actions Release Workflow for iiCourseWPF +# 触发方式: 推送标签 v* 或手动触发 +# 任务拆分: build → release → checksum + +name: Release iiCourseWPF + +on: + # 当推送版本标签时触发 (例如: v1.0.0) + push: + tags: + - 'v*' + # 允许手动触发 + workflow_dispatch: + inputs: + version: + description: '版本号 (例如: 1.8.0)' + required: true + default: '1.8.0' + prerelease: + description: '是否为预发布版本' + type: boolean + required: false + default: false + +env: + DOTNET_VERSION: '9.0.x' + SOLUTION_PATH: 'iiCourseWPF.sln' + MAIN_PROJECT: 'iiCourseWPF/iiCourseWPF.csproj' + +jobs: + # ========== Job 1: 构建 ========== + build: + runs-on: windows-latest + outputs: + version: ${{ steps.version.outputs.version }} + assembly_version: ${{ steps.version.outputs.assembly_version }} + + steps: + # 检出代码 + - name: 检出代码 + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + # 设置 .NET 9.0 + - name: 设置 .NET ${{ env.DOTNET_VERSION }} + uses: actions/setup-dotnet@v4 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + + # 提取版本号 + - name: 提取版本号 + id: version + shell: pwsh + run: | + if ('${{ github.event_name }}' -eq 'workflow_dispatch') { + $version = '${{ github.event.inputs.version }}' + } else { + $tag = '${{ github.ref_name }}' + $version = $tag -replace '^v', '' + } + $assemblyVersion = "$version.0" + echo "version=$version" >> $env:GITHUB_OUTPUT + echo "assembly_version=$assemblyVersion" >> $env:GITHUB_OUTPUT + Write-Host "版本: $version" + Write-Host "程序集版本: $assemblyVersion" + + # 还原 NuGet 包 + - name: 还原 NuGet 包 + run: dotnet restore ${{ env.SOLUTION_PATH }} + + # 更新项目版本号 + - name: 更新版本号 + shell: pwsh + run: | + $version = '${{ steps.version.outputs.version }}' + $assemblyVersion = '${{ steps.version.outputs.assembly_version }}' + + # 更新主项目 + $mainProject = '${{ env.MAIN_PROJECT }}' + [xml]$xml = Get-Content $mainProject + $xml.Project.PropertyGroup.Version = $version + $xml.Project.PropertyGroup.AssemblyVersion = $assemblyVersion + $xml.Project.PropertyGroup.FileVersion = $assemblyVersion + $xml.Save($mainProject) + + # 更新 Core 项目 + $coreProject = 'iiCourse.Core/iiCourse.Core.csproj' + [xml]$xml = Get-Content $coreProject + $xml.Project.PropertyGroup.Version = $version + $xml.Project.PropertyGroup.AssemblyVersion = $assemblyVersion + $xml.Project.PropertyGroup.FileVersion = $assemblyVersion + $xml.Save($coreProject) + + Write-Host "版本号已更新为: $version" + + # 构建项目 (Release 配置) + - name: 构建项目 + run: dotnet build ${{ env.SOLUTION_PATH }} --configuration Release --no-restore + + # 运行测试 (如果有测试项目) + - name: 运行测试 + run: dotnet test ${{ env.SOLUTION_PATH }} --configuration Release --no-build --verbosity normal + continue-on-error: true + + # 发布自包含应用 (x64) + - name: 发布应用 (x64 自包含) + run: | + dotnet publish ${{ env.MAIN_PROJECT }} ` + --configuration Release ` + --runtime win-x64 ` + --self-contained true ` + --output ./publish/x64 ` + -p:PublishSingleFile=true ` + -p:IncludeNativeLibrariesForSelfExtract=true + + # 发布框架依赖应用 (x64) + - name: 发布应用 (x64 框架依赖) + run: | + dotnet publish ${{ env.MAIN_PROJECT }} ` + --configuration Release ` + --runtime win-x64 ` + --self-contained false ` + --output ./publish/x64-framework ` + -p:PublishSingleFile=true + + # 发布自包含应用 (x86) + - name: 发布应用 (x86 自包含) + run: | + dotnet publish ${{ env.MAIN_PROJECT }} ` + --configuration Release ` + --runtime win-x86 ` + --self-contained true ` + --output ./publish/x86 ` + -p:PublishSingleFile=true ` + -p:IncludeNativeLibrariesForSelfExtract=true + + # 发布框架依赖应用 (x86) + - name: 发布应用 (x86 框架依赖) + run: | + dotnet publish ${{ env.MAIN_PROJECT }} ` + --configuration Release ` + --runtime win-x86 ` + --self-contained false ` + --output ./publish/x86-framework ` + -p:PublishSingleFile=true + + # 发布自包含应用 (ARM64) + - name: 发布应用 (ARM64 自包含) + run: | + dotnet publish ${{ env.MAIN_PROJECT }} ` + --configuration Release ` + --runtime win-arm64 ` + --self-contained true ` + --output ./publish/arm64 ` + -p:PublishSingleFile=true ` + -p:IncludeNativeLibrariesForSelfExtract=true + + # 发布框架依赖应用 (ARM64) + - name: 发布应用 (ARM64 框架依赖) + run: | + dotnet publish ${{ env.MAIN_PROJECT }} ` + --configuration Release ` + --runtime win-arm64 ` + --self-contained false ` + --output ./publish/arm64-framework ` + -p:PublishSingleFile=true + + # 发布纯框架依赖应用 + - name: 发布应用 (纯框架依赖) + run: | + dotnet publish ${{ env.MAIN_PROJECT }} ` + --configuration Release ` + --self-contained false ` + --output ./publish/dotnet9-required + + # 上传构建产物 + - name: 上传构建产物 + uses: actions/upload-artifact@v4 + with: + name: build-artifacts + path: ./publish/ + retention-days: 1 + + # ========== Job 2: 打包和发布 ========== + release: + needs: build + runs-on: windows-latest + + steps: + # 下载构建产物 + - name: 下载构建产物 + uses: actions/download-artifact@v4 + with: + name: build-artifacts + path: ./publish/ + + # 获取版本号 + - name: 获取版本号 + id: version + shell: pwsh + run: | + if ('${{ github.event_name }}' -eq 'workflow_dispatch') { + $version = '${{ github.event.inputs.version }}' + } else { + $tag = '${{ github.ref_name }}' + $version = $tag -replace '^v', '' + } + echo "version=$version" >> $env:GITHUB_OUTPUT + Write-Host "版本: $version" + + # 打包所有版本 + - name: 打包所有版本 + shell: pwsh + run: | + $version = '${{ steps.version.outputs.version }}' + Compress-Archive -Path ./publish/x64/* -DestinationPath "./iiCourseWPF-v$version-win-x64-self-contained.zip" -Force + Compress-Archive -Path ./publish/x64-framework/* -DestinationPath "./iiCourseWPF-v$version-win-x64-framework.zip" -Force + Compress-Archive -Path ./publish/x86/* -DestinationPath "./iiCourseWPF-v$version-win-x86-self-contained.zip" -Force + Compress-Archive -Path ./publish/x86-framework/* -DestinationPath "./iiCourseWPF-v$version-win-x86-framework.zip" -Force + Compress-Archive -Path ./publish/arm64/* -DestinationPath "./iiCourseWPF-v$version-win-arm64-self-contained.zip" -Force + Compress-Archive -Path ./publish/arm64-framework/* -DestinationPath "./iiCourseWPF-v$version-win-arm64-framework.zip" -Force + Compress-Archive -Path ./publish/dotnet9-required/* -DestinationPath "./iiCourseWPF-v$version-dotnet9-required.zip" -Force + Write-Host "打包完成" + + # 上传发布产物 + - name: 上传发布产物 + uses: actions/upload-artifact@v4 + with: + name: release-artifacts + path: ./iiCourseWPF-v*.zip + retention-days: 30 + + # ========== Job 3: 创建 GitHub Release ========== + create-release: + needs: release + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + # 下载发布产物 + - name: 下载发布产物 + uses: actions/download-artifact@v4 + with: + name: release-artifacts + path: ./artifacts + + # 获取版本号 + - name: 获取版本号 + id: version + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + echo "version=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT + else + version=$(echo "${{ github.ref_name }}" | sed 's/^v//') + echo "version=$version" >> $GITHUB_OUTPUT + fi + + # 创建 GitHub Release + - name: 创建 GitHub Release + uses: softprops/action-gh-release@v1 + with: + tag_name: ${{ github.event_name == 'workflow_dispatch' && format('v{0}', github.event.inputs.version) || github.ref_name }} + name: ${{ github.event_name == 'workflow_dispatch' && format('iiCourseWPF v{0}', github.event.inputs.version) || format('iiCourseWPF {0}', github.ref_name) }} + body: | + ## iiCourseWPF ${{ steps.version.outputs.version }} + + ### 下载地址 + + **Windows (需要 Windows 10 1809+ 或 Windows 11)** + + 自包含版本(推荐,无需安装 .NET 9 运行时) + - [64位(常用)](https://github.com/${{ github.repository }}/releases/download/${{ github.event_name == 'workflow_dispatch' && format('v{0}', github.event.inputs.version) || github.ref_name }}/iiCourseWPF-v${{ steps.version.outputs.version }}-win-x64-self-contained.zip) | [32位](https://github.com/${{ github.repository }}/releases/download/${{ github.event_name == 'workflow_dispatch' && format('v{0}', github.event.inputs.version) || github.ref_name }}/iiCourseWPF-v${{ steps.version.outputs.version }}-win-x86-self-contained.zip) | [ARM64](https://github.com/${{ github.repository }}/releases/download/${{ github.event_name == 'workflow_dispatch' && format('v{0}', github.event.inputs.version) || github.ref_name }}/iiCourseWPF-v${{ steps.version.outputs.version }}-win-arm64-self-contained.zip) + + 框架依赖版本(体积较小,需先安装 [.NET 9 运行时](https://dotnet.microsoft.com/download/dotnet/9.0)) + - [64位](https://github.com/${{ github.repository }}/releases/download/${{ github.event_name == 'workflow_dispatch' && format('v{0}', github.event.inputs.version) || github.ref_name }}/iiCourseWPF-v${{ steps.version.outputs.version }}-win-x64-framework.zip) | [32位](https://github.com/${{ github.repository }}/releases/download/${{ github.event_name == 'workflow_dispatch' && format('v{0}', github.event.inputs.version) || github.ref_name }}/iiCourseWPF-v${{ steps.version.outputs.version }}-win-x86-framework.zip) | [ARM64](https://github.com/${{ github.repository }}/releases/download/${{ github.event_name == 'workflow_dispatch' && format('v{0}', github.event.inputs.version) || github.ref_name }}/iiCourseWPF-v${{ steps.version.outputs.version }}-win-arm64-framework.zip) + + 纯框架依赖版本(体积最小 ~200KB,需先安装 [.NET 9 运行时](https://dotnet.microsoft.com/download/dotnet/9.0)) + - [下载](https://github.com/${{ github.repository }}/releases/download/${{ github.event_name == 'workflow_dispatch' && format('v{0}', github.event.inputs.version) || github.ref_name }}/iiCourseWPF-v${{ steps.version.outputs.version }}-dotnet9-required.zip) + + ### 如何选择版本? + + | 版本类型 | 文件大小 | 是否需要 .NET 9 | 适用场景 | + |---------|---------|----------------|---------| + | 自包含 64位 | ~50MB | ❌ 不需要 | **大多数用户推荐**,64位 Windows | + | 自包含 32位 | ~45MB | ❌ 不需要 | 32位 Windows 系统 | + | 自包含 ARM64 | ~45MB | ❌ 不需要 | Surface Pro X、Copilot+ PC 等 ARM 设备 | + | 框架依赖 64位 | ~5MB | ✅ 需要 | 已安装 .NET 9 的 64位系统 | + | 框架依赖 32位 | ~4MB | ✅ 需要 | 已安装 .NET 9 的 32位系统 | + | 框架依赖 ARM64 | ~4MB | ✅ 需要 | 已安装 .NET 9 的 ARM 设备 | + | 纯框架依赖 | ~200KB | ✅ 必须 | 开发者或磁盘空间极紧张 | + + ### 快速开始 + + 1. **下载对应版本**(不确定就选「自包含 64位」) + 2. **解压**到任意文件夹 + 3. **运行** `iiCourseWPF.exe` + + ### 校验 + + 文件 SHA256 校验和可在发布页面查看,或下载 [checksums.txt](https://github.com/${{ github.repository }}/releases/download/${{ github.event_name == 'workflow_dispatch' && format('v{0}', github.event.inputs.version) || github.ref_name }}/checksums.txt)。 + + --- + **完整更新日志**: 参见 [CHANGELOG.md](./docs/changelog.md) + files: ./artifacts/*.zip + prerelease: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.prerelease || false }} + generate_release_notes: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + # ========== Job 4: 生成校验和 ========== + checksum: + needs: create-release + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + # 检出代码 + - name: 检出代码 + uses: actions/checkout@v4 + + # 下载发布产物 + - name: 下载发布产物 + uses: actions/download-artifact@v4 + with: + name: release-artifacts + path: ./artifacts + + # 生成校验和文件 + - name: 生成 SHA256 校验和 + run: | + cd ./artifacts + sha256sum *.zip > checksums.txt + cat checksums.txt + + # 上传校验和到 Release + - name: 上传校验和 + uses: softprops/action-gh-release@v1 + with: + tag_name: ${{ github.event_name == 'workflow_dispatch' && format('v{0}', github.event.inputs.version) || github.ref_name }} + files: ./artifacts/checksums.txt + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}