先把概念弄清楚

在 GitHub 生态里,大家说的 CI/CD,绝大多数场景指的就是 GitHub Actions:用仓库里的 YAML 描述「什么时候跑什么命令」,在 GitHub 托管的 Runner(或自建 Runner)上自动执行。

我这篇文章按「能跑 → 能看懂 → 能改」写:
触发器 → Workflow → Job → Step → 密钥与权限 → 一条常见前后端都能套用的流水线骨架。

说明: 以下 YAML 以 GitHub Actions 当前通用写法为准;若你读到旧教程仍写 ::set-output,请改用官方推荐的 $GITHUB_OUTPUT 写法(后文会提)。


一、核心概念:你写的不是“脚本网页”,是状态机

概念 一句话
Workflow(工作流) 仓库 .github/workflows/ 下的一个 YAML 文件,定义一整条流水线
Event(事件) 什么时候触发:push、pull_request、schedule、workflow_dispatch 等
Job(任务) 一组在同一 Runner 上顺序执行的 Steps;多个 Job 可并行或 needs 串联
Step(步骤) 真正跑命令或调用 Action 的最小单元
Action 别人封装好的可复用步骤(例如 checkout、setup-node)
Runner 执行环境,常用 ubuntu-latest

一句话结论:CI 多半是「每次提交自动验货」;CD 多半是「验货通过后自动发布」——可以写在同一个 Workflow,也可以拆成两个文件,团队怎么清晰怎么来。


二、最小可运行示例:PR / Push 时跑测试

在仓库创建:.github/workflows/ci.yml

name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

permissions:
  contents: read

jobs:
  build-test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm

      - name: Install
        run: npm ci

      - name: Lint
        run: npm run lint --if-present

      - name: Test
        run: npm test --if-present

这段在干什么:

  • on:有人往 main 推代码,或向 main 提 PR,就跑一遍
  • permissions: contents: read:显式收紧权限(很多团队会要求默认最小权限)
  • npm ci:比 npm install 更适合 CI(锁文件一致时更可复现)

如果你第一次跑失败,别慌:把本地 package.json 里的脚本名对照一下——很多项目不叫 lint/test


三、CD:什么时候算“部署”

部署没有标准答案,常见三种触发:

  1. 推送到 main 自动发布(快,但要配合分支保护与评审)
  2. 打 Tag(v1.2.3)触发发布(更可控)
  3. 手动 workflow_dispatch(适合低频发布)

下面给一个「合并进 main 后构建产物」的骨架(部署动作因云平台而异,我用占位表达):

name: Release

on:
  push:
    branches: [main]

permissions:
  contents: read
  id-token: write   # 若你用 OIDC 连云(常见),很多教程需要这一项

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production   # 建议在仓库 Settings → Environments 配置保护规则
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm

      - run: npm ci
      - run: npm run build

      # 下面这一步因目标平台不同而不同:Vercel / OSS / K8s / 虚拟机……
      # - name: Deploy
      #   run: ...

关键点: environment: production 不是摆设——你可以给生产环境加 required reviewerswait timer,让 CD 不那么“误触”。


四、Secrets:别把密钥写进 YAML

你会在教程里看到:

env:
  SOME_TOKEN: ${{ secrets.SOME_TOKEN }}

正确姿势:

  • 在 GitHub 仓库 Settings → Secrets and variables → Actions 里配置
  • YAML 里只引用 secrets.*,不要把真实 token 提交进 Git

如果是团队项目,还要分清:

  • Repository secrets:本仓库可用
  • Organization secrets:组织级统一下发(视权限)

五、矩阵构建:一次测多个版本

比如你要同时验证 Node 18/20:

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [18, 20]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: npm
      - run: npm ci
      - run: npm test --if-present

这类写法特别适合开源库:兼容性问题越早暴露越好


六、缓存:省钱也省时间

前端项目常见瓶颈是依赖安装。setup-nodecache: npm 是一键方案;更复杂场景可以用 actions/cache 自己控 key(Monorepo 时常用)。

原则只有一句:缓存是为了快,不是为了“掩盖不稳定的构建”。 锁文件该锁还是要锁。


七、我踩过/见过的坑(建议你直接对照)

  1. 权限默认过宽:能 permissions: 收紧就收紧;需要写内容、发 Release 再逐步放开。
  2. 把部署密钥塞仓库:哪怕私有仓也不建议;优先 OIDC 或短期令牌方案(依云厂商文档)。
  3. 同一 Workflow 里又测又发版:可以,但要清楚分支条件;很多人用 if: 区分 pull_requestpush
  4. Runner 时区/环境变量:CI 里“本地能跑”经常是因为本地有全局工具;把依赖写进项目与 Workflow。
  5. 输出变量:旧式 ::set-output 已不推荐,改用:
- name: Set version
  id: ver
  run: echo "version=$(node -p \"require('./package.json').version\")" >> $GITHUB_OUTPUT

Windows Runner 上路径/换行有差异时,要以官方文档为准(跨平台项目尤其要注意)。


八、总结:你怎么判断自己“会用 CI/CD 了”

你可以用这张清单自测:

  • 能解释 on / jobs / steps / runs-on 各自管什么
  • 能给项目加一条 PR 必过的检查(至少 lint 或 test)
  • 知道 Secrets 放哪、YAML 里怎么引用
  • 知道生产部署要用 environment 或等价门禁,而不是“谁 push 谁上线”

欢迎点赞关注,一起学习进步~~~

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐