patorashのブログ

方向性はまだない

CircleCIからテストが失敗したファイル一覧を取得するRails Runner作った

表題の通りですが、作りました。

CircleCIで失敗したテストをローカルで流したいのだけれど、わざわざCircleCIのページを見に行くのもあれだし、どうせならガバッと実行したいな〜と思ってCircleCI APIを叩いて取得できるんじゃないかな?と思って調査してみたらできました。

Railsプロジェクトの準備

gemのインストール

gem circleciとgem gitをインストールします。 circleciは、CircleCI APIにアクセスするためのgemで、直接REST Clientとかを使うより便利です。 gitは、現在のブランチ名を取得するために使っています。

また、dotenv-railsを使っていることを前提とします(環境変数をたくさん使うので)

Gemfileに追記します。

group :development, :test do
  gem 'circleci'
  gem 'git', require: false
  gem 'dotenv-rails'
end

bundle installしましょう。

.envにCircleCIのトークンなどの設定

.envファイルに、CircleCIにアクセスするための環境変数を設定します。 これらは自分の環境に合わせて変更をお願いします。

CIRCLE_PROJECT_USERNAME='username'
CIRCLE_PROJECT_REPONAME='reponame'
CIRCLE_TOKEN='******'

config/initializers/circleci.rbの作成

Rails起動時にトークンを設定するようにします。

if Rails.env.development? || Rails.env.test?
  CircleCi.configure do |config|
    config.token = ENV['CIRCLE_TOKEN']
  end
end

Rails Runnerの作成

scriptディレクトリに以下のファイルを追加します。gistで公開しています。

gist959f476c8d0df95f96709bb65264f10f

使い方

ヘルプを見る

ヘルプは-hまたは--helpで見れます。どんな引数を使うのかなどがわかります。

$ bin/rails runner script/circleci_failed_spec_files.rb -h
Usage: circleci_failed_spec_files [options]
    -n, --build_num VALUE            CircleCI Build number(default: nil)
    -l, --[no-]line                  output lines(default: false)
    -j, --job_name VALUE             job name(default: build)
    -b, --branch VALUE               git branch name(default: current_branch)
    -t, --vcs_type VALUE             vcs_type(default: github)
    -h, --help                       Prints this help
--build_num(-n)

CircleCIのビルド番号を指定します。これが指定されている場合は、対象のビルド番号から落ちているテストのファイル一覧を取得します。対象のビルドが成功している場合は、何も返しません。

--[no-]line(-l)

戻ってきたファイル一覧を1行ごとに表示するか、スペース区切りで取得するかです。デフォルトはスペース区切りです。

スペース区切りの場合は直接rspecに渡すときに便利で、行ごと表示の場合はpecoやCircleCIで加工する際などに便利です。

--job_name(-j)

Workflowを使っている場合に実際にテストをしているジョブの名前を指定します。

--branch(-b)

gitのブランチ名を指定します。デフォルトだと現在のブランチを自動で取得します。

--vcs_type(-t)

バージョン管理システムのタイプを指定します。デフォルトはgithubです。bitbucketを使っている場合は、-vcs_type bitbucketとする必要があります。

使い方のサンプル(基本編)

Workflowを使っていない場合

基本はこれでいいです。

$ bin/rails runner script/circleci_failed_spec_files.rb

Workflowを使っている場合

実際にテストしているjobの名前がtestとしますと、以下の通りです。

$ bin/rails runner script/circleci_failed_spec_files.rb -j test

実際に利用する

現在のブランチで失敗したテストをローカルで実行する

$ bin/rspec $(bin/rails runner script/circleci_failed_spec_files.rb)

他のブランチで失敗したテストをローカルで実行する

$ bin/rspec $(bin/rails runner script/circleci_failed_spec_files.rb -b feature-xxx)

ビルド番号を指定してローカルで実行する

$ bin/rspec $(bin/rails runner script/circleci_failed_spec_files.rb -n 1234)

応用編

pecoに渡す

私はfish使いなのでfishの関数を定義しました。

function peco_pipe_rspec
  peco | read line
  if test -n "$line"
    commandline "bin/rspec $line"
  end
  set -e line
end

そして、これにオプション--lineをつけて渡します。

$ bin/rails runner script/circleci_failed_spec_files.rb --line | peco_pipe_rspec
# 選ぶと…
$ bin/rspec spec/features/xxx_spec.rb # エンター押して実行!

CircleCIで落ちたテストが複数ファイルあった場合、全部流すと時間がかかるのでこれは便利です。

おまけ

昨日書いたのですが、fishでCommand Substitutionsを使うと戻り値を1つの文字列と認識してしまうので、工夫が必要です。

patorash.hatenablog.com

$ bin/rspec (bin/rails runner script/circleci_failed_spec_files.rb | string split " ")

これでバッチリ!

導入が多少面倒ですが、便利です。CircleCIのほうでもこれを使って全体テストを流す前に落ちたテストを実行するようにしました。それについては別記事を書こうと思います。また、余裕ができたらgemにしようと思います。

追記:書きました。

patorash.hatenablog.com