昨日、CircleCIで失敗したテストのファイル一覧を取得するという記事を書きました。
今度はそれを使って、CircleCIで前に落ちたテストを先に検証するワークフローを組みました。
こんな感じです。
何故そうしたのか?
以前に落ちたテストはまた落ちる可能性が高い、と感じています。全体テストを流すと結果が出るまで長時間かかりますが、以前に落ちたところだけ流すのは数分で済みます。そして、落ちたらそこでテストは終了するので、時間の節約ができる!と思ったわけです。
もし再テストを通過したら全体テストが行われます。そうなると、再テストの後に全体テストとなるので、その分時間はかかります。
CircleCIの設定を行なう
ワークフローを組む
まずは先にワークフローの部分を書いていきます。
version: 2.1 # jobの設定などは後述 workflows: build: jobs: - prepare_test - retry_failed_test: requires: - prepare_test - test: requires: - retry_failed_test
全体テストのジョブ(test)のrequiresに再テストのジョブ(retry_failed_test)を指定しているので、再テストが失敗したら全体テストは流れなくなります。
retry_failed_testを定義する
では、該当ジョブを定義します。
version: 2.1 # executors, commandsは省略 jobs: # prepare_test, testは省略 retry_failed_test: executor: rspec parallelism: 4 steps: - restore_code_cache - run: bundle --path vendor/bundle - run: bundle exec chromedriver-update - setup_database - run: name: Run failed tests if exists command: | FAILED_FILES=$(bin/rails runner script/circleci_failed_spec_files.rb --line) if [ -n "$FAILED_FILES" ]; then TEST_FILES=$(echo -e "$FAILED_FILES" | circleci tests split --split-by=filesize) if [ -n "$TEST_FILES" ]; then bin/rspec ${TEST_FILES} fi fi - store_test_results: path: tmp/test-results - store_artifacts: path: /tmp/test-results destination: test-results
該当箇所の説明
肝の箇所はここです。
- run: name: Run failed tests if exists command: | FAILED_FILES=$(bin/rails runner script/circleci_failed_spec_files.rb --line) if [ -n "$FAILED_FILES" ]; then TEST_FILES=$(echo -e "$FAILED_FILES" | circleci tests split --split-by=filesize) if [ -n "$TEST_FILES" ]; then bin/rspec ${TEST_FILES} fi fi
- 以前のテストで失敗したファイルがあれば、ファイル名を行毎に出力したものを変数
FAILED_FILES
に入れる $FAILED_FILES
の中身がなければ何もせず終了。$FAILED_FILES
の中身があれば、落ちたテスト一覧を並列テストするために内容をecho -e
で出力して、その結果をpipeでcircleci tests split --split-by=filesize
に渡します(--split-byの指定はお好きに変更を)。そうすることで、コンテナ毎にテスト対象ファイル名が変数TEST_FIELS
に配布されます。$TEST_FILES
の中身がなければ、そのコンテナでは何もせず終了。$TEST_FILES
の中身があれば、テストを実行。
感想
テストは全体では15分くらいかかるようになってしまいましたが、retry_failed_testのところで落ちたら5分で終わるようになったので、いいかなと思います。もし新規ブランチで初のテストの場合は落ちたテストがないのでretry_faile_testのジョブも1分くらいで終了しますし、問題ないくらいかなと思います。