Gemfile.lock を最新に保つため、bundle update を毎日自動でできるようにしたい。
Tachikoma.io というサービスもあるみたいだけど、 private repo は有料っぽいので自作した。
勝手に update されてアプリケーションがバグると困るので、
- Gemfile.lock を更新したプルリクエストを作る
- プルリクエストを人間が確認してマージ
という手順で行う。
先人の知恵
ここら辺を参考にした。
環境
- CircleCI 1.X
- 1年前に構築した環境なので 2.0 ではない...
- GitHub Private Repository
- Heroku
- Rails 5.X
流れ
- Heroku Scheduler が CircleCI を叩く
- CircleCI で bundle update を実施
- Gemfile.lock 更新があれば CircleCI が GitHub に PR を作成
- PR を人間が確認してマージボタンをポチ
1. 前準備
2. rake task 作成
lib/tasks/bundle_update_pull_request.rake
を作成する。
namespace :bundle_update_pull_request do
desc 'pull request if bundle updated'
task check: :environment do
project = 'repo-team/repo-rails'
branch = 'master'
token = 'CircleCI Token'
params = '{"build_parameters": {"BUNDLE_UPDATE": true}}'
header = { 'Content-Type' => 'application/json' }
client = Net::HTTP.new('circleci.com', 443)
client.use_ssl = true
response = client.post("/api/v1/project/#{project}/tree/#{branch}?circle-token=#{token}", params, header)
end
end
CircleCI の Nightly Builds を叩くだけの task。
params に '{"build_parameters": {"BUNDLE_UPDATE": true}}'
を渡していて、 CircleCI ではこのパラメータをみて bundle update するのか判断する。
この task は以下のコマンドで実行できる。
$ bundle exec rake bundle_update_pull_request:check
3. circle.yml
circle.yml をこんな感じで書く。
test:
post:
- >
if [ -n "${BUNDLE_UPDATE}" -a "${CIRCLE_BRANCH}" = 'master' ] ; then
bundle update
fi
deployment:
master:
branch: master
commands:
- >
if [ -n "${BUNDLE_UPDATE}" ] ; then
bash script/circleci/create_pull_request_if_needed.sh
fi
2 で params に渡した BUNDLE_UPDATE
が true だったら bundle update 実行 + PR 作成するようになっている。
4. create_pull_request_if_needed.sh
script/circleci/create_pull_request_if_needed.sh
を作成する。
export BRANCH=bundle-update-`date -u "+%Y%m%d"`
if [[ -n `git status -sb 2> /dev/null | grep Gemfile.lock` ]] ; then
git config --global user.email git@git.com
git config --global user.name 'git'
git add Gemfile.lock
git commit -m 'Bundle update'
git branch -M $BRANCH
git push origin $BRANCH
bundle exec ruby script/circleci/create_pull_request.rb
fi
3 で実行された bundle update で、 Gemfile.lock に差分があれば PR を作成するだけ。
5. create_pull_request.rb
script/circleci/create_pull_request.rb
を作成。
require 'octokit'
client = Octokit::Client.new(access_token: 'GitHub Personal access tokens')
client.create_pull_request(
'repo-team/repo-rails',
'master',
ENV['BRANCH'],
'Bundle update',
''
)
これで PR が作成される。
ここまでで bundle exec rake bundle_update_pull_request:check
で Bundle update の PR が自動で作成されるようになった。
6. Heroku Scheduler で定期実行
ここでは Heroku を使っているけど、定期実行できればなんでも良い。
動かしてみる
こんな感じで GitHub に毎日 PR がくるようになります。
これを人間が目視で確認して問題なければマージしましょう。
しかし、目視といっても version が変わったことしかわからないので、これを実際に運用するにはテストがしっかりと書かれていて、そのテストが壊れてないことを確認したらマージするようにしないとダメですね。