# 对工作流和操作中的表达式求值

在 GitHub Actions 中查找有关表达式的信息。

## 文本

作为表达式的一部分，可使用 `boolean`、`null`、`number` 或 `string` 数据类型。

| 数据类型             | 文本值                                                                                                           |
| ---------------- | ------------------------------------------------------------------------------------------------------------- |
| `boolean`        |                                                                                                               |
| `true` 或 `false` |                                                                                                               |
| `null`           | `null`                                                                                                        |
| `number`         | JSON 支持的任何数字格式。                                                                                               |
| `string`         | 无需将字符串括在 `${` 和 `}` 中。 但是，如果这样做，则必须在字符串两边使用单引号 (`'`)。 要使用文本单引号，请使用额外的单引号 (`''`) 转义文本单引号。 用双引号 (`"`) 括起来会引发错误。 |

请注意，在条件中，假值（`false`、`0`、`-0`、`""`、`''`、`null`）被强制转换为 `false`，且真值（`true` 和其他非假值）被强制转换为 `true`。

### 文本示例

```yaml
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!' }}
```

## 运营商

| 操作员               | 说明     |
| ----------------- | ------ |
| `( )`             | 逻辑分组   |
| `[ ]`             | 索引     |
| `.`               | 属性取消引用 |
| `!`               | Not    |
| `<`               | 小于     |
| `<=`              | 小于或等于  |
| `>`               | 大于     |
| `>=`              | 大于或等于  |
| `==`              | 等于     |
| `!=`              | 不等于    |
| `&&`              | 和      |
| <code>\|\|</code> | 或      |

> \[!NOTE]
> \*
> GitHub 在比较字符串时忽略大小写。
> \*
> `steps.<step_id>.outputs.<output_name>` 计算结果为字符串。
> 您需要使用特定语法指示 GitHub 对表达式求值，而不是将其视为字符串。 有关详细信息，请参阅 [上下文参考](/zh/enterprise-server@3.22/actions/reference/workflows-and-actions/contexts#steps-context)。
>
> * 对于数值比较，`fromJSON()` 函数可用于将字符串转换为数字。 有关 `fromJSON()` 函数的更多信息，请参阅 [fromJSON](#fromjson)。

GitHub 进行宽松的等式比较。

* 如果类型不匹配， GitHub 将类型强制转换为数字。
  GitHub 使用以下转换将数据类型转换为数值：

  | 类型   | 结果  |
  | ---- | --- |
  | Null | `0` |
  | 布尔   |     |

`true` 返回 `1` <br />
`false` 返回 `0` |
\| 字符串  | 从任何合法的 JSON 数字格式进行分析，否则为 `NaN`。 <br /> 注意：空字符串返回 `0`。 |
\| Array   | `NaN` |
\| 对象  | `NaN` |

* 当 `NaN` 是任何关系比较（`>`、`<`、`>=`、`<=`）的操作数之一，结果始终为 `false`。 有关更多信息，请参阅 [NaN Mozilla 文档](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN)。
* GitHub 在比较字符串时忽略大小写。
* 对象和数组仅在为同一实例时才视为相等。

## Functions

GitHub 提供了一组可在表达式中使用的内置函数。 有些函数抛出值到字符串以进行比较。
GitHub 通过以下转换将数据类型转换为字符串：

| 类型                   | 结果             |
| -------------------- | -------------- |
| Null                 | `''`           |
| 布尔                   |                |
| `'true'` 或 `'false'` |                |
| Number               | 十进制格式，对大数字使用指数 |
| Array                | 数组不转换为字符串      |
| 对象                   | 对象不转换为字符串      |

### contains

`contains( search, item )`

如果 `true` 包含 `search`，则返回 `item`。 如果 `search` 是一个数组，`true` 是数组中的一个元素，此函数将返回 `item`。 如果 `search` 是一个字符串，`true` 是 `item` 的 substring，此函数将返回 `search`。 此函数不区分大小写。 抛出值到字符串。

#### 使用字符串的示例

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

#### 使用对象筛选器的示例

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

有关更多信息，请参阅[对象筛选器](#object-filters)。

#### 匹配字符串数组的示例

可以将 `github.event_name == "push" || github.event_name == "pull_request"` 与 `contains()` 配合使用来检查字符串数组是否包含 `fromJSON()`，而不是编写 `item`。

例如，如果 `contains(fromJSON('["push", "pull_request"]'), github.event_name)` 是“push”或“pull\_request”，`true` 便会返回 `github.event_name`。

### startsWith

`startsWith( searchString, searchValue )`

如果 `true` 以 `searchString` 开头，将返回 `searchValue`。 此函数不区分大小写。 抛出值到字符串。

#### `startsWith` 的示例

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

### endsWith

`endsWith( searchString, searchValue )`

如果 `true` 以 `searchString` 结尾，则返回 `searchValue`。 此函数不区分大小写。 抛出值到字符串。

#### `endsWith` 的示例

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

### 格式

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

将 `string` 中的值替换为变量 `replaceValueN`。
`string` 中的变量是使用 `{N}` 语法指定的，其中 `N` 是一个整数。 必须至少指定一个 `replaceValue` 和 `string`。 可使用的变量 (`replaceValueN`) 的数量没有上限。 使用双小括号逸出大括号。

#### `format` 的示例

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

返回“Hello Mona the Octocat”。

#### 逸出括号示例

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

返回“{Hello Mona the Octocat!}”。

### 加入

`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 copy
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 copy
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](https://en.wikipedia.org/wiki/SHA-2)。

你可以使用模式匹配字符来匹配文件名。 与 `hashFiles` 匹配的模式遵循 glob 模式匹配，并且在 Windows 上不区分大小写。 有关支持的模式匹配字符的详细信息，请参阅 [](https://www.npmjs.com/package/@actions/glob#patterns) 文档中的`@actions/glob`部分。

#### 单个模式示例

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

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

匹配根级别 `.js` 目录中的所有 `src` 文件，但忽略 `src` 的任何子目录。

`hashFiles('/src/*.js')`

匹配根级别 `.rb` 目录中的所有 `lib` 文件，包括 `lib` 的任何子目录。

`hashFiles('/lib/**/*.rb')`

#### 多个模式示例

为存储库中的任何 `package-lock.json` 和 `Gemfile.lock` 文件创建哈希。

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

为根级别 `.rb` 目录中的所有 `lib` 文件（包括 `lib` 的任何子目录）创建哈希，但排除 `.rb` 子目录中的 `foo` 文件。

`hashFiles('/lib/**/*.rb', '!/lib/foo/*.rb')`

## 状态检查函数

可以将以下状态检查函数用作 `if` 条件中的表达式。 除非包含这些函数之一，否则将应用 `success()` 的默认状态检查。 有关 `if` 条件的详细信息，请参阅“[GitHub Actions 的工作流语法](/zh/enterprise-server@3.22/actions/reference/workflows-and-actions/workflow-syntax#jobsjob_idif)”和“[元数据语法参考](/zh/enterprise-server@3.22/actions/reference/workflows-and-actions/metadata-syntax#runsstepsif)”。

在 `if` 条件之外，可以使用 `job.status` 来访问作业状态。 有关详细信息，请参阅“[上下文参考](/zh/enterprise-server@3.22/actions/reference/workflows-and-actions/contexts#job-context)”。

### success

当前面的所有步骤都成功时返回 `true`。

#### `success` 的示例

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

### 始终

导致步骤始终执行，并返回 `true`，即使取消也一样。
`always` 表达式最适用于步骤级别或预期即使作业取消仍会运行的任务。 例如，即使作业取消，仍然可以使用 `always` 发送日志。

> \[!WARNING]
> 避免将 `always` 用于任何可能出现严重故障的任务，例如：获取源代码，否则工作流可能会挂起直到超时。如果要无论作业或步骤成功与否都运行它，请使用推荐的替代方案：`if: ${{ !cancelled() }}`

#### `always` 的示例

```yaml
if: ${{ always() }}
```

### cancelled

如果工作流被取消，则返回 `true`。

#### `cancelled` 的示例

```yaml
if: ${{ cancelled() }}
```

### 失败

如果作业的任何先前步骤失败，将返回 `true`。 如果有一系列依赖项作业，则 `failure()` 在任何上级作业失败时返回 `true`。

#### `failure` 的示例

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

#### 有条件的失败

可以包含一个在失败后运行的步骤的额外条件，但仍必须包含 `failure()` 以覆盖自动应用于不包含状态检查函数的 `success()` 条件的默认 `if` 状态检查。

##### 有条件 `failure` 的示例

```yaml
steps:
  ...
  - name: Failing step
    id: demo
    run: exit 1
  - name: The demo step has failed
    if: ${{ failure() && steps.demo.conclusion == 'failure' }}
```

## 对象筛选器

可使用 `*` 语法来应用筛选器并选择集合中的匹配项。

例如，考虑名为 `fruits` 的对象数组。

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

筛选器 `fruits.*.name` 返回数组 `[ "apple", "orange", "pear" ]`。

还可以对某个对象使用 `*` 语法。 例如，假设有一个名为 `vegetables` 的对象。

```json

{
  "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` 的计算结果如下：

```json

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

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