Skip to main content

Actions を使用した Projects の自動化

GitHub Actions を使ってプロジェクトを自動化できます。

GitHub Actionsのワークフロー

このセクションでは、GraphQL APIとGitHub Actionsを使ってOrganizationのプロジェクトにPull Requestを追加する方法を紹介します。 このワークフローの例では、Pull Requestが"ready for review"としてマークされると、プロジェクトに新しいタスクが追加され、"Status"フィールドが"Todo"に設定され、現在の日付がカスタムの"Date posted"フィールドに追加されます。

必要に応じて、以下のワークフローの1つをコピーして、以下の表にあるように変更できます。

プロジェクトは複数のリポジトリにまたがることができますが、ワークフローは1つのリポジトリに固有です。 プロジェクトで追跡する各リポジトリにワークフローを追加します。ワークフロー ファイルの作成の詳細については、「GitHub Actions のクイックスタート」を参照してください。

この記事は、GitHub Actionsを基本的に理解していることを前提としています。 GitHub Actions の詳細については、「GitHub Actions」を参照してください。

API を使用してプロジェクトに加えることができるその他の変更の詳細については、「API を使ったプロジェクト (ベータ) の管理」を参照してください。

また、GitHub によって管理され、指定されたプロジェクトに現在の issue または pull request を追加する actions/add-to-project ワークフローを使用することもできます。 詳しくは、actions/add-to-project リポジトリと README を参照してください。

注: GITHUB_TOKEN はリポジトリ レベルをスコープとしており、projects にはアクセスできません。 projects にアクセスするために、GitHub App (Organization プロジェクトの場合に推奨) または個人用アクセス トークン (ユーザー プロジェクトの場合に推奨) を作成できます。 以下には、どちらの方法のワークフローの例も示します。

GitHub Appで認証を行うワークフローの例

  1. GitHub Appを作成するか、自分のOrganizationが所有する既存のGitHub Appを選択してください。 詳細については、「GitHub App を作成する」を参照してください。

  2. GitHub Appに、Organizationプロジェクトに対する読み込み及び書き込み権限を与えてください。 詳細については、「GitHub App の権限を編集する」を参照してください。

    注: Organization プロジェクトおよびリポジトリ プロジェクトに対するアプリのアクセス許可を制御できます。 Organizationプロジェクトに対する読み書き権限を与えなければなりません。リポジトリプロジェクトに対する読み書き権限だけでは不十分です。

  3. OrganizationにGitHub Appをインストールしてください。 プロジェクトがアクセスする必要があるすべてのリポジトリにインストールしてください。 詳細については、「GitHub Apps のインストール」を参照してください。

  4. GitHub AppのIDを、リポジトリもしくはOrganizationのシークレットとして保存してください。 以下のワークフローでは、APP_ID をシークレットの名前に置き換えます。 アプリケーションIDは、アプリケーションの設定ページで、あるいはアプリケーションのAPIを通じて確認できます。 詳細については、「アプリ」を参照してください。

  5. アプリケーションの秘密鍵を生成してください。 作成されたファイルの内容を、シークレットとしてリポジトリもしくはOrganizationに保存してください。 (-----BEGIN RSA PRIVATE KEY----- および -----END RSA PRIVATE KEY----- を含め、ファイルの内容全体を保存してください)。以下のワークフローでは、APP_PEM をシークレットの名前に置き換えます。 詳細については、「GitHub Apps による認証」を参照してください。

  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@36464acb844fc53b9b8b2401da68844f6b05ebb0
        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

個人アクセストークンで認証するワークフローの例

  1. project および repo スコープで個人のアクセス トークンを作成します。 詳細については、個人アクセス トークンの作成に関する記事を参照してください。
  2. この個人アクセストークンをシークレットとしてリポジトリもしくはOrganizationに保存します。
  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
このワークフローは、リポジトリ内のPull Requestが"ready for review"としてマークされたときに実行されます。

GitHub App のみ:

- name: Generate token
  id: generate_token
  uses: tibdex/github-app-token@36464acb844fc53b9b8b2401da68844f6b05ebb0
  with:
    app_id: ${{ secrets.APP_ID }}
    private_key: ${{ secrets.APP_PEM }}
tibdex/github-app-token action を使用して、アプリ 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

個人用アクセス トークン:

env:
  GITHUB_TOKEN: ${{ secrets.YOUR_TOKEN }}
  ORGANIZATION: YOUR_ORGANIZATION
  PROJECT_NUMBER: YOUR_PROJECT_NUMBER
このステップのための環境変数を設定します。

個人用アクセス トークンを使用する場合は、YOUR_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) を使用して ProjectV2Field フィールドと ProjectV2SingleSelectField フィールドに関する情報を返します。

応答は、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 を追加します
注: このワークフローでは、プロジェクトに、"Todo" という名前のオプションを含む "Status" という名前の単一の選択フィールドと、"Date posted" という名前の日付フィールドがあることを前提としています。 テーブル中にあるフィールドにマッチするよう、このセクションは変更しなければなりません。

GitHub App:

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

個人用アクセス トークン:

env:
  GITHUB_TOKEN: ${{ secrets.YOUR_TOKEN }}
  PR_ID: ${{ github.event.pull_request.node_id }}
このステップのための環境変数を設定します。 GITHUB_TOKEN は、前述のとおりです。 PR_ID は、このワークフローをトリガーする pull request の 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 を使用して、このワークフローをトリガーした pull request をプロジェクトに追加します。 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 }}

個人用アクセス トークン:

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 フィールドの値を設定します。