ruby - ¿Cómo ejecuto una tarea de rastrillo desde Capistrano?
rake (15)
Usa la gema capistrano-rake
Simplemente instale la gema 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í
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.
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
... 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
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 rama 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
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]"
Esto también funciona:
run("cd #{release_path}/current && /usr/bin/rake <rake_task_name>", :env => {''RAILS_ENV'' => rails_env})
Más información: Capistrano Run
Hay una cape gemas 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 gema, 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''
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
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"]
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
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!
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 gema capistrano-rails
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
run("cd #{deploy_to}/current && /usr/bin/env rake `<task_name>` 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.