0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Github Actionsを使ってレビュー開始日時および完了日時をNotionのタスクチケットに記録する

Last updated at Posted at 2025-08-22

概要

example1.png

コードレビューにかかる時間の可視化に向けて、最初にレビュー依頼した時および approve された時の日時を Notion のタスクチケットに自動で記録する仕組みを Github Actions + Notion API で実装しました。今回はその手順を書いていこうと思います。

動作イメージ:
image.gif

手順

Notion準備

インテグレーションを作成する

以下のページから Notion のインテグレーションを作成してください。「新しいインテグレーション」をクリックし、インテグレーション名と関連ワークスペースを選択して「保存」を押すことで保存できます。

保存後の設定画面にて ntn_ で始まるインテグレーションシークレットを確認できるのでコピーしてください。Github Actions にて使用するので、Github の設定画面の Secrets and variables > Actions のシークレットに保存してください(シークレット名は何でも大丈夫です。ここでは NOTION_TOKEN とします)。

secrets_1.png

データベースとインテグレーションを接続する

タスクチケットを管理しているデータベースの Notion テーブルを開いてください。まず、URL 内にあるデータベースID部分をコピーしてください(クエリパラメータ ? の手前にある文字列がデータベースIDです)。これを Github Actions のシークレットに保存してください(ここでは NOTION_DATABASE_ID とします)。

url1.png

次に、Notion テーブルの右上の三点リーダーから「接続」をクリックして先ほど作成したインテグレーションを選択し、インテグレーションを接続してください。

データベースにプロパティを追加する

レビュー開始日時およびレビュー完了日時を記録するプロパティをデータベースに追加します。名前は何でも大丈夫ですが、ここでは「レビュー開始日時」「レビュー完了日時」という名前にします。種類はどちらも日付タイプで作成してください。

Github Actionsのワークフロー実装

Notion と連携させたいリポジトリにてワークフローを作成します。今回は

  • TASK-1234 あああ のように TASK-XXX(XXX 部分は更新したい Notion タスクチケットの ID)で始まるタイトルで作成したプルリクを対象とする
  • 初回レビュー依頼時に「レビュー開始日時」プロパティに現在日時を記録(既にプロパティに日時が記録されている場合はスキップ)
  • プルリクが approve された時に「レビュー完了日時」プロパティに現在日時を記録(既にプロパティに日時が記録されている場合は日時を更新)

するワークフローを作成したいと思います。

以下の内容で yml ファイルを作成してください。

.github/workflows/connect-notion-task.yml
name: Connect Notion Task with GitHub PR

on:
  pull_request:
    types:
      - review_requested
      - edited
  pull_request_review:
    types:
      - submitted

env:
  NOTION_TOKEN: ${{ secrets.NOTION_TOKEN }} # ntn_から始まるNotionのトークン
  DATABASE_ID: ${{ secrets.NOTION_DATABASE_ID }} # NotionページURLの先頭に付くID
  NOTION_REVIEW_START_DATE_PROPERTY_NAME: 'レビュー開始日時' # レビュー開始日時を記録するプロパティ名
  NOTION_REVIEW_APPROVED_DATE_PROPERTY_NAME: 'レビュー完了日時' # レビュー完了日時を記録するプロパティ名

jobs:
  connect-notion-task-with-github-pr:
    runs-on: ubuntu-22.04
    permissions:
      contents: read
      pull-requests: write
    steps:
      - uses: actions/checkout@v4

      # TASK-XXX で始まるタイトルのプルリクにて、初回レビュー依頼時にNotionにレビュー開始日時を記録する(既に日付が設定されている場合はスキップ)
      - name: Install jq
        if: github.event.action == 'review_requested'
        id: install_jq_requested
        run: sudo apt-get update && sudo apt-get install -y jq

      - name: Extract Notion ID from PR title
        if: github.event.action == 'review_requested'
        id: extract_notion_id_requested
        env:
          PR_TITLE: ${{ github.event.pull_request.title }}
        run: |
          # TASK-XXX のようなパターンから数値部分のみを抽出
          if [[ "${PR_TITLE}" =~ TASK-([0-9]+) ]]; then
            NOTION_ID="${BASH_REMATCH[1]}"
            echo "抽出されたNotion ID: $NOTION_ID"
            echo "VALUE=$NOTION_ID" >> $GITHUB_OUTPUT
          else
            echo "PRタイトルからNotion IDが見つかりませんでした: $PR_TITLE"
            echo "VALUE=" >> $GITHUB_OUTPUT
          fi

      - name: Find Notion page by ID
        id: find_page_requested
        if: steps.extract_notion_id_requested.outputs.VALUE != ''
        run: |
          SEARCH_RESPONSE=$(curl -s -X POST "https://api.notion.com/v1/databases/${{ env.DATABASE_ID }}/query" \
            -H "Authorization: Bearer ${{ env.NOTION_TOKEN }}" \
            -H "Content-Type: application/json" \
            -H "Notion-Version: 2022-06-28" \
            -d "{
              \"filter\": {
                \"property\": \"ID\",
                \"unique_id\": {
                  \"equals\": ${{ steps.extract_notion_id_requested.outputs.VALUE }}
                }
              }
            }")
          
          echo "検索レスポンス: $SEARCH_RESPONSE"
          
          # エラーチェック
          if echo "$SEARCH_RESPONSE" | jq -e '.object == "error"' > /dev/null; then
            echo "検索エラー: $(echo "$SEARCH_RESPONSE" | jq -r '.message')"
            exit 1
          fi
          
          PAGE_ID=$(echo "$SEARCH_RESPONSE" | jq -r '.results[0].id // empty')
          
          if [ -n "$PAGE_ID" ]; then
            echo "見つかったページID: $PAGE_ID"
            echo "VALUE=$PAGE_ID" >> $GITHUB_OUTPUT
          
            # レビュー開始日時プロパティの現在値を取得
            REVIEW_START_DATE_VALUE=$(echo "$SEARCH_RESPONSE" | jq -r ".results[0].properties[\"${{ env.NOTION_REVIEW_START_DATE_PROPERTY_NAME }}\"].date.start // empty")
            echo "現在のレビュー開始日時: $REVIEW_START_DATE_VALUE"
            echo "CURRENT_VALUE=$REVIEW_START_DATE_VALUE" >> $GITHUB_OUTPUT
          else
            echo "対象のNotionページが見つかりませんでした"
            exit 1
          fi

      - name: Check if review start date is already set
        id: check_existing_date_requested
        if: steps.find_page_requested.outputs.VALUE != ''
        run: |
          CURRENT_VALUE="${{ steps.find_page_requested.outputs.CURRENT_VALUE }}"
          
          if [ -z "$CURRENT_VALUE" ] || [ "$CURRENT_VALUE" = "null" ]; then
            echo "レビュー開始日時が未設定のため、更新を実行します"
            echo "SHOULD_UPDATE=true" >> $GITHUB_OUTPUT
          else
            echo "レビュー開始日時が既に設定されています: $CURRENT_VALUE"
            echo "更新をスキップします"
            echo "SHOULD_UPDATE=false" >> $GITHUB_OUTPUT
          fi

      - name: Get current datetime
        if: steps.check_existing_date_requested.outputs.SHOULD_UPDATE == 'true'
        id: get_datetime_requested
        run: |
          # 日本時間でISO 8601形式の日時を取得(タイムゾーンオフセット付き)
          CURRENT_DATETIME=$(TZ=Asia/Tokyo date +'%Y-%m-%dT%H:%M:%S+09:00')
          echo "現在日時(JST): $CURRENT_DATETIME"
          echo "VALUE=$CURRENT_DATETIME" >> $GITHUB_OUTPUT

      - name: Update Notion page with review start date
        if: steps.check_existing_date_requested.outputs.SHOULD_UPDATE == 'true' && steps.get_datetime_requested.outputs.VALUE != ''
        id: update_notion_review_start_date
        run: |
          echo "ページを更新中: ${{ steps.find_page_requested.outputs.VALUE }}"
          echo "日時: ${{ steps.get_datetime_requested.outputs.VALUE }}"
          
          UPDATE_RESPONSE=$(curl -s -X PATCH "https://api.notion.com/v1/pages/${{ steps.find_page_requested.outputs.VALUE }}" \
            -H "Authorization: Bearer ${{ env.NOTION_TOKEN }}" \
            -H "Content-Type: application/json" \
            -H "Notion-Version: 2022-06-28" \
            -d "{
              \"properties\": {
                \"${{ env.NOTION_REVIEW_START_DATE_PROPERTY_NAME }}\": {
                  \"date\": {
                    \"start\": \"${{ steps.get_datetime_requested.outputs.VALUE }}\"
                  }
                }
              }
            }")
          
          # エラーチェック
          if echo "$UPDATE_RESPONSE" | jq -e '.object == "error"' > /dev/null; then
            echo "❌ 更新エラー: $(echo "$UPDATE_RESPONSE" | jq -r '.message')"
            echo "レスポンス詳細: $UPDATE_RESPONSE"
            exit 1
          else
            echo "✅ レビュー開始日時を更新しました"
            echo "📅 日時: ${{ steps.get_datetime_requested.outputs.VALUE }}"
            echo "📄 ページID: ${{ steps.find_page_requested.outputs.VALUE }}"
          fi

      # TASK-XXX で始まるタイトルのプルリクにて、approve時にNotionにレビュー完了日時を記録する(既に日付が設定されている場合は更新する)
      - name: Install jq
        if: github.event.review.state == 'approved'
        id: install_jq_approved
        run: sudo apt-get update && sudo apt-get install -y jq

      - name: Extract Notion ID from PR title
        if: github.event.review.state == 'approved'
        id: extract_notion_id_approved
        env:
          PR_TITLE: ${{ github.event.pull_request.title }}
        run: |
          # TASK-XXX のようなパターンから数値部分のみを抽出
          if [[ "${PR_TITLE}" =~ TASK-([0-9]+) ]]; then
            NOTION_ID="${BASH_REMATCH[1]}"
            echo "抽出されたNotion ID: $NOTION_ID"
            echo "VALUE=$NOTION_ID" >> $GITHUB_OUTPUT
          else
            echo "PRタイトルからNotion IDが見つかりませんでした: $PR_TITLE"
            echo "VALUE=" >> $GITHUB_OUTPUT
          fi

      - name: Find Notion page by ID
        id: find_page_approved
        if: steps.extract_notion_id_approved.outputs.VALUE != ''
        run: |
          SEARCH_RESPONSE=$(curl -s -X POST "https://api.notion.com/v1/databases/${{ env.DATABASE_ID }}/query" \
            -H "Authorization: Bearer ${{ env.NOTION_TOKEN }}" \
            -H "Content-Type: application/json" \
            -H "Notion-Version: 2022-06-28" \
            -d "{
              \"filter\": {
                \"property\": \"ID\",
                \"unique_id\": {
                  \"equals\": ${{ steps.extract_notion_id_approved.outputs.VALUE }}
                }
              }
            }")
          
          echo "検索レスポンス: $SEARCH_RESPONSE"
          
          # エラーチェック
          if echo "$SEARCH_RESPONSE" | jq -e '.object == "error"' > /dev/null; then
            echo "検索エラー: $(echo "$SEARCH_RESPONSE" | jq -r '.message')"
            exit 1
          fi
          
          PAGE_ID=$(echo "$SEARCH_RESPONSE" | jq -r '.results[0].id // empty')
          
          if [ -n "$PAGE_ID" ]; then
            echo "見つかったページID: $PAGE_ID"
            echo "VALUE=$PAGE_ID" >> $GITHUB_OUTPUT
          
            # レビュー完了日時プロパティの現在値を取得
            REVIEW_APPROVED_DATE_VALUE=$(echo "$SEARCH_RESPONSE" | jq -r ".results[0].properties[\"${{ env.NOTION_REVIEW_APPROVED_DATE_PROPERTY_NAME }}\"].date.start // empty")
            echo "現在のレビュー完了日時: $REVIEW_APPROVED_DATE_VALUE"
            echo "CURRENT_VALUE=$REVIEW_APPROVED_DATE_VALUE" >> $GITHUB_OUTPUT
          else
            echo "対象のNotionページが見つかりませんでした"
            exit 1
          fi

      - name: Get current datetime
        if: steps.extract_notion_id_approved.outputs.VALUE != ''
        id: get_datetime_approved
        run: |
          # 日本時間でISO 8601形式の日時を取得(タイムゾーンオフセット付き)
          CURRENT_DATETIME=$(TZ=Asia/Tokyo date +'%Y-%m-%dT%H:%M:%S+09:00')
          echo "現在日時(JST): $CURRENT_DATETIME"
          echo "VALUE=$CURRENT_DATETIME" >> $GITHUB_OUTPUT

      - name: Update Notion page with review approved date
        if: steps.get_datetime_approved.outputs.VALUE != ''
        id: update_notion_review_approved_date
        run: |
          echo "ページを更新中: ${{ steps.find_page_approved.outputs.VALUE }}"
          echo "日時: ${{ steps.get_datetime_approved.outputs.VALUE }}"
          
          UPDATE_RESPONSE=$(curl -s -X PATCH "https://api.notion.com/v1/pages/${{ steps.find_page_approved.outputs.VALUE }}" \
            -H "Authorization: Bearer ${{ env.NOTION_TOKEN }}" \
            -H "Content-Type: application/json" \
            -H "Notion-Version: 2022-06-28" \
            -d "{
              \"properties\": {
                \"${{ env.NOTION_REVIEW_APPROVED_DATE_PROPERTY_NAME }}\": {
                  \"date\": {
                    \"start\": \"${{ steps.get_datetime_approved.outputs.VALUE }}\"
                  }
                }
              }
            }")
          
          # エラーチェック
          if echo "$UPDATE_RESPONSE" | jq -e '.object == "error"' > /dev/null; then
            echo "❌ 更新エラー: $(echo "$UPDATE_RESPONSE" | jq -r '.message')"
            echo "レスポンス詳細: $UPDATE_RESPONSE"
            exit 1
          else
            echo "✅ レビュー完了日時を更新しました"
            echo "📅 日時: ${{ steps.get_datetime_approved.outputs.VALUE }}"
            echo "📄 ページID: ${{ steps.find_page_approved.outputs.VALUE }}"
          fi

プルリクを作成してレビュー依頼を出すと、「レビュー開始日時」プロパティに現在日時が記録されます。再レビュー依頼時など、既にプロパティに日付が記録されている場合はスキップされます。

プルリクが approve された時に「レビュー完了日時」プロパティに現在日時が記録されます。再 approve した場合など、既にプロパティに日付が記録されている場合は日時が更新されます。

今回は TASK-XXX で始まる名前でプルリクを作成した場合に発火するようにしましたが、正規表現部分を変えればここの条件は変更可能です。

まとめ

今回はレビュー開始日時およびレビュー完了日時を記録できるようにしましたが、Notion API を使えば任意のプロパティの値を更新できるので他にもやれることはありそうです。ぜひ色々試してみてください。

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?