GitHub Actionsでプルリク時にStoryBookをS3にデプロイする

この記事は、ニフティグループ Advent Calendar 2020の20日目の記事です。
昨日は @shotaws さんの [Next.jsでCore Web VitalsをAmazon CloudWatchに送信してみる](https://qiita.com/shotaws/items/20b5fd64bebcaa0e9627) でした。
弊社ではAWSを活用しているので、何事もCloudWatchに集約できるのいいですね。
加えてCore Web Vitalsは興味のある分野なので非常に参考になりました！
# はじめに
それでは本題に入っていきます。

企画やデザインとの認識が合わなくて何度も修正作業が発生することはありませんか？
その都度、開発環境にデプロイして確認をとってもらうのは面倒だと思います。
こういった問題を解決するためにStoryBookとGitHub Actionsを導入しました。
# StoryBookとは
簡単に言うとUIコンポーネントを分離して開発するためのオープンソースツールです。
各コンポーネントがどのような挙動をするのかを確認したり、コンポーネントを一望できるスタイルガイドのように使えたりします。
[StoryBook公式](https://storybook.js.org)
# GitHub Actionsとは
高機能のCI / CDですべてのソフトウェアワークフローを簡単に自動化できます。
[GitHub Actions](https://github.co.jp/features/actions)
# StoryBookの導入
今回はVue.jsにStoryBookを導入していきます。
導入したいプロジェクトに移動して以下のコマンドを入力します。

```
# Storybook CLIをインストール
$ yarn global add @storybook/cli

# プロジェクトディレクトリへ移動
$ cd <プロジェクトディレクトリ>

# StoryBookをプロジェクトにインストール
$ npx -p @storybook/cli sb init

# StoryBook起動
$ yarn run storybook
```

起動するとデフォルトで用意されているボタンやヘッダーなどを各コンポーネントごとに確認することができるようになります。
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575290/f86f4ec9-703b-faa6-1dae-62fdf59b44d3.png">
# AWSでの準備
今回はStoryBookをAmazon S3にデプロイして静的ウェブサイトホスティングをします。
## デプロイ先のS3バケットを作る
S3のプロパティにある静的ウェブサイトホスティングを有効化してください。
[詳しい設定方法はこちら](https://blog.web.nifty.com/engineer/2401)
静的ウェブサイトホスティングが有効化されるとエンドポイントが発行されるので控えておいてください。
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575290/242d939b-0b6b-4add-c465-bbf7a4c2fc71.png">
## IAMユーザーの作成
GitHub ActionsでS3にアクセスするために利用します。
AmazonS3FullAccessの権限だけで大丈夫です。
アクセスキーIDとシークレットアクセスキーは後ほど使うので控えておいてください。
# GitHub Actionsの作成
今回作成するGitHub Actionsの要件は以下です。

* プルリク時に特定のコメントが投稿されたらStoryBookをデプロイする
* プルリクの番号ごとにS3のフォルダを切る
* S3のURLをプルリクにコメントする

特定のコメントをトリガーにしている理由は、プルリクが作成されたら毎回デプロイを行ってしまうとライブラリの更新などのデプロイを必要としないプルリクが来たときに不要なデプロイが発生してしまうからです。
S3のフォルダを切る理由は、複数のプルリクが来ているときにデプロイをしてしまうと内容を上書きしてしまうからです。
## シークレットの設定
github の project の Settings > Secrets から登録できます。
先ほど作成したIAMユーザーのアクセスキーIDとシークレットアクセスキーを登録してください。
その他にS3のバケット名とエンドポイントを登録してください。
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575290/0b850fab-5447-5ca1-58b3-29e7d6e2cbec.png">
## 設定ファイル
先ほど作成したvueのプロジェクトに.github/workflowsというフォルダを作成します。

```
├─.github
│  └─workflows
```

```.github/workflows/deploy_storybook_pr.yml
name: StoryBook Deploy S3[pull_request]

on:
  issue_comment:
    types: [created]

jobs:
  build:
    runs-on: ubuntu-latest
    env:
      S3_BUCKET_NAME: ${{ secrets.S3_BUCKET_NAME }}
      S3_URL: ${{ secrets.S3_URL }}
      API_ENDPOINT: ${{ github.event.issue.pull_request.url }}
      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      GITHUB_PULL_REQUEST_NUMBER: ${{ github.event.issue.number }}
    steps:
    - id: check
        # If the comment contains the string deploy-storybook and pull_requrest, then run
      if: "contains(github.event.comment.body, 'deploy-storybook') && github.event.issue.pull_request" 
      run: |
        branch=`curl -X GET -H "Authorization: token ${GITHUB_TOKEN}" ${API_ENDPOINT} | jq -r '.head.ref'`
        echo ::set-output name=branch::$branch
     
    - name: Checkout
      if: "steps.check.outputs.branch" 
      uses: actions/checkout@v2

    - name: Setup node
      if: "steps.check.outputs.branch"
      uses: actions/setup-node@v1
      with:
        node-version: '14.x'

    - name: Configure AWS credentials
      if: "steps.check.outputs.branch" 
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: ap-northeast-1

    - name: Build StoryBook
      if: "steps.check.outputs.branch" 
      run: |
        yarn install
        yarn build-storybook
      
    - name: Upload file to S3
      if: "steps.check.outputs.branch" 
      run: |
        aws s3 sync ./storybook-static s3://$S3_BUCKET_NAME/pr-$GITHUB_PULL_REQUEST_NUMBER --quiet
        
    - name: Create URL
      if: "steps.check.outputs.branch" 
      run: |
        curl -X POST -H "Authorization: token ${GITHUB_TOKEN}" -i ${API_ENDPOINT} -d "`printf '{\"body\":\"deploy to %s\"}' ${S3_URL}/"pr-"${GITHUB_PULL_REQUEST_NUMBER}`"

```
作成したらGitHubにpushします。
# 動作確認
プルリクを作成し、deploy-storybook とコメントすると設定ファイルに記述した内容でGitHub Actionsが起動します。
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575290/28bef381-ebee-971a-bfdd-fe75f0ed8dc8.png">
ビルドが成功するとプルリクのコメントにURLが投稿されます。
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575290/fccb9bfd-13ce-2b37-ef48-46def4111e1b.png">
URLを確認すると先程ローカルで確認したものと同じものがデプロイされています。
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575290/39692a5a-72d9-4e19-4ae1-0039c1502803.png">
# おまけ：生成されたURLをSlack通知する
開発効率をさらに上げるために生成されたURLをSlack通知できるようにします。
通知したいチャンネルのincoming webhookのURLをSecretsのSLACK_WEBHOOK_URLに登録してください。

```
    # Slack notification
    - name: Slack Notification
      uses: 8398a7/action-slack@v3
      env:
        SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
      with:
        status: custom
        fields: workflow,job,commit,repo,ref,author,took
        custom_payload: |
          {
            username: 'StoryBookURL通知BOT',
            icon_emoji: ':github:',
            attachments: [{
              "color": '${{ job.status }}' === 'success' ? 'good' : '${{ job.status }}' === 'failure' ? 'danger' : 'warning',
              "author_name": "${{ github.actor }}",
              "author_icon": "${{ github.event.sender.avatar_url }}",
              "text": "StoryBookのURLを生成しました。確認をお願いします。",
              "fields": [
                {
                  "title": "変更内容",
                  "value": "${{ github.event.issue.title }}"
                },
                {
                  "title": "URL",
                  "value": "${{ secrets.S3_URL }}/pr-${{ github.event.issue.number }}"
                }],
              }
            ]
          }
```
ビルドが完了すると指定したチャンネルに通知が来ます。
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575290/e73a4282-283d-d74c-b4d0-270c3476cc38.png">
# おわりに
今回はStoryBookを例にGitHub Actionsの活用方法を紹介してきました。
その他にもGitHub Actionsではリポジトリのラベル付けやリリースノートの作成を自動化したり、Terraformと連携させてmasterにマージされたらインフラをデプロイすることも可能です。
自動化できる作業はなるべく自動化して効率化を図りつつ、楽をしていきましょう！

明日は@matsu-matsuさんの回です。楽しみにお待ち下さい！