Go lint 實踐
什麼是 lint?
靜態代碼分析。通俗地講,掃描源代碼,在不運行代碼的情況下,找出一些不規範的書寫方式以修正,
例如:if foo != false {...}
這樣的寫法顯然不如 if foo {}
好理解。
lint 程序掃描到這樣的 case 就可以給出提示,敦促開發者修正。下面是一些 lint 能檢測到的問題樣例:
fmt.Sprintf("%d", "123") // 錯誤
fmt.Sprintf("%s", "123") // 正確
for i, _ := range []int{1,2,3}{} // 錯誤
for i := range []int{1,2,3}{} // 正確
a := make([]int, 0, 0) // 錯誤
a := make([]int, 0) // 正確
for _, v := range vs { // 錯誤
vectors = append(vectors, v)
}
vectors = append(vectors, vs...) // 正確
怎樣使用 lint?
-
執行掃描工作的程序是一個 bin 文件(稱爲 linter)。執行它就可以掃描項目源代碼給出提示。
在 Go 生態內的 linter 有很多種,大部分是開源項目提供的,它們能掃描各式各樣的問題如 “廢棄代碼”,“冗餘的寫法”,“調用 deprecated api” 等。 -
經調研,在 Go 開發中最好的選擇不是使用某一種 linter,而是使用 Golangci-lint,他是一個開源的 linter 框架,作用類似手機上的應用市場,你可以通過配置選擇開啓五花八門的 linter,兼顧了使用靈活、功能強大。
-
golangci-lint 的安裝使用見後文。
怎樣將 lint 集成到團隊工作流?
-
團隊工作中代碼倉庫是共享的,一個人跑 lint 沒用,需要大家遵循同一套 lint 規則。
-
具體辦法是,將 linter 的運行加入到 ci 流程中。
任意開發 push 新代碼,都會觸發 lint,結果展示在 merge request 界面。如果存在 bad case,就不允許 merge 到 master 分支。這樣協作項目的代碼就能始終符合 lint 規範。
實踐介紹
背景: 團隊代碼庫,因爲歷史遺留小問題很多,肉眼排查不實際,想到引入 lint 解決該問題。
**ci 工具選擇:**linter 如上介紹使用 Golangci-lint。我們公司使用 Gitlab 作爲源碼管理平臺,ci 工具使用它提供的 Gitlabci。
下面是我自己做的準備工作,
- 安裝 Golangci-lint,命令如下,詳細說明可參考其 README
GOPATH_FIRST=$(echo $(go env GOPATH) | awk -F':' '{ print $1}')
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b ${GOPATH_FIRST}/bin v1.21.0
- 配置 Golangci-lint
在項目根目錄下創建文件.golangci.yml
,這個文件是 golangci-lint 的配置文件,可自定義開啓/關閉哪些linter
、跳過某些文件
、跳過某些lint規則
等。
如無配置文件,Golangci-lint 會開啓一些預設 linter,這些在其文檔內有說明。
下面是我們組一個項目現在的.golangci.yml
內容,
linters:
disable-all: true # 關閉其他linter
enable: # 下面是開啓的linter列表,之後的英文註釋介紹了相應linter的功能
- deadcode # Finds unused code
# - errcheck # Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases
- gosimple # Linter for Go source code that specializes in simplifying a code
- govet # Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string
- ineffassign # Detects when assignments to existing variables are not used
- staticcheck # Staticcheck is a go vet on steroids, applying a ton of static analysis checks
- structcheck # Finds unused struct fields
- typecheck # Like the front-end of a Go compiler, parses and type-checks Go code
- unused # Checks Go code for unused constants, variables, functions and types
- varcheck # Finds unused global variables and constants
- scopelint # Scopelint checks for unpinned variables in go programs
# - golint # Carry out the stylistic conventions put forth in Effective Go and CodeReviewComments
linters-settings:
govet: # 對於linter govet,我們手動開啓了它的某些掃描規則
check-shadowing: true
check-unreachable: true
check-rangeloops: true
check-copylocks: true
- 運行 linter / 修正錯誤
在項目根目錄下運行golangci-lint run
,
該命令會加載.golangci.yml
(如有),執行 lint。如代碼有問題,命令行會輸出錯誤提示,包括犯錯地點、修正方法,有時 linter 提示會比較含糊,拿關鍵字 google 一下能找到詳細說明
- 推廣
爲做到平滑的推廣 lint,在操作時有下面的實踐
-
分批放開 linter,先啓用規則簡單的 linter 例如
deadcode
,unused
,之後開啓規則更嚴格的 linter 例如gosimple
。以使同事逐漸適應。 -
在開啓一個 linter 前,我會手動修復該 linter 對應的的所有錯誤。確保之後發起 mr 的同事只需爲新改動負責。
-
** 與 gitlabci 集成,** 走到這裏 lint 工具的準備就 ok 了,下面要將它和 ci 工具銜接在一起,
-
參考 Gitlabci 文檔,安裝 gitlabci runner
-
將它和 gitlab project 綁定在一起。自行安裝 gitlab runner 有點複雜,我們公司的工程效率團隊提供了公用的 docker runner,我這裏只要做好綁定就行。
-
在項目根目錄下創建一個名爲
.gitlab-ci.yml
的配置文件,這樣每當 push 代碼時,gitlab 檢測到有該文件,就會觸發 runner 執行 ci。我的.gitlab-ci.yml
文件內容如下
image: registry.company.cn/ee/go:1.12.9-4
stages:
- qa
lint:
stage: qa
script:
- golangci-lint runGitLab CI/CD | GitLabimage: registry.company.cn/ee/go:1.12.9-4
stages:
- qa
lint:
stage: qa
script:
- golangci-lint run
轉自:夏路
zhuanlan.zhihu.com/p/143567949
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/yIpgbO2-ednPDspQMblCYQ