Skip to content

运行时上下文

返回总览

workflow 真正跑起来后,业务代码能拿到的核心对象就是 context

WorkflowRuntimeContext 里最重要的字段

字段作用
values当前已解析的输入值
results当前已产生的步骤结果
locale当前运行语言
timeZone当前运行时区
runId当前运行唯一标识
workflowId当前 workflow 标识
tools文件、JSON、glob、sleep、命令探测等辅助函数
colorspicocolors 实例
log、note、box结构化输出接口
t翻译函数

values 和 results 在运行中如何变化

运行时读取 context 时,要记住它们都是逐步累积的

  • 前面的输入步骤完成后,values 会立刻可读
  • 前面的命令步骤返回后,results 会立刻可读
  • 后面的步骤不能提前读取尚未产生的数据
ts
defineStep.command({
  id: 'build',
  title: '构建项目',
  async run(context) {
    if (context.values.environment === 'production') {
      return { minify: true };
    }
    return { minify: false };
  },
});

tools 里自带什么

context.tools 里默认有这些能力

方法作用
commandExists检查某个可执行命令或路径是否可用
readFile读取文本文件
readJson读取 JSON 文件
writeFile写文本文件
writeJson写 JSON 文件
patchJson读改写 JSON 文件
globFiles查询匹配文件
sleep休眠
clack原始 @clack/prompts runtime
projectRoot当前项目根目录

这些工具既可以在 onStart、onComplete 中使用,也可以在 command 的 run(context, io) 中配合业务逻辑使用

如果要在 when 中做“某个命令存在才执行”的分支,直接用 context.tools.commandExists() 就够了

ts
defineStep.command({
  id: 'docker-pull',
  command: 'docker pull alpine:latest',
  when(context) {
    return context.tools.commandExists('docker');
  },
});

onStart 和 onComplete 里的 context

onStart

onStart 适合做运行前准备

  • 输出说明
  • 校验外部状态
  • 读取额外配置文件

onComplete

onComplete 适合做运行后收尾

  • 输出自定义总结
  • 根据 results 写补充文件
  • 做通知和归档
ts
const workflow = defineWorkflow({
  id: 'release',
  async onStart(context) {
    context.log('info', `开始执行 ${context.workflowId}`);
  },
  async onComplete(context) {
    await context.tools.writeJson('tmp/result.json', {
      values: context.values,
      results: context.results,
    });
  },
  steps,
});

colors 和结构化输出

context.colors 是 picocolors 实例,不必额外引入颜色库

ts
const workflow = defineWorkflow({
  id: 'deploy',
  onStart(context) {
    context.note(context.colors.cyan('将要开始部署'), '提示');
  },
  steps,
});

colors、log、note、box 这些能力适合做流程级说明,不适合替代 command 步骤的 stdout 和 stderr

run 结果里的 snapshot 和 events

WorkflowRunResult 还提供两个常用入口

  • events,直接读取结构化事件列表
  • snapshot(),读取完整运行快照

当 logs 已启用但尚未保存到磁盘时,这两个入口仍然可用

扩展后的 tools 会出现在什么位置

插件通过 extendContextTools 返回的新能力,会挂到 context.tools 上

ts
const plugin = {
  name: 'repo-tools',
  extendContextTools(tools) {
    return {
      ...tools,
      readPackageName: async () => {
        const pkg = await tools.readJson<{ name?: string }>('package.json');
        return pkg.name ?? 'unknown';
      },
    };
  },
};

下一步建议