CircleCIでmasterにmergeされた場合のみビルドしたバイナリをCloud Source Repositoresへpushする

CircleCIからGoogleの Cloud Source Repositories へのpush手順です
## Google Cloud Source Repositoriesへpushする事前準備
### GCPのサービスアカウントからサービスキーを取得
CircleCIからGCPのCloud Source Repositoryにpushするために、CircleCIのコンテナ内でGCPの認証を行う必要があります。<br>
そのために必要なのが、外部サービス用のサービスアカウントキーです。
サービスアカウント、サービスアカウントキーについてはGCPのドキュメントを参照しました<br>

- [サービス アカウント](https://cloud.google.com/iam/docs/service-accounts?hl=JA)

#### サービスアカウントとは
サービスアカウントは、アプリケーションや仮想マシンの間で使用する特別なアカウントのことです。<br>
GCPのプロジェクト内のアプリケーションはサービスアカウントに毎日発行されるサービスアカウントキーを使用して、ユーザーの直接の認証を必要とせずにGCPの各種APIを呼び出すことができます。<br>
CircleCIから、GCPのプロジェクトへデプロイやリポジトリへのpushを行う場合は、外部用のサービスアカウントキーを発行します。<br>
サービスアカウントキーを安全に管理する方法については、下記のブログに詳しく掲載されていますが、個人でのサービス開発であれば、ここまでする必要はないかもしれません。
- [Google Cloud のサービス アカウント キーを安全に管理する](https://cloudplatform-jp.googleblog.com/2017/08/help-keep-your-Google-Cloud-service-account-keys-safe.html)
- [GCP Service Accountを理解する](https://qiita.com/t-yotsu/items/5d3d36847fbc71b72b76)

### CircleCIのcontextに設定しておく
作成した外部サービスアカウントキーを、CircleCIのcontextに保存しておきます。<br>
contextの名前をここではgcpとしています。workflow内のジョブ内で`context: gcp`のように呼び出すと、そのジョブ内でgcp context内で定義した値を参照することができます。<br>

#### 定義しておくと便利はcontextの定数
その他にも、context内で定義しておくと便利な定数があります

```
GOOGLE_COMPUTE_ZONE = 任意のインスタンスのリージョン
GOOGLE_PROJECT_ID = gcp内のprojectID
```
とくに、gcpのプロジェクトIDはgithubにpushせずに、context内に置いておいて参照すべきだと思います。

## 設定ファイル
### workflowの設定
workflowでは、jobs以下で定義したジョブの順番やジョブ間の従属関係を定義することができます<br>

```yaml

#circleci/config.yml内のworkflow
workflows:
    version: 2
    build:
      jobs:
        - build
        - deploy:
            context: gcp
            requires:
                - build
            filters:
              branches:
                only: master
```

workflowの流れは以下の通り

1. buildする（jobs以下のbuildジョブ）
2. buildが成功したらdeployジョブを開始（`requires: build`）
3. `context: gcp`でcontext内で定義した値をジョブ内で参照できる
4. `filters`で条件を指定できる
5. masterブランチのみdeployジョブを実行する（`only: master`）

### deployジョブ
#### deployジョブに使用する docker image
deploy用のdocker imageはgoogleが提供している[google/cloud-sdk](https://hub.docker.com/r/google/cloud-sdk/)利用します（あらかじめDockerfileでcloud-sdkのインストールと設定をしてくれます）

#### 前回のジョブから引き継いだwork spaceをattachする
前回のジョブ（build）の最後で、`persist_to_workspace`と設定するとジョブ間でディレクトリを引き継ぐことができます。<br>
引き継ぐことで、`src/`以下にビルドしたgoのバイナリを次のジョブでそのまま使用することができます。<br>

```yaml

# src/以下をrootに保存しておく
- persist_to_workspace:
          root: .
          paths:
              - src/
```

deployジョブ内でattachして`src/`以下を引き継ぐ

```yaml

# deployジョブ内でattachする
- attach_workspace:
          at: .
```
#### contextからサービスアカウントキーをjsonファイルに書き出す
```yaml

- run:
    name: Service Account Key
    command: echo ${GCLOUD_SERVICE_KEY} > ${HOME}/gcloud-service-key.json
```
#### gcloudコマンドのセットアップ
contextから`GOOGLE_PROJECT_ID`と`GOOGLE_COMPUTE_ZONE`を参照しています

```yaml

 - run:
     name: Set gcloud command
     command: |
         cloud auth activate-service-account --key-file=${HOME}/gcloud-service-key.json
         gcloud --quiet config set project ${GOOGLE_PROJECT_ID}
         gcloud --quiet config set compute/zone ${GOOGLE_COMPUTE_ZONE}
```

#### gitアカウントの設定
```yaml

- run:
    name: setting git account
    command: |
        git config user.name circle
        git config user.email circle@example.com
```

#### Googleの Cloud Source Repositoriesへpush
```yaml

- run:
    name: deploy
    command: |
        gcloud init && git config --global credential.https://source.developers.google.com.helper gcloud.sh
        git remote add google https://source.developers.google.com/p/${GOOGLE_PROJECT_ID}/r/${GOOGLE_PROJECT_REPOSITORY}
        git add -f src/app
        git commit -m "deploy code"
        git push google master -f
```

## circleci/config.yml
```yaml

version: 2
jobs:
  build:
    working_directory: /go/src/github.com/tanden/go-echo-with-mysql/

    docker:
      - image: circleci/golang:1.10

    steps:
      - checkout

      - restore_cache:
          keys:
              - v1-vendor-{{ .Branch }}-{{ checksum "src/Gopkg.lock" }}
              - v1-vendor-{{ .Branch }}
              - v1-vendor
              - v1-dep

      - run:
          name: dep ensure
          command: |
              cd src/
              if [ ! -d vendor ]; then
                if ! type dep >/dev/null 2>&1; then
                  go get -u github.com/golang/dep/cmd/dep
                fi
                dep ensure
              fi
      - save_cache:
          key: v1-vendor-{{ .Branch }}-{{ checksum "src/Gopkg.lock" }}
          paths:
              - src/vendor

      - save_cache:
          key: v1-dep
          paths:
              - /go/bin/dep

      - run:
          name: go build
          command: |
              go build -v -o src/app src/server.go

      - persist_to_workspace:
          root: .
          paths:
              - src/

  deploy:
    working_directory: /go/src/github.com/tanden/go-echo-with-mysql/

    docker:
      - image: google/cloud-sdk

    steps:
      - checkout
      - attach_workspace:
          at: .
      - run:
          name: Service Account Key
          command: echo ${GCLOUD_SERVICE_KEY} > ${HOME}/gcloud-service-key.json
      - run:
          name: Set gcloud command
          command: |
              gcloud auth activate-service-account --key-file=${HOME}/gcloud-service-key.json
              gcloud --quiet config set project ${GOOGLE_PROJECT_ID}
              gcloud --quiet config set compute/zone ${GOOGLE_COMPUTE_ZONE}
      - run:
          name: setting git account
          command: |
              git config user.name circle
              git config user.email circle@example.com
      - run:
          name: deploy
          command: |
              gcloud init && git config --global credential.https://source.developers.google.com.helper gcloud.sh
              git remote add google https://source.developers.google.com/p/${GOOGLE_PROJECT_ID}/r/${GOOGLE_PROJECT_REPOSITORY}
              git add -f src/app
              git commit -m "deploy code"
              git push google master -f

workflows:
    version: 2
    build:
      jobs:
        - build
        - deploy:
            context: gcp
            requires:
                - build
            filters:
              branches:
                only: master
```