CircleCI 2.1のすゝめ


# はじめに

CircleCIは開発・運用を効率化してくれる自動化サービスです。
githubやbitbucketと連携させ、指定したブランチに更新があった時点で自動でビルドやテスト、デプロイなどの実行ができます。
2.1を使ったことがなかったので、新機能を調べてみました。
※ CircleCI2.0までを知っている方向けの記事になります

# CircleCI 2.1

* 2018年末、 2.0 -> 2.1 にアップグレード
* DRYに設定ファイルを記述するには、yaml記法では限界があった
* **冗長な `jobs` の記述をシンプルにできる** :sparkles: 
* これまでと性能的な違いはない
* **2.0からの移行が簡単** :smiley: 
  * CircleCIの設定画面で新しいパイプラインを有効にする([Advanced (詳細設定)] セクションの下部)
  * 既存の `config.yml` で `version: 2.0` を `2.1` にするだけ!
  * 2.0から廃止された機能はないので使って損なし!!


# 新機能 :tada:
* commands
* executors
* parameters
* when ステップ
* orbs



## commands
jobs内で実行する__steps内で再利用できる__コマンドを定義します


```yaml

commands:
  bundle-install:
    description: "バンドルをインストールするコマンド"
    steps:
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "Gemfile.lock" }}
            # fallback to using the latest cache if no exact match is found
            - v1-dependencies-
      - run: bundle install --path vendor/bundle
      - save_cache:
          key: v1-dependencies-{{ checksum "Gemfile.lock" }}
          paths:
            - vendor/bundle

jobs:
  my-job:
    steps:
      - checkout
      - bundle-install # コマンドで定義した処理が実行される
```

| キー | 必須 | 型 | 
|:--|:--|:--|
| steps | ○ | Sequence | 
| parameters | - | Map |
| description | - | String | 


## executors
stepsを実行するための**環境**を定義します

```yaml

executors:
  frontend_executor:
    working_directory: ~/app
    environment:
      DIST_DIR: public
    docker:
      - image: circleci/node:10.16.0

jobs:
  frontend-build:
    executor: frontend_executor
    steps:
      - checkout
      - run: ...
```

| キー | 必須 | 型 | 
|:--|:--|:--|
| docker | ○(1) | List | 
| resource_class | - | String | 
| machine | ○(1) | Map | 
| macos | ○(1) | Map | 
| shell | - | String | 
| working_directory | - | String | 
| environment | - | Map | 

※ ○(1)のうち1つは必須


## parameters
parametersを使うことで、**部分的な出し分け**が可能になります。
jobs, commands, executors の直下で宣言します。


```yaml

commands:
  say-hello:
    description: "デモ用のごく簡単なコマンド"
    parameters:
      to:
        type: string
        default: "Hello World"
    steps:
      - run: echo << parameters.to >>
jobs:
  my-job:
    steps:
      - say-hello:
          to: "こんにちは世界"
```

|キー名|必須|型|
|:--|:--|:--|
|description|-|string|
|type※|○|string|
|default|-|typeで指定した型の値|


### ※ type

* 文字列
* ブール値
* 整数
* 列挙
* Executor
* ステップ
* 環境変数名

cf. https://circleci.com/docs/ja/2.0/reusing-config/#%E3%83%91%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%BF%E3%83%BC%E5%9E%8B


## when ステップ
条件付きステップを使用すると、条件が満たされた場合にのみ実行されるステップを定義できます。
ワークフローが実際に実行される前に評価されるので注意です。

```yaml

jobs:
  my-job:
    steps:
      - when:
         condition: << parameters.preinstall-foo >>
         steps:
            - run: echo "preinstall"
      - unless:
          condition: << parameters.preinstall-foo >>
          steps:
            - run: echo "don't preinstall"
```

## orbs
CircleCI2.1の目玉機能！
commands, jobs, executorsで構成されるコンフィグパッケージ
CircleCI公認のもの、パートナー企業によるサードパーティ製のもの、自分で自作することもでき、ソースコードはすべて公開されています。

例えば [circleci/aws\-s3](https://circleci.com/orbs/registry/orb/circleci/aws-s3) を使うとこうなります。

```yaml
orbs:
  aws-s3: circleci/aws-s3@1.0.11
  
jobs:
  my-job:
    steps:
      - aws-s3/sync:
          from: "public"
          to: "s3://hoge-dev"
          overwrite: true
```

CircleCI公認のOrbsはこちら :eyes:
https://circleci.com/orbs/registry/


# Before / After

stagingとproduction、それぞれ別のS3バケットにアップロードする設定ファイルを比較してみましょう！

## Before
```yaml
version: 2.0

jobs:
  sync_s3:
    docker:
      - image: xueshanf/awscli
        environment:
          BUCKET_NAME_PRODUCTION: sample-production
          BUCKET_NAME_STAGING: sample-staging
          ROOT_DIR: public
    steps:
      - checkout
      - deploy:
          name: Upload S3
          command: |
            if [ $CIRCLE_BRANCH == "production" ]; then
              aws s3 sync --exact-timestamps --exclude "**/.*" --delete $ROOT_DIR s3://$BUCKET_NAME_PRODUCTION
            fi
            if [ $CIRCLE_BRANCH == "staging" ]; then
              aws s3 sync --exact-timestamps --exclude "**/.*" --delete $ROOT_DIR s3://$BUCKET_NAME_STAGING
            fi

workflows:
  version: 2
  build_deploy:
    jobs:
      - sync_s3:
          filters:
            branches:
              only:
                - production
                - staging
```

## After
```yaml
version: 2.1

orbs:
  aws-s3: circleci/aws-s3@1.0.11

jobs:
 sync_s3:
    parameters:
      bucket_name:
        type: string
    steps:
      - aws-s3/sync:
          from: "public"
          to: "s3://<< parameters.bucket_name >>"
          overwrite: true
          arguments: --exact-timestamps --exclude "**/.*"

workflows:
  version: 2
  build_deploy:
    jobs:
      - sync_s3:
          bucket_name: sample-staging
          filters:
            branches:
              only:
                - staging
      - sync_s3:
          bucket_name: sample-production
          filters:
            branches:
              only:
                - production
```

記述量は少し増えましたが、かなり読みやすくなった気がします。
より複雑な構成だと更に効果を発揮しそうです。

# おまけ
circleCI ローカルCLI をインストールすると、 2.1 -> 2.0 の変換もできます。

```bash
$ circleci config process .circleci/config.yml > past-config.yml
```
[CircleCI のローカル CLI の使用 \- CircleCI](https://circleci.com/docs/ja/2.0/local-cli/)

# 参考サイト
- [CircleCI を設定する \- CircleCI](https://circleci.com/docs/ja/2.0/configuration-reference/#commandsversion21-%E3%81%8C%E5%BF%85%E9%A0%88)
- [コンフィグの再利用 \- CircleCI](https://circleci.com/docs/ja/2.0/reusing-config/#section=configuration)

- [Orbs を使う \- CircleCI](https://circleci.com/docs/ja/2.0/using-orbs/#section=configuration)