CI/CD未経験者がVue CLI 3で作ったアプリをCircleCIでFirebaseにデプロイ

# はじめに
この記事はCI/CD未経験者が書いたものです。(これが初めて)

動作の確認は出来ていますが、きれいな作り方でない恐れがあります。

そして勉強のメモとしての側面もありますので、本来ならば書くべきでないコメントをコードの中に書いています。

以上の理由から、鵜呑みにするべきものではありませんので、あくまでご参考までにどうぞ。

# 環境
- リモートリポジトリ: GitHub
- IDE: Cloud9.io（AWS Cloud9ではないが、中身は殆ど一緒）

Cloud9は、ローカル等の他の開発環境でも代用可能ですが、記事の内容にCloud9の為の作業も記載しているので、一部の作業が記事の内容と異なるようになるかと思います。

# この記事に書いていないもの
CircleCI、Firebase、Cloud9、GitHubの基本操作(アカウントの登録方法など)

## 補足
GitHubを使ったことが無い方は[Udemyのコチラ](https://www.udemy.com/intro_git/)が個人的にオススメです。(要ユーザー登録)

CircleCIの登録については[コチラ](https://mikoto2000.blogspot.com/2018/05/circleci-sphinx-gh-pages.html)が画像付きで分かりやすいです。パスワードを入力するところまで実施すればOKでしょう。

# アプリの作成～GitHubにアップロード
アプリは[【Try! Vue CLI 3（インストール~プロジェクト作成~テスト~Buefy使用）】](https://qiita.com/takahiro-kato/items/03c840f6fbfb72008d87)の「Jest(ユニットテスト)の実行 - e.g.sum関数のテスト」までを実施したものを使用しました。「Buefy」以降は不要です。
（`vue create [プロジェクト名]`で入力したプロジェクト名は`my-dev-env`）
（上記の記事で作られたものは、厳密にはアプリと呼べるレベルではありません。`Hello World`です。）

アプリ作成後、GitHubにアプリ用のリポジトリを作成。（本記事のリポジトリ名は`my-dev-repository`）

Cloud9のターミナル上で下記コマンドを実行して、アプリをGitHubにアップロード。
(本記事ではREADME.md等を編集せずに、そのままGitHubにPushしているが、仕事では適した内容に編集するべき)

```
git add .
```

```
git commit -m "first commit"
```

```
git remote add origin https://github.com/<GitHubのユーザー名>/my-dev-repository.git
```

```
git push -u origin master
```

# CircleCIでアプリをビルド

## CircleCIにプロジェクトを追加
「ADD PROJECTS」-(my-dev-repository行の)「Set Up Project」をクリック。
（プロジェクトが表示されない場合は、CircleCIの再ログインで表示されるケースを確認してます）
![CircleCI-01.PNG](https://qiita-image-store.s3.amazonaws.com/0/128060/0948d54a-6095-ea90-216c-7d4a5b1f7b53.png)

Set Up Project画面に遷移したら`Operating System`は`Linux`、`Language`は`Node`を選択。

**※以降は、Set Up Project画面に記載してある`Next Steps`の作業。**
![CircleCI-02.PNG](https://qiita-image-store.s3.amazonaws.com/0/128060/cad8fe8e-56e6-a4ed-f7e5-2d1a23e3f94a.png)


Cloud9に戻り、`my-dev-env`フォルダ直下に`.circleci`フォルダを作成。

`my-dev-env/.circleci/`フォルダ直下に`config.yml`を作成して、下記コードを入力。
**※config.ymlファイルの内容はSet Up Project画面記載のサンプルとは少し異なります**

```
version: 2
jobs:
  build:
    docker:
      - image: node:8.11.0 # nodeのバージョンは開発環境に合わせる
      
    working_directory: ~/repo # 作業フォルダ
    
    steps:
      - checkout # プロジェクトに追加したGitHubリポジトリをworking_directoryにcloneしてcheckout
      
      # キャッシュがある場合はキャッシュから依存関係を復元
      - restore_cache:
          # 復元するキャッシュのkey
          keys:
            - v1-dependencies-{{ checksum "yarn.lock" }}
            - v1-dependencies-
      
      # 依存関係のインストール
      - run:
          name: Install dependencies # CircleCI上で表示される処理名(任意)
          command: yarn install # 処理コマンド
      
      # ビルド
      - run:
          name: Build
          command: yarn build
      
      # ビルドの確認
      - run:
          name: Check dist
          command: ls -la dist
      
      # キャッシュの保存
      - save_cache:
          paths:
            - node_modules
          key: v1-dependencies-{{ checksum "yarn.lock" }}
      
      # ユニットテスト
      - run:
          name: UnitTest
          command: yarn run test:unit
```

### memo
- キャッシュのkeyに`{{ checksum "yarn.lock" }}`を記載するのは重要。こうする事で依存関係(yarn.lock)が変わると、新たなキャッシュのkeyが生成される。`{{ checksum "yarn.lock" }}`はyarn.lockの内容をハッシュ化したものがセットされる。

- キャッシュのkeyはkeysに記載された設定を上から読み込んでいく。
今回の設定の場合、`v1-dependencies-{{ checksum "yarn.lock" }}`が存在しない場合、`v1-dependencies-`に前方一致するキャッシュを探す。
つまり、依存関係が変わって`v1-dependencies-{{ .Branch }}-{{ checksum "yarn.lock" }}`が見つからなくても、`v1-dependencies-`の前方一致検索によって、これまでにキャッシュに登録されたものはキャッシュからダウンロードできる設定が実現できる。

- キャッシュをクリーンしたい場合は、keysの値を見つからないkeyに指定する事で代用可（頭の`v1`を`v2`にするなど）

- `config.yml`で設定した処理は自身の開発環境ではなく、CircleCI上の環境に対して実施している。

## GitHubにプッシュ
下記コマンドを実行。

```
git add ./.circleci/config.yml
```

```
git commit -m "add CircleCI files"
```

```
git push origin master
```

## CircleCIでビルド開始
CircleCIの画面に戻り、`Next Steps`の5番目に配置された「Start building」ボタンをクリック。

![CircleCI-03.png](https://qiita-image-store.s3.amazonaws.com/0/128060/4ec12685-44ad-d02e-59ac-5b1364a8d0db.png)

## 動作確認
「JOBS」-「GitHubのユーザー名/my-dev-repository/master #1」をクリック。
![CircleCI-04.PNG](https://qiita-image-store.s3.amazonaws.com/0/128060/d320711f-407c-fec1-8992-9ba5c5ecbaf5.png)

処理の一覧が表示され、処理名左の「＞」をクリックすると処理の内容が展開される。
下図は「UnitTest」を展開して、テスト結果を表示させている画像。
![CircleCI-05.PNG](https://qiita-image-store.s3.amazonaws.com/0/128060/0a41e229-1fb6-3e33-94ef-42ef5d258ac7.png)

## 参考記事

[Circle CI 2.0 移行時のキャッシュ設定メモ](https://qiita.com/gaaamii/items/b2e8178d7d6e1423374f)

[Circle CI 2.0の基礎的な設定まとめてみた(GAE/Goのサンプル付き)](https://qiita.com/Sekky0905/items/7f9aa94261e17e4fd040)

# Firebaseにビルド

CircleCIにビルドを実施した後、Firebaseにビルドするように設定。

ref. [公式ドキュメント(英語)](https://circleci.com/docs/2.0/deployment-integrations/#firebase)

## firebase-toolsのインストール
下記コマンドを実行。

```
yarn add --dev firebase-tools
```

global installしないので、package.jsonのscriptsにfirebaseコマンドを登録。

```
  "scripts": {
     "firebase": "firebase"
  }
```

firebaseコマンドの動作確認。

```
yarn run firebase --version
```

## Firebaseにログイン
下記コマンドを実行。

```
yarn run firebase login --no-localhost
```

「CLIの使用方法やエラー情報を収集しても良いか？」という類の質問がくるので、妥当な方を選択。本記事では`n`を選択。
![Firebase-01.PNG](https://qiita-image-store.s3.amazonaws.com/0/128060/9cee4583-7418-461d-73d5-5f174e503eb5.png)

`Visit this URL on any device to log in:`というメッセージの後にURLが表示されるのでクリック。
![Firebase-02.PNG](https://qiita-image-store.s3.amazonaws.com/0/128060/d363cb76-f623-c1e0-3aa0-90ac1df6d123.png)


画面遷移先の「アカウントの選択」画面で自身のアカウントをクリックしてログイン。
![Firebase-03.PNG](https://qiita-image-store.s3.amazonaws.com/0/128060/3e25301d-28d1-23c3-1d23-a4dde02867e6.png)

「Firebase CLI が Google アカウントへのアクセスをリクエストしています」の画面になるので「許可」ボタンをクリック。
![Firebase-04.PNG](https://qiita-image-store.s3.amazonaws.com/0/128060/2a7c1ede-8805-6550-bf47-95a4de580523.png)

認証コードが表示されるのでクリップボードにコピー。
![Firebase-05.PNG](https://qiita-image-store.s3.amazonaws.com/0/128060/2d682a39-2d06-7a59-43df-4eb339aab7b7.png)

Cloud9のコンソール画面の`Paste authorization code here`に認証コードをペーストしてEnter。
![Firebase-06.PNG](https://qiita-image-store.s3.amazonaws.com/0/128060/876136ca-ee0a-b182-f591-89e9b8a83d98.png)

`Success! Logged in as [e-mail Address]`と表示されればOK。

# 初期化
Firebaseの初期化コマンドを実行。

```
yarn run firebase init
```

下図メッセージが表示されるので、`Hosting: Configure and deploy Firebase Hosting sites`だけをスペースで選択してEnter。
![Firebase-07.PNG](https://qiita-image-store.s3.amazonaws.com/0/128060/29f86d2a-87e2-628a-cdbb-387cdc357196.png)

下図メッセージが表示されるので、デプロイしたいプロジェクトにカーソルを合わせてEnter。
本記事では`[create a new project]`を選択して、デプロイするプロジェクトを後で新規作成する。
![Firebase-08.PNG](https://qiita-image-store.s3.amazonaws.com/0/128060/b1b0ba06-3784-e3ab-ff75-87be78c94976.png)

下図メッセージが表示されるので、`dist`を入力してEnter。（ビルド結果が出力されるフォルダを入力）
![Firebase-09.PNG](https://qiita-image-store.s3.amazonaws.com/0/128060/4c8cc5ff-7678-9208-9216-49e1e01599b5.png)

下図メッセージが表示されるので、`N`を入力してEnter。(シングルページアプリケーションの場合は`y`)
![Firebase-10.PNG](https://qiita-image-store.s3.amazonaws.com/0/128060/2f4ab469-d63f-4cbf-9c61-63e61ab83b4b.png)

下図メッセージが表示されると初期化の完了ですが、メッセージにあるように[Firebaseのコンソール画面](https://console.firebase.google.com)から新規プロジェクトを作成して、`firebase use --add`を実行する必要があります。
![Firebase-11.PNG](https://qiita-image-store.s3.amazonaws.com/0/128060/569a54de-4e17-7ae3-db28-4c7134354ed7.png)

[Firebaseのコンソール画面](https://console.firebase.google.com)にログインして新規プロジェクトを作成。
本記事ではプロジェクト名を`my-dev-firebase`にしました。

下記コマンドを実行して、プロジェクトを追加。

```
yarn run firebase use --add
```

下図メッセージが表示されたら、作成したプロジェクトを選択してEnter。
![Firebase-12.PNG](https://qiita-image-store.s3.amazonaws.com/0/128060/820bdea0-2202-91fb-5e2e-711e167ce76a.png)

下図メッセージが表示されたら、任意のエイリアスを入力してEnter。
本記事では`development`と入力。
![Firebase-13.PNG](https://qiita-image-store.s3.amazonaws.com/0/128060/01348f00-ea49-1e6a-1148-02a7d9079a21.png)

.gitignoreにFirebase関係のファイルを追加。

```
# Firebase files
.firebaserc # プロジェクトIDが記載されている。2018/11/21現在、大きな問題には至らないみたいだが念の為に...
/.firebase  # キャッシュファイルが含まれている。GitHubにプッシュする必要はない
```

アプリをビルド。

```
yarn run build
```

Firebaseにデプロイ。

```
yarn run firebase deploy
```


CircleCIからFirebaseにデプロイする為のトークンを発行。

```
yarn run firebase login:ci --no-localhost
```

`Visit this URL on any device to log in:`というメッセージの後にURLが表示されるのでクリック。
![Firebase-02.PNG](https://qiita-image-store.s3.amazonaws.com/0/128060/d363cb76-f623-c1e0-3aa0-90ac1df6d123.png)


画面遷移先の「アカウントの選択」画面で自身のアカウントをクリックしてログイン。
![Firebase-03.PNG](https://qiita-image-store.s3.amazonaws.com/0/128060/3e25301d-28d1-23c3-1d23-a4dde02867e6.png)

「Firebase CLI が Google アカウントへのアクセスをリクエストしています」の画面になるので「許可」ボタンをクリック。
![Firebase-04.PNG](https://qiita-image-store.s3.amazonaws.com/0/128060/2a7c1ede-8805-6550-bf47-95a4de580523.png)

認証コードが表示されるのでクリップボードにコピー。
![Firebase-05.PNG](https://qiita-image-store.s3.amazonaws.com/0/128060/2d682a39-2d06-7a59-43df-4eb339aab7b7.png)

Cloud9のコンソール画面の`Paste authorization code here`に認証コードをペーストしてEnter。
![Firebase-06.PNG](https://qiita-image-store.s3.amazonaws.com/0/128060/876136ca-ee0a-b182-f591-89e9b8a83d98.png)

`Success! Logged in as [e-mail Address]`と表示されればOK。

下図画面の灰色で塗りつぶされた場所に認証トークンが表示されるので記録しておく。
![Firebase-14.PNG](https://qiita-image-store.s3.amazonaws.com/0/128060/b5de1634-69b8-b521-a5c4-1368e44c0612.png)


### memo
発行した認証トークンの取消。

```
firebase logout --token <認証トークン>
```

# Firebaseの設定 in Circle CI
## Circle CIの環境変数の設定
Circle CIの環境変数にFirebaseのトークンとプロジェクトIDを設定。

CircleCIのメニュー「SETTINGS」-「Projects」-「[プロジェクト名の横にある設定アイコン]」をクリック。

![CircleCI-06.PNG](https://qiita-image-store.s3.amazonaws.com/0/128060/d50fce13-bd03-3c85-10f1-2f5b7da80172.png)


「BUILD SETTINGS」-「Environment Variables」をクリックして「Add Variable」ボタンをクリック。

設定画面が表示されたら認証トークンを設定する為に、下記の情報を入力して「Add Variable」ボタンをクリック。

```
Name: FIREBASE_DEPLOY_TOKEN
Value: [認証トークン]
```

同じ要領でFirebaseのプロジェクトIDを設定。

```
Name: FIREBASE_PROJECT_ID
Value: [FirebaseのプロジェクトID]
```

### 補足
FirebaseのプロジェクトIDは、Firebaseのコンソール画面からプロジェクトの画面に移って、「プロジェクトの設定」をクリックすると、遷移先の画面に表示されています。
![Firebase-15.PNG](https://qiita-image-store.s3.amazonaws.com/0/128060/d27756d4-0ec2-3006-bbeb-7e7861505006.png)



## config.ymlにFirebaseの設定を追加
`my-dev-env/.circleci/config.yml`に下記コードを追加。

```diff
# 依存関係のインストール
- run:
    name: Install dependencies # CircleCI上で表示させる為の処理名(任意)
    command: yarn install # 処理コマンド

+ # Firebase-toolsのインストール
+ - run:
+     name: Install Firebase-tools
+     command: yarn add --dev firebase-tools

・
・
・
      
# ユニットテスト
- run:
    name: UnitTest
    command: yarn run test:unit

+ # Firebaseにデプロイ
+ - run: 
+     name: Deploy to Firebase hosting
+     command: yarn run firebase deploy --project "$FIREBASE_PROJECT_ID" --token "$FIREBASE_DEPLOY_TOKEN"
```

# Circle CIでFirebaseにデプロイ
下記コマンドを実行。

```
git add .
```

```
git commit -m "add Firebase settings"
```

```
git push origin master
```

## 動作確認
Circle CIの画面に移り、「JOBS」-「GitHubのユーザー名/my-dev-repository/master #2」をクリック。
![CircleCI-08.PNG](https://qiita-image-store.s3.amazonaws.com/0/128060/7e0d6a15-7276-6c34-bb66-d3ff2718783f.png)

処理の一覧の中から、「Deploy to Firebase hosting」の「＞」をクリックして処理の内容を展開。
その中の「Hosting URL」に記載されているURLにアクセスすると、Firebaseにデプロイしたアプリが起動します。
![CircleCI-09.PNG](https://qiita-image-store.s3.amazonaws.com/0/128060/2b0cf39f-f47b-18de-e710-af1c9d954815.png)


以上で作業が完了です。

## 参考記事

[CircleCIで、Firebaseのコマンドを実行させる方法](https://qiita.com/samuraikun/items/a7de51dab70ab853b9ff)

[Circle CIでFirebaseにデプロイする方法](https://qiita.com/ottijp/items/974e092a87fbffc3f191)

# 所感
CI/CD未経験者の私でも簡単にCI/CDを実現することが出来ました。

実際の開発現場になるとチーム・組織的な運用が絡んで、もっと色々な機能を駆使しないといけないかもしれませんが、入門としては上出来ではないかと思います。

今後も色々触っていきたいと思います。