为什么要自动化

如果说我在拥有一个开源系统的这些年里学到了什么,那就是你要做的例行事项越少,你就有越多的空闲时间用于实际的工作(比如修复缺陷或者开发新功能)。因此,我们应该力求尽可能自动化。

在实际中,首先检查两个工作流程(非自动化和全自动化),看你有多少时间实际上是花在例行事项上的。然后,我们将探讨如何实现改进的工作流程,让我们有更多的时间来修复缺陷和开发新功能。

最糟糕的情况——没有自动化

graph TD
    A[Someone creates a PR with a bug fix] -->|Inspect the code| B[You]
    B -->|Checkout the fork, build and run the tests| C[You]
    C -->|Approve the PR| D[You]
    D -->|Merge the PR| E[You]
    E -->|Checkout the master, build and run the tests| F[You]
    F -->|Update the change log| G[You]
    G -->|Bump the version and publish| H[You]
    H -->|Push the change log to Github and create a Github release| I[You]

如上图,在没有任何自动化的情况下,所有的工作都由你来做。仅仅对于一个缺陷修复来说,你就需要做很多工作,更重要的是,每次修复缺陷或开发新功能时,你都重复进行这些工作!

最好的情况——一切都是自动化的

graph TD
    PR[Someone creates a PR with a bug fix] -->|Inspect the code| You[You]
    You -->|Approve the PR| Auto1[Automation]
    Auto1 -->|Checks out the fork, builds and runs the tests| Auto2[Automation]
    Auto2 -->|Merges the PR| Auto3[Automation]
    Auto3 -->|Checks out the master, builds and runs the tests| Auto4[Automation]
    Auto4 -->|Updates the change log| Auto5[Automation]
    Auto5 -->|Bumps the version and publishes| Auto6[Automation]
    Auto6 -->|Pushes the change log to Github and creates Github release| Auto7[Automation]

在这种情况下,你只需要做必须要做的事情——检查代码和(偶尔)批准拉取请求,其他的一切都是自动完成的。这被称为持续集成(continuous integration)和 持续部署(continuous deployment)。在这里,我们并不会深入构建脚本和特定系统配置的细节。相反,我们将会查看让它发挥作用所需的工具,我将会让你自己决定具体细节。

持续集成(CI)

持续集成(CI)是一种自动将代码改动从多个贡献者集成到单个软件项目中的实践。 CI 过程由自动工具组成,这些工具会在集成之前断言新代码的正确性。

一个非常基础的 CI 运行将会包括 构建(build)单元测试(unit tests),但是并不局限于这两种。可能也会包含各种各样的静态代码分析工具、链接器等等。这里的标准由你定。

为什么应该使用 E2E(端到端) 测试?

构建和单元测试可以为你提供有关代码变动的快速反馈,所需时间相对较短,并且在出现问题的时候迅速失败。但是端到端(end-to-end,E2E)测试在 CI 中有着特殊的地位。

端到端测试不仅应该覆盖代码的正确性,还应该覆盖到你的部署流程、包的完整性等等。

这里有一个关键点:端到端测试应该像真实用户使用那样测试你的软件包。

CI 系统是如何工作的

市面上存在很多很多 CI 系统,比如 Travis CI、Circle CI、AppVeyor、Azure Pipelines、GitHub Actions 等等。它们的功能都比较多,做的事情也基本相同:检出你的代码、运行你定义的脚本(通常运行构建和测试),然后向报告成功或失败。

一般 CI 会在每个 PR 上运行,并向 GitHub 报告状态,您需要及时 Review 并处理。具体的构建脚本由你的生态系统、编写项目的语言、你所使用的框架等决定。

持续部署(CD)

持续部署(CD)是一个软件发布过程,它使用自动化测试来验证对代码库的更改是否正确和稳定,以便立即自动部署到生产环境中。

在我们的情况中,生产环境就是程序包在包注册中心中公开可用的时候。这是一个无法返回的阶段,因为一旦发布,就不能取消发布了,因为程序包是公开可用的(因此,它可能正被使用)。

持续部署有多种策略,具体策略取决于项目及其复杂程度。一般情况下,发行(release)只应该基于主干分支,因为这会让工作流变得非常简单。具体做法如下:

  1. 每个 PR 要么代表一个缺陷修复,要么代表一个新功能。
  2. 代码在进入主干之前经过了测试(包括端到端测试)。
  3. 主干分支是受保护的分支,所以只要你不合并失败的 PR,它就会保持稳定。
  4. 每个合并到主干的 PR 都会触发主干 CI 运行,CI 最终会发布一个新版本。

这将确保所有的发布都是按顺序进行的,并且可以很容易地将某些 PR 与特定的版本联系起来。

为了自动化程序包的发行过程,你需要做几件事情:

  1. 基于提交信息自动升级版本。
  2. 基于提交信息自动更新 CHANGELOG。
  3. 自动发布程序包到公共程序包仓库。
  4. 自动在 GitHub 上发行。

Semantic-release

semantic-release 自动化整个程序包发行工作流程,包括:确定下个版本号、生成发行说明和发布程序包。这消除了人类感情和版本号之间的直接联系,严格遵循 语义化版本 版本规范。

semantic-release 通过分析提交信息来确定下一个版本号。它使用 Angular Commit Message Conventions 来解析提交信息。这意味着你需要遵循这些规则来提交代码,否则 semantic-release 将无法正常工作。这里不做赘述,你可以在 semantic-release 的文档中找到更多信息。

如何保持项目的更新

如果你的项目没有外部依赖,跳过这一部分。然而,大多数项目都依赖于其它程序包,而其它程序包往往会发生变化。

使项目保持最新的依赖关系很重要,但这很耗时。幸运的是,我们有一个解决方案。实际上,有一些,例如 GreenkeeperRenovateDependabot。推荐使用 GitHub 自带的 Dependabot,不过请确保你的 CI 是在发挥作用的情况下再开启使用。