Appearance
运行时上下文
workflow 真正跑起来后,业务代码能拿到的核心对象就是 context
WorkflowRuntimeContext 里最重要的字段
| 字段 | 作用 |
|---|---|
| values | 当前已解析的输入值 |
| results | 当前已产生的步骤结果 |
| locale | 当前运行语言 |
| timeZone | 当前运行时区 |
| runId | 当前运行唯一标识 |
| workflowId | 当前 workflow 标识 |
| tools | 文件、JSON、glob、sleep、命令探测等辅助函数 |
| colors | picocolors 实例 |
| 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';
},
};
},
};