Skip to content

chore: 发布v0.5.3版本,同时测试release workflow能不能正常工作 #9

chore: 发布v0.5.3版本,同时测试release workflow能不能正常工作

chore: 发布v0.5.3版本,同时测试release workflow能不能正常工作 #9

Workflow file for this run

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