fix: unify desktop updater artifacts (#1320)

This commit is contained in:
mumu
2026-05-16 17:49:34 +08:00
committed by GitHub
parent 71501d6873
commit 4733d2185a
5 changed files with 63 additions and 32 deletions

View File

@@ -70,22 +70,20 @@ jobs:
- name: Prepare release artifact (Windows)
shell: pwsh
run: |
$installerExe = Get-ChildItem -Path 'apps/dsa-desktop/dist' -Filter '*.exe' `
| Where-Object { $_.Name -match 'Setup' } `
| Sort-Object LastWriteTime -Descending `
| Select-Object -First 1
$expectedInstallerName = "daily-stock-analysis-windows-installer-$env:RELEASE_TAG.exe"
$installerPath = Join-Path 'apps/dsa-desktop/dist' $expectedInstallerName
$installerExe = Get-Item -Path $installerPath -ErrorAction SilentlyContinue
if (-not $installerExe) {
throw 'No NSIS setup .exe found under apps/dsa-desktop/dist.'
throw "No expected NSIS installer found under apps/dsa-desktop/dist: $expectedInstallerName"
}
$winUnpacked = 'apps/dsa-desktop/dist/win-unpacked'
if (-not (Test-Path $winUnpacked)) {
throw 'No win-unpacked directory found under apps/dsa-desktop/dist.'
}
New-Item -ItemType Directory -Path 'dist/release-assets' -Force | Out-Null
$exeTarget = "dist/release-assets/daily-stock-analysis-windows-installer-$env:RELEASE_TAG.exe"
$exeTarget = "dist/release-assets/$expectedInstallerName"
$zipTarget = "dist/release-assets/daily-stock-analysis-windows-noinstall-$env:RELEASE_TAG.zip"
Copy-Item -Path $installerExe.FullName -Destination $exeTarget -Force
Copy-Item -Path $installerExe.FullName -Destination "dist/release-assets/$($installerExe.Name)" -Force
Compress-Archive -Path $winUnpacked -DestinationPath $zipTarget -CompressionLevel Optimal -Force
Get-ChildItem -Path 'apps/dsa-desktop/dist' -File |
Where-Object { $_.Name -eq 'latest.yml' -or $_.Name -like '*.blockmap' } |
@@ -100,8 +98,22 @@ jobs:
if (-not (Select-String -Path 'dist/release-assets/latest.yml' -Pattern $versionPattern)) {
throw "latest.yml version does not match release tag $env:RELEASE_TAG."
}
if (-not (Get-ChildItem -Path 'dist/release-assets' -Filter '*.blockmap' -File)) {
throw 'No blockmap files found under dist/release-assets.'
$latestText = Get-Content -Path 'dist/release-assets/latest.yml' -Raw
$pathMatch = [regex]::Match($latestText, '(?m)^\s*path:\s*[''"]?([^''"\r\n]+)[''"]?\s*$')
if (-not $pathMatch.Success) {
throw 'latest.yml missing path field.'
}
$latestInstallerPath = $pathMatch.Groups[1].Value.Trim()
if ($latestInstallerPath -ne $expectedInstallerName) {
throw "latest.yml path ($latestInstallerPath) does not match release installer $expectedInstallerName."
}
$urlMatch = [regex]::Match($latestText, '(?m)^\s*-\s*url:\s*[''"]?([^''"\r\n]+)[''"]?\s*$')
if ($urlMatch.Success -and $urlMatch.Groups[1].Value.Trim() -ne $expectedInstallerName) {
throw "latest.yml file url ($($urlMatch.Groups[1].Value.Trim())) does not match release installer $expectedInstallerName."
}
$expectedBlockmapName = "$expectedInstallerName.blockmap"
if (-not (Get-ChildItem -Path 'dist/release-assets' -Filter $expectedBlockmapName -File)) {
throw "No matching blockmap found under dist/release-assets: $expectedBlockmapName"
}
Get-ChildItem -Path 'dist/release-assets' -File | Sort-Object Name | Format-Table Name, Length

View File

@@ -38,6 +38,7 @@
],
"win": {
"target": "nsis",
"artifactName": "daily-stock-analysis-windows-installer-v${version}.${ext}",
"publish": [
{
"provider": "github",

View File

@@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
<!-- 新条目格式:- [类型] 描述(类型取值:新功能/改进/修复/文档/测试/chore-->
<!-- 每条独立一行追加到本段末尾,无需分类标题,合并时冲突最小 -->
- [修复] 统一 Windows 桌面安装包与自动更新元数据文件名,避免 Release 中出现重复安装包并阻断 `latest.yml` 指向不存在附件。
## [3.17.1] - 2026-05-16
### 发布亮点

View File

@@ -68,8 +68,8 @@ powershell -ExecutionPolicy Bypass -File scripts\build-all.ps1
- 推送语义化 tag`v3.2.12`)后自动触发
- 在 Actions 页面手动触发并指定 `release_tag`
- 产物:
- Windows 安装包Release 附件会整理`daily-stock-analysis-windows-installer-<tag>.exe`,本地 `apps/dsa-desktop/dist/` 中仍是 `*Setup*.exe`
- Windows 自动更新元数据Release 附件会额外保留 electron-builder 原始 `*Setup*.exe``latest.yml``*.blockmap`,供安装版桌面端后台下载与校验更新
- Windows 安装包Release 附件和本地 `apps/dsa-desktop/dist/` 中统一`daily-stock-analysis-windows-installer-<tag>.exe`
- Windows 自动更新元数据Release 附件会额外保留 `latest.yml``*.blockmap`,供安装版桌面端后台下载与校验更新;普通用户无需手动下载这些元数据
- Windows 免安装包:`daily-stock-analysis-windows-noinstall-<tag>.zip`
- macOS Intel`daily-stock-analysis-macos-x64-<tag>.dmg`
- macOS Apple Silicon`daily-stock-analysis-macos-arm64-<tag>.dmg`
@@ -112,7 +112,7 @@ npm run build
./scripts/verify-desktop-updater-artifacts.ps1 -ReleaseTag v$(node -p "require('./apps/dsa-desktop/package.json').version")
```
> 预期当前执行环境不支持生成 Windows `Setup*.exe` 时,请在交付说明中明确注明平台限制,并要求指定的 Windows 发布链路复核人补齐该项验证。
> 预期当前执行环境不支持生成 Windows NSIS 安装器时,请在交付说明中明确注明平台限制,并要求指定的 Windows 发布链路复核人补齐该项验证。
3. 检查更新元数据是否产出
@@ -127,7 +127,7 @@ ls -1 dist/*.yml dist/*.blockmap 2>/dev/null || true
RELEASE_TAG="v$(node -p \"require('./package.json').version\")"
REPO="ZhuLinsen/daily_stock_analysis"
for f in dist/*latest.yml dist/*.blockmap dist/*Setup*.exe; do
for f in dist/*latest.yml dist/*.blockmap dist/daily-stock-analysis-windows-installer-*.exe; do
[ -f \"$f\" ] && echo \"[FOUND] $f\"
done
@@ -141,10 +141,9 @@ echo \"Release Tag: $RELEASE_TAG\"
echo \"Release 地址: https://github.com/$REPO/releases/tag/$RELEASE_TAG\"
echo \"应核对附件是否包含:\"
echo \"- daily-stock-analysis-windows-installer-*.exe\"
echo \"- *Setup*.exe\"
echo \"- latest.yml\"
echo \"- *.blockmap\"
echo \"并确保 latest.yml 中 version 与 tag 的语义化版本一致\"
echo \"并确保 latest.yml 中 version 与 tag 的语义化版本一致path/url 与安装包附件名一致\"
```
5a. 建议在 PR 描述里记录的“可复核输出”Windows
@@ -156,14 +155,14 @@ grep -E "^version:" dist/latest.yml
echo "latest.yml files:"
sed -n '1,80p' dist/latest.yml
echo "packaging artifacts:"
ls -1 dist/*.yml dist/*.blockmap dist/*Setup*.exe dist/*installer*.exe 2>/dev/null | sort
ls -1 dist/*.yml dist/*.blockmap dist/*installer*.exe 2>/dev/null | sort
```
Windows 发布链路复核清单(在 PR 后由发布团队/维护者执行):
- release/tag 与 `daily-stock-analysis-windows-installer-<tag>.exe` 的版本号一致;
- `latest.yml``*Setup*.exe``*.blockmap` 同 tag 同步出现且可下载;
- `latest.yml``version` 与 Release tag 语义一致(去掉 `v` 前缀后比对);
- `latest.yml``daily-stock-analysis-windows-installer-<tag>.exe``*.blockmap` 同 tag 同步出现且可下载;
- `latest.yml``version` 与 Release tag 语义一致(去掉 `v` 前缀后比对),且 `path` / `files.url` 与安装包附件名一致
- 如缺少上述文件或 `release-tag` 不匹配,需标注阻断并补齐 `desktop-release` 打包流程。
5. Windows/NSIS 产物与发布附件一致性请在 Windows 环境手动验证(可人工触发发布流程),并在升级后核对运行时文件留存:
@@ -213,7 +212,7 @@ npm install
npm run build
```
打包产物位于 `apps/dsa-desktop/dist/`。Windows 安装器会生成 `*Setup*.exe`,安装向导中可选择安装目录。
打包产物位于 `apps/dsa-desktop/dist/`。Windows 安装器会生成 `daily-stock-analysis-windows-installer-<tag>.exe`,安装向导中可选择安装目录。
## 目录结构
@@ -303,7 +302,7 @@ PyInstaller 打包时缺少模块,需要在 `scripts/build-backend.ps1` 中增
Windows 分发现在有两种方式:
1. 安装包:分发 `apps/dsa-desktop/dist/` 下的 `*Setup*.exe`,用户安装时可自行选择目标目录
1. 安装包:分发 `apps/dsa-desktop/dist/` 下的 `daily-stock-analysis-windows-installer-<tag>.exe`,用户安装时可自行选择目标目录
2. 免安装包:将 `apps/dsa-desktop/dist/win-unpacked/` 整个文件夹打包发给用户
使用 `win-unpacked` 免安装包时,用户只需:

View File

@@ -68,14 +68,34 @@ if ($normalizedLatestVersion -ne $normalizedReleaseTag) {
throw "Version mismatch: latest.yml=$normalizedLatestVersion, expected=$normalizedReleaseTag"
}
$setupFiles = Get-ChildItem -Path $distDirPath -Filter '*Setup*.exe' -File -ErrorAction SilentlyContinue
if (-not $setupFiles) {
throw 'No *Setup*.exe found in dist (NSIS installer is required).'
$expectedInstallerFileName = "daily-stock-analysis-windows-installer-v$normalizedReleaseTag.exe"
if ($ymlText -match '(?m)^\s*path:\s*[''"]?([^''"\r\n]+)[''"]?\s*$') {
$latestInstallerPath = $matches[1].Trim()
} else {
throw "latest.yml appears invalid: missing path field."
}
$blockmapFiles = Get-ChildItem -Path $distDirPath -Filter '*.blockmap' -File -ErrorAction SilentlyContinue
if ($latestInstallerPath -ne $expectedInstallerFileName) {
throw "latest.yml path ($latestInstallerPath) does not match expected installer $expectedInstallerFileName."
}
if ($ymlText -match '(?m)^\s*-\s*url:\s*[''"]?([^''"\r\n]+)[''"]?\s*$') {
$latestInstallerUrl = $matches[1].Trim()
if ($latestInstallerUrl -ne $expectedInstallerFileName) {
throw "latest.yml file url ($latestInstallerUrl) does not match expected installer $expectedInstallerFileName."
}
}
$setupFiles = Get-ChildItem -Path $distDirPath -Filter $expectedInstallerFileName -File -ErrorAction SilentlyContinue
if (-not $setupFiles) {
throw "No expected NSIS installer found in dist: $expectedInstallerFileName"
}
$expectedBlockmapFileName = "$expectedInstallerFileName.blockmap"
$blockmapFiles = Get-ChildItem -Path $distDirPath -Filter $expectedBlockmapFileName -File -ErrorAction SilentlyContinue
if (-not $blockmapFiles) {
throw 'No *.blockmap found in dist; updater metadata may be incomplete.'
throw "No matching blockmap found in dist: $expectedBlockmapFileName"
}
$installerFiles = @()
@@ -101,9 +121,9 @@ if ($releaseAssetsDirWasExplicit) {
}
if ($releaseAssetsDirPath) {
$installerFiles = Get-ChildItem -Path $releaseAssetsDirPath -Filter 'daily-stock-analysis-windows-installer-*.exe' -File -ErrorAction SilentlyContinue
$installerFiles = Get-ChildItem -Path $releaseAssetsDirPath -Filter $expectedInstallerFileName -File -ErrorAction SilentlyContinue
if (-not $installerFiles) {
throw "No daily-stock-analysis-windows-installer-*.exe found in release assets: $releaseAssetsDirPath"
throw "No expected Windows installer found in release assets: $expectedInstallerFileName"
}
} else {
Write-Host "[check] release attachment alias check skipped: run after release assets are prepared or pass -ReleaseAssetsDir."
@@ -112,7 +132,8 @@ if ($releaseAssetsDirPath) {
Write-Host "[check] dist: $distDirPath"
Write-Host "[check] latest.yml version: $normalizedLatestVersion"
Write-Host "[check] expected release version: $normalizedReleaseTag"
Write-Host "[check] NSIS installers (Setup):"
Write-Host "[check] latest.yml installer path: $latestInstallerPath"
Write-Host "[check] NSIS installers:"
$setupFiles | ForEach-Object { Write-Host "[found] $($_.Name)" }
if ($installerFiles) {
Write-Host "[check] release assets: $releaseAssetsDirPath"
@@ -122,10 +143,6 @@ if ($installerFiles) {
Write-Host "[check] blockmaps:"
$blockmapFiles | ForEach-Object { Write-Host "[found] $($_.Name)" }
if (-not $ymlText.Contains('path:')) {
throw "latest.yml appears invalid: missing path field."
}
$versionInTag = Normalize-SemverText -VersionText $ReleaseTag
if ($versionInTag -and $versionInTag -ne $normalizedReleaseTag) {
Write-Host "[warn] input release tag ($versionInTag) differs from package version ($normalizedReleaseTag)."