capistrano3のデプロイを把握する

[結局Node.jsアプリケーションのデプロイはどうすればいいの？](http://qiita.com/taizo/items/52921ab6fa027a840842) で
色々node.jsアプリのデプロイを考えたのですが、
やっぱり[capistrano](http://capistranorb.com/)が結構使いやすい気がしてきました。

デプロイ対象でリポジトリから直接ソースコードを落とせるならば
デプロイ専用のリポジトリを作成して、それをCIで実行するようにすればいいわけです。

capistrano3では、基本的なデプロイタスクがあり、
それに独自のタスクを追加することで、様々な状況に対応しています。
どのようなタスクが実行されているかを把握できれば、柔軟にデプロイ設定が出来ます。

# capistrano3をまず使ってみる

`--dry-run` で動くこと確認

```bash
$ gem install capistrano
$ cap install
mkdir -p config/deploy
create config/deploy.rb
create config/deploy/staging.rb
create config/deploy/production.rb
mkdir -p lib/capistrano/tasks
Capified
$ cap staging deploy --dry-run
** Invoke staging (first_time)
** Execute (dry run) staging
** Invoke deploy (first_time)
** Execute (dry run) deploy
```

# capistrano3のデプロイフロー

capistrano3では、まず `capistrano/setup` と `capistrano/deploy` を
基本利用することになります。

それを軸にして、各タスクの前後に処理を記載すればその設定に合わせて実行してくれます。
なので、デプロイの流れを把握すればいいわけです。

## [capistrano/deploy](https://github.com/capistrano/capistrano/blob/master/lib/capistrano/tasks/deploy.rake)のフロー

```
deploy:starting
  deploy:check
    #{scm}:check
    deploy:check:directories
    deploy:check:linked_dirs
    deploy:check:make_linked_dirs
    deploy:check:linked_files
  deploy:set_previous_revision
deploy:started
deploy:updating
  #{scm}:create_release
  deploy:symlink:shared
    deploy:symlink:linked_files
    deploy:symlink:linked_dirs
deploy:updated
deploy:publishing
  deploy:symlink:release
deploy:published
deploy:finishing
  deploy:cleanup
deploy:finished
  deploy:log_revision
```

# 各プラグインのフロー

capistrano3ではすでによく使う状況については、プラグインが提供されています。
なので、`Capfile`で`require capistrano/rails/assets`と記載するだけで
組み込むことが出来ます。
これらのプラグインを見ると、capistranoの独自のタスクの作り方が大体わかります。

## [capistrano/rails/assets](https://github.com/capistrano/rails/blob/master/lib/capistrano/tasks/assets.rake)

`deploy:updated`の後に、`assets::precompile`の処理を行っています。

```yaml
deploy:starting
  deploy:check
    #{scm}:check
    deploy:check:directories
    deploy:check:linked_dirs
    deploy:check:make_linked_dirs
    deploy:check:linked_files
  deploy:set_previous_revision
deploy:started
deploy:updating
  #{scm}:create_release
  deploy:symlink:shared
    deploy:symlink:linked_files
    deploy:symlink:linked_dirs
deploy:updated
  deploy:compile_assets            # 追加
    deploy:assets:precompile       # 追加
    deploy:assets:backup_manifest  # 追加
  deploy:normalize_assets          # 追加
deploy:publishing
  deploy:symlink:release
deploy:published
deploy:finishing
  deploy:cleanup
deploy:finished
  deploy:log_revision
```

## [capistrano/rails/migrations](https://github.com/capistrano/rails/blob/master/lib/capistrano/tasks/migrations.rake)

`deploy:updated`の後に、`deploy:migrate`の処理を行っています。

```yaml
deploy:starting
  deploy:check
    #{scm}:check
    deploy:check:directories
    deploy:check:linked_dirs
    deploy:check:make_linked_dirs
    deploy:check:linked_files
  deploy:set_previous_revision
deploy:started
deploy:updating
  #{scm}:create_release
  deploy:symlink:shared
    deploy:symlink:linked_files
    deploy:symlink:linked_dirs
deploy:updated
  deploy:migrate                # 追加
deploy:publishing
  deploy:symlink:release
deploy:published
deploy:finishing
  deploy:cleanup
deploy:finished
  deploy:log_revision
``` 

## [capistrano/npm](https://github.com/capistrano/npm/blob/master/lib/capistrano/tasks/npm.rake)

この場合`deploy:updated`の**前に**`npm:install`を実行しています。

```yaml
deploy:starting
  deploy:check
    #{scm}:check
    deploy:check:directories
    deploy:check:linked_dirs
    deploy:check:make_linked_dirs
    deploy:check:linked_files
  deploy:set_previous_revision
deploy:started
deploy:updating
  #{scm}:create_release
  deploy:symlink:shared
    deploy:symlink:linked_files
    deploy:symlink:linked_dirs
npm:install                      # 追加
deploy:updated 
deploy:publishing
  deploy:symlink:release
deploy:published
deploy:finishing
  deploy:cleanup
deploy:finished
  deploy:log_revision
```

# タスクの書き方

独自のタスクを書きたい場合は、`lib/capistrano/tasks/` 以下に記載するのが通常です。
書き方は、各プラグインを参考にすると良いと思います。

```ruby:https://github.com/capistrano/npm/blob/master/lib/capistrano/tasks/npm.rake
namespace :npm do
  desc <<-DESC
    # 省略
  DESC
  task :install do  # npm:install タスクを作成
    on roles fetch(:npm_roles) do
      within fetch(:npm_target_path, release_path) do
        execute :npm, 'install', fetch(:npm_flags)
      end
    end
  end

  before 'deploy:updated', 'npm:install' # deploy:updateの前に npm:install を実行する
  # ...
end
```

# 参考

* [入門 Capistrano 3 ~ 全ての手作業を生まれる前に消し去りたい](http://labs.gree.jp/blog/2013/12/10084/)
* [はじめてのCapistrano](http://qiita.com/mosson/items/1a4cfd01cb538f2d8f0e)