FirebaseとGitHubを連携しCI/CD環境を構築する

本記事では、前回記事でFirebase HostingにデプロイしたReactアプリ(Firebase Authenticationによる認証とFirestoreによるCRUD機能があるメモアプリ)を対象にGitHubと連携することでCI(Continuous Integration: 継続的インテグレーション)/CD(Continuous Deployment: 継続的デプロイ)環境を構築します。

以前はGitHubと連携してCI/CD環境を構築するには自前作業が色々ありましたが、2020年10月8日にFirebaseとGitHubの連携が強化されほとんど自動でCI/CD環境を構築できるようになりました。

完成するCI/CD環境は、GitHubでプルリクエストすると自動的にプレビューチャンネル(サイト)が構築され、プルリクエストをマージするとFirebase Hostingに自動でデプロイ(ライブチャンネル: 本番環境)されるものになります。注意点として、プレビューチャンネルはライブチャンネルとFirebaseのリソース(DBなど)を共有しますので、既に本番環境を公開している場合は特に留意しておく必要があります。

前回記事

本記事では以前FirebaseのAuthenticationとFirestoreを使って作ったWebアプリをFirebase Hostingにサクッとデプロイした後に独自ドメインを追加する方法までを解説します。 FirebaseのHo[…]

domain_settings_1

作業環境

macOS 10.15.7

Node.js 14.3.0

npm 6.14.5

firebase-tools 8.14.1

Firebase CLIによるGitHub Actionsの設定

ローカル環境のプロジェクトルートディレクトリで以下のどちらかのコマンドを実行します。本記事の場合は既に前回の記事でFirebase Hostingにデプロイしているので後者のコマンドを実行しています。

// Firebase Hosting未実施の場合
firebase init hosting

// Firebase Hosting実施済みの場合
firebase init hosting:github

 

するとブラウザ上でGitHubのアカウント認証を要求されますので指示に従い認証を行ってください。

GitHub認証1

GitHub認証2

GitHub認証3

 

GitHubのアカウント認証に成功するとコマンドラインにも以下のメッセージが出ます。

✔ Success! Logged into GitHub as ganeo

 

次に、接続するGitHubのリポジトリを尋ねられますのでリポジトリを入力してエンターキーを押します。

? For which GitHub repository would you like to set up a GitHub workflow? ganeo/react-firestore-crud-sample

 

すると以下のメッセージが出ます。これはGitHubのSecrets(環境変数)にFirebaseとの接続に必要なキー情報を自動で登録したというメッセージです。GitHubの「Settings > Secrets」を確認すると下図のとおり登録されています。

✔ Created service account github-action-306564914 with Firebase Hosting admin permissions.
✔ Uploaded service account JSON to GitHub as secret FIREBASE_SERVICE_ACCOUNT_REACT_FIREBASE_AUTH_SAMP_73FC1.
i You can manage your secrets at https://github.com/ganeo/react-firestore-crud-sample/settings/secrets.

GitHub_Secrets_1

 

デプロイ前にビルドスクリプトを実行するかを問われるのでYesのyを入力してエンターキーを押します。

? Set up the workflow to run a build script before every deploy? (y/N) y

 

ビルドスクリプトを入力してエンターキーを押します。
本記事ではyarnの例を示していますが、npmであれば「npm ci && npm run build」で同様の挙動になります。

? What script should be run before every deploy? yarn –frozen-lockfile && yarn run build

 

「.github/workflows」ディレクトリに「firebase-hosting-pull-request.yml」というファイルを作成したとメッセージが出ます。このファイルにはプルリクエストをトリガーとするGitHub Actionsワークフローが書かれています。

✔ Created workflow file /react-firestore-crud-sample/.github/workflows/firebase-hosting-pull-request.yml

 

ライブチャンネル(本番環境)にプルリクエストのマージと同時に自動デプロイするかを尋ねられるのでYesのyを入力してエンターキーを押します。

? Set up automatic deployment to your site’s live channel when a PR is merged? (Y/n) y
本番環境のリリースファイルがあるブランチ名を問われます。本記事ではmasterで本番環境用ファイルを管理しているのでmasterと入力してエンターキーを押します。
? What is the name of the GitHub branch associated with your site’s live channel? master

 

メッセージが出て一番上に「.github/workflows」ディレクトリに「irebase-hosting-merge.yml」というファイルを作成したと書かれています。このファイルにはプルリクエストのマージをトリガーとするGitHub Actionsワークフローが書かれています。
以上でFirebase CLIによる作業は完了です。

✔ Created workflow file /react-firestore-crud-sample/.github/workflows/firebase-hosting-merge.yml

i Action required: Visit this URL to revoke authorization for the Firebase CLI GitHub OAuth App:
https://github.com/settings/connections/applications/89cf50f02ac6aaed3484
i Action required: Push any new workflow file(s) to your repo

i Writing configuration info to firebase.json…
i Writing project information to .firebaserc…

✔ Firebase initialization complete!

GitHubでのビルド準備

本記事でデプロイするアプリは「.env」ファイルにFirebase用のキー情報を環境変数として登録していて、このファイルはGitHubにpushしていません。この状態でGitHubでビルドしても「.env」ファイルが存在しないためデプロイがうまくいきません。

そこでビルド時にGitHubにこれから登録する環境変数を読み込むようにするため「firebase-hosting-pull-request.yml」と「firebase-hosting-merge.yml」ファイルに下記赤字のように追記しています。なおGitHubの環境変数をGitHub Actionsで利用する方法について詳しくは本セクション最後に添付した別記事をご参照ください。

最後の「CI: false」は別の目的(ビルド時に出現するワーニングを無視する設定)で追加しています。この環境変数CIはGitHub Actionsのデフォルト設定でtrueとなっています。デフォルトの環境変数については公式ドキュメントをご参照ください。

# .github/workflows/firebase-hosting-pull-request.yml

# This file was auto-generated by the Firebase CLI
# https://github.com/firebase/firebase-tools

name: Deploy to Firebase Hosting on PR
'on': pull_request
jobs:
  build_and_preview:
    runs-on: ubuntu-latest
    env:
      REACT_APP_FIREBASE_KEY: ${{ secrets.REACT_APP_FIREBASE_KEY }}
      REACT_APP_FIREBASE_DOMAIN: ${{ secrets.REACT_APP_FIREBASE_DOMAIN }}
      REACT_APP_FIREBASE_DATABASE: ${{ secrets.REACT_APP_FIREBASE_DATABASE }}
      REACT_APP_FIREBASE_PROJECT_ID: ${{ secrets.REACT_APP_FIREBASE_PROJECT_ID }}
      REACT_APP_FIREBASE_STORAGE_BUCKET: ${{ secrets.REACT_APP_FIREBASE_STORAGE_BUCKET }}
      REACT_APP_FIREBASE_SENDER_ID: ${{ secrets.REACT_APP_FIREBASE_SENDER_ID }}
      CI: false
    steps:
      - uses: actions/checkout@v2
      - run: yarn --frozen-lockfile && yarn run build
      - uses: FirebaseExtended/action-hosting-deploy@v0
        with:
          repoToken: '${{ secrets.GITHUB_TOKEN }}'
          firebaseServiceAccount: >-
            ${{ secrets.FIREBASE_SERVICE_ACCOUNT_REACT_FIREBASE_AUTH_SAMP_73FC1
            }}
          projectId: react-firebase-auth-samp-73fc1
        env:
          FIREBASE_CLI_PREVIEWS: hostingchannels
# .github/workflows/firebase-hosting-merge.yml

# This file was auto-generated by the Firebase CLI
# https://github.com/firebase/firebase-tools

name: Deploy to Firebase Hosting on merge
'on':
  push:
    branches:
      - master
jobs:
  build_and_deploy:
    runs-on: ubuntu-latest
    env:
      REACT_APP_FIREBASE_KEY: ${{ secrets.REACT_APP_FIREBASE_KEY }}
      REACT_APP_FIREBASE_DOMAIN: ${{ secrets.REACT_APP_FIREBASE_DOMAIN }}
      REACT_APP_FIREBASE_DATABASE: ${{ secrets.REACT_APP_FIREBASE_DATABASE }}
      REACT_APP_FIREBASE_PROJECT_ID: ${{ secrets.REACT_APP_FIREBASE_PROJECT_ID }}
      REACT_APP_FIREBASE_STORAGE_BUCKET: ${{ secrets.REACT_APP_FIREBASE_STORAGE_BUCKET }}
      REACT_APP_FIREBASE_SENDER_ID: ${{ secrets.REACT_APP_FIREBASE_SENDER_ID }}
      CI: false
    steps:
      - uses: actions/checkout@v2
      - run: yarn --frozen-lockfile && yarn run build
      - uses: FirebaseExtended/action-hosting-deploy@v0
        with:
          repoToken: '${{ secrets.GITHUB_TOKEN }}'
          firebaseServiceAccount: >-
            ${{ secrets.FIREBASE_SERVICE_ACCOUNT_REACT_FIREBASE_AUTH_SAMP_73FC1
            }}
          channelId: live
          projectId: react-firebase-auth-samp-73fc1
        env:
          FIREBASE_CLI_PREVIEWS: hostingchannels

 

GitHubの「Settings > Secrets」に下図赤枠のとおりFirebase用のキー情報を登録します。

GitHub_Secrets_2

 

関連記事

ローカル環境で例えば「.env」ファイルなどにAPIキーなどの秘密情報を書いておいて環境変数としてアプリで利用している場合、通常GitHubに「.env」ファイルをpushしないと思います。ただこの場合GitHub Actionsを使って自[…]

GitHub_secrets

CI/CDの動作確認

CI/CD環境が問題なく動くかテストしてみます。

テストの流れは以下リストのとおりです。なお現状masterブランチにて本番稼働させています。

  1. (@Local環境) 開発用にmasterブランチからdevelopブランチをきる。
  2. (@Local環境) デプロイ結果の確認用にHTMLを一部修正する。
  3. (@Local環境) GitHubにpushする。
  4. (@GitHub) プルリクエストを行う。
    ➡︎自動的にプレビューチャンネルがデプロイされるので②の変更が反映されているかを確認する。
  5. (@GitHub) masterブランチにプルリクエストのマージを行う。
    ➡︎自動的にライブチャンネル(本番環境)にデプロイされるので②の変更が反映されているかを確認する。

Local環境での作業

次のコマンドでmasterブランチからdevelopブランチをきります。

git checkout -b develop

 

デプロイのテスト確認のため、developブランチのpublic/index.htmlのtitleを「React Firestore CRUD Sample」に変更しておきます。

title修正結果

 

以下のとおりpushまで行います。

# インデックスを追加
git add .

# コミット
git commit -m “CI test”

# プッシュ
git push origin develop

 

GitHubでの作業

続いてGitHub側の作業になります。

developブランチにて「Pull request」ボタンをクリックします。

プルリクエスト1

 

「Create pull request」ボタンをクリックしてプルリクエストします。

プルリクエスト2

 

プルリクエストを行うと自動的にビルドが行われプレビューチャンネルがデプロイされます。プレビューチャンネルのURLは下図1つ目の赤枠にあります。

プルリクエスト3

 

プレビューチャンネルにてタイトルが変わっていることを確認できます。冒頭でも述べましたがプレビューチャンネルはライブチャンネルとリソースを共有していますのでご注意ください。

プレビューチャンネル

 

続いて2つ上の図にある2つ目の赤枠にある「Merge pull request」ボタンをクリックします。developブランチからmasterブランチへのマージが行われ、自動的にビルドとライブチャンネル(本番環境)へのデプロイが行われます。

下図ではFirebaseのHosting画面にてデプロイがGitHub Actionsによって実行されたことがわかります。

本番デプロイ結果確認

 

本番環境にてタイトルが変更されているのを確認できました。

本番確認

参考サイト

Firebaseの公式ドキュメント

sponsor