ADR 0003 — Velopack 發布流程與版本號管理¶
- 日期:2026-04-20
- 狀態:Accepted
- 決策者:使用者
Context¶
TsERP 之前用 ClickOnce 發布(autodeploy.ps1 / darbtestDeploy.ps1),分別上傳到 Azure Blob 的 cy-erp / darb-test container。程式同時已經引入 Velopack 0.0.1298(TsERP.csproj),App.xaml.cs:60 有 VelopackApp.Build().Run()、App.xaml.cs:72 從 https://tworkerpdeploy.blob.core.windows.net/darb-vpk 抓更新,但沒有配套的發布腳本,僅有 TsERP/打包.txt 一行 vpk pack 範例。
手動組指令會踩的坑:
- 版本號:csproj 內只有 ClickOnce 用的
<ApplicationVersion>1.0.1.%2a</ApplicationVersion>(4 段帶萬用字元),不符合 Velopack 需要的 3 段式 SemVer - Delta update:若沒先
vpk download既有 releases,vpk pack會當作首次發布,使用者端拿不到 delta 只能整包下載 - 簽章參數:csproj
ManifestCertificateThumbprint=66AE9BC6...只用在 ClickOnce manifest,Velopack EXE 簽章要另外傳--signParams - Azure 上傳:既有 ClickOnce 腳本上傳路徑結構(
Application Files/<版本資料夾>/)與 Velopack(*.nupkg+RELEASES放 container 根)完全不同,不能直接套用
Decision¶
- csproj 新增獨立標籤
<VelopackVersion>X.Y.Z</VelopackVersion> - 與 ClickOnce 的
<ApplicationVersion>/<ApplicationRevision>完全解耦,各走各的 -
由發布腳本讀取 / 遞增 / 寫回,用 regex 替換避免 XmlDocument 重寫整份檔案打亂 git diff
-
發布腳本放
TsERP/release-velopack.ps1,單一環境(darb-vpkcontainer,無 multi-channel 參數) -
版號策略:每次發布前自動把 patch 段 +1(
1.0.1 -> 1.0.2),不提供手動指定 -
Major / Minor 需要時使用者直接編輯 csproj
-
流程順序固定:
- 檢查 csproj 無未提交變更(避免 auto-commit 掃入無關 diff)
- 版號 +1 寫回 csproj
dotnet restore-> FrameworkMSBuild.exe /t:Publish(見下點 7)輸出到publish\vpk download http --url <feed>(抓既有 releases 產 delta;-SkipDownload首次發布用)vpk pack帶--signParams "/fd SHA256 /td SHA256 /tr http://timestamp.sectigo.com /sha1 66AE9BC6..."az login --tenant 75ef...+az storage blob upload-batch到darb-vpk-
git commit只 addTsERP/TsERP.csproj,訊息release: v{newVersion} -
Publish 必須用 .NET Framework 版 MSBuild:
TsERP.csproj和ViewModel.csproj都有<COMReference>(Office.Core、VBIDE)。dotnet publish底層走 .NET Core 版 MSBuild,不支援ResolveComReference任務,build 會報 MSB4803 直接失敗。腳本透過vswhere.exe定位 VS 2022 / Build Tools 的 Framework MSBuild 後再呼叫/t:Publish -
簽章:沿用 ClickOnce 同一張 EV 憑證(USB 硬體 token,signtool 會彈 PIN 視窗)。
--signParams透過/sha1 <thumbprint>對應,無需匯出 PFX -
逃生閘:4 個開關
-SkipDownload、-SkipSign、-SkipUpload、-SkipCommit,給首次發布、本地驗證、USB 未插時使用
Consequences¶
正面¶
vpk pack/ upload 流程腳本化,減少手動輸入出錯- 版號單向遞增 + 自動 commit,git log 可追每一版發布時點
- ClickOnce 舊腳本完全不動,兩條線並存直到決定淘汰 ClickOnce
負面 / 風險¶
- 首次發布必須記得加
-SkipDownload:darb-vpkcontainer 沒有 RELEASES 檔時vpk download http會失敗並中止流程(版號此時已寫回,重跑前需手動 revert csproj 或繼續用新版號) - 發布過程中任何階段失敗,csproj 版號已寫回但還沒 commit:重跑前需要
git checkout -- TsERP/TsERP.csproj還原,否則第二次執行會因 pre-check(csproj 不乾淨)被拒 - 版號強制 +1:若 pack 或 upload 失敗、但前面 csproj 已 commit,需要手動 revert commit 才能重試同版號。目前實作 commit 放在最後一步降低機率,但不是 100% 安全
- csproj auto-commit 會合併到 release commit:若 csproj 同時有其他無關修改沒 commit,腳本會拒絕執行,強迫使用者先處理(預期行為)
- EV 簽章的 USB PIN 每次都要人工輸入:不能 fully unattended,CI/CD 化需換 HSM / 雲端 signing
- Build 機器必須裝 Visual Studio 2022 或 Build Tools:腳本依賴
vswhere+ Framework MSBuild;若只有 .NET SDK 會找不到 MSBuild.exe 直接中止
Migration¶
- 既有安裝的 ClickOnce 使用者無法自動升級到 Velopack 安裝包,兩者是不同的安裝方式。切換時需規劃使用者端手動遷移(移除 ClickOnce 版、安裝 Velopack setup.exe)
- 本 ADR 範圍內不處理 migration,僅建立 Velopack 發布管線
Alternatives Considered¶
- (拒絕) 複用
<ApplicationVersion>1.0.1.%2a</ApplicationVersion>解析出1.0.1:看似省一個標籤,但兩條發布線(ClickOnce、Velopack)的版本推進節奏不一樣,硬綁會互相干擾。獨立標籤清楚、未來淘汰 ClickOnce 時刪掉對應標籤即可 - (拒絕) 用
[xml]$csproj物件修改後 Save:會重寫整份 XML,縮排、屬性順序、換行全會被 .NET XmlWriter 重排,製造巨大 git diff。regex replace 只動單一標籤,diff 乾淨 - (拒絕) 腳本自動
git push:push 是跨機器可見的破壞性操作,照CLAUDE.md規範不自動做。使用者驗證 release commit 後手動 push - (拒絕) 支援多 channel(darb-vpk / darb-test / cy-erp):本次需求明確只做單一環境,多 channel 等確有需求再擴。避免過早抽象
- (拒絕) 自動
git tag v{version}:使用者未要求,且 tag 推上 remote 後不易回收,保守不做