golang在gitlab中的工作流

golang在gitlab中的工作流,第1张

概述在敏捷开发的时代, 快速的编码, code review, 测试, 部署, 是提升程序员效率的关键。 同时在基础工具完备的如今, 我们甚至无需过多的 *** 作就可以轻松实现上述步骤, 本文就以gitlab为例, 分享一下golang项目结合gitlab如何实现自动化CI。 在gitlab中执行CI, 需要在项目根目录下增加.gitlab-ci.yml文件, 定义执行CI任务的步骤及方式, 例如典型的 *** 作

在敏捷开发的时代,快速的编码,code revIEw,测试,部署,是提升程序员效率的关键。 同时在基础工具完备的如今,我们甚至无需过多的 *** 作就可以轻松实现上述步骤,本文就以gitlab为例,分享一下golang项目结合gitlab如何实现自动化CI。

在gitlab中执行CI,需要在项目根目录下增加.gitlab-ci.yml文件,定义执行CI任务的步骤及方式,例如典型的 *** 作:执行代码检测,编译,发布。 gitlab会在每次commit或push的时候调用runner来执行该文件中所定义的 *** 作。runner是一个执行具体CI任务的工具,可以运行在任意实体机,docker或k8s集群,在项目中配置好后,gitlab就会自动调用runner并将结果返回。

配置gitlab runner

runner可以为某个项目单独配置,也可以由gitlab管理员预先定义一些公共使用的runner,后者无需开发人员过多 *** 作,主要讲解一下前者,如何单独配置一个runner。首先安装gitlab runner,参照官方安装教程,安装好之后需要注册该runner到项目中,本文使用的是docker作为executer,也就是用docker执行pipeline,在setting->pipeline下获取到项目的token和url,通过gitlab-runner register来注册该runner,
其中DOCKER_IMAGE 是如果未在.gitlab-ci.yml文件中指定image时默认的image。

sudo gitlab-runner register -n -u $CI_SERVER_URL  -r $REGISTRATION_TOKEN  --description "test-docker-runner"  --executor docker  --docker-image $DOCKER_IMAGE  --docker-privileged
编写ci文件

上述如此就安装并关联好了gitlab-runner,接下来就是编写.gitlab-ci.yml文件了:

image: cr.registry.name/groupname/project-name-builderstages:  - test  - build  - releasecache:  paths:  - binbefore_script:  - echo "Git Branch is ${CI_COMMIT_REF_name}"testcase:  stage: test  script:  - echo "begin run test"  - make testbuild_bin:  stage: build  script:  - makerelease_bin:  stage: release  script:  - echo "begin release rpm pkg"  - make push_rpm

image运行pipeline的镜像,可以直接使用golang这些基础镜像,也可以是自己写的一个Budiler镜像,本例中笔者使用的是一个自己写好的builder镜像,因为在后面的ci *** 作中,笔者会打包rpm包并上传到文件服务器上以便后续的发布,这些clIEnt都需要在镜像中准备好,基础镜像无法满足条件,所有笔者就自己打包了一个镜像。
接下来是stage的定义,stage就是定义ci任务的各个阶段,本例中是执行测试,发布三个阶段(因为go test的实现并不是分析编译后binary文件,所以可以看到测试在编译之前),各个stage串行执行,只有前一阶段执行完毕才会执行后面的阶段,如果哪个stage失败则整个pipeline失败。下面的testcase,build_bin,release_bin分别是各个stage的具体定义,称为job,各个job的script中可以执行任意的命令,需要注意script中的命令必须在上面指定的image中存在,笔者的script只是调用了项目中的makefil,makefile中写好了具体执行的 *** 作,如果一个stage中定义了多个job的话,他们会并行执行。before_script定义了在各个job的script执行之前执行的 *** 作,笔者是打印出执行pipeline的branch,其中CI_COMMIT_REF_name是gitlab内置变量,表示当前的branch,如果需要使用自己的变量,可以通过variables来定义,但是程序中使用到的敏感的token,key等信息,不要直接定义在variables中,可以通过setting->pipeline->Secret variables中设置,使用的时候会自动作为环境变量注入进去。cache定义了各个stage直接可以保存下来供其他stage使用的数据,笔者这里是项目下的bin文件,因为在build阶段生成了binary可执行文件之后,在release阶段就可以直接使用。需要注意的是,cache并不能保证每次都会存在,所以在release中需要有其他的逻辑保证没找到cache也可以正常的工作。
笔者上述只是三个stage,在一个成熟的项目中应该包括很多这样的stage,依次进行lint,unit tests,data race,memory sanitizer,code coverage,build,release。幸运的是对于这些步骤中的大部分go都直接提供了相应的工具来使用,例如goline,go test等,其中代码测试覆盖率这块有个小问题需要单独拿出来讲一下。

golang 项目的 test coverage

golang项目的测试覆盖率可以直接用go test -cover ${package}输出
也可以通过go test -coverprofile生成coverage profile,该文件中保存了一些收集到的测试信息,然后将这些信息提供给go tool cover使用来输出测试覆盖率。

go test -coverprofile "profile.cov" ${package_name}go tool cover -func="profile.cov"

但是上面的测试覆盖率只是针对一个package,对于一个项目中有多个package,需要依次调用go test -coverprofile产生每个package的profile,然后将其合并在一起,再调用go tool cover产生整个项目的coverage例如:

#!/bin/bash## Code coverage generationCOVERAGE_DIR="${COVERAGE_DIR:-coverage}"PKG_List=$(go List ./... | grep -v /vendor/)# Create the coverage files directorymkdir -p "$COVERAGE_DIR";# Create a coverage file for each packagefor package in ${PKG_List}; do    go test -covermode=count -coverprofile "${COVERAGE_DIR}/${package##*/}.cov" "$package" ;done ;# Merge the coverage profile filesecho ‘mode: count‘ > "${COVERAGE_DIR}"/coverage.cov ;tail -q -n +2 "${COVERAGE_DIR}"/*.cov >> "${COVERAGE_DIR}"/coverage.cov ;# display the global code coveragego tool cover -func="${COVERAGE_DIR}"/coverage.cov ;# Remove the coverage files directoryrm -rf "$COVERAGE_DIR";

在golang 1.10中已经支持了go test后面的多个package共同生成一个profile,无需手动合并多个profile,go test $(go List ./... | grep -v vendor) -v -coverprofile .testCoverage.txt
所以现在整个项目的coverage的输出方式为:go test $(go List ./...) -v -coverprofile .testCoverage.txt && go tool cover --func=.testCoverage.txt 如果你需要一步生成coverage的话记得升级你的golang版本。
如果项目中某个package不含有测试文件,则这个package的coverage应该为0%,但是目前go tes对于不含有测试文件的package就不会在profile中产生对应的记录,在算项目的coverage的时候也就不会包括该package。如此整个项目的coverage其实比实际值大,因为少算了coverage为0的package,这个目前还没有一种简单的解决方式,只能是在每个package中都增加测试文件,其实这也是我们应该做到的。

徽章(Badges)

有了测试覆盖率的数据就可以在项目的首页展示这些数据了,如下图所示:

在项目的Setting-> pipeline 最下面可以找到对应的MarkDown格式的输出,在首页的ReadMe中添加上即可,形如

[![Build Status](https://gitlab.com/pantomath-io/demo-tools/badges/master/build.svg)](https://gitlab.com/pantomath-io/demo-tools/commits/master)

对于测试覆盖率还需要在项目中配置正则表达式,来匹配pipeline的输出中的测试覆盖率,如果用上面的命令则正则表达式为: total:\s+\(statements\)\s+(\d+.\d+\%)
如果想要添加其他的badege,查阅相关资料即可。如果想要使用go report card badges 而有不想公开公司内网的代码则需要自己搭建go report 服务器了。

gitlab与golang 的其他要点 项目中每次改代码都应该在一个新的branch上进行编码 *** 作,每次push代码都会触发提前设置好的pipeline自动执行一些编译测试等 *** 作,pipeline结束后会生成代码的测试覆盖率,code small等数据,如果数据不符合预先的规范,需要继续修改直到数据达标。开发完成之后然后提交merge request,然后指派给同事进行code revIEw,如何需要多人revIEw的话就在description里cc @somebody 艾特其他人就可以了。 gitlab本身的code revIEw效果还不错,可以选择在任意两个commit 之间进行diff。 如果本次提交是为了解决issue的话,在commit message中直接通过#issueID来链接或关闭对应的issue。最后merge request通过之后代码合并至master,master中的pipeline与dev分支的有些不同,可以在master中执行CD进行自动发布。
对于所有出现的BUG都应该反应在一次issue里,后续的进展都应该及时更新在issue里。 issue可以通过设置tag,milestone 来管理,这样做更加清晰明了,方便管理,回溯。 项目中必须包含makefile,任何编译,发布,都通过make subcommand 一条命令解决,无需额外设置GOPATH的位置,git submodule,go package的下载等,这样才足够敏捷,.gitlab-ci.yml文件中也无需写冗长的script,将来如果编译方式变化也可以只修改makefile就可以了,同时对于新人刚接触项目也更友好。 项目中推荐写一个builder镜像,取名为Dockerfile.build以区分真正的业务镜像,这样的好处是对开发环境依赖较少,只需要有docker就行,golang,rpm制作工具等都打包在builder镜像之中,使用的时候直接docker run -v ``pwd``:/project cr.registry.name/groupname/project-name-builder make即可。尤其是在gitlab ci的时候,可能ci过程中需要执行代码质量检查等,需要用到golint等工具,如果只使用基础镜像,则每次ci任务都需要在去下载,这样费时费力,不如将这些工具打包在builder镜像中,然后在yaml文件的image中指定该builder镜像即可。 reference

Go tools and GitLab: How to do continuous integration like a boss

总结

以上是内存溢出为你收集整理的golang在gitlab中的工作流全部内容,希望文章能够帮你解决golang在gitlab中的工作流所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1270476.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-08
下一篇 2022-06-08

发表评论

登录后才能评论

评论列表(0条)

保存