做这件事的起因是因为公司处于高速发展阶段,前端的代码也在逐步从原来的ko、jquery转变成现在的react,因此也出现了构建一个版本需要分别打包,然后手动合并的情况。以此为契机,我开始了整合前端资源,搭建符合公司现有业务场景的自动化构建流程。
主要用到的工具:gitlab、Jenkins、sonarqube
主要模块:任务管理、分支管理、Jenkins工作流、质量检测、资源发布。
讲任务管理之前我先提一下我们公司的代码管理流程,因为它决定了任务管理的切入点在哪,我们公司的代码管理类似于gitflow,但是也在此流程上做了一些调整以适应公司的现状,因此每次发版之前我们都会创建一个对应的发版分支release,以便开发者将自己的feature代码合并到当前分支(可以看下图),所以任务管理模块的主要功能就是管理release走向,我们会提供release创建暂且就叫做task,同时将task关联到jenkins、gitlab、运维发布系统。这便是任务管理模块所要做的事。
这里大家可能会有疑问,分支管理不是有gitlab吗?还有一些辅助的工具比如sourceTree、Tower等。其实呢gitlab有很多很强大的功能需要我们去定制。比如
上面我提到每次发版都会新建发版分支release,通常我们会从master创建一个新的branch。而这里就有一个注意点(假如创建出来的分支名称叫A),为了当前分支代码不被其他分支污染,通常会将分支A设置为protected,如果我们手动在gitlab中设置,那么就显的很不自动了,这与我们的标题就不符了。这时候我们可以通过调用gitlab的api来实现这个步骤。
为了把控任务的走向,我们会通过很多webhooks来本地记录分支的状态,比如feature会通过merge request的方式提交代码给release,然后由管理者去处理,具体的处理结果我们就会通过webhooks关联到我们的任务中。这其实也是分支管理的一部分
其实我们还提供了分支的创建删除,提供了一些实时的统计数据,目的是为了让开发者在同一个地方完成所有的工作。
有了发版分支,接下来就要创建环境去执行项目的build,这一步其实蛮关键的,构建服务在创建完分支之后自动调用jenkins api来完成job的创建,这里小小的吐槽一下,jenkins的api写的确实有点...接受参数都是xml,让我想起了早些年开发微信公众号的场景:joy:。在job创建时重点关注以下几个点(括号里是xml中的节点名称)
1.构建时的分支(hudson.plugins.git.BranchSpec) 2.gitlab证书id(credentialsId) 3.构建脚本(command) 复制代码
说一下构建脚本,主要是用shell,实现的功能包括了获取资源、代码校验(包含了eslint和其他库合法性的校验,具体的大家可以根据业务来定)、webpack打包、提交dist到资源仓(发版)、消息通知。具体代码就不贴了
这里的发布系统是我司自己搭建的,也就不过多的解释了,主要做的事就是把打包好的资源发布到线上。
上面我简单的把每一个模块做了阐述,其实大部分功能都是运行在我们自建的服务中,作为一个帮助开发者简化流程的工具,我们也要考虑使用者的感受,所以我们也提供了管理端,展示任务时间轴,构建状态,代码质量指标等等。
随着公司逐渐的壮大,团队人数的增加带来了很多高并发,但易忽视的问题,就拿发版流程来说,由最初的 开发->测试->线上
的三步操作衍生出 开发->测试->灰度->线上
四步。看起来没什么问题,随着业务碎片化,微服务化,灰度到线上这一步出现了弊端,开发者无法把控灰度和线上之间的同步,品牌之间的同步。导致每到发布日,我们都得通宵去验证测试环境,灰度环境是否正确。
后来我们尝试着去掉灰度,只保留测试和线上,但线上会保留多个版本,最新版本验证通过之后做流量切换。这保证了发布效率的同时,也为提供了很好的回滚方式。但是这样的流程迫使我们再一次去梳理前端自动化流程,去思考如何去适应。
2019年的某一天,我们几个小伙伴再一次来到“小黑屋”,一起探讨如何优化前端构建流程。多版本发布带给我们几个难题
为此我们做出了如下调整,所有分支创建权限移交至manager,同时记录分支信息,feature向release/develop提交merge request时增加合法性校验,验证是否同步master,组件库版本等信息。release构建时增加上诉合法性校验的同时,关联同一项目不同任务状态的判断,保证release包含所有预发布功能。同时所有验证失败结果实时通知到manager/developer。
接下来我们说说除了校验分支的同时我们还做了哪些质量检测。
#eslint { cp -v -r /Users/android/pc/eslint/eslintrc.js /Users/android/.jenkins/workspace/$1/.eslintrc_copy.js node ./node_modules/eslint/bin/eslint.js -c .eslintrc_copy.js --ext .jsx,.js,.ts,.tsx src --ignore-path .eslintignore } || { send $2 $5 'fail' $1 'eslint验证失败' 'eslint' exit 1 } 复制代码