はじめに
このブログはGitHub Pagesを使用して公開している。
記事自体はorg-modeで書いたあと、Hakyllで投稿用のHTMLに変換して投稿しているが、これを毎回手動で実施するのは手間なので、GitHub Actionsで自動化することにした。
構成は以下の通り。
自動化に際し、以下2つのリポジトリを作成した。
- 記事のソースや静的サイトジェネレータを格納する
chupaaaaaaan-blog
(以下、blog-source) - GitHub Pagesで公開するための
chupaaaaaaan.github.io
(以下、pages)
blog-sourceリポジトリで記事毎にブランチを作成して下書きを執筆し、公開するタイミングで main
ブランチへのPRを作る運用にしてみた。
PRがマージされたら、記事がpagesリポジトリでビルド・公開されるようになっている。
下書きについては非公開としたいので、blog-sourceリポジトリはプライベートリポジトリにしている。
記事のビルドはどちらのリポジトリでも可能だが、プライベートリポジトリでGitHub Actionsの無料利用枠を使い切ったら悲しいので、パブリックリポジトリのpagesリポジトリで行うようにした。
フロー詳細
①blog-sourceリポジトリ: 記事ブランチを main
ブランチにマージ
前述の通り、 main
ブランチへのPRをマージするだけ。
②③blog-sourceリポジトリ: PRのマージをpagesリポジトリに通知
blog-sourceリポジトリのPRマージ完了をpagesリポジトリ側に通知し、ビルド・公開のワークフローを実行する必要がある。
通知する方法はいくつか考えられるが、今回はPRマージ時にpagesリポジトリに対して repository_dispatch
イベントを発行するワークフローを作成した。
以下のような感じになる(プライベートリポジトリのワークフローなので、URLは省略)
name: Trigger chupaaaaaaan.github.io Workflow on PR Merge
on:
pull_request:
types:
- closed
branches:
- main
jobs:
notify:
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
steps:
- name: Notify chupaaaaaaan.github.io workflow
env:
TARGET_REPO: chupaaaaaaan/chupaaaaaaan.github.io
EVENT_TYPE: pr_merged
PAT: ${{ secrets.PAT_NOTIFY_BLOG_SITE }}
run: |
curl -f -X POST \
-H "Accept: application/vnd.github.v3+json" \
-H "Authorization: Bearer ${PAT}" \
https://api.github.com/repos/${TARGET_REPO}/dispatches \ -d "{\"event_type\": \"${EVENT_TYPE}\"}"
なお、 repository_dispatch
イベントを発行するためには、適切な権限を設定したパーソナルアクセストークンが必要となるので、忘れずに作成してシークレットに登録しておく。
今回は、Fine-grained personal access tokenを作成した。
④⑤pagesリポジトリ: blog-sourceリポジトリから資材を取得し、ビルド・公開
前段で通知を受け取ったら、blog-sourceリポジトリの資材を取得し、ビルド・公開する。
ワークフローは以下の通り。
name: Update Blog Site
on:
workflow_dispatch:
repository_dispatch:
types:
- pr_merged
jobs:
build-pages:
runs-on: ubuntu-latest
steps:
- name: Checkout blog source
env:
TARGET_REPO: chupaaaaaaan/chupaaaaaaan-blog
DK: ${{ secrets.DK_CLONE_BLOG_SOURCE }}
uses: actions/checkout@v4
with:
repository: ${{ env.TARGET_REPO }}
ssh-key: ${{ env.DK }}
- name: Setup haskell environment
uses: haskell-actions/setup@v2
id: setup
with:
ghc-version: 9.6.6
cabal-version: 3.12.1
cabal-update: true
- name: Configure the build
run: |
cabal configure --enable-tests --enable-benchmarks --disable-documentation
cabal build all --dry-run
- name: Restore cached dependencies
uses: actions/cache/restore@v4
id: cache
env:
KEY: ${{ runner.os }}-ghc-${{ steps.setup.outputs.ghc-version }}-cabal-${{ steps.setup.outputs.cabal-version }}
with:
path: ${{ steps.setup.outputs.cabal-store }}
key: ${{ env.KEY }}-plan-${{ hashFiles('**/plan.json') }}
restore-keys: ${{ env.KEY }}-
- name: Install dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: cabal build all --only-dependencies
- name: Save cached dependencies
uses: actions/cache/save@v4
if: steps.cache.outputs.cache-hit != 'true'
with:
path: ${{ steps.setup.outputs.cabal-store }}
key: ${{ steps.cache.outputs.cache-primary-key }}
- name: Setup pages
id: pages
uses: actions/configure-pages@v5
- name: Build pages
run: cabal run site build
- name: Upload pages artifact
uses: actions/upload-pages-artifact@v3
deploy-pages:
needs: build-pages
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
permissions:
id-token: write
pages: write
runs-on: ubuntu-latest
steps:
- name: Deploy pages
id: deployment
uses: actions/deploy-pages@v4
blog-sourceリポジトリはプライベートリポジトリのため、資材をチェックアウトするためには適切な権限を設定したパーソナルアクセストークンか、デプロイキーが必要になる。 今回はblog-sourceリポジトリでデプロイキーを作成し、シークレットとして登録した。
資材チェックアウト以降の処理は、以下を参考にした。
GitHub ActionsからGitHub Pagesを公開するためには、カスタム GitHub Actions ワークフローによる公開に記載の通り、公開元を「GitHub Actions」に設定しておく必要がある(これをせずに、 deploy-pages
ジョブが延々謎のエラーで失敗し続けるのに悩まされた。。。)。
終わりに
実は以前もGitHub Pagesでブログを公開していたのだが、途中で面倒になって途絶えてしまった。。。(以前公開していたもの) 今回は多少やりやすいように整備したので、またモチベを上げて書いていきたい。 また、過去の記事のいくつかは、折を見てこのブログで再度公開するつもり。
今回は静的サイトジェネレータにはほとんど触れていない(ほとんど hakyll-init
で生成したものをそのまま使っている)。
過去に作った静的サイトジェネレータの機能を移植したり、他にもなにか思いついたら改良したい(今のままだと、コードハイライトすらないので・・・)。
自動化を試すにあたって、以下のウェブページを参考にさせていただきました。 Hakyllで個人ウェブページを作りましたので全体概要を紹介