不久前,我对 持续集成 (CI) 的理解还很肤浅,认为它似乎是一个额外的流程,迫使工程师在已经很大的项目上做额外的工作。我的团队开始在项目中实施 CI,在一些实践经验之后,我意识到了它巨大的好处,不仅对公司,而且对我这个工程师来说!在这篇文章中,我将描述 CI,我发现的好处,以及如何免费快速地实施它。
CI 和 持续交付 (CD) 通常一起讨论。在一篇文章中同时写 CI 和 CD 内容很多,一次性读起来也很累,所以这里只讨论 CI。也许,我将在以后的文章中介绍 CD。😉
目录
什么是 CI?
持续集成,据我理解,是一种编程模式,它结合了测试、安全检查和开发实践,以便持续自信地将代码从开发分支推送到生产就绪分支。
Microsoft Word 是 CI 的一个例子。将文字写入程序并根据拼写和语法算法进行检查,以断言文档的一般可读性和拼写。
为什么 CI 应该在所有地方使用
我们已经稍微谈到过这一点,但我认为 CI 最大的好处是它通过提高工程师的生产力节省了大量资金。具体来说,它提供了更快的反馈循环、更轻松的集成,并减少了瓶颈。将 CI 与公司节省的成本直接关联起来很难,因为 SaaS 成本会随着用户群的变化而变化。因此,如果开发人员想向企业推销 CI,可以使用以下公式。好奇它到底能节省多少?我的朋友,David Inoa,创建了以下演示来帮助计算节省的成本。
查看 David (@davidinoa) 在 CodePen 上的笔 持续集成 (CI) 公司成本节省估算器。
真正令人兴奋到足以大声喊出来的是 CI 如何能使你我作为开发人员受益!
首先,CI 将为你节省时间。多少?我们说的是每周几个小时。如何?哦,我是不是想告诉你!CI 自动测试你的代码,并让你知道它是否可以合并到一个发布到生产环境的分支中。你花费在测试代码和与他人协作以使代码准备好发布到生产环境的时间非常多。
然后是它有助于防止代码疲劳的方式。它支持像 Greenkeeper 这样的工具,它可以自动设置——甚至 合并——代码审查后的拉取请求。这使代码保持最新,并允许开发人员专注于我们真正需要做的事情。你知道的,比如编写代码或生活。软件包内的代码更新通常只需要查看主要版本更新,因此无需跟踪每个次要版本以查找需要采取措施的重大更改。

没有借口,使用 CI!
与开发人员交谈时,对话通常会变成以下样子
“我想使用 CI,但是……[插入借口]。”
对我来说,这是一种逃避!CI 可以是免费的。它也可以很容易。确实,CI 的好处会带来一些成本,包括 CircleCI 或 Greenkeeper 等工具的月费。但这与它提供的长期节省相比只是九牛一毛。确实,设置它需要时间。但值得一提的是,CI 的强大功能可以免费用于开源项目。如果你需要或想要保持代码私密并且不想为 CI 工具付费,那么你确实可以用几个很棒的 npm 包构建自己的 CI 设置。
所以,别再找借口了,感受 CI 的强大功能吧!
CI 解决什么问题?
在深入研究之前,我们应该介绍 CI 的用例。它解决了大量问题,并在许多情况下派上用场。
- 当多个开发人员希望同时合并到生产分支时
- 当错误未被捕获或无法在部署之前修复时
- 当依赖项已过期时
- 当开发人员必须等待较长时间才能合并代码时
- 当软件包依赖于其他软件包时
- 当更新软件包并且必须在多个位置更改时

推荐的 CI 工具
让我们看看用于创建 CI 反馈循环的高级部分,以及一些快速代码片段,以便今天为任何开源项目设置 CI。我们将将其分解成易于消化的块。
文档
为了立即让 CI 为我工作,我通常将 CI 设置为测试我项目中的初始文档。具体来说,我使用 MarkdownLint 和 Write Good,因为它们提供了我编写此项目部分测试所需的所有功能。
好消息是 GitHub 提供了标准模板,并且有很多内容可以复制以快速设置文档。阅读更多关于快速设置文档和创建文档 反馈循环的信息。
我将 package.json
文件保存在项目的根目录下,并运行如下脚本命令
"grammar": "write-good *.md --no-passive",
"markdownlint": "markdownlint *.md"
这两行代码允许我开始使用 CI。就是这样!我现在可以运行 CI 来测试语法了。
此时,我可以继续设置 CircleCI 和 Greenkeeper 以帮助我确保软件包是最新的。我们稍后会讲到这一点。
单元测试
单元测试是一种测试代码块(单元)的方法,以确保该块的预期行为按预期工作。
单元测试在 CI 中提供了很多帮助。它们定义了代码质量,并在无需推送/合并/托管代码的情况下为开发人员提供反馈。阅读更多关于单元测试和快速设置单元测试 反馈循环的信息。
以下是在不使用库的情况下非常基本的单元测试示例
const addsOne = (num) => num + 1 // We start with 1 as an initial value
const numPlus1 = addsOne(3) // Function to add 3
const stringNumPlus1 = addsOne('3') // Add the two functions, expect 4 as the value
/**
* console.assert
* https://mdn.org.cn/en-US/docs/Web/API/console/assert
* @param test?
* @param string
* @returns string if the test fails
**/
console.assert(numPlus1 === 4, 'The variable `numPlus1` is not 4!')
console.assert(stringNumPlus1 === 4, 'The variable `stringNumPlus1` is not 4!')
随着时间的推移,使用像 Jest 这样的库来进行单元测试代码是很好的,但这个例子让你了解了我们正在关注什么。
下面是使用 Jest 的相同测试示例
const addsOne = (num) => num + 1
describe('addsOne', () => {
it('adds a number', () => {
const numPlus1 = addsOne(3)
expect(numPlus1).toEqual(4)
})
it('will not add a string', () => {
const stringNumPlus1 = addsOne('3')
expect(stringNumPlus1 === 4).toBeFalsy();
})
})
使用 Jest,可以通过在 package.json
中添加如下命令将测试与 CI 挂钩
"test:jest": "jest --coverage",
标志 --coverage
配置 Jest 报告测试覆盖率。
安全检查
安全检查有助于传达代码和代码质量。文档、文档模板、代码风格检查器、拼写检查器和类型检查器都是安全检查。这些工具可以自动化,在提交、开发、CI 期间甚至在代码编辑器中运行。
安全检查属于 CI 的多个类别:反馈循环和测试。我整理了一份我通常在项目中内置的安全检查类型列表。
所有这些检查可能看起来像是另一层代码抽象或学习,所以如果这让你或其他人感到不知所措,请放松心态。这些工具帮助我的团队弥合了经验差距,定义了可共享的团队模式,并在开发人员对代码的功能感到困惑时提供帮助。
- 提交、合并、沟通:像 husky、commitizen、GitHub 模板 和变更日志这样的工具有助于保持 CI 运行干净的代码,并为协作团队环境形成良好的工作流程。
- 定义代码(类型检查器):像 TypeScript 这样的工具定义并传达代码接口——不仅仅是类型!
- 代码风格检查:这是确保某些内容符合定义的标准和模式的做法。几乎所有编程语言都有代码风格检查器,你可能在其他项目中使用过一些常见的代码风格检查器,例如 ESlint(JavaScript)和 Stylelint(CSS)。
- 编写和注释:Write Good 有助于捕获文档中的语法错误。像 JSDoc、Doctrine 和 TypeDoc 这样的工具有助于编写文档并在代码编辑器中添加有用的提示。两者都可以编译成 Markdown 文档。
ESlint 是如何在此类工具中实现 CI 的一个很好的例子。例如,在 package.json
中只需添加以下内容即可检查 JavaScript 代码风格
"eslint": "eslint ."
显然,有很多选项允许你配置代码风格检查器以符合你和你团队的编码标准,但你可以看到设置起来是多么实用。
高级 CI 设置
为仓库启动 CI 通常只需要很少的时间,但是如果需要,我们也可以使用许多高级配置。让我们先看看一个快速设置,然后进入更高级的配置。即使是最基本的设置也有助于节省时间和提高代码质量!
两个可以帮助开发人员每周节省数小时的简单 CI 功能是自动依赖项更新和构建测试。依赖项更新将在 此处 详细介绍。
构建测试指的是通过运行安装命令在 CI 期间安装 node_modules
——例如,(npm install)所有 node_modules
都按预期安装。这是一个简单的任务,确实会失败。确保 node_modules
按预期安装可以节省大量时间!
快速 CI 设置
可以为 CircleCI 和 Travis 自动设置 CI!如果仓库的 package.json
中已经定义了有效的 test
命令,那么无需任何其他配置即可实现 CI。
在像 CircleCI 或 Travis 这样的 CI 工具中,登录或身份验证后可以搜索仓库。然后,按照 CI 工具的 UI 开始测试。

对于 JavaScript,CircleCI 将查看仓库 package.json
中的 test
,以查看是否添加了有效的测试脚本。如果添加了,则 CircleCI 将自动开始运行 CI!在此处阅读有关自动设置 CircleCI 的更多信息 此处。

高级配置
如果单元测试未完成,或者需要更多配置,可以为 CI 工具(如 CircleCI)添加一个 .yml
文件,用于创建执行运行程序脚本。
下面是如何为 CircleCI 设置自定义配置,使用 JavaScript 代码风格检查(再次使用 ESlint 作为示例)。
首先,运行此命令
mkdir .circleci && touch .circleci/config.yml
然后将以下内容添加到生成的的文件中
defaults: &defaults
working_directory: ~/code
docker:
- image: circleci/node:10
environment:
NPM_CONFIG_LOGLEVEL: error # make npm commands less noisy
JOBS: max <h3>https://gist.github.com/ralphtheninja/f7c45bdee00784b41fed
version: 2
jobs:
build:
<<: *defaults
steps:
- checkout
- run: npm i
- run: npm run eslint:ci
完成这些步骤后,并在 GitHub 中配置了 CircleCI 后(更多信息请参阅 此处),CircleCI 将获取 .circleci/config.yml
并在提交拉取请求时在 CI 流程中检查 JavaScript 代码风格。

我在此演示仓库中创建了一个包含示例的文件夹 在此演示仓库中,以展示使用 config.yml
文件配置 CI 的思路,你可以将其作为你自己的项目的参考或作为起点。

还有更多可以设置的 CI 工具,可以帮助开发人员节省更多时间,例如 自动合并、自动更新、监控等等!


总结
我们在这里涵盖了很多内容!概括来说,设置 CI 是非常可行的,甚至可以免费。借助其他工具(付费和开源工具),我们可以有更多时间编写代码,更多时间为 CI 编写更多测试——或者享受更多远离屏幕的生活!
以下是一些演示仓库,可以帮助开发人员快速设置或学习。如有任何问题、想法或改进建议,请随时在仓库中与我们联系。
还有其他人认为应该将其称为“写得好”而不是“写得不错”吗?