布完全指南:以 cloud.google.com/go 的 RELEASING 流程與源碼實現(xiàn)為例)
Go 多模塊倉庫版本發(fā)布完全指南以 cloud.google.com/go 的 RELEASING 流程與源碼實現(xiàn)為例【免費下載鏈接】substrateAgent Substrate: the core system項目地址: https://gitcode.com/GitHub_Trending/substrate7/substrate本指南以當(dāng)前倉庫 vendor 目錄下攜帶的 vendor/cloud.google.com/go/RELEASING.md 為核心藍(lán)本系統(tǒng)講解 Google Cloud Go 客戶端庫這種典型「多模塊倉庫」monorepo with multiple Go modules的版本發(fā)布機(jī)制如何定位需要發(fā)布的模塊、如何判斷發(fā)布阻塞、如何走 release-please 自動化流程以及如何在不依賴自動化工具時手動為根模塊與子模塊打 tag。讀完本文你將掌握多模塊倉庫發(fā)布的完整心智模型與可復(fù)制的操作步驟并能對照倉庫中真實的 release-please 配置、版本生成腳本與變更日志理解這套流程在底層是如何運轉(zhuǎn)的。為什么 cloud.google.com/go 需要一套專門的發(fā)布流程cloud.google.com/go并不是一個單一庫而是一棵由多個 Go module 組成的「模塊樹」。Google Cloud Go 客戶端庫的每個模塊對應(yīng)目錄樹中的一個子樹一個模塊可以包含多個庫每個庫往往對應(yīng)一個云服務(wù) API。這一點從當(dāng)前倉庫的 vendor 快照中可以直接得到印證在 vendor/modules.txt 中可以看到cloud.google.com/go根模塊與cloud.google.com/go/auth、cloud.google.com/go/container、cloud.google.com/go/iam、cloud.google.com/go/monitoring、cloud.google.com/go/resourcemanager、cloud.google.com/go/serviceusage、cloud.google.com/go/storage等多個子模塊分別以獨立版本被引入例如根模塊為v0.123.0storage 為v1.62.1而 go.mod 中也同時列出cloud.google.com/go/container v1.49.0、cloud.google.com/go/monitoring v1.24.3等子模塊版本。每個模塊擁有自己的 go.mod、自己的版本號、自己的 tag彼此獨立發(fā)布。這種「多模塊、獨立版本」的設(shè)計帶來一個核心問題改動一個文件該發(fā)哪個模塊的版本RELEASING.md 給出的規(guī)則簡單而嚴(yán)格——如果要發(fā)布的文件屬于某個模塊的目錄樹則必須發(fā)布該文件最近祖先模塊closest ancestor module的新版本。第一步確定要發(fā)布哪個模塊RELEASING.md 給出了兩種判定示例是理解這套規(guī)則最好的入口修改了bigtable/bttest/inmem.go其最近祖先模塊是cloud.google.com/go/bigtable因此應(yīng)發(fā)布cloud.google.com/go/bigtable子模塊的新版本修改了asset/apiv1/asset_client.go其最近祖先模塊是倉庫根模塊cloud.google.com/goasset目錄屬于根模塊因此應(yīng)發(fā)布根模塊的新版本。其中「cloud.google.com/go是倉庫根模塊其余每個模塊都是子模塊」這一事實決定了發(fā)布動作的邊界發(fā)布根模塊對任何子模塊沒有影響反之亦然二者完全獨立。在動手前可以用文檔提供的命令查看倉庫中全部模塊$ cat find . -name go.mod | grep module module cloud.google.com/go/pubsub module cloud.google.com/go/spanner module cloud.google.com/go module cloud.google.com/go/bigtable module cloud.google.com/go/bigquery module cloud.google.com/go/storage module cloud.google.com/go/pubsublite module cloud.google.com/go/firestore module cloud.google.com/go/logging module cloud.google.com/go/internal/gapicgen module cloud.google.com/go/internal/godocfx module cloud.google.com/go/internal/examples/fake module cloud.google.com/go/internal/examples/mock module cloud.google.com/go/datastore值得留意的是即使是internal/...這類目錄只要它擁有自己的 go.mod也會構(gòu)成獨立的子模塊如internal/gapicgen、internal/godocfx同樣遵循「最近祖先模塊」規(guī)則。倉庫中攜帶的 vendor/cloud.google.com/go/go.work 以 Go workspace 的方式列出了一百多個use目錄從./accessapproval到./workstations直觀展示了這個多模塊倉庫的規(guī)?!@解釋了為什么必須依賴工具化、流程化的發(fā)布方式而不是靠人工逐個管理。發(fā)布前置條件測試必須全部通過無論走自動化還是手動流程Kokoro 持續(xù)構(gòu)建中的任何測試失敗都會阻塞發(fā)布。RELEASING.md 特別強(qiáng)調(diào)兩點只要 Kokoro 最近一次構(gòu)建存在失敗就必須先解決再繼續(xù)發(fā)布即使失敗發(fā)生在「即將發(fā)布的模塊之外」的其他子模塊同樣構(gòu)成阻塞——因為多模塊倉庫的構(gòu)建是整體性的。這一「全綠放行」策略避免了發(fā)布一個帶著已知失敗模塊的版本也保證了根模塊與子模塊之間引用的一致性。自動化發(fā)布基于 release-please 的「合并即發(fā)布」當(dāng)前cloud.google.com/go根模塊及全部子模塊都使用 release-please 這類工具做自動化發(fā)布。核心思路是發(fā)布動作收斂為一次 PR 的評審與合并。自動化流程分為四步等待機(jī)器人開 PR當(dāng)存在尚未發(fā)布的改動時release-please 會自動打開一個標(biāo)題形如chore: release X.Y.Z根模塊或chore: release datastore X.Y.Zdatastore 子模塊的 PR其中 X.Y.Z 是下一個待發(fā)布版本號檢查 Kokoro 構(gòu)建查看最近一次持續(xù)構(gòu)建若有失敗先處理即使失敗屬于其他子模塊也不例外評審發(fā)布說明發(fā)布說明由上次發(fā)布以來所有已合并提交的標(biāo)題自動生成如需修改可以直接編輯發(fā)布 PR 中的變更內(nèi)容合并即發(fā)布評審?fù)ㄟ^后合并該 PRrelease-please 會自動完成三件事——更新CHANGES.md、為合并提交打上對應(yīng)版本 tag、草擬一份 GitHub Release 并把CHANGES.md的內(nèi)容復(fù)制為發(fā)布說明。這套配置在倉庫的 vendor 快照中真實存在是理解自動化機(jī)制的絕佳素材。vendor 目錄下同時攜帶了三份 release-please 配置文件對應(yīng)不同歷史階段/不同發(fā)布粒度的策略vendor/cloud.google.com/go/release-please-config.json面向根模塊的配置release-type為go-yoshiseparate-pull-requests為true每個組件單獨開 PRinclude-component-in-tag為false根模塊 tag 不含組件前綴packages中只有一個.組件mainvendor/cloud.google.com/go/release-please-config-yoshi-submodules.json面向全部子模塊的配置include-component-in-tag為true、tag-separator為/packages枚舉了從 accessapproval 到 workstations 的數(shù)百個組件每個組件目錄對應(yīng)一個發(fā)布單元這解釋了子模塊 tag 為什么形如datastore/vX.Y.Zvendor/cloud.google.com/go/release-please-config-individual.json僅針對少量重量級子模塊auth、bigquery、bigtable、datastore、firestore、logging、pubsub、spanner、storage、vertexai 等單獨管理并對bigquery、pubsub通過exclude-paths排除其/v2目錄避免與 v2 子模塊的發(fā)布范圍沖突。三份配置都以go-yoshi為 release-type 并掛載sentence-case插件將提交標(biāo)題規(guī)范化為句子大小寫用于生成發(fā)布說明展示了同一個倉庫在不同階段、不同粒度下對自動化發(fā)布邊界的靈活切分。從輸出物看vendor/cloud.google.com/go/CHANGES.md 就是這套機(jī)制長期運行的產(chǎn)物它以## 版本號 (發(fā)布日期)為章節(jié)頭按### Features/### Bug Fixes組織條目每條都標(biāo)注影響組件如**internal/stategen:**并附帶提交哈?!@正是「從合并提交標(biāo)題自動生成發(fā)布說明」的最終形態(tài)。手動發(fā)布根模塊當(dāng)自動化流程不可用時如果 release-please 自動化流程因故無法工作RELEASING.md 提供了完整的手動兜底方案。以發(fā)布cloud.google.com/go根模塊為例檢查 Kokoro 構(gòu)建確認(rèn)最近一次構(gòu)建無失敗否則先修復(fù)準(zhǔn)備代碼切換到google-cloud-go/倉庫的 main 分支并git pull確定新舊版本號git tag -l | grep -v beta | grep -v alpha取最大的 tag 為當(dāng)前版本$CV形如vX.Y.Z。注意忽略所有LIB/vX.Y.Z形式的 tag——那是具體某個庫的 tag不是根模塊版本。新版本記為$NV盤點變更執(zhí)行g(shù)it log $CV...列出上次發(fā)布以來的全部提交并手動篩掉子模塊的改動git log會混入子模塊內(nèi)容它們不屬于本次根模塊發(fā)布更新變更日志編輯根目錄CHANGES.md寫入本次變更摘要更新版本日期編輯internal/version/version.go把const Repo改為當(dāng)天日期格式Y(jié)YYYMMDD重新生成版本文件在internal/version目錄執(zhí)行g(shù)o generate提交并開 PR提交改動忽略生成的.go-r文件推送到 fork創(chuàng)建標(biāo)題為chore: release $NV的 PR等待評審合并合并后打 tag 發(fā)布期間不要合并其他 PRgit pull切回 main 并同步git tag $NV打上新版本 taggit push origin $NV推送 tag更新 Releases 頁面把CHANGES.md的內(nèi)容復(fù)制為 GitHub Release 發(fā)布說明。這套手動流程中internal/version/version.go與go generate是值得展開的源碼細(xì)節(jié)。在倉庫攜帶的 vendor/cloud.google.com/go/internal/version/version.go 中第 15 行是//go:generate ./update_version.sh聲明了生成命令第 28-29 行是const Repo 20201104注釋明確要求該值格式為YYYYMMDD日期——這正是 RELEASING.md 第 6 步要修改的目標(biāo)該包注釋說明Repo表示客戶端庫當(dāng)前版本會作為請求頭上報給 Google Cloud 服務(wù)端因此發(fā)布時更新它是為了讓服務(wù)端能識別客戶端版本。而 vendor/cloud.google.com/go/internal/version/update_version.sh 就是go generate實際執(zhí)行的腳本它用date %Y%m%d取當(dāng)天日期再通過sed -i把version.go中形如const Repo ([0-9]{8})的日期替換為今天——整個「更新版本→重新生成」一步到位與手動流程第 6、7 步完全對應(yīng)。手動發(fā)布子模塊以 datastore 為例子模塊的手動發(fā)布與根模塊同構(gòu)差異集中在 tag 格式與變更范圍界定上。RELEASING.md 以cloud.google.com/go/datastore為例給出了完整步驟檢查 Kokoro 構(gòu)建確認(rèn)無失敗含其他子模塊的失敗準(zhǔn)備代碼切到 main 分支并git pull確定新舊版本號git tag -l | grep datastore | grep -v beta | grep -v alpha取最大的 tag 為$CV形如datastore/vX.Y.Z新版本為$NV盤點變更執(zhí)行g(shù)it log $CV.. -- datastore/——與根模塊不同這里通過路徑限定參數(shù)-- datastore/只列出該子模塊目錄內(nèi)的提交不需要人工篩選更新變更日志編輯datastore/CHANGES.md寫入摘要注意是子模塊自己的 CHANGES.md重新生成版本文件在internal/version目錄執(zhí)行g(shù)o generate與根模塊共享同一個版本包提交并開 PR提交改動忽略生成的.go-r文件推送 forkPR 標(biāo)題格式為chore(datastore): release $NV合并后打 taggit pull→git tag $NV→git push origin $NV更新 Releases 頁面復(fù)制datastore/CHANGES.md內(nèi)容到 GitHub Release。對比根模塊與子模塊的流程可以看到一個清晰的設(shè)計分層版本號機(jī)制統(tǒng)一SemVer 可選日期后綴、tag 命名空間按模塊隔離vX.Y.Zvsdatastore/vX.Y.Z、變更范圍通過目錄過濾收斂。這套約定保證了在多模塊倉庫中g(shù)o get一個子模塊時只會看到與該模塊相關(guān)的版本歷史。這套機(jī)制對使用方意味著什么理解發(fā)布流程對下游使用者同樣有實際價值尤其是本倉庫這類把cloud.google.com/go作為 vendor 依賴的項目版本獨立更新根模塊與各子模塊版本互不耦合。例如本倉庫 go.mod 中cloud.google.com/go/container v1.49.0與cloud.google.com/go v0.123.0分屬不同模塊的不同版本線升級其中一個不需要連帶升級另一個vendor 快照與版本一一對應(yīng)vendor/modules.txt 頂部# cloud.google.com/go v0.123.0之類的標(biāo)記正是發(fā)布流程打出的 tag 在消費端的落點CHANGES.md中的 Features/Bug Fixes 條目則可用于判斷某個上游版本是否包含你關(guān)心的修復(fù)internal/version的副作用Repo日期會隨客戶端請求頭發(fā)送給 Google 服務(wù)端因此廠商會持續(xù)發(fā)布新版本以攜帶最新日期下游如需固定行為應(yīng)以 go.mod 中鎖定的版本為準(zhǔn)。對于維護(hù)多模塊 Go 倉庫的開發(fā)者這套流程的核心啟示可以濃縮為三點用「最近祖先模塊」規(guī)則收斂發(fā)布邊界用自動化release-please 合并即發(fā)布把發(fā)布動作原子化用統(tǒng)一的 tag 命名空間與目錄過濾保證多模塊版本互不干擾。必要時根模塊與子模塊的手動發(fā)布步驟就是最可靠的回退方案?!久赓M下載鏈接】substrateAgent Substrate: the core system項目地址: https://gitcode.com/GitHub_Trending/substrate7/substrate創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考