Domanda

Ho già un deploy.rb che può distribuire la mia app sul mio server di produzione.

La mia app contiene un'attività di rake personalizzata (un file .rake nella directory lib / task).

Vorrei creare un'attività limite che eseguirà in remoto quell'attività di rake.

È stato utile?

Soluzione 2

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

Trovato con Google - http : //ananelson.com/said/on/2007/12/30/remote-rake-tasks-with-capistrano/

Il RAILS_ENV = production era un gotcha - all'inizio non ci pensavo e non riuscivo a capire perché il compito non stesse facendo nulla.

Altri suggerimenti

Un po 'più esplicito, nel tuo \ config \ deploy.rb , aggiungi al di fuori di qualsiasi attività o spazio dei nomi:

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

Quindi, da / rails_root / , puoi eseguire:

cap staging rake:invoke task=rebuild_table_abc

... un paio d'anni dopo ...

Dai un'occhiata al plugin rails di capistrano, puoi vedere https://github.com/capistrano/rails/blob/master/lib/capistrano/tasks/migrations.rake#L5-L14 può assomigliare a:

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 Versione generica (esegui qualsiasi attività di rake)

Creazione di una versione generica della risposta di 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

Esempio di utilizzo: cap staging " invoke [db: migrate] "

Nota che deploy: set_rails_env richiede proviene dalla gemma capistrano-rails

Usa invocazioni di rake in stile Capistrano

C'è un modo comune che " semplicemente funzionerà " con richiedono 'bundler / capistrano' e altre estensioni che modificano il rake. Funzionerà anche con ambienti di pre-produzione se si utilizza il multistadio. L'essenza? Usa le configurazioni di configurazione se puoi.

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

Utilizza la capistrano-rake gem

Installa la gemma senza fare confusione con le ricette personalizzate di Capistrano ed esegui le attività di rake desiderate su server remoti in questo modo:

cap production invoke:rake TASK=my:rake_task

Divulgazione completa: l'ho scritto

Uso personalmente in produzione un metodo di supporto come questo:

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

Ciò consente di eseguire attività di rake simili all'utilizzo del metodo run (comando).


NOTA: è simile a ciò che Duke propose, ma io:

  • usa latest_release invece di current_release - dalla mia esperienza è più quello che ti aspetti quando esegui un comando rake;
  • segui la convenzione di denominazione di Rake e Capistrano (invece di: cmd - > task and rake - > run_rake)
  • non impostare RAILS_ENV = # {rails_env} perché il posto giusto per impostarlo è la variabile default_run_options. Ad esempio default_run_options [: env] = {'RAILS_ENV' = > 'produzione'} # - > SECCO!

C'è una gemma interessante mantellina che rende le tue attività di rake disponibili come attività di Capistrano, così puoi eseguirle da remoto. cape è ben documentato, ma ecco una breve panoramica su come configurarlo.

Dopo aver installato la gemma, basta aggiungerla al file config / deploy.rb .

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

Ora puoi eseguire tutte le tue attività rake localmente o in remoto tramite cap .

Come bonus aggiuntivo, mantello ti consente di impostare come eseguire l'attività di rake localmente e in remoto (non più bundle exec rake ), basta aggiungere questo al tuo File 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 

Ecco cosa ho inserito nel mio deploy.rb per semplificare l'esecuzione delle attività di rake. È un semplice wrapper per il metodo run () di 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

Quindi eseguo qualsiasi attività di rake in questo modo:

rake 'app:compile:jammit'

Questo ha funzionato per me:

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

Quindi esegui semplicemente cap production " invoke [task_name] "

La maggior parte proviene da sopra la risposta con un piccolo miglioramento per eseguire qualsiasi attività rake da capistrano

Esegui qualsiasi attività di rake da 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

Questo funziona anche:

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

Ulteriori informazioni: Capistrano Run

Se vuoi essere in grado di passare più argomenti, prova questo (basato sulla risposta di 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

Quindi puoi eseguire un'attività in questo modo: cap production invoke [" task ", " arg1 ", " arg2 "]

Quindi ci ho lavorato. sembra funzionare bene. Tuttavia è necessario un formattatore per sfruttare davvero il codice.

Se non si desidera utilizzare un formattatore, impostare il livello di registro su modalità debug. Queste semifinali a 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

Questo è il formatter che ho creato per funzionare con il codice sopra. È basato sul: semplice testo integrato in sshkit ma non è un brutto modo per invocare attività personalizzate. Oh, questo non funziona con l'ultima versione di sshkit gem. So che funziona con 1.7.1. Dico questo perché il ramo master ha modificato i metodi SSHKit :: Command disponibili.

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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top