くりにっき

フルスタックキュアエンジニアです

Jenkinsのジョブごとにdatabase.ymlを動的生成する

database.ymlって書いてますがファイルならなんでもいけます

前提

自分のビルドスクリプトだとこういう風にすることが多いです

# 最初にJenkins用のDB接続情報が書かれたdatabase.ymlを作る
cp config/database.yml.jenkins config/database.yml

# あとは普通にテスト
RAILS_ENV=test bundle exec rake db:create
RAILS_ENV=test bundle exec rake db:migrate:reset
bundle exec rspec

しかしこれだと同じプロジェクトを別々のジョブ*1にした場合にも同じDBを使うためロックがかかってテストが落ちることになり、Throttle Concurrent Builds Plugin - Jenkins - Jenkins Wiki で同一DBは1つずつしかテストしないような排他制御をしていました。

ジョブが増えてくるとDBがボトルネックになってビルド全体が遅くなるため、スクリプト

if [ $JOB_NAME = "app_develop" ]; then
  cp config/database.yml.jenkins_develop config/database.yml
else
  cp config/database.yml.jenkins_master config/database.yml
fi

cp config/database.yml.${JOB_NAME} config/database.yml

のようにすることも考えたのですが、ジョブが増えた時に似たようなファイルが大量にできてしまうので汎用性がありません。

差し込み変数でファイルを作れるようにgemやJenkinsのプラグイン作るしかないと思ってたのですが、今日画期的な方法*2を思いついたので実践してみました。

【本題】ジョブごとに手軽にファイルを動的生成する

こんなファイルを作っておいて

database.yml.jenkins

test:
  adapter: mysql2
  encoding: utf8
  database: app_test_JOB_NAME
  pool: 20
  username: user
  password: pass
  socket: /var/run/mysqld/mysqld.sock

スクリプト内ではsedで置換するw

cat config/database.yml.jenkins | sed -e "s/JOB_NAME/${JOB_NAME}/" > config/database.yml

sedし忘れてもエラーにならないように CREATE DATABASE できる名前にしてます

ビルド実行時には環境変数が代入されるため実際には

cat config/database.yml.jenkins | sed -e "s/JOB_NAME/app_develop/" > config/database.yml

のようなコマンドが実行されて

test:
  adapter: mysql2
  encoding: utf8
  database: app_test_app_develop
  pool: 20
  username: user
  password: pass
  socket: /var/run/mysqld/mysqld.sock

のようなdatabase.ymlが作られるため、ジョブの増減に柔軟に対応できるようになりました。

まとめ

Simple is best.

gemやpluginを作らずともシェルの基本コマンドだけで簡単に実現できるならそれにこしたことはないと思った次第。

参考リンク

*1:例えばmasterとdevelopでジョブを分けるとか

*2:俺調べ