ウェブサービスを作っています。

wercker + Capistrano で自動デプロイ

GitHub / Bitbucket のプライベートリポジトリも無料で CI し放題の wercker というサービスがあります。(2013/11/30 現在)
サイトもきれいで素敵です。ビルド成功後、Capistrano でデプロイが自動実行される方法を書いておきます。


まず、アプリの設定で SSH 公開鍵を作成します。


生成された公開鍵は、デプロイ先サーバの ~/.ssh/authorized_keys や Bitbucket のデプロイ鍵などに追加しておきます。
次に、アプリの設定から Deploy targets の設定をします。Custom deploy を選択して、


master ブランチのビルドに成功したら、自動デプロイするようにします。
入力したら、Deploy pipeline の Add new variable をクリック。


SSH Key pair を選択し、先ほど作成した鍵を選択します。
名前の欄には、WERCKER_SSH_KEY と設定しました。
これで、デプロイ時に WERCKER_SSH_KEY_PUBLIC, WERCKER_SSH_KEY_PRIVATE という環境変数が設定されます。
OK をクリック。


Save をクリック。


あとは、wercker.yml に deploy 部分を追加して commit & push すれば、自動デプロイ環境構築完了です。
Capistrano の config/deploy.rb も、適切に設定してあるか確認しておくと良いと思います。
以下、wercker.yml の追加部分です。

deploy:
    steps:
        - script:
            name: make .ssh directory
            code: mkdir -p "$HOME/.ssh"
        - create-file:
            name: write ssh key
            filename: $HOME/.ssh/id_rsa
            overwrite: true
            hide-from-log: true
            content: $WERCKER_SSH_KEY_PRIVATE
        - script:
            name: set permissions for ssh key
            code: chmod 0400 $HOME/.ssh/id_rsa
        - cap


最後に、とある Rails アプリの wercker.yml 全体例も貼っておきます。

box: wercker/ubuntu12.04-ruby2.0.0
services:
    - wercker/mysql
build:
    steps:
        - bundle-install
        - rails-database-yml
        - script:
            name: echo ruby information
            code: |
                echo "ruby version $(ruby --version) running"
                echo "from location $(which ruby)"
                echo -p "gem list: $(gem list)"
        - script:
            name: setup config files
            code: |
                cp config/resque.sample.yml config/resque.yml
                cp config/sunspot.sample.yml config/sunspot.yml
        - script:
            name: setup db
            code: bundle exec rake db:schema:load RAILS_ENV=test
        - script:
            name: rspec
            code: bundle exec rspec
    after-steps:
        - hipchat-notify:
            token: $HIPCHAT_TOKEN
            room-id: 357378
            from-name: wercker
deploy:
    steps:
        - script:
            name: make .ssh directory
            code: mkdir -p "$HOME/.ssh"
        - create-file:
            name: write ssh key
            filename: $HOME/.ssh/id_rsa
            overwrite: true
            hide-from-log: true
            content: $WERCKER_SSH_KEY_PRIVATE
        - script:
            name: set permissions for ssh key
            code: chmod 0400 $HOME/.ssh/id_rsa
        - cap
    after-steps:
        - hipchat-notify:
            token: $HIPCHAT_TOKEN
            room-id: 357378
            from-name: wercker

order メソッドをチェインしたときの挙動が Rails3 と Rails4.0.0 で逆

ActiveRecord の AR::Relation#order メソッドですが、チェインした場合の挙動が Rails4.0.0 で変更されていました。
追記(2013/11/7 18:00):
Rails4.0.1 で、Rails3 の挙動に戻りましたので、この記事は Rails4.0.0 に対してのみ有用です。ご注意ください。
Ruby on Rails 4.0.1リリース!大量のバグ修正、3系からの移行も少し簡単になりました | TechRacho


Rails3

User.order(:a).order(:b)  # => ORDER BY a, b


Rails4.0.0

User.order(:a).order(:b)  # => ORDER BY b, a


後から設定した値が、優先されるようになったんですね。

git push されたら Jenkins でビルドする

まず、Jenkins を叩くスクリプトを ~/git/jenkins.rb などに置きます。

require 'net/http'
require 'uri'
Net::HTTP.version_1_2

unless ARGV[0]
  puts 'usage: ruby jenkins.rb [JOB_NAME]'
  exit 1
end

user = "(Jenkins ユーザーID)"
api_token = "(ユーザの API トークン。Jenkins の、ユーザ設定ページに載っています)"
uri = URI("http://JENKINS_HOST/job/#{ ARGV[0] }/build")  # ARGV[0] に job 名が渡ってきます

Net::HTTP.start(uri.host, uri.port) do |http|
  req = Net::HTTP::Get.new(uri.request_uri)
  req.basic_auth user, api_token
  res = http.request(req)
  raise "response code was #{ res.code }" if res.code.to_i >= 400
end


次に、push される git リポジトリの hooks/post-receive ファイルに以下を追記します。

# rbenv 使っている前提で、PATH を通す
PATH=$HOME/.rbenv/shims:$HOME/.rbenv/bin:$PATH
ruby ~/git/jenkins.rb (Jenkins ジョブ名)


最後に、hooks/post-receive に実行権限を付与します。

chmod +x hooks/post-receive


以上で、git push すると自動で Jenkins が働くようになります。

Devise + OmniAuth で Facebook ログインしているユーザのウォールに自動で投稿する

Gemfile は、以下の通りです。koala gem は、Facebook を処理するライブラリです。

gem 'devise', '2.1.2'
gem 'omniauth-facebook', '1.4.1'
gem 'koala', '1.6.0'


config/initializers/devise.rb の facebook 設定に、scope オプションを追加します。
ウォールへの投稿時、publish_stream という権限が必要なためです。

config.omniauth :facebook, 'APP_ID', 'APP_SECRET', scope: 'email,publish_stream'


あとは、以下のコードをコントローラに書けば、投稿できます。(投稿権限をユーザが許可している場合)

oauth = Koala::Facebook::OAuth.new(*Devise.omniauth_configs[:facebook].args)
graph = Koala::Facebook::API.new(oauth.get_app_access_token)
begin
  graph.put_connections current_user.uid, 'feed', message: 'メッセージ', link: 'http://example.com/'
rescue Koala::Facebook::ClientError
  # ignore permission errors
end

capybara-webkit を debian の CI サーバで動かす (headless)

まず、Qt と xvfb を入れます。

sudo aptitude install libqt4-dev xvfb


Gemfile に、headless gem を追加します。

group :test do
  ...
  gem 'capybara'
  gem 'database_cleaner'
  gem 'launchy'
  gem 'capybara-webkit'
  gem 'headless'
  ...
end


spec/spec_helper.rb に、headless の設定を追加します。

DatabaseCleaner.strategy = :truncation
Capybara.javascript_driver = :webkit

# headless の設定
if Headless::CliUtil.application_exists?('Xvfb')
  headless = Headless.new
  headless.start
end

RSpec.configure do |config|
  ...
  config.before { DatabaseCleaner.start }
  config.after { DatabaseCleaner.clean }
  ...
end


以上です。