Course Builder个人学习工作台 · 本地模式
mise 实战:从工具版本到可复现 CI

M008:Capstone:从 fresh checkout 到 CI 的可复现环境

目标:用一条从配置、lockfile、统一 task 到 clean checkout 与 CI 的证据链,判断仓库是否真正可复现。

0–5 分钟:先定义交付包和判定规则

Capstone 不是再加一个命令,而是把前七课连成一个可验证系统。最终仓库至少包含:

mise.toml          # min_version、tools、env、check/ci tasks
mise.lock          # 具体解析结果与可用的平台工件信息
mise-tasks/        # 需要时保存复杂 file tasks
.env.example       # 只有变量契约和安全假值
.gitignore         # 排除 local 与真实 secret 文件
CI workflow        # locked install + 同一个 mise run ci
README-mise.md     # 启动、更新、故障排查与安全边界

在运行前写判定规则:

只有 clean checkout 在不依赖个人 shell rc/local 文件的情况下完成 locked install,
并且本地与 CI 调用同一个 mise run ci,负向测试也按预期失败,才判定 adopt;
否则判定 revise,并列出缺口。

这样可以避免看到绿色 CI 后临时降低标准。[S03][S04][S05][S06]

5–14 分钟:组装并静态审阅仓库契约

步骤 1:检查必要文件

在你的实验仓库或真实候选仓库根运行:

for file in mise.toml mise.lock .env.example .gitignore README-mise.md; do
  test -f "$file" && printf 'OK %s\n' "$file" || printf 'MISSING %s\n' "$file"
done

任何 MISSING 都先补齐,不要进入 clean checkout 测试。

步骤 2:审阅配置的六个问题

逐项回答:

  1. [tools] 是否至少声明两个项目实际需要的工具?
  2. 是否有安全默认 env,以及至少一个从外部提供的 required 输入?
  3. task 是否把 fmt/lint/test 等叶子检查聚合为 check,再由 ci 复用?
  4. 是否存在个人绝对路径、真实 token 或未说明的 _.source/hook?
  5. min_version 是否与使用的配置能力一致?
  6. lockfile 是否覆盖本地与 CI 平台,backend 限制是否被记录?

步骤 3:运行静态 secret 检查

git status --short
git ls-files | grep -E '(^|/)(\.env|mise\.local\.toml)$' && printf 'REVIEW tracked local file\n' || true

这不是完整 secret scanner,但能发现课程中最常见的边界错误。若出现真实凭据,先轮换和清理,再继续。

14–21 分钟:从 clean checkout 验证,而不是在工作目录自证

当前工作目录可能靠缓存、local 文件或未提交改动成功。必须建立新的 checkout。

步骤 1:提交实验状态并创建 clean clone

对可丢弃仓库:

git status --short
git add mise.toml mise.lock .env.example .gitignore README-mise.md
# 同时添加项目源码、tests、必要的 mise-tasks 和 CI workflow
git commit -m 'Add reproducible mise environment'

rm -rf /tmp/mise-capstone-clone
git clone "$(pwd)" /tmp/mise-capstone-clone
cd /tmp/mise-capstone-clone
git status --short

预期观察:新 clone 工作树干净,且没有 mise.local.toml 或真实 .env。真实仓库不方便本地 clone 时,可使用新的 worktree,但要明确它是否共享缓存和 trust 状态。

步骤 2:不 activation,显式安装并运行

mise install --locked
mise run ci
printf 'ci_exit=%s\n' "$?"

若项目还没有 ci task,先回原仓库定义它,使其复用 check,而不是在 clone 里临时执行 lint/test。显式 mise run ci 证明入口不依赖个人 shell rc。[S05][S09]

步骤 3:记录工具身份

mise ls --current
mise which python 2>/dev/null || true
mise which node 2>/dev/null || true
mise config

证据应能串起:加载的配置 → 版本选择器/lock 结果 → 二进制路径 → task 输出。只有绿色退出码,无法排除跑到系统工具的可能。

21–26 分钟:做两个负向测试

负向测试 A:required 输入缺失

选择一个不会接触生产系统的 task,在不注入 required 假值时运行:

unset API_TOKEN
mise run ci
printf 'missing_secret_exit=%s\n' "$?"

预期尽早非零失败,并显示变量用途,不打印值。然后用课程专用假值恢复成功:

API_TOKEN='course-only-not-a-secret' mise run ci

如果 ci 实际不需要该变量,应把 required 约束放在真正需要它的 deploy task,而不是为了通过课程强行耦合。

负向测试 B:lock 缺口

在临时副本修改 mise.toml 增加一个未锁定且 backend 可严格检查的工具,然后运行:

mise install --locked
printf 'missing_lock_exit=%s\n' "$?"

预期非零失败;若 backend 能力导致跳过,报告“该控制不覆盖此工具”,并为目标平台选择可验证的替代测试。完成后丢弃临时副本,不手改 lockfile。

26–29 分钟:让 CI 与本地真正收敛

CI workflow 的逻辑应保持短:checkout、安装固定/受审阅的 mise、locked install、调用同一 task。示意结构:

steps:
  - uses: actions/checkout@<reviewed-major>
  - uses: jdx/mise-action@<reviewed-major>
    with:
      install: false
  - run: mise install --locked
  - run: mise run ci

action major、mise 版本和缓存策略会变化,发布时应以当前官方 CI 文档为准。[S09] 评审 workflow 时逐项核对:

  1. CI 是否复制了 lint/test 命令?若是,改回 mise run ci。
  2. cache key 是否包含 mise.toml 与 mise.lock,避免旧缓存掩盖变更?
  3. fork PR 是否获得不必要的 secret?
  4. 正常 test job 是否错误开启 safe mode,导致 task 根本不能运行?
  5. 专门处理不可信配置的 lock-bump job 是否使用 MISE_SAFE=1 且不持有业务 secret?[S08]

29–30 分钟:做采用决定

按证据填写,不允许只写“基本没问题”:

结论:ADOPT / REVISE
clean checkout:通过/失败,证据是 ____
本地与 CI 统一入口:通过/失败,证据是 ____
目标平台 lock 覆盖:____
secret 边界:____
trust/safe mode 边界:____
已验证负向行为:____
剩余风险:____
下一次 lock 更新触发条件与回滚方法:____

Worked verdict

结论:REVISE
原因:macOS clean clone 与 mise run ci 成功,但 mise.lock 没有 Linux CI 所需的平台 URL;
required secret 负向测试通过,CI 也调用统一 task。
下一步:在 linux-x64 生成并审阅 lock 信息,再重跑 locked install;其他证据保留。

这个结论比“CI 绿了,所以完成”更强,因为它没有让一个成功指标掩盖平台缺口。

常见失败与下一步:

  • clone 成功、CI 失败:比较 mise --version、mise config、目标平台和 secret 注入,不要在 CI 复制一套临时命令。
  • 本地只有 activation 后成功:把入口改成 mise run ci 或 mise exec,再在全新非交互 shell 验证。
  • cache 命中后看似成功:清理/更换 cache key 做一次冷启动验证。
  • lock-bump job 需要执行 task:重新拆分职责;不可信解析 job 与受审阅 test job 不应共享权限模型。

通过标准

  • clean checkout 不依赖个人 shell rc、未提交 local 文件或工作区脏改动。
  • 本地与 CI 都调用同一个 mise run ci。
  • 工具身份、lock 平台覆盖和 backend 限制都有可追溯证据。
  • required 输入与 lock 缺口各有一次可诊断的负向验证。
  • 最终结论明确是 ADOPT 或 REVISE,并列出剩余风险与下一次更新/回滚条件。

Sources used

  • S03 jdx/mise, Configuration.
  • S04 jdx/mise, Environments.
  • S05 jdx/mise, Tasks.
  • S06 jdx/mise, mise.lock Lockfile.
  • S08 jdx/mise, Security.
  • S09 jdx/mise, Continuous integration.