Как выполнить задачу рейка из Capistrano?

У меня уже есть deploy.rb, который может развернуть мое приложение на моем рабочем сервере.

Мое приложение содержит настраиваемую задачу rake (файл .rake в каталоге lib/tasks).

Я бы хотел создать задачу cap, которая будет удаленно запускать эту команду rake.

Ответ 1

run("cd #{deploy_to}/current && /usr/bin/env rake `<task_name>` RAILS_ENV=production")

Нашел его с Google - http://ananelson.com/said/on/2007/12/30/remote-rake-tasks-with-capistrano/

RAILS_ENV=production был gotcha - я не думал об этом сначала и не мог понять, почему задача ничего не делала.

Ответ 2

Немного более явный, в вашем \config\deploy.rb, добавить вне любой задачи или пространства имен:

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

Затем из /rails_root/ вы можете запустить:

cap staging rake:invoke task=rebuild_table_abc

Ответ 3

... пару лет спустя...

Посмотрите на плагин capistrano rails, вы можете видеть на https://github.com/capistrano/rails/blob/master/lib/capistrano/tasks/migrations.rake#L5-L14 он может выглядеть примерно так:

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

Ответ 4

Capistrano 3 Generic Version (выполнить любую команду rake)

Построение общей версии ответа Мирека Русина:

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

Пример использования: cap staging "invoke[db:migrate]"

Обратите внимание, что deploy:set_rails_env требуется, исходя из графа capistrano-rails

Ответ 5

Используйте призывы рейки в стиле Capistrano

Существует общий способ "просто работать" с require 'bundler/capistrano' и другими расширениями, которые изменяют rake. Это также будет работать с средами предварительной обработки, если вы используете многоступенчатый режим. Суть? Используйте config vars, если вы можете.

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

Ответ 6

Используйте capistrano-rake gem

Просто установите драгоценный камень, не испортивсь с помощью специальных рецептов capistrano и выполните требуемые задачи рейка на удаленных серверах, например:

cap production invoke:rake TASK=my:rake_task

Полное раскрытие: я написал его

Ответ 7

Я лично использую в производстве вспомогательный метод, подобный этому:

def run_rake(task, options={}, &block)
  command = "cd #{latest_release} && /usr/bin/env bundle exec rake #{task}"
  run(command, options, &block)
end

Это позволяет запускать задачу rake, аналогичную использованию метода run (command).


ПРИМЕЧАНИЕ. Это похоже на то, что предлагал герцог, но я:

  • используйте last_release вместо current_release - из моего опыта это больше того, чего вы ожидаете при запуске команды rake;
  • следуйте соглашению об именах Rake и Capistrano (вместо: cmd → task and rake → run_rake)
  • не устанавливайте RAILS_ENV = # {rails_env}, потому что правильным местом для его установки является переменная default_run_options. Например, default_run_options [: env] = {'RAILS_ENV' = > 'production'} # → DRY!

Ответ 8

Там интересный камень cape, который делает ваши задачи рейка доступными как задачи Capistrano, поэтому вы можете запускать их удаленно. cape хорошо документирован, но вот краткий обзор того, как настроить i.

После установки драгоценного камня просто добавьте это в свой config/deploy.rb файл.

# config/deploy.rb
require 'cape'
Cape do
  # Create Capistrano recipes for all Rake tasks.
  mirror_rake_tasks
end

Теперь вы можете запускать все задачи rake локально или удаленно через cap.

В качестве дополнительного бонуса cape позволяет установить, как вы хотите запускать свою рейк-задачу локально и удаленно (не более bundle exec rake), просто добавьте это в свой файл 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'

Ответ 9

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 

Ответ 10

Вот что я добавил в свой deploy.rb, чтобы упростить выполнение задач rake. Это простая оболочка вокруг метода capistrano run().

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

Затем я просто запускаю любую команду rake следующим образом:

rake 'app:compile:jammit'

Ответ 11

Это сработало для меня:

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

Затем просто запустите cap production "invoke[task_name]"

Ответ 12

Это также работает:

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

Дополнительная информация: Capistrano Run

Ответ 13

Большая часть из выше ответа с незначительным улучшением для запуска любой команды rake из capistrano

Запустите любую команду rake из 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

Ответ 14

Если вы хотите передать несколько аргументов, попробуйте это (на основе ответа 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

Затем вы можете запустить задачу следующим образом: cap production invoke["task","arg1","arg2"]

Ответ 15

Если задача Rake требует взаимодействия с пользователем, она не будет работать

Ответ 16

Итак, я работал над этим. он швы хорошо работает. Однако вам нужен форматир, чтобы действительно воспользоваться кодом.

Если вы не хотите использовать форматтера, просто установите уровень журнала в режим отладки. Эти семабы к h

SSHKit.config.output_verbosity = Logger::DEBUG

Cap 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

Это форматтер, который я построил для работы с указанным выше кодом. Он основан на: textimple встроенном в sshkit, но это не плохой способ вызвать пользовательские задачи. О, это многие не работают с новейшей версией sshkit gem. Я знаю, что это работает с 1.7.1. Я говорю это, потому что главная ветвь изменила доступные методы SSHKit:: Command.

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

Ответ 17

Я понятия не имею, как работает capistrano, но только для записи - это синтаксис, чтобы вызвать команду rake из Ruby:

Rake::Task["task:name"].invoke