GitHub ActionsでHugoのビルドを自動化する
概要
Hugoで作ったブログをGitHub Pagesで公開するときに、HugoのビルドをGitHub Actionsで行うことでビルドを自動化します。
GitHubのリポジトリはHugoのソース用のリポジトリと、Hugoのビルドの生成物のリポジトリの二つ作っている場合を考えます。前者は下の構成図でsuzuna/blog-source、後者はsuzuna/blogにあたります。
このとき、前者にgit push
すると、Hugoでビルドし、生成物を後者にpushするようなGitHub Actionsを前者のリポジトリで動かすということです。
Hugoのビルド自動化×リポジトリ分割のメリット
HugoのビルドをGitHub Actionsで自動化するメリットは、主に二つあると思います。
記事を書き上げてGitHub Pagesで公開する前に、ローカルPCでHugoのビルドのコマンドを実行する必要がないのが一つです。hugo
でビルドするのを忘れてpushすることがよくあるんですよね。
また、Hugoのビルド環境が統一されるのがもう一つのメリットです。複数のPCで記事を書くような場合でも環境の差異に悩むことがなくなりますし、Markdownが書ければよいのでHugoを入れていない端末でも記事を書けます。
次にHugoのソースと生成物を別々のリポジトリに分割することで、ソースと生成物が同じリポジトリに混ざらないためGit上で差分が見やすくなります。記事やHugoのThemeのテンプレートを編集するときなどに、ソースとビルドの生成物の差分が混ざらないメリットをよく実感できます。このリポジトリ分割は一般的な方法なのか分かりませんが(ググるとちらほら出てきます)、Git管理上快適だと感じています。
GitHub Actionsのトークンの作成
ここから実際の方法を説明します。
GitHub Actionsを実行するリポジトリから別のリポジトリにpushし、pushしたリポジトリでGitHub Pagesとして公開するGitHub Actionとして、peaceiris/actions-gh-pagesを用います。
このGitHub Actionsは、同一のリポジトリにpushしてGitHub Pagesとして公開することもできます。GitHubのReadmeにある通り、この場合は特段GitHubのトークンは必要ではないのですが、今回のように別のリポジトリにpushする際はGitHubのトークンを渡す必要があります。
そのため、最初にssh鍵であるdeploy_key
か、Personal Access Tokenであるpersonal_token
のどちらかを用意する必要があります。以下のどちらかを行ってください。
トークンの作成(deploy_key)
ssh鍵を作ります。GitHubにssh接続する際にも作るやつですね。GitHubの公式ドキュメントの通りなのですが、簡単に説明します。
まずGit Bashで以下を実行します。
ssh-keygen -t ed25519 -C "<GitHubに登録したメールアドレス>"
これを実行すると、以下の3項目を入力するようメッセージが出ますので、順に入力します。
- “Enter file in which to save the key”: ssh鍵に付けるファイル名を入力します。
- “Enter passphrase (empty for no passphrase)” 鍵のパスフレーズです。emptyでいいので何も入力せずEnterを押します。
- “Enter same passphrase again”: 上と同じ値を入力します。こちらも同じく何も入力せずEnterを入力します。
1個目で何も入力しなければ、id_ed25519
(秘密鍵)とid_ed25519.pub
(公開鍵)の2つの鍵が生成されています。
そうしたら、ソース管理用のGitHubリポジトリ(構成図のsuzuna/blog-source)をブラウザで開き、Settings > Secrets > Actions > New repository secretを開きます。NameとValueを入力する欄があります。NameはGitHub Actions上で参照するSecretの名前です。任意の文字列でよいですが、ここではACTIONS_DEPLOY_KEY
とします。Valueは秘密鍵の中身を貼り付けます。後者はid_ed25519
をテキストエディタで開いて中身を全部コピーして貼り付ければOKです。
次に、Hugoの生成物のリポジトリ(構成図のsuzuna/blog)をブラウザで開き、Settings > Deploy keys > Add deploy keyを開きます。Titleは任意の名前を設定します。Keyは公開鍵の中身を貼り付けます。最後にAllow write access
にチェックを入れます。
トークンの作成(personal_token)
GitHubをブラウザで開き、Account SettingsのSettings > Developer settings > Personal access tokens > Generate new tokenを開きます。Personal Access TokenのScopeとしてrepo
とworkflow
にチェックを入れます。Tokenが表示されるので控えておきます。
そうしたら、deploy_keyの場合と同様に、ソース管理用のGitHubリポジトリのrepository secretを開き、Nameには任意の名前(ここではPERSONAL_TOKEN
とします)、Valueには先程のTokenを入力します。
GitHub Actionsの作成
次に、GitHub Actionsのymlファイルを作成します。
deploy_key
を用いる場合は、下記をソース管理用のリポジトリに".github/workflows/<任意のファイル名>.yml"で保存してcommitします。on
に記載の通り、masterにpushするとGitHub Actionsが実行されます。
name: github-pages
on:
push:
branches:
- master
jobs:
deploy:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
with:
submodules: true # Fetch Hugo themes (true OR recursive)
fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod
- name: Setup Hugo
uses: peaceiris/actions-hugo@v2
with:
hugo-version: 'latest'
# extended: true # if use extended version
- name: Build
run: hugo
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
deploy_key: ${{ secrets.ACTIONS_DEPLOY_KEY }}
external_repository: <name>/<repository>
publish_dir: ./docs
publish_branch: master
timeout-minutes
を設定しておくと、何らかの理由でビルドに失敗した場合でもGitHub Actionsのquotaを大量に消費せずに済みます。- peaceiris/actions-gh-pagesのパラメータは以下の通り指定します。
external_repository
: Hugoのビルドの生成物をpushするリポジトリ(最初の構成図ではsuzuna/blog)publish_dir
:external_repository
にpushするディレクトリ- HugoのThemeのconfig.ymlの
publishDir
にします
- HugoのThemeのconfig.ymlの
publish_branch
:external_repository
のpushするブランチ
なお、personal_token
を用いる場合は、こちらを
deploy_key: ${{ secrets.ACTIONS_DEPLOY_KEY }}
以下に変更します。
personal_token: ${{ secrets.PERSONAL_TOKEN }}
以上、GitHub Actionsとリポジトリ分割で快適なHugo環境を作れました!
独自ドメイン対応
GitHub Pagesに独自ドメインを使っている場合は、以下のどちらかを行います。
- ソース管理用のリポジトリにおいて、staticフォルダ内にCNAMEファイルを置く
- 以下のように、ソース管理用のリポジトリの".github/workflows/main.yml"において、peaceiris/actions-gh-pages@v3のwith内にcnameを指定する
- peaceiris/actions-gh-pagesのREADME.mdの"Add CNAME file cname"を参照
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
deploy_key: ${{ secrets.ACTIONS_DEPLOY_KEY }}
external_repository: <name>/<repository>
publish_dir: ./docs
publish_branch: master
cname: <customdomain>