GitHub Actions 工作流程
本文说明如何使用 GraphQL API 和 GitHub Actions 向组织项目添加拉取请求。 在示例工作流程中,当拉取请求标记为“准备审核”时,项目中会添加一项“状态”字段设置为“待办”的新任务,并且当前日期添加到自定义的“发布日期”字段中。
您可以复制以下工作流程之一,并按照下表中的说明对其进行修改,以满足您的需求。
项目可以跨越多个仓库,但工作流是特定于仓库的。 将工作流添加到希望项目跟踪的每个存储库。有关创建工作流文件的详细信息,请参阅“GitHub Actions 快速入门”。
本文假设您基本了解 GitHub Actions。 有关 GitHub Actions 的详细信息,请参阅“GitHub Actions文档”。
有关可以通过 API 对项目进行的其他更改的详细信息,请参阅“使用 API 管理 Projects”。
你可能还希望使用 actions/add-to-project 工作流,该工作流由 GitHub 维护,并将当前问题或拉取请求添加到指定的项目。 有关详细信息,请参阅 actions/add-to-project 存储库和自述文件。
注意:GITHUB_TOKEN
的范围限定为存储库级别,并且无法访问 projects。 若要访问 projects,可以创建 GitHub App(建议用于组织项目)或者 personal access token(建议用于用户项目)。 下面显示了这两种方法的工作流程示例。
使用 GitHub App 进行身份验证的示例工作流程
有关使用 GitHub App 在 GitHub Actions 工作流中进行身份验证的详细信息,请参阅“Making authenticated API requests with a GitHub App in a GitHub Actions workflow”。
-
创建 GitHub App 或选择组织拥有的现有 GitHub App。 有关详细信息,请参阅“Registering a GitHub App”。
-
授予 GitHub App 对组织项目的读取和写入权限。 对于此特定示例,你的 GitHub App 还需要有对存储库拉取请求和存储库问题的读取权限。 有关详细信息,请参阅“Modifying a GitHub App registration”。
注意:你可以控制应用对组织项目和存储库项目的权限。 您必须授予读取和写入组织项目的权限;读取和写入存储库项目的权限是不够的。
-
在组织中安装 GitHub App。 为项目需要访问的所有存储库安装它。 有关详细信息,请参阅“Installing your own GitHub App”。
-
将 GitHub App 的 ID 作为机密存储在存储库或组织中。 在以下工作流中,将
APP_ID
替换为机密的名称。 您可以在应用的设置页面上或通过应用 API 找到应用 ID。 有关详细信息,请参阅“应用”。 -
为应用生成私钥。 将生成的文件的内容作为机密存储在存储库或组织中。 (存储文件的全部内容,包括
-----BEGIN RSA PRIVATE KEY-----
和-----END RSA PRIVATE KEY-----
。)在以下工作流中,将APP_PEM
替换为机密的名称。 有关详细信息,请参阅“管理 GitHub 应用的私钥”。 -
在以下工作流中,将
YOUR_ORGANIZATION
替换为组织的名称。 例如octo-org
。 将YOUR_PROJECT_NUMBER
替换为项目编号。 要查找项目编号,请查看项目 URL。 例如,https://github.com/orgs/octo-org/projects/5
的项目编号为 5。 为了使此特定示例正常运行,项目还必须具有一个“发布日期”的日期字段。
# 此工作流使用未经 GitHub 认证的操作。
# 它们由第三方提供,并受
# 单独的服务条款、隐私政策和支持
# 文档。
# GitHub 建议将操作固定到提交 SHA。
# 若要获取较新版本,需要更新 SHA。
# 还可以引用标记或分支,但该操作可能会更改而不发出警告。
name: Add PR to project
on:
pull_request:
types:
- ready_for_review
jobs:
track_pr:
runs-on: ubuntu-latest
steps:
- name: Generate token
id: generate_token
uses: tibdex/github-app-token@b62528385c34dbc9f38e5f4225ac829252d1ea92
with:
app_id: ${{ secrets.APP_ID }}
private_key: ${{ secrets.APP_PEM }}
- name: Get project data
env:
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
ORGANIZATION: YOUR_ORGANIZATION
PROJECT_NUMBER: YOUR_PROJECT_NUMBER
run: |
gh api graphql -f query='
query($org: String!, $number: Int!) {
organization(login: $org){
projectV2(number: $number) {
id
fields(first:20) {
nodes {
... on ProjectV2Field {
id
name
}
... on ProjectV2SingleSelectField {
id
name
options {
id
name
}
}
}
}
}
}
}' -f org=$ORGANIZATION -F number=$PROJECT_NUMBER > project_data.json
echo 'PROJECT_ID='$(jq '.data.organization.projectV2.id' project_data.json) >> $GITHUB_ENV
echo 'DATE_FIELD_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Date posted") | .id' project_data.json) >> $GITHUB_ENV
echo 'STATUS_FIELD_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .id' project_data.json) >> $GITHUB_ENV
echo 'TODO_OPTION_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .options[] | select(.name=="Todo") |.id' project_data.json) >> $GITHUB_ENV
- name: Add PR to project
env:
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
PR_ID: ${{ github.event.pull_request.node_id }}
run: |
item_id="$( gh api graphql -f query='
mutation($project:ID!, $pr:ID!) {
addProjectV2ItemById(input: {projectId: $project, contentId: $pr}) {
item {
id
}
}
}' -f project=$PROJECT_ID -f pr=$PR_ID --jq '.data.addProjectV2ItemById.item.id')"
echo 'ITEM_ID='$item_id >> $GITHUB_ENV
- name: Get date
run: echo "DATE=$(date +"%Y-%m-%d")" >> $GITHUB_ENV
- name: Set fields
env:
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
run: |
gh api graphql -f query='
mutation (
$project: ID!
$item: ID!
$status_field: ID!
$status_value: String!
$date_field: ID!
$date_value: Date!
) {
set_status: updateProjectV2ItemFieldValue(input: {
projectId: $project
itemId: $item
fieldId: $status_field
value: {
singleSelectOptionId: $status_value
}
}) {
projectV2Item {
id
}
}
set_date_posted: updateProjectV2ItemFieldValue(input: {
projectId: $project
itemId: $item
fieldId: $date_field
value: {
date: $date_value
}
}) {
projectV2Item {
id
}
}
}' -f project=$PROJECT_ID -f item=$ITEM_ID -f status_field=$STATUS_FIELD_ID -f status_value=${{ env.TODO_OPTION_ID }} -f date_field=$DATE_FIELD_ID -f date_value=$DATE --silent
使用 personal access token 进行身份验证的示例工作流程
- 使用
project
和repo
范围创建 personal access token (classic)。 有关详细信息,请参阅“Managing your personal access tokens”。 - 将 personal access token 保存为存储库或组织中的机密。
- 在以下工作流中,将
YOUR_TOKEN
替换为机密的名称。 将YOUR_ORGANIZATION
替换为组织的名称。 例如octo-org
。 将YOUR_PROJECT_NUMBER
替换为项目编号。 要查找项目编号,请查看项目 URL。 例如,https://github.com/orgs/octo-org/projects/5
的项目编号为 5。
name: Add PR to project
on:
pull_request:
types:
- ready_for_review
jobs:
track_pr:
runs-on: ubuntu-latest
steps:
- name: Get project data
env:
GITHUB_TOKEN: ${{ secrets.YOUR_TOKEN }}
ORGANIZATION: YOUR_ORGANIZATION
PROJECT_NUMBER: YOUR_PROJECT_NUMBER
run: |
gh api graphql -f query='
query($org: String!, $number: Int!) {
organization(login: $org){
projectV2(number: $number) {
id
fields(first:20) {
nodes {
... on ProjectV2Field {
id
name
}
... on ProjectV2SingleSelectField {
id
name
options {
id
name
}
}
}
}
}
}
}' -f org=$ORGANIZATION -F number=$PROJECT_NUMBER > project_data.json
echo 'PROJECT_ID='$(jq '.data.organization.projectV2.id' project_data.json) >> $GITHUB_ENV
echo 'DATE_FIELD_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Date posted") | .id' project_data.json) >> $GITHUB_ENV
echo 'STATUS_FIELD_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .id' project_data.json) >> $GITHUB_ENV
echo 'TODO_OPTION_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .options[] | select(.name=="Todo") |.id' project_data.json) >> $GITHUB_ENV
- name: Add PR to project
env:
GITHUB_TOKEN: ${{ secrets.YOUR_TOKEN }}
PR_ID: ${{ github.event.pull_request.node_id }}
run: |
item_id="$( gh api graphql -f query='
mutation($project:ID!, $pr:ID!) {
addProjectV2ItemById(input: {projectId: $project, contentId: $pr}) {
item {
id
}
}
}' -f project=$PROJECT_ID -f pr=$PR_ID --jq '.data.addProjectV2ItemById.item.id')"
echo 'ITEM_ID='$item_id >> $GITHUB_ENV
- name: Get date
run: echo "DATE=$(date +"%Y-%m-%d")" >> $GITHUB_ENV
- name: Set fields
env:
GITHUB_TOKEN: ${{ secrets.YOUR_TOKEN }}
run: |
gh api graphql -f query='
mutation (
$project: ID!
$item: ID!
$status_field: ID!
$status_value: String!
$date_field: ID!
$date_value: Date!
) {
set_status: updateProjectV2ItemFieldValue(input: {
projectId: $project
itemId: $item
fieldId: $status_field
value: {
singleSelectOptionId: $status_value
}
}) {
projectV2Item {
id
}
}
set_date_posted: updateProjectV2ItemFieldValue(input: {
projectId: $project
itemId: $item
fieldId: $date_field
value: {
date: $date_value
}
}) {
projectV2Item {
id
}
}
}' -f project=$PROJECT_ID -f item=$ITEM_ID -f status_field=$STATUS_FIELD_ID -f status_value=${{ env.TODO_OPTION_ID }} -f date_field=$DATE_FIELD_ID -f date_value=$DATE --silent
工作流程说明
下表说明了示例工作流程的各个部分,并向您展示了如何调整工作流程以供自己使用。
代码 | 说明 |
---|---|
|
当仓库中的拉取请求标记为“准备审核”时,此工作流程将运行。 |
仅限 GitHub App:
|
使用 tibdex/github-app-token 操作从应用 ID 和私钥为应用生成安装访问令牌。 稍后在工作流中以 ${{ steps.generate_token.outputs.token }} 的形式访问安装访问令牌。
将 APP_ID 替换为包含应用 ID 的机密的名称。
将 APP_PEM 替换为包含应用私钥的机密的名称。
|
GitHub App:
Personal access token:
|
为此步骤设置环境变量。
如果使用 personal access token,请将 YOUR_TOKEN 替换为包含 personal access token 的机密的名称。
将 YOUR_ORGANIZATION 替换为组织的名称。 例如 octo-org 。
将 YOUR_PROJECT_NUMBER 替换为项目编号。 要查找项目编号,请查看项目 URL。 例如,https://github.com/orgs/octo-org/projects/5 的项目编号为 5。
|
|
使用 GitHub CLI 查询项目的 ID 的 API,并返回项目中前 20 个字段的名称和 ID。 响应存储在名为 |
|
解析 API 查询的响应,并将相关 ID 存储为环境变量。 修改此选项以获取不同字段或选项的 ID。 例如:
|
GitHub App:
Personal access token:
|
为此步骤设置环境变量。 GITHUB_TOKEN 如上所述。 PR_ID 是触发此工作流的拉取请求的 ID。
|
|
使用 GitHub CLI 和 API 将触发此工作流的拉取请求添加到项目。 jq 标志解析响应以获取所创建项目的 ID。
|
|
将已创建项的 ID 存储为环境变量。 |
|
以 yyyy-mm-dd 格式将当前日期保存为环境变量。
|
GitHub App:
Personal access token:
|
为此步骤设置环境变量。 GITHUB_TOKEN 如上所述。
|
|
将 Status 字段的值设置为 Todo 。 设置 Date posted 字段的值。
|