[CircleCI2.0]Markdown仕様書をBasic認証付きURLで公開する

## モチベーション

- CircleCIをもっと活用したい
- ドキュメント作成をプログラムちっくにしたい
- ER図を毎回更新したくない
- サーバレス（今回がサーバレスかは置いてといて）やりたい
- ソースコードとドキュメントをプルリクの中で見れたら幸せと思う

## 使用技術

- CircleCI 2.0
- Rails 5.1.5
- Mysql 5.7
- AWS S3
- AWS Lambda
- AWS CloudFront
- Gitbook

Railsアプリをサンプルにします。

## 全体構成

![AWS Networking.png](https://qiita-image-store.s3.amazonaws.com/0/100766/5c61634b-8004-6173-fc23-65a563e50107.png)

Githubにpushすると、それをフックにCircleCIがBuild & Deployを行います。
S3にアップロードしたものをCloudFront経由で配信します。
Lambdaにbasic認証のコードを書いて、リクエストがきたら認証を求めます。
これで限定されたドキュメント公開ができます。

## 実装

### 前提条件

- CircleCIのアカウントがある
- Gitbookが使える
- IAMユーザー作成済み

### S3

- S3のbucketを作成する
- `<bucket-name>-docs`というプレフィックスを付ける（管理のため）
- バケットポリシーやホスティング設定は不要なので何もしない（CloudFrontでやる）

### CircleCI

- Buildするリポジトリを追加
- 追加したリポジトリの設定から「AWS Permissions」を選択してIAMのキーを設定する

![Cursor_と_Project_settings_-_IJGN_mypo-web_-_CircleCI.png](https://qiita-image-store.s3.amazonaws.com/0/100766/3b2801d8-2241-ef1b-9f32-d5ef53987040.png)

### Markdown

リポジトリのルートに`docs`フォルダを作ってその中でgitbookを使います。

```bash
$ mkdir docs
$ cd docs
$ gitbook init
$ echo /docs/_book >> .gitignore
```

あとはMarkdownでゴリゴリ書きます。

*注意：名前はdocsじゃなくてもいいですが、CircleCIの設定ファイルで指定しているので合わせる必要があります。*

### 設定ファイル

以下の要件で設定ファイルを作ってみました。
1. Rspec実行
2. [rails-erd](https://github.com/voormedia/rails-erd)からER図を生成し、`docs/img`に移動する
3. gitbookでdocs配下のmdファイルからhtmlファイルを生成
4. S3にアップロード
5. 3,4は特定のbranchのみ動作させたい

```.circleci/config.yml
version: 2

workspace_root: &workspace_root
    ~/workspace

defaults: &defaults
  docker:
    - image: circleci/ruby:2.4.2-node-browsers
      environment:
        RAILS_ENV: test
        BUNDLE_JOBS: 3
        BUNDLE_RETRY: 3
        BUNDLE_PATH: vendor/bundle
        DB_HOST: 127.0.0.1
    - image: circleci/mysql:5.7
  working_directory: *workspace_root

attach_workspace: &attach_workspace
  attach_workspace:
    at: *workspace_root

jobs:
  build:
    <<: *defaults
    steps:
      - checkout

      # Restore bundle cache
      - restore_cache:
          keys:
            - bundle-{{ checksum "Gemfile.lock" }}
            - bundle

      - run:
          name: Bundle Install
          command: bundle check || bundle install

      # Store bundle cache
      - save_cache:
          key: bundle-{{ checksum "Gemfile.lock" }}
          paths:
            - vendor/bundle

      # Database setup
      - run:
          name: Database setup
          command: |
            bin/rails db:create
            bin/rails db:schema:load

      # Run rspec in parallel
      - run:
          name: Run tests
          command: |
            bundle exec rspec --profile 10 \
                              --format RspecJunitFormatter \
                              --out test_results/rspec.xml \
                              --format progress \
                              $(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)

      # Save test results for timing analysis
      - store_test_results:
          path: test_results

      - persist_to_workspace:
          root: *workspace_root
          paths:
            - .

  docs:
    <<: *defaults
    steps:
      - <<: *attach_workspace

      - run:
          name: Install dependencies
          command: |
            sudo apt-get install graphviz
            sudo npm install gitbook-cli -g

      - run:
          name: ER diagram
          command: |
            bin/rails db:create
            bin/rails db:schema:load
            bundle exec erd --attributes=foreign_keys,primary_keys,content,timestamp --filename=erd --filetype=png
            mv -f erd.png docs/img/

      - run:
          name: Gitbook
          command: gitbook build docs docs/_book

      - persist_to_workspace:
          root: *workspace_root
          paths:
            - docs

  deploy_s3:
    <<: *defaults
    steps:
      - <<: *attach_workspace

      - run:
          name: Install dependencies
          command: sudo apt-get -y -qq install awscli

      - run:
          name: Deploy to S3 if tests pass and branch is Master
          command: aws s3 sync docs/_book s3://$S3_BUCKET --delete

workflows:
  version: 2
  workflows:
    jobs:
      - build
      - docs:
          requires:
            - build
          filters:
            branches:
              only: develop
      - deploy_s3:
          requires:
            - build
            - docs
          filters:
            branches:
              only: develop
```


### Build

CircleCI2.0で追加されたworkflowsを使うと次のように複数のjobが連結された感じで実行されます。
何か気持ちいい。

![CircleCI_-_CircleCI.png](https://qiita-image-store.s3.amazonaws.com/0/100766/7144df3f-b49d-24b4-1f77-d107c6604e86.png)

### Basic認証をかけて公開する

参考記事にある[こちら](https://qiita.com/m4fg/items/80db7ce0050e5f3ab801)を参考にさせていただきました。
ありがとうございます！

## ハマった点

**awscliの使い方**

S3にsyncするときにbucket名の指定に`s3://`を付けないといけないところ

**CircleCI 2.0の設定ファイルの書き方**

1.0と2.0が書き方が全然違うので学習コストかかるところ

**Build中にxxxx command not found**

`apt-get`しているはずが、コマンドがないと怒られました。
`sudo`を付けたら解決しました。

**Railsでmysqlを使う場合**

`config/database.yml`を変更する必要がありました。

```config/database.yml
test:
  <<: *default
  adapter: mysql2
  database: yourapp_test
  host: <%= ENV['DB_HOST'] || 'localhost' %> # 追加
```

この`DB_HOST`にはCircleCIの設定ファイルで書いた`DB_HOST: 127.0.0.1`が入ります。
`localhost`だとエラーになるようです。

## 参考記事

[gitbookで楽々ドキュメント作成](https://www.cresco.co.jp/blog/entry/2509/)
[GitBook/GitHub/CircleCIでメンテ可能な仕様書を書く](https://qiita.com/KeitaMoromizato/items/04ac6058010248b3ce82)
[CircleCIを使ってS3にブログをデプロイする](https://ishiis.net/2016/09/18/circle-ci-setup/)
[CircleCI 2.0 に移行しました](http://tech.smarthr.jp/entry/2017/07/12/073000)
[CloudfrontとS3でBasic認証をかける](https://qiita.com/m4fg/items/80db7ce0050e5f3ab801)
[Github, CircleCI, S3, CloudFront, Middlemanを活用して、https対応のサーバレスで自動deployなWEBサイト構築](https://qiita.com/mokokko/items/f593bc4adc36a55db80f)

## 成果物

https://github.com/TakuyaHarayama/gitbook-docs-template

CircleCIのデプロイ部分を一部コメントにしてるので、適宜変更してください。
erd生成はないです。

## 終わりに

これでソースコードと一緒にドキュメントも管理できて、クライアントにもbasic認証で共有できて
レビューもしやすくなる、そして幸せになるw