gitbook/持续交付36讲/docs/39706.md
2022-09-03 22:05:03 +08:00

189 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 32 | 细谈移动APP的交付流水线pipeline
你好我是王潇俊。今天我和你分享的主题是细谈移动APP的交付流水线pipeline
在上一篇文章[《了解移动App的持续交付生命周期》](https://time.geekbang.org/column/article/23611)中我和你分享了移动App的整个交付生命周期并把移动客户端的交付与后端服务的交付方式进行了对比。从中我们发现移动App自身的特点使得其持续交付流程与后端服务存在一定的差异。
所以今天我会在上一篇文章的基础上和你分享移动App持续交付中的个性化内容。这些个性化的内容主要表现在流水线的三个重要环节上
1. 采用与发布快车Release Train模式匹配的代码分支管理策略
2. 支持多项目、多组件并行的全新构建通道;
3. 自动化发布,完全托管的打包、发布、分发流程。
接下来我就从这三个角度和你详细聊聊移动App的持续交付吧。
## 发布快车模式
首先,我先和你说说什么是发布快车。
顾名思义,发布快车,就像一列由多节车厢组成的火车,每一节车厢代表一个发布版本,整个火车以一节节车厢或者说一个个版本的节奏,定期向前发车。而工程师们,则会把自己开发完成的功能集成到一节节的车厢上,这样集成在一节车厢的功能代码,就形成了一个新的版本。
如图1所示就很好地展示了发布快车的含义。
![](https://static001.geekbang.org/resource/image/c8/d2/c802a0f8f0cf4e57e4854b4e227918d2.png)
图1 发布快车详解图
从这张图上,我们可以看到,每个版本(也就是每节车厢)都由多个功能组成。
关于发布快车还有三个关键点,容易被误解或者疏忽。
**第一个关键点是,并不是说所有开发的功能,都一定要集成到最近的那节车厢、最近的那个版本中**。任何功能都应该按照既定计划规划纳入到适合的那节车厢、那个版本中。这也是为什么移动端App的持续交付需要良好的信息管理的原因。
**第二个关键点是,我们必须要保证固定间隔的发车时间,每周、每两周都可以,但必须保证每个车厢到点即发**。只有这样,我们才能保证持续交付流水线的持续运行,以及不间断地产出。这里需要注意的是,对于一些特殊的、不规则的发布,我们要把它们归类到热修复的流程,而不是在发布快车中处理。
**第三个关键点是,这个过程的最终产物是可以发布到市场的版本,而不是发布到用户侧的版本**。虽然我们把这个发布模式叫作发布快车,但其实它的最终产物是可以发布的待发布版本。所以这个流程完成后的版本没有被正式发布,或出现了部分缺陷无法发布的情况是很正常的,可以被接受。我们并不需要保证每个版本都一定能发布到用户手上。
发布快车的发布模式特别是以上说的三个特性非常符合移动App对持续交付的需求分散开发定期集成控制发布。所以绝大部分的移动App团队都选择采用发布快车的发布方式。
那么,如何才能实现这个发布快车模式的真实落地呢?
1. 选择与发布快车模式匹配的代码分支策略;
2. 改造出与发布快车模式匹配的构建通道;
3. 实现发布流程的全自动化。
## 选择与发布快车模式匹配的代码分支策略
首先选择一套与之匹配的代码分支管理策略否则整个发布快车的实施会非常别扭。我们先一起回顾一下专栏的第4篇文章[《一切的源头,代码分支策略的选择》](https://time.geekbang.org/column/article/10858)。
我在这篇文章中介绍的代码分支策略中Gitlab Flow与 发布快车模式的思想看上去非常接近。那我们不妨推演一下,这个分支策略是否符合我们的需要。
首先项目仓库的初始状态如图2所示。这里有一个版本V1代码仓库中有2个分支Master是集成分支Production是发布分支。
![](https://static001.geekbang.org/resource/image/ad/9c/adc587c19ca50248a589639e3439019c.png)
图2 项目仓库的初始状态
然后以V1的commit为基准建立功能分支1并进行开发如图3所示。
![](https://static001.geekbang.org/resource/image/00/24/006d004b8f4c2fa2d12451ff2de76524.png)
图3 引入功能分支1
如图4所示功能分支1开发完成后合并入Master。测试通过之后形成版本V2V2就可以作为待发布的产物了。另外在形成V2之前我们可以看到另外一个功能分支2也被建立了但这个功能分支并没有被合并到Master所以不会出现在版本V2中。
![](https://static001.geekbang.org/resource/image/78/cb/789bece7976130a9722a0ca90acccbcb.png)
图4 形成版本2并引入功能分支2
从图5中我们可以看到V2版本后又出现了一个新的功能分支3它与功能分支2并行开发。这两个功能分支合并入Master之后被同时附加到版本V3中。
![](https://static001.geekbang.org/resource/image/df/45/dfb010fd678e02dc9065659657c6c745.png)
图5 引入功能分支3并形成版本3
正如以上的几个步骤,如果每个版本都是定时进行构建和打包,那么这样的代码分支管理模型就是一个典型的符合发布快车的物理实现了。
## 全新的构建通道
当然,为了发布快车模式的落地,我们只是建立与之配套的代码分支管理策略还远远不够,还需要有配套的构建通道。
你可能会问,发布快车模式的落地,为什么还要选择特定的构建通道呢?
我先和你说说发布快车,以及与之配套的代码分支策略的弱点都有哪些吧。
如果功能分支合入Master分支的过程缺乏校验以及必要的构建检查的话那么Production分支在进行自动定期构建时就很容易产生问题而一旦产生问题就会错过这个要定期发布的版本。
如果这只会影响到一个或少数几个功能的话,还好;但设想一下,如果你要发布一个大版本,由于某个小功能而影响了所有的其他功能,是不是就得不偿失了呢?
所以,为了高效的持续交付,我们就必须对构建通道进行一定的改造。
![](https://static001.geekbang.org/resource/image/ae/f4/aeb7a2ab53ecb8e2a4d9ebefa63d5bf4.png)
图6 被改造后的构建通道
如图6所示我们会在功能分支合并入Master分支前增加一次构建Merge CI Service这次构建的作用是保证功能分支的集成是成功的否则不允许合并同时对于一个代码仓库来说增加的这次构建过程要保证是串行的即如果这个仓库正有一个合并构建在进行则后续的合并构建需要等待。
这个合并构建过程保证了Master分支上的任何commit随时都可以成功构建。之后再根据发布快车的要求定期启动版本构建Auto CI Service就能顺利地得到可测试版本了。
构建测试版本之后流水线还可以继续处理在production分支上打上对应的tag。
## 自动化的发布
构建通道建立之后就是发布了。我在上一篇文章中提到移动App的发布与后端服务有所区别。移动App的发布需要特别注意这两点需求
1. 通常在发布到市场之前,会先发布内部,进行针对新功能的内测;
2. 通常为了节省调试信息带来的额外开销内部发布会采用debug包而正式发布则采用release包。
但是从另一方面看相比于后端服务的发布移动App的发布步骤固定且逻辑相对简单。
* iOS系统的发布步骤为构建导出ipa包记录符号表备份上传至iTC
* Android系统的发布步骤为构建打包更新渠道标识签名保存mapping文件备份上传至发布点。
理解了iOS和Android系统各自的发布步骤我们就可以很容易地做到发布自动化了。
比如针对iOS的版本发布来说在构建和打包之后我们可以获取到对应的ipa包关联对应的版本信息元数据后就可以上传到内部的发布站点供QA下载测试了或者上传到Apple TestFlight进行公测当然也可以部署到App Store了。
接下来,我就和你详细说说如何做到发布的自动化。
你可以使用Fastlane等类似的工具完成整个发布过程还可以根据不同发布的渠道定义各自的lane。当然Fastlane也可以提供打包等一系列Action帮助你完成自动化。
```
lane :release do #发布到AppStore
increment_build_number #自增版本号的方法
cocoapods #更新pod
gym #打包
deliver(force: true) #发布到AppStore
end
```
这是一段最简单的Fastfile脚本。它的功能是利用Fastlane提供的Action完成了打包并发布到AppStore。另外你还可以在AppfileFastlane用来描述App基本信息的专用描述文件中定义关于App的信息。
当然你还可以按照发布流程的需求定义自己的lane和Action完成不同的操作。
```
private_lane :build do |options|
project = options[:project] #获取项目对象
build_number = project.build_number #获取项目定义的版本号
gym(
workspace: project.workspace, #编译工作空间
configuration: project.config, #编译配置
include_symbols: true, #是否包含符号
scheme: project.scheme, #编译计划
xcargs: "BUILD_NUMBER=#{build_number}", #版本号
build_path: project.package_path, #编译路径
output_directory: project.package_path, #ipa包输出地址
output_name: project.ipa_name, #ipa包的名字
silent: false) # 编译Action
end
```
这段代码展示的就是用gym action构建一个自定义的、带参数的完整的构建过程了。我们可以看到这里的参数是具体的一个project对象。当然这里还有一个叫作output\_directory的参数你可以利用这个参数把构建的ipa包放到内部的下载地址。
这样看移动App的自动化发布是不是很简单[https://github.com/fastlane/examples](https://github.com/fastlane/examples)这里还有更多相关的例子,你可以参考它们完成更加复杂的自动化发布。
## 总结
今天,我和你一起分享了移动客户端持续交付流水线的几个详细点:
1. 利用发布快车的发布模式,可以有效地管理客户端的版本,保证研发工作按节奏持续向前进展;
2. 采用带发布分支的GitLab Flow配合发布快车的模型可以使其做到物理落地
3. 发布快车本身也有一些弊端比如对Master分支的合并检查不够严格的话会拖累项目进度因此我们采用改造构建通道的方式避免了这个问题的产生
4. 移动App的发布有其独特的流程通常是先内测后正式发布但其流程相对固定且容易自动化。所以我的建议是实现发布的完全自动化以提高研发效率。
另外我还介绍了Fastlane这样一个工具能够帮助你快速完成自动化的实现。
当然我今天所分享的只是移App持续交付流水线的一种方式。在工程实践中不同的产品和组织往往会存在不同的流水线。
所以关于移动App的流水线并没有对错、优劣之分合适的才是最好的。
## 思考题
你所在的团队移动App的持续交付流水线有哪些点与我今天分享的内容有所不同你可以分析出是什么原因导致了这些不同吗又是否可以进行优化呢
感谢你的收听,欢迎你给我留言。