一、背景
在日常开发中,我们经常会有发布需求,而且还会遇到各种环境,比如:线上环境(Online),模拟环境(Staging),开发环境(Dev)等。最简单的就是手动构建、上传服务器,但这种方式太过于繁琐,使用持续集成可以完美地解决这个问题,推荐了解一下Jenkins。
Jenkins构建也有很多种方式,现在使用比较多的是自由风格的软件项目(Jenkins构建的一种方式,会结合SCM和构建系统来构建你的项目,甚至可以构建软件以外的系统)的方式。针对单个项目的简单构建,这种方式已经足够了,但是针对多个类似且又存在差异的项目,就难以满足要求,否则就需要大量的job来支持,这就存在,一个小的变动,就需要修改很多个job的情况,难以维护。我们团队之前就存在这样的问题。
目前,我们团队主要负责开发和维护多个Android项目,而且每个项目都需要构建,每个构建流程非常类似但又存在一定的差异。比如构建的流程大概如下:克隆代码;
静态代码检查(可选);
单元测试(可选);
编译打包APK或者热补丁;
APK分析,获取版本号(VersionCode),包的Hash值(apkhash)等;
加固;
上传测试分发平台;
存档(可选);
触发自动化测试(可选);
通知负责人构建结果等。
整个流程大体上是相同的,但是又存在一些差异。比如有的构建可以没有单元测试,有的构建不用触发自动化测试,而且构建结果通知的负责人也不同。如果使用自由风格软件项目的普通构建,每个项目都要建立一个job来处理流程(可能会调用其他job)。
这种处理方式原本也是可以的,但是必须考虑到,可能会有新的流程接入(比如二次签名),构建流程也可能存在Bug等多种问题。无论哪种情况,一旦修改主构建流程,每个项目的job都需要修改和测试,就必然会浪费大量的时间。针对这种情况,我们使用了Pipeline的构建方式来解决。
当然,如果有项目集成了React Native,还需要构建JsBundle。在Native修改以后,JsBundle不一定会有更新,如果是构建Native的时候一起构建JsBundle,就会造成很多资源浪费。并且直接把JsBundle这类大文件放在Native的Git仓库里,也不是特别合适。
本文是分享一种Pipeline的使用经验,来解决这类问题。
二、Pipeline的介绍
Pipeline也就是构建流水线,对于程序员来说,最好的解释是:使用代码来控制项目的构建、测试、部署等。使用它的好处有很多,包括但不限于:
- 使用Pipeline可以非常灵活的控制整个构建过程;
- 可以清楚的知道每个构建阶段使用的时间,方便构建的优化;
- 构建出错,使用stageView可以快速定位出错的阶段;
- 一个job可以搞定整个构建,方便管理和维护等。
Stage View
三、使用Pipeline构建
新建一个Pipeline项目,写入Pipeline的构建脚本,就像下面这样:
对于单个项目来说,使用这样的Pipeline来构建能够满足绝大部分需求,但是这样做也有很多缺陷,包括:多个项目的Pipeline打包脚本不能公用,导致一个项目写一份脚本,维护比较麻烦。一个变动,需要修改多个job的脚本;
多个人维护构建job的时候,可能会覆盖彼此的代码;
修改脚本失败以后,无法回滚到上个版本;
无法进行构建脚本的版本管理,老版本发修复版本需要构建,可能和现在用的job版本已经不一样了,等等。
四、把Pipeline当代码写
既然存在缺陷,我们就要找更好的方式,其实Jenkins提供了一个更优雅的管理Pipeline脚本的方式,在配置项目Pipeline的时候,选择Pipeline script from SCM,就像下面这样:
这样,Jenkins在启动job的时候,首先会去仓库里面拉取脚本,然后再运行这个脚本。在脚本里面,我们规定的构建方式和流程,就会按部就班地执行。构建的脚本,可以实现多人维护,还可以Review,避免出错。
以上就算搭建好了一个基础,而针对多个项目时,还有一些事情要做,不可能完全一样,以下是构建的结构图:
如此以来,我们的构建数据来源分为三部分:job UI界面、仓库的通用Pipeline脚本、项目下的特殊配置,我们分别来看一下。
job UI界面(参数化构建)