跳至主要内容

在工作流和操作中评估表达式

您可以在工作流和操作中评估表达式。

关于表达式

您可以使用表达式以编程方式在工作流文件中设置环境变量并访问上下文。表达式可以是字面值、上下文引用或函数的任意组合。您可以使用运算符组合字面量、上下文引用和函数。有关上下文的更多信息,请参阅“访问有关工作流运行的上下文信息”。

表达式通常与工作流文件中的条件if关键字一起使用,以确定是否应运行步骤。当if条件为true时,将运行该步骤。

您需要使用特定语法来告诉 GitHub 评估表达式,而不是将其视为字符串。

${{ <expression> }}

注意

此规则的例外情况是当您在if子句中使用表达式时,您可以选择省略${{}}。有关if条件的更多信息,请参阅“GitHub Actions 的工作流语法”。

警告

创建工作流和操作时,应始终考虑您的代码是否可能会执行来自潜在攻击者的不受信任的输入。某些上下文应被视为不受信任的输入,因为攻击者可能会插入他们自己的恶意内容。有关更多信息,请参阅“GitHub Actions 的安全加固”。

设置环境变量的示例

env:
  MY_ENV_VAR: ${{ <expression> }}

字面量

作为表达式的一部分,您可以使用booleannullnumberstring数据类型。

数据类型字面值
booleantruefalse
nullnull
numberJSON 支持的任何数字格式。
string您不需要将字符串括在${{}}中。但是,如果您这样做,则必须使用单引号 (') 括起字符串。要使用字面单引号,请使用另一个单引号 ('') 转义字面单引号。用双引号 (") 括起来会引发错误。

请注意,在条件语句中,虚假值 (false0-0""''null) 会强制转换为false,而真值 (true和其他非虚假值) 会强制转换为true

字面量的示例

env:
  myNull: ${{ null }}
  myBoolean: ${{ false }}
  myIntegerNumber: ${{ 711 }}
  myFloatNumber: ${{ -9.2 }}
  myHexNumber: ${{ 0xff }}
  myExponentialNumber: ${{ -2.99e-2 }}
  myString: Mona the Octocat
  myStringInBraces: ${{ 'It''s open source!' }}

运算符

运算符描述
( )逻辑分组
[ ]索引
.属性取消引用
!
<小于
<=小于或等于
>大于
>=大于或等于
==等于
!=不等于
&&
||

注意

  • 比较字符串时,GitHub 会忽略大小写。
  • steps.<step_id>.outputs.<output_name> 会被评估为字符串。您需要使用特定的语法来告诉 GitHub 评估表达式而不是将其视为字符串。更多信息,请参见“访问有关工作流运行的上下文信息”。
  • 对于数值比较,可以使用 fromJSON() 函数将字符串转换为数字。有关 fromJSON() 函数的更多信息,请参见“fromJSON”。

GitHub 执行宽松的相等性比较。

  • 如果类型不匹配,GitHub 会将类型强制转换为数字。GitHub 使用以下转换将数据类型转换为数字:

    类型结果
    Null0
    布尔值true 返回 1
    false 返回 0
    字符串从任何合法的 JSON 数字格式解析,否则返回 NaN
    注意:空字符串返回 0
    数组NaN
    对象NaN
  • NaN 是任何关系比较运算符 (>, <, >=, <=) 的操作数之一时,结果始终为 false。更多信息,请参见“NaN Mozilla 文档”。

  • 比较字符串时,GitHub 会忽略大小写。

  • 只有当对象和数组是同一个实例时,它们才被认为是相等的。

GitHub 提供类似三元运算符的行为,您可以在表达式中使用它。通过这种方式使用三元运算符,您可以根据条件动态设置环境变量的值,而无需为每个可能的选项编写单独的 if-else 块。

示例

env:
  MY_ENV_VAR: ${{ github.ref == 'refs/heads/main' && 'value_for_main_branch' || 'value_for_other_branches' }}

在此示例中,我们使用三元运算符根据 GitHub 引用是否设置为 refs/heads/main 来设置 MY_ENV_VAR 环境变量的值。如果设置为 refs/heads/main,则变量设置为 value_for_main_branch。否则,它将设置为 value_for_other_branches。需要注意的是,&& 后的第一个值必须为真值。否则,|| 后的值将始终被返回。

函数

GitHub 提供了一组内置函数,您可以在表达式中使用它们。某些函数会将值转换为字符串以执行比较。GitHub 使用以下转换将数据类型转换为字符串:

类型结果
Null''
布尔值'true''false'
数字十进制格式,大数字用指数表示
数组数组不会转换为字符串
对象对象不会转换为字符串

contains

contains( search, item )

如果 search 包含 item,则返回 true。如果 search 是一个数组,则如果 item 是数组中的一个元素,此函数返回 true。如果 search 是一个字符串,则如果 itemsearch 的子字符串,此函数返回 true。此函数不区分大小写。将值转换为字符串。

使用字符串的示例

contains('Hello world', 'llo') 返回 true

使用对象过滤器的示例

如果与事件相关的 issue 具有标签“bug”,则 contains(github.event.issue.labels.*.name, 'bug') 返回 true

更多信息,请参见“对象过滤器”。

匹配字符串数组的示例

无需编写 github.event_name == "push" || github.event_name == "pull_request",您可以使用带有 fromJSON()contains() 来检查字符串数组是否包含 item

例如,如果 github.event_name 是“push”或“pull_request”,则 contains(fromJSON('["push", "pull_request"]'), github.event_name) 返回 true

startsWith

startsWith( searchString, searchValue )

searchStringsearchValue 开头时返回 true。此函数不区分大小写。将值转换为字符串。

startsWith 的示例

startsWith('Hello world', 'He') 返回 true

endsWith

endsWith( searchString, searchValue )

如果 searchStringsearchValue 结尾,则返回 true。此函数不区分大小写。将值转换为字符串。

endsWith 的示例

endsWith('Hello world', 'ld') 返回 true

format

format( string, replaceValue0, replaceValue1, ..., replaceValueN)

使用变量 replaceValueN 替换 string 中的值。string 中的变量使用 {N} 语法指定,其中 N 是一个整数。您必须至少指定一个 replaceValuestring。您可以使用的变量 (replaceValueN) 数量没有上限。使用双花括号转义花括号。

format 的示例

format('Hello {0} {1} {2}', 'Mona', 'the', 'Octocat')

返回 'Hello Mona the Octocat'。

转义花括号的示例

format('{{Hello {0} {1} {2}!}}', 'Mona', 'the', 'Octocat')

返回 '{Hello Mona the Octocat!}’。

join

join( array, optionalSeparator )

array 的值可以是数组或字符串。array 中的所有值都连接到一个字符串中。如果您提供 optionalSeparator,它将插入到连接的值之间。否则,将使用默认分隔符 ,。将值转换为字符串。

join 的示例

join(github.event.issue.labels.*.name, ', ') 可能返回 'bug, help wanted'

toJSON

toJSON(value)

返回 value 的漂亮打印 JSON 表示形式。您可以使用此函数调试上下文中提供的信息。

toJSON 的示例

toJSON(job) 可能返回 { "status": "success" }

fromJSON

fromJSON(value)

返回 value 的 JSON 对象或 JSON 数据类型。您可以使用此函数提供 JSON 对象作为已评估的表达式,或转换任何可以用 JSON 或 JavaScript 表示的数据类型,例如字符串、布尔值、null 值、数组和对象。

返回 JSON 对象的示例

此工作流在一个作业中设置 JSON 矩阵,并使用输出和 fromJSON 将其传递给下一个作业。

YAML
name: build
on: push
jobs:
  job1:
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.set-matrix.outputs.matrix }}
    steps:
      - id: set-matrix
        run: echo "matrix={\"include\":[{\"project\":\"foo\",\"config\":\"Debug\"},{\"project\":\"bar\",\"config\":\"Release\"}]}" >> $GITHUB_OUTPUT
  job2:
    needs: job1
    runs-on: ubuntu-latest
    strategy:
      matrix: ${{ fromJSON(needs.job1.outputs.matrix) }}
    steps:
      - run: echo "Matrix - Project ${{ matrix.project }}, Config ${{ matrix.config }}"

返回 JSON 数据类型的示例

此工作流使用 fromJSON 将环境变量从字符串转换为布尔值或整数。

YAML
name: print
on: push
env:
  continue: true
  time: 3
jobs:
  job1:
    runs-on: ubuntu-latest
    steps:
      - continue-on-error: ${{ fromJSON(env.continue) }}
        timeout-minutes: ${{ fromJSON(env.time) }}
        run: echo ...

此工作流使用 fromJSON() 函数将环境变量 continue 从字符串转换为布尔值,从而确定是否继续执行错误或不继续执行错误。类似地,它将环境变量 time 从字符串转换为整数,以分钟为单位设置作业的超时时间。

hashFiles

hashFiles(path)

返回与 path 模式匹配的文件集的单个哈希值。您可以提供单个 path 模式或多个用逗号分隔的 path 模式。path 相对于 GITHUB_WORKSPACE 目录,并且只能包含 GITHUB_WORKSPACE 内的文件。此函数为每个匹配的文件计算单个 SHA-256 哈希值,然后使用这些哈希值来计算文件集的最终 SHA-256 哈希值。如果 path 模式与任何文件都不匹配,则返回空字符串。有关 SHA-256 的更多信息,请参见“SHA-2”。

您可以使用模式匹配字符来匹配文件名。hashFiles 的模式匹配遵循 glob 模式匹配,在 Windows 上不区分大小写。有关支持的模式匹配字符的更多信息,请参见 @actions/glob 文档中的模式部分。

使用单个模式的示例

匹配存储库中的任何 package-lock.json 文件。

hashFiles('**/package-lock.json')

使用多个模式的示例

为存储库中的任何 package-lock.jsonGemfile.lock 文件创建哈希值。

hashFiles('**/package-lock.json', '**/Gemfile.lock')

状态检查函数

您可以将以下状态检查函数用作 if 条件中的表达式。除非您包含这些函数之一,否则将应用 success() 的默认状态检查。有关 if 条件的更多信息,请参见“GitHub Actions 的工作流语法”和“GitHub Actions 的元数据语法”。

success

当所有先前步骤都成功时返回 true

success 的示例

steps:
  ...
  - name: The job has succeeded
    if: ${{ success() }}

always

导致步骤始终执行并返回 true,即使被取消也是如此。always 表达式最好用于步骤级别或您期望即使作业被取消也要运行的任务。例如,即使作业被取消,您也可以使用 always 发送日志。

警告

避免将 always 用于任何可能遭受严重故障的任务,例如:获取源代码,否则工作流可能会挂起直到超时。如果您想运行作业或步骤而不管其成功或失败,请使用推荐的替代方法:if: ${{ !cancelled() }}

always 的示例

if: ${{ always() }}

cancelled

如果工作流被取消,则返回 true

cancelled 的示例

if: ${{ cancelled() }}

failure

当作业的任何先前步骤失败时返回 true。如果您有一系列依赖作业,则如果任何祖先作业失败,failure() 将返回 true

failure 的示例

steps:
  ...
  - name: The job has failed
    if: ${{ failure() }}

带条件的 failure

您可以为步骤在失败后运行包含额外的条件,但是您仍然必须包含 failure() 来覆盖自动应用于不包含状态检查函数的 if 条件的默认状态检查 success()

带条件的 failure 的示例
steps:
  ...
  - name: Failing step
    id: demo
    run: exit 1
  - name: The demo step has failed
    if: ${{ failure() && steps.demo.conclusion == 'failure' }}

对象过滤器

您可以使用*语法应用过滤器并选择集合中匹配的项。

例如,考虑一个名为fruits的对象数组。

[
  { "name": "apple", "quantity": 1 },
  { "name": "orange", "quantity": 2 },
  { "name": "pear", "quantity": 1 }
]

过滤器fruits.*.name将返回数组[ "apple", "orange", "pear" ]

您也可以在对象上使用*语法。例如,假设您有一个名为vegetables的对象。


{
  "scallions":
  {
    "colors": ["green", "white", "red"],
    "ediblePortions": ["roots", "stalks"],
  },
  "beets":
  {
    "colors": ["purple", "red", "gold", "white", "pink"],
    "ediblePortions": ["roots", "stems", "leaves"],
  },
  "artichokes":
  {
    "colors": ["green", "purple", "red", "black"],
    "ediblePortions": ["hearts", "stems", "leaves"],
  },
}

过滤器vegetables.*.ediblePortions可能评估为


[
  ["roots", "stalks"],
  ["hearts", "stems", "leaves"],
  ["roots", "stems", "leaves"],
]

由于对象不保留顺序,因此无法保证输出的顺序。