golangci-lint 是什么?golangci-lint 是一个 go linters 聚合器,而 linter 是使用工具来对代码提供一些检查,保证提交代码的质量。
为什么不直接使用 golangci-lint ?需要手动执行,在之前使用的过程中,由于项目是多人活动,总是会忘记执行golangci-lint 进行代码检查,当前我自己也是。所以我们希望采用一种隐式的方式来自动执行。那么经过多番思考,采用 git 的 hooks 可以来自动执行一些脚本。
这期间还有一些其他的尝试,不过这个文章主要说 在git中的使用ci-lint,有兴趣的可以移步到为什么最终采用git 本地 hooks 的方式执行golangci-lint?
采用 git 的 hooks 来自动执行检查!前提条件:
请设置 goland 的默认终端为 bash,不然后面执行脚本的时候,可能会不支持。
由于现在采用 git 作为我们的版本管理系统(vcs),而git在执行一些操作之前,允许执行脚本,这就可以让我们来执行一些操作前的代码检查。
项目代码目录:
├── .githooks│ ├── applypatch-msg.sample│ ├── commit-msg.sample│ ├── fsmonitor-watchman.sample│ ├── post-update.sample│ ├── pre-applypatch.sample│ ├── pre-commit│ ├── pre-merge-commit.sample│ ├── pre-push│ ├── pre-rebase.sample│ ├── pre-receive.sample│ ├── prepare-commit-msg.sample│ ├── push-to-checkout.sample│ └── update.sample├── .golangci.yml├── go.mod├── golangci-lint.sh└── init.sh
可以通过项目结构看到,需要在项目根目录增加一个 .githooks 文件夹,
然后增加 .golangci.yml golangci-lint 使用的配置文件,
增加一个 手动执行goalngci-lint的执行脚本golangci-lint.sh,
最后就是项目应用 git hooks 的脚本init.sh,用于初始化这个项目的脚本。
说了这么多,还不知道这个到底是干啥的,先来看一下效果图
在commit的时候会帮助我们进行文件的 fmt:
在push的时候会检查整个项目是否存在有问题的地方:
如果项目存在可能的问题,那么是不会让你 push 的。通过这种方式来保证服务器上的代码都是符合规则的。
使用方式:1. 项目中已经存在这些内容首次通过执行 init.sh 脚本进行项目初始化设置。
这会检查你的环境,如果一些工具不存在,它会自动下载。并会修改默认 git 钩子指向当前项目的 .githooks 文件夹。
好了,就这样,就是这么简单。
2. 新建项目这个怎么搞这都是小问题,复制内容过去吧。
但是在复制这些之前,你一定已经是在一个git 管理的根目录下。
那么下面就开始你的复制吧。
.githooks/pre-commit:
#!/bin/sh## an example hook script to verify what is about to be committed.# called by "git commit" with no arguments. the hook should# exit with non-zero status after issuing an appropriate message if# it wants to stop the commit.## to enable this hook, rename this file to "pre-commit".# 获取所有变化的go文件staged_go_files=$(git diff --cached --name-only --diff-filter=acm | grep .go$)if [ "$staged_go_files" = "" ]; then exit 0fiecho "check gofmt ..."check_fmt=$(gofmt -s -w -l $staged_go_files)if [ -n "${check_fmt##* }" ]; then echo echo -e "these files will be\033[32m gofmt\033[0m formatted:" for file in ${check_fmt[*]}; do echo -e "\033[36m\t$file\033[0m" done git add ${check_fmt//\/n/ } echofiecho "check goimports ..."check_gopls=$(goimports -l -w $staged_go_files)if [ -n "${check_gopls##* }" ]; then echo echo -e "these files will be\033[32m goimports\033[0m formatted:" for file in ${check_gopls[*]}; do echo -e "\033[36m\t$file\033[0m" done git add ${check_gopls//\/n/ } echofiprintf "\033[32m commit succeeded \033[0m\n"echoexit 0
.githooks/pre-push:
#!/bin/sh# an example hook script to verify what is about to be pushed. called by "git# push" after it has checked the remote status, but before anything has been# pushed. if this script exits with a non-zero status nothing will be pushed.## this hook is called with the following parameters:## $1 -- name of the remote to which the push is being done# $2 -- url to which the push is being done## if pushing without using a named remote those arguments will be equal.## information about the commits which are being pushed is supplied as lines to# the standard input in the form:## <local ref> <local oid> <remote ref> <remote oid>## this sample shows how to prevent push of commits where the log message starts# with "wip" (work in progress).#remote="$1"#url="$2"printf "\033[32m 推送前需要检查当前项目可以 go build 通过 \033[0m\n"echo "run golangci-lint..."echo# 运行 golangci-lint 检查工具golangci-lint run ./...if [ $? -ne 0 ]; then printf "\033[31m push failed \033[0m\n" exit 1fiprintf "\033[32m push succeeded \033[0m\n"echoexit 0
golangci-lint.sh
#!/bin/shif ! command -v golangci-lint &>/dev/null; then echo "golangci-lint not installed or available in the path" >&2 echo "install golangci-lint ..." >&2 go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.50.1fi#goland 可直接定位文件golangci-lint run ./... |sed 's/\\/\//g'
init.sh
#!/bin/sh# 检查 go 是否安装checkgoenv() { # go是否安装 if ! command -v go &>/dev/null; then echo "go not installed or available in the path" >&2 echo "please check https://golang.google.cn" >&2 exit 1 fi # go proxy 是否设置 if [ -z $goproxy ]; then echo "go proxy not set in the path" >&2 echo "please set goproxy, https://goproxy.cn,direct || https://goproxy.io,direct" >&2 exit 1 fi echo "go env installed ..."}# 检查 go 相关工具包是否安装checkgolintenv() { if ! command -v goimports &>/dev/null; then echo "goimports not installed or available in the path" >&2 echo "install goimports ..." >&2 go install golang.org/x/tools/cmd/goimports@latest checkgolintenv return fi echo "goimports installed ..."}# 检查 golangci-lint 是否安装checkcilintenv() { if ! command -v golangci-lint &>/dev/null; then echo "golangci-lint not installed or available in the path" >&2 echo "install golangci-lint ..." >&2 go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.50.1 checkcilintenv fi echo "golangci-lint installed ..."}# 初始化钩子配置inithooks() { # 如果当前目录不存在 .githooks 目录,说明位置不对 if [ ! -d ".githooks" ]; then echo "exec incorrect position" exit 1 fi # 检查是否已经设置了 exist=$(git config core.hookspath) if [ -z $exist ]; then # 设置 hooks 默认位置 git config core.hookspath .githooks echo "init git hooks ..." >&2 fi}main() { checkgoenv checkgolintenv checkcilintenv inithooks}main
.golangci.yml
run: timeout: 2m tests: falselinters: disable-all: true enable: - typecheck - staticcheck - govet - gocriticlinters-settings: govet: check-shadowing: true disable-all: true enable: - asmdecl - assign - atomic - atomicalign - bools - buildtag - cgocall - composites - copylocks - httpresponse - loopclosure - lostcancel - nilfunc - nilness - printf - shadow - shift - stdmethods - structtag - tests - unmarshal - unreachable - unsafeptr - unusedresult staticcheck: go: "1.17" checks: [ "all", "-sa3*", "-sa6000", "-sa6001", "-sa6003", "-st*", "st1006", "st1008", "st1016", "-qf1" ] gocritic: enabled-tags: - diagnostic - experimental - opinionated - style enabled-checks: - sliceclear disabled-tags: - performance disabled-checks: - assignop - badlock - badregexp - codegencomment - commentformatting - commentedoutcode - docstub - duparg - dupbranchbody - dupcase - dupimport - exitafterdefer - externalerrorreassign - flagderef - hexliteral - ifelsechain - importshadow - initclause - mapkey - nestingreduce - newderef - redundantsprint - regexpmust - regexppattern - regexpsimplify - ruleguard - sloppylen - sloppytypeassert - sortslice - sprintfquotedstring - sqlquery - stringconcatsimplify - syncmaploadanddelete - toomanyresultschecker - typedeffirst - typeunparen - underef - unlabelstmt - unlambda - unnecessaryblock - unnecessarydefer - yodastyleexpr - whynolint - paramtypecombine - emptystringtest
好了,现在你应该是这样的结构了吧
项目代码目录:
├── .githooks│ ├── pre-commit│ └── pre-push├── .golangci.yml├── golangci-lint.sh└── init.sh
如果不是,请返回到上面在看一下步骤。
这个时候可以执行 init.sh 脚本来初始化了。
最后可以在 https://github.com/ywanbing/golangci仓库中获取代码。
以上就是golangci-lint应用的详细内容。