🐙

GitHub Actions で Issue を作成すると同時に Notion のデータベースにページを作成する

2022/02/11に公開

GitHub Actions により Issue を作成すると同時に Notion のデータベースにページを作成するということを実現するための例コードと解説を公開しておきます。Notion ページには GitHub Issue へのリンクを含ませる形にします。

例コードの方が話が早いという方もいると思いますので、まずは例コードを置いたリポジトリへのリンクを置いておきます:
https://github.com/tnagatomi/issue-and-notion-database-page

このコードの解説という形で説明を進めていこうと思います。Node.js や npm パッケージのセットアップなどの処理は省いてあります。ディレクトリ構成などはリポジトリを参考にしてください。

ユースケース

まずはユースケースですが、GitHub Actions により、cron などを使って自動で Issue を立てるという場面は多いと思います。
それに加えて、Notion を利用している場合、データベースにその Issue に関連したページを作成したいという場面があるかと思います。作業自体は Issue に記録し、タスク管理は Notion で行うといったような形です。
この記事ではそのような場面での同時作成の方法を説明しています。

利用するツール

Issue の作成には imjohnbo/issue-bot を利用します。タイトルや本文、ラベルといったプロパティを指定して Issue を作成できる便利な action です。

Notion のページ作成には Notion APIJavaScript action 経由で利用します。

準備

Notion の APIトークンを取得し、ページを作成するデータベースの ID を取得しておいてください。この辺りは 公式の Notion API ドキュメントを参考にしてください。

Notion データベースは次のような構成としておきます:

準備する Notion データベース

Title 型の Title、Select 型の Category、URL 型の Link というプロパティを用意しています。 Link には作成した GitHub Issue へのリンクが入ってくる形です。

例コードの解説

Action の構成は以下の通りです:

  • JavaScript action
  • JavaScript スクリプト
  • Workflow

では例コードの解説を始めていきます。

JavaScript action

まずは JavaScript action の YAML からです。Action として認識させるため、必ず action.yml という名前で作成してください。

action.yml
name: 'Create Notion Page in Database'
description: 'Create Notion Page in Database'
inputs:
  title:
    description: 'Title'
    required: true
  category:
    description: 'Category'
    required: true
  issue-number:
    description: 'Issue number'
    required: true
runs:
  using: 'node16'
  main: 'dist/index.js'

inputs にそれぞれ Title、Category、Link 用の入力を与えます。Link 用には Issue 番号のみ与え、番号より左の URL はスクリプト側で固定にします。ここには更に後ほど解説する workflow から入力が渡ってくる形となります。
runs.main で実際に実行する JavaScript ファイルを指定します。dist/index.js としているのは、vercel/ncc でコンパイルしたものを利用するためです。これにより node_modules/ のリモートリポジトリへの push が必要なくなります。

JavaScript

次は JavaScript のスクリプト本体です。

index.js
import {getInput, setFailed} from '@actions/core'
import {Client, LogLevel} from '@notionhq/client'

const notion = new Client({
    auth: process.env.NOTION_TOKEN,
    logLevel: LogLevel.DEBUG,
})

const NOTION_DATABASE_ID = process.env.NOTION_DATABASE_ID
const GITHUB_REPOSITORY_URL = 'https://github.com/tnagatomi/issue-and-notion-database-page'

const TITLE = 'title'
const CATEGORY = 'category'
const ISSUE_NUMBER = 'issue-number'

try {
    await notion.request({
        path: 'pages',
        method: 'post',
        body: {
            parent: {database_id: NOTION_DATABASE_ID},
            properties: {
                Title: [{text: {content: getInput(TITLE)}}],
                Category: {name: getInput(CATEGORY)},
                Link: `${GITHUB_REPOSITORY_URL}/issues/${getInput(ISSUE_NUMBER)}`,
            },
        },
    })
} catch (error) {
    setFailed(error.message)
}

NOTION_TOKEN は Notion API のトークンを、NOTION_DATABASE_ID は Notion のデータベース ID を GitHub Actions の Secrets として登録しておきます。Workflow 経由で渡ってきます。
GITHUB_REPOSITORY_URL は Issue を作成するリポジトリの URL に置き換えてください。

Notion のクライアントでリクエストを送っている様子がわかると思います。ボディの指定がプロパティにより独特なのでそこは注意です。

getInput() で先ほど JavaScript action の inputs で得た入力を取得しています。

これを vercel/nccdist/index.js にコンパイルします。

Workflow

最後に workflow です。ファイル名は .github/workflows に配置さえしていれば任意のもので良いです。

main.yml
name: Create GitHub Issue and Notion Database Page
on:
  workflow_dispatch:
jobs:
  create-issue:
    name: Create Issue
    runs-on: ubuntu-latest
    outputs:
      issue-number: ${{ steps.create-issue.outputs.issue-number }}
    steps:
      - name: Create Issue
        id: create-issue
        uses: imjohnbo/issue-bot@v3
        with:
          title: 'Awesome title here'
          labels: "development"
          body: |
            Awesome body here.
  create-notion-page:
    runs-on: ubuntu-latest
    needs: create-issue
    name: Create Notion Page
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Create Notion Page
        uses: ./
        env:
          NOTION_TOKEN: ${{ secrets.NOTION_TOKEN }}
          NOTION_DATABASE_ID: ${{ secrets.NOTION_DATABASE_ID }}
        with:
          title: 'Awesome title here'
          category: "development"
          issue-number: ${{ needs.create-issue.outputs.issue-number }}

on は例のために workflow_dispatch にしていますが、ユースケースに合わせて変えてください。

"Create Notion Page" step で uses: ./ とすることで JavaScript action を実行し、 with で入力を与えています。

jobs.create-notion-page.needscreate-issue とすることで Issue の作成 job が終わった後で Notion ページ作成 job が実行されるようにします。

以下の箇所がポイントで、"create-issue" step の issue-number という imjohnbo/issue-bot の出力を "create-issue" job で出力し、"Create Notion Page" step で受け取っています。

    outputs:
      issue-number: ${{ steps.create-issue.outputs.issue-number }}
        with:
          title: 'Awesome title here'
          category: "development"
          issue-number: ${{ needs.create-issue.outputs.issue-number }}

この方法については GitHub 公式のドキュメントが参考になると思います。

以上で解説は終わりです。

まとめ

  • imjohnbo/issue-bot での Issue の作成方法
  • Notion API による JavaScript でのページ作成方法
  • Job 間の入出力の受け渡し

この辺りがポイントかなと思います。参考になれば幸いです😄

Discussion