Firebase Hostingを使ってホスティングするCDをGithub Actionsで構築する

### 目的
Firebase Hostingを使用してホスティングするフローをCDで自動化して人間のミスや工数を減らしたい

### 実装の流れ
Github ActionsでCDを構築すること（やりたいこと）をベースに実装していきます。

1. Github ActionsでホスティングするプロジェクトをBuildするコードを書く
2. Github ActionsでFirebase Hostingを使うために必要な情報をGithub Secretsに保存する
3. 2で作成したアカウントのキーを使用してGithub Actionsでホスティングするコードを書く

### Github ActionsでホスティングするプロジェクトをBuildするコードを書く

```yml:deploy.yml
name: deploy
on:
  push:
    branches:
      - master
  workflow_dispatch:
jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Create env file
        run: echo "${{ secrets.ENV_VAR }}" > .env
      - name: yarn install
        run: yarn install
      - name: Build
        run: nuxt generate
      - name: Archive Production Artifact
        uses: actions/upload-artifact@v2
        with:
          name: dist
          path: dist
```

VueとNuxtを使用しています。
`Build`
`Create env file`
などについては適宜使っている環境によって書き換えてください
[upload-artifact](https://github.com/actions/upload-artifact)を使用して、ジョブ間でデータの共有ができるようにして次の`deploy`ジョブで使えるようにしています。
`dist`はホスティングするプロジェクトのディレクトリ名です。

### Github ActionsでFirebase Hostingを使うために必要な情報をGithub Secretsに保存する

**必要なもの**
1. プロジェクトID
2. 認証情報

**1.プロジェクトID**

GCPのプロジェクトIDをコピーしてGithub Secretsに保存します。

**2.認証情報**
公式を見ると、FirebaseのトークンかGCPの認証情報があればHostingできそうです。

今回は、
- FirebaseのトークンだとGoogleのアカウントに紐付いているということで、発行者がいなくなってトークンの影響でデプロイできなくなると困るかも
- GCPをTerraformで管理している
という理由からGCPのサービスアカウントキーを利用して認証する方法を選択します。

**GCPのサービスアカウントの作成、権限の付与、鍵発行、の手順についてはここでは詳しくは触れません**ので、わからない方は適当にググるかfirebaseのtokenを利用するかにしてください。

サービスアカウントを作成したら、`Firebase Hostingへのアクセス権限`を与えてあげないといけません。
サービスアカウント自身が必要以上の権限をもつと権限が強すぎて思わぬ事故につながりかねないので、必要な権限のみ与えることにします。

以下のページより


https://firebase.google.com/docs/projects/iam/roles-predefined-product?hl=ja#hosting



今回は読み書きを行うので、`Firebase Hosting 管理者`ロールをサービスアカウントに付与します。

うっかりしていると下の

>重要: Firebase CLI を使用してデプロイするには、プロジェクト メンバーに API キー閲覧者のロール（roles/serviceusage.apiKeysViewer）も割り当てる必要があります。

この注意書きを見逃すので、

https://cloud.google.com/iam/docs/understanding-roles?hl=ja#service-usage-roles

から`API キー閲覧者`も付与します。

※現在`Firebase Hosting 管理者`周りの権限はカスタムロールに対応していないようなのでこちらをつけるしかなさそうです。[参考](https://firebase.google.com/docs/projects/iam/permissions?hl=ja#hosting)


付与すると、そのサービスアカウントの鍵を発行して、それをGithub Secretsに保存します。
（私はいつも発行された.jsonファイルの中身をそのままsecretに入れています）

### 2で作成したアカウントのキーを使用してGithub Actionsでホスティングするコードを書く

deployができる環境が整いました。

デプロイを含めたワークフローのコードは以下になります。

```yml:deploy.yml
name: deploy
on:
  push:
    branches:
      - master
  workflow_dispatch:
jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Create env file
        run: echo "${{ secrets.ENV_VAR }}" > .env
      - name: yarn install
        run: yarn install
      - name: Build
        run: nuxt generate
      - name: Archive Production Artifact
        uses: actions/upload-artifact@v2
        with:
          name: dist
          path: dist
  deploy:
      name: Deploy
      needs: build
      runs-on: ubuntu-latest
      environment:
        name: dev
      steps:
        - uses: actions/checkout@v2
        - name: Set up Cloud SDK
          uses: google-github-actions/setup-gcloud@master
          with:
            project_id: ${{ secrets.GCP_PROJECT_ID }}
            service_account_key: ${{ secrets.GCP_SA_FIREBASE_HOSTING_KEY }}
            export_default_credentials: true
        - name: Download Artifact
          uses: actions/download-artifact@v2
          with:
            name: dist
            path: dist
        - uses: actions/setup-node@v2
          with:
            node-version: '14'
        - name: Install firebase-tools
          run: |
            yarn global add firebase-tools
            echo "$(yarn global bin)" >> $GITHUB_PATH
        - name: Deploy to Firebase
          run: firebase deploy --only hosting --project $GCP_PROJECT_ID
          env:
            GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }}

```

※`GCP_PROJECT_ID`...前述の1.プロジェクトID
※`GCP_SA_FIREBASE_HOSTING_KEY`...2.で作成したサービスアカウントのキー

順番に見ていきます。

`Set up Cloud SDK`

認証情報を登録しています。
`Successfully exported Default Application Credentials`が出ていれば正常なのですが、何か設定できていないと`No credentials provided, skipping authentication`で認証がスキップされているので注意してください。こちらに関してはその場所でエラーが出るわけではないのでハマりかねません。

`Download Artifact`

Build時にした`Upload Artfact`のデータをダウンロードします。

`Install firebase-tools`
次の`firebase deploy`を実行するためにグローバルにインストールしてパスを通しています。


補足ですが、ホスティング予定のリポジトリに`firebase.json`がないとエラーが出ますので、リポジトリに含まれているかを確認してください。（そのため初回は手動でinitする必要があるかも？）

これでワークフローを回します。

```
i  hosting[***]: finalizing version...
✔  hosting[***]: version finalized
i  hosting[***]: releasing new version...
✔  hosting[***]: release complete

✔  Deploy complete!
```

デプロイまで走ったら完了です🎉🎉🎉🎉🎉🎉

Github ActionsとFirebase HostingとGCPの合わせ技でCD構築に成功しました。
この辺りは、サービスをまたがる実装なので、各サービスの公式ドキュメントも交じえながら適度に参考にしていただければと思います。