Circle CIを使い始めてみた

Circle CIを使い始めてみました。
運用方法はあんまりよくないと思いますが備忘録がてら。

# アカウント作成
GitHubかBitbucketでログインできる。
CIしたいリポジトリをホストしてるアカウントでログインする。

両方使ってる人はひとつのCircle CIアカウントにGitHubもBitbuketも連携できる。
一度Circle CIのアカウントに連携してしまうと自分で解除することができず、お問い合わせ案件になってしまう。

GitHubとBitbucketで別のアカウントにしてしまったぼくはそうなってしまいまして...

# 使うマシンを選ぶ
dockerイメージを使うか、物理マシンを使うか選べる。
物理マシンにもバージョンが色々ある。

`jobs/build`のところに指定する。

[Executor タイプの選び方 - CircleCI](https://circleci.com/docs/ja/2.0/executor-types/#section=configuration)

# .circleci/config.ymlを作る
`.circleci`ディレクトリはその名の通り、Circle CIの設定ファイルとかを置くディレクトリになるっぽい。`config.yml`はビルドしたりテストしたりするコンテナの設定をするっぽい。

手持ちのNuxt × Firebaseのプロジェクトで、こんなのを書いてみた。

```yml
version: 2.1
jobs:
  build:
    machine: true
    steps:
      - run:
          name: Installing Docker Compose
          command: |
            curl -L https://github.com/docker/compose/releases/download/1.19.0/docker-compose-`uname -s`-`uname -m` > ~/docker-compose
            chmod +x ~/docker-compose
            sudo mv ~/docker-compose /usr/local/bin/docker-compose
      - checkout
      - run:
          name: docker-compose up
          command: |
              set -x
              docker-compose up --build -d
      - run:
          name: docker-compose up
          command: |
              set -x
              docker-compose up --build -d
      - run:
          name: run all tests
          command: docker exec -t nodejs_app_1 npm run ftest
      - run:
          name: docker-compose down
          command: docker-compose down
          
```

うごくかな。
## -checkout
Gitからコードをクローンしてくる決り文句

## run
コマンド実行

# ローカルにCircle CIをインストール
コピペしてインストールしよう。

```
curl https://raw.githubusercontent.com/CircleCI-Public/circleci-cli/master/install.sh --fail --show-error |bash
```

これは全然関係ないお小言なんだけど、Dockerを知ってからマシンに何かをインストールするのをすごくためらわれるようになった。

# 文法チェックをしてみる
さっきので`circleci`コマンドが使えるようになったんだって。
コマンド使って、`.circleci/config.yml`の文法チェックをしてみよう。

```
circleci config validate
```

実行してみると、アップデートを確認して少しの間、虚無に待たされる。
...どんな処理をしているんだろう。

# いざ、ローカルで実行！
`circleci`コマンドを使うよ〜

```
circleci execute local
```

...できると思うじゃん？
`version: 2.1`だとローカル実行まだできないんだって...

なので、`version: 2`形式に変換してもらって、それをローカルで実行してみる。

```zsh
# 変換
circleci config process .circleci/config.yml > .circleci/process.yml

# ローカル実行
circleci local execute -c .circleci/process.yml
```

`-c`で設定ファイルのパスを指定できるっぽいね。

[CircleCI 2.1 の job をローカルの CLI で実行する - Qiita](https://qiita.com/keiichi4e/items/433b613f592e7869ca9b)

**すいません。なんかローカルで実行やれません。
おそらく`machine executor`を指定しているからだと思います。

# リモートで試してみよう
- Circle CIのwebページにログイン
- プロジェクトを選んで「Start building」を押す
    - 「Is you config.yml added?」って聞かれる。さっき作ったので青いボタンをクリック
- まず、masterブランチのビルドが始まる
    - masterブランチに`.circleci/config.yml」を作ったならすぐに始まる
    - そうでない場合、エラーが帰る
- お好みのブランチで`.circleci/config.yml`を編集して、pushするとビルドしてくれる！

思ったより簡単。
あと、無料プランの限界ビルド時間は**500 min/week**[^1]。

[^1]: 週に与えられるクレジットが2,500。マシンがSmallのときは5 credit/min、Mediumだと10 credit/min。[料金プラン - CircleCI](https://circleci.com/ja/pricing/)

# テスト結果とかを出力
`store_test_results`と`store_artifacts`ステップを設定するとテスト結果をweb上でいい感じに確認できるようになる。

```yaml:.circleci/config.yml
- run:
    name: run all tests
    command: |
        docker exec -it php_app_1 php /var/www/app/vendor/bin/phpunit --log-junit ~/junit.xml /var/www/app/tests
        mkdir ~/phpunit
        docker exec -it php_app_1 cat ~/junit.xml > ~/phpunit/junit.xml
- store_test_results:
    path: ~/phpunit
- store_artifacts:
    path: ~/phpunit
```

PHPUnitの`--log-junit`オプションによって、JUnitの形式でテスト結果ファイルが生成される。
Circle CI上でDockerを動かしていて、コンテナ内に生成されてしまうので、それをリダイレクションでホスト環境へ出している。

`store_test_results`と`store_artifacts`ではテスト結果が配置されているディレクトリを指定してやれば良い。

JUnitの形式で出力できればどんなテストフレームワークでも使えそう。

## 前のステップが失敗していると、それ以降のステップは実行されなくなる
テストが失敗していようがいまいがテスト結果ファイルはほしい。

そういうときは`when: always`とかを指定する。

```yaml:.circleci/config.yml
- run:
    name: export test summary file
    when: always
    command: ...
```

あと、コマンドを複数行指定しているときも、途中で失敗するとそれ以降のコマンドは実行されなくなってしまう。

これを防ぐには`set +e`するか、利用するシェルを上書き指定する。
シェルに対してデフォルトで`set -e`が指定されていて、これにより失敗すると止まってしまうらしい。

```yaml:.circleci/config.yml
- run:
    shell: /bin/bash
    name: dont exit
    command: |
        echo 'hello world!'
        ...
- run:
    name: dont exit
    command: |
        set +e
        echo 'hello world!'
        ...
```

# 参考
[いまさらだけどCircleCIに入門したので分かりやすくまとめてみた - Qiita](https://qiita.com/gold-kou/items/4c7e62434af455e977c2#%E5%BF%85%E9%A0%88%E3%82%AD%E3%83%BC)
[CircleCIでdocker-composeは最強 - Qiita](https://qiita.com/walkers/items/352057493c7c8907b83f)

[Circle CI 2.0でステップが失敗しても次のステップを実行したい](https://blog.sshn.me/posts/circleci-when-attribute/)
[テストメタデータの収集 - CircleCI](https://circleci.com/docs/ja/2.0/collect-test-data/#jest)

# わかってないこと
- `set -x`って何
- Dockerイメージをそのまま運用するベストプラクティスがわからない
    - この方法だと後々追加料金がかかるかもしれないらしい
    - node環境が欲しいだけならDockerfileをstepsにすればいい
    - コンテナを2つ動かしたいときとかどうするんだろう？