patorashのブログ

方向性はまだない

gemのCIをTravisCIからCircleCIに変更した

gem imyouのCIをTravisCIからCircleCIに変更した。

理由は単純で、普段からCircleCIを使っているので、CIの構築がやりやすいから。TravisCIは滅多に使わないのでわからなくなることが多く、それがストレスだった。他のgemもCircleCIに変更していこうと思うが、まぁ時間が取れたらやっていく…。

CircleCIに変更した際に、業務では使わなかったCircleCI 2.1の機能があったので、それを使えたのはいい経験だった。主にparametersである。

parametersを使う

parametersを使うと、executor, command, jobの一部を書き換えることができる。 gemのテストは複数のRubyのバージョンやRailsのバージョンで行いたいため、重宝した。

executorsの定義

定義は、以下のようにする。<< parameters.ruby_version >>に指定されたバージョンが入る。

executors:
  ruby:
    parameters:
      ruby_version:
        default: '2.6.2'
        type: enum
        enum: ['2.4.5', '2.5.5', '2.6.2']
    working_directory: ~/repo
    docker:
      - image: circleci/ruby:<< parameters.ruby_version >>-node-browsers

使う際は、以下のようにruby_versionを指定する。

jobs:
  test:
    executor:
      name: ruby
      ruby_version: '2.4.5'
    parallelism: 1
    steps:
      - run_test

commandsの定義

commandsでもparametersは使える。RubyのバージョンはexecutorsでRubyのdockerイメージのバージョン指定でなんとかなるが、RailsのほうはGemfileを変えないといけない。このあたりはTravisCIを使っていたときに実行されていた処理(BUNDLE_GEMFILEという環境変数を定義する)を拝借して作った。

commands:
  run_test:
    parameters:
      rails_version:
        default: '5.2'
        type: enum
        enum: ['4.2', '5.0', '5.1', '5.2']
    steps:
      - checkout
      - run:
          name: bundle install
          command: |
            export BUNDLE_GEMFILE=$PWD/gemfiles/rails_<< parameters.rails_version >>.gemfile
            bundle check || bundle install --jobs=4 --retry=3
      - rspec
      # 略

このbundle installの際に、--path=vendor/bundleを指定すると、なぜかgemfiles/vendor/bundleにgemがインストールされ、しかもパスが通っていないという謎でrspecコマンドが見つからないと言われてしまったので、敢えてpath指定を消した。しかし、そのせいでgemのキャッシュができないので、いい方法があったら教えてほしいところ。まぁgemのテストなので、毎回bundle installが実行されるほうがいいのかもしれない、とポジティブに捉えている(が、遅いのは気になる)。

jobsの定義

これらを組み合わせて、jobsでも引数を使えるようにする。

jobs:
  test:
    parameters:
      ruby_version:
        type: enum
        enum: ['2.4.5', '2.5.5', '2.6.2']
      rails_version:
        type: enum
        enum: ['4.2', '5.0', '5.1', '5.2']
    executor:
      name: ruby
      ruby_version: << parameters.ruby_version >>
    parallelism: 1
    steps:
      - run_test:
          rails_version: << parameters.rails_version >>

workflowsからjobを呼ぶ

あとは、先ほど作ったtestジョブにRubyのバージョンとRailsのバージョンを渡してテストを実行する。RubyのバージョンとサポートするRailsのバージョンとの組み合わせの数だけテストが並列になるので、書くのがしんどい。TravisCIは配列でRubyのバージョンと配列でgemfileを定義したらよしなに組み合わせしてくれていたので、その点はTravisCIのほうがいいなと思う。

workflows:
  build:
    jobs:
      - test:
          name: 'Ruby 2.4.5-Rails 4.2'
          ruby_version:  '2.4.5'
          rails_version: '4.2'
      - test:
          name: 'Ruby 2.5.5-Rails 4.2'
          ruby_version:  '2.5.5'
          rails_version: '4.2'
      - test:
          name: 'Ruby 2.6.2-Rails 4.2'
          ruby_version:  '2.6.2'
          rails_version: '4.2'
      # 略

実行結果

実行結果のワークフローの見た目はこんな感じになって気持ち良い。

f:id:patorash:20190327151340p:plain
CircleCIでRubyRailsのバージョンの組み合わせてgemの並列テスト

課題

せっかくなので、masterでテストが通ったらrake releaseするようにしたいなと思い、試行錯誤中。 ハードコーディングなら、一応できたので、また後日記事にしようかなと思う。