いまさらだけどCircleCIに入門したので分かりやすくまとめてみた

# はじめに
今度入社する会社では、JenkinsでなくCircleCIを使っているということなので、1から勉強した内容を初心者向けにまとめました。
また、最新バージョン2.1(2018/12時点)の新機能も本記事では触れています。

<img width="1237" alt="スクリーンショット 2018-12-20 17.04.20.png" src="https://qiita-image-store.s3.amazonaws.com/0/221948/cc9f9579-954f-06f9-3504-2abbab2d84c0.png">

※2019/8/8追記
Slack連携に関する記事も書きました。
[SlackでCircleCIからカバレッジレポート通知を受け取る設定手順](https://qiita.com/gold-kou/items/24a1d68a65d641115b9e)

※2020/4/2追記
https://twitter.com/CircleCIJapan/status/1245253320551399424
CircleCIさんより、本記事を紹介いただきました！
なお、本記事は初回投稿時（2018/12）の情報がメインのため、ご留意いただきますようお願いします。

# 前提知識
- CI/CDに関する入門レベルの知識
- ymlファイルに関する入門レベルの知識
- コンテナに関する入門レベルの知識
	- 未学習の方は私の記事ですが、[こちら](https://qiita.com/gold-kou/items/44860fbda1a34a001fc1)を参考にしてください。

# 概要
## CircleCIとは
一言でいえば、Saas型のCI/CDサービスです。Saas型であるという点が特徴です。
CircleCIはクラウド上のコンテナあるいはVMを実行環境として使用します。
コンテナかVMかはユーザーが選択可能ですが、コンテナの方が起動が速く、VMは今後有料になる可能性があります。CircleCIではコンテナの利用を推奨しているようです。
この記事では主にコンテナ寄りで説明することにします。

## CircleCIでできること
CircleCIに限らないですが、一般的にCI/CDでやることはビルドとテストとデプロイの3点です。

### ビルド
ソースコードから実行可能なアプリケーションを構築します。
具体的には、Dockerイメージのpull、依存パッケージのインストール、コンパイルなどです。

### テスト
UTなどのテストコードを実行して動作確認をしたり、Rubocop(Ruby)などのコードスタイルチェックなどを行います。

### デプロイ
ビルドしてテストが通ったものを本番環境や検証環境などにリリースします。

## Jenkinsと比較して
多くのCIツールが世の中に存在しますが、最も有名なJenkinsと比べてCircleCIは以下の特徴があります。

### CircleCIが優れている点
- 環境構築コストが低い
	- Saasだから
	- Web-UIで初期設定を少しやるだけ
	- 冗長化とかも勝手にされている
	- Jenkinsの場合、自前でJenkins用のサーバを立てる必要がある
- 運用コストが低い
	- Saasだから
	- サーバーメンテナンスや故障時の対応をやる必要がない
- ymlファイルで設定できる
	- Jenkinsの場合、Web-UIで細かい設定までできるが、職人芸になりがち

### CircleCIが劣っている点（気をつけるべき点）
- バージョン管理でSVNを使っているプロジェクトでは使えない
	- GitHub/Bitbucket連携が前提
- リアルタイムにビルド実行ができない
	- 定期実行はできる
- CircleCIで故障が発生しても自分たちで原因解析や復旧をすることが困難
	- Saasだから
- Saasの利用料には要注意

## 必要なもの
CircleCIを利用するにあたって必要なものはGitHubあるいはBitbucketのアカウントのみです。

## 料金
※2020年4月2日追記
最新の料金情報はこちらのようです。
https://circleci.com/ja/pricing/

### 無料枠(2018/12現在)
個人開発や試し使いには充分そう。

- 1コンテナのみ
	- したがって、同時実行ジョブは1つのみ
- 1ヶ月あたり1000分のビルド時間まで
	- 最近、1500分から減ってしまったらしい 
- リポジトリ数の制限なし
- ユーザー数の制限なし

### 有料枠
- コンテナ1つ増やす毎に50ドル。
- 2コンテナ以上利用する場合は、ビルド時間の制限はなくなるようです。
- 詳細は[公式サイト](https://circleci.com/pricing/)へ

## 導入実績企業
海外企業、国内企業含め数千の企業で導入がされているようです。
有名どころでいうとこんなところ。

- Facebook
- Spotify
- CyberAgent
- ZOZOテクノロジーズ
- DeNAなど

## CI/CDの契機
CIとCDがそれぞれ走る契機をまとめました。

- CI
	- pull-request作成した時
	- pull-request作成以降にpushした時
	- 定期実行時(cron)
- CD
	- mergeした時
		- ブランチによってデプロイ先を変えられる
			- masterブランチへmergeされたら本番環境、developブランチへmergeされたら検証環境など
	- 定期実行時(cron)

# config.yml
CI/CDの設定は全て `.circleci/config.yml` に記載します。(1.0系ではcircle.ymlという名前であった。)
間違えて、 `config.yaml` と書いてCircleCIでエラーになるケースはあるある（？)
なので、気をつけてください。
`.circleci` ディレクトリは対象Gitリポジトリのトップに置きます。

## キー
config.ymlでよく使用するキーに絞って説明します。
その他のキーは[公式リファレンス](https://circleci.com/docs/2.0/configuration-reference/)を参考にしてください。

### 必須キー
必ず設定必要なキー。

- `version`: CircleCIのバージョンを指定する。現状、1か2か2.1を指定可能だが、これからCircleCI始める場合は2か2.1にする。
- `jobs`: 1つ以上のjobを設定する。jobが1つだけの場合、job名は `build` でなければならない。各jobではCI環境設定などを行う。
	- `<job_name>`: 任意のjob名を設定する。
		- `steps`: CI環境上で動作させるコマンドや実行結果の保存、キャッシュ操作などを設定する。詳細は後述。

```yaml:sample
version: 2.1
jobs:
  build:
    steps:
      (省略)
```

### オプションキー
必須キーの子あるいは孫などとして設定可能なキー。
必要に応じてそれぞれを設定する。

#### イメージ系
CI環境で利用するDockerコンテナあるいはVMのイメージを指定する。
CircleCIではDockerの利用が推奨されている。
DockerHub上では既に各種言語やミドルウェアなどのインストールや設定が完了しているイメージが多く存在しているため、これらをベースにすることでビルド部分の構築稼働を削減できる。
`docker` / `machine` / `macos` のいずれかをconfig.ymlに記載する必要がある。

- `docker`: CI環境にDockerを利用する場合の設定。
	- `image`: ベースとなるDockerイメージを指定する。複数指定することも可能。
	- `auth`: DockerHubのプライベートイメージを使用する場合の認証情報を指定する。
		- `username`: ユーザ名
		- `password`: パスワード
	- `aws_auth`: ECR(Amazon Elastic Container Registry)のプライベートイメージを使用する場合の認証情報を指定する。
		- `aws_access_key_id`: アクセスキーのID
		- `aws_secret_access_key`: アクセスキー

```yaml:複数imageのsample
jobs:
  build:
    docker:
      - image: circleci/golang:1.8
      - image: circleci/postgres:9.4
```
```yaml:authのsample
jobs:
  build:
    docker:
      - image: acme-private/private-image:321
        auth:
          username: mydockerhub-user
          password: $DOCKERHUB_PASSWORD
```
```yaml:aws_authのsample
jobs:
  build:
    docker:
      - image: account-id.dkr.ecr.us-east-1.amazonaws.com/org/repo:0.1
        aws_auth:
          aws_access_key_id: AKIAQWERVA
          aws_secret_access_key: $ECR_AWS_SECRET_ACCESS_KEY
```

- `machine`: CI環境にVMを採用する場合の設定。 `true` を指定した場合、最新バージョンのVMイメージを利用する。
	- `image`: VMイメージの指定

```yaml:sample
jobs:
  build:
    machine: true
```

- `macos`: CI環境にVM(MacOS)を採用する場合の設定。
	- `xcode`: xcodeのバージョン指定

```yaml:sample
jobs:
  build:
    macos:
      xcode: "9.2.0"
```

- `parallelism`: jobを並列実行するコンテナ(VM)数を指定する。デフォルトは1。

```yaml:sample
jobs:
  test:
    docker:
      - image: circleci/golang:1.8
    parallelism: 4
```

#### 実行環境系
- `working_directory`: 実行ディレクトリを設定する。デフォルトは `~/project`

```yaml:sample
jobs:
  build:
    working_directory: ~/work
```

- `checkout`: CI環境上の `working_directory` の値の場所にGitリポジトリをコピーする。

```yaml:sample
steps:
  - checkout
```

- shell: 実行シェルを指定する。`executors` (後述)で指定しても `jobs` に直接指定してもよい。デフォルトは `/bin/sh -eo pipefail`

```yaml:sample
executors:
  sample-executor:
    shell: /bin/bash
```
```yaml:sample
jobs:
  build:
    shell: /bin/bash
```

#### コマンド操作系
- `run`: コマンドを実行する
	- `name`: 任意のrunの名前
	- `command`: コマンドを設定する

```yaml:sample
steps:
  - run:
    name: Test
    command: npm test
```

#### 条件判定系
- `when`: 真ならば実行する
	- `condition`: 条件判定
	- `steps`: (説明省略)
- `unless`: 偽ならば実行する
	- `condition`: (説明省略)
	- `steps`: (説明省略)

```yaml:sample
steps:
  - when:
    condition: <<parameters.custom_checkout>>
    steps:
      - run: echo \"my custom checkout\"
  - unless:
    condition: <<parameters.custom_checkout>>
    steps:
      - checkout
```

#### ファイル操作系
- `restore_cache`: キャッシュが `save_cache` されていればリストアする(あれば速くなる)
	- `key`: リストアするキャッシュを指定する
	- `keys`: リストアするキャッシュを複数指定する
- `save_cache`: パッケージなどのファイルをキャッシュする
	- `key`: キャッシュの名前を設定する
	- `paths`: キャッシュするファイルを指定する
	
key/keysに使用できるテンプレートは以下。

- {{ .Branch }}: 対象のGitのブランチ名
- {{ .Revision }}: 対象のGitのコミットのリビジョン
- {{ .Environment.<環境変数> }}: 環境変数
- {{ checksum "<ファイル名>" }}: ファイルのハッシュ値
- {{ arch }}: OSとCPU情報

```yaml:sample
steps:
  - checkout
  - run:
    name: Update npm
    command: 'sudo npm install -g npm@latest'
  - restore_cache:
    key: dependency-cache-{{ checksum "package.json" }}
  - run:
    name: Install npm wee
    command: npm install
  - save_cache:
    key: dependency-cache-{{ checksum "package.json" }}
    paths:
      - node_modules
```

- `store_artifacts`: ログやカバレッジ、jarファイルなどのバイナリをS3にアップロードして保管する(3GBまで)。アップロードされたファイルはCircleCIのWeb-UI上で確認できる。
	- `path`: アップロードするファイル/ディレクトリのパスを指定する

```yaml:sample
steps:
  - run:
    name: Creating Dummy Artifacts
      command: |
        echo "This is a sample artifact" > /tmp/artifacts;
  - store_artifacts:
      path: /tmp/artifacts
```

- `persist_to_workspace`: 一時的にファイルをjob間で共有できるようにする(最大30日間)
	- `root`: 共有する場所の指定をルートディレクトリ配下のパスで行う
	- `paths`: 共有対象ファイルのパスをrootで指定したパスからの相対パスで指定する
- `attach_workspace`: `persist_to_workspace` で共有されたファイルを取得する
	- `at`: `persist_to_workspace` で指定した `root` の値を指定する

```yaml:persist_to_workspaceのsample
steps:
  - persist_to_workspace:
    root: /tmp/dir
    paths:
      - foo/bar
      - baz
```
```yaml:attach_workspaceのsample
steps:
  - attach_workspace:
    at: /tmp/dir
```

#### DRY(Don't Repeat Yourself)系
ver2.1から導入されたymlファイルをDRYに書くための機能。

- `commands`: jobsで再利用可能なcommandを定義する。関数のように扱える。
	- `<command_name>`: 任意のcommand名を指定する。
		- `description`: 定義するcommandの説明を記載する。
		- `parameters`: commandに与えるパラメータを定義する。
			- `<parameter_name>`: 任意のparameter名を指定する。
				- `type`: 型を定める。string/boolean/enumから選択する。
				- `default`: パラメータのデフォルト値を設定する。
		- `steps`: (説明省略)
			- `run`: (説明省略)

```yaml:sample
commands:
  sayhello:
    description: "A very simple command for demonstration purposes"
    parameters:
      to:
        type: string
        default: "Hello World"
    steps:
      - run: echo << parameters.to >>

jobs:
  myjob:
    docker:
      - image: "circleci/node:9.6.1"
    steps:
      - sayhello:
          to: "James"
```

- `executors`: jobsで再利用可能な実行環境を定義する
	- `<executor_name>`: 任意のexecutor名を指定する
		- `docker`: dockerを使用する場合に指定する
			- (説明省略)
		- `machine`: VMを使用する場合に指定する
			- (説明省略)
		- `macos`: VM(macos)を使用する場合に指定する
			- (説明省略)
		- `shell`: (説明省略)
		- `working_directory`: (説明省略)
		- `environment`: (説明省略)

```yaml:sample
executors:
  my-executor:
    docker:
      - image: circleci/ruby:2.5.1-node-browsers

jobs:
  my-job:
    executor: my-executor
    steps:
      - run: echo outside the executor
```

#### workflows系
ver2.0以降に導入されたビルドパイプライン機能。

##### ビルドパイプラインの種類
- パラレル
	- デフォルト設定。jobがパラレルに実行される。
- シーケンシャル
	- 1つ前のjobの完了を待って次の1つのjobを実行する。 `requires` を利用して実現する。
- ファンアウト
	- 1つ前のjobの完了を待って複数のjobを実行する。 `requires` を利用して実現する。
- ファンイン
	- 複数のjobの完了を待って1つのjobを実行する。 `requires` を利用して実現する。
- スケジューリング
	- 定期実行する(cron)。 `triggers` を利用して実現する。

##### 各workflowのステータス一覧
- RUNNING: 進行中
- NOT RUN: 開始されなかった
- CANCELLED: 進行途中でキャンセルされた
- FAILING: 進行途中でworkflow内のあるjobが失敗している
- FAILED: workflow内の1つ以上のjobが失敗した
- SUCCESS: workflow内の全てのjobが成功した
- ON HOLD: workflow内のあるjobが承認待ち
- NEEDS SETUP: config.ymlに文法的な誤りがある

##### 基本的な書き方
- `workflows`: 1つ以上のワークフローを設定する
	- `version`: (説明省略)
	- `<work_flow_name>`: 任意のワークフロー名
	  - `jobs`: workflowで管理する対象jobの設定をする
	    - `<job_name>`: 対象jobのjob名を指定する

```yaml:sample
workflows:
  version: 2
  sample_workflow:
    jobs:
      - build
```

##### シーケンシャル
- `requires`: 完了前提のjobを指定することでシーケンシャルにする。指定しない場合、jobはパラレルで動作する。
  - `<job_name>`: 完了前提のjob名を指定する

```yaml:sample
jobs:
  - build
  - test1:
    requires: 
      - build
```

上記のsampleでは、test1はbuildが完了するまで実行されない。（これがシーケンシャル）

##### ファンアウト/ファンイン
例えば、ビルドjobが1つ、テストjobが複数、デプロイjobが1つなどの一般的によくあるパターンで、ファンアウト/ファンインを利用すると効率的にCI/CDを回せる。

<img width="629" alt="スクリーンショット 2018-12-28 18.11.08.png" src="https://qiita-image-store.s3.amazonaws.com/0/221948/a8170b0b-8ca1-248a-6cca-658dde7b355e.png">

```yaml:sample
jobs:
  - build
  - acceptance_test_1:
    requires:
      - build
  - acceptance_test_2:
    requires:
      - build
  - acceptance_test_3:
    requires:
      - build
  - acceptance_test_4:
    requires:
      - build
  - deploy:
    requires:
      - acceptance_test_1
      - acceptance_test_2
      - acceptance_test_3
      - acceptance_test_4
```

上記のsampleでは、build⇨acceptance_test_1~4⇨deployでファンアウト/ファンインしている。

##### スケジューリング
- `triggers`: スケジュール指定で実行トリガーを設定する。デフォルトではbranchへpushされたタイミング。
	- `schedule`: UTC時刻でスケジュール設定する
		- `cron`: cron設定

```yaml:sample
triggers:
  - schedule:
    cron: "0 0 * * *"
```
		
##### ブランチ指定/タグ指定
- `filters`: ブランチ名かタグ名で実行条件をつける
	- `branches`: ブランチ名でフィルタリングする
		- `only`: 許可するブランチ名を指定する
			- `<branch_name>`: 任意のブランチ名を指定する
		- `ignore`: 許可しないブランチ名を指定する
			- `<branch_name>`: (説明省略)
	- `tags`: タグ名でフィルタリングする
		- `only`: (説明省略)
		- `ignore`: (説明省略)

```yaml:sample
filters:
  branches:
    only:
      - master
      - develop
```
```yaml:sample
filters:
  tags:
    ignore:
      - 1.0
      - 2.0
```

#### ON HOLD(一時停止)にする
- `type`: `approval` を指定することで次のjobを続けて実行せずに一時停止する。続行するためにはWeb-UI上でApproveボタンを押下する必要がある。

```yaml:sample
jobs:
  - request-testing
    type: approval
  - build
    requires: 
      - request-testing  
  - build-mab-:
    requires: 
      - request-testing
  - build-mab-aws:
    requires:
      - request-testing
  - test-aws:
    requires:
      - build
      - build-mab-
      - build-mab-aws
  - test:
    requires:
      - build
      - build-mab-
      - build-mab-aws
```

`type:approve` のjobが完了すると、statusがON HOLDで一時停止する。

<img width="843" alt="スクリーンショット 2018-12-28 17.37.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/221948/95a15172-4e04-b49f-900e-76f3b9c9e04b.png">

対象jobを押下すると、以下の画面がでてくるため、Approveボタンを押下するとworkflowが続行される。

<img width="823" alt="スクリーンショット 2018-12-28 17.38.26.png" src="https://qiita-image-store.s3.amazonaws.com/0/221948/f0957e38-128c-cef9-ed3d-b44bf30901f9.png">

#### DRYに書く
- `pre-steps`: 指定したjobの実行前に必ず実行するstepを指定する。ver2.1以降で利用可能。
  - `run`: (説明省略)
  - `command`: (説明省略)
- `post-steps`: 指定したjobの実行後に必ず実行するstepを指定するver2.1以降で利用可能。
  - `run`: (説明省略)
  - `command`: (説明省略)

```yaml:sample
version: 2.1
jobs:
  bar:
    machine: true
    steps:
      - checkout
      - run:
        command: echo "building"
      - run:
        command: echo "testing"
workflows:
  build:
    jobs:
      - bar:
        pre-steps:
          - run:
            command: echo "install custom dependency"
        post-steps:
          - run:
            command: echo "upload artifact to s3"
```

# 環境変数
環境変数を利用することで、環境に依存する情報や秘匿情報をソースコードから分離しデプロイを簡単かつ安全に行うことができる。
例えば、環境名やIPアドレス情報、鍵情報などを環境変数として設定する。
環境変数にはCircleCI側で元から用意されているビルドイン環境変数と自分で任意に設定する環境変数の2種類がある。

## ビルドイン環境変数
ビルドイン環境変数で主要なものは以下です。
これらの具体的な値はCircleCIのWeb-UI上の実行結果などから確認できます。

- CI: CI環境であるかどうか
- CIRCLE_BRANCH: Gitのブランチ名
- CIRCLE_BUILD_NUM: プロジェクト内のビルド番号
- CIRCLE_PROJECT_REPONAME: Gitのリポジトリ名
- CIRCLE_SHA1: Gitの最終コミットのハッシュ値
- CIRCLE_NODE_TOTAL: インスタンスの数
- CIRCLE_NODE_INDEX: インスタンスの番号(0から始まる)

## 自分で設定する環境変数
設定方法は `config.yml` で設定する方法とWeb-UIで設定する方法の2通りがある。

### config.ymlで設定する場合
`environment` で環境変数の設定をする。
jobs配下でもsteps配下でもdocker配下でも色々なところで宣言可能。

```yaml
jobs:
  build:
    environment:
      FOO: bar
```

### Web-UIで設定する場合
`プロジェクト設定のBUILD SETTINGS > Environment Variables > Add Variable` から設定する。
秘匿情報の場合は、config.ymlではGitで公開されてしまうためWeb-UIで設定する。

# 動かしてみる
## ローカルで動かしてみる
CircleCIはローカル環境でも実行可能。
`config.yml` の文法チェック、jobの動作確認などをわざわざリモートリポジトリにpushしなくてもローカルで手軽に確認できる。
ここでの動作環境はMacOSを前提とします。

### (Step1) Dockerインストール
動作環境用にDockerを[公式サイト](https://store.docker.com/editions/community/docker-ce-desktop-mac)にしたがってインストールしてください。

### (Step2) CircleCIインストール
```console
$ curl https://raw.githubusercontent.com/CircleCI-Public/circleci-cli/master/install.sh --fail --show-error |bash
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  1309  100  1309    0     0   1225      0  0:00:01  0:00:01 --:--:--  1225
Installing CircleCI CLI
Finding latest release.
Downloading CircleCI v0.1.4427
Installing to /usr/local/bin
/usr/local/bin/circleci

$ circleci update check
Already up-to-date.
```

### (Step3) config.yml作成
今回は動作確認用に、golangのDockerイメージを使って、単にechoするだけの簡単なconfig.ymlの例です。

```console
$ mkdir .circleci

$ vi .circleci/config.yml
version: 2
jobs:
  build:
    docker:
      - image: circleci/golang:1.11.2
    steps:
      - run: echo "hello world"
```

### (Step4) CircleCI動作確認
まずは文法チェック。問題ないことを確認。

```console
$ circleci config validate
Config file at .circleci/config.yml is valid.
```

蛇足ですが、動作中のコンテナは存在せず、Dockerイメージも無い状態であることを確認。

```console
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
```

ローカルでcircleci実行。

```console
$ circleci local execute
(省略)
Using build environment variables:
  BASH_ENV=/tmp/.bash_env-localbuild-1544496655
  CI=true
  CIRCLECI=true
  CIRCLE_BRANCH=
  CIRCLE_BUILD_NUM=
  CIRCLE_JOB=build
  CIRCLE_NODE_INDEX=0
  CIRCLE_NODE_TOTAL=1
  CIRCLE_REPOSITORY_URL=
  CIRCLE_SHA1=
  CIRCLE_SHELL_ENV=/tmp/.bash_env-localbuild-1544496655
  CIRCLE_WORKING_DIRECTORY=~/project

====>> echo "hello world"
  #!/bin/bash -eo pipefail
echo "hello world"
hello world
Success!
```

見事、成功！
蛇足ですが、circleci実行中にコンテナが起動し、実行完了後は消えたことを確認できた。

```console:CI実行中
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS               NAMES
fe36f90355b9        circleci/picard     "circleci build"    About a minute ago   Up About a minute                       stoic_noyce
```
```console:CI実行完了後
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
```

蛇足ですが、Dockerイメージが増えていることが確認できた。

```console
$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
circleci/golang     1.11.2              30d34aa355de        3 hours ago         1.13GB
circleci/picard     <none>              b1f2c41821a8        3 days ago          83.8MB
```

## GitHubとCircleCIを連携して動かす
基本的に[こちらの記事](http://tweeeety.hateblo.jp/entry/2018/02/09/195345)に沿って説明していきます。
golangで簡単な関数とUTを実装し、CI/CDする簡単な例です。

### (Step1)設定
#### [必須]初期設定
GitとCircleCIの連携に関する初期設定は多くの記事で紹介されているので省略します。
基本的には、Authorizeして、Gitのリポジトリごとに対応するCircleCIのプロジェクトを作成するだけです。

#### [任意]CIに成功しないとマージができないようにしたい(GitHub側の設定)
こちらは、CircleCIというよりGitHub上で行う設定ですが、よく利用すると思いますので掲載しておきます。

- `Braches > Branch protection rule` へ移動
- `Apply rule to` にブランチ名を入力
- `Require status checks to pass before merging` と `Require branches to be up to date before merging` にチェックをつける

<img width="1051" alt="スクリーンショット 2018-12-13 17.13.28.png" src="https://qiita-image-store.s3.amazonaws.com/0/221948/264cd833-615a-fed7-76ca-4efdd2877c5e.png">

#### [任意]Slack連携
設定方法は[こちらの記事](https://qiita.com/su-kun1899/items/640f6fa8b48749396c16#slack%E5%81%B4%E3%81%AE%E8%A8%AD%E5%AE%9A)に譲ります。
上記の設定により、ビルド結果の通知は自動で行われます。
ただし、デプロイ結果の通知は別途、下記のようにconfig.ymlのjobsに定義が必要です。(workflowのrequiresも要)

```yaml
jobs:
  deploy_notify:
    executor: default
      steps:
        - run:
          name: デプロイ通知
          command: |
            curl -X POST -H 'Content-type: application/json' --data \
            "{'text': 'DEPLOY DONE! ${CIRCLE_PROJECT_REPONAME}'" \
            ${SLACK_WEBHOOK_URL} 
```

### (Step2)対象コードを書く
単純にGolangで文字列を返すだけの関数です。

```go:sample01.go
package sample01

func HelloWorld(s string) string {
  return "hello world, " + s
}
```

上記の関数が期待通りのレスポンスをするかを確認するUTです。

```go:sample01_test.go
package sample01

import (
  "testing"
)

func TestHelloWorld(t *testing.T) {
  actual := HelloWorld("hoge")
  expected := "hello world, hoge"
  if actual != expected {
    t.Errorf("actual %v\nwant %v", actual, expected)
  }
}
```

### (Step3)config.ymlを書く
基本的に、公式サイドのサンプルそのままですが、 `working_directory` の値は適切なものに編集します。

```yaml
version: 2
jobs:
  build:
    docker:
      - image: circleci/golang:1.8
    working_directory: /go/src/github.com/gold-kou/go-test-circleci-sample
    steps:
      - checkout
      - run: go get -v -t -d ./...
      - run: go test -v ./...
```

### (Step4)pull-request作成してCIを走らせる
pull-requestを作成すると、自動でUTが実行されます。
UTが正常に完了していれば、下記の通り `All checks have passed` となり、マージ可能となる。
これは、GitHubとCircleCIが連携し、pull-requestされるとCircleCIが `config.yml` を自動で読み込むから。CIって素晴らしい！！！
pull-request作成後は、push契機でCI/CDが走る。

<img width="782" alt="スクリーンショット 2018-12-27 16.41.45.png" src="https://qiita-image-store.s3.amazonaws.com/0/221948/93946fa4-6a0f-853f-8ed4-c445b7920528.png">

# その他Tips
## CIをスキップしたい
ソースコードに関係のない変更(例えばREADME.mdの編集)をpushした時など、pushしたけどCIを実行したくない場合がある。
2通りの方法がある。

### Gitのコミットメッセージで指定する方法
Gitのコミットメッセージに[ci skip]あるいは[skip ci]を埋め込む。

```console
$ git commit -m "<コミットメッセージ> [ci skip]"
```

### Web-UIで指定する方法
`プロジェクトの設定(歯車) > BUILD SETTINGS > Advanced Settings > Auto-cancel rudundant buildsをON`

<img width="1409" alt="スクリーンショット 2018-12-13 14.47.30.png" src="https://qiita-image-store.s3.amazonaws.com/0/221948/f3d8243a-d492-3dda-8c16-e97ce62af434.png">

## CI再実行したい
該当Jobで `Rerun workflow` を押下する。

<img width="1417" alt="スクリーンショット 2018-12-13 14.40.06.png" src="https://qiita-image-store.s3.amazonaws.com/0/221948/e7b0bd78-77b3-207a-1cf3-ee6dd814da45.png">

## CI実行したコンテナにSSHしたい
デバッグなどを目的にコンテナに入りたい場合もある。
Web-UIで該当jobで以下の操作方法で10分間SSHが可能になる。
`Rerun workflow > Rerun job with SSH`

<img width="1403" alt="スクリーンショット 2018-12-13 14.57.45.png" src="https://qiita-image-store.s3.amazonaws.com/0/221948/a44a62ce-2468-e18e-26d1-42b9b941d4d6.png">

画面が切り替わり、ポート番号とIPアドレスが併記されたSSHコマンドが案内されるため、鍵が適切に設定されていればSSHできる。

# まとめと感想
- CircleCIはSaas型のため始めるハードルが低い
- 個人開発では無料枠で充分そう
- `config.yml` の文法を覚える学習ハードルがある。とはいえJenkinsの職人芸よりはマシそう。
- ver2.0で大きく変わった模様。2.1でも新機能がいくつか追加され、まだまだ成長途中である印象を受けた。特に、 `config.yml` の記載方法は今後も大きく変わる予感を感じた。例えば、よりDRYに書くための機能やenvファイルの切り出し、ファイル分割などは今後追加されていくのではないだろうか。

# さらにCircleCI力を高める
[Qiitaのアドベントカレンダー](https://qiita.com/advent-calendar/2018/circleci)では実践例やこの記事ではとりあげなかった機能の説明、マイナーな話がされていたりするので、いろいろ見てみるとよさそう。
今後、学んだことあれば、追記していきます。

# 参考
- [CircleCI公式ドキュメント](https://circleci.com/docs/)
- WEB+DB PRESS Vol.107「実践CircleCI」
- [【CircleCI】CircleCI 2.0からはじめる個人での簡単なCI導入方法 - githubとの連携まで](http://tweeeety.hateblo.jp/entry/2018/02/09/195345)
- [まだ間に合う！CircleCI 2.0へ移行する](https://qiita.com/hitsuji-haneta/items/821c91619b3ddb9981d8)