新增: 应用内版本更新与自动升级全链路
后端 update.rs: app_check_update(拉 latest.json+ed25519 签名校验) / app_download_install_update / prefs 读写 / mark_checked / mark_notified 五命令, lib.rs 注册;tauri.conf updater 段(endpoints=app.1216.top/download/devflow/latest.json + pubkey + createUpdaterArtifacts) + tauri-plugin-updater 依赖 + capabilities 权限。 前端 UpdateBadge.vue(顶栏徽章+下拉) / useUpdateCheck.ts(检查/下载/安装状态机) / AboutPanel.vue(设置页关于面板) + AppLayout 接线 + SettingsNav/searchIndex 索引 + i18n zh/en settings 键。 运维 scripts/publish-release.ps1(发版) + swap-install.ps1(换装校验) + 设计文档 版本更新与自动升级-设计-2026-10-09.md。 验收: cargo check -p devflow EXIT 0 + vue-tsc EXIT 0 + build EXIT 0。
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
# 用途: DevFlow 应用内升级发布通道(B4/L3)
|
||||
# 构建 updater 产物(.nsis.zip + .sig) -> 生成 latest.json -> 上传 app.1216.top
|
||||
# 设计: docs/02-架构设计/专项设计/版本更新与自动升级-设计-2026-10-09.md §四 L3
|
||||
#
|
||||
# 用法:
|
||||
# .\scripts\publish-release.ps1 # 用 git 最近提交作 notes
|
||||
# .\scripts\publish-release.ps1 -Notes "修复xx" # 手动指定更新说明
|
||||
# .\scripts\publish-release.ps1 -SkipBuild # 复用已有产物(仅生成清单+上传)
|
||||
#
|
||||
# 前置:
|
||||
# 1. tauri.conf.json 与 Cargo.toml 版本号一致(脚本第 1 步校验,防 D1 复发)
|
||||
# 2. 签名私钥就位: $env:TAURI_SIGNING_PRIVATE_KEY = "$env:USERPROFILE\.tauri\devflow.key"
|
||||
# (无密码密钥无需 TAURI_SIGNING_PRIVATE_KEY_PASSWORD)
|
||||
# 3. ssh-proxy 已配 suke-dev(39.99.243.191),web 根 /var/www/app-site/
|
||||
param(
|
||||
[string]$Notes = "",
|
||||
[switch]$SkipBuild
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$repo = "E:\wk-lab\devflow"
|
||||
$site = "suke-dev"
|
||||
$remoteDir = "/var/www/app-site/download/devflow"
|
||||
$baseUrl = "https://app.1216.top/download/devflow"
|
||||
|
||||
Set-Location $repo
|
||||
|
||||
# ── 1. 版本双源校验(防 D1 复发)──
|
||||
Write-Host "[1/6] 校验版本双源一致..."
|
||||
$confVer = (Get-Content "$repo\src-tauri\tauri.conf.json" -Raw | ConvertFrom-Json).version
|
||||
$cargoVer = (Select-String -Path "$repo\src-tauri\Cargo.toml" -Pattern '^version\s*=\s*"([^"]+)"').Matches[0].Groups[1].Value
|
||||
if ($confVer -ne $cargoVer) {
|
||||
Write-Host "[失败] 版本不一致: tauri.conf.json=$confVer, Cargo.toml=$cargoVer"
|
||||
Write-Host " 请先对齐两处版本号再发布(设计 D1:双源必须同值)"
|
||||
exit 1
|
||||
}
|
||||
$version = $confVer
|
||||
Write-Host " 版本 v$version 双源一致,通过"
|
||||
|
||||
# ── 2. 签名私钥就位检查 ──
|
||||
if (-not $env:TAURI_SIGNING_PRIVATE_KEY) {
|
||||
$keyPath = "$env:USERPROFILE\.tauri\devflow.key"
|
||||
if (Test-Path $keyPath) {
|
||||
$env:TAURI_SIGNING_PRIVATE_KEY = $keyPath
|
||||
Write-Host "[2/6] 签名私钥: $keyPath"
|
||||
} else {
|
||||
Write-Host "[失败] 未找到签名私钥($keyPath),且未设 TAURI_SIGNING_PRIVATE_KEY"
|
||||
Write-Host " 先执行: cargo tauri signer generate -w `$env:USERPROFILE\.tauri\devflow.key"
|
||||
exit 1
|
||||
}
|
||||
} else {
|
||||
Write-Host "[2/6] 签名私钥: 取自环境变量"
|
||||
}
|
||||
|
||||
# ── 3. 构建 updater 产物 ──
|
||||
$nsisDir = "$repo\target\release\bundle\nsis"
|
||||
if (-not $SkipBuild) {
|
||||
Write-Host "[3/6] tauri build(含 createUpdaterArtifacts,可能 10 分钟级)..."
|
||||
cmd /c "cargo tauri build 2>&1"
|
||||
if ($LASTEXITCODE -ne 0) { Write-Host "[失败] tauri build"; exit 1 }
|
||||
} else {
|
||||
Write-Host "[3/6] 跳过构建(-SkipBuild),复用已有产物"
|
||||
}
|
||||
|
||||
# 定位产物:裸 exe / .nsis.zip / .sig
|
||||
$setupExe = Get-ChildItem "$nsisDir\devflow_${version}_x64-setup.exe" -ErrorAction SilentlyContinue | Select-Object -First 1
|
||||
$zipFile = Get-ChildItem "$nsisDir\devflow_${version}_x64-setup.nsis.zip" -ErrorAction SilentlyContinue | Select-Object -First 1
|
||||
$sigFile = Get-ChildItem "$nsisDir\devflow_${version}_x64-setup.nsis.zip.sig" -ErrorAction SilentlyContinue | Select-Object -First 1
|
||||
if (-not $zipFile) { Write-Host "[失败] 未找到 .nsis.zip 产物(确认 createUpdaterArtifacts=true)"; exit 1 }
|
||||
if (-not $sigFile) { Write-Host "[失败] 未找到 .sig 签名文件"; exit 1 }
|
||||
Write-Host " 产物: $($zipFile.Name) ($([math]::Round($zipFile.Length/1MB,1))MB)"
|
||||
|
||||
# ── 4. 生成 latest.json ──
|
||||
Write-Host "[4/6] 生成 latest.json..."
|
||||
$sig = (Get-Content $sigFile.FullName -Raw).Trim()
|
||||
if (-not $Notes) {
|
||||
# 用 git 最近一条提交作 notes(无 CHANGELOG 时的兜底)
|
||||
$Notes = (git log -1 --pretty=format:"%s" 2>&1) -join "`n"
|
||||
if (-not $Notes) { $Notes = "DevFlow v$version" }
|
||||
}
|
||||
$pubDate = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
|
||||
$sha256 = (Get-FileHash $zipFile.FullName -Algorithm SHA256).Hash.ToLower()
|
||||
$latestJson = [ordered]@{
|
||||
version = $version
|
||||
notes = $Notes
|
||||
pub_date = $pubDate
|
||||
platforms = [ordered]@{
|
||||
"windows-x86_64" = [ordered]@{
|
||||
signature = $sig
|
||||
url = "$baseUrl/devflow_${version}_x64-setup.nsis.zip"
|
||||
}
|
||||
}
|
||||
} | ConvertTo-Json -Depth 5
|
||||
$latestPath = "$repo\target\release\bundle\nsis\latest.json"
|
||||
$latestJson | Out-File $latestPath -Encoding utf8 -NoNewline
|
||||
Write-Host " latest.json: version=$version, sha256=$($sha256.Substring(0,16))..."
|
||||
|
||||
# ── 5. 上传到 app.1216.top ──
|
||||
Write-Host "[5/6] 上传到 $site`:$remoteDir ..."
|
||||
$env:MSYS_NO_PATHCONV = "1"
|
||||
# 确保远程目录存在
|
||||
ssh-proxy exec -n $site -c "mkdir -p $remoteDir"
|
||||
if ($LASTEXITCODE -ne 0) { Write-Host "[失败] 创建远程目录"; exit 1 }
|
||||
|
||||
$uploads = @($latestPath, $zipFile.FullName, $sigFile.FullName)
|
||||
if ($setupExe) { $uploads += $setupExe.FullName }
|
||||
foreach ($f in $uploads) {
|
||||
$name = Split-Path $f -Leaf
|
||||
Write-Host " 上传 $name ..."
|
||||
ssh-proxy upload --name $site --src $f --dst "$remoteDir/$name"
|
||||
if ($LASTEXITCODE -ne 0) { Write-Host "[失败] 上传 $name"; exit 1 }
|
||||
}
|
||||
|
||||
# ── 6. 验证 ──
|
||||
Write-Host "[6/6] 验证远端清单..."
|
||||
$remoteCheck = ssh-proxy exec -n $site -c "ls -la $remoteDir && echo '---' && cat $remoteDir/latest.json | head -5"
|
||||
Write-Host $remoteCheck
|
||||
Write-Host ""
|
||||
Write-Host "[发布完成] v$version"
|
||||
Write-Host " 清单地址: $baseUrl/latest.json"
|
||||
Write-Host " 应用内检查更新即可发现新版本(app.1216.top 已配 no-cache,无需刷 CDN)"
|
||||
Reference in New Issue
Block a user