我已经有一个deploy.rb,可以将我的应用程序部署到生产服务器上。
我的应用程序包含一个自定义的rake任务(lib / tasks目录中的.rake文件)。
我想创建一个上限任务,该任务将远程运行该rake任务。
我已经有一个deploy.rb,可以将我的应用程序部署到生产服务器上。
我的应用程序包含一个自定义的rake任务(lib / tasks目录中的.rake文件)。
我想创建一个上限任务,该任务将远程运行该rake任务。
Answers:
在您的中\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
几年后
看看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
run
将在capistrano上有效,直到版本2。从版本3开始,这是必须的方法。
Capistrano 3通用版本(运行任何rake任务)
构建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
rake args[:command]
与 execute :rake, "#{args.command}[#{args.extras.join(",")}]"
您可以执行与多个参数的任务,像这样: cap production invoke["task","arg1","arg2"]
cap staging invoke['task[arg1\,arg2]']
。我喜欢您提到的这种方法,因为它反映了rake的实际调用。通过这种方法,您还可以链接多个任务,这通常很有用:cap staging invoke['task1 task2[arg1] task3[arg2\,arg3]']
。适用于rake 10.2.0或更高版本
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
是一个陷阱-一开始我没有想到它,也无法弄清楚为什么任务没有做任何事情。
"cd #{deploy_to}/current && #{rake} <task_name> RAILS_ENV=production"
有一种通用的方法可以“正常工作”,require 'bundler/capistrano'
并且可以修改rake的其他扩展。如果您使用的是多阶段,这也将与预生产环境一起使用。要点?如果可以,请使用config vars。
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
top.run
而不是run
capistrano-rake
宝石只需安装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
这样就可以运行rake任务,类似于使用run(command)方法。
注意:它类似于Duke提出的内容,但我:
有一个有趣的宝石斗篷,可以将耙任务用作Capistrano任务,因此您可以远程运行它们。cape
有充分的记录,但是这里是有关如何设置我的简短概述。
安装gem之后,只需将其添加到您的config/deploy.rb
文件中即可。
# config/deploy.rb
require 'cape'
Cape do
# Create Capistrano recipes for all Rake tasks.
mirror_rake_tasks
end
现在,您可以rake
通过本地或远程运行所有任务cap
。
另外,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
RAILS_ENV=production
为RAILS_ENV=#{rails_env}
也可以在我的登台服务器上使用。
这是我放入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'
大部分是从上面的答案中得到的,并进行了较小的增强以运行来自capistrano的任何rake任务
从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 Run
如果您希望能够传递多个参数,请尝试以下操作(基于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"]
所以我一直在努力。它看起来很不错。但是,您需要格式化程序才能真正利用代码。
如果您不想使用格式化程序,只需将日志级别设置为调试模式。这些对
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
这是我为使用上面的代码而构建的格式化程序。它基于sshkit中内置的:textsimple,但这并不是调用自定义任务的不错方法。哦,这许多不适用于最新版本的sshkit gem。我知道它适用于1.7.1。我之所以这样说,是因为master分支更改了可用的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
以前的答案对我没有帮助,我发现了这一点:来自http://kenglish.co/run-rake-tasks-on-the-server-with-capistrano-3-and-rbenv/
namespace :deploy do
# ....
# @example
# bundle exec cap uat deploy:invoke task=users:update_defaults
desc 'Invoke rake task on the server'
task :invoke do
fail 'no task provided' unless ENV['task']
on roles(:app) do
within release_path do
with rails_env: fetch(:rails_env) do
execute :rake, ENV['task']
end
end
end
end
end
运行您的任务
bundle exec cap uat deploy:invoke task=users:update_defaults
也许对某人有用
#{rake}
变量的利弊吗?似乎并不总是最好的选择。