Gopher一定要會的代碼自動化檢查

本文講解如何通過 golangci-lintpre-commit 兩大框架,利用 git hooks 實現 Go 語言 git commit 的代碼自動化審查。

靜態代碼檢查

靜態代碼檢查是一個老生常態的問題,它能很大程度上保證代碼質量。Go 語言自帶套件爲我們提供了靜態代碼分析工具 vet,它能用於檢查 go 項目中可以通過編譯但仍可能存在錯誤的代碼,不瞭解的讀者可以查看之前 文章 的介紹。除了 go vet,不少 Gopher 也許還知道用於自動導包的 goimports 工具,用於格式化代碼的 gofmt,還有已經停止更新的用於檢查代碼命令錯誤等的 golint 工具。

以上談到的工具,我們可以稱之爲 linter。在這裏,我們首先需要知道什麼是 lint。在維基百科是如下定義 lint 的:

在計算機科學中,lint 是一種工具程序的名稱,它用來標記源代碼中,某些可疑的、不具結構性(可能造成bug)的段落。它是一種靜態程序分析工具,最早適用於C語言,在UNIX平臺上開發出來。後來它成爲通用術語,可用於描述在任何一種計算機程序語言中,用來標記源代碼中有疑義段落的工具。

而在 Go 語言領域, golangci-lint 是一個集大成者的 linter 框架。它集成了非常多的 linter,包括了上文提到的幾個,合理使用它可以幫助我們更全面地分析與檢查 Go 代碼。golangci-lint 所支持的 linter 項可以查看頁面 https://golangci-lint.run/usage/linters/#golint

使用 golangci-lint

下載
1go get github.com/golangci/golangci-lint/cmd/golangci-lint@latest
檢查安裝成功
1$ golangci-lint version
2golangci-lint has version v1.41.1 built from (unknown, mod sum: "h1:KH28pTSqRu6DTXIAANl1sPXNCmqg4VEH21z6G9Wj4SM=") on (unknown)
查看幫助文檔
1$ golangci-lint help linters
  • 默認生效的 linters


  • 默認不生效 linters


  • linters 的分類

可以看出,golangci-lint 框架支持的 linter 非常全面,它包括了 bugs、error、format、unused、module 等常見類別的分析 linter。

實例

下面來展示使用示例,現有以下項目結構代碼

1.
2├── go.mod
3├── main.go
4└── typecheck
5    └── typecheckDemo.go

其中 main.go 中的代碼如下

 1package main
2
3import (
4    "fmt"
5)
6
7func main() {
8    s1 := "this is a string"
9    fmt.Printf("inappropriate formate %s\n", &s1)
10
11    i := 1
12    fmt.Println(i != 0 || i != 1)
13
14    arr := []int{123}
15    for _, i := range arr {
16        go func() {
17            fmt.Println(i)
18        }()
19    }
20}

typecheckDemo.go 中的代碼

 1package typecheck
2
3import "fmt"
4
5func check() {
6    t := unexistType{}
7    fmt.Println(t)
8}
9
10func unused() {
11    i := 1
12}

這兩個源碼文件中的代碼都是存在一些問題的。此時,我們通過 golangci-lint 工具來對源碼文件進行檢查

可以看到,我們在程序根目錄中執行 golangci-lint run 命令,它等效於 golangci-lint run ./... 。此時,它將 main.gotypecheckDemo.go 中存在的潛在問題都檢測到了,並標記了是何種 linter 檢測(這裏是 typecheck 和 govet 兩種)到的。

當然,也可以通過命令 golangci-lint run dir1 dir2/... dir3/file1.go 對某特定的文件或文件夾進行分析。

靈活運用命令選項
  • golangci-lint 可以通過 -E/--enable 去開啓指定 linter,或者 -D/--disable 禁止指定 linter。

1golangci-lint run --disable-all -E errcheck

如上命令代表的就是除了 errcheck 的 linter,禁止其他所有的 linter 生效。

  • golangci-lint 還可以通過 -p/--preset 指定一系列 linter 開啓。

1golangci-lint run -p bugs -p error

如上命令代表的就是所有屬於 bugserror 分類的 linter 生效。

  • 更多命令選項,可以通過 golangci-lint run -h 查看

配置文件

當然,如果我們要爲項目配置 golangci-lint,最好的方式還是配置文件。golangci-lint 在當前工作目錄按如下順序搜索配置文件。

  • .golangci.yml

  • .golangci.yaml

  • .golangci.toml

  • .golangci.json

在 golangci-lint 官方文檔 https://golangci-lint.run/usage/configuration/#config-file 中,提供了一個示例配置文件,非常地詳細,在這其中包含了所有支持的選項、描述和默認值。

在這裏給出一個比較不錯的配置示例文檔

 1linters-settings:
2  errcheck:
3    check-type-assertions: true
4  goconst:
5    min-len: 2
6    min-occurrences: 3
7  gocritic:
8    enabled-tags:
9      - diagnostic
10      - experimental
11      - opinionated
12      - performance
13      - style
14  govet:
15    check-shadowing: true
16  nolintlint:
17    require-explanation: true
18    require-specific: true
19
20linters:
21  disable-all: true
22  enable:
23    - bodyclose
24    - deadcode
25    - depguard
26    - dogsled
27    - dupl
28    - errcheck
29    - exportloopref
30    - exhaustive
31    - goconst
32    - gocritic
33    - gofmt
34    - goimports
35    - gomnd
36    - gocyclo
37    - gosec
38    - gosimple
39    - govet
40    - ineffassign
41    - misspell
42    - nolintlint
43    - nakedret
44    - prealloc
45    - predeclared
46    - revive
47    - staticcheck
48    - structcheck
49    - stylecheck
50    - thelper
51    - tparallel
52    - typecheck
53    - unconvert
54    - unparam
55    - varcheck
56    - whitespace
57    - wsl
58
59run:
60  issues-exit-code: 1

使用 pre-commit hook

在項目開發中,我們都會使用到 git,因此我們可以將代碼靜態檢查放在一個 git 觸發點上,而不用每次寫完代碼手動去執行 golangci-lint run 命令。這裏,我們就需要用到 git hooks。

git hooks

git hooks 是 git 的一種鉤子機制,可以讓用戶在 git 操作的各個階段執行自定義的邏輯。git hooks  在項目根目錄的 .git/hooks 下面配置,配置文件的名稱是固定的,實質上就是一個個 shell 腳本。根據 git 執行體,鉤子被分爲客戶端鉤子和服務端鉤子兩類。

客戶端鉤子包括:pre-commitprepare-commit-msgcommit-msgpost-commit等,主要用於控制客戶端git的提交工作流。服務端鉤子:pre-receivepost-receiveupdate,主要在服務端接收提交對象時、推送到服務器之前調用。

注意,以 .sample 結尾的文件名是官方示例,這些示例腳本是不會執行的,只有重命名後纔會生效(去除 .sample 後綴)。

而 pre-commit 正如其名一樣,它在 git add 提交之後,運行 git commit 時執行,腳本執行沒報錯就繼續提交,反之就駁回提交的操作。

pre-commit

試想,如果我們同時開發多個項目,也許項目的所採用的的編程語言並不一樣,那麼它們所需要的 git hooks 將不一致,此時我們是否要手動給每個項目都配置一個單獨的 pre-commit 腳本呢,或者我們是否要去手動下載每一個鉤子腳本呢。

實際上,並不需要這麼麻煩。這裏就引出了 pre-commit 框架,它是一個與語言無關的用於管理 git hooks 鉤子腳本的工具(雖然採用 Python 開發,但不止於 Python )。

  • 安裝

1$ pip install pre-commit
2或者
3$ curl https://pre-commit.com/install-local.py | python -
4或者
5$ brew install pre-commit
  • 安裝成功

1$ pre-commit --version
2pre-commit 1.20.0
  • 編寫配置文件

首先我們在項目根目錄下新建一個 .pre-commit-config.yaml 文件,這個文件我們可以通過 pre-commit sample-config 得到最基本的配置模板,通過 pre-commit 支持的 hooks 列表 https://pre-commit.com/hooks.html 中,我們找到了 golangci-lint。

因此,使用 golangci-lint 的 .pre-commit-config.yaml 配置內容如下

1repos:
2-   repo: https://github.com/golangci/golangci-lint
3    rev: v1.41.1 # the current latest version
4    hooks:
5    -   id: golangci-lint
  • 安裝 git hook 腳本

運行 pre-commit install 命令根據配置文件安裝

1$ pre-commit install
2pre-commit installed at .git/hooks/pre-commit

此時,生成了新的 Python 語言編寫的 .git/hooks/pre-commit 鉤子文件。

  • git commit 觸發 golangci-lint 檢查

首次運行時,由於 pre-commit 沒有 golangci-lint 的環境,會初始化下載安裝相關依賴。在下一次 git-commit 的時候,就不會有前三行信息了。

如上圖所示,報錯內容和我們手動執行 golangci-lint run 命令輸出的一樣,只有當我們將代碼更改正確,才能順利通過檢查,從而 commit 成功。

總結

代碼質量是每位開發者都必須重視的問題,golangci-lint 提供的一系列 linter 插件能夠在很大程度上幫助 Gopher 及時發現與解決潛在 bug。同時,藉助 golangci-lint 還可以有效規範項目組內的代碼風格,減輕 code review 的心智負擔,希望 Gopher 們能有效利用它。

git-commit 工具通過配置文件生成 git hooks 所需要的 pre-commit 鉤子腳本,這可以將通過 golangci-lint 的靜態代碼檢查工作,由手工動作轉化爲自動化流程。上文關於 git-commit 的介紹比較簡單,想更詳細探究的讀者可以直接去官網 https://pre-commit.com/index.html 學習。其實,這種自動化流程我們可以擴展得更廣,例如我們可以利用 golangci-lint 規則防止從項目中拉取不符合標準的代碼進入本地代碼庫,這可以在持續集成 CI 過程中添加它來實現自動化。鑑於篇幅原因,CI 部分的利用,留待讀者自行探究了。

------------------- End -------------------

往期精彩文章推薦:

歡迎大家點贊,留言,轉發,轉載,感謝大家的相伴與支持

想加入Go學習羣請在後臺回覆【入羣

萬水千山總是情,點個【在看】行不行

本文分享自微信公衆號 - Go語言進階學習(gh_dced3d6523fb)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章