xx公司 CI阶段在gitlab完成

xx的git flow: 所有feature基于master切出,完成开发后(uat环境,pre环境,原则上只能部署类似creative/test、creative/pre,creative-job/test,creative-job/pre这样的分支)。 用test(或pre分支)分支merge feature分支,部署test(或pre)进行测试。如果多人开发中有冲突,则解决。 最后用master来merge这个feature分支 (即 将feature分支合入master;feature一般如 creative/add_note_switch这样来命名)。


之后到gitlab页面,会有一合入master的选项。 代码提交后ep机器人会自动进行一系列检查(即所谓的pipeline),如fmt,lint,unit-test覆盖率等check。如果必须通过的check都通过,同时还有两位(包含你自己)reviewers点赞,则会自动合入master。(有些必过check不过,也可以通过approvers强制合入,但一般这种属非正常流程。 角色的定义在项目OWNER文件中)



在此亲自实现这样一个功能:即代码提交后可实现自动lint,可进行单元测试覆盖率统计,进行构建和部署等

将前文介绍的Go静态代码检查工具GolangCI-Lint,集成进gitlab,每次有新的push或merge,自动触发该操作


在项目根目录 创建一个 .gitlab-ci.yml 文件


通过配置.gitlab-ci.yml文件来告诉CI要对项目做些什么。.gitlab-ci.yml位于仓库的根目录下

仓库一旦收到任何推送,GitLab将立即查找.gitlab-ci.yml文件,并根据文件的内容在Runner上启动作业


关于该文件的具体写法,可参考Gitlab CI yaml官方配置文件翻译. 官方文档

或参考

Gitlab CI 配置文件 .gitlab-ci.yaml 详解(上)

GitLab-CI:从零开始的前端自动化部署


另外还需要一个Runner去实地跑这些任务(如lint,build等),Runner可以二进制安装(支持多个平台),也可以通过docker方式 (GitLab与Runner之间通过API进行通信,因此只需要Runner所在的机器有网络并且可以访问GitLab服务器即可)

关于Runner的安装与使用,参考前文 gitlab-runner的安装与配置


在ubuntu服务器(或其他机器),使用docker方式启动runner,并进入容器中新建一个name为testttt,tags为cs的runner,如下:


参考 golang项目 配置Gitlab CI

.gitlab-ci.yml文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# This file is a template, and might need editing before it works on your project.
image: hub-mirror.c.163.com/library/golang:latest

.go-cache:
variables:
GOPATH: $CI_PROJECT_DIR/.go
cache:
paths:
- .go/pkg/mod/

variables:
OUTPUT_NAME: helloworld-app

stages:
- lint
- build
- deploy

before_script:
- echo "before_script"
- git version
#- go env -w GOPRIVATE=code.haiziwang.com
- mkdir -p .go
- go version
- go env -w GO111MODULE=on
- go env -w GOPROXY="https://goproxy.io,direct"

golangci-lint:
image: golangci/golangci-lint:v1.27.0 #使用docker方式安装golangci-lint,也可以用二进制方式;前者更方便一些
stage: lint
extends: .go-cache
allow_failure: true
script:
- golangci-lint run -v
tags:
- cs

compile:
stage: build
extends: .go-cache
script:
- go mod download
- go build -race -o $OUTPUT_NAME
artifacts:
paths:
- $OUTPUT_NAME
tags:
- cs

deploy-dev:
stage: deploy
script:
- echo "deploy dev environment"
tags:
- cs


当有新的提交push时,会自动触发Pipeline

可见由于代码没有通过lint,故而lint的流水线失败



因为lint部分有 allow_failure: true配置,即该job允许失败,不影响后面job的进行;compile这个job也发生了错误,因为没有allow_failure: true,故而阻塞 下一个job无法进行)








和在本地运行golangci-lint是一样的,只是pipeline将这个操作自动化了~


.gitlab-ci.yml文件 中的golangci-lint run -v修改为golangci-lint run -v -D errcheck,staticcheck,然后再进行提交,可以发现lint这个job成功通过


但compile这个job依然失败

看原因是go的镜像没有找到,故而无法进行编译。

image: hub-mirror.c.163.com/library/golang:latest修改为image: golang:latest (即从hub.docker.com去pull go的镜像)

提交后,自动触发pipeline,但compile阶段依然失败

这是因为在根目录没有.go文件,所以build失败。在本地执行,同样会如此:


修改- go build -race -o $OUTPUT_NAME

1
2
- cd cmd/
- go build -race -o $OUTPUT_NAME

再次进行提交 (main.go在cmd文件下)

编译成功,但在将构建出的二进制文件作为作业产物导出时,发生错误,原因是没有这个文件



golint阶段也完全可以通过

- golangci-lint run --timeout 3m --issues-exit-code 0 --out-format code-climate | tee gl-code-quality-report.json | jq -r '.[] | "\(.location.path):\(.location.lines.begin) \(.description)"'

将lint的结果作为作业产物生成并下载

这是因为go build出来的文件在cmd目录下,而当前默认在根目录下


1
2
3
artifacts:
paths:
- $OUTPUT_NAME

修改为

1
2
3
artifacts:
paths:
- cmd/$OUTPUT_NAME

再次提交,触发pipeline后,compile阶段生成的产物也正常找到并可以导出


至此,一个完整的Gitlab CI Pipeline就执行结束


关于代码的ut覆盖率和测试报告,值得在此基础上,新起一篇博文进行记述


更多可参考:

GitLab Continuous Integration (CI)

GitLab CI/CD

B站视频-Gitlab CI 的基本使用

B站视频-GitLab CI 流水线构建优化


关于github上的持续集成,可参考 阮一峰-持续集成服务 Travis CI 教程