CircleCI を使って Github pages のリポジトリをソースコード管理用とサイト公開用に分ける

# 前提知識
Githubには github pages という、リポジトリをウェブページとして扱う仕組みが存在します。

リポジトリに index.html を配置すると、 `https://[userid].github.io/[repo_name]` で見られるようになるという仕組みです。

簡単なサイトであれば非常に手軽にウェブページを公開することが出来ます。

しかし、現代のウェブページは html や JavaScript を直書きすることは少なく、 AltJS や React などを使って書いたコードを webpack などのバンドラーでビルドした js を配置することが多いはずです。

そこで、リポジトリの master とは別のブランチにビルドした結果を含めて、そのブランチを github pages として公開するという方法を取ることが出来ます。

実際、npm には、実行することで `gh-pages`  というブランチに指定したディレクトリを commit してくれるというツールが存在します。

https://www.npmjs.com/package/gh-pages

通常であれば各リポジトリの Options > GitHub Pages > Source で、こうして作ったブランチをウェブサイトとして公開するブランチとして選ぶか、もしくは docs/ ディレクトリを公開するかが選べるのですが、このときブランチを master ブランチしか選べなくなる状況が発生することがあります。

それは、「User pages」で github pages を立てた場合です。

# Github pages の User pages では master ブランチしか公開できない

User pages とは、リポジトリの名前を `[userid].github.io` にすると、 `https://[userid].github.io` というURLでウェブサイトが作られるという機能です。

これは、ユーザーや Organisations が自分のページを分かりやすいURLで公開したい場合などに役立ちますが、上記のような欠点があります。

User pages で github pages を立てると、GitHub Pages オプションの Source が以下のように変わります。

![20190524221058.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79558/8b746b8a-650e-17b5-5ea9-e0f4a5850aeb.png)


ただ単に「ソースコードリポジトリを master に push → CircleCIでビルド → ビルド成果物を push」という流れだけであれば、 .circleci/config.yml で単純にこの手順を書いていくだけで済むのですが、今回の例は master ブランチしか公開出来ないため、そのようには行きません。

解決策を先に書くと

1. 手元のマシンで ssh-keygen する(-m pem オプション必須) 
1.  CircleCI の 各プロジェクトの設定の SSH Permissions に秘密鍵を登録
1. github のリポジトリの settings の Deploy keys に公開鍵を登録

こうすることで、 CircleCI のビルド手順の中で、ソースコード用リポジトリからソースコードをビルドしたあと、公開用リポジトリに push するという工程を完了させることが出来るようになります。

# 手順

Windowsであれば WSL で、 Mac/Linux であればそのままターミナルで以下のようにコマンドを叩きます。
`$ ssh-keygen -t rsa -b 4096 -m pem -C "for User pages"`
生成した秘密鍵と公開鍵を、 CircleCI と Github の公開用リポジトリにそれぞれ登録します。

このとき<b>「秘密鍵は CircleCI」「公開鍵は Github」</b>の組み合わせを間違えないようにします。

![20190524224256.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79558/e450b220-53b0-0c21-2868-742257164883.png)


![20190524224932.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79558/f1c115a6-0891-91ce-50b1-af0a54692810.png)


このように登録しておくことで、 CircleCI のビルド手順内での git push コマンドの認証で、作成したSSHキーが使われるようになります。

ソースコードリポジトリの .circleci/config.yml には以下のような感じで書きます。

```yaml
version: 2
jobs:
  build:
    docker:
      - image: circleci/node:10.15.3
    steps:
      - checkout
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "package.json" }}
            # fallback to using the latest cache if no exact match is found
            - v1-dependencies-

      - run: git clone https://github.com/happou31/happou31.github.io
      - run: npm install
      - run: npm run build
      - run: rm -rf ./happou31.github.io/*
      - run: cp -r ./dist/* ./happou31.github.io/
      - run:
          name: Deploy to repository
          working_directory: happou31.github.io
          command: |
            git config user.email "happou31+circleci@users.noreply.github.com"
            git config user.name "happou31+circleci"
            git add .
            git commit -m "built from -https://github.com/happou31/source.happou31.github.io/commit/$CIRCLE_SHA1"
            git push origin master
      - run: rm -rf ./happou31.github.io

      - save_cache:
          paths:
            - node_modules
          key: v1-dependencies-{{ checksum "package.json" }}

```


ここまで出来たら、ソースコードリポジトリを push します。すると…

![20190524230733.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79558/668ebaf9-776d-035a-b98d-25b8ad5add76.png)

ビルドが完了したようです！

公開用リポジトリにもいい感じでコミットメッセージが残ってます。

![20190524230842.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79558/d2ba083b-4c56-2a40-f661-ec67b3e21754.png)



一応、公開用リポジトリの Deploy keys を確認します。
ちゃんと Last used within the last week と出て、公開鍵が認証に使われていることが分かります。

![20190524231044.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79558/f5a6ebe8-01b0-845b-7195-482cb8e6c4c8.png)



お疲れ様でした。

# 終わり
このやり方、結構需要がある気がするのに情報がなかったので色々調べて書いてみました。

まあリポジトリを2つ分ける必要があったりするのでちょっと面倒かなとは思いますが、毎回手動でビルド&デプロイするよりは圧倒的に楽かと思います。（あと、自動化はロマン）

というわけでみなさんもレッツ自動化！！！

(本記事は以前に自身のブログにて投稿したものです。)