ヘッドレスCMSのContentfulをHugoと連携してGithub Pagesで公開する(5)


概要

ContentfulとHugoを連携したコンテンツ作成の最終回。
ラストの今回はContentfulでのデータ更新をイベントトリガーとしてGithub Actionsを発火させる方法について解説する。

最終的には以下のような構成となる。

注目してほしいのはワークフローのピンクのブロックで、投稿者がブログを更新したら自動的に公開されるということ。
つまり途中のゴチャゴチャした過程は意識しなくてよい。

最終的なソース → higebobo/hugo-contentful-blog: Blog sample with Hugo and Contentful
完成したブログ → Hugo Contentful Blog

準備

既に説明してあるのでContentfulのトークンは取得済みとする(メニューからSettings>API Keys>Add API keyを実行)。

Githubのトークン取得

GithubのAPIを利用するためにはPersoanl access tokensと呼ばれるトークンが必要になる。
ダッシュボード画面右上のDevelopper settings>Persoanl access tokens>Generate new tokenを順次クリック。

名前は適当につけてExpirationは無期限設定のNo expirationとし(もちろん期限付きで設定してもよい)、Select scopesはとりあえずrepoをチェック。

最後にGenerate tokenをクリックすると発行される。二度とお目にかかれないと警告が出ているのでコピーしておくこと。
もし忘れたら再発行するしかない。

ちなみにこのトークンはレポジトリではなくアカウントに紐付いているので既に発行済で別レポジトリで使用しているトークンがあればそちらをつかってもよい。

確認

curlが実行できる環境ならこの時点で設定確認ができる。

curl -X POST \
-H "Accept: application/vnd.github.everest-preview+json" \
-H "Authorization: token <取得したトークン>" \
-d '{"event_type": "Wehook test"}' \
https://api.github.com/repos/<アカウント名>/<レポジトリ名>/dispatches

これを実行して何も返ってこなければ成功。とやや紛らわしい。
なので上記に-iオプションをつけてみるとヘッダ情報が取得できる。

HTTP/2 204 
server: GitHub.com
...

204を返せばOK。
ちなみに例えばわざと間違ったトークンを渡すとこんなエラーが返ってくる。

{
  "message": "Bad credentials",
  "documentation_url": "https://docs.github.com/rest"
}

ContentfulのWebhook設定

次にコンテンツ更新をGithubにお知らせするためWebhookをContentfulに設定する。
ダッシュボード上部メニューのSettings>Webhook>Add Webhookをクリック。
そして設定を行う。
基本的には上記curlでの確認テストの項目を渡すように設定してやれば良い。

まずNameは適当でURLhttps://api.github.com/repos/<アカウント名>/<レポジトリ名>/dispatchesとする。
Nameはなんでもよいがわかりやすくしたほうがよいので私の場合は<アカウント名>/<レポジトリ名>としている。

TriggersSelect specific triggering eventsにチェック。
CONTENT EVENTSは下図参照。ここまでの設定はこんな感じ。

画面をスクロールしてHeadersのセクションまで行く。
ここでAdd custom headerをクリックしてヘッダーを追加する。ただしトークンのようにセキュリティ関連の情報は非表示にしたいのでその場合はAdd secret headerを使う。
設定するヘッダは以下

  • Accept: application/vnd.github.everest-preview+json
  • User-Agent: Contentful Webhook (値は適当でよい)
  • Authorization: token <上記で取得したGithubのPersonal access tokens>

Authorizationの値は先頭にtokenを加えるのを忘れないように。
例えばトークンの値がabcだったらtoken abcとすること。

更にスクロールしてPayloadまで行く。
GithubのAPIを叩くためにはリクエストボディにevent_typeという値が必要となる。
なのでCustomize the webhook payloadを選択し以下のように適当に値を設定する。

最後にSaveをクリックして完了。
このまま適当にコンテンツを更新してWebhookの起動を試してもよいが、受け側のGithubの設定ができていないのでそれを次に行う。

Github Actionsの設定変更

Github Actionsはrepository_dispatch:を追加するだけである。

.github/workflows/gh-pages.yaml(全文)

name: GitHub Pages

on:
  push:
    branches:
      - main
  repository_dispatch: # ここ

jobs:
  deploy:
    runs-on: ubuntu-latest
    concurrency:
      group: ${{ github.workflow }}-${{ github.ref }}

    steps:
      - uses: actions/checkout@v2
        with:
          submodules: true
          fetch-depth: 0
      - name: Setup Node.js
        uses: actions/setup-node@v1
        with:
          node-version: 14.x
      - run: npm ci

      - name: Setup Hugo
        uses: peaceiris/actions-hugo@v2
        with:
          hugo-version: 'latest'
          extended: true

      - name: Build
        # run: npm run build
        run: ./node_modules/.bin/contentful-hugo && hugo --minify --baseUrl="https://higebobo.github.io/hugo-contentful-blog/"
        env:
          CONTENTFUL_SPACE: ${{ secrets.CONTENTFUL_SPACE }}
          CONTENTFUL_TOKEN: ${{ secrets.CONTENTFUL_TOKEN }}

      - name: Deploy
        uses: peaceiris/actions-gh-pages@v3
        if: ${{ github.ref == 'refs/heads/main' }}
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./public

上記修正を加えてレポジトリにプッシュすればブログのコンテンツは再ビルドされるが、これはワークフローでいうところの開発者のフローである。

Contentfulに投稿して動作確認する。

実際にContentfulでのコンテンツ更新でビルドプロセスが走るか試してみる。
今現在は2つの投稿しか無い。

新規投稿をしてみる。

書き終わったらPublish状態にする。

Contenful側の確認

ダッシュボード>Settings>Webhooksをクリック。

こんなふうになっていたら成功。念の為view detailsで下っていくと最終的なリクエストとレスポンスのログが確認できる。

Github側の確認

ダッシュボード>Actionsをクリック。

最下行のaccespt webhook(タイポでスマソ)がレポジトリのmainブランチにプッシュしたときのコミットログ。
その上にあるWebhook from ContentfulがContenful側からのWebhook。
上記payloadのevent_typeで設定した値が表示される。
3つあるのはコンテンツ作成時にブログ本文と画像とタグを新規登録したからそのたびにWebhookが走っている。

そして

はい。できました。

まとめ

五回に分けてHugoとContenfulの連携およびGithub Pagesでの自動公開を説明した。
スタティックサイトジェネレータとしてHugoに魅了されたのだが、その仕様ゆえヘッドレスCMSとの連携が難しいのを歯がゆく思っていた。
しかし、工夫次第でなんとでもなることを示すことができた。
仕様が固まりソース自体の変更が無い状態になれば、ContentfulとGithub間だけのサービスに完結する完全なサーバレス環境となる。
つまり、極端に言えばローカル環境にHugoやNode.jsは不要になるのだ。

最終的なソース → higebobo/hugo-contentful-blog: Blog sample with Hugo and Contentful
完成したブログ → Hugo Contentful Blog

謝辞

Hugoの開発チーム、GithubやContenfulの運営者は当然ながら、このすばらしいライブラリを提供してくれたModiiMediaさん、またHugoのGithub Actionsを作成していただいたpeaceirisさん(いつもLGTMありがとうございます)に多大なる感謝を申し上げます。
これを機に少しでもHugoユーザが増えれば幸いです。