GitHub Actions + microCMS + Jekyll で GitHub Pages を構築する

<!--
title: GitHub Actions + microCMS + Jekyll で GitHub Pages を構築する
tags: GithubPages GitHubActions microCMS Jekyll Ruby
author: shimizu@ferix.jp
-->

## はじめに

### 概要

GitHub PagesとmicroCMSで静的サイトを構築するための情報をまとめます。

### なぜこの構成を選んだか

#### 事前にいただいていた要件

- GitHub Pagesでホスティングする
- microCMSのHobbyプラン(無料)で新着情報を投稿して表示したい
- WebサイトのデザインとHTMLコーディングは、デザイナーが担当

#### 今回採用した技術

- Jekyll (読み方:ジキル)
  - 理由1：GitHub Pagesが使っていると[公式ドキュメント](https://docs.github.com/ja/pages/setting-up-a-github-pages-site-with-jekyll/about-github-pages-and-jekyll)に書いてあったため
  - 理由2：実装中のHTMLの既存構成を大きく変える必要がなく、連携が容易そうなため
- GitHub Actions
  - 理由：microCMSでのコンテンツ更新をトリガーに、自動でWebサイトをビルド＆公開するため

#### 対象読者

- GitHubリポジトリのAdmin権限がある
- GitHub Pagesのホスティングができる
- 非エンジニアでも可
- Mac M1以上、[Homebrew](https://brew.sh/ja/)インストール済
:::note warn
which brewが以下じゃない場合は、arm64版に更新が必要です。
更新方法の参考URL: [Intel Homebrewと決別した \- kokh log](https://tech.ymkokh.com/entry/2024/06/14/011703)
以下になっていたら準備OKです。
```bash
$ which brew
/opt/homebrew/bin/brew
```
:::

本記事は弊社のデザイナーへの情報共有を目的に作成しました。

## 構成図

```mermaid
graph TB
    subgraph GitHubリポジトリ
        B("HTML(Liquid), Ruby")
    end

    C(microCMS) --API--> F(JSON)
    B --> F

    subgraph "GitHub Actions"
        D{Jekyll} --> E(HTML)
        F --> D
    end
    
    E --> G(GitHub Pages)
    G <--URLから画像取得--> C

    H(["fa:fa-user 実装者"]) -.git push.-> B;
    I(["fa:fa-user コンテンツ管理者"]) -.追加・更新・削除.-> C;
    J(["fa:fa-user 訪問者"]) -.-> G;

    style C fill:#ccf,stroke:#333,stroke-width:2px
    style G fill:#f9f,stroke:#333,stroke-width:2px
```

## 構築手順

### 1. Jekyllのインストール

#### 1. 必要なツールをインストール
Jekyll のローカル動作確認のために、 Ruby と Bundler をインストールします。
Rubyのインストール方法やバージョンは[Jekyll公式](https://jekyllrb.com/docs/installation/macos/)を参考にしました。

```bash:Ruby, Bundlerインストール
# Homebrew を使用して chruby と ruby-install をインストール
brew install chruby ruby-install

# Ruby をインストール
ruby-install ruby 3.4.1

# シェルの設定を更新
echo 'source /opt/homebrew/opt/chruby/share/chruby/chruby.sh' >> ~/.zshrc
echo 'source /opt/homebrew/opt/chruby/share/chruby/auto.sh' >> ~/.zshrc
echo "chruby ruby-3.4.1" >> ~/.zshrc # run 'chruby' to see actual version
source ~/.zshrc

# Ruby のバージョンを確認
ruby -v # ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [arm64-darwin24]

# Bundler をインストール
gem install bundler
```

#### 2. Jekyllインストール、サイト作成

リポジトリルートで以下のコマンドを実行します。
Jekyllをインストールし、Jekyllサイトを新規に作成します。

```bash
# Jekyll をインストール
bundle add jekyll

# リポジトリのルート ディレクトリで jekyll new コマンドを使用する
`bundle exec jekyll new `--skip-bundle .
```

:::note
`jekyll new`は、ディレクトリが空でないとコンフリクトを起こすので、すでにファイルがある場合は`--force`をつけます。
`--force`で実行しても以下のファイルが追加されるだけで、既存ファイルに影響は出ませんでした。
:::

```bash:jekyll new 実行後に追加されるファイル
.
├── _posts # 不要
│   └── 2025-02-18-welcome-to-jekyll.markdown # 不要
├── _config.yml
├── .gitignore
├── 404.html
├── about.markdown # 不要
├── Gemfile
└── index.markdown # 不要
```

今回はHTMLでホスティングするので、不必要なmarkdownファイルを削除します。

```bash:不要ファイル削除後
.
├── _config.yml
├── .gitignore
├── 404.html
└── Gemfile
```

#### 3. 設定ファイル変更

以下のGitHub公式ドキュメントを参照しながら、設定ファイルに変更を加えます。

https://docs.github.com/ja/pages/setting-up-a-github-pages-site-with-jekyll/creating-a-github-pages-site-with-jekyll#creating-your-site

.gitignoreにGemfile.lockを追加します
```text:.gitignore
_site
.sass-cache
.jekyll-cache
.jekyll-metadata
vendor
Gemfile.lock # 追加
```

Gemfileを開きます。
jekyllをコメントアウトして、github-pagesをアンコメントします。
公式ドキュメントに記載の通りに、[Dependency versions \| GitHub Pages](https://pages.github.com/versions/)に載っているバージョンを追記します。
```ruby:Gemfile
# Happy Jekylling!
# gem "jekyll", "~> 4.4.1" # ←コメントアウトする
# This is the default theme for new Jekyll sites. You may change this to anything you like.
gem "minima", "~> 2.5"
# If you want to use GitHub Pages, remove the "gem "jekyll"" above and
# uncomment the line below. To upgrade, run `bundle update github-pages`.
gem "github-pages", "~> 232", group: :jekyll_plugins # アンコメントしてバージョン追記
```

_config.ymlは必要に応じて修正してください。
README.mdを使用する場合は、GitHub Pagesのビルド対象にならないようにexcludeします。
```yml:_config.yml
exclude: # 初期はコメントアウトされているので、アンコメント
  - .sass-cache/
  - .jekyll-cache/
  - gemfiles/
  - Gemfile
  - Gemfile.lock
  - node_modules/
  - vendor/bundle/
  - vendor/cache/
  - vendor/gems/
  - vendor/ruby/
  - README.md # 追加
```

### 2. GitHub Pagesの準備

1で用意したJekyllのサイトに、HTMLコンテンツやCSSを用意します。
```bash:HTMLコンテンツ用意後のディレクトリ構成
.
├── css # 追加
│   └── style.css # 追加
├── _config.yml
├── .gitignore
├── 404.html
├── Gemfile
├── favicon.ico # 追加
├── icon.svg # 追加
└── index.html # 追加
```

:::note
HTMLコンテンツが先にリポジトリに用意されている場合は、2→1の順で作業しても良いです。
その場合は、[2. Jekyllインストール、サイト作成](#2-jekyllインストールサイト作成)のノートにある通り、`jekyll new`実施時に`--force`オプションをつけてください。
:::

### 3. microCMSの準備

公式ドキュメントを参照しながら、microCMSを用意します。

https://blog.microcms.io/getting-started/

ドキュメント通りにリスト形式で進め、**APIプレビューの確認**まで行います。

### 4. microCMSコンテンツのHTML表示をローカルでテストする

microCMSと連携する前に、ローカルでテストします。

#### 1. `_data/`ディレクトリとJSONファイル作成

今回は新着情報の表示なので`_data/news.json`というファイルを作成します。
JSONファイルの中身は、このあとGitHub ActionsでmicroCMSのコンテンツを取得して更新する設定を行いますが、あらかじめファイル自体は作成しておいてください。
ここでは、[3. microCMSの準備](#3-microcmsの準備) のAPIプレビューの確認で取得したレスポンスを入れておきます。

```json:_data/news.json の例
{
  "contents":[
    {
      "id": "63hr77w-d29",
      "createdAt": "2024-09-23T03:05:36.143Z",
      "updatedAt": "2024-09-23T03:05:36.143Z",
      "publishedAt": "2024-09-23T03:05:36.143Z",
      "revisedAt": "2024-09-23T03:05:36.143Z",
      "title": "次のお知らせです",
      "contents": "お知らせ記事の本文です。"
    },
    {
      "id": "63hr77w-d28",
      "createdAt": "2024-09-23T03:05:36.143Z",
      "updatedAt": "2024-09-23T03:05:36.143Z",
      "publishedAt": "2024-09-23T03:05:36.143Z",
      "revisedAt": "2024-09-23T03:05:36.143Z",
      "title": "最初のお知らせです",
      "contents": "お知らせ記事の本文です。"
    }
  ]
}
```

#### 2. HTMLからJSONの内容を参照する



Jekyllでは`_data/news.json`の内容を、HTMLから`{{site.data.news}}`という形で取得できます。
[Liquid](https://jekyllrb-ja.github.io/docs/liquid/)というテンプレート言語です。
```liquid
{{ site.data.news | jsonify }}
```
とindex.htmlなどのHTMLに書くと、jsonの中身がそのまま表示されます。

JSONを参照するHTMLファイルの1行目に以下を追加すると、Jekyllのビルド時にLiquidで書いた内容を認識してくれます。
```html:index.html
---
# front matter tells Jekyll to process Liquid
---
```


#### 3. Jekyll を起動する

以下のコマンドでローカルサーバーを起動します。
```bash
bundle exec jekyll serve --baseurl=""
```

ブラウザで `http://localhost:4000` にアクセスしてください。
`{{ site.data.news | jsonify }}`と書いた場所が、JSONファイルの中身で表示されていたら成功です🎉

あとはデザインに合わせてLiquidで内容を記載してください。
Jekyllは静的サイトジェネレータのため、HTML等の変更後は、ブラウザでの更新操作が必要です。

Jekyllにはテンプレート機能もありますが、ここでは説明を省略します。

### 4. microCMSのコンテンツを取得するRubyスクリプト実装

`_pulgins/microcms.rb`を作成して、以下のように記載します。
`MICROCMS_API_KEY`は機密情報のため、Git管理はせず、GitHubリポジトリのSecretsに登録して参照します。

```ruby:microcms.rb
require 'json'
require 'open-uri'

begin
  # 環境変数取得
  api_key = ENV.fetch('MICROCMS_API_KEY', nil)
  raise '!!! ERROR: MICROCMS_API_KEY is not set in .env' if api_key.nil? || api_key.empty?

  # ニュースを取得
  # デフォルトのリミット(取得コンテンツ件数)は10なので、この例では最大値の100を設定しています。
  response = URI.open('{APIプレビューにあった microCMSのGET APIのURL}?limit=100', 'X-MICROCMS-API-KEY' => api_key).read
  news_data = JSON.parse(response)
  File.write('_data/news.json', JSON.pretty_generate(news_data))
rescue StandardError => e
  puts "!!! MicroCMS Plugin Error: #{e.message}"
  puts e.backtrace
  exit 1
end
```

:::note warn
GitHub Pagesが使用しているJekyllのバージョンやセキュリティ設定では、`_plugins`の下を認識しないなどの制限がかかっています。
なので、このあとの設定で、GitHub Actions経由で上記Rubyスクリプトを呼び出します。
:::

### 5. GitHub Actionsで自動化

#### 1. ワークフローファイルを用意

`.github/workflows/build.yml`を作成します。

```yml:.github/workflows/build.yml
name: Deploy Jekyll Site

on:
  push:
    branches:
      - main  # mainブランチにプッシュされたときに実行

  repository_dispatch:
    types: [microcms-update]  # microCMS の Webhook のトリガーイベント名

  workflow_dispatch: # 手動実行も可能

jobs:
  build:
    environment: github-pages
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup Ruby & Bundler
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: '3.4.1'
          bundler-cache: true

      - name: Install dependencies
        run: bundle install

      - name: Fetch microCMS data
        run: bundle exec ruby ./_plugins/microcms.rb  # microCMSからデータ取得
        env:
          MICROCMS_API_KEY: ${{ secrets.MICROCMS_API_KEY }}

      - name: Build Jekyll site
        run: bundle exec jekyll build

      - name: Upload static files as artifact
        uses: actions/upload-pages-artifact@v3
        with:
          path: ./_site # Jekyllの出力ディレクトリ

  deploy:
    runs-on: ubuntu-latest
    
    needs: build
    
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    
    permissions:
      pages: write
      id-token: write

    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4
```

#### 2. microCMS Webhook設定

microCMSでの記事の更新をGitHub Pagesに反映させるために、Webhookを設定します。
詳細は以下の記事を参照してください。

https://help.microcms.io/ja/knowledge/webhook-github-actions-settings

mircoCMSから更新するコンテンツ(API)が複数ある場合は、すべてのコンテンツ(API)でWebhook設定を行なってください。

##### 手順：

1. GitHubでトークンを作成します。Tokens（classic）での手順を記載します。
    1. GitHubのユーザー設定ページ（ https://github.com/settings/profile ）にアクセスします。
    2. ユーザー設定ページにて、左カラムの最下部にある「Developer settings」（ https://github.com/settings/apps ）にアクセスします。
    3. 左カラムから「Personal access tokens」のメニューを押下し、Tokens（classic）を押下します。
    4. トークン一覧画面にて「Generate new token」ボタンを押下します。
    5. 「New personal access token（classic）」の画面で、以下の情報を入力します。
        - Note（必須）: 任意の説明を入力してください。
        - Expiration（必須）: 任意の有効期限を選択してください。
            - 有効期限が切れると、再度トークンを作成し、microCMSのWebhook設定を更新する必要があります。
            - 有効期限なしも設定可能ですが、セキュリティ的には推奨されていません。
    6. 次に、「Select scopes」セクションへ進み、「repo」にチェックをいれます。
    7. ページ下部の「Generate token」ボタンを押下します。
    8. トークンの一覧画面に戻り、作成したばかりのトークンが表示されているので、コピーして保存しておきます。トークンの作成はここで終了です。
        - トークンはあとから再表示できません。忘れた場合は、再度作成が必要です。
2. **microCMS**にログインし、コンテンツが含まれている「サービス」を開きます。
3. 左側のメニューからコンテンツ（API）を選択し、右側の(歯車のマーク)API設定を選択します。
4. 左側のメニューから「Webhooks」を選択し、GitHub Actions Webhookが既に作成されているので選択すると、設定が開きます。
5. 以下の情報を本番環境用GitHubリポジトリの内容に変更します:
   - **GitHubトークンを設定してください。**: 手順2.で取得したトークンを貼ります。
   - **リポジトリのユーザー名を入力してください。通常、`https://github.com/:user/:repo` の :user 部分です。**: 本番環境用GitHubリポジトリURLの`:user`部分を入力してください
   - **リポジトリ名を入力してください。通常、`https://github.com/:user/:repo`の :repo 部分です。**: 同様に、URLの`:repo`部分を入力してください
6. トリガーイベント名はワークフローファイルに設定した内容（repository_dispatchのtypes）を入力します。
7. 「通知タイミングの設定」セクションにて、任意の通知タイミングを選択してください。設定した通知タイミングでGitHub Pagesが更新されます。
8. 設定を保存します。

#### 3. GitHub ActionsのSecretsにmicroCMS APIキーを設定

microCMSのAPIキーをGitHubのSecretsに保存し、GitHub Actionsから利用できるようにします。
詳細は以下の記事を参照してください。

https://docs.github.com/ja/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions#creating-secrets-for-an-environment

https://document.microcms.io/content-api/x-microcms-api-key

##### 手順：
1. microCMSのAPIキーを取得します。
    1. **microCMS**にログインし、コンテンツが含まれている「サービス」を開きます。
    2. 左側のメニューから「権限管理」> 「1個のAPIキー」を選択します。
    3. APIキーの一部が表示されているので、横のコピーマーク（紙が2枚重なっているマーク）をクリックしてコピーします。
2. GitHubにログインし、本番環境用GitHubリポジトリにアクセスします。
3. GitHubリポジトリのトップページで、「Settings」を選択します。
4. 左側のメニューで「Security」セクションの「Secrets and variables」をクリックし、「Actions」を選択します。
5. 「Secret」 タブが選択されていることを確認します。
6. 「Manage environment secrets」を選択します。
7. 「github-pages」の環境を選択します。なければ「New environment」から作成してください。
8.  「Environment secrets」セクションで「Add environment secret」を選択して、以下の情報を入力します:
     - **Name**: `MICROCMS_API_KEY`
     - **Value**: 手順1. でコピーしたmicroCMSのAPIキー
9.  設定を保存します。

#### 4. ワークフローを実行

ワークフローファイルをGitHubのリモートにプッシュして、mainブランチを更新します。
`Deploy Jekyll Site`が実行されるので、成功するのを見守りましょう。
成功したら、GitHub Pagesのホスティング内容を確認してください。

#### 5. GitHub Pages サイトの公開元を GitHub Actions ワークフローに変更する

GitHub Pagesの更新が、microCMSで記事が更新されたときに動作するGitHub Actionsと連動するように変更します。
詳細は以下の記事を参照してください。

https://docs.github.com/ja/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site#%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0-github-actions-%E3%83%AF%E3%83%BC%E3%82%AF%E3%83%95%E3%83%AD%E3%83%BC%E3%81%AB%E3%82%88%E3%82%8B%E5%85%AC%E9%96%8B

##### 手順：
1. GitHubにログインし、GitHubリポジトリにアクセスします。
2. GitHubリポジトリのトップページで、「Settings」を選択します。
3. 左側のメニューで「Code and automation」セクションから「Pages」を選択します。
4. 「Build and deployment」セクションの「Source」を「GitHub Actions」に変更します。

:::note
上記リンク内で
> GitHub Pages では、特定のワークフローを GitHub Pages 設定に関連付けません。 ただし、GitHub Pages 設定は、最近サイトをデプロイしたワークフロー実行にリンクされます。

とある通り、GitHub Pagesへのデプロイが成功したワークフローを自動的に紐づけてくれます。
:::

#### 6. 最終確認

1. microCMSで記事を追加・更新・削除して、Webhooksを動作させます。
2. GitHub Actionsがトリガーされ、変更がGitHub Pagesに反映されていることを確認します。

最終確認までできたら完了です！
お疲れ様でした🎉

## 注意点

- 画像は、都度microCMSサーバー上のURLにアクセスする形になります。
- microCMSの無料プランのデータ転送量制限は、主に上記アクセス毎の画像サイズの転送量に拠ります。

https://help.microcms.io/ja/knowledge/estimate-data-amount

- GitHub Freeアカウントは、GitHub Pagesはパブリックリポジトリでないと公開できません。また、プライベートリポジトリでも、GitHub Enterprise Cloud以外のアカウントでは、GitHub Pagesはパブリック公開されます。

https://docs.github.com/ja/pages/getting-started-with-github-pages/about-github-pages

- microCMSでは、管理画面では日本時間表記ですが、APIのレスポンスではUTC表記になっています。`_config.yml`の`timezone:`は`_data`の内容表示には影響を与えないので、日本時間で表示するにはLiquidで+9hします。

```liquid:例：アメリカ式日付表記
{{ item.date | date: "%s" | plus: 32400 | date: "%B %d, %Y" }}
```

## まとめ

長くなりましたが、GitHub PagesとmicroCMSの連携の、テンプレートパターンのひとつとして参考にしてください。

## 参考資料

- 記事中のURL
- [これだけで「静的サイトジェネレーター」のすべてがわかります ｜ monotein](https://monotein.com/blog/what-is-ssg)
- [ポートフォリオっぽいサイトをGitHub Pages \+ Jekyll構成に移行した話 \- Mikimemo](https://mikimemo.hateblo.jp/entry/2022/02/28/232101)
- [GitHub ActionsへのWebhook通知に対応しました \| microCMSブログ](https://blog.microcms.io/webhook-for-github-actions/)
- [新しいGitHub Pagesのデプロイ方法を試す](https://zenn.dev/zozotech/articles/f2509a21b768ed)
- [Timezone in config is not used as timezone in post date · Issue \#4778 · jekyll/jekyll](https://github.com/jekyll/jekyll/issues/4778)