Comment exécuter une tâche de râteau de Capistrano?
-
10-07-2019 - |
Question
J'ai déjà un fichier deploy.rb qui peut déployer mon application sur mon serveur de production.
Mon application contient une tâche de rake personnalisée (un fichier .rake dans le répertoire lib / tasks).
J'aimerais créer une tâche de plafonnement qui exécutera cette tâche de rake à distance.
La solution 2
run("cd #{deploy_to}/current && /usr/bin/env rake `<task_name>` RAILS_ENV=production")
Je l'ai 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 avais pas pensé au début et je ne pouvais pas comprendre pourquoi la tâche ne faisait rien.
Autres conseils
Un peu plus explicite, dans votre \ config \ deploy.rb
, ajoutez en dehors de toute tâche ou espace de nom:
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 /
, vous pouvez exécuter:
cap staging rake:invoke task=rebuild_table_abc
... quelques années plus tard ...
Jetez un coup d’œil au plugin rails de capistrano. rel = "noreferrer"> 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
Version générique de Capistrano 3 (exécuter une tâche de rake)
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: staging de cap " invoke [db: migrate] "
Notez que deploy: set_rails_env
requiert provient de la gem capistrano-rails
Utiliser des invocations de rake de style Capistrano
Il existe un moyen courant de "travailler simplement". avec require 'bundler / capistrano'
et d'autres extensions modifiant le rake. Cela fonctionnera également avec les environnements de pré-production si vous utilisez plusieurs étapes. L'essentiel? Utilisez les paramètres 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
Utilisez le capistrano-rake
bijou
Installez simplement la gemme sans manipuler les recettes capistrano personnalisées et exécutez les tâches de rake souhaitées sur des serveurs distants, comme suit:
cap production invoke:rake TASK=my:rake_task
Full Disclosure: je l'ai écrit
J'utilise personnellement dans la production une méthode d'assistance 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 rake similaire à l'utilisation de la méthode run (commande).
REMARQUE: Il est similaire à ce que Duc proposé, mais je:
- utilisez latest_release au lieu de current_release - de par mon expérience, c’est plus ce à quoi vous vous attendez lors de l’exécution d’une commande rake;
- suivez les conventions de nommage de Rake et Capistrano (au lieu de: cmd - > tâche et rake - > run_rake)
- ne définissez pas RAILS_ENV = # {rails_env} car le bon endroit pour le définir est la variable default_run_options. E.g default_run_options [: env] = {'RAILS_ENV' = > 'production'} # - > SEC!
Il existe un bijou intéressant, cape , qui rend vos tâches de rake disponibles en tant que tâches Capistrano, afin que vous puissiez les exécuter. à distance. cape
est bien documenté, mais voici un bref aperçu de la configuration.
Après avoir installé la gemme, ajoutez simplement ceci à votre fichier config / deploy.rb
.
# 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 manière dont vous souhaitez exécuter votre tâche de rake localement et à distance (plus de bundle exec rake
), ajoutez-le simplement à votre Fichier 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
Voici ce que j'ai mis dans le fichier deploy.rb pour simplifier l'exécution des tâches de rake. 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 juste n'importe quelle tâche de rake 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 [nom_tâche]" & <; code>
La majeure partie provient de ci-dessus, réponse avec une amélioration mineure pour exécuter n'importe quelle tâche de capistrano
Exécutez n'importe quelle tâche de ratissage 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 aussi:
run("cd #{release_path}/current && /usr/bin/rake <rake_task_name>", :env => {'RAILS_ENV' => rails_env})
Plus d'infos: Capistrano Run
Si vous voulez pouvoir passer plusieurs arguments, essayez ceci (d'après 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
Vous pouvez ensuite exécuter une tâche comme suit: cap production appel ["tâche", "arg1", "arg2"]
Donc, j'ai travaillé sur cela. il semble bien fonctionner. Cependant, vous avez besoin d'un formateur pour vraiment tirer parti 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
Casquette
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 fonctionner avec le code ci-dessus. Il est basé sur la commande texto intégrée au sshkit, mais ce n’est pas un mauvais moyen 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 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