第 07 章

GitHub Actions

push 之后自动测试、构建、部署——把重复劳动交给机器

写一次 workflow,省下一辈子的手动操作

手动太累

每次改完代码,你都在重复做同样的事

手动测试

改完代码,你得手动跑一遍测试,确认没坏。忘了跑就合并,bug 进了主干。

手动部署

每次发版,要本地 build、上传服务器、重启服务。步骤繁琐,还容易出错。

环境不一致

「我这能跑啊」——你本地能跑,到别人机器就挂。没有统一的环境保证。

本章让机器替你做这些:写一个 workflow 文件,定义「push 时自动跑测试、构建、部署」。之后每次 push,GitHub 帮你执行。
这是现代软件开发的基础设施,也是后续章节(Pages 部署、CLI 触发)的前置。

开始之前

适合谁

  • 会 PR,想让代码自动测试
  • 听说过 CI/CD 但没动手配过
  • 想自动化构建、部署、发版流程

你将学会

  • 读懂和编写 workflow.yaml
  • 配置各类触发器(push、PR、定时、手动)
  • 理解 job、step、runner 的关系
  • 用 matrix 做多环境测试
  • 用 cache 加速、artifact 存产物
  • 安全管理 secrets

本章暂不覆盖

  • 自托管 runner(企业场景)
  • Actions 市场发布(进阶)
  • 复杂部署平台集成(第 08 章部分)

Actions 是什么

GitHub 内置的 CI/CD 平台——代码仓库自带的自动化引擎

它能做什么

  • CI:push/PR 时自动跑测试
  • CD:合并后自动构建并部署
  • 自动化:定时任务、发版、通知

核心优势

  • 免费额度:公开仓库无限分钟,私有仓库每月 2000 分钟
  • 无需自建服务器,GitHub 提供 runner
  • 配置即代码(YAML 文件随仓库走)
  • 海量现成 Action 可复用
对学生完全够用。公开仓库免费无限使用,足够跑作业项目的测试和部署。这章的例子都能在免费额度内完成。

workflow 放哪

约定俗成的目录:.github/workflows/

你的仓库/
├── .github/
│   └── workflows/
│       ├── test.yml      # 测试 workflow
│       └── deploy.yml    # 部署 workflow
├── src/
└── package.json

规则

  • 每个 .yml / .yaml 文件是一个独立 workflow
  • 文件名随意,通常按用途命名
  • 可以放多个 workflow,互不干扰
  • push 这个文件到仓库即生效

路径写错(如放在 .github/ 根目录而非 workflows/)会导致 Actions 不识别。

workflow 结构

一个最简 workflow 的五大要素

name: CI                          # ① workflow 名字

on: [push]                        # ② 触发条件

jobs:                             # ③ 任务集合
  test:                           # ④ 一个 job
    runs-on: ubuntu-latest        #    运行环境
    steps:                        # ⑤ 步骤序列
      - uses: actions/checkout@v7
      - run: echo "Hello"
五要素:name(名字)、on(何时触发)、jobs(任务组)、每个 job 有 runs-on(在哪跑)和 steps(具体做什么)。
这是最小骨架,所有 workflow 都是它的扩展。

触发器 on

定义「什么时候跑这个 workflow」

触发器何时触发典型用途
push 推送代码时 测试、构建
pull_request 开/更新 PR 时 PR 检查
schedule 定时(cron) 每日报告、爬虫
workflow_dispatch 手动点按钮 发版、临时执行

可组合:on: [push, pull_request] 表示推送或开 PR 都触发。

触发过滤

精细控制——只在特定分支、路径触发

on:
  push:
    branches:
      - main          # 只在 push 到 main 时触发
      - 'release/*'   # 或 release/ 开头的分支
    paths:
      - 'src/**'      # 只有 src 下文件变了才触发
      - '!**.md'      # 排除 markdown 改动
  pull_request:
    branches:
      - main
过滤能省额度。不写过滤,改个 README 也会触发完整测试。用 paths 过滤,让文档改动不浪费 CI 资源。

job 与 runner

job 是一组步骤,在某个 runner(虚拟机)上执行

runs-on 选环境

  • ubuntu-latest:Linux,最常用、最省额度
  • windows-latest:Windows(费额度)
  • macos-latest:macOS(最贵,慎用)

无特殊需求一律选 ubuntu,它最便宜。

job 之间默认并行

多个 job 默认同时跑。要用 needs 指定依赖:

jobs:
  test:
    ...
  deploy:
    needs: test   # 等 test 成功才跑

steps 详解

一个 job 里按顺序执行的步骤,每步是个 action 或命令

steps:
  # 用现成的 action(uses)
  - name: 检出代码
    uses: actions/checkout@v7

  # 跑命令(run)
  - name: 安装依赖
    run: npm install

  # 多行命令
  - name: 跑测试
    run: |
      npm test
      npm run lint
两种 step:uses 引用现成 Action(别人写好的能力),run 执行 shell 命令。
actions/checkout@v7 几乎是每个 workflow 的第一步——把代码拉到 runner 上才能操作。

Action 市场

不用从零写,现成 Action 覆盖绝大多数需求

常用官方 Action

  • actions/checkout:检出代码
  • actions/setup-node:装 Node.js
  • actions/setup-python:装 Python
  • actions/cache:缓存依赖
  • actions/upload-artifact:存产物

第三方 Action

  • peaceiris/actions-gh-pages:部署 Pages
  • softprops/action-gh-release:发 Release
  • 市场:github.com/marketplace 搜

引用格式:作者/动作名@版本。版本用 tag(如 @v4)或 commit SHA,别用 main 分支(不安全)。

实战:Node 测试

一个完整的 Node.js 自动测试 workflow

name: Node CI

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-node@v7
        with:
          node-version: '20'
      - run: npm install
      - run: npm test
这 8 行做了什么:每次 push 或 PR,拉代码 → 装 Node 20 → 装依赖 → 跑测试。
把它存为 .github/workflows/test.yml push 上去,下次推送就能在 Actions 标签看到运行结果。

实战:Python 测试

Python 项目的对应写法

name: Python CI

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-python@v7
        with:
          python-version: '3.12'
      - run: pip install -r requirements.txt
      - run: pytest

结构完全一样,只是 setup action 和测试命令不同。workflow 的套路是通用的,换语言只换 setup 和 run。

矩阵测试

matrix——一次在多个版本/系统上跑同一套测试

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [18, 20, 22]
        os: [ubuntu-latest, windows-latest]
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-node@v7
        with:
          node-version: ${{ matrix.node-version }}
      - run: npm install
      - run: npm test
这会跑 3 × 2 = 6 个 job:Node 18/20/22 × Linux/Windows。
适合库项目——确保你的代码在不同环境都能跑。应用项目通常不需要这么全面。

缓存加速

每次重装依赖很慢——缓存能让后续运行快几倍

steps:
  - uses: actions/checkout@v7
  - uses: actions/setup-node@v7
    with:
      node-version: '20'
      cache: 'npm'     # 自动缓存 npm 依赖
  - run: npm install   # 有缓存时这步快很多
  - run: npm test

setup-node/python 内置 cache

现代 setup action 都支持 cache 参数,自动处理。不用手动写缓存逻辑。

手动缓存

用 actions/cache@v6,指定 path 和 key。适合自定义缓存需求。

存产物

artifact——把构建结果保存下来,供下载或传递给下一步

steps:
  - uses: actions/checkout@v7
  - run: npm run build           # 构建产物在 dist/

  - name: 上传产物
    uses: actions/upload-artifact@v7
    with:
      name: build-output
      path: dist/
artifact 用途:构建后想下载打包结果查看、把测试报告存档、或让 deploy job 读取 build job 的产物。
在 Actions 运行页面能直接下载 artifact,保留 90 天。

密钥管理

secrets——加密存储的敏感信息,workflow 里安全引用

怎么设置

仓库 → Settings → Secrets and variables → Actions → New repository secret。

  • 名字如 DEPLOY_KEY
  • 值加密存储,设置后不可读
  • 只能改不能查

怎么用

steps:
  - name: 部署
    run: ./deploy.sh
    env:
      SSH_KEY: ${{ secrets.DEPLOY_KEY }}

引用时用 ${{ secrets.名字 }},日志里会自动打码。

绝不把密钥写进 yaml 明文。push 到公开仓库就泄露了。一律用 secrets。

完整 CI/CD

测试 → 构建 → 部署,多 job 串联

name: CI/CD

on:
  push:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-node@v7
        with: { node-version: '20', cache: 'npm' }
      - run: npm install
      - run: npm test

  build:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - run: npm install && npm run build
      - uses: actions/upload-artifact@v7
        with: { name: dist, path: dist/ }

  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/download-artifact@v8
        with: { name: dist, path: dist/ }
      - run: ./deploy.sh
        env:
          TOKEN: ${{ secrets.DEPLOY_TOKEN }}

解读这个流程

三个 job 串联,模拟真实发布管线

test job

跑测试。失败则后面都不跑——bug 代码不会进构建。

build job

needs: test,测试通过才构建。产物存为 artifact。

deploy job

needs: build,下载 artifact 部署。用 secret 存 token。

这是 CI/CD 的经典模式:检查 → 打包 → 发布,每步成功才进下一步。
push 到 main 自动跑完全程,代码就从你的键盘走到了生产环境。

状态徽章

把 CI 状态显示在 README 里——一眼看出项目健康度

![CI](https://github.com/用户/仓库/actions/workflows/test.yml/badge.svg)

效果

README 顶部显示一个徽章:绿色 passing(全部通过)或红色 failing(有失败)。

怎么拿地址

仓库 → Actions → 选某个 workflow → 右上角 ... → Create status badge → 复制 markdown。

开源项目几乎都会在 README 顶部放 CI 徽章——这是项目专业度的标志。

排错:workflow 不触发

push 了 yml,Actions 标签却什么都没有

常见原因

  • 文件不在 .github/workflows/ 目录
  • YAML 缩进错误(最常见)
  • on 触发器写错或过滤不匹配
  • 文件扩展名不是 .yml/.yaml

排查

在 Actions 页面看有没有黄色感叹号的 workflow——那是语法错误。

点进去看具体报错,通常是缩进问题。YAML 对空格敏感,用空格不用 Tab。

排错:step 失败

workflow 跑起来了但某个 step 报红

怎么看

  1. Actions 页面点失败的 run
  2. 展开红色失败的 step
  3. 看完整日志,找错误信息

常见原因

  • 命令在 runner 上不存在(如没装某工具)
  • 测试本身没过(代码 bug)
  • secret 名字写错(值为空)
  • 路径大小写错(Linux 区分大小写)
能在本地复现就先在本地跑。runner 是个 Linux 环境,本地能跑的命令,runner 上大概率也能跑。先确保本地通过再交给 CI。

免费额度

知道边界,避免超额停服

仓库类型每月分钟数说明
公开仓库 无限 完全免费,随便用
私有仓库(免费账号) 2000 分钟 够个人项目

费率换算

  • Linux:1 分钟 = 1 分钟
  • Windows:1 分钟 = 2 分钟
  • macOS:1 分钟 = 10 分钟

所以 macOS 慎用,10 倍费率很快耗尽额度。

动手试一试

给自己的项目加上自动测试

你的任务

任务:为任意已有项目配一个 CI workflow。

要求:

  1. 建 .github/workflows/test.yml
  2. 触发条件:push 和 pull_request
  3. 用 ubuntu-latest,checkout + setup(node 或 python)
  4. 安装依赖并跑测试
  5. push 后在 Actions 标签确认运行成功
  6. 把状态徽章加到 README

提示

  1. 没有测试脚本?先加一个最简单的,如 node -e "console.log('ok')"
  2. YAML 用空格缩进,2 空格最常见
第 07 章

小结

你已经能让代码在 push 后自动测试、构建、部署了

本章要点

  • workflow 放 .github/workflows/*.yml,含 name/on/jobs/steps
  • 触发器:push、pull_request、schedule、workflow_dispatch
  • job 默认并行,用 needs 串依赖
  • matrix 多环境、cache 加速、artifact 存产物
  • 敏感信息一律用 secrets,别写明文
下一步:第 08 章 GitHub Pages —— 用 Actions 自动部署一个作品集个人主页,把你学的 CI/CD 立刻变现。