ABCABC Tech Catalog

NotionをヘッドレスCMSとして使ってNext.jsでTechブログを作った ⑤GitHub Actions編

ブログのレビュー体制をどのように構築するか

レビューというフロー

個人でブログを立ち上げるときと異なり、このようなブログを立ち上げる際は誰か承認者のレビューを経ておいたほうが安全です。

細かい日本語の修正もあれば、この内容って公開していいんだっけ?といったリスク管理的な要因もあります。

本ブログはここまで触れてきたように、Next.js + Vercel + Notion(CMS)な構成をとっている中で、レビューを差し込むタイミングについて検討しました。

Notionでレビューを行うパターン

ひとつは、Notionでレビューを行うパターンです。

具体的にはNotionのコメント機能を活用し、そこでレビューを行うということです。

file1

Notionのコメント機能は箇所指定の上で見やすいUIで付与できるので、こういったレビューにかなり向いていますね。

Slackベースでレビューを行うパターン

もうひとつは、Slackベースでレビューを行うパターンです。

Vercelのデプロイ通知がGitHub経由でSlackに到達したら、そのPreviewリンクをもとにスレッドを立ててレビューをしてもらうパターンですね。

file2

個人的にはVercel + GitHubのこのPreviewを含めたDeployment通知がかなり使えると思っていて、Slackでのレビュー体制もなかなか悪くない印象を受けました。

GitHubベースでレビューを行うパターン

そしてもう一つ考えられるのは、GitHubベースでレビューを行うパターンです。

後述しますが、本番環境へのデプロイは基本的にGitHubへのPull-Requestがマージされる形で行っています。逆に言うと、レビューを依頼できる状況=プレビュー環境が立ち上がっている状況ではPull-Requestが立ち上がっているので、そこにコメントの形でレビュー結果を伝える事が出来ます。

もちろんGitHubとSlackの連携が行われている場合、そのコメントもSlackに通知がいくようにできるので、こちらの方法でも汎用性はあると思います。

NotionやSlackでレビューする場合に比べ、こちらの方式だとレビュー内容がStockされるというメリットがありますね。

どのようにレビューを実施するようにしているか

実際のところ、本ブログで採用しているレビューのフロー概要は以下の通りです。

  1. Slackベースでプルリクエストを出すための申請を上げる
  2. GitHub Actionsがトリガされ、Pull-Requestが立ち上がる
  3. それと同時にプレビュー環境がデプロイされ、Slackに通知が行くので、その通知からスレッドを立ててレビュー依頼→レビュー実施・修正依頼はNotionのコメント機能を活用
  4. 問題無ければ承認者がマージ→本番環境へのデプロイが行われる

つまり、 レビューにはNotionのコメント機能を活用しており、Slackでレビュー完了等の連絡を実施 しています。

GitHub Actionsのトリガについて

そこで本記事の本題ですが、先ほど挙げた手順で重要なのは1〜2のステップです。

Slackベースでの申請→勝手にPull-Requestが立ち上がる 、という形は非エンジニアでも更新出来るブログとするためには必須条件になってくるかと思います。

そこで、本記事ではどのようにそれを実現させたかのポイントをまとめていきます。

Slack Appの活用

まず、最初のステップ、Slackベースでの申請についてです。これは実際下記のようなメッセージを送信することで実施しています。

file3

アーキテクチャ…というほどではないですが、このとき、裏側では何がおきているかというと、SlackへのメッセージをもとにCloud Functionsを呼び出して、Cloud FuncitonsからGitHub ActionsにPOSTリクエストを投げています。

ただリプライの内容をCloud Functionsに丸投げする本当にシンプルなSlack Appを立ち上げ、Cloud Functionsはそのリクエストの内容をもとに整形してGitHub Actionsをトリガしています。

送信するPayloadとしては

{"event_type": "publish-post", "client_payload": {"url": "notionの記事URL"}}

のような形で準備し、GitHub Actionsとしては

on:
  repository_dispatch:
    types: [publish-post]

のような形でトリガを設定しておけばOKです。

上記のように client_payload でGitHub Actionsへパラメータを渡すこともできます。

たとえば、NotionのURLのID部分だけを抜き取りたい場合は

- name: Get Post ID
  env:
    URL: ${{ github.event.client_payload.url }}
  run: echo "POST_ID=${URL##*-}" >> $GITHUB_ENV

のようにすれば、 POST_ID として以降のステップで利用できるようになります。

GitHub Actionsがトリガされた旨をSlackに投げる

Cloud FunctionsがどうしてもコールドスタートになるのでSlack申請からGitHub Actionsがトリガされるまで微妙にタイムラグがあります。

そこで、Slackへの通知をGitHub Actionsへ組み込んでおきます

# Slackへの受付通知
- name: Notify to Slack
  uses: rtCamp/action-slack-notify@v2
  if: ${{ always() }}
  env:
    SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
    SLACK_CHANNEL: [チャンネル名]
    SLACK_ICON_EMOJI: ":building_construction:"
    SLACK_USERNAME: 投稿申請受付通知
    MSG_MINIMAL: true
    SLACK_MESSAGE: 投稿申請を受け付けました 処理を開始します

ここでは、 rtCamp/action-slack-notify を使わせていただいております。

file4

このような形で投稿申請受付の通知が来るので安心してPull-Requestが立ち上がるまでお茶を飲めますね 🍵

GitHub ActionsでPull-Requestを立てる

そしてPull-Requestを立てるステップについてです。

まず、ブランチ名を決めます。例えば、先ほど取得した POST_ID を使って、actions/publish-post-[POST_ID] とでもしておきます。

- name: Set Branch Name
	run: echo "BRANCH_NAME=actions/publish-post-${{ env.POST_ID }}" >> $GITHUB_ENV

同一記事の修正等は同じブランチで行いたいので、記事ページのIDという一意な値を活用しています。実際はそれに関連してブランチ有無を確認するステップを入れたりしていますが、本題からズレるのでここでは割愛します。

scripts/generate_data/main.py がライブラリがPoetryで管理されているデータ取得用のスクリプトとしたとき、 NOTION_TOKEN としてリポジトリのシークレットにNotion APIのトークンを格納の上で、

- uses: actions/setup-python@v4
  with:
    python-version: 3.9
- uses: abatilo/actions-poetry@v2.0.0
  with:
    poetry-version: 1.0

- name: Commit and Push(New Post)
  env:
    NOTION_TOKEN: ${{ secrets.NOTION_TOKEN }}
  run: |
    git config user.name [ユーザー名]
    git config user.email [メールアドレス]
    git checkout -b "${{ env.BRANCH_NAME }}"
    cd ./scripts/generate_data
    poetry install --no-interaction
    poetry run python main.py "${{ github.event.client_payload.url }}"
    cd ..
    cd ..
    git add .
    git commit -m "記事追加: ${{ github.event.client_payload.url }}"
    echo "POST_TITLE=""$(git show | grep 'title: ' | sed -e s/\+title:\ //g)" >> $GITHUB_ENV
    git push --set-upstream origin "${{ env.BRANCH_NAME }}"

のようにして一気に投稿の内容を取り込みからPushまで実施しています。

このタイミングで投稿タイトルを POST_TITLE としてmdファイルのFrontmatterのtitleからとってしまっているのもポイントです。

これでPull-Requestのタイトルなどに活用できます。実際、下記のようにしてPull-Requestは立てています。

- name: create PR(New Post)
  env:
    GH_TOKEN: ${{ secrets.GH_API_KEY_FOR_CREATE_ISSUE }}
  run: |
    gh pr create --base main --head "${{ env.BRANCH_NAME }}" \
    -t "記事追加: ${{ env.POST_TITLE }}" \
    -b "Notion 記事URL: ${{ github.event.client_payload.url }}"

GH_API_KEY_FOR_CREATE_ISSUE はIssue生成に使用するGitHub API Keyで、リポジトリのシークレットに登録しておきます。

こうすれば、下記のように、Pull-Reuquestのタイトルに記事タイトルがそのまま表示されるのでとてもPull-Requestの見通しが良くなる、というわけです。

file5

GitHub関連のアクションをGitHub Actionsで行う場合はこのように gh コマンドを使うことがとても有用です。

個人的には、日頃の作業でもブラウザを開かずに gh で全て済ます強い人たちに憧れますが、なかなか踏ん切りが付かない昨今です…

まとめ

いかがでしたでしょうか。

今回は実際にどういったものを活用しているかに触れたので実践的な内容になっているかと思います。ブログのレビューのみでなく様々なシーンでこのようなGitHub Actionsによるフローの自動化にトライしてみていただけると良いと思いますし、私自身積極的に活用を続けていきたいところです。

また、もっと良いベストプラクティスがあるような気もするので、そのあたりは追って探って行ければと思っています。が、少なくとも現状はこれで問題無くフローとして回っているのでとりあえずは良し、かと思っています。

5回に渡ってお届けしたTechブログ構築周りの話は今回でいったん終了です。

とはいえSlack Appの構築・Cloud Functionsの整形内容など細かいTipsとなり得る要素はあるので、そのあたりは単体の記事として出して行ければと思っています!

AUTHOR

伴 拓也

朝日放送グループホールディングス株式会社 デジタル・アーキテック局 データ戦略チーム

アプリケーションからインフラ、ネットワーク、データエンジニアリングまで幅広い守備範囲が売り。最近はデータ基盤の構築まわりに力を入れて取り組む。 主な実績として、M-1グランプリ敗者復活戦投票システムのマルチクラウド化等。

WORK@ABC

技術力を培うための
環境と文化

ABCに昔から根付く「自分たちで開発する」文化を支える環境や取り組みをご紹介します
ABCについてもっと知る