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