Tech Blog

GitHub Projects を Actions で自動化する

チケット駆動開発で GitHub Projects を導入することになったので、Issue と Projects の紐付等の反復作業を GitHub CLI + GraphQL API を駆使して Actions ワークフローで自動化したい

今回の環境

TL;DR

1. GitHub App の作成

Register new GitHub App

2. ワークフロー定義 YAML ファイルの作成

  # .github/workflows/auto-track-issue.yml
+ #
+ name: Add Issue to project
+ # This workflow runs whenever a issue is opened.
+ on:
+   issues:
+     types:
+       - opened
+
+ jobs:
+   track_issue:
+     runs-on: ubuntu-latest
+     steps:
+       # Uses the [actions/create-github-app-token](https://github.com/marketplace/actions/create-github-app-token) action to generate an installation access token for your app from the app ID and private key. The installation access token is accessed later in the workflow as `${{ steps.generate-token.outputs.token }}`.
+       #
+       # Replace `APP_ID` with the name of the configuration variable that contains your app ID.
+       #
+       # Replace `APP_PEM` with the name of the secret that contains your app private key.
+       - name: Generate token
+         id: generate-token
+         uses: actions/create-github-app-token@v1
+         with:
+           app-id: ${{ vars.APP_ID }}
+           private-key: ${{ secrets.APP_PEM }}
+       # Sets environment variables for this step.
+       #
+       # Replace `YOUR_ORGANIZATION` with the name of your organization. For example, `octo-org`.
+       #
+       # Replace `YOUR_PROJECT_NUMBER` with your project number. To find the project number, look at the project URL. For example, `https://github.com/orgs/octo-org/projects/5` has a project number of 5.
+       - name: Get project data
+         env:
+           GH_TOKEN: ${{ steps.generate-token.outputs.token }}
+           ORGANIZATION: ${{ github.repository_owner }}
+           PROJECT_NUMBER: YOUR_PROJECT_NUMBER
+         # Uses [GitHub CLI](https://cli.github.com/manual/) to query the API for the ID of the project and return the name and ID of the first 20 fields in the project. `fields` returns a union and the query uses inline fragments (`... on`) to return information about any `ProjectV2Field` and `ProjectV2SingleSelectField` fields. The response is stored in a file called `project_data.json`.
+         run: |
+           gh api graphql -f query='
+             query($org: String!, $number: Int!) {
+               organization(login: $org){
+                 projectV2(number: $number) {
+                   id
+                   fields(first:20) {
+                     nodes {
+                       ... on ProjectV2FieldCommon {
+                         id
+                         dataType
+                       }
+                     }
+                   }
+                 }
+               }
+             }' -f org=$ORGANIZATION -F number=$PROJECT_NUMBER > project_data.json
+ 
+           # Parses the response from the API query and stores the relevant IDs as environment variables. Modify this to get the ID for different fields or options. For example:
+           #
+           # - To get the ID of a field called `Team`, add `echo 'TEAM_FIELD_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Team") | .id' project_data.json) >> $GITHUB_ENV`.
+           # - To get the ID of an option called `Octoteam` for the `Team` single select field, add `echo 'OCTOTEAM_OPTION_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Team") |.options[] | select(.name=="Octoteam") |.id' project_data.json) >> $GITHUB_ENV`.
+           #
+           # **Note:** This workflow assumes that you have a project with a single select field called "Status" that includes an option called "Todo" and a date field called "Date posted". You must modify this section to match the fields that are present in your table.
+ 
+           echo 'PROJECT_ID='$(jq '.data.organization.projectV2.id' project_data.json) >> $GITHUB_ENV
+           echo 'MILESTONE_FIELD_ID='$(jq '.data.user.projectV2.fields.nodes[] | select(.dataType=="MILESTONE") | .id' project_data.json)
+ 
+       # Sets environment variables for this step. `GH_TOKEN` is the token generated in the first step. `PR_ID` is the ID of the pull request that triggered this workflow.
+       - name: Add issue to project
+         env:
+           GH_TOKEN: ${{ steps.generate-token.outputs.token }}
+           ISSUE_ID: ${{ github.event.pull_request.node_id }}
+         # Uses [GitHub CLI](https://cli.github.com/manual/) and the API to add the pull request that triggered this workflow to the project. The `jq` flag parses the response to get the ID of the created item.
+         run: |
+           item_id="$( gh api graphql -f query='
+             mutation($project: ID!, $issue: ID!) {
+               addProjectV2ItemById(input: {projectId: $project, contentId: $issue}) {
+                 item {
+                   id
+                 }
+               }
+             }' -f project=$PROJECT_ID -f issue=$ISSUE_ID --jq '.data.addProjectV2ItemById.item.id')"
+ 
+           # Stores the ID of the created item as an environment variable.
+           echo 'ITEM_ID='$item_id >> $GITHUB_ENV
+

参考にしたページ