【firebase】HostingをGitHubやCircleCIと連携してみる。

#はじめに
どうせfirebaseのHosting使うのなら、GitHubやCircleCiも使いたいよね。

と言うことで、手を出してみました。
意外と簡単に実現できてCircleCIとは何ぞや？と言うのを**表層**だけ感じられたかなと…（多分

忘れないうちにメモしておきます。
間違ってて目も当てられないとかあれば、指摘をいただけると非常にありがたいです。。

#全体の流れ
今回はこんな感じの流れになります。

[ GitHubにリポジトリを作成しアップする　]
　　↓
[ CircleCIにWorkflow&Jobを作成する ]
　　↓
[ 動作確認をしてみる ]
　　↓
[ 完了 ]

#構成図チックな何か
完成すれば、こんな感じの流れになるはず…!!
（色々ツッコミどころありますが、スルーしてください）

　　①``git push``　　　  ②workflow起動
　[私]　→ → →  [ GitHub ]  → → →  [ CircleCI ]
 　　　　　　　　　　　　　　　　　 ⇩ ③-1workflowに定義されたJobを実行
 　　　　　　　　　　　　　　　　　 ⇩ ( Jobはビルド環境としてDockerを最初に構築 ）
　　　　　　　　　　　　　　　　 [ docker ] ③-3``firebase deploy``
　　　　　　　　　　　　　　　＜firebaseCLI＞　  → → → → →  [ firebase(Hosting) ]　　　
　　　　　　　　　　　　　　③-2Docker上にインストール

#前提事項
・別Qiitaの手順が完了している前提で進めます！
　→ [【firebase】hostingサービスで超簡単にポートフォリオデプロイ。](https://qiita.com/ozackiee/items/7a4f9cdaf3372af8cd0a)
・GitHubおよび、CircleCiのアカウント登録は事前に済ませてください！
・コマンド実行は先頭に**$**をつけています。（ちょっと分かりづらくなっちゃいました…）

#GitHubにリポジトリを作成しアップする
前回作成したフォルダの構成は以下の通りです。
このフォルダに対して、gitコマンドを使用して[GitHub](https://github.com/)にアップします。

【対象のフォルダ構成】
　ozackiee-portfolio[対象フォルダ]
　　∟ .firebase
　　∟ .firebaserc
　　∟ .gitignore
　　∟ .firebase.json
　　∟ public
　　　∟ index.html
　　　∟ img
　　　∟ css
　　　∟ js

##①ローカルリポジトリの初期化
対象フォルダに移動し、下記のコマンドを実行します。

```ターミナル.
 # 初期化実施
 $ git init

 # gitignore以外の全てのファイルを対象にする                           
 $ git add *                            

 # addしたファイルをcommit(初回コミットとして）
 $ git commit -m "initial commit"       
```

##②リモートリポジトリの作成
GitHubにログインし、ヘッダメニューから[new repository]を選択します。
CreateRepository画面が表示されるので、対象フォルダと同名のリポジトリ名をつけてサクッと作成しましょう。
[![Image from Gyazo](https://i.gyazo.com/f7210de09666ddf135b0f80188b129f9.png)](https://gyazo.com/f7210de09666ddf135b0f80188b129f9)

作成が完了すると、下図の画面が表示されるのでGitHubのパスをコピーしましょう。
[![Image from Gyazo](https://i.gyazo.com/7b3b51c9c0f7c7afe8ba303ed33a7213.png)](https://gyazo.com/7b3b51c9c0f7c7afe8ba303ed33a7213)

##③リモートリポジトリへの紐付け&アップロード
以下のコマンドを実行して、リモートリポジトリとローカルリポジトリを紐付けます。

```ターミナル.
　# 紐付けの実施（紐付けと言うのかな…
　$ git remote add origin https://github.com/ユーザ名/リポジトリ名.git ←先ほどコピペしたパス

　# リモートリポジトリへmasterブランチをアップロード（ブランチ切ってないので、これしかない!)
　$ git push origin master
```
これでGitHubの設定は完了です〜!!!

#CircleCIにWorkflow&Jobを作成する
CircleCIでやることは大きく３つあります。
ですが、今回は３つ目のデプロイ作業にフォーカスを当てて実施しました。
もちろん、ビルドやテストもコマンド組み込めば行けるかと…（分からないけど

・ビルド作業
・テスト作業
・デプロイ作業

また、私の理解では、それぞれ以下のような役割。
Job→ビルドやテスト、デプロイといったそれぞれの作業を定義したもの。
Workflow→Jobの順序制御。例えば、①ビルド→②テスト→③デプロイの順で実行してねって言うような定義をしているもの。

それでは早速始めましょう。

##①CircleCIプロジェクトの作成
[CircleCI](https://circleci.com/)にGitHubユーザでログインします。
初回ログインした際、Getting Startedという欄に、以下のような画面が出てくると思います。該当のGitHubリポジトリを選択し[Follow]（Set Up New Projects）を選択しましょう。
[![Image from Gyazo](https://i.gyazo.com/f7453158903ac488b63d54af14be495e.png)](https://gyazo.com/f7453158903ac488b63d54af14be495e)

##②デプロイ用の認証トークンを取得
次はターミナルでの作業です。
プロジェクトフォルダ配下に移動するし、下記のコマンドを実行します。
実行するとブラウザが起動し、アカウントの指定とアクセス許可画面が出るので、許可してください。その後、ターミナルに認証トークンが表示されるため、値をコピーして控えておきましょう。

```ターミナル.
$ firebase login
  ✔  Logged out from xxxx.xxxx.xxxx@gmail.com   ←logoutしてなかった場合
$ firebase login:ci
Visit this URL on this device to log in:
https://accounts.google.com/o/oauth2/auth?client_id=******

Waiting for authentication...

　✔  Success! Use this token to login on a CI server:

[******************************] ←ここに認証トークンが表示されるのでコピー

Example: firebase deploy --token "$FIREBASE_TOKEN"　←Jobにはこのコマンドを仕込めばOK（ちょい付け足しが必要ですが）
```

##③Jobに環境変数を設定する
②で例示された``$FIREBASE_TOKEN``に直接トークン貼っても通りますが、セキュリティ上よろしくないのでビルド環境上の環境変数として仕込みます。
CircleCIのトップ画面から[JOB]-[該当リポジトリの右側の設定マーク]を選択してください。
[![Image from Gyazo](https://i.gyazo.com/4ae32b15b6e1cd9d02248c0f49a093ba.png)](https://gyazo.com/4ae32b15b6e1cd9d02248c0f49a093ba)

設定メニューの[BUILD SETTING]-[Envaronment Variables]を選択し、設定画面を開きます。
[![Image from Gyazo](https://i.gyazo.com/9aefa655ae47525d74bd89eef9477ead.png)](https://gyazo.com/9aefa655ae47525d74bd89eef9477ead)

設定画面で[Add Variables]ボタンをクリックすると、登録画面が表示されます。
[Name：FIREBASE_TOKEN]/[Value:"コピーした認証トークンを貼り付け"]して、[Add Variable]をクリックし、環境変数登録は完了です。
[![Image from Gyazo](https://i.gyazo.com/fc39c7abcceffa206e14f015168e3786.png)](https://gyazo.com/fc39c7abcceffa206e14f015168e3786)

##④configファイルを作成する(=workflow&jobの定義は全てココに詰まってます !)
プロジェクトフォルダ直下に``.circleci/config.yml``を作成します。
ビルド環境にはDockerを使用します。ビルドやテスト（今回は無いですが）、デプロイなどCircleCIでの作業は、全てこのビルド環境から実行されます！
そのため、今までローカルでやっていた作業を全てデプロイ環境から自動実施できるように環境構築して、バッチ処理化してあげる必要があるわけですね！

その前提で先ほど設定した環境変数などを使いつつ、以下のように記述しました。
(2.1じゃなくてゴメンなさい><)

```.circleci/config.yml

version: 2                                       # 1/2/2.1の何れかを指定。バージョンによって記述の仕方が異なるので注意（現状であれば、2,2.1のどちらかが推奨みたい
jobs:                                            # 必須固定
  build:                                         # Job名/Jobが1つの場合は必ず"build:"
    docker:                                      # ビルド環境(machine/macosなどのVPCを選ぶことも可能だけど、dockerが主流みたい
      - image: circleci/node:10                  # ビルドイメージを指定。firebaseCLIはnode.js ver6.0.0以上推奨であることを確認しつつ、現在のnode.js推奨バージョンである10を指定
    steps:                                       # 実行内容記述開始の合図
      - run:                                     # firebaseCLI入れる前に念のためnpmバージョンチェック
          name: 'npm version check'
          command: npm --version
      - run:                                     # firebaseCLI入れる前に念のためnode.jsのバージョンチェック
          name: 'Node.js version check'          
          command: node --version
      - checkout                                 # GitHubのリポジトリ配下のファイルを丸っとビルド環境に持ってくる
      - run:                                     # firebaseCLIのインストール
          name: 'Install Firebase CLI'
          command: npm install --save-dev firebase-tools
      - run:                                     # firebaseCLIを使ってデプロイ実行
          name: 'Deploy to Hosting'
          command: ./node_modules/.bin/firebase deploy --token="$FIREBASE_TOKEN"
workflows:                                       # 定義したJobを流すフローを指定
  version: 2
  build_and_deploy:                              # 任意のフロー名でOK
    jobs:                                        # 実行Jobを配下に記述
      - build:                                   # 今回は”build"のみなので、これだけ！あまりフローを組む必要性ないですけど、必須みたいです！
          filters:
            branches:
              only: master                       # filtersでmasterブランチへのコミットのみを対象にflowを動かすように指定
```
本当はキャッシュなども使いつつ、もっと上手くできるんだろうなぁ…が、理解が足らない。
##⑤ config.yml事前チェック
circleCICLIをインストールすることで、ローカルでcircleCIを実行することが可能になります。
無闇に失敗履歴を増やしたくない場合は、このツールを使ってconfigファイルのチェックや、job実行を試してみると良いかと思います。

**【注意点】**
ローカルでのjob実行では環境変数``$FIREBASE_TOKEN``が上手く参照できず失敗します。
ただ、実環境では上手く行きますので、私のようにココで１時間以上浪費しませぬよう。。。
 ↑ちなみにトークン直指定だと、上手くいきます。

```ターミナル.
 #circleCI CLIのインストール
 $ brew install circlec

 #config.ymlの記述チェック
 $ Config file at .circleci/config.yml is valid.

 #circleCIのローカル実行
 $ circleci local execute --job build
   # 中略 #
  Error: Command requires authentication, please run firebase login
  Error: Exited with code 1
  Step failed
  Error: runner failed (exited with 101)
  Task failed
  Error: task failed
```

CircleCIのJob仕込みはこれで完了！（にする！）

# 動作確認をしてみる
実際の稼動確認に入ります！
``config.yml``だけだと、変化が分かりにくいので適宜``index.html``ファイル何かも修正しておくと良いかもです。ここでは[GitHubへのコミット]→[CircleCIの動作確認]の順で見ていきます。

##①コミット対象を確認する
``.circleci/config``を変更したので、対象として上がってくるはずです。
念のため、状況を確認しましょう。

```ターミナル.
 # 変更ファイルの確認
 $ git status

On branch master
Your branch is up to date with 'origin/master'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)
  (commit or discard the untracked or modified content in submodules)

	modified:   .circleci/config.yml　　← 存在しますね！

no changes added to commit (use "git add" and/or "git commit -a")
```

##②コミット対象に追加＆コミット
差分確認ができたところで、コミットを切っちゃいます。

```ターミナル.
 # 変更対象のファイルを全てコミット対象に追加
 $ git add -A

 # もう一度、状況確認してみましょうか
 $ git status
 
On branch master
Your branch is up to date with 'origin/master'.

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	modified:   .circleci/config.yml　← コミット待ちになってます

 # よっしゃ、コミットしちゃう!
 $  git commit -m "update .circleci/config.yml"

[master d0e235b] update .circleci/config.yml
 1 file changed, 1 insertion(+), 1 deletion(-)

 # そしてリモートリポジトリにもプッシュ!!
 $ git push origin master

Enumerating objects: 7, done.
Counting objects: 100% (7/7), done.
Delta compression using up to 4 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 359 bytes | 359.00 KiB/s, done.
Total 4 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
To https://github.com/******/ozackiee-portfolio-ee34d.git
   7c844b9..d0e235b  master -> master
```

##③CircleCIのJob実行状況を確認する
CircleCIの画面に戻ってみましょう。
メニューからJobを選択すると、今回作成したJobに実行結果の履歴が残っているはずです。
やった！SUCCESSしてる！（5回目であることは、知らないふりで…
[![Image from Gyazo](https://i.gyazo.com/a8756ee909cd9e6066f2f25d48e2924c.png)](https://gyazo.com/a8756ee909cd9e6066f2f25d48e2924c)

履歴をクリックすると``config.yml``で指定した``RUN:``ごとの実行履歴も確認できます。
↓こんな感じ。
[![Image from Gyazo](https://i.gyazo.com/6b3bf54c924471e25e62387381ac8e9c.png)](https://gyazo.com/6b3bf54c924471e25e62387381ac8e9c)

#完了
index.htmlも更新されていれば…一応自動デプロイと呼んで良いでしょう!!(多分!!

#【補足説明】GitHubでの不具合について
公開フォルダ(public)配下の修正をGitが認識してくれないと言う事象がありました。
その場合は、一旦publicフォルダを消してコミットし、再度登録すればなんとかなりました。
※ただし、この場合は初回のcircleciがコケます。
　が、public配下のファイルを編集し、再挑戦すれば、その後は上手く動いています。
（publicフォルダ自体は既に存在しているため、firebaseは、もうあるよ！！！と怒ってきます)

#まとめ
なんとなくCircleCIがやってることが理解できた気がする！
あとは、やはりテスト…テスト実行のコマンドは打てても、中身が無いとね…orz

でも、コマンドはif分で分岐などもでき、色々と奥が深そうです。
これはこれで、次の機会(?)が楽しみですね！

٩( 'ω' )و

#参考
以下のサイトを参考にさせていただきました。ありがとうございましたmm

[CircleCIドキュメント:CircleCI のローカル CLI の使用](https://circleci.com/docs/ja/2.0/local-cli/)
[いまさらだけどCircleCIに入門したので分かりやすくまとめてみた](https://qiita.com/gold-kou/items/4c7e62434af455e977c2)
[Circle CIからFirebase Hostingに自動ビルド&デプロイする](https://qiita.com/nakata_kazuhiro/items/53c7f06900ae3156e07b)
[CircleCiとFireBaseを連携させるのに4時間かかった](https://qiita.com/kajirikajiri/items/bcf553715b1e441c216f)