跳至內容

版本發布

當變更合併至 main 分支時,Tuist 會自動發布新版本。CLI、伺服器與 Kura 快取伺服器皆透過發布管道(canary、候選版本、穩定版)交付,確保建議安裝保持穩定且更新節奏較慢;切割候選版本並提升為穩定版是每週刻意執行的步驟。App 持續發布(iOS App 僅持續部署至 TestFlight,詳見此處)。

概覽#

我們發布以下主要元件:

  • Tuist CLI - 命令列工具,透過 canary、候選版本與穩定管道交付
  • Tuist Server - 後端服務,採用與 CLI 相同的管道模型交付
  • Kura - 快取伺服器,採用與 CLI 相同的管道模型交付
  • Tuist App - macOS 與 iOS App,持續發布(iOS App 僅持續部署至 TestFlight,詳見此處)

每次推送到 main 都會為 CLI、伺服器與 Kura 發布 canary 預發布版本。這些元件的穩定版本僅在維護者將經過充分驗證的候選版本提升時才會切割,而每週排程會讓三條發布列車同步執行(請參閱發布管道)。App 會在每次推送到 main 時發布穩定版。

運作方式#

1. 提交規範#

我們使用Conventional Commits來組織提交訊息。這讓我們的工具能夠理解變更性質、決定版本遞增,並產生適當的變更紀錄。

格式:type(scope): description

提交類型及其影響#

類型說明版本影響範例
feat新功能或能力次版本遞增(x.Y.z)feat(cli): add support for Swift 6
fix錯誤修正修補版本遞增(x.y.Z)fix(app): resolve crash when opening projects
docs文件變更不發布docs: update installation guide
style程式碼風格變更不發布style: format code with swiftformat
refactor程式碼重構不發布refactor(server): simplify auth logic
perf效能改進修補版本遞增perf(cli): optimize dependency resolution
test測試新增/變更不發布test: add unit tests for cache
chore維護工作不發布chore: update dependencies
ciCI/CD 變更不發布ci: add workflow for releases

對 CLI 而言,這些遞增決定 canary 版本與變更紀錄的分組。穩定的 CLI 版本為手動切割的次版本線(X.Y.0),而穩定修補版本(X.Y.Z)僅來自回溯移植,因此feat或fix會透過下方的管道流程送達 CLI 使用者,而非立即作為穩定版本發布。

破壞性變更#

破壞性變更會觸發主版本遞增(X.0.0),並應在提交內文中標示:

plaintext
feat(cli): change default cache location
BREAKING CHANGE: The cache is now stored in ~/.tuist/cache instead of .tuist-cache.
Users will need to clear their old cache directory.

2. 變更偵測#

每個元件都使用git cliff來:

  • 分析自上次發布以來的提交
  • 依範圍篩選提交(cli、app、server)
  • 判斷是否有可發布的變更
  • 自動產生變更紀錄

3. 發布流程#

當偵測到可發布的變更時:

  1. 版本計算:流程決定下一個版本號
  2. 變更紀錄產生:git cliff 根據提交訊息建立變更紀錄
  3. 建置流程:建置並測試元件
  4. 產物產生:產生發布專屬資產,例如 CLI 套件、校驗和,以及由tuist --experimental-dump-help產生的tuist.spec.jsonCLI 規格
  5. 建立發布:建立包含產物的 GitHub 發布
  6. 分發:將更新推送到套件管理器(例如 CLI 的 Homebrew)

對 App 而言,這會在每次合併時產生穩定版本。對 CLI、伺服器與 Kura 而言,此自動化流程僅產生canary預發布版本;候選版本與穩定版本則在每週發布列車上切割(請參閱發布管道)。

4. 範圍篩選#

每個元件僅在有相關變更時才會發布:

  • CLI:具有(cli)範圍或無範圍的提交
  • App:具有(app)範圍的提交
  • Server:具有(server)範圍的提交

發布管道#

CLI、伺服器與 Kura 不會在每次推送到main時提升為穩定版本。每個元件都透過三個管道交付,讓建議安裝保持穩定且變動緩慢,同時讓早期採用者保留每次提交的建置。使用者可見的文件位於CLI 發布管道與Server 發布管道;本節為維護者操作手冊。

每個元件都使用相同的三個管道:

管道版本切割方式
CanaryX.Y.0-canary.N自動執行,於每次影響元件的推送到main時觸發(<component>-release.yml;對 Kura 而言,當kura/變更時由server-production-deployment.yml呼叫)
候選版本X.Y.0-rc.N每週一,或手動於releases/<component>-<major>.<minor>.x分支上執行(<component>-rc.yml)
穩定X.Y.Z每週一,或手動提升經過充分驗證的 RC(<component>-promote.yml);修補版本透過<component>-backport.yml

Canary 與 RC 建置會以 GitHub 預發布形式發布(絕不標示為「Latest」,絕不在 GHCR 上移動:latest,也絕不推送到 CLI 的 Homebrew),因此套件管理器與映像解析器僅在明確選擇加入時才會採用。Canary 始終針對下一個尚未發布的次版本:一旦切割出 RC 線,main的 canary 就會推進到下一個次版本。

託管 Tuist 不會等待穩定列車:伺服器依提交部署,而託管 canary 與生產環境執行最新的 Kura canary。部署串流在部署前會先發布該 canary,因此kura-release.yml沒有自己的觸發條件。僅對 Kura 發布工具鏈的變更(mise/tasks/kura/**、kura-*.yml工作流程)不會切割 canary。

你從不手動挑選版本號。每個管道的下一個版本都由mise/tasks/<component>/release/channel-version.sh從現有的 git 標籤推导得出,以下工作流程會叫用它。

發布分支依元件命名空間隔離(releases/server-X.Y.x、releases/kura-X.Y.x、CLI 為releases/X.Y.x),因此三個元件的線不會在同一個次版本衝突。

每週排程#

每週一 UTC 06:00,三個元件的提升作業同步執行:CLI 提升至穩定、Server 提升至穩定與Kura 提升至穩定。每個作業都會提升最新且尚未穩定的 RC 線,通常是上週一切割的線。若沒有這樣的線,該作業就不會發布任何內容。

當提升完成時,無論結果為何,其對應的候選版本工作流程(cli-rc.yml、server-rc.yml、kura-rc.yml)會透過workflow_run觸發,並從main切割下一條線。

若任一預定執行失敗或被取消,系統會將訊息張貼至 Slack。當發布分支在其最新 RC 之後仍有提交時,提升會失敗。若要發布該線,請在其上切割新的 RC 並手動提升。否則,下週一會改為提升較新的線。

切割候選版本#

若要在每週排程之外切割新線(請將下方的元件工作流程名稱替換為對應元件):

  1. 以空的branch輸入執行 <Component> 候選版本工作流程(例如server-rc.yml)。
  2. 它會發布X.Y.0-rc.1,並在成功後於建置的提交處建立受保護的releases/<component>-X.Y.x分支。

若要將關鍵修正或回歸問題拉入正在驗證的線,請透過 PR 將其 cherry-pick 到發布分支(流程與回溯移植相同;CI 從不執行 cherry-pick),然後迭代 RC:

  1. 從releases/<component>-X.Y.x建立分支,cherry-pick 該修正,開啟一個 PR 合併回發布分支,解決其中的任何衝突,然後合併。
  2. 再次以branch=releases/<component>-X.Y.x執行候選版本工作流程。它會從分支 HEAD 發布X.Y.0-rc.(N+1)。

驗證中的線會凍結功能:僅允許關鍵修正與回歸修復進入。

提升至穩定版#

若要在每週排程之外提升一條線,請在其 RC 通過充分驗證後:

  1. 以branch=releases/<component>-X.Y.x執行 <Component> 提升至穩定工作流程(例如server-promote.yml)。
  2. 它會使用make_latest=true發布帶有語意化版本標籤的映像,並移動 GHCR 的:latest標籤與 GitHub 的「Latest」指標。CLI 還會更新 Homebrew formula。

除非分支 HEAD 正好是最新 RC 指向的提交,否則提升作業不會執行。因此,若在最後一個 RC 之後有任何修复合併到該線,你必須切割新的 RC 並讓其經過驗證,才能作為穩定版發布。

將修補程式回溯移植到穩定線#

一旦某條線成為穩定版,就使用僅限 CLI 的回溯移植發布工作流程(cli-backport.yml)來發布修補程式:透過 PR 將修補程式 cherry-pick 到releases/X.Y.x,然後以該分支執行工作流程以切割X.Y.(Z+1)。回溯移植絕不會移動「Latest」指標或 Homebrew formula。同時維護兩條線:當前線接受回歸與安全性修正,前一條線僅接受關鍵與安全性修正。其他錯誤修正不會回溯移植,而是隨下一個次版本發布。

對於 Server 與 Kura,請使用Server 回溯移植發布(server-backport.yml)或Kura 回溯移植發布(kura-backport.yml)。提升作業僅發布 RC 的X.Y.0;它無法修補已穩定的線。

  1. 從所選X.Y線上最新發布的穩定元件標籤開始,並針對其現有的releases/server-X.Y.x或releases/kura-X.Y.x分支開啟精準修正 PR。較新的次版本或主要版本發布不會阻礙對維護中線的修補。請避免納入與 main 無關的變更。
  2. 審查並合併來源 PR。抓取遠端發布分支並確認其最終合併頂點,包括元件支援的平台與 TLS 正負向控制。通過合併前檢查的頭部並不代表對其他 squash 或合併提交的確認。
  3. 在獲得獨立的發布核准後,從 main 觸發對應的 backport 工作流程from main,將source_sha設為該精確合格的最終合併尖端,並將base_tag設為目前的穩定標籤,例如[email protected]或[email protected]。工作流程會推導出X.Y.(Z+1);操作人員不會選擇次版本遞增或提升 canary 內容。

規劃階段會刷新精確的遠端分支與基礎標籤,要求所選來源等於分支頂點,拒絕未變動的來源或元件以外的變更、其信任政策輸入與驗證,並鎖定已解析的基礎提交。源自 main 的控制項會在版本化映像與 GitHub 發布前立即重複這些檢查。若來源分支、穩定基礎或可用版本發生變更,請停止並重新確認,而非替換為新來源。

回溯移植使用現有的多平台發布器,且不會移動 GitHub 的「Latest」指標或 GHCR :latest。發布與託管部署是分開的:這些工作流程不會提升託管伺服器或 Kura 叢集,不會繞過 canary 接受程序,也不會確認已安裝的執行環境。建置輔助工具與 Dockerfile 仍來自所選的穩定來源。這些控制項是發布閘門,而非免憑證的建置作業;在建置過程中,最終閘門之前可以上傳未標記的映像摘要。映像與 GitHub 發布並非原子操作:若在映像標籤發布後後續閘門失敗,請檢查部分發布並保留其原始來源與構件。切勿替換現有發布或在其標籤下使用不同的位元組。

撰寫良好的提交訊息#

由於提交訊息會直接影響發布說明,因此撰寫清晰、具描述性的訊息至關重要:

建議做法:#

  • 使用現在式:「add feature」而非「added feature」
  • 簡潔但具描述性
  • 當變更僅限於特定元件時,請包含範圍
  • 在適用時參考議題:fix(cli): resolve build cache issue (#1234)

避免做法:#

  • 使用模糊的訊息,例如「fix bug」或「update code」
  • 在一次提交中混合多個不相關的變更
  • 忘記包含重大變更資訊

重大變更#

對於重大變更,請在提交內文中包含BREAKING CHANGE::

plaintext
feat(cli): change cache directory structure
BREAKING CHANGE: Cache files are now stored in a new directory structure.
Users need to clear their cache after updating.

發布工作流程#

CLI、Server 與 Kura 各自擁有一組管道工作流程,結構相同:

  • <component>-release.yml - 在每次影響元件的推送至main時發布 canary(Kura 的是可重複使用的工作流程,由server-production-deployment.yml在kura/變更時呼叫)
  • <component>-rc.yml - 每週一切割候選版本(透過提升後的workflow_run觸發),或手動切割或迭代
  • <component>-promote.yml - 每週一 UTC 06:00 將待處理的 RC 提升至穩定版,或手動提升經過驗證的 RC
  • <component>-build-publish.yml - 上述三者共用的建置與發布管線

CLI、Server 與 Kura 另外擁有<component>-backport.yml,用於在穩定線上切割修補程式。元件的所有工作流程都透過單一<component>-publish並行群組序列化,因此版本解析與標籤不會競爭。Kura 是例外:其 canary 使用kura-canary-publish,而其 RC、提升與回溯移植使用kura-stable-publish,因此長時間的穩定建置不會阻礙部署串流。標籤命名空間互不相交,因此兩個群組不會衝突。

Helm Chart 與基礎設施映像檔(CAPI operator、runners controller、xcresult processor image、linux runner image 等)仍透過.github/workflows/server-production-deployment.yml發布。它在推送到main時執行,並針對託管部署串流 canary → 驗收測試 → 生產環境,同時在這些基礎設施元件變更時發布它們。App、快取、Gradle 外掛程式、skills、Noora 以及獨立的基礎設施控制器各自擁有專用的*-release.yml工作流程。它們共用變更偵測:mise/tasks/release/components.json宣告每個元件的標籤前綴與包含路徑,而 git cliff 將符合的提交轉換為發布說明。

CLI 建置(cli-build-publish.yml)也會產生並發布tuist.spec.json構件(由tuist --experimental-dump-help產生),以便下游工具能夠使用命令介面。

監控發布#

你可以透過以下方式監控發布:

  • GitHub Releases 頁面
  • GitHub Actions 分頁中的工作流程執行記錄
  • 每個元件目錄中的變更記錄檔案

優點#

這種持續發布方法提供:

  • 快速交付:變更在合併後立即送達使用者
  • 減少瓶頸:無需等待手動發布
  • 清晰溝通:從提交訊息自動產生變更記錄
  • 一致的流程:所有元件採用相同的發布流程
  • 品質保證:僅發布經過測試的變更

疑難排解#

如果發布失敗:

  1. 檢查 GitHub Actions 中失敗工作流程的日誌
  2. 確保你的提交訊息遵循慣例格式
  3. 驗證所有測試皆通過
  4. 確認元件建置成功

對於需要立即發布的緊急修復:

  1. 確保你的提交具有明確的範圍
  2. 合併後,監控發布工作流程
  3. 對於 Server 或 App,修復會在下一次推送時交付;如有需要,觸發手動發布
  4. 對於 CLI,修復會自動進入 canary。若要讓穩定版使用者取得修復,請將其回溯移植至維護中的穩定線(參見將修復回溯移植至穩定線)

App Store 發布#

雖然 CLI 與 Server 遵循上述的持續發布流程,但由於 Apple 的 App Store 審查流程,iOS App是例外:

  • 手動發布:iOS App 發布需要手動提交至 App Store
  • 審查延遲:每次發布都必須經過 Apple 的審查流程,可能需要 1-7 天
  • 批次變更:多個變通常常打包在每次 iOS 發布中
  • TestFlight:Beta 版本可能在 App Store 發布前透過 TestFlight 分發
  • 發布說明:必須根據 App Store 規範專門撰寫

iOS App 仍遵循相同的提交慣例並使用 git cliff 產生變更記錄,但實際向使用者發布的頻率較低,且採用手動排程。