1

我在这里描述了同样的问题:

如何在另一个 Capistrano 的任务中调用 Capistrano 的任务?

但是回滚到 Capistrano v3.0.1 和 sshkit 1.0 的解决方案对我不起作用。

使用本教程,我在 lib/capistrano/tasks 中声明了自定义任务,这些任务使用存储在 lib/capistrano/ 中的 .rb 文件中标定的函数

帽文件:

# Load DSL and Setup Up Stages
require 'capistrano/setup'

# Includes default deployment tasks
require 'capistrano/deploy'

require 'capistrano/rails'

require 'capistrano/rvm'

# Loads custom tasks from `lib/capistrano/tasks' if you have any defined.
Dir.glob('lib/capistrano/tasks/*.cap').each { |r| import r }

# Loads custom tasks from all folders below `lib/capistrano' if you have any defined.
Dir.glob('lib/capistrano/**/*.rb').each { |r| import r }

# because the above didn't quite look right to me, and all the .rbs are in /lib/capistrano
Dir.glob('lib/capistrano/*.rb').each { |r| import r }

部署.rb

set :application, 'hello-rails'
set :app_shortname, 'hr'
set :repo_url, 'git@bitbutcket.org:me/myapp.git'  #<-substituted fake info here for this post

# Default value for :linked_files is []
set :linked_files, %w{config/database.yml config/application.yml}

# Default value for linked_dirs is []
 set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system}

# everything below this comment adapted from the talkingquickly tutorial
#which config files should be copied by deploy:setup_config
set(:config_files, %w(
  nginx.conf
  unicorn.rb
  unicorn_init.sh
))

# which config files should be made executable after copying
# by deploy:setup_config
set(:executable_config_files, %w(unicorn_init.sh))

# files which need to be symlinked
set(:symlinks, [
  {
    source: "nginx.conf",
    link: "/etc/nginx/sites-enabled/{{full_app_name}}"
  },
  {
    source: "unicorn_init.sh",
    link: "/etc/init.d/unicorn_{{full_app_name}}"
  }
])

#specify my ruby version
set :rvm_type, :system

#specify my gemset
set :rvm_ruby_version, '1.9.3-p385@hello-rails'

namespace :deploy do
  # make sure we're deploying what we think we're deploying
  before :deploy, "deploy:check_revision"
  # only allow a deploy with passing tests to deployed
  before :deploy, "deploy:run_tests"
  # compile assets locally then rsync
  after 'deploy:symlink:shared', 'deploy:compile_assets_locally'
  after :finishing, 'deploy:cleanup'
end

配置/暂存.rb

set :stage, :staging
set :branch, "cap-rails"
set :rails_env, :test

# used in case we're deploying multiple versions of the same
# app side by side. Also provides quick sanity checks when looking
# at filepaths
set :full_app_name, "#{fetch(:app_shortname)}_#{fetch(:stage)}"

set :deploy_to, "/srv/#{fetch(:app_shortname)}"

# number of unicorn workers
set :unicorn_worker_count, 5

# For building nginx config file
set :enable_ssl, false

# extended properties on the server.
server 'dev', user: 'deployer', roles: %w{web app}  #<-substituted fake info here for this post

# custom ssh options
 set :ssh_options, {
   user: 'deployer',  #<-substituted fake info here for this post
   keys: %w(path.to.key),  #<-substituted fake info here for this post
   forward_agent: true,
   auth_methods: %w(publickey)
 }

lib/capistrano/tasks/setup_config.cap

namespace :deploy do
  task :setup_config do
    on roles(:app) do
      # make the config dir
      execute :mkdir, "-p #{shared_path}/config"
      full_app_name = fetch(:full_app_name)

      # config files to be uploaded to shared/config, see the
      # definition of smart_template for details of operation.
      # Essentially looks for #{filename}.erb in deploy/#{full_app_name}/
      # and if it isn't there, falls back to deploy/#{shared}. Generally
      # everything should be in deploy/shared with params which differ
      # set in the stage files
      config_files = fetch(:config_files)
      config_files.each do |file|
        smart_template file
      end

      # which of the above files should be marked as executable
      executable_files = fetch(:executable_config_files)
      executable_files.each do |file|
        execute :chmod, "+x #{shared_path}/config/#{file}"
      end

      # symlink stuff which should be... symlinked
      symlinks = fetch(:symlinks)

      symlinks.each do |symlink|
        sudo "ln -nfs #{shared_path}/config/#{symlink[:source]} #{sub_strings(symlink[:link])}"
      end
    end
  end
end

lib/capistrano/template.rb

def smart_template(from, to=nil)
  to ||= from
  full_to_path = "#{shared_path}/config/#{to}"
  if from_erb_path = template_file(from)
    from_erb = StringIO.new(ERB.new(File.read(from_erb_path)).result(binding))
    upload! from_erb, full_to_path
    info "copying: #{from_erb} to: #{full_to_path}"
  else
    error "error #{from} not found"
  end
end

def template_file(name)
  if File.exist?((file = "config/deploy/#{fetch(:full_app_name)}/#{name}.erb"))
    return file
  elsif File.exist?((file = "config/deploy/shared/#{name}.erb"))
    return file
  end
  return nil
end

宝石文件

    source 'https://rubygems.org'

    # Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
    gem 'rails', '4.0.4'

    # Use sqlite3 as the database for Active Record
    gem 'sqlite3'

    # Use SCSS for stylesheets
    gem 'sass-rails', '~> 4.0.2'

    # Use Uglifier as compressor for JavaScript assets
    gem 'uglifier', '>= 1.3.0'

    # Use CoffeeScript for .js.coffee assets and views
    gem 'coffee-rails', '~> 4.0.0'

    # Use jquery as the JavaScript library
    gem 'jquery-rails'

    # Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks
    gem 'turbolinks'

    # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
    gem 'jbuilder', '~> 1.2'

    #because sshkit 1.3 has this bug: https://stackoverflow.com/questions/21401665/how-to-call-a-capistranos-task-within-another-capistranos-task
    gem 'sshkit', '~> 1.0.0'
    gem 'capistrano',  '~> 3.0.1'

    gem 'capistrano-rails', '~> 1.1'
    gem 'capistrano-rvm'

    group :doc do
      # bundle exec rake doc:rails generates the API under doc/api.
      gem 'sdoc', require: false
    end

Gemfile.lock

GEM
  remote: https://rubygems.org/
  specs:
    actionmailer (4.0.4)
      actionpack (= 4.0.4)
      mail (~> 2.5.4)
    actionpack (4.0.4)
      activesupport (= 4.0.4)
      builder (~> 3.1.0)
      erubis (~> 2.7.0)
      rack (~> 1.5.2)
      rack-test (~> 0.6.2)
    activemodel (4.0.4)
      activesupport (= 4.0.4)
      builder (~> 3.1.0)
    activerecord (4.0.4)
      activemodel (= 4.0.4)
      activerecord-deprecated_finders (~> 1.0.2)
      activesupport (= 4.0.4)
      arel (~> 4.0.0)
    activerecord-deprecated_finders (1.0.3)
    activesupport (4.0.4)
      i18n (~> 0.6, >= 0.6.9)
      minitest (~> 4.2)
      multi_json (~> 1.3)
      thread_safe (~> 0.1)
      tzinfo (~> 0.3.37)
    arel (4.0.2)
    atomic (1.1.16)
    builder (3.1.4)
    capistrano (3.0.1)
      i18n
      rake (>= 10.0.0)
      sshkit (>= 0.0.23)
    capistrano-bundler (1.0.0)
      capistrano (>= 3.0.0.pre)
    capistrano-rails (1.1.0)
      capistrano (>= 3.0.0)
      capistrano-bundler (>= 1.0.0)
    capistrano-rvm (0.0.3)
      capistrano
    coffee-rails (4.0.1)
      coffee-script (>= 2.2.0)
      railties (>= 4.0.0, < 5.0)
    coffee-script (2.2.0)
      coffee-script-source
      execjs
    coffee-script-source (1.7.0)
    erubis (2.7.0)
    execjs (2.0.2)
    hike (1.2.3)
    i18n (0.6.9)
    jbuilder (1.5.3)
      activesupport (>= 3.0.0)
      multi_json (>= 1.2.0)
    jquery-rails (3.1.0)
      railties (>= 3.0, < 5.0)
      thor (>= 0.14, < 2.0)
    json (1.8.1)
    mail (2.5.4)
      mime-types (~> 1.16)
      treetop (~> 1.4.8)
    mime-types (1.25.1)
    minitest (4.7.5)
    multi_json (1.9.2)
    net-scp (1.1.2)
      net-ssh (>= 2.6.5)
    net-ssh (2.8.0)
    polyglot (0.3.4)
    rack (1.5.2)
    rack-test (0.6.2)
      rack (>= 1.0)
    rails (4.0.4)
      actionmailer (= 4.0.4)
      actionpack (= 4.0.4)
      activerecord (= 4.0.4)
      activesupport (= 4.0.4)
      bundler (>= 1.3.0, < 2.0)
      railties (= 4.0.4)
      sprockets-rails (~> 2.0.0)
    railties (4.0.4)
      actionpack (= 4.0.4)
      activesupport (= 4.0.4)
      rake (>= 0.8.7)
      thor (>= 0.18.1, < 2.0)
    rake (10.2.2)
    rdoc (4.1.1)
      json (~> 1.4)
    sass (3.2.18)
    sass-rails (4.0.2)
      railties (>= 4.0.0, < 5.0)
      sass (~> 3.2.0)
      sprockets (~> 2.8, <= 2.11.0)
      sprockets-rails (~> 2.0.0)
    sdoc (0.4.0)
      json (~> 1.8)
      rdoc (~> 4.0, < 5.0)
    sprockets (2.11.0)
      hike (~> 1.2)
      multi_json (~> 1.0)
      rack (~> 1.0)
      tilt (~> 1.1, != 1.3.0)
    sprockets-rails (2.0.1)
      actionpack (>= 3.0)
      activesupport (>= 3.0)
      sprockets (~> 2.8)
    sqlite3 (1.3.9)
    sshkit (1.0.0)
      net-scp
      net-ssh
      term-ansicolor
    term-ansicolor (1.3.0)
      tins (~> 1.0)
    thor (0.19.1)
    thread_safe (0.3.1)
      atomic (>= 1.1.7, < 2)
    tilt (1.4.1)
    tins (1.0.1)
    treetop (1.4.15)
      polyglot
      polyglot (>= 0.3.1)
    turbolinks (2.2.1)
      coffee-rails
    tzinfo (0.3.39)
    uglifier (2.5.0)
      execjs (>= 0.3.0)
      json (>= 1.8.0)

PLATFORMS
  ruby

DEPENDENCIES
  capistrano (~> 3.0.1)
  capistrano-rails (~> 1.1)
  capistrano-rvm
  coffee-rails (~> 4.0.0)
  jbuilder (~> 1.2)
  jquery-rails
  rails (= 4.0.4)
  sass-rails (~> 4.0.2)
  sdoc
  sqlite3
  sshkit (~> 1.0.0)
  turbolinks
  uglifier (>= 1.3.0)

当我执行 bundle exec cap staging deploy:setup_config

我得到这个输出:

INFO [9e71d728] Running mkdir -p /srv/hr/shared/config on ruby-dev
DEBUG [9e71d728] Command: mkdir -p /srv/hr/shared/config
 INFO [9e71d728] Finished in 0.738 seconds command successful.
cap aborted!
NoMethodError: undefined method `smart_template' for #<SSHKit::Backend::Netssh:0x007f8a4dc04980>
/Users/nico/DevOps/repo/hello-rails/lib/capistrano/tasks/setup_config.cap:16:in `block (4 levels) in <top (required)>'
/Users/nico/DevOps/repo/hello-rails/lib/capistrano/tasks/setup_config.cap:15:in `each'
/Users/nico/DevOps/repo/hello-rails/lib/capistrano/tasks/setup_config.cap:15:in `block (3 levels) in <top (required)>'
/Users/nico/.rvm/gems/ruby-1.9.3-p385@hello-rails-cap-v3-sshkit-v1/gems/sshkit-1.0.0/lib/sshkit/backends/netssh.rb:42:in `instance_exec'
/Users/nico/.rvm/gems/ruby-1.9.3-p385@hello-rails-cap-v3-sshkit-v1/gems/sshkit-1.0.0/lib/sshkit/backends/netssh.rb:42:in `run'

看来使用 capistrano v3.0.1 和 sshkit v1.0 并不能解决我的问题。deploy:setup_config 任务正在尝试调用 lib/capistrano/template.rb 中定义的函数 smart_template,输出指示找不到该函数。我不知道如何让它正常工作。欢迎任何有关解决该问题的建议。此外,如果存在为 nginx 和 unicorn 创建配置和可执行文件的更好方法,我很想听听。

编辑

在怀疑来自 ruby​​gems 的 sshkit gem 仍然包含错误后,我添加了

gem 'sshkit', :git => 'https://github.com/capistrano/sshkit.git' 

到我的 Capfile 并重建我的本地 gemset。然而,这并没有解决问题,并指示我寻找其他地方。从那里我能够诊断出这个问题与我的 Capfile 中这些行定义的 ruby​​ 文件的导入有关:

Dir.glob('lib/capistrano/*.rb').each { |r| import r }
Dir.glob('lib/capistrano/**/*.rb').each { |r| import r }

我将这些行注释掉并替换为:

require_relative 'lib/capistrano/template.rb'
require_relative 'lib/capistrano/substitute_strings.rb'

我的 deploy:setup_config 任务现在可以正确调用这些函数。我导出了工作的 gem 集,并使用 ruby​​ gems 中的 sshkit 创建了一个新的 gemset。使用上面列出的 require_relative 行,来自 ruby​​gems 的 sshkit gem 运行良好。所以问题从来不在于 sshkit 中的错误,无论我使用的是哪个源(git 或 ruby​​gems),而是导入包含我的 cap 任务调用的函数的 ruby​​ 文件。

4

2 回答 2

1

您的示例有两个问题,正确的行是:

Dir.glob('lib/capistrano/tasks/*.cap').each { |r| import r }                                                                                                                                      
Dir.glob('lib/capistrano/**/*.rb').each { |r| import r }    

你可以在这里看到完整的例子

于 2014-04-16T00:31:43.400 回答
0

根据我在原始问题中的编辑,sshkit gem 的来源不是我的问题。相反,问题在于导入语句。

换行:

# Loads custom tasks from all folders below `lib/capistrano' if you have any defined.
Dir.glob('lib/capistrano/*.rb').each { |r| import r }
Dir.glob('lib/capistrano/**/*.rb').each { |r| import r }

至:

require_relative 'lib/capistrano/template.rb'
require_relative 'lib/capistrano/substitute_strings.rb'

为我解决了这个问题。

我不确定为什么 Dir.glob 方法对我不起作用,我假设操作员错误并期望弄清楚我做错了什么对于在未来的上限部署中概括导入很有用。

于 2014-04-01T13:44:16.803 回答