示例概述
本文使用一个示例工作流来演示 GitHub Actions 的一些主要 CI 功能。当触发此工作流时,它会自动运行一个脚本,检查 GitHub Docs 站点是否有任何损坏的链接。如果发现任何损坏的链接,工作流将使用 GitHub CLI 创建一个包含详细信息的 GitHub 问题。
下图显示了工作流步骤的高级视图以及它们如何在作业中运行
本示例中使用的功能
示例工作流演示了 GitHub Actions 的以下功能。
功能 | 实现 |
---|---|
定期运行工作流 | schedule |
设置令牌权限 | permissions |
防止在未满足特定条件时运行作业 | if |
在工作流中引用机密 | 机密 |
将存储库克隆到运行程序 | actions/checkout |
在运行程序上安装 node | actions/setup-node |
使用第三方操作 | peter-evans/create-issue-from-file |
在运行程序上运行 shell 命令 | run |
在运行程序上运行脚本 | 使用 script/check-english-links.js |
生成输出文件 | 使用 > 运算符管道输出 |
使用 GitHub CLI 检查现有问题 | gh issue list |
使用 GitHub CLI 评论问题 | gh issue comment |
示例工作流
以下工作流由 GitHub Docs 工程团队创建。若要查看 github/docs
存储库中此文件的最新版本,请参阅 check-all-english-links.yml
。
以下工作流每天检查一次所有英文链接,并通过创建新问题供文档内容团队查看来报告损坏的链接。
# This defines the name of the workflow as it will appear in the "Actions" tab of the GitHub repository. name: Check all English links # Defines the `workflow_dispatch` and `scheduled` as triggers for the workflow. # # The `workflow_dispatch` event lets you manually run this workflow from the UI. For more information, see [`workflow_dispatch`](/actions/using-workflows/events-that-trigger-workflows#workflow_dispatch). # # The `schedule` event lets you use `cron` syntax to define a regular interval for automatically triggering the workflow. For more information, see [`schedule`](/actions/using-workflows/events-that-trigger-workflows#schedule). on: workflow_dispatch: schedule: - cron: '40 19 * * *' # once a day at 19:40 UTC / 11:40 PST # 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 issues: write # Groups together all the jobs that run in the workflow file. jobs: # Defines a job with the ID `check_all_english_links`, and the name `Check all links`, that is stored within the `jobs` key. check_all_english_links: name: Check all links # Only run the `check_all_english_links` job if the repository is named `docs-internal` and is within the `github` organization. Otherwise, the job is marked as _skipped_. if: github.repository == 'github/docs-internal' # Configures the job to run on an Ubuntu Linux runner. This means that the job will execute on a fresh virtual machine hosted by GitHub. For syntax examples using other runners, see "[AUTOTITLE](/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idruns-on)." runs-on: ubuntu-latest # Creates custom environment variables, and redefines the built-in `GITHUB_TOKEN` variable to use a custom [secret](/actions/security-guides/using-secrets-in-github-actions). These variables will be referenced later in the workflow. 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 # Groups together all the steps that will run as part of the `check_all_english_links` job. Each job in the 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 run against the repository's code or you are using an action defined in the repository. - name: Check out repo's default branch uses: actions/checkout@v4 # 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.13.x cache: npm # The `run` keyword tells the job to execute a command on the runner. In this case, the `npm ci` and `npm run build` commands are run as separate steps to install and build the Node.js application in the repository. - name: Run the "npm ci" command run: npm ci - name: Run the "npm run build" command run: npm run build # This `run` command executes a script that is stored in the repository at `script/check-english-links.js`, and pipes the output to a file called `broken_links.md`. - name: Run script run: | script/check-english-links.js > broken_links.md # If the `check-english-links.js` script detects broken links and returns a non-zero (failure) exit status, then use a [workflow command](/actions/using-workflows/workflow-commands-for-github-actions#setting-an-output-parameter) to set an output that has the value of the first line of the `broken_links.md` file (this is used the next step). # # `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 # Uses the `peter-evans/create-issue-from-file` action to create a new GitHub issue. This example is pinned to a specific version of the action, using the `ceef9be92406ace67ab5421f66570acf213ec395` SHA. - if: ${{ failure() }} name: Create issue from file id: broken-link-report uses: peter-evans/create-issue-from-file@ceef9be92406ace67ab5421f66570acf213ec395 with: token: ${{ env.GITHUB_TOKEN }} title: ${{ steps.check.outputs.title }} content-filepath: ./broken_links.md repository: ${{ env.REPORT_REPOSITORY }} labels: ${{ env.REPORT_LABEL }} # Uses [`gh issue list`](https://cli.github.com/manual/gh_issue_list) to locate the previously created issue from earlier runs. This is [aliased](https://cli.github.com/manual/gh_alias_set) to `gh list-reports` for simpler processing in later steps. - 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`](https://cli.github.com/manual/gh_issue_comment) is used to add a comment to the new issue that links to the previous one. gh issue comment ${{ env.NEW_REPORT_URL }} --body "⬅️ [Previous report]($previous_report_url)" # If an issue from a previous run is open and assigned to someone, then use [`gh issue comment`](https://cli.github.com/manual/gh_issue_comment) to add a comment with a link to the new issue without closing the old report. To get the issue URL, the `jq` expression processes the resulting JSON output. # # If an issue from a previous run is open and is not assigned to anyone, use [`gh issue comment`](https://cli.github.com/manual/gh_issue_comment) to add a comment with a link to the new issue. Then use [`gh issue close`](https://cli.github.com/manual/gh_issue_close) and [`gh issue edit`](https://cli.github.com/manual/gh_issue_edit) to close the issue and remove it from the project board. 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 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 }})" # Use [`gh issue close`](https://cli.github.com/manual/gh_issue_close) to close the old issue. gh issue close $issue_url # Use [`gh issue edit`](https://cli.github.com/manual/gh_issue_edit) to edit the old issue and remove it from a specific GitHub project board. gh issue edit $issue_url --remove-project "${{ env.FIRST_RESPONDER_PROJECT }}" fi done
name: Check all English links
这定义了工作流的名称,该名称将显示在 GitHub 存储库的“操作”选项卡中。
on:
workflow_dispatch:
schedule:
- cron: '40 19 * * *' # once a day at 19:40 UTC / 11:40 PST
将 workflow_dispatch
和 scheduled
定义为工作流的触发器。
workflow_dispatch
事件允许您从 UI 手动运行此工作流。有关更多信息,请参阅 workflow_dispatch
。
schedule
事件允许您使用 cron
语法定义自动触发工作流的常规间隔。有关更多信息,请参阅 schedule
。
permissions:
contents: read
issues: write
修改授予 GITHUB_TOKEN
的默认权限。这会根据工作流的需要而有所不同。有关更多信息,请参阅“为作业分配权限”。
jobs:
将工作流文件中运行的所有作业组合在一起。
check_all_english_links:
name: Check all links
定义一个 ID 为 check_all_english_links
、名称为 Check all links
的作业,该作业存储在 jobs
键中。
if: github.repository == 'github/docs-internal'
仅当存储库名为 docs-internal
且位于 github
组织中时,才运行 check_all_english_links
作业。否则,该作业将标记为已跳过。
runs-on: ubuntu-latest
将作业配置为在 Ubuntu Linux 运行程序上运行。这意味着该作业将在 GitHub 托管的新虚拟机上执行。有关使用其他运行程序的语法示例,请参阅“GitHub Actions 的工作流语法”。
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
创建自定义环境变量,并重新定义内置 GITHUB_TOKEN
变量以使用自定义秘密。这些变量将在工作流中稍后引用。
steps:
将作为 check_all_english_links
作业一部分运行的所有步骤组合在一起。工作流中的每个作业都有其自己的 steps
部分。
- name: Check out repo's default branch
uses: actions/checkout@v4
uses
关键字告诉作业检索名为 actions/checkout
的操作。这是一个签出存储库并将其下载到运行程序的操作,允许您对代码运行操作(例如测试工具)。无论何时你的工作流针对存储库的代码运行,或者你在存储库中使用已定义的操作,你都必须使用签出操作。
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 16.13.x
cache: npm
此步骤使用 actions/setup-node
操作在运行程序上安装指定版本的 node
软件包,这使你可以访问 npm
命令。
- name: Run the "npm ci" command
run: npm ci
- name: Run the "npm run build" command
run: npm run build
run
关键字告诉作业在运行程序上执行命令。在这种情况下,npm ci
和 npm run build
命令作为单独的步骤运行,以安装和构建存储库中的 Node.js 应用程序。
- name: Run script
run: |
script/check-english-links.js > broken_links.md
此 run
命令执行存储在存储库的 script/check-english-links.js
中的脚本,并将输出管道传输到名为 broken_links.md
的文件。
- 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
文件的第一行(这用于下一步)。
如果没有任何链接损坏,则 check-english-links.js
返回 0,如果任何链接损坏,则返回 1。当操作步骤的退出代码为 1 时,操作运行的作业状态为失败,并且运行结束。
以下步骤仅在任何链接损坏时为损坏的链接报告创建问题,因此 if: ${{ failure() }}
确保这些步骤在尽管前一步骤导致作业失败的情况下运行。
- if: ${{ failure() }}
name: Create issue from file
id: broken-link-report
uses: peter-evans/create-issue-from-file@ceef9be92406ace67ab5421f66570acf213ec395
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 问题。此示例固定到操作的特定版本,使用 ceef9be92406ace67ab5421f66570acf213ec395
SHA。
- 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 list
查找之前运行中创建的问题。这被 别名为 gh list-reports
以便在后续步骤中更轻松地处理。
gh issue comment ${{ env.NEW_REPORT_URL }} --body "⬅️ [Previous report]($previous_report_url)"
gh issue comment
用于向链接到前一个问题的新问题添加评论。
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
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 comment
添加带有链接到新问题的评论,而无需关闭旧报告。要获取问题 URL,jq
表达式会处理结果 JSON 输出。
如果前一次运行中的问题是开放的并且未分配给任何人,则使用 gh issue comment
添加带有链接到新问题的评论。然后使用 gh issue close
和 gh issue edit
关闭问题并将其从项目看板中移除。
gh issue close $issue_url
使用 gh issue close
关闭旧问题。
gh issue edit $issue_url --remove-project "${{ env.FIRST_RESPONDER_PROJECT }}"
fi
done
使用 gh issue edit
编辑旧问题并将其从特定的 GitHub 项目看板中移除。
# This defines the name of the workflow as it will appear in the "Actions" tab of the GitHub repository.
name: Check all English links
# Defines the `workflow_dispatch` and `scheduled` as triggers for the workflow.
#
# The `workflow_dispatch` event lets you manually run this workflow from the UI. For more information, see [`workflow_dispatch`](/actions/using-workflows/events-that-trigger-workflows#workflow_dispatch).
#
# The `schedule` event lets you use `cron` syntax to define a regular interval for automatically triggering the workflow. For more information, see [`schedule`](/actions/using-workflows/events-that-trigger-workflows#schedule).
on:
workflow_dispatch:
schedule:
- cron: '40 19 * * *' # once a day at 19:40 UTC / 11:40 PST
# 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
issues: write
# Groups together all the jobs that run in the workflow file.
jobs:
# Defines a job with the ID `check_all_english_links`, and the name `Check all links`, that is stored within the `jobs` key.
check_all_english_links:
name: Check all links
# Only run the `check_all_english_links` job if the repository is named `docs-internal` and is within the `github` organization. Otherwise, the job is marked as _skipped_.
if: github.repository == 'github/docs-internal'
# Configures the job to run on an Ubuntu Linux runner. This means that the job will execute on a fresh virtual machine hosted by GitHub. For syntax examples using other runners, see "[AUTOTITLE](/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idruns-on)."
runs-on: ubuntu-latest
# Creates custom environment variables, and redefines the built-in `GITHUB_TOKEN` variable to use a custom [secret](/actions/security-guides/using-secrets-in-github-actions). These variables will be referenced later in the workflow.
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
# Groups together all the steps that will run as part of the `check_all_english_links` job. Each job in the 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 run against the repository's code or you are using an action defined in the repository.
- name: Check out repo's default branch
uses: actions/checkout@v4
# 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.13.x
cache: npm
# The `run` keyword tells the job to execute a command on the runner. In this case, the `npm ci` and `npm run build` commands are run as separate steps to install and build the Node.js application in the repository.
- name: Run the "npm ci" command
run: npm ci
- name: Run the "npm run build" command
run: npm run build
# This `run` command executes a script that is stored in the repository at `script/check-english-links.js`, and pipes the output to a file called `broken_links.md`.
- name: Run script
run: |
script/check-english-links.js > broken_links.md
# If the `check-english-links.js` script detects broken links and returns a non-zero (failure) exit status, then use a [workflow command](/actions/using-workflows/workflow-commands-for-github-actions#setting-an-output-parameter) to set an output that has the value of the first line of the `broken_links.md` file (this is used the next step).
#
# `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
# Uses the `peter-evans/create-issue-from-file` action to create a new GitHub issue. This example is pinned to a specific version of the action, using the `ceef9be92406ace67ab5421f66570acf213ec395` SHA.
- if: ${{ failure() }}
name: Create issue from file
id: broken-link-report
uses: peter-evans/create-issue-from-file@ceef9be92406ace67ab5421f66570acf213ec395
with:
token: ${{ env.GITHUB_TOKEN }}
title: ${{ steps.check.outputs.title }}
content-filepath: ./broken_links.md
repository: ${{ env.REPORT_REPOSITORY }}
labels: ${{ env.REPORT_LABEL }}
# Uses [`gh issue list`](https://cli.github.com/manual/gh_issue_list) to locate the previously created issue from earlier runs. This is [aliased](https://cli.github.com/manual/gh_alias_set) to `gh list-reports` for simpler processing in later steps.
- 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`](https://cli.github.com/manual/gh_issue_comment) is used to add a comment to the new issue that links to the previous one.
gh issue comment ${{ env.NEW_REPORT_URL }} --body "⬅️ [Previous report]($previous_report_url)"
# If an issue from a previous run is open and assigned to someone, then use [`gh issue comment`](https://cli.github.com/manual/gh_issue_comment) to add a comment with a link to the new issue without closing the old report. To get the issue URL, the `jq` expression processes the resulting JSON output.
#
# If an issue from a previous run is open and is not assigned to anyone, use [`gh issue comment`](https://cli.github.com/manual/gh_issue_comment) to add a comment with a link to the new issue. Then use [`gh issue close`](https://cli.github.com/manual/gh_issue_close) and [`gh issue edit`](https://cli.github.com/manual/gh_issue_edit) to close the issue and remove it from the project board.
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
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 }})"
# Use [`gh issue close`](https://cli.github.com/manual/gh_issue_close) to close the old issue.
gh issue close $issue_url
# Use [`gh issue edit`](https://cli.github.com/manual/gh_issue_edit) to edit the old issue and remove it from a specific GitHub project board.
gh issue edit $issue_url --remove-project "${{ env.FIRST_RESPONDER_PROJECT }}"
fi
done
后续步骤
- 要了解 GitHub Actions 概念,请参阅“了解 GitHub Actions”。
- 有关创建基本工作流的更多分步指南,请参阅“GitHub Actions 快速入门”。
- 如果您熟悉 GitHub Actions 的基础知识,则可以在“关于工作流”中了解工作流及其功能。