Continuous Integration - Build

三种分支模式

  1. 稳定主线

    项目中只有一条稳定主线,所有开发人员的代码都直接提交到该主线上,包括新features,bug fix 等。项目Release时不开新分支,只给主线上打上tag进行标记。

        该模式的最大好处就是管理方便,分支零成本管理,不涉及多分支间的合并问题。也是Martin Fowler同学推荐的模式。

      该模式带来的问题是如果团队规模较大(20人+),构建时间较长时,开发人员提交代码的频率会降低,也会降低开发人员提交代码的积极性。

 

  1. 稳定分支

    项目中有一条稳定主线,该主线只进行新features开发。项目Release时拉新分支作为发布分支。发布分支相对stable,不做新特性开发,只进行hot fixes.

        该模式比较适合传统软件的开发,例如freebsd 只有一条主线current,所有的新features都在该主线上发布,等到主线的特性积累到一定的milestone时,再从主干分出一个stable分支。

      如果新功能已经集成在主干上,但是达不到发布的要求,那么稳定分支就不能创建,这会影响到下一个发布计划。并且所有在stable上做的hot fixes最终都要合并到主干上来。

 

  1. 活跃分支-稳定主线-稳定分支

    项目中除了一条稳定主线与若干条稳定分支外,还存在有一条或多条活跃分支,该类型分支的建立通常有两方面原因:
  • 项目中开发人员人员较多时,会出现稳定主线模式所带来的问题。此时按照feature等拉出新的活跃分支时,可以使相关开发人员的集成关注点更加明确,也能提高他们提交代码的积极性。比如CWP项目中的Proxy feature最初就是在新分支上进行构建,每天早上由指定人员来与主干进行合并。
  • 有时项目中可能会有一些改动的影响面较大,并且需要较长时间。但是这些改动同时具有原子性,即或者全部改动生效,或者全部改动都需要进行回滚。例如CWP项目中的new branding 特性就属于这类情况。该特性需要对所有页面进行布局重构,影响面很大,最初的做法是将改动直接提交到主干上,但是发现经常会break 集成测试。因此对该特性也拉出一条活跃分支,使其独立工作在活跃分支上。最后在改动全部完成后,将其所有代码合并回主干。

这种模式所带来的最大问题就是代码合并,因为随着分支数量的增加,意味着每条分支所作的修改最终可能都需要合并到主干上。

构建

 Martin Fowler指出一次完整的构建应该包括如下七个步骤:

  • 将已集成的源代码复制一份到本地计算机。
  • 修改产品代码和添加修改自动化测试。
  • 在自己的计算机上启动一个自动化构建。
  • 构建成功后,把别人的修改更新到我的工作拷贝中。
  • 再重新做构建。
  • 把修改提交到源码仓库。
  • 在集成计算机上并基于主线的代码再做一次构建。

其中第5步操作会要求锁住主线代码,不允许其他人在这个时间段再次提交。

在讨论有哪些步骤可以省略的过程时,我首先想到的是省略本地构建过程,这里包含了两个假设:

  1. 主线必须是长绿的,表示随时可以发布,项目发展健康。并且只有在主线绿的时候才能更新代码。
  2. 第4步更新下来的代码无论如何都是需要本地构建的。而此时构建出的错误也必须是构建者来修理。

因此,无论有没有第3步构建,4,5两步都是要做的,而且错误发生在本地,还必须由构建者来处理。因此这样看来第3步似乎有些多余。那么第3步的价值究竟体现在哪里呢?个人觉得是在于出错后的反馈时间较快,并且能较为容易的定位到问题。

换一种思路,如果省掉的不是步骤3,而是步骤5会怎么样?这也可以从几个方面来分析:

  1. 本地自己写的代码质量是由第3步构建保证的,而第5步之所以可能出错,原因也一定是由合并代码导致的。但是这种错误出现的几率较小,可以考虑忽略。
  2. 如果省略了第5步,就不会导致主线在该阶段被锁,这样有助于提升构建效率。
  3. 主线是要保证健康的,但是健康状态一定是由长绿来保证么?我觉得未必,健康不代表不会出错,而是应该关注出错后的修复时间,如果主线构建出错,但是只需要很少的时间便能修复。那么把第5步的构建过程推迟到第7步去做,即使构建出错,也问题不大。

构建问题:

构建时间长:

每次构建需要较长时间,已经超出团队的容忍限度。解决方式通常包括几个方面:

  1. 分析原因。构建脚本做了太多没用的事情?构建流程是否应该改进等等。
  2. 并行构建。一般通过增加硬件机器来进行。这也是一种见效最快的方案。
  3. 低成本测试。将项目中花费时间较长的测试改为时间较短的测试,通常可以尽可能多的将功能(集成)测试的验证通过做单元测试来覆盖。数据库相关的测试改为内存相关等等。但是这同时也会带来一些负面影响,比如降低了测试的可信度。
  4. 分阶段或者减少无用测试。通常可以将测试划分为快和慢两种情况,针对速度较快的测试,可以在每次构建的时候都运行,而对于速度较慢但相对稳定的测试,可以选择分时段运行。

环境不一致:

构建的环境与产品实际运行环境不一致。通常包括几个方面:

  • 操作系统不一致。比如开发用windows,构建用linux。而实际产品可能跨平台。解决方法是采用多种平台进行构建。
  • 测试工具不一致。通常为开发环境下用的测试工具和集成环境下用的测试工具上的差异。
  • 设置不一致。包括权限设置不一致、环境变量设置不一致、文件系统不一致等等。
  • 数据不一致。比如测试用的数据都是些固定简单的fixtures,而产品环境下的数据较为复杂。虽然每次构建都是通过的,但是没能暴露出问题。这也可以归朔回构建不可信的原因。

强行提交:

构建尚未通过,其他人就已经开始提交。这类问题的解决方法是提交前进行检查,如果上次提交未通过,那么先revert上次提交的代码,直到待提交分支通过后再提交本地改动代码。

构建报告的通知方式:

包括email,SMS,音乐,熔岩灯,显示器等。

报告的分析:

结合工具从横向(不同人,不同团队之间)与纵向(团队自身的过去与现在)将数据以趋势和对比的形式展示出来.

 

参考文献:http://www.infoq.com/cn/articles/ci-theory-practice 肖鹏

Posted by Leo 2011年12月09日 01:22