Files
cs-note/hzh/CICD/CICD 在 Slidev 中的应用/workflow-configuration.md
T

6.9 KiB
Raw Blame History

tags, create time
tags create time
CI/CD
Gitea Actions
Slidev
2026-05-27 19:30

Workflow 配置详解

概述

本文档对 CICD 在 Slidev 中的应用 中的 Workflow YAML 进行逐块解析,涵盖从触发条件到构建部署的每一步配置逻辑。

[!NOTE] 如需了解部署架构和容器通信模式,详见 deployment-strategy。

正文

1. 触发条件

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

向 main 分支推送代码或提交 PR 时都会触发。这意味着开发者通过特性分支提 PR,CI 会先验证构建是否通过——只有合并到主干后才执行部署。

[!TIP] PR 事件只适合跑验证性步骤(build、lint),实际部署仍保留在 push: main 中,因为 PR 上下文通常没有写入权限。如果 Gitea Actions 的 PR 事件无法读取 secret,可改用 pull_request_target,但需避免直接使用 PR 代码中的敏感操作以防止 token 泄露。

[!QUESTION] 思考:如果你的 Slidev 项目需要同时支持 staging 和 production 环境,你会如何设计触发规则?

2. 运行环境与容器

jobs:
  build-and-deploy:
    runs-on: aliyun
    container: node:22-alpine
  • runs-on: aliyun — 使用了自定义的 Gitea runner,运行在一台阿里云机器上(而非官方 GitHub-hosted runner)。
  • container: node:22-alpine — 在 Alpine Linux 上的 Node.js 22 容器中执行,体积小、启动快,适合纯前端构建场景。

3. 安装系统工具

- name: Install tools
  run: |
    sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
    apk add --no-cache docker-cli git

Alpine 默认的软件源在海外,先用 sed 替换为阿里云镜像源加速下载。然后安装三个必要的工具:

工具 用途
docker-cli 指挥宿主机 Docker daemon,管理其他容器的生命周期
git 版本控制操作所需
apk Alpine 的包管理器(已内置)

[!NOTE] 这里只安装了 docker-cli(客户端),没有安装完整的 docker。完整的 Docker 包包含 daemon 本身(约 80MB),而我们需要的是轻量级 CLI(约 50MB on Alpine)——因为 daemon 已经在宿主机上运行了。

4. 检出代码 (Checkout)

- name: Checkout
  uses: http://47.121.181.112:3000/wonder/checkout@v4
  with:
    github-server-url: http://47.121.181.112:3000

使用私有 Gitea 实例的 checkout action,指向地址 http://47.121.181.112:3000。通过 github-server-url 参数告知 action 正确的 Gitea 服务器地址。

Checkout 到底做了什么?

很多开发者误以为 workflow 启动后工作目录里已经有代码了——实际上 runner 初始环境是空的。Checkout action 会在幕后执行一系列 git 操作:

flowchart LR
    A["Runner 启动<br/>空工作目录"] --> B["git clone 仓库"]
    B --> C["git fetch 指定 commit 的引用"]
    C --> D["git reset --hard 精确 SHA"]
    D --> E[".git 隐藏目录<br/>pnpm install 可用"]
步骤 Git 命令等价物 作用
Clone git clone <repo-url> 拉取全量历史到 action 工作区
Fetch git fetch origin <commit-sha> 获取触发 workflow 的具体 commit 引用
Reset git reset --hard <commit-sha> 将工作树精确还原到目标提交(而非默认分支最新)

[!TIP] PR 场景下尤其要注意:如果 workflow 被 pull_request 事件触发,Checkout 会自动检出 PR 合并后的结果(即 refs/pull/<number>/merge),而不是 PR 分支本身。这确保了 CI 验证的是"合并后能否构建",而非"分支本身能否构建"。

常用配置参数

实际项目中经常需要调整 checkout 的行为,以下是高频参数及适用场景:

参数 默认值 用途
ref 触发 workflow 的 commit SHA 指定检出的分支、标签或 commit
clean true 检出前是否清理工作目录残留文件
persist-credentials true 是否在后续步骤中保持 git 认证信息
fetch-depth 1 只拉取最近一次提交(fast clone)

[!QUESTION] 什么时候应该设置 fetch-depth: 0?

答案:当你需要完整的 git 历史时——比如用 git log 生成 changelog、执行语义化版本计算 (conventional-changelog),或者需要 git blame 追溯代码来源。fetch-depth: 1 是默认值,因为它更快更省空间;只有确实需要历史记录时才改为 0。

[!WARNING] 安全注意:CI 中的 checkout 会拿到完整的 repo token。如果 workflow 包含不可信的第三方 action(如开源社区提供的 step),建议设置 persist-credentials: false,防止 token 被泄露给非官方代码。

5. 安装依赖与构建

- name: Install pnpm
  run: npm install -g pnpm

- name: Install dependencies
  run: pnpm install --frozen-lockfile

- name: Build all decks
  run: pnpm run build

三步完成从包管理到构建的过程:

  1. 全局安装 pnpm — 容器初始状态只有 Node.js,需要先装包管理器
  2. 安装项目依赖 — --frozen-lockfile 确保依赖版本精确锁定(详见下方说明)
  3. 执行构建 — pnpm run build 对应 slidev build,将所有 .md deck 编译为静态站点

[!TIP] Slidev 的 build 命令输出目录默认为 dist/,每个 slide deck 一个子目录。这就是为什么最后一步可以直接 cp dist/. nginx:/usr/share/nginx/html/。

--frozen-lockfile 的 CI 哲学

# 不加参数:lockfile 被悄悄更新 → 下次构建可能用不同版本
pnpm install

# 加 --frozen-lockfile:严格一致,否则立即失败
pnpm install --frozen-lockfile
场景 不加 --frozen-lockfile 加上 --frozen-lockfile
lockfile 正常 ✅ 安装 ✅ 安装
lockfile 缺失 🔧 自动生成一个新的 ❌ 报错退出
lockfile 与 package.json 不匹配 🔧 悄悄更新 lockfile ❌ 报错退出

CI 环境追求的是 构建可复现性 (Build Reproducibility)。同一个 commit,不同的人、不同的时间、不同的机器上构建出来的结果必须完全一致——否则线上 bug 将无法定位是"代码问题"还是"环境差异"。

flowchart LR
    A["开发者修改 package.json"] --> B{"push"}
    B --> C["CI: frozen-lockfile 检查"]
    C -->|lockfile 已同步| D["✅ 构建通过"]
    C -->|lockfile 未同步| E["❌ 立即失败<br/>提示手动运行 pnpm install"]

    style E fill:#ffe8e8
    style D fill:#e8ffe8

[!TIP] 正确的工作流:开发者改完依赖 → pnpm install 自动更新 lockfile → 同时提交两个文件。CI 只负责验证一致性,不负责修锁。

关联笔记

  • CICD 在 Slidev 中的应用
  • deployment-strategy