我遇到了同样的问题:
How to call a Capistrano's task within another Capistrano's task?
然而,回滚到Capistrano v3.0.1和sshkit 1.0的解决方案对我来说不起作用。
使用this tutorial,我已经在lib / capistrano / tasks中声明了自定义任务,这些任务使用了存储在lib / capistrano /
中的.rb文件中的函数decalaredcapfile:
# 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 }
deploy.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
配置/ staging.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的/任务/ 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
的Gemfile
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的配置和可执行文件,我很乐意听到。
修改
在怀疑来自rubygems的sshkit gem仍然包含bug之后,我添加了
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任务正确调用了这些函数。我导出了工作宝石集,并使用来自ruby gems的sshkit创建了一个新的宝石集。使用上面列出的require_relative行,rubygems中的sshkit gem工作正常。因此问题从来都不是sshkit中的错误,无论我使用哪个源(git或rubygems),而是导入包含我的cap任务所调用的函数的ruby文件。
答案 0 :(得分:1)
您的示例有两个问题,正确的行是:
Dir.glob('lib/capistrano/tasks/*.cap').each { |r| import r }
Dir.glob('lib/capistrano/**/*.rb').each { |r| import r }
您可以看到完整示例here
答案 1 :(得分: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方法对我不起作用,我认为操作员错误,期望弄清楚我做错了将有助于在未来的帽子部署中推广导入。