##背景
私の会社のアプリケーションは、大きくclient/*
とserver/*
に分かれており(SPA構成)、GitHubにpushするごとに全てのテストを回していました。
しかし、テストの量が多くなっていくにつれ、CIが通るまで1回あたりに10分程度かかるようになってしまいました。
そこで、client/*
とserver/*
のうち、変更があった方(両方変更があったなら両方)のテストのみを回せば効率化できるだろうということで色々記事を探したのですが、意外とハマったりしたので記事にしました。
##今までの実装
CircleCI2.0で登場したworkflows
を使って以下のように実装していました。
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することができれば一番いいのですが、どうやら無理らしいです。)
#!/bin/bash
# Database setup
# run tests
#!/bin/bash
# install packages
# test
##stepsでシェルスクリプトを実行する
jobs:
build_client:
docker:
xxx
working_directory: xxx
steps:
- checkout
- run:
name: tests
command: |
if # clientに変更があれば
bash .circleci/build_client.sh
fi
##変更の有無によって条件分岐する
はじめ、以下のように実装しました。
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ではなくブランチを比較してテストを回すことになりました。
実行は以下の通りです。
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がサクサク回るので快適です!