web-dev-qa-db-fra.com

Comment exécuter une tâche de râteau depuis Capistrano?

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.

100
Richard Poirier
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.

41
Richard Poirier

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
56
Coward

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

41
marinosb

... 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
41
Mirek Rusin

Utilisez des invocations de râteau de style Capistrano

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
20
captainpete

Utilisez le capistrano-rake bijou

Installez 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

14
Sheharyar

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:

  • utilisez latest_release au lieu de current_release - d'après mon expérience, c'est plus ce à quoi vous vous attendez lorsque vous exécutez une commande rake;
  • suivez la convention de dénomination de Rake et Capistrano (au lieu de: cmd -> task 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. Par exemple default_run_options [: env] = {'Rails_ENV' => 'production'} # -> SEC!
7
Szymon 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'
5
yacc
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 
3
Darme

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'
2
Duke

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]"

2
Abram

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"]

1
Robin Clowers

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
1
Sairam

Cela fonctionne également:

run("cd #{release_path}/current && /usr/bin/rake <rake_task_name>", :env => {'Rails_ENV' => Rails_env})

Plus d'informations: Capistrano Run

1
acw

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

Casquette Stuff

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
0
brand-it