GitHub ActionsでGitHub Pagesへポートフォリオサイトを自動デプロイ


# はじめに

以前に[自分のポートフォリオサイトをHugoでGitHub Pagesへサクッとデプロイ](https://qiita.com/momotaro98/items/cf34ea6ae21d74f1f961)という記事を書きました。

この記事の中では[GitHub Pages](https://help.github.com/en/github/working-with-github-pages/about-github-pages)へのデプロイはローカルのMacからデプロイ用のスクリプトを走らせることでやっていましたがGitHub Actionsでできた方がイケてる！ということでやってみました。
やってみたところなかなかハマったので共有します。

GitHub Pagesには[こんなサイト](https://momotaro98.github.io/)があがっています。

# 前提

* 静的サイトジェネレータに[Hugo](https://gohugo.io/)を使います。
* Hugo公式にある[Host on GitHub | GitHub User or Organization Pages](https://gohugo.io/hosting-and-deployment/hosting-on-github/#github-user-or-organization-pages)にてInstructionがある、HugoのレポジトリにGitHub Pages(github.io)のレポジトリをgit submoduleとして組み込んで使っていくやり方に則っています。

サイトジェネレータ(Hugo)用レポジトリ リンク https://github.com/momotaro98/hugo-bio
GitHub Pagesレポジトリ リンク https://github.com/momotaro98/momotaro98.github.io

# Main Contents

## Workflowファイルとデプロイ用スクリプト

```yaml:.github/workflows.main.yml
on:
  push:
    branches:
      - master

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - name: Fix up git URLs # ポイント3 submoduleの扱い
        run: echo -e '[url "https://github.com/"]\n  insteadOf = "git@github.com:"' >> ~/.gitconfig

      - uses: actions/checkout@v1
        with:
          submodules: true # ポイント3 submoduleの扱い

      - name: Read environment variables # ポイント1 Hugoのビルドと環境変数の受け渡し
        id: env
        run: |
          . ./.env
          echo "::set-output name=HUGO_VERSION::${HUGO_VERSION}"
          echo "::set-output name=THEME_NAME::${THEME_NAME}"

      - name: Setup Hugo # ポイント1 Hugoのビルドと環境変数の受け渡し
        uses: peaceiris/actions-hugo@v2
        with:
          hugo-version: '${{ steps.env.outputs.HUGO_VERSION }}'

      - name: Build
        run: hugo -t '${{ steps.env.outputs.THEME_NAME }}'

      - name: Deploy the artifact onto hosting service
        env: # ポイント2 Secretsの扱い
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
          EMAIL_ADDRESS: ${{ secrets.EMAIL_ADDRESS }}
        run: ./deploy.sh
```

```bash:deploy.sh
#!/bin/bash

set -eu

echo 'Deploying updates to GitHub...'

user_name="momotaro98"

echo 'Set Git configurations'
git config --global user.name $user_name
git config --global user.email ${EMAIL_ADDRESS}

echo 'Start deploying onto hosting service'

cd public # ポイント3 submoduleの扱い

# Check if there's change in the generated artifact
if [[ ! `git status --porcelain` ]]; then
  echo 'No change in artifact then finishing this deploying workflow'
  exit 0
fi

# ポイント2 Secretsの扱い
git remote set-url origin https://$user_name:${DEPLOY_TOKEN}@github.com/$user_name/$user_name.github.io.git
git checkout master
git add .

msg="rebuilding site `date`"
if [ $# -eq 1 ]
  then msg="$1"
fi
git commit -m "$msg"

git push origin HEAD

echo 'Deploy done'

echo 'Start doing git commit to master itself'

cd ..
# ポイント2 Secretsの扱い
git remote set-url origin https://$user_name:${GITHUB_TOKEN}@github.com/$user_name/hugo-bio.git
git checkout master
git add public
git commit -m "Deploy public `date`"
git push origin HEAD

echo 'Git commit done'
```

## ポイント1 Hugoのビルドと環境変数の受け渡し

サイトをビルドするにはGitHub ActionsのランナーにHugoをインストールしてあげる必要があります。
今回 @peaceiris さんが作成したActionモジュールを利用しました。

https://github.com/peaceiris/actions-hugo

また、レポジトリページのREADMEのTipsをそのまま拝借しました。

```..env
HUGO_VERSION=0.59.1
THEME_NAME=resume
```

```..github/workflows/main.ymlの一部
# 環境変数をファイルから読み込み設定
. ./.env
echo "::set-output name=HUGO_VERSION::${HUGO_VERSION}"
echo "::set-output name=THEME_NAME::${THEME_NAME}"
.
.
# 設定された環境変数を取得
hugo-version: '${{ steps.env.outputs.HUGO_VERSION }}'
```

このようにすることで環境変数をStep間で受け渡すことができます。

## ポイント2 Secretsの扱い

```..github/workflows/main.ymlの一部
- name: Deploy the artifact onto hosting service
  env:
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
    EMAIL_ADDRESS: ${{ secrets.EMAIL_ADDRESS }}
```

今回、3つの[シークレット](https://help.github.com/ja/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets)の値を使っています。

1つ目の`secrets.GITHUB_TOKEN`が特別です。

From [公式ドキュメント](https://help.github.com/ja/actions/automating-your-workflow-with-github-actions/authenticating-with-the-github_token)

> GitHubは、ワークフローで利用するGITHUB_TOKENシークレットを自動的に生成します。 このGITHUB_TOKENは、ワークフローの実行内での認証に利用できます。
GitHub Actionsを有効化すると、GitHubはリポジトリにGitHub Appをインストールします。 GITHUB_TOKENシークレットは、GitHub Appインストールアクセストークンです。 このインストールアクセストークンは、リポジトリにインストールされたGitHub Appの代わりに認証を受けるために利用できます このトークンの権限は、ワークフローを含むリポジトリに限定されます。

`GITHUB_TOKEN`はデフォルトで用意されておりworkflowが置かれるレポジトリスコープ内で有効です。
今回はデプロイスクリプトにて最後にsubmodule更新分をコミットしmasterにPushするために利用しています。

`DEPLOY_TOKEN`と`EMAIL_ADDRESS`は以下スクショのようにレポジトリのSettingから入力し設定します。

<img width="916" alt="スクリーンショット 2019-12-07 21.42.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91562/22e6051f-1e7a-7798-7787-71f4a1e4ffc0.png">


`DEPLOY_TOKEN`はGitHub PagesのレポジトリにPushするために必要なトークンで個人の[Personal access tokens](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line)のページから生成したものです。

## ポイント3 Git submoduleの扱い

ハマりました。

標準の[actions/checkout@v1](https://github.com/actions/checkout)のアクションモジュールを利用していましたがこれは下記のように`submodules: true`を入れてあげないとsubmoduleの実体がディレクトリ下に現れません。

```..github/workflows/main.ymlの一部
- uses: actions/checkout@v1
  with:
    submodules: true
```

このフラグを入れたあとも[このissue](https://github.com/actions/checkout/issues/14#issuecomment-523916396)と同じエラーが出てしまいました。

```
fatal: Could not read from remote repository.
```

どうやら現状ではsubmoduleをCloneするのにgitプロトコルではNGでhttpsを使うようにしないといけないようです。

[こちら](https://github.com/actions/checkout/issues/14#issuecomment-523916396)の解決方法を拝借しジョブの一番はじめに

```
- name: Fix up git URLs
  run: echo -e '[url "https://github.com/"]\n  insteadOf = "git@github.com:"' >> ~/.gitconfig
```

このステップを入れることで無事Submoduleが取得されました。

## デプロイの様子

`master`ブランチに変更が入るごとに[Actionのページ](https://github.com/momotaro98/hugo-bio/actions)から確認できます。

<img width="813" alt="スクリーンショット 2019-12-07 22.22.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91562/0d7d2039-1d3e-401d-0c74-284f9373b1bc.png">

# 補足 ローカルでのHugo起動はDockerで

GitHub ActionsとローカルでのHugoのバージョンが異なると困るので上述の`.env`ファイルにあるバージョンをローカルでも利用するようにDockerを利用します。

こちらに関しても @peaceiris さんが作成した[HugoのDockerのイメージ](https://hub.docker.com/r/peaceiris/hugo)を利用します。
[Tips](https://github.com/peaceiris/actions-hugo#tips)にあるように`docker-compose.yml`を設定すれば柔軟に環境変数でバージョンを指定できかつホットリロードで編集できるHugo環境ができます。

```docker-compose.yml
version: '3'

services:
  hugo:
    container_name: hugo
    image: "peaceiris/hugo:v${HUGO_VERSION}"
    # image: peaceiris/hugo:v${HUGO_VERSION}-mod  # Hugo Modules
    ports:
      - 1313:1313
    volumes:
      - ${PWD}:/src
    command:
      - server
      - --bind=0.0.0.0
      - --buildDrafts
```


`docker-compose up`をするだけでHugoサーバが`http://localhost:1313`で立ち上がります。

# 参考

* https://github.com/peaceiris/actions-hugo
* https://help.github.com/ja/actions/automating-your-workflow-with-github-actions
* http://beet-aizu.hatenablog.com/entry/2019/09/05/190123
* https://stackoverflow.com/questions/18935539/authenticate-with-github-using-a-token