Go 部落格
發佈 Go 模組
簡介
這篇文章是分篇連載的第 3 篇。
- 第 1 篇 — 使用 Go 模組
- 第 2 篇 — 移轉至 Go 模組
- 第 3 篇 — 發佈 Go 模組(此篇貼文)
- 第 4 篇 — Go 模組:第 2 版及後續版本
- 第 5 篇 — 保持模組相容性
注意:如需開發模組的文件,請參閱 開發並發佈模組。
此文將討論如何撰寫及發佈模組,讓其他模組可依賴它們。
請注意:這篇文章報導的開發版本包含 v1
。如果您有興趣瞭解 v2
,請參閱 Go 模組:第 2 版及後續版本。
本篇文章範例中使用 Git,也支援 Mercurial、Bazaar 及其他版本控制軟體。
專案設定
在看這篇文章時,您需要一個現有的專案做為範例。因此,可使用 使用 Go 模組 文章最後面的檔案
$ cat go.mod
module example.com/hello
go 1.12
require rsc.io/quote/v3 v3.1.0
$ cat go.sum
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:qgOY6WgZOaTkIIMiVjBQcw93ERBE4m30iBm00nkL0i8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
$ cat hello.go
package hello
import "rsc.io/quote/v3"
func Hello() string {
return quote.HelloV3()
}
func Proverb() string {
return quote.Concurrency()
}
$ cat hello_test.go
package hello
import (
"testing"
)
func TestHello(t *testing.T) {
want := "Hello, world."
if got := Hello(); got != want {
t.Errorf("Hello() = %q, want %q", got, want)
}
}
func TestProverb(t *testing.T) {
want := "Concurrency is not parallelism."
if got := Proverb(); got != want {
t.Errorf("Proverb() = %q, want %q", got, want)
}
}
$
接著,建立一個新的 git
存放庫並新增初始提交。如果您要發佈自己的專案,請務必包含一個 LICENSE
檔案。變更到含有 go.mod
的目錄,然後建立存放庫
$ git init
$ git add LICENSE go.mod go.sum hello.go hello_test.go
$ git commit -m "hello: initial commit"
$
語意化版本與模組
go.mod
中的每個必備模組都有 語意化版本,這個版本是建置模組所使用的相依項目的最低版本。
語意化版本的形式為 vMAJOR.MINOR.PATCH
。
- 當您對模組的公開 API 進行 向後不相容 的變更時,請增加
MAJOR
版本。這只有在絕對有必要時才應該執行。 - 當您對 API 進行向後相容的變更,例如變更相依項目或新增新的函式、方法、結構欄位或類型時,請增加
MINOR
版本。 - 在進行不影響模組的公開 API 或相依項目的次要變更,例如修正錯誤後,請增加
PATCH
版本。
您可以透過附加連字號和以句點分隔的識別碼 (例如 v1.0.1-alpha
或 v2.2.2-beta.2
) 來指定預發行版本。go
指令比較喜歡一般發行版本,而不是預發行版本,因此如果您的模組有任何一般發行版本,使用者必須明確要求預發行版本 (例如 go get example.com/hello@v1.0.1-alpha
)。
v0
主要版本與預發行版本不保證向後相容性。在對使用者做出穩定性承諾之前,您可以用它們來改善您的 API。不過,v1
主要版本及更高版本則需要在那一個主要版本內具有向後相容性。
go.mod
中所引用的版本可能是存放庫中明確標記的發行版本 (例如 v1.5.2
),或基於特定提交的 擬版本 (例如 v0.0.0-20170915032832-14c0d48ead0c
)。擬版本是預發行版本的特例。當使用者需要依賴尚未發佈任何語意化版本標記的專案,或針對尚未標記的提交進行開發時,擬版本會很有用,但使用者不應假設擬版本會提供穩定或測試完善的 API。以明確版本標記您的模組會向您的使用者發出訊號,表示特定版本已充分測試,而且已經準備好使用。
一旦您開始以版本標記儲存庫,在開發模組的過程中,持續標記新的發行版本非常重要。當使用者要求模組的新版本 (使用 go get -u
或 go get example.com/hello
) 時,go
指令會選擇可用的最大語意化發行版本,即使該版本已有好幾年歷史,而且許多變更都落後於主要分支。持續標記新的發行版本會讓您的使用者可用於持續改進的功能。
不要從儲存庫中刪除版本標籤。如果您發現某個版本的錯誤或安全性問題,請發布一個新版本。如果其他人依賴您已刪除的版本,它們的建置可能會失敗。同樣地,一旦您發布一個版本,就不要變更或覆寫它。模組鏡像和雜湊資料庫會儲存模組、模組的版本和帶有簽名的加密雜湊,以確保特定版本可以長期重複建置。
v0:最初的不穩定版本
讓我們使用語義化版本 v0
標記這個模組。v0
版本無法保證穩定性,所以幾乎所有專案都應從v0
開始,同時逐漸完善公開 API。
標記新版本有幾個步驟
-
執行
go mod tidy
,移除模組中任何可能已累積但不再必要的相依性。 -
最後一次執行
go test ./...
,確保一切正常。 -
使用
git tag
標記專案,使用新版本。 -
將新的標籤推送到起源儲存庫。
$ go mod tidy
$ go test ./...
ok example.com/hello 0.015s
$ git add go.mod go.sum hello.go hello_test.go
$ git commit -m "hello: changes for v0.1.0"
$ git tag v0.1.0
$ git push origin v0.1.0
$
現在其他專案可以依賴於example.com/hello
的v0.1.0
。對於您自己的模組,您可以執行 go list -m example.com/hello@v0.1.0
,確認可以使用最新版本(這個模組範例不存在,所以無法取得任何版本)。如果您沒有立即看到最新版本,而且您使用 Go 模組代理(從 Go 1.13 開始的預設值),請在幾分鐘後再試一次,讓代理伺服器有時間載入新版本。
如果您新增到公共 API,對v0
模組進行重大變更,或是升級依賴項的次要或版本,請為下一個版本增加次要
版本。例如,v0.1.0
之後的下一個版本將會是v0.2.0
。
如果您修正先前版本的錯誤,請增加修補
版本。例如,v0.1.0
之後的下一個版本將會是v0.1.1
。
v1:第一個穩定版本
當您對模組的 API 絕對有把握後,可以發布v1.0.0
。主版本號v1
傳達給使用者模組的 API 將不會進行不相容變更。他們可以升級到新的v1
次要版本和修補版本,而他們的程式碼不應會中斷。函式和方法簽名不會變更,匯出的類型不會被移除,依此類推。如果有 API 變更,它們將會向下相容(例如,新增欄位到結構),並包含在新次要版本中。如果有些錯誤修正(例如,安全性修正),它們將包含在修補版本中(或包含在次要版本中)。
有時候,維護向後相容性可能會造成不順手的 API。這很正常。不完美的 API 也優於破壞使用者的現有程式碼。
標準程式庫的 strings
套件就是為了維持向後相容性以成本 API 一致性而有的絕佳範例。
不過,Replace
計算的是要從頭開始取代的字串有幾個執行個體(不像 Split
)。
根據 Split
和 SplitN
,您會預期看到像 Replace
和 ReplaceN
這樣的函式。但是,在不破壞呼叫方(我們承諾不這麼做)的情況下,我們並無法變更現有的 Replace
。因此,在 Go 1.12 中,我們新增了新函式,ReplaceAll
。產生的 API 稍嫌奇怪,因為 Split
和 Replace
的行為不同,但這種不一致的性優於強制變更。
假設您滿意 example.com/hello
的 API,並且想要將 v1
發布為第一個穩定版本。
加上 v1
標籤所使用的程序與加上 v0
版本標籤的程序相同:執行 go mod tidy
和 go test ./...
,加上版本標籤,並將標籤推送到原始程式庫
$ go mod tidy
$ go test ./...
ok example.com/hello 0.015s
$ git add go.mod go.sum hello.go hello_test.go
$ git commit -m "hello: changes for v1.0.0"
$ git tag v1.0.0
$ git push origin v1.0.0
$
此時,example.com/hello
的 v1
API 已確定。這傳達給大家的訊息是我們的 API 穩定,他們可以放心地使用。
結論
本文詳細說明加上語意化版本模組標籤的程序,以及何時要發布 v1
。後續的文章將說明如何在 v2
及其後續版本維護和發布模組。
為了提供回饋並協助做好 Go 相依性管理的未來規劃,請寄送 錯誤報告 或 經驗報告 給我們。
感謝您提供的所有回饋和協助改進 Go 模組。
下一篇文章: 使用 Go 1.13 中的錯誤
前一篇文章: Go 1.13 已發布
部落格索引