はじめに
仕事で「自分、CIの理解が浅いなあ」と思うことが度々あり、
特に最近だとローカル環境ではエラーが起きず、CircleCI上でのみエラーが発生する事象に遭遇し、CIの設定ファイルで何をしてるのかに関して、ブラックボックスだったので即時対応できませんでした。
教訓として、
基本的なCIのサンプルファイルを作成し、lint(rubocop)とtest(RSpec)を実行する設定ファイルの書き方を未来の自分に向けて、噛み砕いてまとめました。
想定読者
- CircleCIでビルド・テスト・デプロイを自動で行う開発環境で仕事をしているが、CIの設定の中身がブラックボックスな人
目標
- CircleCIの
config.yml
ファイルを作成- LintツールとRSpecをCIで実行
それではいってみましょう!
1. CircleCIの基本構成
CircleCIの設定ファイル config.yml
は、主に以下の要素で構成されています。
-
version
: CircleCIの設定バージョン -
jobs
: 個別のタスクを定義する場所。ビルドやテスト、デプロイなどの「タスク」をまとめてます -
workflows
: 定義されたジョブをどういうタイミングで実行するかを指定します。複数のジョブを並列や順番に実行する場合に必要です。
基本的な config.yml
の例
version: 2.1
jobs:
build: # 自由に名前を定義できる
docker:
- image: circleci/ruby:3.0.0
steps:
- checkout #コードをGitリポジトリからチェックアウト
- run:
name: Bundle Install
command: bundle install # 依存パッケージをインストール
# ワークフローの定義
workflows:
version: 2
build_and_test: # 自由に名前を定義できる
jobs:
- build # ビルドジョブを実行
【Jobsセクションについて】
build ジョブでは、まずCircleCI上にRuby環境を構築します。
そして、checkoutでGitリポジトリから最新のソースコードを取得。
その後、bundle install を使ってプロジェクトに必要な依存関係を一気にインストールします。
【Workflowsセクションについて】
workflow を定義することで、どの順序でジョブが実行されるかを指定できます。
今回の設定では、シンプルに build ジョブのみを実行するフローです。
この基本構成にこれから追加・修正を加えていきます!
2. lint
ジョブでrubocop自動実行の設定
rubocop
を自動実行するためlint
ジョブを設定します。
※rubocopはRubyのコードを静的解析するツールです。
Lint用のジョブ追加
jobs:
lint:
docker:
- image: circleci/ruby:3.0.0
steps:
- checkout
- run:
name: Bundle Install
command: bundle install
- run:
name: Run RuboCop
command: bundle exec rubocop # rubocopを実行
この設定では、lint
という新しいジョブを作成し、rubocop
を実行しています。
これで、プッシュ時にrubocopが自動実行され、コードの静的解析が行われます。
3. test
ジョブでRSpec自動実行の設定
続いて、RSpecを実行するジョブtest
を設定します。
※RSpecはRubyのテストフレームワークです。
jobs:
test:
docker:
- image: circleci/ruby:3.0.0
steps:
- checkout
- run:
name: Bundle Install
command: bundle install
- run:
name: Run RSpec
command: bundle exec rspec # RSpecを実行
ここでは、test というジョブを追加し、RSpecテストを実行するコマンドを定義しています。
4. ワークフローの設定
最後に、LintとRSpecテストを連続して実行するためのワークフローを定義します。
ワークフローの追加
workflows:
version: 2
build_and_test:
jobs:
- lint
- test
この設定では、lintのチェックが完了した後にtest(RSpec)を実行する流れにしています。
つまり、もしlintにエラーがあればそこで止まり、testは実行されない形になります。
完成したconfig.yml
version: 2.1
# ジョブの定義
jobs:
lint:
docker:
- image: circleci/ruby:3.0.0 # 使用するDockerイメージの指定
steps:
- checkout # ソースコードのチェックアウト
- run:
name: Bundle Install
command: bundle install
- run:
name: Run RuboCop
command: bundle exec rubocop # Gemの依存関係をインストール
test:
docker:
- image: circleci/ruby:3.0.0
steps:
- checkout
- run:
name: Bundle Install
command: bundle install
- run:
name: Run RSpec
command: bundle exec rspec
workflows:
version: 2
lint_and_test:
jobs:
- lint
- test
この設定では、2つのJobの中で、以下のbundle install
の設定を毎回してますが、restore_cacheやsave_cache
を用いて、依存関係のインストールをキャッシュし、ジョブの実行時間を短縮することもできるっぽいですね。
# 毎回のジョブで実行するのは非効率
- run:
name: Bundle Install
command: bundle install
【キャッシュを使用して、効率化したconfig.yml
】
version: 2.1
# ジョブの定義
jobs:
lint:
docker:
- image: circleci/ruby:3.0.0
steps:
- checkout # ソースコードのチェックアウト
- restore_cache:
keys:
- v1-bundle-cache-{{ checksum "Gemfile.lock" }} # キャッシュの復元
- run:
name: Bundle Install
command: bundle install --path vendor/bundle # 依存関係のインストール
- save_cache:
paths:
- vendor/bundle
key: v1-bundle-cache-{{ checksum "Gemfile.lock" }} # キャッシュの保存
- run:
name: Run RuboCop
command: bundle exec rubocop
test:
docker:
- image: circleci/ruby:3.0.0
steps:
- checkout
- restore_cache:
keys:
- v1-bundle-cache-{{ checksum "Gemfile.lock" }} # キャッシュの復元
- run:
name: Bundle Install
command: bundle install --path vendor/bundle # 依存関係のインストール
- save_cache:
paths:
- vendor/bundle
key: v1-bundle-cache-{{ checksum "Gemfile.lock" }} # キャッシュの保存
- run:
name: Run RSpec
command: bundle exec rspec
# ワークフローの定義
workflows:
version: 2
lint_and_test:
jobs:
- lint
- test
まとめ・感想
CircleCIの config.yml を使ってRubocopとRSpecを実行する基本的な設定方法を紹介しました。
まだまだ実務で扱っているymlファイルの中身は「完全に理解した」とは言えませんが、少しづつ時間の空いているときに読み進めようと思ってます。
また、自分の開発してるプロダクトではコードをプッシュしてからCIの自動実行が完了するまでが長い(20~30分くらい)ので、config.ymlの設定を見直すことで時短につなげることにもチャレンジしたいなと思ってます.
参考
ご紹介! CircleCIの超基本! 設定ファイルの基礎を優しく解説!【CircleCI入門】