跳至主要内容

使用并发、表达式和测试矩阵

如何使用高级 GitHub Actions 功能进行持续集成 (CI)。

示例概述

本文使用示例工作流来演示 GitHub Actions 的一些主要 CI 功能。当此工作流触发时,它将使用 npm test 测试您的代码,并使用测试组合矩阵。

下图显示了工作流步骤的高级视图以及它们在作业中的运行方式

Diagram of an event triggering a workflow that uses a test matrix.

此示例中使用的功能

示例工作流演示了 GitHub Actions 的以下功能。

功能实现
从 UI 手动运行工作流workflow_dispatch
自动触发工作流运行pull_request
定期运行工作流schedule
设置令牌的权限permissions
控制同时运行的工作流运行或作业数量concurrency
根据仓库在不同的运行器上运行作业runs-on
防止作业在未满足特定条件的情况下运行if
使用矩阵创建不同的测试配置matrix
将您的仓库克隆到运行器actions/checkout
在运行器上安装 nodeactions/setup-node
缓存依赖项actions/cache
在运行器上运行测试npm test

示例工作流

以下工作流由 GitHub 文档工程团队创建。该工作流针对拉取请求中的代码运行测试。要查看此文件在 github/docs 仓库中的最新版本,请参阅 test.yml

YAML
name: Node.js Tests

这定义了工作流的名称,它将显示在 GitHub 仓库的“操作”选项卡中。

on:

on 关键字允许您定义触发工作流运行的事件。您可以在此处定义多个事件。有关更多信息,请参阅“触发工作流”。

  workflow_dispatch:

如果您希望能够手动运行此工作流,请添加 workflow_dispatch 事件。有关更多信息,请参阅 workflow_dispatch

  pull_request:

添加 pull_request 事件,以便工作流在每次创建或更新拉取请求时自动运行。有关更多信息,请参阅 pull_request

  push:
    branches:
      - main

添加带有 `branch` 过滤器的 `push` 事件,以便每次将提交推送到名为“main”的分支时,工作流都会自动运行。有关更多信息,请参阅 push

permissions:
  contents: read
  pull-requests: read

这将修改授予 `GITHUB_TOKEN` 的默认权限。这将根据工作流的需求而有所不同。有关更多信息,请参阅“为作业分配权限”。

concurrency:
  group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'
  cancel-in-progress: true

concurrency 键确保在同一并发组中,一次只运行一个工作流。有关更多信息,请参阅“使用并发”。concurrency.group 从工作流名称和拉取请求信息生成并发组名称。|| 运算符用于定义回退值。concurrency.cancel-in-progress 取消同一并发组中任何当前正在运行的作业或工作流。

jobs:

这将所有在工作流文件中运行的作业分组在一起。

  test:

这定义了一个名为 `test` 的作业,该作业存储在 `jobs` 键中。

    runs-on: ${{ fromJSON('["ubuntu-latest", "self-hosted"]')[github.repository == 'github/docs-internal'] }}

这将作业配置为在 GitHub 托管的运行器或自托管的运行器上运行,具体取决于运行工作流的存储库。

在此示例中,如果存储库名为 `docs-internal` 并且位于 `github` 组织中,则作业将在自托管的运行器上运行。如果存储库与该路径不匹配,则它将在 GitHub 托管的 `ubuntu-latest` 运行器上运行。有关这些选项的更多信息,请参阅“选择作业的运行器”。

    timeout-minutes: 60

这设置了在作业自动取消之前允许作业运行的最大分钟数。有关更多信息,请参阅 timeout-minutes

    strategy:

本节定义了作业的构建矩阵。

      fail-fast: false

将 `fail-fast` 设置为 `false` 可以防止 GitHub 在任何矩阵作业失败时取消所有正在进行的作业。

      matrix:
        test-group:
          [
            content,
            graphql,
            meta,
            rendering,
            routing,
            unit,
            linting,
            translations,
          ]

这将创建一个名为 `test-group` 的矩阵,其中包含一个测试组数组。这些值与 `npm test` 将运行的测试组的名称匹配。

    steps:

这将所有将作为 `test` 作业的一部分运行的步骤分组在一起。工作流中的每个作业都有自己的 `steps` 部分。

      - name: Check out repo
        uses: actions/checkout@v4
        with:
          lfs: ${{ matrix.test-group == 'content' }}
          persist-credentials: 'false'

uses 关键字告诉作业检索名为 actions/checkout 的操作。这是一个检出您的仓库并将其下载到运行器的操作,允许您对您的代码运行操作(例如测试工具)。只要您的工作流程使用您的仓库代码,您就必须使用 checkout 操作。使用 with 键为操作提供了一些额外的选项。

      - name: Checkout LFS objects
        run: git lfs checkout

此步骤运行一个命令来从仓库中检出大型文件存储 (LFS) 对象。

      - name: Gather files changed
        uses: trilom/file-changes-action@a6ca26c14274c33b15e6499323aac178af06ad4b
        id: get_diff_files
        with:
          output: ' '

此步骤使用 trilom/file-changes-action 操作来收集拉取请求中更改的文件,以便在下一步中对其进行分析。此示例固定到操作的特定版本,使用 a6ca26c14274c33b15e6499323aac178af06ad4b SHA。

      - name: Insight into changed files
        run: |
          echo "${{ steps.get_diff_files.outputs.files }}" > get_diff_files.txt

此步骤运行一个 shell 命令,该命令使用上一步的输出创建一个包含拉取请求中更改的文件列表的文件。

      - name: Setup node
        uses: actions/setup-node@v4
        with:
          node-version: 16.14.x
          cache: npm

此步骤使用 actions/setup-node 操作在运行器上安装指定版本的 node 软件包,这使您可以访问 npm 命令。

      - name: Install dependencies
        run: npm ci

此步骤运行 npm ci shell 命令来安装项目的 npm 软件包。

      - name: Cache nextjs build
        uses: actions/cache@v3
        with:
          path: .next/cache
          key: ${{ runner.os }}-nextjs-${{ hashFiles('package*.json') }}

此步骤使用 actions/cache 操作来缓存 Next.js 构建,以便工作流程将尝试检索构建的缓存,而不是每次都从头开始重建。有关更多信息,请参阅 "缓存依赖项以加快工作流程速度"。

      - name: Run build script
        run: npm run build

此步骤运行构建脚本。

      - name: Run tests
        env:
          DIFF_FILE: get_diff_files.txt
          CHANGELOG_CACHE_FILE_PATH: src/fixtures/fixtures/changelog-feed.json
        run: npm test -- tests/${{ matrix.test-group }}/

此步骤使用 npm test 运行测试,测试矩阵为每个矩阵作业提供 ${{ matrix.test-group }} 的不同值。它使用 DIFF_FILE 环境变量来了解哪些文件已更改,并使用 CHANGELOG_CACHE_FILE_PATH 环境变量来获取变更日志缓存文件。

# This defines the name of the workflow as it will appear in the "Actions" tab of the GitHub repository.
name: Node.js Tests

# The `on` keyword lets you define the events that trigger when the workflow is run. You can define multiple events here. For more information, see "[AUTOTITLE](/actions/using-workflows/triggering-a-workflow#using-events-to-trigger-workflows)."
on:

  # Add the `workflow_dispatch` event if you want to be able to manually run this workflow. For more information, see [`workflow_dispatch`](/actions/using-workflows/events-that-trigger-workflows#workflow_dispatch).
  workflow_dispatch:

  # Add the `pull_request` event, so that the workflow runs automatically every time a pull request is created or updated. For more information, see [`pull_request`](/actions/using-workflows/events-that-trigger-workflows#pull_request).
  pull_request:

  # Add the `push` event with the `branch` filter, so that the workflow runs automatically every time a commit is pushed to a branch called "main". For more information, see [`push`](/actions/using-workflows/events-that-trigger-workflows#push).
  push:
    branches:
      - main

# This modifies the default permissions granted to `GITHUB_TOKEN`. This will vary depending on the needs of your workflow. For more information, see "[AUTOTITLE](/actions/using-jobs/assigning-permissions-to-jobs)."
permissions:
  contents: read
  pull-requests: read

# The `concurrency` key ensures that only a single workflow in the same concurrency group will run at the same time. For more information, see "[AUTOTITLE](/actions/using-jobs/using-concurrency)."
# `concurrency.group` generates a concurrency group name from the workflow name and pull request information. The `||` operator is used to define fallback values.
# `concurrency.cancel-in-progress` cancels any currently running job or workflow in the same concurrency group.
concurrency:
  group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'
  cancel-in-progress: true

# This groups together all the jobs that run in the workflow file.
jobs:

  # This defines a job with the ID `test` that is stored within the `jobs` key.
  test:

    # This configures the job to run on a GitHub-hosted runner or a self-hosted runner, depending on the repository running the workflow.
    #
    # In this example, the job will run on a self-hosted runner if the repository is named `docs-internal` and is within the `github` organization. If the repository doesn't match this path, then it will run on an `ubuntu-latest` runner hosted by GitHub. For more information on these options, see "[AUTOTITLE](/actions/using-jobs/choosing-the-runner-for-a-job)."
    runs-on: ${{ fromJSON('["ubuntu-latest", "self-hosted"]')[github.repository == 'github/docs-internal'] }}

    # This sets the maximum number of minutes to let the job run before it is automatically canceled. For more information, see [`timeout-minutes`](/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idtimeout-minutes).
    timeout-minutes: 60

    # This section defines the build matrix for your jobs.
    strategy:

      # Setting `fail-fast` to `false` prevents GitHub from cancelling all in-progress jobs if any matrix job fails.
      fail-fast: false

      # This creates a matrix named `test-group`, with an array of test groups. These values match the names of test groups that will be run by `npm test`.
      matrix:
        test-group:
          [
            content,
            graphql,
            meta,
            rendering,
            routing,
            unit,
            linting,
            translations,
          ]

    # This groups together all the steps that will run as part of the `test` job. Each job in a workflow has its own `steps` section.
    steps:

      # The `uses` keyword tells the job to retrieve the action named `actions/checkout`. This is an action that checks out your repository and downloads it to the runner, allowing you to run actions against your code (such as testing tools). You must use the checkout action any time your workflow will use your repository's code. Some extra options are provided to the action using the `with` key.
      - name: Check out repo
        uses: actions/checkout@v4
        with:
          lfs: ${{ matrix.test-group == 'content' }}
          persist-credentials: 'false'

      # This step runs a command to check out large file storage (LFS) objects from the repository.
      - name: Checkout LFS objects
        run: git lfs checkout

      # This step uses the `trilom/file-changes-action` action to gather the files changed in the pull request, so they can be analyzed in the next step. This example is pinned to a specific version of the action, using the `a6ca26c14274c33b15e6499323aac178af06ad4b` SHA.
      - name: Gather files changed
        uses: trilom/file-changes-action@a6ca26c14274c33b15e6499323aac178af06ad4b
        id: get_diff_files
        with:
          output: ' '

      # This step runs a shell command that uses an output from the previous step to create a file containing the list of files changed in the pull request.
      - name: Insight into changed files
        run: |

          echo "${{ steps.get_diff_files.outputs.files }}" > get_diff_files.txt

      # This step uses the `actions/setup-node` action to install the specified version of the `node` software package on the runner, which gives you access to the `npm` command.
      - name: Setup node
        uses: actions/setup-node@v4
        with:
          node-version: 16.14.x
          cache: npm

      # This step runs the `npm ci` shell command to install the npm software packages for the project.
      - name: Install dependencies
        run: npm ci

      # This step uses the `actions/cache` action to cache the Next.js build, so that the workflow will attempt to retrieve a cache of the build, and not rebuild it from scratch every time. For more information, see "[AUTOTITLE](/actions/using-workflows/caching-dependencies-to-speed-up-workflows)."
      - name: Cache nextjs build
        uses: actions/cache@v3
        with:
          path: .next/cache
          key: ${{ runner.os }}-nextjs-${{ hashFiles('package*.json') }}

      # This step runs the build script.
      - name: Run build script
        run: npm run build

      # This step runs the tests using `npm test`, and the test matrix provides a different value for `${{ matrix.test-group }}` for each job in the matrix. It uses the `DIFF_FILE` environment variable to know which files have changed, and uses the `CHANGELOG_CACHE_FILE_PATH` environment variable for the changelog cache file.
      - name: Run tests
        env:
          DIFF_FILE: get_diff_files.txt
          CHANGELOG_CACHE_FILE_PATH: src/fixtures/fixtures/changelog-feed.json
        run: npm test -- tests/${{ matrix.test-group }}/

下一步