LoginSignup
19
14

More than 5 years have passed since last update.

CircleCI効率化

Last updated at Posted at 2018-03-07

背景

私の会社のアプリケーションは、大きくclient/*server/*に分かれており(SPA構成)、GitHubにpushするごとに全てのテストを回していました。
しかし、テストの量が多くなっていくにつれ、CIが通るまで1回あたりに10分程度かかるようになってしまいました。
そこで、client/*server/*のうち、変更があった方(両方変更があったなら両方)のテストのみを回せば効率化できるだろうということで色々記事を探したのですが、意外とハマったりしたので記事にしました。

今までの実装

CircleCI2.0で登場したworkflowsを使って以下のように実装していました。

.circleci/config.yml
version: 2

jobs:
  build_client:
    docker:
      xxx
    working_directory: xxx
    steps:
      # パッケージのインストール...
            # テスト...etc

  build_server:
    docker:
      xxx
    working_directory: xxx
    steps:
      # パッケージのインストール...
            # テスト...etc

workflows:
  version: 2
  build-all:
    jobs:
      - build_client:
          filters:
            xxx
      - build_server:
          filters:
            xxx

このコードを
・stepsでの実行コマンドを別スクリプトに移す
・stepsで↑のシェルスクリプトを実行する
・変更の有無によって条件分岐する(ハマりポイント)
ことで、効率化を図りました。

実行コマンドを別スクリプトに移す

以下の2つのファイルを作成しました。
全ての工程を移すのではなく、特に時間のかかっていた工程を移しました。
(job自体をskipすることができれば一番いいのですが、どうやら無理らしいです。)

build_server.sh
#!/bin/bash

# Database setup
# run tests
build_client.sh
#!/bin/bash

# install packages
# test

stepsでシェルスクリプトを実行する

.circleci/config.yml
jobs:
  build_client:
    docker:
      xxx
    working_directory: xxx
    steps:
      - checkout

      - run:
          name: tests
          command: |
            if # clientに変更があれば
              bash .circleci/build_client.sh
            fi

変更の有無によって条件分岐する

はじめ、以下のように実装しました。

.circleci/config.yml
jobs:
  build_client:
    docker:
      xxx
    working_directory: xxx
    steps:
      - checkout

      - run:
          name: tests
          command: |
            compare_url=$CIRCLE_COMPARE_URL
            compare_ids=${compare_url##*/}
            diff=$(git diff --name-only $compare_ids)

            if [[ "${diff}" =~ client/ ]] ; then
              bash .circleci/build_client.sh
            else
              echo 'skip client test'
            fi

CircleCIには環境変数が与えられていて、CIRCLE_COMPARE_URLもその1つです。
これには、https://github.com/xxx/xxx/compare/yyy...zzzというような値が入っています。
ここから比較すべきコミットID(yyyとzzz)を取り出し、変更ファイル名を見てclient/があればシェルスクリプトを実行、なければskipという意図でした。

大抵はうまくいったのですが、たまにCIRCLE_COMPARE_URLの値が
https://github.com/xxx/xxx/commit/yyyのようになっていることがあり、うまくdiffを取り出せないことがありました。
(原因はわかっていません。ご存知の方がいましたらコメント欄にてご指摘いただければと思います。)

改善

結局、コミットIDではなくブランチを比較してテストを回すことになりました。
実行は以下の通りです。

.circleci/config.yml
jobs:
  build_client:
    docker:
      xxx
    working_directory: xxx
    steps:
      - checkout

      - run:
          name: tests
          command: |
            branch=$CIRCLE_BRANCH
            diff=$(git diff --name-only origin/develop...${branch})

            if [[ "${diff}" =~ client/ ]] ; then
              bash .circleci/build_client.sh
            else
              echo 'skip client test'
            fi

何はともあれ、回す必要のないテストをskipすることで、CIがサクサク回るので快適です!

19
14
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
14