【CircleCi】CICD構築 パイプラインの書き方備忘録

## はじめに
CICD導入で学んだことを備忘録として残しておく。
主にパイプラインの書き方の部分のフォーカスして記載。

※この記事は特に、モバイルアプリのE2Eテスト自動化のパイプラインを作成した時の備忘録。

yaml全体は以下の通り。

```yaml:sample.yml
version: 2.1

workflows:
  e2e:
    jobs:
      - check

      - run_test_android:
          requires:
            - check

      - run_test_ios:
          requires:
            - check

executors:
  android:
    machine:
      image: android:202102-01
    working_directory: "~/automation-test"
  ios:
    macos:
      xcode: 12.5.1
    working_directory: "~/automation-test"

jobs:
  # check job
  check:
    docker:
      - image: cimg/base:2021.04
    steps:
      - run_check

  # run_test_android job
  run_test_android:
    executor: android
    steps:
      - checkout
      - run_test:
          os: "android"

  # run_test_ios job
  run_test_ios:
    executor: ios
    steps:
      - checkout
      - run_test:
          os: "ios"

commands:
  # run_check command
  run_check:
    steps:
      - run:
          name: チェック
          command: |
            echo "hoge"

  # run_test command
  run_test:
    parameters:
      os:
        type: string
    steps:
      - when:
          condition:
            equal: ["ios", << parameters.os >>]
          steps:
            - run:
                name: iOS用の設定
                command: |
                  echo "hoge"

      - run:
          name: Appiumのインストール及び起動
          command: |
            npm install -g appium
            appium
          background: true

      - run:
          name: テスト実行
          no_output_timeout: 2h
          command: |
            echo "hoge"

      - run:
          name: レポート生成
          command: |
            echo "hoge"
          when: always

```

## パイプラインの中身の詳細
### executorの定義
[^executor]: https://circleci.com/docs/ja/2.0/executor-types/
CircleCI上に構築するコンテナの種類を設定するもの。[^executor]

```yaml:sample.yaml
executors:
  android:
    machine:
      image: android:202102-01
    working_directory: "~/automation-test"
  ios:
    macos:
      xcode: 12.5.1
    working_directory: "~/automation-test"
```

上記の例はCircleCiを用いてモバイルアプリのテスト自動化を行った際の設定であり、そのテスト自動化では、


- Android<br>emulator（AVD(Android仮想デバイス)）を起動しE2Eを実行[^1]
- iOS<br>emulator（Xcode）を起動しE2Eを実行[^2]

という2つ実行環境を用意してE2Eテストを実行していた
[^1]: https://circleci.com/docs/2.0/android-machine-image/#no-orb-example
[^2]: https://circleci.com/docs/2.0/testing-ios/#example-configuration-for-using-fastlane-on-circleci

### workflowsの定義
CircleCIのworkflowsはそれぞれのjobをどんな順番で実行するのか？を定義するもので、CircleCI公式のページで図示されているので詳細は[そちらを参照](https://circleci.com/docs/ja/2.0/workflows/)

```yaml:sample.yaml
workflows:
  e2e:
    jobs:
      - check

      # テスト実行(Android)
      - run_test_android:
          requires:
            - check

      # テスト実行(iOS)
      - run_test_ios:
          requires:
            - check
```

上記では、checkというjobの実行が成功であればe2eの自動テストを実行するような設定になっている。

### job実行時のexecutorの指定, checkout
```yaml:sample.yml
run_test_android:
  executor: android
  steps:
    - checkout
    - run_test:
        os: "android"

run_test_ios:
  executor: ios
  steps:
    - checkout
    - run_test:
        os: "ios"
```

#### job実行時のexecutorの指定
job実行時にどのexecutorを使うか？を`executor: `で指定する。
上記の例では[executorの設定](#executorの設定)で定義していた`android`という名前のexecutorを指定している。

#### checkout
リポジトリをチェックアウトし、ワークフロー(Runner)がリポジトリにアクセスできるようにする。
上記の例では`- checkout`の部分が実際にcheckoutを行っている箇所で、それに続く`- run_test`は[次のセクション「commandsの設定」](#commandsの設定)で扱っているcommandsに定義されたジョブ内で実行する一連のステップを実行している。

### commandsの設定
[^3]: https://circleci.com/docs/ja/2.0/configuration-reference/#commands-requires-version-21
workflowsのjobs内で実行するひとまとまりの処理内容（一連のステップ）を定義でき、これによりパイプライン内でDRY原則を守るようなyamlの書き方ができる。[^3]

```yaml:sample.yaml
commands:
  run_test:
    parameters:
      os:
        type: string
    steps:
      - when:
          condition:
            equal: [ "ios", << parameters.os >> ]
          steps:
            - run:
                name: iOSの設定
                command: |
                  echo "hoge"

      - run:
          name: Appiumのインストール及び起動
          command: |
            npm install -g appium
            appium
          background: true

      - run:
          name: テスト実行
          no_output_timeout: 2h
          command: |
            echo "hoge"

      - run:
          name: レポート生成
          command: |
            echo "hoge"
          when: always
```
[^4]: https://circleci.com/docs/2.0/configuration-reference/#logic-statement-examples
以下の記述では、各ステップの実行に条件を付けて特定の条件の時だけそのステップを実行するようにしている。[^4]

```
- when:
    condition:
      equal: [ "ios", << parameters.os >> ]
```

※上記の例では実際にテスト実行を行うbashコマンドは記述せず、`echo "hoge"`にしている。