¿Cómo ejecuto una tarea de rastrillo desde Capistrano?
-
10-07-2019 - |
Pregunta
Ya tengo un deploy.rb que puede implementar mi aplicación en mi servidor de producción.
Mi aplicación contiene una tarea de rastrillo personalizada (un archivo .rake en el directorio lib / task).
Me gustaría crear una tarea de límite que ejecute remotamente esa tarea de rastrillo.
Solución 2
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/
El RAILS_ENV = production
fue un problema: al principio no lo pensé y no pude entender por qué la tarea no estaba haciendo nada.
Otros consejos
Un poco más explícito, en su \ config \ deploy.rb
, agregue fuera 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
... un par de años después ...
Eche un vistazo al complemento de rieles de capistrano, puede verlo en https://github.com/capistrano/rails/blob/master/lib/capistrano/tasks/migrations.rake#L5-L14 puede verse algo 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 (ejecute cualquier tarea de rastrillo)
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
Ejemplo de uso: puesta en escena de tope " invoke [db: migrate] "
Tenga en cuenta que deploy: set_rails_env
requiere proviene de la gema capistrano-rails
Usar invocaciones de rastrillo estilo Capistrano
Hay una forma común que simplemente "funcionará" con requiere 'bundler / capistrano'
y otras extensiones que modifican rake. Esto también funcionará con entornos de preproducción si está utilizando etapas múltiples. ¿La esencia? Use config vars si puede.
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
Utilice la capistrano-rake
gem
Simplemente instale la gema sin meterse con recetas personalizadas de capistrano y ejecute las tareas de rastrillo deseadas en servidores remotos como este:
cap production invoke:rake TASK=my:rake_task
Divulgación completa: lo escribí
Personalmente uso en producción un método auxiliar 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 rastrillo similar al uso del método de ejecución (comando).
NOTA: es similar a lo que Duque propuso, pero yo:
- use latest_release en lugar de current_release: según mi experiencia, es más de lo que espera al ejecutar un comando rake;
- siga la convención de nomenclatura de Rake y Capistrano (en lugar de: cmd - > task and rake - > run_rake)
- no establezca RAILS_ENV = # {rails_env} porque el lugar correcto para configurarlo es la variable default_run_options. Por ejemplo, default_run_options [: env] = {'RAILS_ENV' = > 'producción'} # - > SECO!
Hay una gema interesante capa que hace que tus tareas de rastrillo estén disponibles como tareas de Capistrano, para que puedas ejecutarlas remotamente cape
está bien documentado, pero aquí hay una breve descripción de cómo configurar i.
Después de instalar la gema, simplemente agregue esto 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
de forma local o remota a través de cap
.
Como una ventaja adicional, cape
le permite configurar cómo desea ejecutar su tarea de rake local y remotamente (no más bundle exec rake
), solo 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 contenedor simple alrededor 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 rastrillo de esta manera:
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 cap production " invoke [task_name] "
La mayor parte es de respuesta anterior con una mejora menor para ejecutar cualquier tarea de rastrillo desde capistrano
Ejecuta cualquier tarea de rastrillo 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 <rake_task_name>", :env => {'RAILS_ENV' => rails_env})
Más información: Capistrano Run
Si desea poder pasar varios argumentos, intente esto (según 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
Entonces puede ejecutar una tarea como esta: cap producción 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 modo de depuración. Estas semas a h
SSHKit.config.output_verbosity = Logger::DEBUG
Material de tapa
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: textimple integrado en el sshkit, pero no es una mala manera de invocar tareas personalizadas. Oh, esto no funciona con la versión más nueva de sshkit gem. Sé que funciona con 1.7.1. Digo esto porque la rama maestra 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