golang在gitlab中的工作流
在敏捷开发的时代, 快速的编码, 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-builder
stages:
- test
- build
- release
cache:
paths:
- bin
before_script:
- echo "Git Branch is ${CI_COMMIT_REF_NAME}"
testcase:
stage: test
script:
- echo "begin run test"
- make test
build_bin:
stage: build
script:
- make
release_bin:
stage: release
script:
- echo "begin release rpm pkg"
- make push_rpm
image运行pipeline的镜像, 可以直接使用golang这些基础镜像, 也可以是自己写的一个Builder镜像, 本例中笔者使用的是一个自己写好的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只是调用了项目中的makefile, 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 generation
COVERAGE_DIR="${COVERAGE_DIR:-coverage}"
PKG_LIST=$(go list ./... | grep -v /vendor/)
# Create the coverage files directory
mkdir -p "$COVERAGE_DIR";
# Create a coverage file for each package
for package in ${PKG_LIST}; do
go test -covermode=count -coverprofile "${COVERAGE_DIR}/${package##*/}.cov" "$package" ;
done ;
# Merge the coverage profile files
echo 'mode: count' > "${COVERAGE_DIR}"/coverage.cov ;
tail -q -n +2 "${COVERAGE_DIR}"/*.cov >> "${COVERAGE_DIR}"/coverage.cov ;
# Display the global code coverage
go tool cover -func="${COVERAGE_DIR}"/coverage.cov ;
# Remove the coverage files directory
rm -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中添加上即可, 形如
[](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 结构体中的匿名接口
golang 结构体中的匿名接口 代码示例 golang 中,可以给结构体增加匿名field,可参考 unknwon 大神的书. 匿名字段和内嵌结构体 但,golang同时也可以给结构体定义一个匿名i ...
- 将gitlab中的postgresql数据库开通远程访问
postgresql数据库是gitlab的一个配置数据库,记录gitlab的一些配置信息. 我们访问gitlab中的postgresql数据有本地命令行访问和远程可视化软件访问2种方式. (一)本地命 ...
- Eclipse导入GitLab中指定分支的项目
一.如果主分支丢失,是否可以恢复其他分支? 答案是可以的,下面我们就拿恢复分支publish-2018-6-5来说明问题,最终实现把分支publish-2018-6-5还原成项目放到Eclipse中 ...
- 在本地生成ssh-key 免密码远程clone GitLab中的项目到本地
每次项目push.pull都需要输入账号和密码,很烦,方便免密pull与push代码,在本地需要用git bash 创建一个公钥,然后在gitlab中把公钥保存下来. 步骤如下: 1.打开 git b ...
- Vue&Element开发框架中增加工作流处理,查看申请单中整合多个处理类型的处理
关于我在Winform框架.混合框架.Bootstrap开发框架中的简易审批性工作流模块,我写过不少文章,有兴趣可以参考<工作流模块>的随笔进行了解,本篇随笔在完成了Vue&Ele ...
- 微软Azure Services Bus中的工作流
在Azure Services Platform上对于工作流服务的支持,一直是我很感兴趣的内容.当然也是疑问 比较多的领域.鉴于这方面的资料太少,所以今天就从AzureServicesKit中的一个D ...
- Golang网络库中socket阻塞调度源码剖析
本文分析了Golang的socket文件描述符和goroutine阻塞调度的原理.代码中大部分是Go代码,小部分是汇编代码.完整理解本文需要Go语言知识,并且用Golang写过网络程序.更重要的是,需 ...
- Dynamics 365中自定义工作流活动更新了输入输出参数后获取的方法
关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复245或者20170309可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyong. ...
- Dynamics 365中自定义工作流活动获取的上下文分析及注意事项
关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复244或者20170306可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyong. ...
随机推荐
- java如何集成支付宝移动快捷支付功能
项目需要,需要在客户端集成支付宝接口.第一次集成,过程还是挺简单的,不过由于支付宝官方文档写的不够清晰,也是走了一些弯路,下面把过程写出来分享给大家.就研究了一下:因为使用支付宝接口,就需要到支付宝官 ...
- docker 构建 spring boot项目
在docker 开始部署springBoot项目 1.在centos7 ~ 创建一个文件夹docker 里面放置 上面的Dockerfile 和 springBoot 打包的项目docker_spri ...
- SSM的项目框架
- 【转载】45个设计师们不常见的html5和css3漂亮模板
对于Web开发人员来说,当他们需要创建一个非常时尚和新潮的CSS3和HTML5网站时需要非常专业的水准.html5和css3的结合能够做出非同寻常的网站效果..所以,今天,我推荐给大家45个免费的时尚 ...
- Wpf Page间跳转传参数 And Window To Page
这段时间用到Wpf,页面间的跳转网上有不少的示例,但是有些已经不能用了,尤其是页面间的传参问题更是一大堆,但正确的解决方案却没有几个,或者说写的不清楚,让人走了很多弯路,查看官方文档后发现了正确的姿势 ...
- C#多边形求角——实例说
前段时间有写过一个计算多边形角度的代码,这里给它整理整理,留给自己也送给萌新. 看左下图,这是一个多环的多边形,一个外环(内部为多边形内部区域),一个内环(外部为多边形内部区域),同时多边形中任意一个 ...
- PDF文档转换为图片、图片转成PDF 及PDF合并
简介 功能:PDF文档按每页转换成一张图片,一张图片转换成一张PDF 并将多张PDF合成一个多页的PDF文档. 经历:在各个网站上搜索始终出现各种问题,尤其是遇到引用的版本问题尤其头疼,不是不能适用当 ...
- StarUML3.0选择不同类型图和导出
StarUML(简称SU),是一种创建UML类图,生成类图和其他类型的统一建模语言(UML)图表的工具. 可绘制9款UML图:用例图.类图.序列图.状态图.活动图.通信图.构件图.部署图以及复合结构图 ...
- WebBrowser控件支持WebSocket
修改html页面,在Header标签中添加如下标签: <meta http-equiv="X-UA-Compatible"content="IE=edge" ...
- Message Loop 原理及应用
此文已由作者王荣涛授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. Message loop,即消息循环,在不同系统或者机制下叫法也不尽相同,有被叫做event loop,也有 ...