mirror of
https://github.com/ZhuLinsen/daily_stock_analysis
synced 2026-09-20 10:53:33 +08:00
fix: unify desktop updater artifacts (#1320)
This commit is contained in:
30
.github/workflows/desktop-release.yml
vendored
30
.github/workflows/desktop-release.yml
vendored
@@ -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
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
],
|
||||
"win": {
|
||||
"target": "nsis",
|
||||
"artifactName": "daily-stock-analysis-windows-installer-v${version}.${ext}",
|
||||
"publish": [
|
||||
{
|
||||
"provider": "github",
|
||||
|
||||
@@ -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
|
||||
|
||||
### 发布亮点
|
||||
|
||||
@@ -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` 免安装包时,用户只需:
|
||||
|
||||
@@ -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)."
|
||||
|
||||
Reference in New Issue
Block a user