J'ai déjà un deploy.rb qui peut déployer mon application sur mon serveur de production.
Mon application contient une tâche de râteau personnalisée (un fichier .rake dans le répertoire lib/tasks).
Je voudrais créer une tâche de plafonnement qui exécutera à distance cette tâche de râteau.
run("cd #{deploy_to}/current && /usr/bin/env rake `<task_name>` Rails_ENV=production")
Trouvé avec Google - http://ananelson.com/said/on/2007/12/30/remote-rake-tasks-with-capistrano/
Le Rails_ENV=production
était un piège - je n'y ai pas pensé au début et je n'ai pas pu comprendre pourquoi la tâche ne faisait rien.
Un peu plus explicite, dans votre \config\deploy.rb
, ajoutez en dehors de toute tâche ou espace de noms:
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
Ensuite, à partir de /Rails_root/
, tu peux courir:
cap staging rake:invoke task=rebuild_table_abc
Capistrano 3 Generic Version (exécuter n'importe quelle tâche de râteau)
Construire une version générique de la réponse 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
Exemple d'utilisation: cap staging "invoke[db:migrate]"
Notez que deploy:set_Rails_env
nécessite provient de la gemme capistrano-Rails
... quelques années plus tard ...
Jetez un œil au plugin Rails plugin de capistrano, vous pouvez le voir sur https://github.com/capistrano/Rails/blob/master/lib/capistrano/tasks/migrations.rake # L5-L14 cela peut ressembler à:
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
Il existe une méthode courante qui "fonctionnera" avec require 'bundler/capistrano'
et d'autres extensions qui modifient le râteau. Cela fonctionnera également avec les environnements de pré-production si vous utilisez plusieurs étages. L'essentiel? Utilisez des vars de configuration si vous le pouvez.
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-rake
bijouInstallez simplement la gemme sans vous soucier des recettes de capistrano personnalisées et exécutez les tâches de râteau souhaitées sur des serveurs distants comme celui-ci:
cap production invoke:rake TASK=my:rake_task
Divulgation complète: je l'ai écrit
J'utilise personnellement dans la production une méthode d'aide comme celle-ci:
def run_rake(task, options={}, &block)
command = "cd #{latest_release} && /usr/bin/env bundle exec rake #{task}"
run(command, options, &block)
end
Cela permet d'exécuter une tâche de râteau similaire à l'utilisation de la méthode run (command).
NOTE: Il est similaire à ce que Duke proposé, mais je:
Il y a un joyau intéressant cape qui rend vos tâches de râteau disponibles en tant que tâches Capistrano, vous pouvez donc les exécuter à distance. cape
est bien documenté, mais voici un bref aperçu de la configuration d'i.
Après avoir installé la gemme, ajoutez-la simplement à votre config/deploy.rb
fichier.
# config/deploy.rb
require 'cape'
Cape do
# Create Capistrano recipes for all Rake tasks.
mirror_rake_tasks
end
Maintenant, vous pouvez exécuter toutes vos tâches rake
localement ou à distance via cap
.
En prime, cape
vous permet de définir la façon dont vous souhaitez exécuter votre tâche de râteau localement et à distance (plus bundle exec rake
), ajoutez simplement ceci à votre config/deploy.rb
fichier:
# 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
Voici ce que j'ai mis dans mon deploy.rb pour simplifier l'exécution des tâches de râteau. C'est un simple wrapper autour de la méthode 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
Ensuite, je lance simplement une tâche de râteau comme ceci:
rake 'app:compile:jammit'
Cela a fonctionné pour moi:
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
Ensuite, exécutez simplement cap production "invoke[task_name]"
Si vous voulez pouvoir passer plusieurs arguments, essayez ceci (basé sur la réponse 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
Ensuite, vous pouvez exécuter une tâche comme ceci: cap production invoke["task","arg1","arg2"]
La plupart provient de réponse ci-dessus avec une amélioration mineure pour exécuter n'importe quelle tâche de râteau depuis capistrano
Exécutez n'importe quelle tâche de râteau depuis 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
Cela fonctionne également:
run("cd #{release_path}/current && /usr/bin/rake <rake_task_name>", :env => {'Rails_ENV' => Rails_env})
Plus d'informations: Capistrano Run
J'ai donc travaillé là-dessus. il semble bien fonctionner. Cependant, vous avez besoin d'un formateur pour vraiment profiter du code.
Si vous ne souhaitez pas utiliser un formateur, définissez simplement le niveau de journalisation sur le mode débogage. Ces 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
C'est le formateur que j'ai construit pour travailler avec le code ci-dessus. Il est basé sur: textimple intégré au sshkit mais ce n'est pas une mauvaise façon d'appeler des tâches personnalisées. Oh, cela ne fonctionne pas avec la dernière version de sshkit gem. Je sais que cela fonctionne avec 1.7.1. Je dis cela parce que la branche principale a changé les méthodes SSHKit :: Command qui sont 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