Как мне запустить рейк-задачу из Capistrano?
-
10-07-2019 - |
Вопрос
У меня уже есть файл Deploy.rb, с помощью которого можно развернуть мое приложение на рабочем сервере.
Мое приложение содержит специальную задачу rake (файл .rake в каталоге lib/tasks).
Я хотел бы создать задачу ограничения, которая будет удаленно запускать эту задачу рейка.
Решение 2
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
был хитом - сначала я не думал об этом и не мог понять, почему задача ничего не делала.
Другие советы
Чуть более явно, в вашем \ 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
... пару лет спустя ...
Взгляните на плагин Capistrano's 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
Универсальная версия Capistrano 3 (запустите любую рейк-задачу)
Создание общей версии ответа Мирека Русина:
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
Использовать грабли в стиле 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
Используйте capistrano-rake
gem
Просто установите драгоценный камень, не вмешиваясь в пользовательские рецепты capistrano, и выполняйте требуемые грабли на удаленных серверах следующим образом:
cap production invoke:rake TASK=my:rake_task
Полное раскрытие: я написал это
Лично я использую в производстве такой вспомогательный метод:
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).
ПРИМЕЧАНИЕ:Это похоже на то, что герцог предложил, но я:
- используйтеlatest_release вместо current_release — по моему опыту, это больше того, что вы ожидаете при запуске команды rake;
- следуйте соглашению об именах Rake и Capistrano (вместо:cmd -> задача и грабли -> run_rake)
- не устанавливайте RAILS_ENV=#{rails_env}, потому что правильным местом для его установки является переменная default_run_options.Например, default_run_options[:env] = {'RAILS_ENV' => 'production'} # -> DRY!
Существует интересная вещь cape , которая делает ваши рейковые задачи доступными как задачи Capistrano, так что вы можете их запускать удаленно. cape
хорошо документирован, но вот краткий обзор того, как его настроить. Р>
После установки гема просто добавьте его в свой файл config / deploy.rb
.
# config/deploy.rb
require 'cape'
Cape do
# Create Capistrano recipes for all Rake tasks.
mirror_rake_tasks
end
Теперь вы можете выполнять все свои задачи rake
локально или удаленно с помощью cap
.
В качестве дополнительного бонуса cape
позволяет вам указать, как вы хотите запускать задачу rake локально и удаленно (не более 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'
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
Вот что я поместил в своем deploy.rb, чтобы упростить запуск граблей. Это простая оболочка для метода run () 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
Тогда я просто запускаю любую задачу с граблями, вот так:
rake 'app:compile:jammit'
Это сработало для меня:
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] "
Большинство из них из вышеупомянутого ответа с небольшим улучшением для запуска любой грабли из капистрано
Запустите любую задачу с граблями из Капистрано
$ 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
Это также работает:
run("cd #{release_path}/current && /usr/bin/rake <rake_task_name>", :env => {'RAILS_ENV' => rails_env})
Дополнительная информация: Запуск Capistrano р>
Если вы хотите передать несколько аргументов, попробуйте это (основываясь на ответе Мариносберна):
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 "]
Так что я работал над этим. это швы, чтобы работать хорошо. Однако вам нужен форматер, чтобы действительно воспользоваться преимуществами кода. Р>
Если вы не хотите использовать средство форматирования, просто установите уровень журнала в режим отладки. Эти семы на ч
SSHKit.config.output_verbosity = Logger::DEBUG
Cap Capff
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
Это форматтер, который я создал для работы с кодом выше. Он основан на: текстовом простом встроенном в sshkit, но это не плохой способ вызывать пользовательские задачи. Ох уж это не работает с новейшей версией сшкит гема. Я знаю, что это работает с 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