如何"優雅"地發佈自己的 go module 模塊到 pkg.go.dev

前言

截止到 go1.13, go 官方推出的包管理工具 go module 已經發布三個版本了,網上也有很多文章介紹如何使用 go module(推薦觀看附錄中Go夜讀的視頻和官方Wiki),但是大部分都是講如何引用別人的 go module 模塊,鮮有提到如何發佈自己的 go module 包的文章。本文將主要介紹如何“優雅”地發佈自己的 go module 模塊。

本文的代碼和命令均在 ubuntu 19.10 中運行,go 的版本為 1.13.5

pkg.go.dev簡介

如何

img

go.dev 是go官方團隊於2019年11月上線的集合go開發資源的網站,包括一些學習課程和一些go的案例,當然最重要的就是提供了go的第三方包的檢索功能。沒錯,他就是用來取代原來的godoc.org的,現在godoc.org上也有提示提醒用戶遷移到pkg.go.dev。在這篇文章中,我們將把go module模塊發佈到pkg.go.dev。

BTW,在我寫這篇文章的時候(2020.02.19),go官方剛好也宣佈了go.dev不久將開源。

發佈第一個版本

這次要發佈的代碼放在github,所以新建一個項目叫how-to-release-go-module, 新增hello.go 文件

為hello.go添加兩個方法和相關注釋

<code>package pkg

import "fmt"

// Hello says hello.
func Hello() {
\tfmt.Println("Hello go mod!")
}

// Bye says bye.
func Bye() {
\tfmt.Println("Bye go mod!")
}/<code>

執行 go mod init 生成go.mod文件

<code>go mod init
go: creating new go.mod: module github.com/YouEclipse/how-to-release-go-module/<code>

內容如下:

<code>module github.com/YouEclipse/how-to-release-go-module

go 1.13/<code>

我們把代碼push 到遠端分支,看起來好像第一個版本就發佈完畢了。我們打開pkg.go.dev搜索一下github.com/YouEclipse/how-to-release-go-module這個包,卻返回未找到這個包。這是為何?

如何

其實在go.dev的about中說的很清楚了,只有通過proxy.golang.org下載包的時候,module才會自動同步到pkg.go.dev。

To add a package or module, simply fetch it from proxy.golang.org.

但是,實際上,proxy.golang.org 國內基本上是無法訪問的,如果我們使用 goproxy.cn,也一樣能夠同步,我沒有研究goproxy的源碼,但是我和goproxy的作者確認過,goproxy的推算行為會用到 proxy.golang.org,所以使用goproxy.cn作為代理也是可行的。

我們可以隨便建一個項目,執行go get -u github.com/YouEclipse/how-to-release-go-module,因為go1.13 go module 已經是默認打開的,所以會默認通過proxy.golang.org拉取。如果不確定是否配置go proxy,可以執行go env和go env -w 命令查看和修改。

<code>go get -u github.com/YouEclipse/how-to-release-go-module
go: finding github.com/YouEclipse/how-to-release-go-module latest
go: downloading github.com/YouEclipse/how-to-release-go-module v0.0.0-20200219150525-4f41ffd1dd8f
go: extracting github.com/YouEclipse/how-to-release-go-module v0.0.0-20200219150525-4f41ffd1dd8f/<code>

當我們成功拉取後,可以在pkg.go.dev再次搜索(具體可能需要等一段時間,大約是十分鐘到半小時的樣子),這時候我們可以看到搜索結果了

如何

如何

看起來似乎我們的第一次發佈大功告成了。我們看看pkg.go.dev包含了的什麼信息:

  • 版本號:由go module自動生成
  • 發佈時間
  • 開源協議
  • commit Hash
  • tag:latest
  • Overview(概覽)
    • 包名
    • 源碼地址
    • README
  • Doc: godoc文檔
  • Subdirectories: 子目錄
  • Versions:已經發布過的版本
  • Imports:引用的包
  • Imported By: 引用此包的moudule
  • Licenses:開源許可證...

到了這裡我們會發現,godoc 和 module的README 都沒有正常顯示,提示 “Doc” not displayed due to license restrictions.和README not displayed due to license restrictions,是說我們的包沒有開源許可證,所以無法顯示。對於這一點,網上有資料提到go官方團隊和他們的律師討論過才做的這個決定,這也是可以理解的。

pkg.go.dev 支持的證書可以在 https://pkg.go.dev/license-policy 查看,我們只要選擇合適的開源協議證書添加到項目中即可(很遺憾,WTFPL並不在支持的開源協議中)。這裡我們選擇Apache2.0協議,添加到項目中,並push 到遠端分支。

在等待一段時間(這裡我等了大約30分鐘)pkg.go.dev 更新後,我們會發現README和doc都可以正常顯示了。這裡生成的doc和godoc.org沒太大的區別,都是基於代碼和註釋生成的,網上也有很多關於生成godoc最佳實踐的文章,這裡不做贅述。

如何

如何

至此,發佈的module包有godoc文檔,有開源許可證,看起來是這麼個樣子,第一個版本至此就算髮布完了。

發佈新版本

其實我們在發佈第一個版本的時候,為了更新license發佈了兩次,但是兩次的版本都是v0.0.0,這麼看起來似乎和go modules版本化的理念背道而馳。go module 實際上是可以通過tag來發布版本的。當我們需要發佈新版本時,對應的,我們需要使用git tag為這個版本打上標籤。假設我們發佈的下個版本是v1.0.0:

<code>git tag v1.0.0/<code>

打上標籤後push到遠端分支,等待一段時間,我們就可以在pkg.go.dev上看到我們發佈的v1.0.0版本了。

如何

(這裡有些奇怪,之前的v0.0.0消失了,不知道什麼原因)

我們執行 go get -u github.com/YouEclipse/how-to-release-go-module 即可獲取最新發布的版本

<code>go get -u github.com/YouEclipse/how-to-release-go-module
go: finding github.com/YouEclipse/how-to-release-go-module v1.0.0
go: downloading github.com/YouEclipse/how-to-release-go-module v1.0.0
go: extracting github.com/YouEclipse/how-to-release-go-module v1.0.0/<code>

發佈breaking changes

在早期沒有go module時,假設我們引用的第三方包的做了breaking changes,API 發生改變,在跑CI或者重新拉取第三方包後,代碼將會編譯失敗。我印象比較深刻的是在2018年左右,go.uuid的API發生了breaking changes,將原來沒有返回err的函數返回了err,而當時我們沒有任何包管理,都是在docker 鏡像更新時通過go get 拉取,這就導致當時我們的CI都跑失敗了。

go官方其實有關於版本控制的最佳實踐,叫做 Semantic Import Version https://github.com/golang/go/wiki/Modules,即語義化版本。關於語義化版本的說明,附錄中官方的Wiki也有介紹,這裡我們按照官方的最佳實踐執行。這裡強調一下Go 官方對於語義化版本的一個基本原則:

If an old package and a new package have the same import path, the new package must be backwards compatible with the old package."

如果舊軟件包和新軟件包具有相同的導入路徑,則新軟件包必須與舊軟件包向後兼容

所以Go官方給了兩個方案,針對進行大版本升級和breaking changes:

  • Major branch 即通過創建version分支和tag進行版本升級
  • Major subdirectory 即通過創建version子目錄來區分不同版本

這裡我們只使用Major branch方案來發布,因為第二種方案看起來很奇怪,而且似乎背離了VCS的意義,所有的版本代碼居然都在一塊,個人不是很推薦。

我們修改原來的代碼,並做出breaking changes.

<code>package pkg

import "fmt"

// Hello says hello.
func Hello() error {
\tfmt.Println("Hello go mod!")
\treturn nil
}

// Bye says bye.
func Bye() error {
\tfmt.Println("Bye go mod!")
\treturn nil
}/<code>

並將import path 改為 v2

<code>module github.com/YouEclipse/how-to-release-go-module/v2

go 1.13/<code>

然後提交代碼,並創建tag

<code>git tag v2.0.0
git push --tags
git push master/<code>

在又等待了一段時間後(pkg.go.dev更新確實是有點慢),可以看到v2版本已經發布了,

如何

這時候我們嘗試在之前的測試項目拉取更新

<code>go get -u github.com/YouEclipse/how-to-release-go-module/<code>

可以看到go.mod中顯示我們使用的依然是v1.0.0,顯然,v1.0.0版本的用戶並沒有受到breaking changes的影響。

如果我們要使用v2.0.0版本,修改go get的路徑為github.com/YouEclipse/how-to-release-go-module/v2即可。

至此,我們的breaking changes版本的發佈也完成了。

添加 go dev badge

大部分的開源的項目我們都可以在README中看到各種小圖標,標識著項目的各種狀態,一般稱之為badge。在pkg.go.dev之前,大部分的go項目都會添加godoc.org的badge引導開發者們去godoc.org查看文檔,但是既然使用了pkg.go.dev,我們自然就應該添加go.dev 的badge。更多的badge和相關設置可以在 https://shields.io/ 查看。

添加badge的方法和markdow添加圖片的方法一樣,只要替換項目在pkg.go.dev的路徑即可

<code>[![go.dev reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=flat-square)](https://pkg.go.dev/url/of/your-module)/<code>

比如github.com/YouEclipse/how-to-release-go-module/v2 這個項目就可以設置成

<code>[![go.dev reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=flat-square)](https://pkg.go.dev/github.com/YouEclipse/how-to-release-go-module?tab=doc)/<code>

效果如下

如何

go.dev reference

這樣,我們的go module 模塊看起來就很完美了。

結語

本文從一個簡單的例子基本覆蓋了發佈go module 模塊到pkg.go.dev可能會遇到的場景,希望能給閱讀此文章的開發者提供幫助。

最後強烈推薦由年輕的大神 盛傲飛開發的 https://goproxy.cn 來作為國內 go module 的代理,速度一流,針對 Go1.13+ 如下配置即可享受它帶來的快感,沒有下載不了的包了。

go env -w GOPROXY=https://goproxy.cn,direct

附錄

1 Go modules Wiki

2 Go夜讀第 61 期 Go Modules、Go Module Proxy 和 goproxy.cn

3 go.dev: serve status badge similar to godoc.org

4 示例項目 how-to-release-go-module

5 Go module機制下升級major版本號的實踐

作者:YouEclipse,授權發佈 原文鏈接:https://juejin.im/post/5e4ccabf6fb9a07ca24f49d4


分享到:


相關文章: