此页面解释了 act 如何实现 GitHub Actions 的表达式语法和评估系统。它涵盖了表达式评估器的架构、可用上下文和函数以及表达式评估过程。有关使用这些表达式的步骤执行信息,请参阅步骤执行。
GitHub Actions 工作流使用表达式在工作流文件中提供动态值。这些表达式,用 ${{ }} 语法括起来,可以包含变量、函数、运算符和上下文引用。例如
Act 提供了 GitHub Actions 表达式语法的完整实现,以确保工作流在本地运行时与在 GitHub 上运行时一致。
来源:pkg/runner/expression.go22-27 pkg/exprparser/interpreter.go22-28
Act 的表达式系统由几个相互关联的组件组成,用于解析、评估和插值表达式。
ExpressionEvaluator 接口:提供评估表达式和插值带有嵌入式表达式的字符串的方法。
Interpreter:解析和评估表达式语法,处理不同的表达式类型。
EvaluationEnvironment:包含表达式可以访问的所有上下文数据(github、env、steps 等)。
来源:pkg/runner/expression.go22-27 pkg/exprparser/interpreter.go14-28 pkg/exprparser/interpreter.go65-67
act 处理表达式时,遵循以下通用流程:
对于包含多个嵌入部分的表达式,act 会将其重写为格式化函数调用,以保持与 GitHub 行为的兼容性。
来源:pkg/runner/expression.go235-248 pkg/runner/expression.go380-398 pkg/runner/expression.go416-480
表达式可以访问以下上下文:
| 上下文 | 描述 | 示例 |
|---|---|---|
github | 工作流、事件、仓库信息 | github.actor, github.event_name |
env | 环境变量 | env.PATH, env.DEBUG |
inputs | 工作流输入 | inputs.version, inputs.deploy_target |
steps | 前一个步骤的输出和状态 | steps.build.outputs.version, steps.test.conclusion |
job | 当前作业的信息 | job.status |
matrix | 当前作业的矩阵值 | matrix.os, matrix.node-version |
needs | 依赖作业的输出 | needs.build.outputs.result |
secrets | 仓库和组织秘密 | secrets.API_TOKEN |
vars(变量) | 仓库和组织变量 | vars.DEPLOY_ENVIRONMENT |
runner | 运行器环境信息 | runner.os, runner.temp |
上下文访问不区分大小写,与 GitHub 的行为一致(例如,secrets.TOKEN 和 secrets.token 访问相同的值)。
来源:pkg/exprparser/interpreter.go14-28 pkg/exprparser/interpreter.go153-187
Act 支持表达式中的以下函数:
| 功能 | 描述 | 示例 |
|---|---|---|
contains(search, item) | 检查 search 是否包含 item | contains('Hello world', 'world') |
startsWith(search, prefix) | 检查 search 是否以 prefix 开头 | startsWith(github.ref, 'refs/tags/') |
endsWith(search, suffix) | 检查 search 是否以 suffix 结尾 | endsWith(github.ref, 'main') |
format(string, values...) | 使用值格式化字符串 | format('Hello {0}!', github.actor) |
join(array, separator) | 使用分隔符连接数组元素 | join(github.event.issue.labels.*.name, ', ') |
toJSON(value) | 将值转换为 JSON 字符串 | toJSON(github.event) |
fromJSON(value) | 将 JSON 字符串解析为对象 | fromJSON('{"foo":"bar"}').foo |
hashFiles(patterns...) | 计算文件的 SHA-256 哈希 | hashFiles('**/*.js', '**/*.ts') |
| 功能 | 描述 |
|---|---|
success() | 当前面的步骤都没有失败时返回 true |
always() | 始终返回 true |
failure() | 当前面任何步骤失败时返回 true |
cancelled() | 如果工作流被取消,则返回 true |
表达式语法支持这些运算符:
==, !=, >, <, >=, <=&& (and), || (or), ! (not)来源:pkg/exprparser/interpreter.go611-669 pkg/runner/expression_test.go85-145
当表达式在布尔上下文中使用时(例如 if 条件),act 的真值评估类似于 JavaScript:
| 值类型 | 在以下情况下被认为是真值 |
|---|---|
| 布尔值 | true |
| 字符串 | 非空字符串 |
| 数字 | 非零值 |
| 对象/数组 (Object/Array) | 始终为真值 |
| Null/nil | 始终为假值 |
| NaN | 始终为假值 |
此行为确保与 GitHub Actions 的表达式评估兼容。
来源:pkg/runner/expression.go401-410 pkg/exprparser/interpreter.go531-556
当表达式嵌入到字符串中时,act 会通过将其评估值替换表达式来执行插值。
对于一个字符串中的多个表达式,act 内部使用格式化函数调用。
来源:pkg/runner/expression.go380-398 pkg/runner/expression.go416-480
Act 对 YAML 节点中的表达式评估有特殊处理,允许复杂的动态配置。
${{ insert }} 指令用于合并对象。这使得工作流作者能够创建高度动态的配置,这些配置可以根据上下文进行调整。
来源:pkg/runner/expression.go246-378
hashFiles 函数计算匹配 glob 模式的文件的 SHA-256 哈希值。在 act 中,这是通过一个专用的 JavaScript 模块实现的,该模块:
此函数对于缓存键和基于文件更改的条件执行非常有用。
来源:pkg/runner/expression.go170-229 pkg/runner/hashfiles/index.js
act 中的表达式评估系统基于几个关键的实现选择:
actionlint 解析表达式语法。success())。这些实现细节确保 act 在本地运行工作流时能够正确复制 GitHub Actions 的行为。
来源:pkg/exprparser/interpreter.go81-92 pkg/runner/expression.go109-168