我如何从Capistrano运行一个耙子任务?

我已经有一个deploy.rb,可以在我的生产服务器上部署我的应用程序。

我的应用程序包含一个自定义的rake任务(lib / tasks目录中的一个.rake文件)。

我想创build一个远程运行该rake任务的上限任务。

在你的\config\deploy.rb稍微更加清楚一些,在任何任务或命名空间之外添加:

 namespace :rake do desc "Run a task on a remote server." # run like: cap staging rake:invoke task=a_certain_task task :invoke do run("cd #{deploy_to}/current; /usr/bin/env rake #{ENV['task']} RAILS_ENV=#{rails_env}") end end 

然后,从/rails_root/ ,您可以运行:

 cap staging rake:invoke task=rebuild_table_abc 
 run("cd #{deploy_to}/current && /usr/bin/env rake `<task_name>` RAILS_ENV=production") 

用Google发现它 – http://ananelson.com/said/on/2007/12/30/remote-rake-tasks-with-capistrano/

RAILS_ENV=production是个棘手的问题 – 我一开始没有想到,也不知道为什么这个任务没有做任何事情。

几年后…

看看capistrano的rails插件,你可以在https://github.com/capistrano/rails/blob/master/lib/capistrano/tasks/migrations.rake#L5-L14看到它可以看起来像这样:;

 desc 'Runs rake db:migrate if migrations are set' task :migrate => [:set_rails_env] do on primary fetch(:migration_role) do within release_path do with rails_env: fetch(:rails_env) do execute :rake, "db:migrate" end end end end 

Capistrano 3通用版本 (运行任何耙子任务)

build立一个Mirek Rusin的答案的通用版本:

 desc 'Invoke a rake command on the remote server' task :invoke, [:command] => 'deploy:set_rails_env' do |task, args| on primary(:app) do within current_path do with :rails_env => fetch(:rails_env) do rake args[:command] end end end end 

用法示例: cap staging "invoke[db:migrate]"

请注意, deploy:set_rails_env需要来自capistrano-rails gem

使用Capistrano风格的耙子调用

有一个常见的方式,只require 'bundler/capistrano'和其他修改rake的扩展就能“正常工作”。 如果您使用多阶段,这也将适用于预生产环境。 要点? 如果可以的话,使用configurationvariables。

 desc "Run the super-awesome rake task" task :super_awesome do rake = fetch(:rake, 'rake') rails_env = fetch(:rails_env, 'production') run "cd '#{current_path}' && #{rake} super_awesome RAILS_ENV=#{rails_env}" end 

使用capistrano-rakegem

只需安装gem而不用搞定制capistrano食谱,并在远程服务器上执行所需的rake任务,如下所示:

 cap production invoke:rake TASK=my:rake_task 

充分披露:我写了

我个人在生产中使用了这样一个辅助方法:

 def run_rake(task, options={}, &block) command = "cd #{latest_release} && /usr/bin/env bundle exec rake #{task}" run(command, options, &block) end 

这允许运行类似于使用run(command)方法的rake任务。


注:这与杜克提出的相似,但我:

  • 使用latest_release而不是current_release – 从我的经验来看,它更像是你在运行rake命令时所期望的;
  • 按照Rake和Capistrano的命名约定(而不是:cmd – > task和rake – > run_rake)
  • 请勿设置RAILS_ENV =#{rails_env},因为设置它的正确位置是default_run_optionsvariables。 例如default_run_options [:env] = {'RAILS_ENV'=>'production'}# – > DRY!

有一个有趣的gem海angular ,使您的耙子任务作为Capistrano任务可用,所以你可以远程运行它们。 cape是有据可查的,但这里是如何设置我的简短的概述。

安装gem后,只需将其添加到您的config/deploy.rb文件。

 # config/deploy.rb require 'cape' Cape do # Create Capistrano recipes for all Rake tasks. mirror_rake_tasks end 

现在,您可以通过本地或远程运行所有您需要的任务。

作为一个额外的好处, cape可以让你设置如何在本地和远程运行你的rake任务(没有更多的bundle exec rake ),只需将它添加到你的config/deploy.rb文件中即可:

 # Configure Cape to execute Rake via Bundler, both locally and remotely. Cape.local_rake_executable = '/usr/bin/env bundle exec rake' Cape.remote_rake_executable = '/usr/bin/env bundle exec rake' 
 namespace :rake_task do task :invoke do if ENV['COMMAND'].to_s.strip == '' puts "USAGE: cap rake_task:invoke COMMAND='db:migrate'" else run "cd #{current_path} && RAILS_ENV=production rake #{ENV['COMMAND']}" end end end 

这是我放在我的deploy.rb中,以简化运行rake任务。 这是capistrano run()方法的简单包装。

 def rake(cmd, options={}, &block) command = "cd #{current_release} && /usr/bin/env bundle exec rake #{cmd} RAILS_ENV=#{rails_env}" run(command, options, &block) end 

然后我只需运行任何rake任务就可以了:

 rake 'app:compile:jammit' 

这对我工作:

 task :invoke, :command do |task, args| on roles(:app) do within current_path do with rails_env: fetch(:rails_env) do execute :rake, args[:command] end end end end 

然后只需运行cap production "invoke[task_name]"

其中大部分来自上面的回答 ,只是一个小小的改进,从capistrano运行任何耙任务

从capistrano运行任何rake任务

 $ cap rake -s rake_task=$rake_task # Capfile task :rake do rake = fetch(:rake, 'rake') rails_env = fetch(:rails_env, 'production') run "cd '#{current_path}' && #{rake} #{rake_task} RAILS_ENV=#{rails_env}" end 

这也适用:

 run("cd #{release_path}/current && /usr/bin/rake <rake_task_name>", :env => {'RAILS_ENV' => rails_env}) 

更多信息: Capistrano跑

如果你想能够传递多个参数试试这个(基于marinosbern的答案):

 task :invoke, [:command] => 'deploy:set_rails_env' do |task, args| on primary(:app) do within current_path do with :rails_env => fetch(:rails_env) do execute :rake, "#{args.command}[#{args.extras.join(",")}]" end end end end 

然后你可以像这样运行一个任务: cap production invoke["task","arg1","arg2"]

如果Rake任务需要用户交互,它将不起作用

所以我一直在做这个。 它接缝工作良好。 但是,你需要一个formater来真正利用代码。

如果您不想使用格式化程序,只需将日志级别设置为debugging模式即可。 这些semas到h

 SSHKit.config.output_verbosity = Logger::DEBUG 

帽子东西

 namespace :invoke do desc 'Run a bash task on a remote server. cap environment invoke:bash[\'ls -la\'] ' task :bash, :execute do |_task, args| on roles(:app), in: :sequence do SSHKit.config.format = :supersimple execute args[:execute] end end desc 'Run a rake task on a remote server. cap environment invoke:rake[\'db:migrate\'] ' task :rake, :task do |_task, args| on primary :app do within current_path do with rails_env: fetch(:rails_env) do SSHKit.config.format = :supersimple rake args[:task] end end end end end 

这是我为了使用上面的代码而构build的格式化程序。 它基于:sshkit中内置的textsimple,但是调用自定义任务并不是一个好方法。 哦,这很多不适用于最新版本的sshkitgem。 我知道它适用于1.7.1。 我这样说是因为主分支已经改变了可用的SSHKit :: Command方法。

 module SSHKit module Formatter class SuperSimple < SSHKit::Formatter::Abstract def write(obj) case obj when SSHKit::Command then write_command(obj) when SSHKit::LogMessage then write_log_message(obj) end end alias :<< :write private def write_command(command) unless command.started? && SSHKit.config.output_verbosity == Logger::DEBUG original_output << "Running #{String(command)} #{command.host.user ? "as #{command.host.user}@" : "on "}#{command.host}\n" if SSHKit.config.output_verbosity == Logger::DEBUG original_output << "Command: #{command.to_command}" + "\n" end end unless command.stdout.empty? command.stdout.lines.each do |line| original_output << line original_output << "\n" unless line[-1] == "\n" end end unless command.stderr.empty? command.stderr.lines.each do |line| original_output << line original_output << "\n" unless line[-1] == "\n" end end end def write_log_message(log_message) original_output << log_message.to_s + "\n" end end end end 

我不知道capistrano是如何工作的,但只是为了logging – 这是从Ruby中调用rake任务的语法:

 Rake::Task["task:name"].invoke