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

使用 Actions 自动化 Projects

可以使用 GitHub Actions 自动化你的项目。

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”。

  1. 创建 GitHub App 或选择组织拥有的现有 GitHub App。 有关详细信息,请参阅“Registering a GitHub App”。

  2. 授予 GitHub App 对组织项目的读取和写入权限。 对于此特定示例,你的 GitHub App 还需要有对存储库拉取请求和存储库问题的读取权限。 有关详细信息,请参阅“Modifying a GitHub App registration”。

    注意:你可以控制应用对组织项目和存储库项目的权限。 您必须授予读取和写入组织项目的权限;读取和写入存储库项目的权限是不够的。

  3. 在组织中安装 GitHub App。 为项目需要访问的所有存储库安装它。 有关详细信息,请参阅“Installing your own GitHub App”。

  4. 将 GitHub App 的 ID 作为机密存储在存储库或组织中。 在以下工作流中,将 APP_ID 替换为机密的名称。 您可以在应用的设置页面上或通过应用 API 找到应用 ID。 有关详细信息,请参阅“应用”。

  5. 为应用生成私钥。 将生成的文件的内容作为机密存储在存储库或组织中。 (存储文件的全部内容,包括 -----BEGIN RSA PRIVATE KEY----------END RSA PRIVATE KEY-----。)在以下工作流中,将 APP_PEM 替换为机密的名称。 有关详细信息,请参阅“管理 GitHub 应用的私钥”。

  6. 在以下工作流中,将 YOUR_ORGANIZATION 替换为组织的名称。 例如 octo-org。 将 YOUR_PROJECT_NUMBER 替换为项目编号。 要查找项目编号,请查看项目 URL。 例如,https://github.com/orgs/octo-org/projects/5 的项目编号为 5。 为了使此特定示例正常运行,项目还必须具有一个“发布日期”的日期字段。

YAML
# 此工作流使用未经 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 进行身份验证的示例工作流程

  1. 使用 projectrepo 范围创建 personal access token (classic)。 有关详细信息,请参阅“Managing your personal access tokens”。
  2. 将 personal access token 保存为存储库或组织中的机密。
  3. 在以下工作流中,将 YOUR_TOKEN 替换为机密的名称。 将 YOUR_ORGANIZATION 替换为组织的名称。 例如 octo-org。 将 YOUR_PROJECT_NUMBER 替换为项目编号。 要查找项目编号,请查看项目 URL。 例如,https://github.com/orgs/octo-org/projects/5 的项目编号为 5。
YAML
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

工作流程说明

下表说明了示例工作流程的各个部分,并向您展示了如何调整工作流程以供自己使用。

代码 说明
on:
  pull_request:
    types:
      - ready_for_review
当仓库中的拉取请求标记为“准备审核”时,此工作流程将运行。

仅限 GitHub App:

- name: Generate token
  id: generate_token
  uses: tibdex/github-app-token@c2055a00597a80f713b78b1650e8d3418f4d9a65
  with:
    app_id: ${{ secrets.APP_ID }}
    private_key: ${{ secrets.APP_PEM }}
使用 tibdex/github-app-token 操作从应用 ID 和私钥为应用生成安装访问令牌。 稍后在工作流中以 ${{ steps.generate_token.outputs.token }} 的形式访问安装访问令牌。

APP_ID 替换为包含应用 ID 的机密的名称。

APP_PEM 替换为包含应用私钥的机密的名称。

GitHub App:

env:
  GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
  ORGANIZATION: YOUR_ORGANIZATION
  PROJECT_NUMBER: YOUR_PROJECT_NUMBER

Personal access token:

env:
  GITHUB_TOKEN: ${{ secrets.YOUR_TOKEN }}
  ORGANIZATION: YOUR_ORGANIZATION
  PROJECT_NUMBER: YOUR_PROJECT_NUMBER
为此步骤设置环境变量。

如果使用 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。
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

使用 GitHub CLI 查询项目的 ID 的 API,并返回项目中前 20 个字段的名称和 ID。 fields 会返回一个联合,查询使用内联片段 (... on) 返回任何 ProjectV2FieldProjectV2SingleSelectField 字段的相关信息。

响应存储在名为 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
解析 API 查询的响应,并将相关 ID 存储为环境变量。 修改此选项以获取不同字段或选项的 ID。 例如:
  • 若要获取名为 Team 的字段的 ID,请添加 echo 'TEAM_FIELD_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Team") | .id' project_data.json) >> $GITHUB_ENV
  • 若要获取 Team 单选字段的名为 Octoteam 的选项的 ID,请添加 echo 'OCTOTEAM_OPTION_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Team") |.options[] | select(.name=="Octoteam") |.id' project_data.json) >> $GITHUB_ENV
注意:此工作流程假定你有一个项目,其中包含一个名为“状态”的单选字段、一个名为“待办”的选项和一个名为“发布日期”的日期字段 。 您必须修改此部分以匹配表中存在的字段。

GitHub App:

env:
  GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
  PR_ID: ${{ github.event.pull_request.node_id }}

Personal access token:

env:
  GITHUB_TOKEN: ${{ secrets.YOUR_TOKEN }}
  PR_ID: ${{ github.event.pull_request.node_id }}
为此步骤设置环境变量。 GITHUB_TOKEN 如上所述。 PR_ID 是触发此工作流的拉取请求的 ID。
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')"
使用 GitHub CLI 和 API 将触发此工作流的拉取请求添加到项目。 jq 标志解析响应以获取所创建项目的 ID。
echo 'ITEM_ID='$item_id >> $GITHUB_ENV
将已创建项的 ID 存储为环境变量。
echo "DATE=$(date +"%Y-%m-%d")" >> $GITHUB_ENV
yyyy-mm-dd 格式将当前日期保存为环境变量。

GitHub App:

env:
  GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}

Personal access token:

env:
  GITHUB_TOKEN: ${{ secrets.YOUR_TOKEN }}
为此步骤设置环境变量。 GITHUB_TOKEN 如上所述。
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
Status 字段的值设置为 Todo。 设置 Date posted 字段的值。