¿Cómo ejecuto una tarea de rastrillo desde Capistrano?

Ya tengo un deploy.rb que puede implementar mi aplicación en mi servidor de producción.

Mi aplicación contiene una tarea de rake personalizada (un archivo .rake en el directorio lib / tasks).

Me gustaría crear una tarea de límite que ejecute de forma remota esa tarea de rake.

Un poco más explícito, en su \config\deploy.rb , agregue afuera de cualquier tarea o espacio de nombres:

 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 

Luego, desde /rails_root/ , puede ejecutar:

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

Lo encontré con Google – http://ananelson.com/said/on/2007/12/30/remote-rake-tasks-with-capistrano/

La RAILS_ENV=production fue una sorpresa. Al principio no pensé en eso y no pude entender por qué la tarea no estaba haciendo nada.

… un par de años después …

Eche un vistazo al plugin de capistrano’s rails, que puede ver en https://github.com/capistrano/rails/blob/master/lib/capistrano/tasks/migrations.rake#L5-L14 y puede verse más o menos así:

 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 

Versión genérica de Capistrano 3 (ejecutar cualquier tarea de rake)

Construyendo una versión genérica de la respuesta de 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 

Uso de ejemplo: cap staging "invoke[db:migrate]"

Tenga en cuenta que deploy:set_rails_env requires proviene de la gem capistrano-rails

Utilice las invocaciones de rastrillo estilo Capistrano

Hay una forma común de “solo funcionar” con require 'bundler/capistrano' y otras extensiones que modifican el rake. Esto también funcionará con entornos de preproducción si está utilizando varias etapas. ¿La esencia? Usa config vars si puedes.

 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 

Usa la gem capistrano-rake

Simplemente instale la gem sin jugar con las recetas personalizadas de capistrano y ejecute las tareas de rake deseadas en servidores remotos como este:

 cap production invoke:rake TASK=my:rake_task 

Divulgación completa: lo escribí

Yo personalmente uso en producción un método de ayuda como este:

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

Eso permite ejecutar una tarea de rake similar a usar el método de ejecución (comando).


NOTA: Es similar a lo que Duke propuso, pero yo:

  • utilice latest_release en lugar de current_release; según mi experiencia, es más de lo que espera al ejecutar un comando de rake;
  • siga la convención de nombres de Rake y Capistrano (en lugar de: cmd -> tarea y rake -> run_rake)
  • no establezca RAILS_ENV = # {rails_env} porque el lugar correcto para establecerlo es la variable default_run_options. Por ejemplo, default_run_options [: env] = {‘RAILS_ENV’ => ‘production’} # -> DRY!

Hay una capa de gems interesante que hace que sus tareas de rake estén disponibles como tareas de Capistrano, por lo que puede ejecutarlas de forma remota. cape está bien documentada, pero aquí hay una breve descripción de cómo configurar i.

Después de instalar la gem, simplemente agréguela a su archivo config/deploy.rb .

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

Ahora puede ejecutar todas sus tareas de rake local o remota a través de cap .

Como una ventaja adicional, cape permite establecer cómo desea ejecutar su tarea de rake de forma local y remota (no más bundle exec rake ), simplemente agregue esto a su archivo 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 

Esto es lo que puse en mi deploy.rb para simplificar la ejecución de tareas de rake. Es un simple contenedor del método run () de capistrano.

 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 

Luego, simplemente ejecuto cualquier tarea de rake así:

 rake 'app:compile:jammit' 

Esto funcionó para mí:

 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 

Luego simplemente ejecute la cap production "invoke[task_name]"

La mayor parte es de la respuesta anterior con una mejora menor para ejecutar cualquier tarea de rastrear desde capistrano

Ejecuta cualquier tarea de rastrear desde capistrano

 $ 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 

Esto también funciona:

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

Más información: Capistrano Run

Si quieres poder pasar múltiples argumentos, prueba esto (basado en la respuesta de 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 

Luego puede ejecutar una tarea como esta: cap production invoke["task","arg1","arg2"]

Así que he estado trabajando en esto. parece que funciona bien. Sin embargo, necesita un formateador para aprovechar realmente el código.

Si no desea utilizar un formateador, simplemente configure el nivel de registro en el modo de depuración. Estos semas a h

 SSHKit.config.output_verbosity = Logger::DEBUG 

Cap cosas

 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 

Este es el formateador que construí para trabajar con el código anterior. Se basa en: text simple integrado en el sshkit, pero no es una mala manera de invocar tareas personalizadas. Oh, esto no funciona con la última versión de sshkit gem. Sé que funciona con 1.7.1. Digo esto porque la twig principal ha cambiado los métodos SSHKit :: Command que están disponibles.

 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 
    Intereting Posts