Skip to main content
我们经常发布文档更新,此页面的翻译可能仍在进行中。 有关最新信息,请访问英语文档

在运行器上使用 GitHub CLI

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

示例概述

本文使用示例工作流演示 GitHub Actions 的某些主要 CI 功能。 此工作流触发后,会自动运行一个脚本,用于检查 GitHub Docs 站点是否有任何损坏的链接。 如果找到任何损坏的链接,工作流将使用 GitHub CLI 创建包含详细信息的 GitHub 问题。

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

触发使用 GitHub CLI 创建问题的工作流的事件示意图。

此示例中使用的功能

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

功能实现
定期运行工作流schedule

示例工作流

GitHub Docs 工程团队创建了以下工作流。 若要查看 github/docs 存储库中此文件的最新版本,请参阅 check-all-english-links.yml

注意:此工作流的每一行将在下一部分“了解示例”中介绍。

YAML
name: Check all English links

# **What it does**: This script once a day checks all English links and reports in issues.
# **Why we have it**: We want to know if any links break.
# **Who does it impact**: Docs content.

on:
  workflow_dispatch:
  schedule:
    - cron: '40 19 * * *' # once a day at 19:40 UTC / 11:40 PST

permissions:
  contents: read
  issues: write

jobs:
  check_all_english_links:
    name: Check all links
    if: github.repository == 'github/docs-internal'
    runs-on: ubuntu-latest
    env:
      GITHUB_TOKEN: ${{ secrets.DOCUBOT_READORG_REPO_WORKFLOW_SCOPES }}
      FIRST_RESPONDER_PROJECT: Docs content first responder
      REPORT_AUTHOR: docubot
      REPORT_LABEL: broken link report
      REPORT_REPOSITORY: github/docs-content
    steps:
      - name: Check out repo's default branch
        uses: actions/checkout@v3
      - name: Setup Node
        uses: actions/setup-node@v3
        with:
          node-version: 16.13.x
          cache: npm
      - name: npm ci
        run: npm ci
      - name: npm run build
        run: npm run build
      - name: Run script
        run: |
          script/check-english-links.js > broken_links.md

      # check-english-links.js returns 0 if no links are broken, and 1 if any links
      # are broken. When an Actions step's exit code is 1, the action run's job status
      # is failure and the run ends. The following steps create an issue for the
      # broken link report only if any links are broken, so `if: ${{ failure() }}`
      # ensures the steps run despite the previous step's failure of the job.

      - if: ${{ failure() }}
        name: Get title for issue
        id: check
        run: echo "title=$(head -1 broken_links.md)" >> $GITHUB_OUTPUT
      - if: ${{ failure() }}
        name: Create issue from file
        id: broken-link-report
        uses: peter-evans/create-issue-from-file@b4f9ee0a9d4abbfc6986601d9b1a4f8f8e74c77e
        with:
          token: ${{ env.GITHUB_TOKEN }}

          title: ${{ steps.check.outputs.title }}
          content-filepath: ./broken_links.md
          repository: ${{ env.REPORT_REPOSITORY }}
          labels: ${{ env.REPORT_LABEL }}
      - if: ${{ failure() }}
        name: Close and/or comment on old issues
        env:
          NEW_REPORT_URL: 'https://github.com/${{ env.REPORT_REPOSITORY }}/issues/${{ steps.broken-link-report.outputs.issue-number }}'
        run: |
          gh alias set list-reports "issue list \
                                       --repo ${{ env.REPORT_REPOSITORY }} \
                                       --author ${{ env.REPORT_AUTHOR }} \
                                       --label '${{ env.REPORT_LABEL }}'"

          # Link to the previous report from the new report that triggered this
          # workflow run.

          previous_report_url=$(gh list-reports \
                                  --state all \
                                  --limit 2 \
                                  --json url \
                                  --jq '.[].url' \
                                  | grep -v ${{ env.NEW_REPORT_URL }} | head -1)

          gh issue comment ${{ env.NEW_REPORT_URL }} --body "⬅️ [Previous report]($previous_report_url)"

          # If an old report is open and assigned to someone, link to the newer
          # report without closing the old report.

          for issue_url in $(gh list-reports \
                                  --json assignees,url \
                                  --jq '.[] | select (.assignees != []) | .url'); do
            if [ "$issue_url" != "${{ env.NEW_REPORT_URL }}" ]; then
              gh issue comment $issue_url --body "➡️ [Newer report](${{ env.NEW_REPORT_URL }})"
            fi
          done

          # Link to the newer report from any older report that is still open,
          # then close the older report and remove it from the first responder's
          # project board.

          for issue_url in $(gh list-reports \
                                  --search 'no:assignee' \
                                  --json url \
                                  --jq '.[].url'); do
            if [ "$issue_url" != "${{ env.NEW_REPORT_URL }}" ]; then
              gh issue comment $issue_url --body "➡️ [Newer report](${{ env.NEW_REPORT_URL }})"
              gh issue close $issue_url
              gh issue edit $issue_url --remove-project "${{ env.FIRST_RESPONDER_PROJECT }}"
            fi
          done

了解示例

下表介绍了在创建 GitHub Actions 工作流时如何使用这些功能。

代码 解释
YAML
name: Check all English links

将显示在 GitHub 存储库的“操作”选项卡中的工作流名称。

YAML
on:
  workflow_dispatch:
  schedule:
    - cron: '40 20 * * *' # once a day at 20:40 UTC / 12:40 PST

workflow_dispatchscheduled 定义为工作流的触发器:

  • 通过 workflow_dispatch,可从 UI 手动运行此工作流。 有关详细信息,请参阅 workflow_dispatch
  • 通过 schedule 事件,可使用 cron 语法来定义自动触发工作流的定期间隔。 有关详细信息,请参阅 schedule
YAML
permissions:
  contents: read
  issues: write

修改授予 GITHUB_TOKEN 的默认权限。 这将因工作流的需求而异。 有关详细信息,请参阅“为作业分配权限”。

YAML
jobs:

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

YAML
  check_all_english_links:
    name: Check all links

定义 ID 为 check_all_english_links、名称为 Check all links 的作业,该作业存储在 jobs 密钥中。

YAML
if: github.repository == 'github/docs-internal'

仅当存储库名为 docs-internal 且位于 github 组织内时,才运行 check_all_english_links 作业。 否则,作业会被标记为“跳过”。

YAML
runs-on: ubuntu-latest

配置作业在 Ubuntu Linux 运行器上运行。 这意味着作业将在 GitHub. 托管的新虚拟机上执行。 有关使用其他运行器的语法示例,请参阅“GitHub Actions 的工作流语法”。

YAML
    env:
      GITHUB_TOKEN: ${{ secrets.DOCUBOT_READORG_REPO_WORKFLOW_SCOPES }}
      REPORT_AUTHOR: docubot
      REPORT_LABEL: broken link report
      REPORT_REPOSITORY: github/docs-content

创建自定义环境变量,并重新定义内置的 GITHUB_TOKEN 变量以使用自定义机密。 稍后将在工作流中引用这些变量。

YAML
    steps:

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

YAML
      - name: Check out repo's default branch
        uses: actions/checkout@v3

uses 关键字指示作业检索名为 actions/checkout 的操作。 这是检出仓库并将其下载到运行器的操作,允许针对您的代码运行操作(例如测试工具)。 只要工作流程针对仓库的代码运行,或者您使用仓库中定义的操作,您都必须使用检出操作。

YAML
      - name: Setup Node
        uses: actions/setup-node@v3
        with:
          node-version: 16.8.x
          cache: npm

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

YAML
      - name: Run the "npm ci" command
        run: npm ci
      - name: Run the "npm run build" command
        run: npm run build

run 关键字指示作业在运行器上执行命令。 在这种情况下,npm cinpm run build 命令作为单独的步骤运行,用于在存储库中安装和生成 Node.js 应用程序。

YAML
      - name: Run script
        run: |
          script/check-english-links.js > broken_links.md

run 命令执行存储库 (script/check-english-links.js) 中存储的脚本,并通过管道将输出传递给名为 broken_links.md 的文件。

YAML
      - if: ${{ failure() }}
        name: Get title for issue
        id: check
        run: echo "title=$(head -1 broken_links.md)" >> $GITHUB_OUTPUT

如果 check-english-links.js 脚本检测到损坏的链接并返回非零(失败)退出状态,则使用工作流命令设置具有 broken_links.md 文件第一行值的输出(下一步中会用到它)。

YAML
      - if: ${{ failure() }}
        name: Create issue from file
        id: broken-link-report
        uses: peter-evans/create-issue-from-file@b4f9ee0a9d4abbfc6986601d9b1a4f8f8e74c77e
        with:
          token: ${{ env.GITHUB_TOKEN }}

          title: ${{ steps.check.outputs.title }}
          content-filepath: ./broken_links.md
          repository: ${{ env.REPORT_REPOSITORY }}
          labels: ${{ env.REPORT_LABEL }}

使用 peter-evans/create-issue-from-file 操作创建新的 GitHub 问题。 此示例使用 b4f9ee0a9d4abbfc6986601d9b1a4f8f8e74c77e SHA 固定到操作的特定版本。

YAML
      - if: ${{ failure() }}
        name: Close and/or comment on old issues
        env:
          NEW_REPORT_URL: 'https://github.com/${{ env.REPORT_REPOSITORY }}/issues/${{ steps.broken-link-report.outputs.issue-number }}'
        run: |
          gh alias set list-reports "issue list \
                                       --repo ${{ env.REPORT_REPOSITORY }} \
                                       --author ${{ env.REPORT_AUTHOR }} \
                                       --label '${{ env.REPORT_LABEL }}'"
          previous_report_url=$(gh list-reports \
                                  --state all \
                                  --limit 2 \
                                  --json url \
                                  --jq '.[].url' \
                                  | grep -v ${{ env.NEW_REPORT_URL }} | head -1)

          gh issue comment ${{ env.NEW_REPORT_URL }} --body "⬅️ [Previous report]($previous_report_url)"

使用 gh issue list 查找之前在早期运行中创建的问题。 在后续步骤中,为了简化处理,这将别名设置为 gh list-reports。 若要获取问题 URL,jq 表达式将处理生成的 JSON 输出。

然后,使用 gh issue comment 向链接到上一个问题的新问题添加注释。

YAML
          for issue_url in $(gh list-reports \
                                  --json assignees,url \
                                  --jq '.[] | select (.assignees != []) | .url'); do
            if [ "$issue_url" != "$" ]; then
              gh issue comment $issue_url --body "➡️ [Newer report]($)"
            fi
          done

如果上一次运行中的问题已打开且已分配给某人,则使用 gh issue comment 添加注释并附上指向新问题的链接。

YAML
          for issue_url in $(gh list-reports \
                                  --search 'no:assignee' \
                                  --json url \
                                  --jq '.[].url'); do
            if [ "$issue_url" != "${{ env.NEW_REPORT_URL }}" ]; then
              gh issue comment $issue_url --body "➡️ [Newer report](${{ env.NEW_REPORT_URL }})"
              gh issue close $issue_url
              gh issue edit $issue_url --remove-project "${{ env.FIRST_RESPONDER_PROJECT }}"
            fi
          done

如果上一次运行中的问题已打开但未分配给任何人,则:

后续步骤