如何有条件地覆盖 Capistrano 的 deploy:migrate 任务?

How to conditionally override Capistrano's deploy:migrate task?

我想有条件地覆盖 deploy:migrate 以便我们可以 运行 手动进行某些迁移。

这是我在 config/deploy/tasks/deploy.rake 中的内容:

namespace :deploy do
  if ENV['DB_MIGRATE'] == 'skip'
    desc "Override Capistrano's default behavior, do not migrate on deploy"
    task :migrate do
      raise 'BOO!'
    end
  end
end

这是我在 运行 DB_MIGRATE=skip cap staging deploy:migrate:

时看到的
INFO [deploy:migrate] Run `rake db:migrate`
DEBUG [c0ed2f81] Running /usr/bin/env if test ! -d /path/current; then echo "Directory does not exist '/path/current'" 1>&2; false; fi as deploy@host.
DEBUG [c0ed2f81] Command: if test ! -d /path/current; then echo "Directory does not exist '/path/current'" 1>&2; false; fi
DEBUG [c0ed2f81] Finished in 1.061 seconds with exit status 0 (successful).
INFO [2f3a4cc7] Running bundle exec rake db:migrate as deploy@host.
DEBUG [2f3a4cc7] Command: cd /path/current && ( RAILS_ENV="staging" bundle exec rake db:migrate )
INFO [2f3a4cc7] Finished in 6.518 seconds with exit status 0 (successful).
(Backtrace restricted to imported tasks)
cap aborted!
BOO!

Tasks: TOP => deploy:migrate
(See full trace by running task with --trace)

从输出来看,Capistrano 似乎在做它一直做的事情,此外,还做了我要求它做的事情(引发异常)。

如何完全摆脱 Capistrano 的默认 deploy:migrate

根据我的经验,我会说它正在查看远程而不是本地的环境变量。调用 cap staging deploy 将远程环境变量设置为 RAILS_ENV=staging。但是因为这意味着登录远程并设置 var,所以它使使用 capistrano 变得很容易。

更好的方法可能是使用 capistrano 条件:https://github.com/deviantech/capistrano-conditional

其自述文件指出:

A major change from Capistrano 2 to Capistrano 3 is that task definitions are now additive, so defining a new task doesn't overwrite the existing definition.

文档中有一章 Overriding Capistrano Tasks 解释了整个过程:

When re-defining a task in Capistrano v2, the original task was replaced. The Rake DSL on which Capistrano v3 is built is additive however […]

But it is also possible to completely clear a task and then re-defining it from scratch.

这正是我所需要的。

在此处扩展已接受的答案,这将 OP 和链接的文档整合到一个完整的解决方案中:

if ENV['DB_MIGRATE'] == 'skip'
  Rake::Task["deploy:migrate"].clear_actions
  namespace :deploy do
    desc "Override Capistrano's default behavior, do not migrate on deploy"
    task :migrate do
      puts 'BOO!'
    end
  end
end

我通过在 Capfile 中有条件地要求 capistrano/rails/migrations 解决了这个问题,即

# Migrations can be skipped by setting up local 'SKIP_MIGRATIONS' variable, i.e.
# SKIP_MIGRATIONS=true bundle exec cap production deploy
unless ENV['SKIP_MIGRATIONS']
  require 'capistrano/rails/migrations'
end