<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Gopher一定要會(huì)的代碼自動(dòng)化檢查

          共 8273字,需瀏覽 17分鐘

           ·

          2021-07-29 08:40

          本文講解如何通過 golangci-lintpre-commit 兩大框架,利用 git hooks 實(shí)現(xiàn) Go 語言 git commit 的代碼自動(dòng)化審查。

          靜態(tài)代碼檢查

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

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

          在計(jì)算機(jī)科學(xué)中,lint 是一種工具程序的名稱,它用來標(biāo)記源代碼中,某些可疑的、不具結(jié)構(gòu)性(可能造成bug)的段落。它是一種靜態(tài)程序分析工具,最早適用于C語言,在UNIX平臺(tái)上開發(fā)出來。后來它成為通用術(shù)語,可用于描述在任何一種計(jì)算機(jī)程序語言中,用來標(biāo)記源代碼中有疑義段落的工具。

          而在 Go 語言領(lǐng)域, golangci-lint 是一個(gè)集大成者的 linter 框架。它集成了非常多的 linter,包括了上文提到的幾個(gè),合理使用它可以幫助我們更全面地分析與檢查 Go 代碼。golangci-lint 所支持的 linter 項(xiàng)可以查看頁面 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
          • 默認(rèn)生效的 linters


          • 默認(rèn)不生效 linters


          • linters 的分類

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

          實(shí)例

          下面來展示使用示例,現(xiàn)有以下項(xiàng)目結(jié)構(gòu)代碼

          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}

          這兩個(gè)源碼文件中的代碼都是存在一些問題的。此時(shí),我們通過 golangci-lint 工具來對(duì)源碼文件進(jìn)行檢查

          可以看到,我們?cè)诔绦蚋夸浿袌?zhí)行 golangci-lint run 命令,它等效于 golangci-lint run ./... 。此時(shí),它將 main.gotypecheckDemo.go 中存在的潛在問題都檢測(cè)到了,并標(biāo)記了是何種 linter 檢測(cè)(這里是 typecheck 和 govet 兩種)到的。

          當(dāng)然,也可以通過命令 golangci-lint run dir1 dir2/... dir3/file1.go 對(duì)某特定的文件或文件夾進(jìn)行分析。

          靈活運(yùn)用命令選項(xiàng)
          • 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 生效。

          • 更多命令選項(xiàng),可以通過 golangci-lint run -h 查看

          配置文件

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

          • .golangci.yml

          • .golangci.yaml

          • .golangci.toml

          • .golangci.json

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

          在這里給出一個(gè)比較不錯(cuò)的配置示例文檔

           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

          在項(xiàng)目開發(fā)中,我們都會(huì)使用到 git,因此我們可以將代碼靜態(tài)檢查放在一個(gè) git 觸發(fā)點(diǎn)上,而不用每次寫完代碼手動(dòng)去執(zhí)行 golangci-lint run 命令。這里,我們就需要用到 git hooks。

          git hooks

          git hooks 是 git 的一種鉤子機(jī)制,可以讓用戶在 git 操作的各個(gè)階段執(zhí)行自定義的邏輯。git hooks  在項(xiàng)目根目錄的 .git/hooks 下面配置,配置文件的名稱是固定的,實(shí)質(zhì)上就是一個(gè)個(gè) shell 腳本。根據(jù) git 執(zhí)行體,鉤子被分為客戶端鉤子和服務(wù)端鉤子兩類。

          客戶端鉤子包括:pre-commitprepare-commit-msgcommit-msgpost-commit等,主要用于控制客戶端git的提交工作流。服務(wù)端鉤子:pre-receivepost-receiveupdate,主要在服務(wù)端接收提交對(duì)象時(shí)、推送到服務(wù)器之前調(diào)用。

          注意,以 .sample 結(jié)尾的文件名是官方示例,這些示例腳本是不會(huì)執(zhí)行的,只有重命名后才會(huì)生效(去除 .sample 后綴)。

          而 pre-commit 正如其名一樣,它在 git add 提交之后,運(yùn)行 git commit 時(shí)執(zhí)行,腳本執(zhí)行沒報(bào)錯(cuò)就繼續(xù)提交,反之就駁回提交的操作。

          pre-commit

          試想,如果我們同時(shí)開發(fā)多個(gè)項(xiàng)目,也許項(xiàng)目的所采用的的編程語言并不一樣,那么它們所需要的 git hooks 將不一致,此時(shí)我們是否要手動(dòng)給每個(gè)項(xiàng)目都配置一個(gè)單獨(dú)的 pre-commit 腳本呢,或者我們是否要去手動(dòng)下載每一個(gè)鉤子腳本呢。

          實(shí)際上,并不需要這么麻煩。這里就引出了 pre-commit 框架,它是一個(gè)與語言無關(guān)的用于管理 git hooks 鉤子腳本的工具(雖然采用 Python 開發(fā),但不止于 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
          • 編寫配置文件

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

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

          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 腳本

          運(yùn)行 pre-commit install 命令根據(jù)配置文件安裝

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

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

          • git commit 觸發(fā) golangci-lint 檢查

          首次運(yùn)行時(shí),由于 pre-commit 沒有 golangci-lint 的環(huán)境,會(huì)初始化下載安裝相關(guān)依賴。在下一次 git-commit 的時(shí)候,就不會(huì)有前三行信息了。

          如上圖所示,報(bào)錯(cuò)內(nèi)容和我們手動(dòng)執(zhí)行 golangci-lint run 命令輸出的一樣,只有當(dāng)我們將代碼更改正確,才能順利通過檢查,從而 commit 成功。

          總結(jié)

          代碼質(zhì)量是每位開發(fā)者都必須重視的問題,golangci-lint 提供的一系列 linter 插件能夠在很大程度上幫助 Gopher 及時(shí)發(fā)現(xiàn)與解決潛在 bug。同時(shí),借助 golangci-lint 還可以有效規(guī)范項(xiàng)目組內(nèi)的代碼風(fēng)格,減輕 code review 的心智負(fù)擔(dān),希望 Gopher 們能有效利用它。

          git-commit 工具通過配置文件生成 git hooks 所需要的 pre-commit 鉤子腳本,這可以將通過 golangci-lint 的靜態(tài)代碼檢查工作,由手工動(dòng)作轉(zhuǎn)化為自動(dòng)化流程。上文關(guān)于 git-commit 的介紹比較簡(jiǎn)單,想更詳細(xì)探究的讀者可以直接去官網(wǎng) https://pre-commit.com/index.html 學(xué)習(xí)。其實(shí),這種自動(dòng)化流程我們可以擴(kuò)展得更廣,例如我們可以利用 golangci-lint 規(guī)則防止從項(xiàng)目中拉取不符合標(biāo)準(zhǔn)的代碼進(jìn)入本地代碼庫,這可以在持續(xù)集成 CI 過程中添加它來實(shí)現(xiàn)自動(dòng)化。鑒于篇幅原因,CI 部分的利用,留待讀者自行探究了。

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

          往期精彩文章推薦:

          歡迎大家點(diǎn)贊,留言,轉(zhuǎn)發(fā),轉(zhuǎn)載,感謝大家的相伴與支持

          想加入Go學(xué)習(xí)群請(qǐng)?jiān)诤笈_(tái)回復(fù)【入群

          萬水千山總是情,點(diǎn)個(gè)【在看】行不行

          瀏覽 54
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  人人干人人插人人摸 | 黄片一级二级三级 | 豆花AV网站在线观看 | 黄色国产在线 | 自拍在线韩国 |