持续集成(CI)

GitBeginner
立即练习

简介

想象一下,你正在和一个大型团队一起写书。每当有人提交新章节,你都需要检查拼写错误和情节漏洞。手动完成这些工作非常耗时。

在软件开发中,我们使用持续集成(CI)来解决这个问题。CI 会自动及早检查代码变更,通常包括安装依赖、运行测试,并在每次更新后验证项目。

其中的关键是快速反馈。与其在几天后才发现问题,不如在变更刚发生后立即发现,这样更容易修复。

正因为速度快,CI 通常是团队构建的第一层自动化。它会把每次推送都变成一次自动质量检查,从而保护主分支。

在本实验中,你将为一个简单的 Node.js 应用搭建这道安全网。你将:

  • 创建一个能够执行基本数学运算的小型应用。
  • 编写测试,验证数学运算是否正确。
  • 配置 GitHub Actions,使其在每次推送代码时自动运行测试。
  • 有意破坏代码,观察安全网如何捕获错误。

前置条件

本实验建立在上一个实验的基础上。我们将继续使用你之前创建的 github-actions-basics 仓库。

准备 Node.js 项目

首先,我们需要准备一些要测试的代码。接下来创建一个很小的 Node.js 应用。如果你不是程序员,也不用担心——我们会提供所需的全部代码。

进入项目目录。由于这是一个新的实验环境,我们需要重新下载仓库。

cd ~/project
git clone https://github.com/your-username/github-actions-basics.git
cd github-actions-basics

注意:请将 your-username 替换为你实际的 GitHub 用户名。

我们需要创建 3 个文件来模拟真实项目。这里使用 cat 命令,它可以直接从命令行快速创建包含内容的文件。

1. 「配方」(package.json)

这个文件告诉计算机项目是什么,以及项目需要哪些工具。我们会在其中声明项目依赖一个名为 jest 的测试工具。

cat > package.json << EOF
{
  "name": "ci-demo",
  "version": "1.0.0",
  "scripts": {
    "test": "jest"
  },
  "dependencies": {
    "jest": "^29.7.0"
  }
}
EOF

2. 「食物」(index.js)

这是应用程序的实际代码。它包含一个用于计算两个数字之和的简单函数。

cat > index.js << EOF
function sum(a, b) {
  return a + b;
}
module.exports = sum;
EOF

3. 「味道测试」(index.test.js)

这是自动化测试。它断言:如果把 1 和 2 相加,结果必须是 3。

cat > index.test.js << EOF
const sum = require('./index');

test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});
EOF

文件创建完成后,需要将它们保存到 GitHub。运行标准 Git 命令上传你的工作。

git add .
git commit -m "Add Node.js project files"
git push

系统可能会要求你再次登录 GitHub。像之前一样,使用你的 Username 和 Personal Access Token(PAT)。

创建 CI 工作流

现在需要告诉我们的机器人助手如何测试这些代码。我们将在标准的 .github/workflows 文件夹中创建一个名为 ci.yml 的新工作流文件。

touch .github/workflows/ci.yml

使用 nano 编辑器打开该文件。

nano .github/workflows/ci.yml

添加以下配置。下面会解释其中新增的部分。

name: Node.js CI

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 16

这里引入了一个重要的新关键词:uses。

这是 GitHub Actions 中一种重要的使用模式。工作流通常不会手动编写每个 shell 步骤,而是组合可复用的 action,将检出代码、设置编程语言环境或上传构件等常见任务封装起来。

你可以把 uses 理解为将一项技能下载到机器人的大脑中。这样就不必从头编写复杂脚本,而是可以使用其他人创建好的 action。

  • **actions/checkout@v4**:这个标准 action 告诉机器人「下载我的代码」。没有它,机器人的工作区就是空的。
  • **actions/setup-node@v3**:这个 action 会在运行器上安装 Node.js。我们还传入了具体版本(16),以确保环境一致。

保存并退出编辑器(Ctrl+X、Y、Enter)。

添加安装和测试步骤

现在我们已经有了代码(检出代码)和工具(Node.js),接下来需要实际运行测试。

在 Node.js 中,通常使用以下两个标准命令:

  1. npm install:下载 package.json 中列出的所有依赖项(例如 jest 测试工具)。
  2. npm test:运行 package.json 中定义的测试脚本。

这两个步骤体现了 CI 的核心流程:准备环境、安装依赖,并在干净的运行器中验证代码,然后再接受这次变更。

将这些步骤添加到工作流中。再次打开 .github/workflows/ci.yml。

nano .github/workflows/ci.yml

将以下两个步骤追加到文件末尾。确保缩进与前面的步骤对齐。

- name: Install dependencies
  run: npm install

- name: Run tests
  run: npm test

完整文件应如下所示:

name: Node.js CI

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 16

      - name: Install dependencies
        run: npm install

      - name: Run tests
        run: npm test

保存并退出编辑器。

现在,将这个文件推送到 GitHub,启动你的安全网。

git add .
git commit -m "Add CI pipeline"
git push

打开 GitHub 上的仓库,然后点击 Actions 标签页。你应该会看到一个名为「Node.js CI」的新工作流正在运行。运行完成后,你会看到一个绿色对勾。这表示代码运行正常!

CI Pipeline

破坏构建

只有在你跌倒时能够接住你,安全网才有用。现在有意「破坏」代码,观察 CI 系统如何工作。

我们将编辑测试文件,让它故意做出错误断言:声称 1 + 2 应该等于 4。

使用 nano 打开 index.test.js。

nano index.test.js

将测试期望值从 3 改为 4。

const sum = require("./index");

test("adds 1 + 2 to equal 3", () => {
  expect(sum(1, 2)).toBe(4); // CHANGED 3 to 4
});

保存并退出。现在提交并推送这个「错误」。

git add .
git commit -m "Intentionally break the test"
git push

立即切回 GitHub 上的 Actions 标签页,查看新的工作流运行情况。

很快,这次运行应该会失败。你会在提交旁边看到一个红色 X 图标。这表示 CI 系统正在发出警告:「停止!出现问题了!」

点击失败的运行记录,然后点击 build 作业。展开 Run tests 步骤,查看错误日志:

Error: expect(received).toBe(expected) // Object.is equality

Expected: 4
Received: 3

这个简单的红色 X 能够在错误刚发生时捕获问题,而不是等到几天或几周后才发现,从而为开发人员节省大量时间。

CI Pipeline Failed

总结

在本实验中,你创建了一个达到专业水平的持续集成流水线。

你学习了:

  • 如何使用 package.json 定义项目「配方」。
  • 如何使用 uses 关键词安装 actions/checkout 和 actions/setup-node 等强大工具。
  • 如何自动运行测试,让机器人验证每次代码变更。
  • 「红色 X」如何作为代码的安全网。

接下来,我们将学习如何把能够正常运行的代码打包起来,让全世界都能看到!