[Notion]GitHub リポジトリの最新リリースノートをActions WorkflowでNotionDB上に出力してみた

GitHub リポジトリの最新リリースノートを手書きでなく自動でNotionDBに出力できないものかと試して、nodejsプロジェクトにて実際に出力までやってみました。
2023.03.15

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

アクセス制限のあるGitHubリポジトリ内容の一部をGitHub外で確認可能とするには何らかの形でアウトプットさせる必要があります。よくあるのはSlack等への出力、所謂フロー情報ですが、スタック情報として出力できないか試していました。

現在Notionに独自形式でのスタック情報を自動出力するにはAPIの経由が必須です。GitHubリポジトリ更新のタイミングで行いたい場合はGitHub Actionsが無難でしょう。問題は出力する内容をAPIが受け付ける構成に変換する方法です。

Notion APIのPython製非公式ラッパー経由であれこれ試していましたが、一番のネックはNotion API用Object Blockに変換する方法を自作せざる得ないところ。Block毎に構成が異なり、validator作成に中々の時間がかかることだけは予想がつきます。

ですが、Nodejsにはtryfabric/martianというmarkdownを元に変換を担当してくれるライブラリが既に存在します。Notion公式ライブラリの@notionhq/clientと合わせることで手軽な更新が可能となります。GitHub Actions上で何らかのJSONレスポンスを扱わざる得ない場合にはjson2mdを使うとよいでしょう。

今回は以下の記事を一部参考としています。

ローカルセットアップ

今回用のリポジトリを新規で作成するか、既存リポジトリに処理用のディレクトリを追加します。

yarn init --yes
yarn add @notionhq/client
yarn add @tryfabric/martian
yarn add typescript
npx tsc --init

環境変数として以下3つを用意します。

変数名 詳細
NOTION_TOKEN コネクト用に発行します。
GITHUB_TOKEN ローカルではPersonal Access Tokenを指定します。
Actions workflow上では secrets.GITHUB_TOKENに差し替えます。
NOTION_DATABASE_ID ActionsからNotionへ出力する際のデータベースIDを指定します。
NOTION_TOKEN連携設定のコネクトを忘れずに。
$ vim .envrc
export NOTION_TOKEN=XXXXXXXXXXXXXXXXXXXXXX
export GITHUB_TOKEN=OOOOOOOOOOOOOOOOOOOOOO
export NOTION_DATABASE_ID=OOOOOOOOOOOOOOOOOOOOOO
$ direnv allow .

Personal Access Tokenが適切に取れているか確認したい場合は、以下のコマンドを実行します。

curl -L \
  -H "Accept: application/vnd.github.v3+json" \
  -H "Authorization: Bearer $GITHUB_TOKEN"\
  -H "X-GitHub-Api-Version: 2022-11-28" \
  https://api.github.com/repos/USER/REPOS/releases/latest

スクリプトの追加

Notion上へページを追加する処理を入れます。

$ mkdir src
$ cd src
$ touch index.ts
import { Client } from '@notionhq/client'
import { markdownToBlocks } from '@tryfabric/martian'

const token = process.env.NOTION_TOKEN
const database_id = process.env.NOTION_DATABASE_ID || "";
const release_note = process.env.RELEASE_NOTE || '{"body": ""}'
async function main() {
  const notion = new Client({ auth: token })
  try {
    var release_status = JSON.parse(release_note) 
    console.log(release_note)
    var params = {
      parent: {
        database_id: database_id
      },
      properties: {
        '名前': {
          title: [{
            text: {
              content: "release_note",
            }
          }]
        }
      },
      children: markdownToBlocks(release_status.body)
    }
    await notion.pages.create(params)
  } catch (e) {
    console.error(e)
  }
}

main()

ページタイトルが全てrelease_noteになってしまうため、実際の処理では環境変数経由で日付を取得するか、スクリプト内で日付を指定することをオススメします。

ページのプロパティに日付やタグを入れることも可能ですが、今回はページ追加と本文にリリースノート出力が出来ることを最優先としたため割愛しています。

ローカルでの検証

コマンドを楽にするため、package.jsonに以下を指定します。

...
  "scripts": {
    "update": "ts-node --esm src/index.ts"
  },
...

仮データを設定します。

$ export RELEASE_NOTE='{"body":"test"}'

設定に漏れがなければ、以下のコマンドでデータベース上にリリースノートが記載されたページを追加できます。

$ npm run update

> yarn-flow@1.0.0 update
> ts-node --esm src/index.ts

{"body":"test"}

Actions workflowの追加

特に特殊なActionは併用していませんが、release-noteが複数行に及ぶためGITHUB_ENVに出力させる手段が少し変わり種です。

$ touch .github/workflow/notion-publish.yml
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs

name: Node.js CI

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]
defaults:
  run:
    working-directory: notion-publish/
jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [18.x]
        # See supported Node.js release schedule at https://nodejs.org/en/about/releases/

    steps:
    - uses: actions/checkout@v3
    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v3
      with:
        node-version: ${{ matrix.node-version }}
        cache: 'npm'
        cache-dependency-path: notion-publish/package-lock.json
    - run: yarn install --frozen-lockfile
    - name: Dump release note
      id: release_note
      run: |
        EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64)
        echo "RELEASE_NOTE<<$EOF" >> $GITHUB_ENV
        curl -X GET -H 'Accept: application/vnd.github.v3+json' -H 'Authorization: token ${{ secrets.GITHUB_TOKEN }}' -H 'X-GitHub-Api-Version: 2022-11-28' https://api.github.com/repos/${{ github.repository }}/releases/latest >> $GITHUB_ENV
        echo "$EOF" >> $GITHUB_ENV
    - name: Set Title
      id: set_title
      run: echo "TITLE=Release $(date +'%Y%m%d')" >> $GITHUB_ENV
    - name: Set Date
      id: set_date
      run: echo "DATE=$(date +'%Y%m%d')" >> $GITHUB_ENV
    - name: Generate release note
      run: npm run update
      env:
        NOTION_TOKEN: ${{ secrets.NOTION_TOKEN }}
        NOTION_DATABASE_ID: ${{ secrets.NOTION_DATABASE_ID }}

ActionsのSecretsにNOTION_TOKENとNOTION_DATABASE_IDを忘れずに設定しましょう。

実行する

Workflowは11秒程度で完了するはずです。

実行後にNotionでデータベースをみるとリリースノートが追加されています。

あとがき

追加するページ構成に合わせてリリースノートAPIのレスポンスを分解する必要があるのですが、とりあえずはリリース日付をプロパティに入れた上で、本文をページ内に指定するだけでも用は果たせるのではないかと思われます。それ以外の要素はリポジトリの運用方針によってデータの持たせ方が異なる可能性もあり、それらに合わせた出力が必要となるはずです。

なお、今回一番手間がかかったのは新規nodejsプロジェクトの正常実行に至るまででした。普段新規で起こすことが滅多にないために各種コンフィグの設定をどう弄るべきか、及びnodejsのバージョンに伴う動作を追うのが中々大変だった感じです。

Notionへのリリースノート出力自体は最低でも今回の2ファイル程度で収まる形となります。手作業でデータを毎回コピペしている場合はその手間が省けるのでオススメします。