.gitlab-ci.yml
流水线入口:阶段
stages:
- lint
- test
- build
- deploy
-
流水线以job为单位运行,每个job就是自己想通过流水线做的事情,例如单元测试的job,核心是运行脚本:
go test -short
go list ./...
-
每个阶段下可以定义多个job。
-
同一阶段的job会并行执行。
-
阶段是串行执行。
全局变量
variables:
IMAGE_GROUP: xxx
NAME_SPACE: xxx
GOPATH: ${CI_PROJECT_DIR}/.go
GOMODCACHE: ${CI_PROJECT_DIR}/.go/pkg/mod
GOCACHE: ${CI_PROJECT_DIR}/.go/.cache/go-build
GOLANGCI_LINT_CACHE: ${CI_PROJECT_DIR}/.go/.cache/golangci-lint
- 自定义一些变量,在流水线执行过程中以环境变量的形式存在。
GOPATH
:指定GOPATH为项目目录下的.go
,原因是流水线缓存只能缓存项目目录下的文件。GOMODCACHE
:Go依赖缓存。GOCACHE
:go build 产生的缓存。GOLANGCI_LINT_CACHE
:golangci-lint 代码质量检查工具,也会产生缓存。
公共模板
job公共模板
.template:
image: 172.30.3.150/xxx/go-tools:latest
tags:
- 172.30.3.219-runner
interruptible: true
-
go-tools
:运行流水线的基础镜像,里面封装了go运行环境。- Dockerfile
FROM golang:1.17.9 USER root ENV GOPATH /go ENV PATH ${GOPATH}/bin:$PATH # 设置私服 RUN go env -w GOPRIVATE=xxx.com # 设置忽略私服的https证书校验 RUN go env -w GOINSECURE=xxx.com RUN git config --global http.sslverify false RUN git config --global https.sslverify false RUN go env -w GOPROXY="https://goproxy.cn,direct" RUN go env -w GO111MODULE=on # install docker RUN curl -O https://get.docker.com/builds/Linux/x86_64/docker-latest.tgz \ && tar zxvf docker-latest.tgz \ && cp docker/docker /usr/local/bin/ \ && rm -rf docker docker-latest.tgz
-
tags
:指定运行流水线的gitlab runner。 -
.template
:gitlab流水线会认为.
开头的脚本不是一个job,就不会去执行。这里只是作为脚本模板,后面真正的job会去extends此模板,达到代码复用的效果。 -
interruptible
:支持可中断,例如上一次流水线还没跑完,又触发了一次,这种情况下会取消上一次流水线。还需要勾选gitlab的这个选项:
缓存模板
.go_cache:
cache:
key: go-cache-${CI_PROJECT_PATH_SLUG}
paths:
- .go
- 创建流水线缓存,以项目名称为key,缓存的目录为项目目录下的
.go
。
lint阶段
代码检测job
golangci_lint:
stage: lint
only:
- merge_requests
- /^release\/.*$/
extends:
- .go_cache
- .template
script:
- make golangci_lint
stage
:指定此job属于lint阶段- 触发方式为合并请求下的提交,和以release开头的分支上的提交。
extends
:继承脚本模板,代码复用。script
:job核心内容,指定此job运行的脚本。
test阶段
单元测试、检查数据竞争job
unit_test:
stage: test
only:
- merge_requests
- /^release\/.*$/
extends:
- .go_cache
- .template
cache:
policy: pull
script:
- make unit_test
cache.policy
:默认缓存策略会pull and push,这个job中只使用了缓存,但没有产生缓存,所以不需要上传缓存。
build阶段
打包镜像的job模板
.build_image:
stage: build
only:
- tags
- /^release\/.*$/
extends:
- .go_cache
- .template
打包镜像job
build_xxx_admin_image:
extends:
- .build_image
script:
- make build_admin_app
- make build_admin_image
- make push_admin_image
build_xxx_interface_image:
extends:
- .build_image
script:
- make build_interface_app
- make build_interface_image
- make push_interface_image
build_xxx_job_image:
extends:
- .build_image
script:
- make build_job_app
- make build_job_image
- make push_job_image
build_xxx_task_image:
extends:
- .build_image
script:
- make build_task_app
- make build_task_image
- make push_task_image
- 一个阶段多个job。
deploy阶段
部署到测试环境的job模板
.deploy_to_test_k8s:
stage: deploy
only:
- tags
- /^release\/.*$/
extends:
- .template
image:
name: 172.30.3.150/xxx/kubectl:latest
entrypoint: [ "" ]
-
image
:指定运行此job的基础镜像,覆盖公共模板里的image。 -
172.30.3.150/xxx/kubectl
:封装kubectl
镜像,增加git、make命令。- Dockerfile
FROM bitnami/kubectl USER root RUN apt-get update && apt-get install -y --no-install-recommends \ make git
部署到测试环境job
deploy_admin_to_test_k8s:
extends:
- .deploy_to_test_k8s
needs: [ build_xxx_admin_image ]
script:
- make deploy_admin_to_test_k8s
deploy_interface_to_test_k8s:
extends:
- .deploy_to_test_k8s
needs: [ build_xxx_interface_image ]
script:
- make deploy_interface_to_test_k8s
deploy_job_to_test_k8s:
extends:
- .deploy_to_test_k8s
needs: [ build_xxx_job_image ]
script:
- make deploy_job_to_test_k8s
.deploy_task_to_test_k8s:
extends:
- .deploy_to_test_k8s
needs: [ build_xxx_task_image ]
script:
- make deploy_task_to_test_k8s
needs
:指定依赖关系,流水线默认是一个阶段一个阶段的运行,这里部署admin,只需要admin镜像制作好就运行,而不是等待整个build阶段运行完才执行。
完整的.gitlab-ci.yml
stages:
- lint
- test
- build
- deploy
#定义全局变量
variables:
IMAGE_GROUP: xxx
NAME_SPACE: xxx
GOPATH: ${CI_PROJECT_DIR}/.go
GOMODCACHE: ${CI_PROJECT_DIR}/.go/pkg/mod
GOCACHE: ${CI_PROJECT_DIR}/.go/.cache/go-build
GOLANGCI_LINT_CACHE: ${CI_PROJECT_DIR}/.go/.cache/golangci-lint
########################### 公共模板 ###########################
#job公共模板
.template:
image: 172.30.3.150/xxx/go-tools:latest
tags:
- 172.30.3.219-runner
interruptible: true
#缓存模板
.go_cache:
cache:
key: go-cache-${CI_PROJECT_PATH_SLUG}
paths:
- .go
########################### lint阶段 ###########################
#代码检测job
golangci_lint:
stage: lint
only:
- merge_requests
- /^release\/.*$/
extends:
- .go_cache
- .template
script:
- make golangci_lint
########################### test阶段 ###########################
#单元测试、检查数据竞争job
unit_test:
stage: test
only:
- merge_requests
- /^release\/.*$/
extends:
- .go_cache
- .template
cache:
policy: pull
script:
- make unit_test
########################### build阶段 ###########################
#打包镜像的job模板
.build_image:
stage: build
only:
- tags
- /^release\/.*$/
extends:
- .go_cache
- .template
#打包镜像job
build_xxx_admin_image:
extends:
- .build_image
script:
- make build_admin_app
- make build_admin_image
- make push_admin_image
build_xxx_interface_image:
extends:
- .build_image
script:
- make build_interface_app
- make build_interface_image
- make push_interface_image
build_xxx_job_image:
extends:
- .build_image
script:
- make build_job_app
- make build_job_image
- make push_job_image
build_xxx_task_image:
extends:
- .build_image
script:
- make build_task_app
- make build_task_image
- make push_task_image
########################### deploy阶段 ###########################
#部署到测试环境的job模板
.deploy_to_test_k8s:
stage: deploy
only:
- tags
- /^release\/.*$/
extends:
- .template
image:
name: 172.30.3.150/xxx/kubectl:latest
entrypoint: [ "" ]
#部署到测试环境job
deploy_admin_to_test_k8s:
extends:
- .deploy_to_test_k8s
needs: [ build_xxx_admin_image ]
script:
- make deploy_admin_to_test_k8s
deploy_interface_to_test_k8s:
extends:
- .deploy_to_test_k8s
needs: [ build_xxx_interface_image ]
script:
- make deploy_interface_to_test_k8s
deploy_job_to_test_k8s:
extends:
- .deploy_to_test_k8s
needs: [ build_xxx_job_image ]
script:
- make deploy_job_to_test_k8s
.deploy_task_to_test_k8s:
extends:
- .deploy_to_test_k8s
needs: [ build_xxx_task_image ]
script:
- make deploy_task_to_test_k8s
Makefile
具体的脚本抽取到Makefile里,.gitlab-ci.yml
只做流水线控制。而且Makefile支持任意环境执行,不依赖于gitlab流水线(使用到gitlab流水线变量的除外),开发可在本地运行Makefile的脚本。
VERSION=$(shell git describe --tags --always)
#################################### 代码检查 ####################################
.PHONY: golangci_lint
golangci_lint:
go mod tidy # 必须先下载依赖,否则golangci-lint会报:could not load export data: no export data for
go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.45.0
golangci-lint run -v --timeout=5m --color always --out-format colored-line-number
#################################### 单元测试 ####################################
.PHONY: unit_test
unit_test:
go test -short `go list ./...`
#################################### 构建应用二进制执行文件 ####################################
.PHONY: build_all_app
build_all_app: build_admin_app build_interface_app build_job_app build_task_app
.PHONY: build_admin_app
build_admin_app:
make build_app SUB_MODULE=admin
.PHONY: build_interface_app
build_interface_app:
make build_app SUB_MODULE=interface
.PHONY: build_job_app
build_job_app:
make build_app SUB_MODULE=job
.PHONY: build_task_app
build_task_app:
make build_app SUB_MODULE=task
.PHONY: build_app
build_app:
mkdir -p bin
cd cmd/$(SUB_MODULE) && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-X main.version=$(VERSION)" -o ../../bin/ && cd -
#################################### 打镜像 ####################################
.PHONY: build_all_image
build_all_image: build_admin_image build_interface_image build_job_image build_task_image
.PHONY: build_admin_image
build_admin_image:
make build_image SUB_MODULE=admin
.PHONY: build_interface_image
build_interface_image:
make build_image SUB_MODULE=interface
.PHONY: build_job_image
build_job_image:
make build_image SUB_MODULE=job
.PHONY: build_task_image
build_task_image:
make build_image SUB_MODULE=task
.PHONY: build_image
build_image:
docker build --build-arg SUB_MODULE=$(SUB_MODULE) -t xxx-$(SUB_MODULE):$(VERSION) .
#################################### 推镜像到私仓 ####################################
.PHONY: push_all_image
build_all_image: push_admin_image push_interface_image push_job_image push_task_image
.PHONY: push_admin_image
push_admin_image:
make push_image SUB_MODULE=admin
.PHONY: push_interface_image
push_interface_image:
make push_image SUB_MODULE=interface
.PHONY: push_job_image
push_job_image:
make push_image SUB_MODULE=job
.PHONY: push_task_image
push_task_image:
make push_image SUB_MODULE=task
.PHONY: push_image
push_image:
docker login "${DOCKER_REGISTRY_SERVER}" --username "${DOCKER_REGISTRY_USER}" --password "${DOCKER_REGISTRY_PASSWORD}"
docker tag "xxx-$(SUB_MODULE):$(VERSION)" "${DOCKER_REGISTRY_ADDR}/${IMAGE_GROUP}/xxx-$(SUB_MODULE):$(VERSION)"
docker push "${DOCKER_REGISTRY_ADDR}/${IMAGE_GROUP}/xxx-$(SUB_MODULE):$(VERSION)"
docker rmi -f "${DOCKER_REGISTRY_ADDR}/${IMAGE_GROUP}/xxx-$(SUB_MODULE):$(VERSION)"
docker tag "xxx-$(SUB_MODULE):$(VERSION)" "${DOCKER_REGISTRY_ADDR}/${IMAGE_GROUP}/xxx-$(SUB_MODULE):latest"
docker push "${DOCKER_REGISTRY_ADDR}/${IMAGE_GROUP}/xxx-$(SUB_MODULE):latest"
docker rmi -f "${DOCKER_REGISTRY_ADDR}/${IMAGE_GROUP}/xxx-$(SUB_MODULE):latest"
docker rmi -f "xxx-$(SUB_MODULE):$(VERSION)"
#################################### 部署到k8s ####################################
.PHONY: deploy_all_to_test_k8s
deploy_all_to_test_k8s: deploy_admin_to_test_k8s deploy_interface_to_test_k8s deploy_job_to_test_k8s deploy_task_to_test_k8s
.PHONY: deploy_admin_to_test_k8s
deploy_admin_to_test_k8s:
make deploy_to_test_k8s SUB_MODULE=admin
.PHONY: deploy_interface_to_test_k8s
deploy_interface_to_test_k8s:
make deploy_to_test_k8s SUB_MODULE=interface
.PHONY: deploy_job_to_test_k8s
deploy_job_to_test_k8s:
make deploy_to_test_k8s SUB_MODULE=job
.PHONY: deploy_task_to_test_k8s
deploy_task_to_test_k8s:
make deploy_to_test_k8s SUB_MODULE=task
.PHONY: deploy_to_test_k8s
deploy_to_test_k8s:
echo ${K8S_CONFIG_192} | base64 -id > /.kube/config
sed -i "s/IMAGE_VERSION/$(VERSION)/g" deploy/$(SUB_MODULE)/test/*.yaml
sed -i "s/NAME_SPACE/${NAME_SPACE}/g" deploy/$(SUB_MODULE)/test/*.yaml
sed -i "s/DOCKER_REGISTRY_ADDR/${DOCKER_REGISTRY_ADDR}/g" deploy/$(SUB_MODULE)/test/*.yaml
sed -i "s/IMAGE_GROUP/${IMAGE_GROUP}/g" deploy/$(SUB_MODULE)/test/*.yaml
kubectl apply -f deploy/$(SUB_MODULE)/test
-
VERSION
:此变量用于打镜像的版本号,如果当前分支打了tag,此变量的值就为tag,没有打tag,值为commit hash标识。 -
.PHONY
:伪目标,可以防止在Makefile中定义的命令目标和工作目录下的实际文件出现名字冲突。 -
DOCKER_REGISTRY_SERVER
:在gitlab配置的变量,可根据实际情况,放到不同级别下。例如gitlab全局,项目群组,项目。
更新
Gitlab CI/CD 已在我司使用了 4 个月,期间不断迭代优化,现在基本稳定了。Gitlab CI/CD 系列 的文章是早期的版本,这里更新下20220927最新的情况。
Go 项目里的流水线脚本
.gitlab-ci.yaml
include:
- project: 'devops/gitlab-cicd-template'
ref: main
file: '/golang/golangci-lint/1.48.0/.gitlab-ci.yml'
- project: 'devops/gitlab-cicd-template'
ref: main
file: '/golang/unit-test/.gitlab-ci.yml'
- project: 'devops/gitlab-cicd-template'
ref: main
file: '/golang/build-image/.gitlab-ci.yml'
- project: 'devops/gitlab-cicd-template'
ref: main
file: '/common/deploy-to-k8s/.gitlab-ci.yml'
stages:
- lint
- test
- build
- deploy
variables: &global-variables
# 用于拼接镜像名
MODULE_PREFIX: google-ads
# 镜像私仓里的项目
IMAGE_GROUP: ads
# 部署环境
ENV: test
# 拷贝部署文件到template仓库的目录
TARGET_DIR: ads
########################### build阶段 ###########################
#打包镜像job
build_admin_image:
extends:
- .golang_build_image_base
variables:
<<: *global-variables
SUB_MODULE: admin
build_interface_image:
extends:
- .golang_build_image_base
variables:
<<: *global-variables
SUB_MODULE: interface
build_job_image:
extends:
- .golang_build_image_base
variables:
<<: *global-variables
SUB_MODULE: job
build_task_image:
extends:
- .golang_build_image_base
variables:
<<: *global-variables
SUB_MODULE: task
build_task_pop_image:
extends:
- .golang_build_image_base
variables:
<<: *global-variables
SUB_MODULE: task-pop
########################### deploy阶段 ###########################
#部署到测试环境job
deploy_admin_to_test_k8s:
extends:
- .deploy_to_k8s_base
before_script:
- K8S_CONFIG=$K8S_CONFIG_192
variables:
<<: *global-variables
SUB_MODULE: admin
NAME_SPACE: gator-cloud
needs: [ build_admin_image ]
deploy_interface_to_test_k8s:
extends:
- .deploy_to_k8s_base
before_script:
- K8S_CONFIG=$K8S_CONFIG_192
variables:
<<: *global-variables
SUB_MODULE: interface
NAME_SPACE: gator-cloud
needs: [ build_interface_image ]
deploy_job_to_test_k8s:
extends:
- .deploy_to_k8s_base
before_script:
- K8S_CONFIG=$K8S_CONFIG_192
variables:
<<: *global-variables
SUB_MODULE: job
NAME_SPACE: gator-cloud
needs: [ build_job_image ]
deploy_task_to_test_k8s:
extends:
- .deploy_to_k8s_base
before_script:
- K8S_CONFIG=$K8S_CONFIG_192
variables:
<<: *global-variables
SUB_MODULE: task
NAME_SPACE: gator-cloud
needs: [ build_task_image ]
deploy_task_pop_to_test_k8s:
extends:
- .deploy_to_k8s_base
before_script:
- K8S_CONFIG=($K8S_CONFIG_192 $K8S_CONFIG_222 $K8S_CONFIG_229 $K8S_CONFIG_230)
- NAME_SPACE=(google-cloud google-cloud google-cloud google-cloud)
variables:
<<: *global-variables
SUB_MODULE: task-pop
needs: [ build_task_pop_image ]
公共脚本库
/golang/golangci-lint/1.48.0/.gitlab-ci.yml
# golang1.19版本对应的golang-lint v1.48.0
golangci_lint:
stage: lint
image: 172.1.1.1/common/golangci-lint:1.48.0
tags:
- 172.1.1.2-runner
interruptible: true
variables:
GOLANGCI_LINT_CACHE: /cache/${CI_PROJECT_PATH}/golangci-lint-cache
script:
- mkdir -p $GOLANGCI_LINT_CACHE
- go mod tidy # 必须先下载依赖,否则golangci-lint会报:could not load export data: no export data for
- golangci-lint run -v --timeout=5m
/cache
:是挂载的目录,具体看Gitlab CI/CD 实践三:Docker 安装 Gitlab Runner172.1.1.1
:公司内部镜像私仓地址172.1.1.1/common/golangci-lint:1.48.0
:这里用到的内部镜像,具体看Gitlab CI/CD 实践五:基础镜像 Dockerfile 仓库 CI 流水线配置172.1.1.2-runner
:runner 的 tag
/golang/unit-test/.gitlab-ci.yml
unit_test:
stage: test
image: 172.1.1.1/common/golang:1.19
tags:
- 172.1.1.2-runner
interruptible: true
script:
- go test -short `go list ./...`
/golang/build-image/.gitlab-ci.yml
.build_image: &build_image
docker build --build-arg SUB_MODULE=$SUB_MODULE -t $MODULE_PREFIX-$SUB_MODULE:$VERSION -f $DOCKER_FILE .;
.push_image: &push_image
VERSION=$(git describe --tags --always);
echo "VERSION:$VERSION";
docker login "${DOCKER_REGISTRY_SERVER}" --username "${DOCKER_REGISTRY_USER}" --password "${DOCKER_REGISTRY_PASSWORD}";
docker tag "$MODULE_PREFIX-$SUB_MODULE:$VERSION" "${DOCKER_REGISTRY_ADDR}/${IMAGE_GROUP}/$MODULE_PREFIX-$SUB_MODULE:$VERSION";
docker tag "$MODULE_PREFIX-$SUB_MODULE:$VERSION" "${DOCKER_REGISTRY_ADDR}/${IMAGE_GROUP}/$MODULE_PREFIX-$SUB_MODULE:latest";
docker push "${DOCKER_REGISTRY_ADDR}/${IMAGE_GROUP}/$MODULE_PREFIX-$SUB_MODULE:$VERSION";
docker push "${DOCKER_REGISTRY_ADDR}/${IMAGE_GROUP}/$MODULE_PREFIX-$SUB_MODULE:latest";
docker rmi -f "${DOCKER_REGISTRY_ADDR}/${IMAGE_GROUP}/$MODULE_PREFIX-$SUB_MODULE:$VERSION";
docker rmi -f "${DOCKER_REGISTRY_ADDR}/${IMAGE_GROUP}/$MODULE_PREFIX-$SUB_MODULE:latest";
docker rmi -f "$MODULE_PREFIX-$SUB_MODULE:$VERSION";
.build_image_base:
stage: build
image: 172.1.1.1/common/golang:1.19
tags:
- 172.1.1.2-runner
interruptible: true
variables:
SUB_MODULE: default
MODULE_PREFIX: default
IMAGE_GROUP: default
DOCKER_FILE: Dockerfile
before_script:
- VERSION=$(git describe --tags --always)
- echo "VERSION:$VERSION"
script:
- *build_image
- *push_image
/common/deploy-to-k8s/.gitlab-ci.yml
.deploy_to_k8s: &deploy_to_k8s
VERSION=$(git describe --tags --always);
echo "VERSION:$VERSION";
mkdir -p /.kube;
mkdir -p /root/.kube;
for ((i=0;i<${#K8S_CONFIG[*]};i++)); do
echo "index:$i";
cp -r deploy /tmp;
cd /tmp;
sed -i "s/IMAGE_VERSION/$VERSION/g" deploy/$SUB_MODULE/$ENV/*.yaml;
sed -i "s/NAME_SPACE/${NAME_SPACE[i]}/g" deploy/$SUB_MODULE/$ENV/*.yaml;
sed -i "s/IMAGE_NAME/$MODULE_PREFIX-$SUB_MODULE/g" deploy/$SUB_MODULE/$ENV/*.yaml;
sed -i "s/DOCKER_REGISTRY_ADDR/${DOCKER_REGISTRY_ADDR}/g" deploy/$SUB_MODULE/$ENV/*.yaml;
sed -i "s/IMAGE_GROUP/${IMAGE_GROUP}/g" deploy/$SUB_MODULE/$ENV/*.yaml;
echo ${K8S_CONFIG[i]} | base64 -id > /.kube/config;
echo ${K8S_CONFIG[i]} | base64 -id > /root/.kube/config;
kubectl apply -f deploy/$SUB_MODULE/$ENV;
cd - > /dev/null;
rm -rf /tmp/deploy;
done;
.deploy_to_k8s_base:
stage: deploy
image:
name: 172.1.1.1/common/kubectl:1.19.10
entrypoint: [ "" ]
tags:
- 172.1.1.2-runner
interruptible: true
variables:
SUB_MODULE: default
MODULE_PREFIX: default
IMAGE_GROUP: default
ENV: default
script:
- *deploy_to_k8s
更新
之前代码检查是各个项目里配置的.golangci.yml
,现在打算团队内部统一使用一套lint规则(参考kratos)。——20221011
删除项目里的 .golangci.yml
/golang/golangci-lint/1.48.0/.gitlab-ci.yml
include: '/golang/golangci-lint/lint-rule.yml'
# golang1.19版本对应的golang-lint v1.48.0
golangci_lint:
stage: lint
image: 172.1.1.1/common/golangci-lint:1.48.0
tags:
- 172.1.1.2-runner
interruptible: true
extends:
- .lint_rule
variables:
GOLANGCI_LINT_CACHE: /cache/${CI_PROJECT_PATH}/golangci-lint-cache
script:
- echo "lint 规则参考 kratos"
- echo "注意:当前使用的代码检查规则是gitlab-cicd-template仓库里的/golang/golangci-lint/lint-rule.yml,并不是当前项目里的.golangci.yml"
- mkdir -p $GOLANGCI_LINT_CACHE
- go mod tidy # 必须先下载依赖,否则golangci-lint会报:could not load export data: no export data for
- golangci-lint run -v
/golang/golangci-lint/lint-rule.yml
#CAUTION: Caution: Variables with multiline values are not currently supported due to limitations with the current Auto DevOps scripting environment.
.lint_rule:
before_script:
- |
cat > .golangci.yml <<- 'EOF'
run:
timeout: 5m
modules-download-mode: readonly
linters:
disable-all: true
fast: false
enable:
- bodyclose
- deadcode
- dogsled
- durationcheck
- errcheck
- exportloopref
- govet
- gosimple
- gofmt
- gofumpt
- goconst
- goimports
- gomnd
- gocyclo
- ineffassign
- lll
- prealloc
- revive
- staticcheck
- structcheck
- typecheck
- unused
- varcheck
- whitespace
- wastedassign
- unconvert
# don't enable:
# - asciicheck
# - scopelint
# - gochecknoglobals
# - gocognit
# - godot
# - godox
# - goerr113
# - interfacer
# - maligned
# - nestif
# - prealloc
# - testpackage
# - stylrcheck
# - wsl
linters-settings:
govet:
check-shadowing: true
# whitespace:
# 和gofumpt冲突
# multi-func: true
lll:
line-length: 160
gomnd:
# don't include the "operation", "argument" and "assign"
checks:
- case
- condition
- return
goconst:
ignore-tests: true
gocyclo:
# recommend 10-20
min-complexity: 50
EOF
大佬,由于没找到您的关于或者留言板的评论界面,所以我在这里评论一下。主要是感觉您的博客写的不错,互链一波,以后多多学习!我已加你。
站点名称:浮云翩迁之间
站点地址:https://blognas.hwb0307.com
站点描述:百代繁华一朝都,谁非过客;千秋明月吹角寒,花是主人。
站点图标:https://blognas.hwb0307.com/logo.jpg
好的,已添加。麻烦修改下你友链中我博客的描述:Golang、后端、Leetcode、程序员。谢谢!
已经修改完成 回复这么快(~ ̄▽ ̄)~