chore: 发布v0.5.3版本,同时测试release workflow能不能正常工作 #9
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 Build | |
| on: | |
| push: | |
| tags: | |
| - 'v*.*.*' # 当推送 v1.0.0 格式的标签时触发 | |
| workflow_dispatch: # 允许手动触发 | |
| permissions: | |
| contents: write | |
| actions: read | |
| env: | |
| CARGO_TERM_COLOR: always | |
| jobs: | |
| build: | |
| name: Build Release | |
| runs-on: windows-latest | |
| outputs: | |
| version: ${{ steps.get_version.outputs.VERSION }} | |
| release_title: ${{ steps.get_version.outputs.RELEASE_TITLE }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| toolchain: stable | |
| targets: x86_64-pc-windows-msvc,aarch64-pc-windows-msvc | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: latest | |
| - name: Install dependencies | |
| run: bun install | |
| - name: Copy i18n locales to src-tauri | |
| shell: pwsh | |
| run: | | |
| $srcLocalesDir = "src\i18n\locales" | |
| $destDir = "src-tauri\locales" | |
| if (-not (Test-Path $destDir)) { | |
| New-Item -Path $destDir -ItemType Directory -Force | Out-Null | |
| } | |
| Copy-Item -Path "$srcLocalesDir\*" -Destination $destDir -Force | |
| Write-Host "✓ i18n locales files copied to src-tauri/locales/" | |
| - name: Get version from tag | |
| id: get_version | |
| shell: pwsh | |
| run: | | |
| $tag = $env:GITHUB_REF -replace 'refs/tags/v', '' | |
| if ([string]::IsNullOrEmpty($tag)) { | |
| $tag = "0.0.0" | |
| } | |
| # 生成 yymmdd 格式的日期 | |
| $date = Get-Date -Format "yyMMdd" | |
| $releaseTitle = "$date-v$tag" | |
| echo "VERSION=$tag" >> $env:GITHUB_OUTPUT | |
| echo "RELEASE_TITLE=$releaseTitle" >> $env:GITHUB_OUTPUT | |
| echo "Version: $tag" | |
| echo "Release Title: $releaseTitle" | |
| - name: Build all variants | |
| shell: pwsh | |
| run: | | |
| cd xtask | |
| # 构建所有架构和 AI 变体 | |
| cargo run --bin xtask build-all --arch all --ai both | |
| cd .. | |
| - name: List build artifacts | |
| shell: pwsh | |
| run: | | |
| echo "=== Build artifacts ===" | |
| echo "当前目录: $(Get-Location)" | |
| # 在根目录查找构建产物(不递归,因为 xtask 会将文件移动到根目录) | |
| $files = Get-ChildItem -Path . -File | Where-Object { $_.Extension -in '.exe', '.msi', '.zip' } | |
| if ($files.Count -eq 0) { | |
| echo "❌ 错误:没有找到任何构建产物!" | |
| echo "根目录下的所有文件:" | |
| Get-ChildItem -Path . -File | Select-Object -First 30 | ForEach-Object { | |
| echo " - $($_.Name) ($($_.Extension))" | |
| } | |
| exit 1 | |
| } | |
| echo "找到 $($files.Count) 个构建产物:" | |
| $files | ForEach-Object { | |
| $sizeMB = [math]::Round($_.Length / 1MB, 2) | |
| echo " ✅ $($_.Name) ($sizeMB MB)" | |
| } | |
| - name: Generate Release Notes | |
| id: release_notes | |
| shell: pwsh | |
| run: | | |
| $version = "${{ steps.get_version.outputs.VERSION }}" | |
| $tag = "v$version" | |
| $repoPath = "${{ github.repository }}" | |
| # 获取上一个标签 | |
| $previousTag = git describe --tags --abbrev=0 "$tag^" 2>$null | |
| if ([string]::IsNullOrEmpty($previousTag)) { | |
| $previousTag = git rev-list --max-parents=0 HEAD | |
| } | |
| # 生成格式化的变更日志 | |
| $commits = (git log "$previousTag..$tag" --pretty=format:"* %s (`%h`)" --no-merges 2>$null) -join "`n" | |
| if ([string]::IsNullOrEmpty($commits)) { | |
| $commits = (git log -10 --pretty=format:"* %s (`%h`)" --no-merges) -join "`n" | |
| } | |
| # 获取贡献者列表 | |
| $contributors = (git log "$previousTag..$tag" --pretty=format:"%an" --no-merges 2>$null | Sort-Object -Unique) | |
| if ($contributors.Count -eq 0) { | |
| $contributors = (git log -10 --pretty=format:"%an" --no-merges | Sort-Object -Unique) | |
| } | |
| $contributorsList = ($contributors | ForEach-Object { "* @$_" }) -join "`n" | |
| # 构建精简后的版本说明 | |
| $versionGuide = @" | |
| ## 📦 版本说明 | |
| - **安装版 (`.exe`/`.msi`)**: 提供传统的安装体验。 | |
| - **便携版 (`.zip`)**: 无需安装,解压即用,适合移动或绿色版爱好者。 | |
| > **完整版**包含 AI 智能搜索功能,而 **精简版 (lite)** 不含 AI 功能,体积更小。 | |
| --- | |
| ### 🤖 关于 AI 功能 | |
| > **重要提示**:AI 智能搜索功能需要单独下载模型权重文件才能使用。 | |
| **模型下载地址**: | |
| - GitHub: https://github.com/$repoPath/releases/tag/model | |
| - Gitee: https://gitee.com/$repoPath/releases/tag/model | |
| - GitCode: https://gitcode.com/$repoPath/releases/model | |
| 请根据模型发布页中的说明进行配置。 | |
| "@ | |
| # 构建最终的 Release Notes | |
| $changelogUrl = "https://github.com/$repoPath/compare/$previousTag...$tag" | |
| $releaseNotes = @" | |
| ## What's Changed | |
| $commits | |
| ## Contributors | |
| $contributorsList | |
| **Full Changelog**: $changelogUrl | |
| $versionGuide | |
| "@ | |
| # 输出到文件 | |
| $releaseNotes | Out-File -FilePath "release_notes.txt" -Encoding UTF8 | |
| echo "RELEASE_NOTES_FILE=release_notes.txt" >> $env:GITHUB_OUTPUT | |
| echo "Generated release notes" | |
| - name: Upload build artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: release-assets | |
| path: | | |
| *.exe | |
| *.msi | |
| *.zip | |
| release_notes.txt | |
| if-no-files-found: error | |
| retention-days: 7 | |
| # ======================================================= | |
| # 独立的 GitHub Release Job | |
| # ======================================================= | |
| release-github: | |
| name: Publish to GitHub | |
| needs: build | |
| runs-on: windows-latest | |
| steps: | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: release-assets | |
| path: . | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| name: ${{ needs.build.outputs.release_title }} | |
| body_path: release_notes.txt | |
| files: | | |
| *.exe | |
| *.msi | |
| *.zip | |
| draft: false | |
| prerelease: false | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # ======================================================= | |
| # 独立的 Gitee Release Job (带重试机制) | |
| # ======================================================= | |
| release-gitee: | |
| name: Publish to Gitee | |
| needs: build | |
| runs-on: windows-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: release-assets | |
| path: . | |
| - name: Push to Gitee | |
| shell: pwsh | |
| env: | |
| GITEE_TOKEN: ${{ secrets.GITEE_TOKEN }} | |
| GITEE_EMAIL: ${{ secrets.GITEE_EMAIL }} | |
| run: | | |
| $owner, $repo = "${{ github.repository }}".Split('/') | |
| git config --global user.name "ghost-him" | |
| git config --global user.email "$env:GITEE_EMAIL" | |
| git remote add gitee "https://oauth2:$($env:GITEE_TOKEN)@gitee.com/$owner/$repo.git" || true | |
| git push gitee HEAD:main --tags -f | |
| - name: Create Gitee Release with Retry | |
| shell: pwsh | |
| env: | |
| VERSION: ${{ needs.build.outputs.version }} | |
| RELEASE_TITLE: ${{ needs.build.outputs.release_title }} | |
| GITEE_TOKEN: ${{ secrets.GITEE_TOKEN }} | |
| run: | | |
| # --- 重试机制配置 --- | |
| $maxRetries = 3 | |
| $retryDelaySeconds = 20 | |
| # -------------------- | |
| # 动态获取仓库所有者和名称 | |
| $owner, $repo = "${{ github.repository }}".Split('/') | |
| Write-Host "Target Gitee Repository: $owner/$repo" | |
| for ($i = 1; $i -le $maxRetries; $i++) { | |
| try { | |
| Write-Host "Attempt $i of $maxRetries to create and upload Gitee release..." | |
| $version = $env:VERSION | |
| $releaseTitle = $env:RELEASE_TITLE | |
| $tag = "v$version" | |
| $releaseNotes = Get-Content -Path "release_notes.txt" -Raw -Encoding UTF8 | |
| $headers = @{"Content-Type" = "application/json"; "Authorization" = "token $env:GITEE_TOKEN"} | |
| $body = @{tag_name = $tag; name = $releaseTitle; body = $releaseNotes; target_commitish = "main"; prerelease = $false} | ConvertTo-Json | |
| # 确保幂等性:先删除旧 Release | |
| try { | |
| $existingRelease = Invoke-RestMethod -Uri "https://gitee.com/api/v5/repos/$owner/$repo/releases/tags/$tag" -Method Get -Headers $headers -ErrorAction SilentlyContinue | |
| if ($existingRelease) { | |
| Invoke-RestMethod -Uri "https://gitee.com/api/v5/repos/$owner/$repo/releases/$($existingRelease.id)" -Method Delete -Headers $headers | |
| Write-Host "已删除旧的 Gitee Release" | |
| } | |
| } catch { Write-Host "没有旧的 Gitee Release 需要删除" } | |
| # 创建新 Release | |
| $response = Invoke-RestMethod -Uri "https://gitee.com/api/v5/repos/$owner/$repo/releases" -Method Post -Headers $headers -Body $body | |
| $releaseId = $response.id | |
| Write-Host "✅ Gitee Release 创建成功,ID: $releaseId" | |
| # 上传文件 | |
| $files = Get-ChildItem -Path . -Recurse -Include *.exe,*.msi,*.zip -File | |
| if ($files.Count -eq 0) { throw "未找到需要上传到 Gitee 的构建产物" } | |
| foreach ($file in $files) { | |
| Write-Host "📦 正在上传 $($file.Name) 到 Gitee Release..." | |
| curl.exe -X POST "https://gitee.com/api/v5/repos/$owner/$repo/releases/$releaseId/attach_files" -F "access_token=$env:GITEE_TOKEN" -F "file=@$($file.FullName)" | |
| if ($LASTEXITCODE -ne 0) { | |
| throw "上传文件 $($file.Name) 到 Gitee 失败" | |
| } | |
| Write-Host "✅ 已上传: $($file.Name)" | |
| } | |
| Write-Host "✅ Gitee Release 所有文件上传完成" | |
| break # 成功则跳出循环 | |
| } catch { | |
| Write-Host "❌ Gitee Release 操作失败: $_" | |
| if ($i -lt $maxRetries) { | |
| Write-Host "将在 $retryDelaySeconds 秒后重试..." | |
| Start-Sleep -Seconds $retryDelaySeconds | |
| } else { | |
| Write-Host "❌ 已达到最大重试次数,Gitee 发布失败。" | |
| throw # 最后一次失败时,抛出异常以使 job 失败 | |
| } | |
| } | |
| } | |
| # ======================================================= | |
| # 独立的 GitCode Release Job (带重试机制) | |
| # ======================================================= | |
| release-gitcode: | |
| name: Publish to GitCode | |
| needs: build | |
| runs-on: windows-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: release-assets | |
| path: . | |
| - name: Push to GitCode | |
| shell: pwsh | |
| env: | |
| GITCODE_TOKEN: ${{ secrets.GITCODE_TOKEN }} | |
| GITCODE_EMAIL: ${{ secrets.GITCODE_EMAIL }} | |
| run: | | |
| $owner, $repo = "${{ github.repository }}".Split('/') | |
| git config --global user.name "ghost-him" | |
| git config --global user.email "$env:GITCODE_EMAIL" | |
| git remote add gitcode "https://oauth2:$($env:GITCODE_TOKEN)@gitcode.com/$owner/$repo.git" || true | |
| git push gitcode HEAD:main --tags -f | |
| - name: Create GitCode Release with Retry | |
| shell: pwsh | |
| env: | |
| VERSION: ${{ needs.build.outputs.version }} | |
| RELEASE_TITLE: ${{ needs.build.outputs.release_title }} | |
| GITCODE_TOKEN: ${{ secrets.GITCODE_TOKEN }} | |
| run: | | |
| # --- 重试机制配置 --- | |
| $maxRetries = 3 | |
| $retryDelaySeconds = 30 # GitCode API 可能更慢,延迟稍长 | |
| # -------------------- | |
| # 动态获取仓库所有者和名称 | |
| $owner, $repo = "${{ github.repository }}".Split('/') | |
| Write-Host "Target GitCode Repository: $owner/$repo" | |
| for ($i = 1; $i -le $maxRetries; $i++) { | |
| try { | |
| Write-Host "Attempt $i of $maxRetries to create and upload GitCode release..." | |
| $version = $env:VERSION | |
| $releaseTitle = $env:RELEASE_TITLE | |
| $tag = "v$version" | |
| $token = $env:GITCODE_TOKEN | |
| $releaseNotes = Get-Content -Path "release_notes.txt" -Raw -Encoding UTF8 | |
| $headers = @{"Private-Token" = $token} | |
| # 1. 创建 Release | |
| $createReleaseUri = "https://gitcode.com/api/v5/repos/$owner/$repo/releases" | |
| $releaseBody = @{tag_name = $tag; name = $releaseTitle; body = $releaseNotes} | ConvertTo-Json -Depth 5 | |
| Invoke-RestMethod -Uri $createReleaseUri -Method Post -Headers $headers -ContentType "application/json" -Body $releaseBody -ErrorAction Stop | |
| Write-Host "✅ GitCode Release 创建成功" | |
| # 2. 上传文件 | |
| $files = Get-ChildItem -Path . -Recurse -Include *.exe,*.msi,*.zip -File | |
| if ($files.Count -eq 0) { throw "未找到需要上传到 GitCode 的构建产物" } | |
| foreach ($file in $files) { | |
| Write-Host "📦 正在上传 $($file.Name) 到 GitCode Release..." | |
| $encodedFileName = [System.Web.HttpUtility]::UrlEncode($file.Name) | |
| $getUploadUrlEndpoint = "https://gitcode.com/api/v5/repos/$owner/$repo/releases/$tag/upload_url?access_token=$token&file_name=$encodedFileName" | |
| $uploadInfo = Invoke-RestMethod -Uri $getUploadUrlEndpoint -Method Get -ErrorAction Stop | |
| if (-not $uploadInfo.url) { throw "未从 GitCode 获取到上传地址" } | |
| $putHeaders = @{} | |
| if ($uploadInfo.headers) { | |
| foreach ($key in $uploadInfo.headers.PSObject.Properties.Name) { $putHeaders[$key] = $uploadInfo.headers.$key } | |
| } | |
| Invoke-RestMethod -Uri $uploadInfo.url -Method Put -InFile $file.FullName -Headers $putHeaders -ErrorAction Stop | |
| Write-Host "✅ 已上传: $($file.Name)" | |
| } | |
| Write-Host "✅ GitCode Release 所有文件上传完成" | |
| break # 成功则跳出循环 | |
| } catch { | |
| Write-Host "❌ GitCode Release 操作失败: $($_.Exception.Message)" | |
| if ($i -lt $maxRetries) { | |
| Write-Host "将在 $retryDelaySeconds 秒后重试..." | |
| Start-Sleep -Seconds $retryDelaySeconds | |
| } else { | |
| Write-Host "❌ 已达到最大重试次数,GitCode 发布失败。" | |
| throw # 最后一次失败时,抛出异常以使 job 失败 | |
| } | |
| } | |
| } | |
| # ======================================================= | |
| # 最终的通知 Job,依赖于所有并行的 release job | |
| # ======================================================= | |
| notify: | |
| name: Notify on completion | |
| needs: | |
| - release-github | |
| - release-gitee | |
| - release-gitcode | |
| runs-on: ubuntu-latest | |
| if: always() | |
| # 无论成功失败都运行 | |
| steps: | |
| - name: Check status of all release jobs | |
| run: | | |
| echo "🔎 Checking status of all release jobs..." | |
| github_status="${{ needs.release-github.result }}" | |
| gitee_status="${{ needs.release-gitee.result }}" | |
| gitcode_status="${{ needs.release-gitcode.result }}" | |
| echo " - GitHub Release: $github_status" | |
| echo " - Gitee Release: $gitee_status" | |
| echo " - GitCode Release: $gitcode_status" | |
| if [[ "$github_status" == "success" && "$gitee_status" == "success" && "$gitcode_status" == "success" ]]; then | |
| echo "✅ All platforms released successfully!" | |
| else | |
| echo "❌ One or more platforms failed to release. Please check the logs." | |
| exit 1 | |
| fi |