capistrano-3.4.0/0000755000004100000410000000000012511755114013713 5ustar www-datawww-datacapistrano-3.4.0/Rakefile0000644000004100000410000000026012511755114015356 0ustar www-datawww-datarequire "bundler/gem_tasks" require "cucumber/rake/task" require "rspec/core/rake_task" task :default => :spec RSpec::Core::RakeTask.new Cucumber::Rake::Task.new(:features) capistrano-3.4.0/bin/0000755000004100000410000000000012511755114014463 5ustar www-datawww-datacapistrano-3.4.0/bin/capify0000755000004100000410000000036212511755114015665 0ustar www-datawww-data#!/usr/bin/env ruby puts "-" * 80 puts "Capistrano 3.x is incompatible with Capistrano 2.x. " puts puts "This command has become `cap install` in Capistrano 3.x" puts puts "For more information see http://www.capistranorb.com/" puts "-" * 80 capistrano-3.4.0/bin/cap0000755000004100000410000000011512511755114015151 0ustar www-datawww-data#!/usr/bin/env ruby require 'capistrano/all' Capistrano::Application.new.run capistrano-3.4.0/capistrano.gemspec0000644000004100000410000000275412511755114017433 0ustar www-datawww-data# -*- encoding: utf-8 -*- lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'capistrano/version' Gem::Specification.new do |gem| gem.name = "capistrano" gem.version = Capistrano::VERSION gem.authors = ["Tom Clements", "Lee Hambley"] gem.email = ["seenmyfate@gmail.com", "lee.hambley@gmail.com"] gem.description = %q{Capistrano is a utility and framework for executing commands in parallel on multiple remote machines, via SSH.} gem.summary = %q{Capistrano - Welcome to easy deployment with Ruby over SSH} gem.homepage = "http://capistranorb.com/" gem.files = `git ls-files`.split($/) gem.executables = ['cap', 'capify'] gem.test_files = gem.files.grep(%r{^(test|spec|features)/}) gem.require_paths = ["lib"] gem.licenses = ['MIT'] gem.post_install_message = < 1.3' gem.add_dependency 'rake', '>= 10.0.0' gem.add_dependency 'i18n' gem.add_development_dependency 'rspec' gem.add_development_dependency 'mocha' end capistrano-3.4.0/Gemfile0000644000004100000410000000024212511755114015204 0ustar www-datawww-datasource 'https://rubygems.org' # Specify your gem's dependencies in capistrano.gemspec gemspec group :cucumber do gem 'cucumber' gem 'rspec', '~> 3.0.0' end capistrano-3.4.0/features/0000755000004100000410000000000012511755114015531 5ustar www-datawww-datacapistrano-3.4.0/features/step_definitions/0000755000004100000410000000000012511755114021077 5ustar www-datawww-datacapistrano-3.4.0/features/step_definitions/setup.rb0000644000004100000410000000311312511755114022562 0ustar www-datawww-dataGiven(/^a test app with the default configuration$/) do TestApp.install end Given(/^servers with the roles app and web$/) do vagrant_cli_command('up') rescue nil end Given(/^a linked file "(.*?)"$/) do |file| # ignoring other linked files TestApp.append_to_deploy_file("set :linked_files, ['#{file}']") end Given(/^file "(.*?)" exists in shared path$/) do |file| file_shared_path = TestApp.shared_path.join(file) run_vagrant_command("mkdir -p #{TestApp.shared_path}") run_vagrant_command("touch #{file_shared_path}") end Given(/^file "(.*?)" does not exist in shared path$/) do |file| file_shared_path = TestApp.shared_path.join(file) run_vagrant_command("mkdir -p #{TestApp.shared_path}") run_vagrant_command("touch #{file_shared_path} && rm #{file_shared_path}") end Given(/^a custom task to generate a file$/) do TestApp.copy_task_to_test_app('spec/support/tasks/database.rake') end Given(/^a task which executes as root$/) do TestApp.copy_task_to_test_app('spec/support/tasks/root.rake') end Given(/config stage file has line "(.*?)"/) do |line| TestApp.append_to_deploy_file(line) end Given(/^the configuration is in a custom location$/) do TestApp.move_configuration_to_custom_location('app') end Given(/^a custom task that will simulate a failure$/) do safely_remove_file(TestApp.shared_path.join('failed')) TestApp.copy_task_to_test_app('spec/support/tasks/fail.rake') end Given(/^a custom task to run in the event of a failure$/) do safely_remove_file(TestApp.shared_path.join('failed')) TestApp.copy_task_to_test_app('spec/support/tasks/failed.rake') end capistrano-3.4.0/features/step_definitions/assertions.rb0000644000004100000410000000666612511755114023634 0ustar www-datawww-dataThen(/^references in the remote repo are listed$/) do expect(@output).to include('refs/heads/master') end Then(/^the shared path is created$/) do run_vagrant_command(test_dir_exists(TestApp.shared_path)) end Then(/^the releases path is created$/) do run_vagrant_command(test_dir_exists(TestApp.releases_path)) end Then(/^directories in :linked_dirs are created in shared$/) do TestApp.linked_dirs.each do |dir| run_vagrant_command(test_dir_exists(TestApp.shared_path.join(dir))) end end Then(/^directories referenced in :linked_files are created in shared$/) do dirs = TestApp.linked_files.map { |path| TestApp.shared_path.join(path).dirname } dirs.each do | dir| run_vagrant_command(test_dir_exists(dir)) end end Then(/^the repo is cloned$/) do run_vagrant_command(test_dir_exists(TestApp.repo_path)) end Then(/^the release is created$/) do run_vagrant_command("ls -g #{TestApp.releases_path}") end Then(/^file symlinks are created in the new release$/) do TestApp.linked_files.each do |file| run_vagrant_command(test_symlink_exists(TestApp.current_path.join(file))) end end Then(/^directory symlinks are created in the new release$/) do pending TestApp.linked_dirs.each do |dir| run_vagrant_command(test_symlink_exists(TestApp.release_path.join(dir))) end end Then(/^the current directory will be a symlink to the release$/) do run_vagrant_command(test_symlink_exists(TestApp.current_path)) end Then(/^the deploy\.rb file is created$/) do file = TestApp.test_app_path.join('config/deploy.rb') expect(File.exists?(file)).to be true end Then(/^the default stage files are created$/) do staging = TestApp.test_app_path.join('config/deploy/staging.rb') production = TestApp.test_app_path.join('config/deploy/production.rb') expect(File.exists?(staging)).to be true expect(File.exists?(production)).to be true end Then(/^the tasks folder is created$/) do path = TestApp.test_app_path.join('lib/capistrano/tasks') expect(Dir.exists?(path)).to be true end Then(/^the specified stage files are created$/) do qa = TestApp.test_app_path.join('config/deploy/qa.rb') production = TestApp.test_app_path.join('config/deploy/production.rb') expect(File.exists?(qa)).to be true expect(File.exists?(production)).to be true end Then(/^it creates the file with the remote_task prerequisite$/) do TestApp.linked_files.each do |file| run_vagrant_command(test_file_exists(TestApp.shared_path.join(file))) end end Then(/^it will not recreate the file$/) do # end Then(/^the task is successful$/) do expect(@success).to be true end Then(/^the task fails$/) do expect(@success).to be_falsey end Then(/^the failure task will run$/) do failed = TestApp.shared_path.join('failed') run_vagrant_command(test_file_exists(failed)) end Then(/^the failure task will not run$/) do failed = TestApp.shared_path.join('failed') expect { run_vagrant_command(test_file_exists(failed)) } .to raise_error(VagrantHelpers::VagrantSSHCommandError) end When(/^an error is raised$/) do error = TestApp.shared_path.join('fail') run_vagrant_command(test_file_exists(error)) end Then(/contains "([^"]*)" in the output/) do |expected| expect(@output).to include(expected) end Then(/the output matches "([^"]*)" followed by "([^"]*)"/) do |expected, followedby| expect(@output).to match(/#{expected}.*#{followedby}/m) end Then(/doesn't contain "([^"]*)" in the output/) do |expected| expect(@output).not_to include(expected) end capistrano-3.4.0/features/step_definitions/cap_commands.rb0000644000004100000410000000043112511755114024046 0ustar www-datawww-dataWhen(/^I run cap "(.*?)"$/) do |task| @success, @output = TestApp.cap(task) end When(/^I run cap "(.*?)" as part of a release$/) do |task| TestApp.cap("deploy:new_release_path #{task}") end When(/^I run "(.*?)"$/) do |command| @success, @output = TestApp.run(command) end capistrano-3.4.0/features/configuration.feature0000644000004100000410000000200712511755114021754 0ustar www-datawww-dataFeature: The path to the configuration can be changed, removing the need to follow Ruby/Rails conventions Background: Given a test app with the default configuration And servers with the roles app and web Scenario: Deploying with configuration in default location When I run "cap test" Then the task is successful Scenario: Deploying with configuration in a custom location But the configuration is in a custom location When I run "cap test" Then the task is successful Scenario: Show install task with configuration in default location When I run "cap -T" Then the task is successful And contains "install" in the output Scenario: Hide install task with configuration in a custom location And config stage file has line "desc 'Special Task'" And config stage file has line "task :special_stage_task" But the configuration is in a custom location When I run "cap -T" Then the task is successful And doesn't contain "special_stage_task" in the output capistrano-3.4.0/features/deploy.feature0000644000004100000410000000353712511755114020412 0ustar www-datawww-dataFeature: Deploy Background: Given a test app with the default configuration And servers with the roles app and web Scenario: Creating the repo When I run cap "git:check" Then the task is successful And references in the remote repo are listed Scenario: Creating the directory structure When I run cap "deploy:check:directories" Then the shared path is created And the releases path is created Scenario: Creating linked directories When I run cap "deploy:check:linked_dirs" Then directories in :linked_dirs are created in shared Scenario: Creating linked directories for linked files When I run cap "deploy:check:make_linked_dirs" Then directories referenced in :linked_files are created in shared Scenario: Checking linked files - missing file Given a linked file "missing_file.txt" But file "missing_file.txt" does not exist in shared path When I run cap "deploy:check:linked_files" Then the task fails Scenario: Checking linked files - file exists Given a linked file "existing_file.txt" And file "existing_file.txt" exists in shared path When I run cap "deploy:check:linked_files" Then the task is successful Scenario: Creating a release Given I run cap "deploy:check:directories" When I run cap "git:create_release" as part of a release Then the repo is cloned And the release is created Scenario: Symlink linked files When I run cap "deploy:symlink:linked_files deploy:symlink:release" as part of a release Then file symlinks are created in the new release Scenario: Symlink linked dirs When I run cap "deploy:symlink:linked_dirs" as part of a release Then directory symlinks are created in the new release Scenario: Publishing When I run cap "deploy:symlink:release" Then the current directory will be a symlink to the release capistrano-3.4.0/features/deploy_failure.feature0000644000004100000410000000100112511755114022101 0ustar www-datawww-dataFeature: Deploy failure Background: Given a test app with the default configuration And a custom task that will simulate a failure And a custom task to run in the event of a failure And servers with the roles app and web Scenario: Triggering the custom task When I run cap "deploy:starting" But an error is raised Then the failure task will not run Scenario: Triggering the custom task When I run cap "deploy" But an error is raised Then the failure task will run capistrano-3.4.0/features/sshconnect.feature0000644000004100000410000000060112511755114021252 0ustar www-datawww-dataFeature: SSH Connection Background: Given a test app with the default configuration And servers with the roles app and web And a task which executes as root Scenario: Switching from default user to root and back again When I run cap "am_i_root" Then the task is successful And the output matches "I am uid=0\(root\)" followed by "I am uid=\d+\(vagrant\)" capistrano-3.4.0/features/installation.feature0000644000004100000410000000073412511755114021613 0ustar www-datawww-dataFeature: Installation Background: Given a test app with the default configuration Scenario: With default stages When I run cap "install" Then the deploy.rb file is created And the default stage files are created And the tasks folder is created Scenario: With specified stages When I run cap "install STAGES=qa,production" Then the deploy.rb file is created And the specified stage files are created And the tasks folder is created capistrano-3.4.0/features/remote_file_task.feature0000644000004100000410000000071312511755114022423 0ustar www-datawww-dataFeature: Remote file task Background: Given a test app with the default configuration And a custom task to generate a file And servers with the roles app and web Scenario: Where the file does not exist When I run cap "deploy:check:linked_files" Then it creates the file with the remote_task prerequisite Scenario: Where the file already exists When I run cap "deploy:check:linked_files" Then it will not recreate the file capistrano-3.4.0/features/support/0000755000004100000410000000000012511755114017245 5ustar www-datawww-datacapistrano-3.4.0/features/support/remote_command_helpers.rb0000644000004100000410000000065512511755114024313 0ustar www-datawww-datamodule RemoteCommandHelpers def test_dir_exists(path) exists?('d', path) end def test_symlink_exists(path) exists?('L', path) end def test_file_exists(path) exists?('f', path) end def exists?(type, path) %{[ -#{type} "#{path}" ]} end def safely_remove_file(path) run_vagrant_command("rm #{test_file}") rescue VagrantHelpers::VagrantSSHCommandError end end World(RemoteCommandHelpers) capistrano-3.4.0/features/support/vagrant_helpers.rb0000644000004100000410000000140112511755114022752 0ustar www-datawww-datamodule VagrantHelpers extend self class VagrantSSHCommandError < RuntimeError; end at_exit do if ENV['KEEP_RUNNING'] puts "Vagrant vm will be left up because KEEP_RUNNING is set." puts "Rerun without KEEP_RUNNING set to cleanup the vm." else vagrant_cli_command("destroy -f") end end def vagrant_cli_command(command) puts "[vagrant] #{command}" Dir.chdir(VAGRANT_ROOT) do `#{VAGRANT_BIN} #{command} 2>&1`.split("\n").each do |line| puts "[vagrant] #{line}" end end $? end def run_vagrant_command(command) if (status = vagrant_cli_command("ssh -c #{command.inspect}")).success? true else fail VagrantSSHCommandError, status end end end World(VagrantHelpers) capistrano-3.4.0/features/support/env.rb0000644000004100000410000000047612511755114020371 0ustar www-datawww-dataPROJECT_ROOT = File.expand_path('../../../', __FILE__) VAGRANT_ROOT = File.join(PROJECT_ROOT, 'spec/support') VAGRANT_BIN = ENV['VAGRANT_BIN'] || "vagrant" at_exit do if ENV['KEEP_RUNNING'] VagrantHelpers.run_vagrant_command("rm -rf /home/vagrant/var") end end require_relative '../../spec/support/test_app' capistrano-3.4.0/LICENSE.txt0000644000004100000410000000210512511755114015534 0ustar www-datawww-dataMIT License (MIT) Copyright (c) 2012-2013 Tom Clements, Lee Hambley Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. capistrano-3.4.0/spec/0000755000004100000410000000000012511755114014645 5ustar www-datawww-datacapistrano-3.4.0/spec/spec_helper.rb0000644000004100000410000000075612511755114017473 0ustar www-datawww-data$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) $LOAD_PATH.unshift(File.dirname(__FILE__)) require 'capistrano/all' require 'rspec' require 'mocha/api' require 'time' # Requires supporting files with custom matchers and macros, etc, # in ./support/ and its subdirectories. Dir['#{File.dirname(__FILE__)}/support/**/*.rb'].each {|f| require f} RSpec.configure do |config| config.raise_errors_for_deprecations! config.mock_framework = :mocha config.order = 'random' end capistrano-3.4.0/spec/lib/0000755000004100000410000000000012511755114015413 5ustar www-datawww-datacapistrano-3.4.0/spec/lib/capistrano_spec.rb0000644000004100000410000000016112511755114021113 0ustar www-datawww-datarequire 'spec_helper' module Capistrano describe Application do let(:app) { Application.new } end end capistrano-3.4.0/spec/lib/capistrano/0000755000004100000410000000000012511755114017556 5ustar www-datawww-datacapistrano-3.4.0/spec/lib/capistrano/git_spec.rb0000644000004100000410000000434112511755114021702 0ustar www-datawww-datarequire 'spec_helper' require 'capistrano/git' module Capistrano describe Git do let(:context) { Class.new.new } subject { Capistrano::Git.new(context, Capistrano::Git::DefaultStrategy) } describe "#git" do it "should call execute git in the context, with arguments" do context.expects(:execute).with(:git, :init) subject.git(:init) end end end describe Git::DefaultStrategy do let(:context) { Class.new.new } subject { Capistrano::Git.new(context, Capistrano::Git::DefaultStrategy) } describe "#test" do it "should call test for repo HEAD" do context.expects(:repo_path).returns("/path/to/repo") context.expects(:test).with " [ -f /path/to/repo/HEAD ] " subject.test end end describe "#check" do it "should test the repo url" do context.expects(:repo_url).returns(:url) context.expects(:execute).with(:git, :'ls-remote --heads', :url).returns(true) subject.check end end describe "#clone" do it "should run git clone" do context.expects(:repo_url).returns(:url) context.expects(:repo_path).returns(:path) context.expects(:execute).with(:git, :clone, '--mirror', :url, :path) subject.clone end end describe "#update" do it "should run git update" do context.expects(:execute).with(:git, :remote, :update) subject.update end end describe "#release" do it "should run git archive without a subtree" do context.expects(:fetch).with(:repo_tree).returns(nil) context.expects(:fetch).with(:branch).returns(:branch) context.expects(:release_path).returns(:path) context.expects(:execute).with(:git, :archive, :branch, '| tar -x -f - -C', :path) subject.release end it "should run git archive with a subtree" do context.expects(:fetch).with(:repo_tree).returns('tree') context.expects(:fetch).with(:branch).returns(:branch) context.expects(:release_path).returns(:path) context.expects(:execute).with(:git, :archive, :branch, 'tree', '| tar -x --strip-components 1 -f - -C', :path) subject.release end end end end capistrano-3.4.0/spec/lib/capistrano/hg_spec.rb0000644000004100000410000000427212511755114021520 0ustar www-datawww-datarequire 'spec_helper' require 'capistrano/hg' module Capistrano describe Hg do let(:context) { Class.new.new } subject { Capistrano::Hg.new(context, Capistrano::Hg::DefaultStrategy) } describe "#hg" do it "should call execute hg in the context, with arguments" do context.expects(:execute).with(:hg, :init) subject.hg(:init) end end end describe Hg::DefaultStrategy do let(:context) { Class.new.new } subject { Capistrano::Hg.new(context, Capistrano::Hg::DefaultStrategy) } describe "#test" do it "should call test for repo HEAD" do context.expects(:repo_path).returns("/path/to/repo") context.expects(:test).with " [ -d /path/to/repo/.hg ] " subject.test end end describe "#check" do it "should test the repo url" do context.expects(:repo_url).returns(:url) context.expects(:execute).with(:hg, "id", :url) subject.check end end describe "#clone" do it "should run hg clone" do context.expects(:repo_url).returns(:url) context.expects(:repo_path).returns(:path) context.expects(:execute).with(:hg, "clone", '--noupdate', :url, :path) subject.clone end end describe "#update" do it "should run hg update" do context.expects(:execute).with(:hg, "pull") subject.update end end describe "#release" do it "should run hg archive without a subtree" do context.expects(:fetch).with(:repo_tree).returns(nil) context.expects(:fetch).with(:branch).returns(:branch) context.expects(:release_path).returns(:path) context.expects(:execute).with(:hg, "archive", :path, "--rev", :branch) subject.release end it "should run hg archive with a subtree" do context.expects(:fetch).with(:repo_tree).returns('tree') context.expects(:fetch).with(:branch).returns(:branch) context.expects(:release_path).returns(:path) context.expects(:execute).with(:hg, "archive --type tgz -p . -I", 'tree', "--rev", :branch, '| tar -x --strip-components 1 -f - -C', :path) subject.release end end end end capistrano-3.4.0/spec/lib/capistrano/scm_spec.rb0000644000004100000410000000456012511755114021704 0ustar www-datawww-datarequire 'spec_helper' require 'capistrano/scm' module RaiseNotImplementedMacro def raise_not_implemented_on(method) it "should raise NotImplemented on #{method}" do expect { subject.send(method) }.to raise_error(NotImplementedError) end end end RSpec.configure do include RaiseNotImplementedMacro end module DummyStrategy def test test!("you dummy!") end end module BlindStrategy; end module Capistrano describe SCM do let(:context) { Class.new.new } describe "#initialize" do subject { Capistrano::SCM.new(context, DummyStrategy) } it "should load the provided strategy" do context.expects(:test).with("you dummy!") subject.test end end describe "Convenience methods" do subject { Capistrano::SCM.new(context, BlindStrategy) } describe "#test!" do it "should return call test on the context" do context.expects(:test).with(:x) subject.test!(:x) end end describe "#repo_url" do it "should return the repo url according to the context" do context.expects(:repo_url).returns(:url) expect(subject.repo_url).to eq(:url) end end describe "#repo_path" do it "should return the repo path according to the context" do context.expects(:repo_path).returns(:path) expect(subject.repo_path).to eq(:path) end end describe "#release_path" do it "should return the release path according to the context" do context.expects(:release_path).returns('/path/to/nowhere') expect(subject.release_path).to eq('/path/to/nowhere') end end describe "#fetch" do it "should call fetch on the context" do context.expects(:fetch) subject.fetch(:branch) end end end describe "With a 'blind' strategy" do subject { Capistrano::SCM.new(context, BlindStrategy) } describe "#test" do raise_not_implemented_on(:test) end describe "#check" do raise_not_implemented_on(:check) end describe "#clone" do raise_not_implemented_on(:clone) end describe "#update" do raise_not_implemented_on(:update) end describe "#release" do raise_not_implemented_on(:release) end end end end capistrano-3.4.0/spec/lib/capistrano/version_validator_spec.rb0000644000004100000410000000416012511755114024650 0ustar www-datawww-datarequire 'spec_helper' module Capistrano describe VersionValidator do let(:validator) { VersionValidator.new(version) } let(:version) { stub } describe '#new' do it 'takes a version' do expect(validator) end end describe '#verify' do let(:current_version) { '3.0.1' } subject { validator.verify } before do validator.stubs(:current_version).returns(current_version) end context 'with exact version' do context 'valid' do let(:version) { '3.0.1' } it { expect(subject).to be_truthy } end context 'invalid - lower' do let(:version) { '3.0.0' } it 'fails' do expect { subject }.to raise_error end end context 'invalid - higher' do let(:version) { '3.0.2' } it 'fails' do expect { subject }.to raise_error end end end context 'with optimistic versioning' do context 'valid' do let(:version) { '>= 3.0.0' } it { expect(subject).to be_truthy } end context 'invalid - lower' do let(:version) { '<= 2.0.0' } it 'fails' do expect { subject }.to raise_error end end end context 'with pessimistic versioning' do context '2 decimal places' do context 'valid' do let(:version) { '~> 3.0.0' } it { expect(subject).to be_truthy } end context 'invalid' do let(:version) { '~> 3.1.0' } it 'fails' do expect { subject }.to raise_error end end end context '1 decimal place' do let(:current_version) { '3.5.0' } context 'valid' do let(:version) { '~> 3.1' } it { expect(subject).to be_truthy } end context 'invalid' do let(:version) { '~> 3.6' } it 'fails' do expect { subject }.to raise_error end end end end end end end capistrano-3.4.0/spec/lib/capistrano/configuration/0000755000004100000410000000000012511755114022425 5ustar www-datawww-datacapistrano-3.4.0/spec/lib/capistrano/configuration/server_spec.rb0000644000004100000410000002133012511755114025271 0ustar www-datawww-datarequire 'spec_helper' module Capistrano class Configuration describe Server do let(:server) { Server.new('root@hostname:1234') } describe 'adding a role' do subject { server.add_role(:test) } it 'adds the role' do expect{subject}.to change{server.roles.size}.from(0).to(1) end end describe 'adding roles' do subject { server.add_roles([:things, :stuff]) } it 'adds the roles' do expect{subject}.to change{server.roles.size}.from(0).to(2) end end describe 'checking roles' do subject { server.has_role?(:test) } before do server.add_role(:test) end it 'adds the role' do expect(subject).to be_truthy end end describe 'comparing identity' do subject { server.hostname == Server[hostname].hostname } context 'with the same user, hostname and port' do let(:hostname) { 'root@hostname:1234' } it { expect(subject).to be_truthy } end context 'with a different user' do let(:hostname) { 'deployer@hostname:1234' } it { expect(subject).to be_truthy } end context 'with a different port' do let(:hostname) { 'root@hostname:5678' } it { expect(subject).to be_truthy } end context 'with a different hostname' do let(:hostname) { 'root@otherserver:1234' } it { expect(subject).to be_falsey } end end describe 'identifying as primary' do subject { server.primary } context 'server is primary' do before do server.set(:primary, true) end it 'returns self' do expect(subject).to eq server end end context 'server is not primary' do it 'is falesy' do expect(subject).to be_falsey end end end describe 'assigning properties' do before do server.with(properties) end context 'properties contains roles' do let(:properties) { {roles: [:clouds]} } it 'adds the roles' do expect(server.roles.first).to eq :clouds end end context 'properties contains user' do let(:properties) { {user: 'tomc'} } it 'sets the user' do expect(server.user).to eq 'tomc' end it 'sets the netssh_options user' do expect(server.netssh_options[:user]).to eq 'tomc' end end context 'properties contains port' do let(:properties) { {port: 2222} } it 'sets the port' do expect(server.port).to eq 2222 end end context 'properties contains key' do let(:properties) { {key: '/key'} } it 'adds the key' do expect(server.keys).to include '/key' end end context 'properties contains password' do let(:properties) { {password: 'supersecret'} } it 'adds the key' do expect(server.password).to eq 'supersecret' end end context 'new properties' do let(:properties) { { webscales: 5 } } it 'adds the properties' do expect(server.properties.webscales).to eq 5 end end context 'existing properties' do let(:properties) { { webscales: 6 } } it 'keeps the existing properties' do expect(server.properties.webscales).to eq 6 server.properties.webscales = 5 expect(server.properties.webscales).to eq 5 end end end describe '#include?' do let(:options) { {} } subject { server.select?(options) } before do server.properties.active = true end context 'options are empty' do it { expect(subject).to be_truthy } end context 'value is a symbol' do context 'value matches server property' do context 'with :filter' do let(:options) { { filter: :active }} it { expect(subject).to be_truthy } end context 'with :select' do let(:options) { { select: :active }} it { expect(subject).to be_truthy } end context 'with :exclude' do let(:options) { { exclude: :active }} it { expect(subject).to be_falsey } end end context 'value does not match server properly' do context 'with :active true' do let(:options) { { active: true }} it { expect(subject).to be_truthy } end context 'with :active false' do let(:options) { { active: false }} it { expect(subject).to be_falsey } end end context 'value does not match server properly' do context 'with :filter' do let(:options) { { filter: :inactive }} it { expect(subject).to be_falsey } end context 'with :select' do let(:options) { { select: :inactive }} it { expect(subject).to be_falsey } end context 'with :exclude' do let(:options) { { exclude: :inactive }} it { expect(subject).to be_truthy } end end end context 'key is a property' do context 'with :active true' do let(:options) { { active: true }} it { expect(subject).to be_truthy } end context 'with :active false' do let(:options) { { active: false }} it { expect(subject).to be_falsey } end end context 'value is a proc' do context 'value matches server property' do context 'with :filter' do let(:options) { { filter: ->(s) { s.properties.active } } } it { expect(subject).to be_truthy } end context 'with :select' do let(:options) { { select: ->(s) { s.properties.active } } } it { expect(subject).to be_truthy } end context 'with :exclude' do let(:options) { { exclude: ->(s) { s.properties.active } } } it { expect(subject).to be_falsey } end end context 'value does not match server properly' do context 'with :filter' do let(:options) { { filter: ->(s) { s.properties.inactive } } } it { expect(subject).to be_falsey } end context 'with :select' do let(:options) { { select: ->(s) { s.properties.inactive } } } it { expect(subject).to be_falsey } end context 'with :exclude' do let(:options) { { exclude: ->(s) { s.properties.inactive } } } it { expect(subject).to be_truthy } end end end end describe 'assign ssh_options' do let(:server) { Server.new('user_name@hostname') } context 'defaults' do it 'forward agent' do expect(server.netssh_options[:forward_agent]).to eq true end it 'contains user' do expect(server.netssh_options[:user]).to eq 'user_name' end end context 'custom' do let(:properties) do { ssh_options: { user: 'another_user', keys: %w(/home/another_user/.ssh/id_rsa), forward_agent: false, auth_methods: %w(publickey password) } } end before do server.with(properties) end it 'not forward agent' do expect(server.netssh_options[:forward_agent]).to eq false end it 'contains correct user' do expect(server.netssh_options[:user]).to eq 'another_user' end it 'does not affect server user in host' do expect(server.user).to eq 'user_name' end it 'contains keys' do expect(server.netssh_options[:keys]).to eq %w(/home/another_user/.ssh/id_rsa) end it 'contains auth_methods' do expect(server.netssh_options[:auth_methods]).to eq %w(publickey password) end end end describe ".[]" do it 'creates a server if its argument is not already a server' do expect(Server['hostname:1234']).to be_a Server end it 'returns its argument if it is already a server' do expect(Server[server]).to be server end end end end end capistrano-3.4.0/spec/lib/capistrano/configuration/servers_spec.rb0000644000004100000410000003017112511755114025457 0ustar www-datawww-datarequire 'spec_helper' module Capistrano class Configuration describe Servers do let(:servers) { Servers.new } describe 'adding a role' do it 'adds two new server instances' do expect{servers.add_role(:app, %w{1 2})}. to change{servers.count}.from(0).to(2) end it 'handles de-duplification within roles' do servers.add_role(:app, %w{1}) servers.add_role(:app, %w{1}) expect(servers.count).to eq 1 end it 'handles de-duplification within roles with users' do servers.add_role(:app, %w{1}, user: 'nick') servers.add_role(:app, %w{1}, user: 'fred') expect(servers.count).to eq 1 end it 'accepts instances of server objects' do servers.add_role(:app, [Capistrano::Configuration::Server.new('example.net'), 'example.com']) expect(servers.roles_for([:app]).length).to eq 2 end it 'accepts non-enumerable types' do servers.add_role(:app, '1') expect(servers.roles_for([:app]).count).to eq 1 end it 'creates distinct server properties' do servers.add_role(:db, %w{1 2}, db: { port: 1234 } ) servers.add_host('1', db: { master: true }) expect(servers.count).to eq(2) expect(servers.roles_for([:db]).count).to eq 2 expect(servers.find(){|s| s.hostname == '1'}.properties.db).to eq({ port: 1234, master: true }) expect(servers.find(){|s| s.hostname == '2'}.properties.db).to eq({ port: 1234 }) end end describe 'adding a role to an existing server' do before do servers.add_role(:web, %w{1 2}) servers.add_role(:app, %w{1 2}) end it 'adds new roles to existing servers' do expect(servers.count).to eq 2 end end describe 'collecting server roles' do let(:app) { Set.new([:app]) } let(:web_app) { Set.new([:web, :app]) } let(:web) { Set.new([:web]) } before do servers.add_role(:app, %w{1 2 3}) servers.add_role(:web, %w{2 3 4}) end it 'returns an array of the roles' do expect(servers.roles_for([:app]).collect(&:roles)).to eq [app, web_app, web_app] expect(servers.roles_for([:web]).collect(&:roles)).to eq [web_app, web_app, web] end end describe 'finding the primary server' do after do Configuration.reset! end it 'takes the first server if none have the primary property' do servers.add_role(:app, %w{1 2}) expect(servers.fetch_primary(:app).hostname).to eq('1') end it 'takes the first server with the primary have the primary flag' do servers.add_role(:app, %w{1 2}) servers.add_host('2', primary: true) expect(servers.fetch_primary(:app).hostname).to eq('2') end it 'ignores any on_filters' do Configuration.env.set :filter, { host: '1'} servers.add_role(:app, %w{1 2}) servers.add_host('2', primary: true) expect(servers.fetch_primary(:app).hostname).to eq('2') end end describe 'fetching servers' do before do servers.add_role(:app, %w{1 2}) servers.add_role(:web, %w{2 3}) end it 'returns the correct app servers' do expect(servers.roles_for([:app]).map(&:hostname)).to eq %w{1 2} end it 'returns the correct web servers' do expect(servers.roles_for([:web]).map(&:hostname)).to eq %w{2 3} end it 'returns the correct app and web servers' do expect(servers.roles_for([:app, :web]).map(&:hostname)).to eq %w{1 2 3} end it 'returns all servers' do expect(servers.roles_for([:all]).map(&:hostname)).to eq %w{1 2 3} end end describe 'adding a server' do before do servers.add_host('1', roles: [:app, 'web'], test: :value) end it 'can create a server with properties' do expect(servers.roles_for([:app]).first.hostname).to eq '1' expect(servers.roles_for([:web]).first.hostname).to eq '1' expect(servers.roles_for([:all]).first.properties.test).to eq :value expect(servers.roles_for([:all]).first.properties.keys).to eq [:test] end it 'can accept multiple servers with the same hostname but different ports or users' do servers.add_host('1', roles: [:app, 'web'], test: :value, port: 12) servers.add_host('1', roles: [:app, 'web'], test: :value, port: 34) servers.add_host('1', roles: [:app, 'web'], test: :value, user: 'root') servers.add_host('1', roles: [:app, 'web'], test: :value, user: 'deployer') servers.add_host('1', roles: [:app, 'web'], test: :value, user: 'root', port: 34) servers.add_host('1', roles: [:app, 'web'], test: :value, user: 'deployer', port: 34) servers.add_host('1', roles: [:app, 'web'], test: :value, user: 'deployer', port: 56) expect(servers.count).to eq(1) end describe "with a :user property" do it 'sets the server ssh username' do servers.add_host('1', roles: [:app, 'web'], user: 'nick') expect(servers.count).to eq(1) expect(servers.roles_for([:all]).first.user).to eq 'nick' end it 'overwrites the value of a user specified in the hostname' do servers.add_host('brian@1', roles: [:app, 'web'], user: 'nick') expect(servers.count).to eq(1) expect(servers.roles_for([:all]).first.user).to eq 'nick' end end it 'overwrites the value of a previously defined scalar property' do servers.add_host('1', roles: [:app, 'web'], test: :volatile) expect(servers.count).to eq(1) expect(servers.roles_for([:all]).first.properties.test).to eq :volatile end it 'merges previously defined hash properties' do servers.add_host('1', roles: [:b], db: { port: 1234 }) servers.add_host('1', roles: [:b], db: { master: true }) expect(servers.count).to eq(1) expect(servers.roles_for([:b]).first.properties.db).to eq({ port: 1234, master: true }) end it 'concatenates previously defined array properties' do servers.add_host('1', roles: [:b], steps: [1,3,5]) servers.add_host('1', roles: [:b], steps: [1,9]) expect(servers.count).to eq(1) expect(servers.roles_for([:b]).first.properties.steps).to eq([1,3,5,1,9]) end it 'merges previously defined set properties' do servers.add_host('1', roles: [:b], endpoints: Set[123,333]) servers.add_host('1', roles: [:b], endpoints: Set[222,333]) expect(servers.count).to eq(1) expect(servers.roles_for([:b]).first.properties.endpoints).to eq(Set[123,222,333]) end it 'adds array property value only ones for a new host' do servers.add_host('2', roles: [:array_test], array_property: [1,2]) expect(servers.roles_for([:array_test]).first.properties.array_property).to eq [1,2] end it 'updates roles when custom user defined' do servers.add_host('1', roles: ['foo'], user: 'custom') servers.add_host('1', roles: ['bar'], user: 'custom') expect(servers.roles_for([:foo]).first.hostname).to eq '1' expect(servers.roles_for([:bar]).first.hostname).to eq '1' end it 'updates roles when custom port defined' do servers.add_host('1', roles: ['foo'], port: 1234) servers.add_host('1', roles: ['bar'], port: 1234) expect(servers.roles_for([:foo]).first.hostname).to eq '1' expect(servers.roles_for([:bar]).first.hostname).to eq '1' end end describe 'selecting roles' do before do servers.add_host('1', roles: :app, active: true) servers.add_host('2', roles: :app) end it 'is empty if the filter would remove all matching hosts' do expect(servers.roles_for([:app, select: :inactive])).to be_empty end it 'can filter hosts by properties on the host object using symbol as shorthand' do expect(servers.roles_for([:app, filter: :active]).length).to eq 1 end it 'can select hosts by properties on the host object using symbol as shorthand' do expect(servers.roles_for([:app, select: :active]).length).to eq 1 end it 'can filter hosts by properties on the host using a regular proc' do expect(servers.roles_for([:app, filter: ->(h) { h.properties.active }]).length).to eq 1 end it 'can select hosts by properties on the host using a regular proc' do expect(servers.roles_for([:app, select: ->(h) { h.properties.active }]).length).to eq 1 end it 'is empty if the regular proc filter would remove all matching hosts' do expect(servers.roles_for([:app, select: ->(h) { h.properties.inactive }])).to be_empty end end describe 'excluding by property' do before do servers.add_host('1', roles: :app, active: true) servers.add_host('2', roles: :app, active: true, no_release: true) end it 'is empty if the filter would remove all matching hosts' do hosts = servers.roles_for([:app, exclude: :active]) expect(hosts.map(&:hostname)).to be_empty end it 'returns the servers without the attributes specified' do hosts = servers.roles_for([:app, exclude: :no_release]) expect(hosts.map(&:hostname)).to eq %w{1} end it 'can exclude hosts by properties on the host using a regular proc' do hosts = servers.roles_for([:app, exclude: ->(h) { h.properties.no_release }]) expect(hosts.map(&:hostname)).to eq %w{1} end it 'is empty if the regular proc filter would remove all matching hosts' do hosts = servers.roles_for([:app, exclude: ->(h) { h.properties.active }]) expect(hosts.map(&:hostname)).to be_empty end end describe 'filtering roles internally' do before do servers.add_host('1', roles: :app, active: true) servers.add_host('2', roles: :app) servers.add_host('3', roles: :web) servers.add_host('4', roles: :web) servers.add_host('5', roles: :db) end subject { servers.roles_for(roles).map(&:hostname) } context 'with the ROLES environment variable set' do before do ENV.stubs(:[]).with('ROLES').returns('web,db') ENV.stubs(:[]).with('HOSTS').returns(nil) end context 'when selecting all roles' do let(:roles) { [:all] } it 'ignores it' do expect(subject).to eq %w{1 2 3 4 5} end end context 'when selecting specific roles' do let(:roles) { [:app, :web] } it 'ignores it' do expect(subject).to eq %w{1 2 3 4} end end context 'when selecting roles not included in ROLE' do let(:roles) { [:app] } it 'ignores it' do expect(subject).to eq %w{1 2} end end end context 'with the HOSTS environment variable set' do before do ENV.stubs(:[]).with('ROLES').returns(nil) ENV.stubs(:[]).with('HOSTS').returns('3,5') end context 'when selecting all roles' do let(:roles) { [:all] } it 'ignores it' do expect(subject).to eq %w{1 2 3 4 5} end end context 'when selecting specific roles' do let(:roles) { [:app, :web] } it 'ignores it' do expect(subject).to eq %w{1 2 3 4} end end context 'when selecting no roles' do let(:roles) { [] } it 'ignores it' do expect(subject).to be_empty end end end end end end end capistrano-3.4.0/spec/lib/capistrano/configuration/filter_spec.rb0000644000004100000410000001055512511755114025257 0ustar www-datawww-datarequire 'spec_helper' module Capistrano class Configuration describe Filter do let(:available) { [ Server.new('server1').add_roles([:web,:db]), Server.new('server2').add_role(:web), Server.new('server3').add_role(:redis), Server.new('server4').add_role(:db), Server.new('server5').add_role(:stageweb) ] } describe '#new' do it "won't create an invalid type of filter" do expect { f = Filter.new(:zarg) }.to raise_error RuntimeError end it 'creates an empty host filter' do expect(Filter.new(:host).filter(available)).to be_empty end it 'creates a null host filter' do expect(Filter.new(:host, :all).filter(available)).to eq(available) end it 'creates an empty role filter' do expect(Filter.new(:role).filter(available)).to be_empty end it 'creates a null role filter' do expect(Filter.new(:role, :all).filter(available)).to eq(available) end end describe 'host filter' do it 'works with a single server' do set = Filter.new(:host, 'server1').filter(available.first) expect(set.map(&:hostname)).to eq(%w{server1}) end it 'returns all hosts matching a string' do set = Filter.new(:host, 'server1').filter(available) expect(set.map(&:hostname)).to eq(%w{server1}) end it 'returns all hosts matching a comma-separated string' do set = Filter.new(:host, 'server1,server3').filter(available) expect(set.map(&:hostname)).to eq(%w{server1 server3}) end it 'returns all hosts matching an array of strings' do set = Filter.new(:host, %w{server1 server3}).filter(available) expect(set.map(&:hostname)).to eq(%w{server1 server3}) end it 'returns all hosts matching regexp' do set = Filter.new(:host, 'server[13]$').filter(available) expect(set.map(&:hostname)).to eq(%w{server1 server3}) end it 'correctly identifies a regex with a comma in' do set = Filter.new(:host, 'server\d{1,3}$').filter(available) expect(set.map(&:hostname)).to eq(%w{server1 server2 server3 server4 server5}) end end describe 'role filter' do it 'returns all hosts' do set = Filter.new(:role, [:all]).filter(available) expect(set.size).to eq(available.size) expect(set.first.hostname).to eq('server1') end it 'returns hosts in a single string role' do set = Filter.new(:role, 'web').filter(available) expect(set.size).to eq(2) expect(set.map(&:hostname)).to eq(%w{server1 server2}) end it 'returns hosts in a single role' do set = Filter.new(:role, [:web]).filter(available) expect(set.size).to eq(2) expect(set.map(&:hostname)).to eq(%w{server1 server2}) end it 'returns hosts in multiple roles specified by a string' do set = Filter.new(:role, 'web,db').filter(available) expect(set.size).to eq(3) expect(set.map(&:hostname)).to eq(%w{server1 server2 server4}) end it 'returns hosts in multiple roles' do set = Filter.new(:role, [:web, :db]).filter(available) expect(set.size).to eq(3) expect(set.map(&:hostname)).to eq(%w{server1 server2 server4}) end it 'returns only hosts for explicit roles' do set = Filter.new(:role, [:web]).filter(available) expect(set.size).to eq(2) expect(set.map(&:hostname)).to eq(%w{server1 server2}) end it 'returns hosts with regex role selection' do set = Filter.new(:role, /red/).filter(available) expect(set.map(&:hostname)).to eq(%w{server3}) end it 'returns hosts with regex role selection using a string' do set = Filter.new(:role, '/red|web/').filter(available) expect(set.map(&:hostname)).to eq(%w{server1 server2 server3 server5}) end it 'returns hosts with combination of string role and regex' do set = Filter.new(:role, 'db,/red/').filter(available) expect(set.map(&:hostname)).to eq(%w{server1 server3 server4}) end end end end end capistrano-3.4.0/spec/lib/capistrano/configuration/question_spec.rb0000644000004100000410000000270612511755114025640 0ustar www-datawww-datarequire 'spec_helper' module Capistrano class Configuration describe Question do let(:question) { Question.new(key, default, options) } let(:question_without_echo) { Question.new(key, default, echo: false) } let(:default) { :default } let(:key) { :branch } let(:options) { nil } describe '.new' do it 'takes a key, default, options' do question end end describe '#call' do context 'value is entered' do let(:branch) { 'branch' } before do $stdout.expects(:print).with('Please enter branch (default): ') end it 'returns the echoed value' do $stdin.expects(:gets).returns(branch) $stdin.expects(:noecho).never expect(question.call).to eq(branch) end it 'returns the value but does not echo it' do $stdin.expects(:noecho).returns(branch) $stdout.expects(:print).with("\n") expect(question_without_echo.call).to eq(branch) end end context 'value is not entered' do let(:branch) { default } before do $stdout.expects(:print).with('Please enter branch (default): ') $stdin.expects(:gets).returns('') end it 'returns the default as the value' do expect(question.call).to eq(branch) end end end end end end capistrano-3.4.0/spec/lib/capistrano/upload_task_spec.rb0000644000004100000410000000107112511755114023422 0ustar www-datawww-datarequire 'spec_helper' describe Capistrano::UploadTask do let(:app) { Rake.application = Rake::Application.new } subject(:upload_task) { described_class.define_task('path/file.yml') } it { is_expected.to be_a(Rake::FileCreationTask) } it { is_expected.to be_needed } context 'inside namespace' do let(:normal_task) { Rake::Task.define_task('path/other_file.yml') } around { |ex| app.in_namespace('namespace', &ex) } it { expect(upload_task.name).to eq('path/file.yml') } it { expect(upload_task.scope.path).to eq('namespace') } end end capistrano-3.4.0/spec/lib/capistrano/dsl_spec.rb0000644000004100000410000000171712511755114021705 0ustar www-datawww-datarequire 'spec_helper' module Capistrano class DummyDSL include DSL end # see also - spec/integration/dsl_spec.rb describe DSL do let(:dsl) { DummyDSL.new } describe '#t' do before do I18n.expects(:t).with(:phrase, {count: 2, scope: :capistrano}) end it 'delegates to I18n' do dsl.t(:phrase, count: 2) end end describe '#stage_set?' do subject { dsl.stage_set? } context 'stage is set' do before do dsl.set(:stage, :sandbox) end it { expect(subject).to be_truthy } end context 'stage is not set' do before do dsl.set(:stage, nil) end it { expect(subject).to be_falsey } end end describe '#sudo' do before do dsl.expects(:execute).with(:sudo, :my, :command) end it 'prepends sudo, delegates to execute' do dsl.sudo(:my, :command) end end end end capistrano-3.4.0/spec/lib/capistrano/dsl/0000755000004100000410000000000012511755114020340 5ustar www-datawww-datacapistrano-3.4.0/spec/lib/capistrano/dsl/task_enhancements_spec.rb0000644000004100000410000000443612511755114025400 0ustar www-datawww-datarequire 'spec_helper' module Capistrano class DummyTaskEnhancements include TaskEnhancements end describe TaskEnhancements do let(:task_enhancements) { DummyTaskEnhancements.new } describe 'ordering' do after do task.clear before_task.clear after_task.clear Rake::Task.clear end let(:order) { [] } let!(:task) do Rake::Task.define_task('task', [:order]) do |t, args| args['order'].push 'task' end end let!(:before_task) do Rake::Task.define_task('before_task') do order.push 'before_task' end end let!(:after_task) do Rake::Task.define_task('after_task') do order.push 'after_task' end end it 'invokes in proper order if define after than before' do task_enhancements.after('task', 'after_task') task_enhancements.before('task', 'before_task') Rake::Task['task'].invoke order expect(order).to eq(['before_task', 'task', 'after_task']) end it 'invokes in proper order if define before than after' do task_enhancements.before('task', 'before_task') task_enhancements.after('task', 'after_task') Rake::Task['task'].invoke order expect(order).to eq(['before_task', 'task', 'after_task']) end it 'invokes in proper order and with arguments and block' do task_enhancements.after('task', 'after_task_custom', :order) do |t, args| order.push 'after_task' end task_enhancements.before('task', 'before_task_custom', :order) do |t, args| order.push 'before_task' end Rake::Task['task'].invoke(order) expect(order).to eq(['before_task', 'task', 'after_task']) end end describe 'remote_file' do subject(:remote_file) { task_enhancements.remote_file('source' => 'destination') } it { expect(remote_file.name).to eq('source') } it { is_expected.to be_a(Capistrano::UploadTask) } describe 'namespaced' do let(:app) { Rake.application } around { |ex| app.in_namespace('namespace', &ex) } it { expect(remote_file.name).to eq('source') } it { is_expected.to be_a(Capistrano::UploadTask) } end end end end capistrano-3.4.0/spec/lib/capistrano/dsl/paths_spec.rb0000644000004100000410000001101112511755114023010 0ustar www-datawww-datarequire 'spec_helper' describe Capistrano::DSL::Paths do let(:dsl) { Class.new.extend Capistrano::DSL } let(:parent) { Pathname.new('/var/shared') } let(:paths) { Class.new.extend Capistrano::DSL::Paths } let(:linked_dirs) { %w{log public/system} } let(:linked_files) { %w{config/database.yml log/my.log} } before do dsl.set(:deploy_to, '/var/www') end describe '#linked_dirs' do subject { paths.linked_dirs(parent) } before do paths.expects(:fetch).with(:linked_dirs).returns(linked_dirs) end it 'returns the full pathnames' do expect(subject).to eq [Pathname.new('/var/shared/log'), Pathname.new('/var/shared/public/system')] end end describe '#linked_files' do subject { paths.linked_files(parent) } before do paths.expects(:fetch).with(:linked_files).returns(linked_files) end it 'returns the full pathnames' do expect(subject).to eq [Pathname.new('/var/shared/config/database.yml'), Pathname.new('/var/shared/log/my.log')] end end describe '#linked_file_dirs' do subject { paths.linked_file_dirs(parent) } before do paths.expects(:fetch).with(:linked_files).returns(linked_files) end it 'returns the full paths names of the parent dirs' do expect(subject).to eq [Pathname.new('/var/shared/config'), Pathname.new('/var/shared/log')] end end describe '#linked_dir_parents' do subject { paths.linked_dir_parents(parent) } before do paths.expects(:fetch).with(:linked_dirs).returns(linked_dirs) end it 'returns the full paths names of the parent dirs' do expect(subject).to eq [Pathname.new('/var/shared'), Pathname.new('/var/shared/public')] end end describe '#release path' do subject { dsl.release_path } context 'where no release path has been set' do before do dsl.delete(:release_path) end it 'returns the `current_path` value' do expect(subject.to_s).to eq '/var/www/current' end end context 'where the release path has been set' do before do dsl.set(:release_path,'/var/www/release_path') end it 'returns the set `release_path` value' do expect(subject.to_s).to eq '/var/www/release_path' end end end describe '#set_release_path' do let(:now) { Time.parse("Oct 21 16:29:00 2015") } subject { dsl.release_path } context 'without a timestamp' do before do dsl.env.expects(:timestamp).returns(now) dsl.set_release_path end it 'returns the release path with the current env timestamp' do expect(subject.to_s).to eq '/var/www/releases/20151021162900' end end context 'with a timestamp' do before do dsl.set_release_path('timestamp') end it 'returns the release path with the timestamp' do expect(subject.to_s).to eq '/var/www/releases/timestamp' end end end describe '#deploy_config_path' do subject { dsl.deploy_config_path.to_s } context 'when not specified' do before do dsl.delete(:deploy_config_path) end it 'returns "config/deploy.rb"' do expect(subject).to eq 'config/deploy.rb' end end context 'when the variable :deploy_config_path is set' do before do dsl.set(:deploy_config_path, 'my/custom/path.rb') end it 'returns the custom path' do expect(subject).to eq 'my/custom/path.rb' end end end describe '#stage_config_path' do subject { dsl.stage_config_path.to_s } context 'when not specified' do before do dsl.delete(:stage_config_path) end it 'returns "config/deploy"' do expect(subject).to eq 'config/deploy' end end context 'when the variable :stage_config_path is set' do before do dsl.set(:stage_config_path, 'my/custom/path') end it 'returns the custom path' do expect(subject).to eq 'my/custom/path' end end end describe '#repo_path' do subject { dsl.repo_path.to_s } context 'when not specified' do before do dsl.delete(:repo_path) end it 'returns the default #{deploy_to}/repo' do dsl.set(:deploy_to, '/var/www') expect(subject).to eq '/var/www/repo' end end context 'when the variable :repo_path is set' do before do dsl.set(:repo_path, 'my/custom/path') end it 'returns the custom path' do expect(subject).to eq 'my/custom/path' end end end end capistrano-3.4.0/spec/lib/capistrano/application_spec.rb0000644000004100000410000000365712511755114023433 0ustar www-datawww-datarequire 'spec_helper' describe Capistrano::Application do it "provides a --trace option which enables SSHKit/NetSSH trace output" it "provides a --format option which enables the choice of output formatting" let(:help_output) do out, _ = capture_io do flags '--help', '-h' end out end it "displays documentation URL as help banner" do expect(help_output.lines.first).to match(/capistranorb.com/) end %w(quiet silent verbose).each do |switch| it "doesn't include --#{switch} in help" do expect(help_output).not_to match(/--#{switch}/) end end it "overrides the rake method, but still prints the rake version" do out, _ = capture_io do flags '--version', '-V' end expect(out).to match(/\bCapistrano Version\b/) expect(out).to match(/\b#{Capistrano::VERSION}\b/) expect(out).to match(/\bRake Version\b/) expect(out).to match(/\b#{RAKEVERSION}\b/) end it "overrides the rake method, and sets the sshkit_backend to SSHKit::Backend::Printer" do out, _ = capture_io do flags '--dry-run', '-n' end sshkit_backend = Capistrano::Configuration.fetch(:sshkit_backend) expect(sshkit_backend).to eq(SSHKit::Backend::Printer) end def flags(*sets) sets.each do |set| ARGV.clear @exit = catch(:system_exit) { command_line(*set) } end yield(subject.options) if block_given? end def command_line(*options) options.each { |opt| ARGV << opt } def subject.exit(*args) throw(:system_exit, :exit) end subject.run subject.options end def capture_io require 'stringio' orig_stdout, orig_stderr = $stdout, $stderr captured_stdout, captured_stderr = StringIO.new, StringIO.new $stdout, $stderr = captured_stdout, captured_stderr yield return captured_stdout.string, captured_stderr.string ensure $stdout = orig_stdout $stderr = orig_stderr end end capistrano-3.4.0/spec/lib/capistrano/configuration_spec.rb0000644000004100000410000001236412511755114023772 0ustar www-datawww-datarequire 'spec_helper' module Capistrano describe Configuration do let(:config) { Configuration.new } let(:servers) { stub } describe '.new' do it 'accepts initial hash' do configuration = described_class.new(custom: 'value') expect(configuration.fetch(:custom)).to eq('value') end end describe '.env' do it 'is a global accessor to a single instance' do Configuration.env.set(:test, true) expect(Configuration.env.fetch(:test)).to be_truthy end end describe '.reset!' do it 'blows away the existing `env` and creates a new one' do old_env = Configuration.env Configuration.reset! expect(Configuration.env).not_to be old_env end end describe 'roles' do context 'adding a role' do subject { config.role(:app, %w{server1 server2}) } before do Configuration::Servers.expects(:new).returns(servers) servers.expects(:add_role).with(:app, %w{server1 server2}, {}) end it 'adds the role' do expect(subject) end end end describe 'setting and fetching' do subject { config.fetch(:key, :default) } context 'value is set' do before do config.set(:key, :value) end it 'returns the set value' do expect(subject).to eq :value end end context 'set_if_empty' do it 'sets the value when none is present' do config.set_if_empty(:key, :value) expect(subject).to eq :value end it 'does not overwrite the value' do config.set(:key, :value) config.set_if_empty(:key, :update) expect(subject).to eq :value end end context 'value is not set' do it 'returns the default value' do expect(subject).to eq :default end end context 'value is a proc' do subject { config.fetch(:key, Proc.new { :proc } ) } it 'calls the proc' do expect(subject).to eq :proc end end context 'value is a lambda' do subject { config.fetch(:key, lambda { :lambda } ) } it 'calls the lambda' do expect(subject).to eq :lambda end end context 'value inside proc inside a proc' do subject { config.fetch(:key, Proc.new { Proc.new { "some value" } } ) } it 'calls all procs and lambdas' do expect(subject).to eq "some value" end end context 'value inside lambda inside a lambda' do subject { config.fetch(:key, lambda { lambda { "some value" } } ) } it 'calls all procs and lambdas' do expect(subject).to eq "some value" end end context 'value inside lambda inside a proc' do subject { config.fetch(:key, Proc.new { lambda { "some value" } } ) } it 'calls all procs and lambdas' do expect(subject).to eq "some value" end end context 'value inside proc inside a lambda' do subject { config.fetch(:key, lambda { Proc.new { "some value" } } ) } it 'calls all procs and lambdas' do expect(subject).to eq "some value" end end context 'lambda with parameters' do subject { config.fetch(:key, lambda { |c| c }).call(42) } it 'is returned as a lambda' do expect(subject).to eq 42 end end context 'block is passed to fetch' do subject { config.fetch(:key, :default) { fail 'we need this!' } } it 'returns the block value' do expect { subject }.to raise_error end end end describe 'keys' do subject { config.keys } before do config.set(:key1, :value1) config.set(:key2, :value2) end it 'returns all set keys' do expect(subject).to match_array [:key1, :key2] end end describe 'deleting' do before do config.set(:key, :value) end it 'deletes the value' do config.delete(:key) expect(config.fetch(:key)).to be_nil end end describe 'asking' do let(:question) { stub } let(:options) { Hash.new } before do Configuration::Question.expects(:new).with(:branch, :default, options). returns(question) end it 'prompts for the value when fetching' do config.ask(:branch, :default, options) expect(config.fetch(:branch)).to eq question end end describe 'setting the backend' do it 'by default, is SSHKit' do expect(config.backend).to eq SSHKit end it 'can be set to another class' do config.backend = :test expect(config.backend).to eq :test end describe "ssh_options for Netssh" do it 'merges them with the :ssh_options variable' do config.set :format, :pretty config.set :log_level, :debug config.set :ssh_options, { user: 'albert' } SSHKit::Backend::Netssh.configure do |ssh| ssh.ssh_options = { password: 'einstein' } end config.configure_backend expect(config.backend.config.backend.config.ssh_options).to eq({ user: 'albert', password: 'einstein' }) end end end end end capistrano-3.4.0/spec/lib/capistrano/svn_spec.rb0000644000004100000410000000363212511755114021727 0ustar www-datawww-datarequire 'spec_helper' require 'capistrano/svn' module Capistrano describe Svn do let(:context) { Class.new.new } subject { Capistrano::Svn.new(context, Capistrano::Svn::DefaultStrategy) } describe "#svn" do it "should call execute svn in the context, with arguments" do context.expects(:execute).with(:svn, :init) subject.svn(:init) end end end describe Svn::DefaultStrategy do let(:context) { Class.new.new } subject { Capistrano::Svn.new(context, Capistrano::Svn::DefaultStrategy) } describe "#test" do it "should call test for repo HEAD" do context.expects(:repo_path).returns("/path/to/repo") context.expects(:test).with " [ -d /path/to/repo/.svn ] " subject.test end end describe "#check" do it "should test the repo url" do context.expects(:repo_url).returns(:url) context.expects(:test).with(:svn, :info, :url).returns(true) subject.check end end describe "#clone" do it "should run svn checkout" do context.expects(:repo_url).returns(:url) context.expects(:repo_path).returns(:path) context.expects(:execute).with(:svn, :checkout, :url, :path) subject.clone end end describe "#update" do it "should run svn update" do context.expects(:execute).with(:svn, :update) subject.update end end describe "#release" do it "should run svn export" do context.expects(:release_path).returns(:path) context.expects(:execute).with(:svn, :export, '--force', '.', :path) subject.release end end describe "#fetch_revision" do it "should run fetch revision" do context.expects(:repo_path).returns(:path) context.expects(:capture).with(:svnversion, :path) subject.fetch_revision end end end end capistrano-3.4.0/spec/integration/0000755000004100000410000000000012511755114017170 5ustar www-datawww-datacapistrano-3.4.0/spec/integration/dsl_spec.rb0000644000004100000410000004315312511755114021317 0ustar www-datawww-datarequire 'spec_helper' describe Capistrano::DSL do let(:dsl) { Class.new.extend Capistrano::DSL } before do Capistrano::Configuration.reset! end describe 'setting and fetching hosts' do describe 'when defining a host using the `server` syntax' do before do dsl.server 'example1.com', roles: %w{web}, active: true dsl.server 'example2.com', roles: %w{web} dsl.server 'example3.com', roles: %w{app web}, active: true dsl.server 'example4.com', roles: %w{app}, primary: true dsl.server 'example5.com', roles: %w{db}, no_release: true, active:true end describe 'fetching all servers' do subject { dsl.roles(:all) } it 'returns all servers' do expect(subject.map(&:hostname)).to eq %w{example1.com example2.com example3.com example4.com example5.com} end end describe 'fetching all release servers' do context 'with no additional options' do subject { dsl.release_roles(:all) } it 'returns all release servers' do expect(subject.map(&:hostname)).to eq %w{example1.com example2.com example3.com example4.com} end end context 'with property filter options' do subject { dsl.release_roles(:all, filter: :active) } it 'returns all release servers that match the property filter' do expect(subject.map(&:hostname)).to eq %w{example1.com example3.com} end end end describe 'fetching servers by multiple roles' do it "does not confuse the last role with options" do expect(dsl.roles(:app, :web).count).to eq 4 expect(dsl.roles(:app, :web, filter: :active).count).to eq 2 end end describe 'fetching servers by role' do subject { dsl.roles(:app) } it 'returns the servers' do expect(subject.map(&:hostname)).to eq %w{example3.com example4.com} end end describe 'fetching servers by an array of roles' do subject { dsl.roles([:app]) } it 'returns the servers' do expect(subject.map(&:hostname)).to eq %w{example3.com example4.com} end end describe 'fetching filtered servers by role' do subject { dsl.roles(:app, filter: :active) } it 'returns the servers' do expect(subject.map(&:hostname)).to eq %w{example3.com} end end describe 'fetching selected servers by role' do subject { dsl.roles(:app, select: :active) } it 'returns the servers' do expect(subject.map(&:hostname)).to eq %w{example3.com} end end describe 'fetching the primary server by role' do context 'when inferring primary status based on order' do subject { dsl.primary(:web) } it 'returns the servers' do expect(subject.hostname).to eq 'example1.com' end end context 'when the attribute `primary` is explicitly set' do subject { dsl.primary(:app) } it 'returns the servers' do expect(subject.hostname).to eq 'example4.com' end end end describe 'setting an internal host filter' do subject { dsl.roles(:app) } it 'is ignored' do dsl.set :filter, { host: 'example3.com' } expect(subject.map(&:hostname)).to eq(['example3.com', 'example4.com']) end end describe 'setting an internal role filter' do subject { dsl.roles(:app) } it 'ignores it' do dsl.set :filter, { role: :web } expect(subject.map(&:hostname)).to eq(['example3.com','example4.com']) end end describe 'setting an internal host and role filter' do subject { dsl.roles(:app) } it 'ignores it' do dsl.set :filter, { role: :web, host: 'example1.com' } expect(subject.map(&:hostname)).to eq(['example3.com','example4.com']) end end describe 'setting an internal regexp host filter' do subject { dsl.roles(:all) } it 'is ignored' do dsl.set :filter, { host: /1/ } expect(subject.map(&:hostname)).to eq(%w{example1.com example2.com example3.com example4.com example5.com}) end end end describe 'when defining role with reserved name' do it 'fails with ArgumentError' do expect { dsl.role :all, %w{example1.com} }.to raise_error(ArgumentError, "all reserved name for role. Please choose another name") end end describe 'when defining hosts using the `role` syntax' do before do dsl.role :web, %w{example1.com example2.com example3.com} dsl.role :web, %w{example1.com}, active: true dsl.role :app, %w{example3.com example4.com} dsl.role :app, %w{example3.com}, active: true dsl.role :app, %w{example4.com}, primary: true dsl.role :db, %w{example5.com}, no_release: true end describe 'fetching all servers' do subject { dsl.roles(:all) } it 'returns all servers' do expect(subject.map(&:hostname)).to eq %w{example1.com example2.com example3.com example4.com example5.com} end end describe 'fetching all release servers' do context 'with no additional options' do subject { dsl.release_roles(:all) } it 'returns all release servers' do expect(subject.map(&:hostname)).to eq %w{example1.com example2.com example3.com example4.com} end end context 'with filter options' do subject { dsl.release_roles(:all, filter: :active) } it 'returns all release servers that match the filter' do expect(subject.map(&:hostname)).to eq %w{example1.com example3.com} end end end describe 'fetching servers by role' do subject { dsl.roles(:app) } it 'returns the servers' do expect(subject.map(&:hostname)).to eq %w{example3.com example4.com} end end describe 'fetching servers by an array of roles' do subject { dsl.roles([:app]) } it 'returns the servers' do expect(subject.map(&:hostname)).to eq %w{example3.com example4.com} end end describe 'fetching filtered servers by role' do subject { dsl.roles(:app, filter: :active) } it 'returns the servers' do expect(subject.map(&:hostname)).to eq %w{example3.com} end end describe 'fetching selected servers by role' do subject { dsl.roles(:app, select: :active) } it 'returns the servers' do expect(subject.map(&:hostname)).to eq %w{example3.com} end end describe 'fetching the primary server by role' do context 'when inferring primary status based on order' do subject { dsl.primary(:web) } it 'returns the servers' do expect(subject.hostname).to eq 'example1.com' end end context 'when the attribute `primary` is explicity set' do subject { dsl.primary(:app) } it 'returns the servers' do expect(subject.hostname).to eq 'example4.com' end end end end describe 'when defining a host using a combination of the `server` and `role` syntax' do before do dsl.server 'db@example1.com:1234', roles: %w{db}, active: true dsl.server 'root@example1.com:1234', roles: %w{web}, active: true dsl.server 'example1.com:5678', roles: %w{web}, active: true dsl.role :app, %w{deployer@example1.com:1234} dsl.role :app, %w{example1.com:5678} end describe 'fetching all servers' do it 'creates one server per hostname, ignoring user and port combinations' do expect(dsl.roles(:all).size).to eq(1) end end describe 'fetching servers for a role' do it 'roles defined using the `server` syntax are included' do as = dsl.roles(:web).map { |server| "#{server.user}@#{server.hostname}:#{server.port}" } expect(as.size).to eq(1) expect(as[0]).to eq("deployer@example1.com:5678") end it 'roles defined using the `role` syntax are included' do as = dsl.roles(:app).map { |server| "#{server.user}@#{server.hostname}:#{server.port}" } expect(as.size).to eq(1) expect(as[0]).to eq("deployer@example1.com:5678") end end end describe 'when setting user and port' do subject { dsl.roles(:all).map { |server| "#{server.user}@#{server.hostname}:#{server.port}" }.first } describe "using the :user property" do it "takes precedence over in the host string" do dsl.server 'db@example1.com:1234', roles: %w{db}, active: true, user: 'brian' expect(subject).to eq("brian@example1.com:1234") end end describe "using the :port property" do it "takes precedence over in the host string" do dsl.server 'db@example1.com:9090', roles: %w{db}, active: true, port: 1234 expect(subject).to eq("db@example1.com:1234") end end end end describe 'setting and fetching variables' do before do dsl.set :scm, :git end context 'without a default' do context 'when the variables is defined' do it 'returns the variable' do expect(dsl.fetch(:scm)).to eq :git end end context 'when the variables is undefined' do it 'returns nil' do expect(dsl.fetch(:source_control)).to be_nil end end end context 'with a default' do context 'when the variables is defined' do it 'returns the variable' do expect(dsl.fetch(:scm, :svn)).to eq :git end end context 'when the variables is undefined' do it 'returns the default' do expect(dsl.fetch(:source_control, :svn)).to eq :svn end end end context 'with a block' do context 'when the variables is defined' do it 'returns the variable' do expect(dsl.fetch(:scm) { :svn }).to eq :git end end context 'when the variables is undefined' do it 'calls the block' do expect(dsl.fetch(:source_control) { :svn }).to eq :svn end end end end describe 'asking for a variable' do before do dsl.ask(:scm, :svn) $stdout.stubs(:print) end context 'variable is provided' do before do $stdin.expects(:gets).returns('git') end it 'sets the input as the variable' do expect(dsl.fetch(:scm)).to eq 'git' end end context 'variable is not provided' do before do $stdin.expects(:gets).returns('') end it 'sets the variable as the default' do expect(dsl.fetch(:scm)).to eq :svn end end end describe 'checking for presence' do subject { dsl.any? :linked_files } before do dsl.set(:linked_files, linked_files) end context 'variable is an non-empty array' do let(:linked_files) { %w{1} } it { expect(subject).to be_truthy } end context 'variable is an empty array' do let(:linked_files) { [] } it { expect(subject).to be_falsey } end context 'variable exists, is not an array' do let(:linked_files) { stub } it { expect(subject).to be_truthy } end context 'variable is nil' do let(:linked_files) { nil } it { expect(subject).to be_falsey } end end describe 'configuration SSHKit' do let(:config) { SSHKit.config } let(:backend) { SSHKit.config.backend.config } let(:default_env) { { rails_env: :production } } before do dsl.set(:format, :dot) dsl.set(:log_level, :debug) dsl.set(:default_env, default_env) dsl.set(:pty, true) dsl.set(:connection_timeout, 10) dsl.set(:ssh_options, { keys: %w(/home/user/.ssh/id_rsa), forward_agent: false, auth_methods: %w(publickey password) }) dsl.configure_backend end it 'sets the output' do expect(config.output).to be_a SSHKit::Formatter::Dot end it 'sets the output verbosity' do expect(config.output_verbosity).to eq 0 end it 'sets the default env' do expect(config.default_env).to eq default_env end it 'sets the backend pty' do expect(backend.pty).to be_truthy end it 'sets the backend connection timeout' do expect(backend.connection_timeout).to eq 10 end it 'sets the backend ssh_options' do expect(backend.ssh_options[:keys]).to eq %w(/home/user/.ssh/id_rsa) expect(backend.ssh_options[:forward_agent]).to eq false expect(backend.ssh_options[:auth_methods]).to eq %w(publickey password) end end describe 'local_user' do before do dsl.set :local_user, -> { Etc.getlogin } end describe 'fetching local_user' do subject { dsl.local_user } context 'where a local_user is not set' do before do Etc.expects(:getlogin).returns('login') end it 'returns the login name' do expect(subject.to_s).to eq 'login' end end context 'where a local_user is set' do before do dsl.set(:local_user, -> { 'custom login' }) end it 'returns the custom name' do expect(subject.to_s).to eq 'custom login' end end end end describe 'on()' do before do dsl.server 'example1.com', roles: %w{web}, active: true dsl.server 'example2.com', roles: %w{web} dsl.server 'example3.com', roles: %w{app web}, active: true dsl.server 'example4.com', roles: %w{app}, primary: true dsl.server 'example5.com', roles: %w{db}, no_release: true @coordinator = mock('coordinator') @coordinator.expects(:each).returns(nil) ENV.delete 'ROLES' ENV.delete 'HOSTS' end it 'filters by role from the :filter variable' do hosts = dsl.roles(:web) all = dsl.roles(:all) SSHKit::Coordinator.expects(:new).with(hosts).returns(@coordinator) dsl.set :filter, { role: 'web' } dsl.on(all) end it 'filters by host and role from the :filter variable' do all = dsl.roles(:all) SSHKit::Coordinator.expects(:new).with([]).returns(@coordinator) dsl.set :filter, { role: 'db', host: 'example3.com' } dsl.on(all) end it 'filters from ENV[ROLES]' do hosts = dsl.roles(:db) all = dsl.roles(:all) SSHKit::Coordinator.expects(:new).with(hosts).returns(@coordinator) ENV['ROLES'] = 'db' dsl.on(all) end it 'filters from ENV[HOSTS]' do hosts = dsl.roles(:db) all = dsl.roles(:all) SSHKit::Coordinator.expects(:new).with(hosts).returns(@coordinator) ENV['HOSTS'] = 'example5.com' dsl.on(all) end it 'filters by ENV[HOSTS] && ENV[ROLES]' do all = dsl.roles(:all) SSHKit::Coordinator.expects(:new).with([]).returns(@coordinator) ENV['HOSTS'] = 'example5.com' ENV['ROLES'] = 'web' dsl.on(all) end end describe 'role_properties()' do before do dsl.role :redis, %w[example1.com example2.com], redis: { port: 6379, type: :slave } dsl.server 'example1.com', roles: %w{web}, active: true, web: { port: 80 } dsl.server 'example2.com', roles: %w{web redis}, web: { port: 81 }, redis: { type: :master } dsl.server 'example3.com', roles: %w{app}, primary: true end it 'retrieves properties for a single role as a set' do rps = dsl.role_properties(:app) expect(rps).to eq(Set[{ hostname: 'example3.com', role: :app}]) end it 'retrieves properties for multiple roles as a set' do rps = dsl.role_properties(:app, :web) expect(rps).to eq(Set[{ hostname: 'example3.com', role: :app},{ hostname: 'example1.com', role: :web, port: 80},{ hostname: 'example2.com', role: :web, port: 81}]) end it 'yields the properties for a single role' do recipient = mock('recipient') recipient.expects(:doit).with('example1.com', :redis, { port: 6379, type: :slave}) recipient.expects(:doit).with('example2.com', :redis, { port: 6379, type: :master}) dsl.role_properties(:redis) do |host, role, props| recipient.doit(host, role, props) end end it 'yields the properties for multiple roles' do recipient = mock('recipient') recipient.expects(:doit).with('example1.com', :redis, { port: 6379, type: :slave}) recipient.expects(:doit).with('example2.com', :redis, { port: 6379, type: :master}) recipient.expects(:doit).with('example3.com', :app, nil) dsl.role_properties(:redis, :app) do |host, role, props| recipient.doit(host, role, props) end end it 'yields the merged properties for multiple roles' do recipient = mock('recipient') recipient.expects(:doit).with('example1.com', :redis, { port: 6379, type: :slave}) recipient.expects(:doit).with('example2.com', :redis, { port: 6379, type: :master}) recipient.expects(:doit).with('example1.com', :web, { port: 80 }) recipient.expects(:doit).with('example2.com', :web, { port: 81 }) dsl.role_properties(:redis, :web) do |host, role, props| recipient.doit(host, role, props) end end it 'honours a property filter before yielding' do recipient = mock('recipient') recipient.expects(:doit).with('example1.com', :redis, { port: 6379, type: :slave}) recipient.expects(:doit).with('example1.com', :web, { port: 80 }) dsl.role_properties(:redis, :web, select: :active) do |host, role, props| recipient.doit(host, role, props) end end end end capistrano-3.4.0/spec/integration_spec_helper.rb0000644000004100000410000000013712511755114022067 0ustar www-datawww-datarequire 'spec_helper' require 'support/test_app' require 'support/matchers' include TestApp capistrano-3.4.0/spec/support/0000755000004100000410000000000012511755114016361 5ustar www-datawww-datacapistrano-3.4.0/spec/support/matchers.rb0000644000004100000410000000017212511755114020514 0ustar www-datawww-dataRSpec::Matchers.define :be_a_symlink_to do |expected| match do |actual| File.identical?(expected, actual) end end capistrano-3.4.0/spec/support/test_app.rb0000644000004100000410000000641412511755114020532 0ustar www-datawww-datarequire 'fileutils' require 'pathname' module TestApp extend self def install install_test_app_with(default_config) end def default_config %{ set :deploy_to, '#{deploy_to}' set :repo_url, 'git://github.com/capistrano/capistrano.git' set :branch, 'master' set :ssh_options, { keys: "\#{ENV['HOME']}/.vagrant.d/insecure_private_key", auth_methods: ['publickey'] } server 'vagrant@localhost:2220', roles: %w{web app} set :linked_files, #{linked_files} set :linked_dirs, #{linked_dirs} } end def linked_files %w{config/database.yml} end def linked_file shared_path.join(linked_files.first) end def linked_dirs %w{bin log public/system vendor/bundle} end def create_test_app FileUtils.rm_rf(test_app_path) FileUtils.mkdir(test_app_path) File.open(gemfile, 'w+') do |file| file.write "gem 'capistrano', path: '#{path_to_cap}'" end Dir.chdir(test_app_path) do %x[bundle] end end def install_test_app_with(config) create_test_app Dir.chdir(test_app_path) do %x[bundle exec cap install STAGES=#{stage}] end write_local_deploy_file(config) end def write_local_deploy_file(config) File.open(test_stage_path, 'w') do |file| file.write config end end def append_to_deploy_file(config) File.open(test_stage_path, 'a') do |file| file.write config + "\n" end end def prepend_to_capfile(config) current_capfile = File.read(capfile) File.open(capfile, 'w') do |file| file.write config file.write current_capfile end end def create_shared_directory(path) FileUtils.mkdir_p(shared_path.join(path)) end def create_shared_file(path) File.open(shared_path.join(path), 'w') end def cap(task) run "bundle exec cap #{stage} #{task}" end def run(command) output = nil Dir.chdir(test_app_path) do output = %x[#{command}] end [$?.success?, output] end def stage 'test' end def test_stage_path test_app_path.join('config/deploy/test.rb') end def test_app_path Pathname.new('/tmp/test_app') end def deploy_to Pathname.new('/home/vagrant/var/www/deploy') end def shared_path deploy_to.join('shared') end def current_path deploy_to.join('current') end def releases_path deploy_to.join('releases') end def release_path releases_path.join(timestamp) end def timestamp Time.now.utc.strftime("%Y%m%d%H%M%S") end def repo_path deploy_to.join('repo') end def path_to_cap File.expand_path('.') end def gemfile test_app_path.join('Gemfile') end def capfile test_app_path.join('Capfile') end def current_user `whoami`.chomp end def task_dir test_app_path.join('lib/capistrano/tasks') end def copy_task_to_test_app(source) FileUtils.cp(source, task_dir) end def config_path test_app_path.join('config') end def move_configuration_to_custom_location(location) prepend_to_capfile( %{ set :stage_config_path, "app/config/deploy" set :deploy_config_path, "app/config/deploy.rb" } ) location = test_app_path.join(location) FileUtils.mkdir_p(location) FileUtils.mv(config_path, location) end end capistrano-3.4.0/spec/support/.gitignore0000644000004100000410000000001112511755114020341 0ustar www-datawww-data.vagrant capistrano-3.4.0/spec/support/Vagrantfile0000644000004100000410000000137212511755114020551 0ustar www-datawww-datarequire 'open-uri' Vagrant.configure("2") do |config| config.ssh.insert_key = false [:app].each_with_index do |role, i| config.vm.define(role, primary: true) do |config| config.vm.define role config.vm.box = 'hashicorp/precise64' config.vm.network "forwarded_port", guest: 22, host: "222#{i}".to_i config.vm.provision :shell, inline: 'sudo apt-get -y install git-core' vagrantkey = open("https://raw.githubusercontent.com/mitchellh/vagrant/master/keys/vagrant.pub", "r",&:read) config.vm.provision :shell, inline: <<-INLINE install -d -m 700 /root/.ssh echo -e "#{vagrantkey}" > /root/.ssh/authorized_keys chmod 0600 /root/.ssh/authorized_keys INLINE end end end capistrano-3.4.0/spec/support/tasks/0000755000004100000410000000000012511755114017506 5ustar www-datawww-datacapistrano-3.4.0/spec/support/tasks/fail.rake0000644000004100000410000000022512511755114021264 0ustar www-datawww-dataset :fail, proc { fail } before 'deploy:starting', :fail do on roles :all do execute :touch, shared_path.join('fail') end fetch(:fail) end capistrano-3.4.0/spec/support/tasks/database.rake0000644000004100000410000000035012511755114022114 0ustar www-datawww-datanamespace :deploy do namespace :check do task :linked_files => 'config/database.yml' end end remote_file 'config/database.yml' => '/tmp/database.yml', roles: :all file '/tmp/database.yml' do |t| sh "touch #{t.name}" end capistrano-3.4.0/spec/support/tasks/root.rake0000644000004100000410000000033612511755114021337 0ustar www-datawww-datatask :am_i_root do on roles(:all) do |host| host.user = 'root' ident = capture :id, '-a' info "I am #{ident}" end on roles(:all) do |host| ident = capture :id, '-a' info "I am #{ident}" end end capistrano-3.4.0/spec/support/tasks/failed.rake0000644000004100000410000000015612511755114021600 0ustar www-datawww-dataafter 'deploy:failed', :failed do on roles :all do execute :touch, shared_path.join('failed') end end capistrano-3.4.0/.travis.yml0000644000004100000410000000027212511755114016025 0ustar www-datawww-datalanguage: ruby rvm: - 2.1.0 - 2.0.0 - 1.9.3 - rbx-2 script: bundle exec rake spec install: bundle install --jobs=1 cache: bundler branches: except: - legacy-v2 sudo: false capistrano-3.4.0/lib/0000755000004100000410000000000012511755114014461 5ustar www-datawww-datacapistrano-3.4.0/lib/Capfile0000644000004100000410000000011012511755114015737 0ustar www-datawww-data#!/usr/bin/env cap include Capistrano::DSL require 'capistrano/install' capistrano-3.4.0/lib/capistrano/0000755000004100000410000000000012511755114016624 5ustar www-datawww-datacapistrano-3.4.0/lib/capistrano/version_validator.rb0000644000004100000410000000105112511755114022700 0ustar www-datawww-datamodule Capistrano class VersionValidator def initialize(version) @version = version end def verify if match? self else fail "Capfile locked at #{version}, but #{current_version} is loaded" end end private attr_reader :version def match? available =~ requested end def current_version VERSION end def available Gem::Dependency.new('cap', version) end def requested Gem::Dependency.new('cap', current_version) end end end capistrano-3.4.0/lib/capistrano/application.rb0000644000004100000410000000702512511755114021460 0ustar www-datawww-datamodule Capistrano class Application < Rake::Application def initialize super @rakefiles = %w{capfile Capfile capfile.rb Capfile.rb} << capfile end def name "cap" end def run Rake.application = self super end def sort_options(options) not_applicable_to_capistrano = %w(quiet silent verbose) options.reject! do |(switch, *)| switch =~ /--#{Regexp.union(not_applicable_to_capistrano)}/ end super.push(version, dry_run, roles, hostfilter) end def handle_options options.rakelib = ['rakelib'] options.trace_output = $stderr OptionParser.new do |opts| opts.banner = "See full documentation at http://capistranorb.com/." opts.separator "" opts.separator "Install capistrano in a project:" opts.separator " bundle exec cap install [STAGES=qa,staging,production,...]" opts.separator "" opts.separator "Show available tasks:" opts.separator " bundle exec cap -T" opts.separator "" opts.separator "Invoke (or simulate invoking) a task:" opts.separator " bundle exec cap [--dry-run] STAGE TASK" opts.separator "" opts.separator "Advanced options:" opts.on_tail("-h", "--help", "-H", "Display this help message.") do puts opts exit end standard_rake_options.each { |args| opts.on(*args) } opts.environment('RAKEOPT') end.parse! end def top_level_tasks if tasks_without_stage_dependency.include?(@top_level_tasks.first) @top_level_tasks else @top_level_tasks.unshift(ensure_stage.to_s) end end def display_error_message(ex) unless options.backtrace if loc = Rake.application.find_rakefile_location whitelist = (@imported.dup << loc[0]).map{|f| File.absolute_path(f, loc[1])} pattern = %r@^(?!#{whitelist.map{|p| Regexp.quote(p)}.join('|')})@ Rake.application.options.suppress_backtrace_pattern = pattern end trace "(Backtrace restricted to imported tasks)" end super end def exit_because_of_exception(ex) if respond_to?(:deploying?) && deploying? exit_deploy_because_of_exception(ex) else super end end private def load_imports if options.show_tasks invoke 'load:defaults' set(:stage, '') Dir[deploy_config_path].each { |f| add_import f } end super end # allows the `cap install` task to load without a capfile def capfile File.expand_path(File.join(File.dirname(__FILE__),'..','Capfile')) end def version ['--version', '-V', "Display the program version.", lambda { |value| puts "Capistrano Version: #{Capistrano::VERSION} (Rake Version: #{RAKEVERSION})" exit } ] end def dry_run ['--dry-run', '-n', "Do a dry run without executing actions", lambda { |value| Configuration.env.set(:sshkit_backend, SSHKit::Backend::Printer) } ] end def roles ['--roles ROLES', '-r', "Run SSH commands only on hosts matching these roles", lambda { |value| Configuration.env.add_cmdline_filter(:role, value) } ] end def hostfilter ['--hosts HOSTS', '-z', "Run SSH commands only on matching hosts", lambda { |value| Configuration.env.add_cmdline_filter(:host, value) } ] end end end capistrano-3.4.0/lib/capistrano/git.rb0000644000004100000410000000205512511755114017736 0ustar www-datawww-dataload File.expand_path("../tasks/git.rake", __FILE__) require 'capistrano/scm' class Capistrano::Git < Capistrano::SCM # execute git with argument in the context # def git(*args) args.unshift :git context.execute *args end # The Capistrano default strategy for git. You should want to use this. module DefaultStrategy def test test! " [ -f #{repo_path}/HEAD ] " end def check git :'ls-remote --heads', repo_url end def clone git :clone, '--mirror', repo_url, repo_path end def update git :remote, :update end def release if tree = fetch(:repo_tree) tree = tree.slice %r#^/?(.*?)/?$#, 1 components = tree.split('/').size git :archive, fetch(:branch), tree, "| tar -x --strip-components #{components} -f - -C", release_path else git :archive, fetch(:branch), '| tar -x -f - -C', release_path end end def fetch_revision context.capture(:git, "rev-list --max-count=1 --abbrev-commit #{fetch(:branch)}") end end end capistrano-3.4.0/lib/capistrano/svn.rb0000644000004100000410000000121112511755114017752 0ustar www-datawww-dataload File.expand_path("../tasks/svn.rake", __FILE__) require 'capistrano/scm' class Capistrano::Svn < Capistrano::SCM # execute svn in context with arguments def svn(*args) args.unshift(:svn) context.execute *args end module DefaultStrategy def test test! " [ -d #{repo_path}/.svn ] " end def check test! :svn, :info, repo_url end def clone svn :checkout, repo_url, repo_path end def update svn :update end def release svn :export, '--force', '.', release_path end def fetch_revision context.capture(:svnversion, repo_path) end end end capistrano-3.4.0/lib/capistrano/scm.rb0000644000004100000410000000556212511755114017743 0ustar www-datawww-datamodule Capistrano # Base class for SCM strategy providers. # # @abstract # # @attr_reader [Rake] context # # @author Hartog de Mik # class SCM attr_reader :context # Provide a wrapper for the SCM that loads a strategy for the user. # # @param [Rake] context The context in which the strategy should run # @param [Module] strategy A module to include into the SCM instance. The # module should provide the abstract methods of Capistrano::SCM # def initialize(context, strategy) @context = context singleton = class << self; self; end singleton.send(:include, strategy) end # Call test in context def test!(*args) context.test *args end # The repository URL according to the context def repo_url context.repo_url end # The repository path according to the context def repo_path context.repo_path end # The release path according to the context def release_path context.release_path end # Fetch a var from the context # @param [Symbol] variable The variable to fetch # @param [Object] default The default value if not found # def fetch(*args) context.fetch(*args) end # @abstract # # Your implementation should check the existence of a cache repository on # the deployment target # # @return [Boolean] # def test raise NotImplementedError.new( "Your SCM strategy module should provide a #test method" ) end # @abstract # # Your implementation should check if the specified remote-repository is # available. # # @return [Boolean] # def check raise NotImplementedError.new( "Your SCM strategy module should provide a #check method" ) end # @abstract # # Create a (new) clone of the remote-repository on the deployment target # # @return void # def clone raise NotImplementedError.new( "Your SCM strategy module should provide a #clone method" ) end # @abstract # # Update the clone on the deployment target # # @return void # def update raise NotImplementedError.new( "Your SCM strategy module should provide a #update method" ) end # @abstract # # Copy the contents of the cache-repository onto the release path # # @return void # def release raise NotImplementedError.new( "Your SCM strategy module should provide a #release method" ) end # @abstract # # Identify the SHA of the commit that will be deployed. This will most likely involve SshKit's capture method. # # @return void # def fetch_revision raise NotImplementedError.new( "Your SCM strategy module should provide a #fetch_revision method" ) end end end capistrano-3.4.0/lib/capistrano/configuration.rb0000644000004100000410000000627112511755114022026 0ustar www-datawww-datarequire_relative 'configuration/filter' require_relative 'configuration/question' require_relative 'configuration/server' require_relative 'configuration/servers' module Capistrano class Configuration def initialize(config = nil) @config ||= config end def self.env @env ||= new end def self.reset! @env = new end def ask(key, default=nil, options={}) question = Question.new(key, default, options) set(key, question) end def set(key, value) config[key] = value end def set_if_empty(key, value) config[key] = value unless config.has_key? key end def delete(key) config.delete(key) end def fetch(key, default=nil, &block) value = fetch_for(key, default, &block) while callable_without_parameters?(value) value = set(key, value.call) end return value end def keys config.keys end def role(name, hosts, options={}) if name == :all raise ArgumentError.new("#{name} reserved name for role. Please choose another name") end servers.add_role(name, hosts, options) end def server(name, properties={}) servers.add_host(name, properties) end def roles_for(names) servers.roles_for(names) end def role_properties_for(names, &block) servers.role_properties_for(names, &block) end def primary(role) servers.fetch_primary(role) end def backend @backend ||= SSHKit end attr_writer :backend def configure_backend backend.configure do |sshkit| sshkit.format = fetch(:format) sshkit.output_verbosity = fetch(:log_level) sshkit.default_env = fetch(:default_env) sshkit.backend = fetch(:sshkit_backend, SSHKit::Backend::Netssh) sshkit.backend.configure do |backend| backend.pty = fetch(:pty) backend.connection_timeout = fetch(:connection_timeout) backend.ssh_options = (backend.ssh_options || {}).merge(fetch(:ssh_options,{})) end end end def timestamp @timestamp ||= Time.now.utc end def setup_filters @filters = cmdline_filters.clone @filters << Filter.new(:role, ENV['ROLES']) if ENV['ROLES'] @filters << Filter.new(:host, ENV['HOSTS']) if ENV['HOSTS'] fh = fetch_for(:filter,{}) @filters << Filter.new(:host, fh[:host]) if fh[:host] @filters << Filter.new(:role, fh[:role]) if fh[:role] end def add_cmdline_filter(type, values) cmdline_filters << Filter.new(type, values) end def filter list setup_filters if @filters.nil? @filters.reduce(list) { |l,f| f.filter l } end private def cmdline_filters @cmdline_filters ||= [] end def servers @servers ||= Servers.new end def config @config ||= Hash.new end def fetch_for(key, default, &block) if block_given? config.fetch(key, &block) else config.fetch(key, default) end end def callable_without_parameters?(x) x.respond_to?(:call) && ( !x.respond_to?(:arity) || x.arity == 0) end end end capistrano-3.4.0/lib/capistrano/upload_task.rb0000644000004100000410000000030212511755114021452 0ustar www-datawww-datarequire 'rake/file_creation_task' module Capistrano class UploadTask < Rake::FileCreationTask def needed? true # always needed because we can't check remote hosts end end end capistrano-3.4.0/lib/capistrano/templates/0000755000004100000410000000000012511755114020622 5ustar www-datawww-datacapistrano-3.4.0/lib/capistrano/templates/Capfile0000644000004100000410000000150512511755114022111 0ustar www-datawww-data# Load DSL and set up stages require 'capistrano/setup' # Include default deployment tasks require 'capistrano/deploy' # Include tasks from other gems included in your Gemfile # # For documentation on these, see for example: # # https://github.com/capistrano/rvm # https://github.com/capistrano/rbenv # https://github.com/capistrano/chruby # https://github.com/capistrano/bundler # https://github.com/capistrano/rails # https://github.com/capistrano/passenger # # require 'capistrano/rvm' # require 'capistrano/rbenv' # require 'capistrano/chruby' # require 'capistrano/bundler' # require 'capistrano/rails/assets' # require 'capistrano/rails/migrations' # require 'capistrano/passenger' # Load custom tasks from `lib/capistrano/tasks` if you have any defined Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r } capistrano-3.4.0/lib/capistrano/templates/stage.rb.erb0000644000004100000410000000405112511755114023021 0ustar www-datawww-data# server-based syntax # ====================== # Defines a single server with a list of roles and multiple properties. # You can define all roles on a single server, or split them: # server 'example.com', user: 'deploy', roles: %w{app db web}, my_property: :my_value # server 'example.com', user: 'deploy', roles: %w{app web}, other_property: :other_value # server 'db.example.com', user: 'deploy', roles: %w{db} # role-based syntax # ================== # Defines a role with one or multiple servers. The primary server in each # group is considered to be the first unless any hosts have the primary # property set. Specify the username and a domain or IP for the server. # Don't use `:all`, it's a meta role. # role :app, %w{deploy@example.com}, my_property: :my_value # role :web, %w{user1@primary.com user2@additional.com}, other_property: :other_value # role :db, %w{deploy@example.com} # Configuration # ============= # You can set any configuration variable like in config/deploy.rb # These variables are then only loaded and set in this stage. # For available Capistrano configuration variables see the documentation page. # http://capistranorb.com/documentation/getting-started/configuration/ # Feel free to add new variables to customise your setup. # Custom SSH Options # ================== # You may pass any option but keep in mind that net/ssh understands a # limited set of options, consult the Net::SSH documentation. # http://net-ssh.github.io/net-ssh/classes/Net/SSH.html#method-c-start # # Global options # -------------- # set :ssh_options, { # keys: %w(/home/rlisowski/.ssh/id_rsa), # forward_agent: false, # auth_methods: %w(password) # } # # The server-based syntax can be used to override options: # ------------------------------------ # server 'example.com', # user: 'user_name', # roles: %w{web app}, # ssh_options: { # user: 'user_name', # overrides user setting above # keys: %w(/home/user_name/.ssh/id_rsa), # forward_agent: false, # auth_methods: %w(publickey password) # # password: 'please use keys' # } capistrano-3.4.0/lib/capistrano/templates/deploy.rb.erb0000644000004100000410000000242112511755114023211 0ustar www-datawww-data# config valid only for current version of Capistrano lock '<%= Capistrano::VERSION %>' set :application, 'my_app_name' set :repo_url, 'git@example.com:me/my_repo.git' # Default branch is :master # ask :branch, `git rev-parse --abbrev-ref HEAD`.chomp # Default deploy_to directory is /var/www/my_app_name # set :deploy_to, '/var/www/my_app_name' # Default value for :scm is :git # set :scm, :git # Default value for :format is :pretty # set :format, :pretty # Default value for :log_level is :debug # set :log_level, :debug # Default value for :pty is false # set :pty, true # Default value for :linked_files is [] # set :linked_files, fetch(:linked_files, []).push('config/database.yml', 'config/secrets.yml') # Default value for linked_dirs is [] # set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system') # Default value for default_env is {} # set :default_env, { path: "/opt/ruby/bin:$PATH" } # Default value for keep_releases is 5 # set :keep_releases, 5 namespace :deploy do after :restart, :clear_cache do on roles(:web), in: :groups, limit: 3, wait: 10 do # Here we can do anything such as: # within release_path do # execute :rake, 'cache:clear' # end end end end capistrano-3.4.0/lib/capistrano/hg.rb0000644000004100000410000000170712511755114017554 0ustar www-datawww-dataload File.expand_path("../tasks/hg.rake", __FILE__) require 'capistrano/scm' class Capistrano::Hg < Capistrano::SCM # execute hg in context with arguments def hg(*args) args.unshift(:hg) context.execute *args end module DefaultStrategy def test test! " [ -d #{repo_path}/.hg ] " end def check hg "id", repo_url end def clone hg "clone", "--noupdate", repo_url, repo_path end def update hg "pull" end def release if tree = fetch(:repo_tree) tree = tree.slice %r#^/?(.*?)/?$#, 1 components = tree.split('/').size hg "archive --type tgz -p . -I", tree, "--rev", fetch(:branch), "| tar -x --strip-components #{components} -f - -C", release_path else hg "archive", release_path, "--rev", fetch(:branch) end end def fetch_revision context.capture(:hg, "log --rev #{fetch(:branch)} --template \"{node}\n\"") end end end capistrano-3.4.0/lib/capistrano/console.rb0000644000004100000410000000007112511755114020611 0ustar www-datawww-dataload File.expand_path("../tasks/console.rake", __FILE__) capistrano-3.4.0/lib/capistrano/defaults.rb0000644000004100000410000000053412511755114020762 0ustar www-datawww-dataset_if_empty :scm, :git set_if_empty :branch, :master set_if_empty :deploy_to, -> { "/var/www/#{fetch(:application)}" } set_if_empty :tmp_dir, "/tmp" set_if_empty :default_env, {} set_if_empty :keep_releases, 5 set_if_empty :format, :pretty set_if_empty :log_level, :debug set_if_empty :pty, false set_if_empty :local_user, -> { Etc.getlogin } capistrano-3.4.0/lib/capistrano/configuration/0000755000004100000410000000000012511755114021473 5ustar www-datawww-datacapistrano-3.4.0/lib/capistrano/configuration/servers.rb0000644000004100000410000000350412511755114023513 0ustar www-datawww-datarequire 'set' require 'capistrano/configuration' require 'capistrano/configuration/filter' module Capistrano class Configuration class Servers include Enumerable def add_host(host, properties={}) new_host = Server[host] if server = servers.find { |s| s.matches? new_host } server.user = new_host.user if new_host.user server.port = new_host.port if new_host.port server.with(properties) else servers << new_host.with(properties) end end def add_role(role, hosts, options={}) options_deepcopy = Marshal.dump(options.merge(roles: role)) Array(hosts).each { |host| add_host(host, Marshal.load(options_deepcopy)) } end def roles_for(names) options = extract_options(names) s = Filter.new(:role, names).filter(servers) s.select { |server| server.select?(options) } end def role_properties_for(rolenames) roles = rolenames.to_set rps = Set.new unless block_given? roles_for(rolenames).each do |host| host.roles.intersection(roles).each do |role| [host.properties.fetch(role)].flatten(1).each do |props| if block_given? yield host, role, props else rps << (props || {}).merge( role: role, hostname: host.hostname ) end end end end block_given? ? nil: rps end def fetch_primary(role) hosts = roles_for([role]) hosts.find(&:primary) || hosts.first end def each servers.each { |server| yield server } end private def servers @servers ||= [] end def extract_options(array) array.last.is_a?(::Hash) ? array.pop : {} end end end end capistrano-3.4.0/lib/capistrano/configuration/filter.rb0000644000004100000410000000306212511755114023306 0ustar www-datawww-datarequire 'capistrano/configuration' module Capistrano class Configuration class Filter def initialize type, values = nil raise "Invalid filter type #{type}" unless [:host,:role].include? type av = Array(values).dup @mode = case when av.size == 0 then :none when av.include?(:all) then :all else type end @rex = case @mode when :host av.map!{|v| (v.is_a?(String) && v =~ /^(?[-A-Za-z0-9.]+)(,\g)*$/) ? v.split(',') : v } av.flatten! av.map! do |v| case v when Regexp then v else vs = v.to_s vs =~ /^[-A-Za-z0-9.]+$/ ? vs : Regexp.new(vs) end end Regexp.union av when :role av.map!{|v| v.is_a?(String) ? v.split(',') : v } av.flatten! av.map! do |v| case v when Regexp then v else vs = v.to_s vs =~ %r{^/(.+)/$} ? Regexp.new($1) : %r{^#{vs}$} end end Regexp.union av else nil end end def filter servers as = Array(servers) case @mode when :none then return [] when :all then return servers when :host as.select {|s| @rex.match s.hostname} when :role as.select {|s| s.roles.any? {|r| @rex.match r} } end end end end end capistrano-3.4.0/lib/capistrano/configuration/question.rb0000644000004100000410000000202012511755114023661 0ustar www-datawww-datamodule Capistrano class Configuration class Question def initialize(key, default, options = {}) @key, @default, @options = key, default, options end def call ask_question value_or_default end private attr_reader :key, :default, :options def ask_question $stdout.print question end def value_or_default if response.empty? default else response end end def response return @response if defined? @response @response = (gets || "").chomp end def gets if echo? $stdin.gets else $stdin.noecho(&:gets).tap{ $stdout.print "\n" } end rescue Errno::EIO # when stdio gets closed end def question I18n.t(:question, key: key, default_value: default, scope: :capistrano) end def echo? (options || {}).fetch(:echo, true) end end end end capistrano-3.4.0/lib/capistrano/configuration/server.rb0000644000004100000410000000513012511755114023325 0ustar www-datawww-datarequire 'set' module Capistrano class Configuration class Server < SSHKit::Host extend Forwardable def_delegators :properties, :roles, :fetch, :set def self.[](host) host.is_a?(Server) ? host : new(host) end def add_roles(roles) Array(roles).each { |role| add_role(role) } self end alias roles= add_roles def add_role(role) roles.add role.to_sym self end def has_role?(role) roles.include? role.to_sym end def select?(options) options.each do |k,v| callable = v.respond_to?(:call) ? v: ->(server){server.fetch(v)} result = case k when :filter, :select callable.call(self) when :exclude !callable.call(self) else self.fetch(k) == v end return false unless result end return true end def primary self if fetch(:primary) end def with(properties) properties.each { |key, value| add_property(key, value) } self end def properties @properties ||= Properties.new end def netssh_options @netssh_options ||= super.merge( fetch(:ssh_options) || {} ) end def roles_array roles.to_a end def matches?(other) hostname == other.hostname end private def add_property(key, value) if respond_to?("#{key}=") send("#{key}=", value) else set(key, value) end end class Properties def initialize @properties = {} end def set(key, value) pval = @properties[key] if pval.is_a? Hash and value.is_a? Hash pval.merge!(value) elsif pval.is_a? Set and value.is_a? Set pval.merge(value) elsif pval.is_a? Array and value.is_a? Array pval.concat value else @properties[key] = value end end def fetch(key) @properties[key] end def respond_to?(method, include_all=false) @properties.has_key?(method) end def roles @roles ||= Set.new end def keys @properties.keys end def method_missing(key, value=nil) if value set(lvalue(key), value) else fetch(key) end end private def lvalue(key) key.to_s.chomp('=').to_sym end end end end end capistrano-3.4.0/lib/capistrano/install.rb0000644000004100000410000000011612511755114020615 0ustar www-datawww-dataload File.expand_path(File.join(File.dirname(__FILE__),'tasks/install.rake')) capistrano-3.4.0/lib/capistrano/version.rb0000644000004100000410000000005212511755114020633 0ustar www-datawww-datamodule Capistrano VERSION = "3.4.0" end capistrano-3.4.0/lib/capistrano/i18n.rb0000644000004100000410000000322512511755114017732 0ustar www-datawww-datarequire 'i18n' en = { starting: 'Starting', capified: 'Capified', start: 'Start', update: 'Update', finalize: 'Finalise', finishing: 'Finishing', finished: 'Finished', stage_not_set: 'Stage not set, please call something such as `cap production deploy`, where production is a stage you have defined.', written_file: 'create %{file}', question: 'Please enter %{key} (%{default_value}): ', keeping_releases: 'Keeping %{keep_releases} of %{releases} deployed releases on %{host}', no_old_releases: 'No old releases (keeping newest %{keep_releases}) on %{host}', linked_file_does_not_exist: 'linked file %{file} does not exist on %{host}', cannot_rollback: 'There are no older releases to rollback to', mirror_exists: 'The repository mirror is at %{at}', revision_log_message: 'Branch %{branch} (at %{sha}) deployed as release %{release} by %{user}', rollback_log_message: '%{user} rolled back to release %{release}', deploy_failed: 'The deploy has failed with an error: %{ex}', console: { welcome: 'capistrano console - enter command to execute on %{stage}', bye: 'bye' }, error: { user: { does_not_exist: 'User %{user} does not exists', cannot_switch: 'Cannot switch to user %{user}' } } } I18n.backend.store_translations(:en, { capistrano: en }) if I18n.respond_to?(:enforce_available_locales=) I18n.enforce_available_locales = true end capistrano-3.4.0/lib/capistrano/dsl/0000755000004100000410000000000012511755114017406 5ustar www-datawww-datacapistrano-3.4.0/lib/capistrano/dsl/stages.rb0000644000004100000410000000046012511755114021221 0ustar www-datawww-datamodule Capistrano module DSL module Stages def stages Dir[stage_definitions].map { |f| File.basename(f, '.rb') } end def stage_definitions stage_config_path.join('*.rb') end def stage_set? !!fetch(:stage, false) end end end end capistrano-3.4.0/lib/capistrano/dsl/task_enhancements.rb0000644000004100000410000000310712511755114023426 0ustar www-datawww-datarequire 'capistrano/upload_task' module Capistrano module TaskEnhancements def before(task, prerequisite, *args, &block) prerequisite = Rake::Task.define_task(prerequisite, *args, &block) if block_given? Rake::Task[task].enhance [prerequisite] end def after(task, post_task, *args, &block) Rake::Task.define_task(post_task, *args, &block) if block_given? post_task = Rake::Task[post_task] Rake::Task[task].enhance do post_task.invoke end end def remote_file(task) target_roles = task.delete(:roles) { :all } define_remote_file_task(task, target_roles) end def define_remote_file_task(task, target_roles) Capistrano::UploadTask.define_task(task) do |t| prerequisite_file = t.prerequisites.first file = shared_path.join(t.name) on roles(target_roles) do unless test "[ -f #{file.to_s.shellescape} ]" info "Uploading #{prerequisite_file} to #{file}" upload! File.open(prerequisite_file), file end end end end def ensure_stage Rake::Task.define_task(:ensure_stage) do unless stage_set? puts t(:stage_not_set) exit 1 end end end def tasks_without_stage_dependency stages + default_tasks end def default_tasks %w{install} end def exit_deploy_because_of_exception(ex) warn t(:deploy_failed, ex: ex.message) invoke 'deploy:failed' exit(false) end def deploying? fetch(:deploying, false) end end end capistrano-3.4.0/lib/capistrano/dsl/paths.rb0000644000004100000410000000444412511755114021060 0ustar www-datawww-datarequire 'pathname' module Capistrano module DSL module Paths def deploy_to fetch(:deploy_to) end def deploy_path Pathname.new(deploy_to) end def current_path deploy_path.join('current') end def releases_path deploy_path.join('releases') end def release_path fetch(:release_path, current_path) end def set_release_path(timestamp=now) set(:release_timestamp, timestamp) set(:release_path, releases_path.join(timestamp)) end def stage_config_path Pathname.new fetch(:stage_config_path, 'config/deploy') end def deploy_config_path Pathname.new fetch(:deploy_config_path, 'config/deploy.rb') end def repo_url require 'cgi' require 'uri' if fetch(:git_http_username) and fetch(:git_http_password) URI.parse(fetch(:repo_url)).tap do |repo_uri| repo_uri.user = fetch(:git_http_username) repo_uri.password = CGI.escape(fetch(:git_http_password)) end.to_s elsif fetch(:git_http_username) URI.parse(fetch(:repo_url)).tap do |repo_uri| repo_uri.user = fetch(:git_http_username) end.to_s else fetch(:repo_url) end end def repo_path Pathname.new(fetch(:repo_path, ->(){deploy_path.join('repo')})) end def shared_path deploy_path.join('shared') end def revision_log deploy_path.join('revisions.log') end def now env.timestamp.strftime("%Y%m%d%H%M%S") end def asset_timestamp env.timestamp.strftime("%Y%m%d%H%M.%S") end def linked_dirs(parent) paths = fetch(:linked_dirs) join_paths(parent, paths) end def linked_files(parent) paths = fetch(:linked_files) join_paths(parent, paths) end def linked_file_dirs(parent) map_dirnames(linked_files(parent)) end def linked_dir_parents(parent) map_dirnames(linked_dirs(parent)) end def join_paths(parent, paths) paths.map { |path| parent.join(path) } end def map_dirnames(paths) paths.map { |path| path.dirname } end end end end capistrano-3.4.0/lib/capistrano/dsl/env.rb0000644000004100000410000000302112511755114020517 0ustar www-datawww-datamodule Capistrano module DSL module Env def configure_backend env.configure_backend end def fetch(key, default=nil, &block) env.fetch(key, default, &block) end def any?(key) value = fetch(key) if value && value.respond_to?(:any?) value.any? else !fetch(key).nil? end end def set(key, value) env.set(key, value) end def set_if_empty(key, value) env.set_if_empty(key, value) end def delete(key) env.delete(key) end def ask(key, value, options={}) env.ask(key, value, options) end def role(name, servers, options={}) env.role(name, servers, options) end def server(name, properties={}) env.server(name, properties) end def roles(*names) env.roles_for(names.flatten) end def role_properties(*names, &block) env.role_properties_for(names, &block) end def release_roles(*names) if names.last.is_a? Hash names.last.merge!({ :exclude => :no_release }) else names << { exclude: :no_release } end roles(*names) end def primary(role) env.primary(role) end def env Configuration.env end def release_timestamp env.timestamp.strftime("%Y%m%d%H%M%S") end def asset_timestamp env.timestamp.strftime("%Y%m%d%H%M.%S") end end end end capistrano-3.4.0/lib/capistrano/all.rb0000644000004100000410000000046112511755114017722 0ustar www-datawww-datarequire 'rake' require 'sshkit' require 'io/console' Rake.application.options.trace = true require 'capistrano/version' require 'capistrano/version_validator' require 'capistrano/i18n' require 'capistrano/dsl' require 'capistrano/application' require 'capistrano/configuration' module Capistrano end capistrano-3.4.0/lib/capistrano/tasks/0000755000004100000410000000000012511755114017751 5ustar www-datawww-datacapistrano-3.4.0/lib/capistrano/tasks/install.rake0000644000004100000410000000242212511755114022263 0ustar www-datawww-datarequire 'erb' require 'pathname' desc 'Install Capistrano, cap install STAGES=staging,production' task :install do envs = ENV['STAGES'] || 'staging,production' tasks_dir = Pathname.new('lib/capistrano/tasks') config_dir = Pathname.new('config') deploy_dir = config_dir.join('deploy') deploy_rb = File.expand_path("../../templates/deploy.rb.erb", __FILE__) stage_rb = File.expand_path("../../templates/stage.rb.erb", __FILE__) capfile = File.expand_path("../../templates/Capfile", __FILE__) mkdir_p deploy_dir entries = [{template: deploy_rb, file: config_dir.join('deploy.rb')}] entries += envs.split(',').map { |stage| {template: stage_rb, file: deploy_dir.join("#{stage}.rb")} } entries.each do |entry| if File.exists?(entry[:file]) warn "[skip] #{entry[:file]} already exists" else File.open(entry[:file], 'w+') do |f| f.write(ERB.new(File.read(entry[:template])).result(binding)) puts I18n.t(:written_file, scope: :capistrano, file: entry[:file]) end end end mkdir_p tasks_dir if File.exists?('Capfile') warn "[skip] Capfile already exists" else FileUtils.cp(capfile, 'Capfile') puts I18n.t(:written_file, scope: :capistrano, file: 'Capfile') end puts I18n.t :capified, scope: :capistrano end capistrano-3.4.0/lib/capistrano/tasks/framework.rake0000644000004100000410000000225512511755114022616 0ustar www-datawww-datanamespace :deploy do desc 'Start a deployment, make sure server(s) ready.' task :starting do end desc 'Started' task :started do end desc 'Update server(s) by setting up a new release.' task :updating do end desc 'Updated' task :updated do end desc 'Revert server(s) to previous release.' task :reverting do end desc 'Reverted' task :reverted do end desc 'Publish the release.' task :publishing do end desc 'Published' task :published do end desc 'Finish the deployment, clean up server(s).' task :finishing do end desc 'Finish the rollback, clean up server(s).' task :finishing_rollback do end desc 'Finished' task :finished do end desc 'Rollback to previous release.' task :rollback do %w{ starting started reverting reverted publishing published finishing_rollback finished }.each do |task| invoke "deploy:#{task}" end end end desc 'Deploy a new release.' task :deploy do set(:deploying, true) %w{ starting started updating updated publishing published finishing finished }.each do |task| invoke "deploy:#{task}" end end task default: :deploy capistrano-3.4.0/lib/capistrano/tasks/console.rake0000644000004100000410000000101212511755114022251 0ustar www-datawww-datadesc 'Execute remote commands' task :console do stage = fetch(:stage) puts I18n.t('console.welcome', scope: :capistrano, stage: stage) loop do print "#{stage}> " if input = $stdin.gets command = input.chomp else command = 'exit' end next if command.empty? if %w{quit exit q}.include? command puts t('console.bye') break else begin on roles :all do execute command end rescue => e puts e end end end end capistrano-3.4.0/lib/capistrano/tasks/hg.rake0000644000004100000410000000211112511755114021206 0ustar www-datawww-datanamespace :hg do def strategy @strategy ||= Capistrano::Hg.new(self, fetch(:hg_strategy, Capistrano::Hg::DefaultStrategy)) end desc 'Check that the repo is reachable' task :check do on release_roles :all do strategy.check end end desc 'Clone the repo to the cache' task :clone do on release_roles :all do if strategy.test info t(:mirror_exists, at: repo_path) else within deploy_path do strategy.clone end end end end desc 'Pull changes from the remote repo' task :update => :'hg:clone' do on release_roles :all do within repo_path do strategy.update end end end desc 'Copy repo to releases' task :create_release => :'hg:update' do on release_roles :all do within repo_path do strategy.release end end end desc 'Determine the revision that will be deployed' task :set_current_revision do on release_roles :all do within repo_path do set :current_revision, strategy.fetch_revision end end end end capistrano-3.4.0/lib/capistrano/tasks/deploy.rake0000644000004100000410000001411112511755114022107 0ustar www-datawww-datanamespace :deploy do task :starting do invoke 'deploy:check' invoke 'deploy:set_previous_revision' end task :updating => :new_release_path do invoke "#{scm}:create_release" invoke "deploy:set_current_revision" invoke 'deploy:symlink:shared' end task :reverting do invoke 'deploy:revert_release' end task :publishing do invoke 'deploy:symlink:release' end task :finishing do invoke 'deploy:cleanup' end task :finishing_rollback do invoke 'deploy:cleanup_rollback' end task :finished do invoke 'deploy:log_revision' end desc 'Check required files and directories exist' task :check do invoke "#{scm}:check" invoke 'deploy:check:directories' invoke 'deploy:check:linked_dirs' invoke 'deploy:check:make_linked_dirs' invoke 'deploy:check:linked_files' end namespace :check do desc 'Check shared and release directories exist' task :directories do on release_roles :all do execute :mkdir, '-p', shared_path, releases_path end end desc 'Check directories to be linked exist in shared' task :linked_dirs do next unless any? :linked_dirs on release_roles :all do execute :mkdir, '-p', linked_dirs(shared_path) end end desc 'Check directories of files to be linked exist in shared' task :make_linked_dirs do next unless any? :linked_files on release_roles :all do |host| execute :mkdir, '-p', linked_file_dirs(shared_path) end end desc 'Check files to be linked exist in shared' task :linked_files do next unless any? :linked_files on release_roles :all do |host| linked_files(shared_path).each do |file| unless test "[ -f #{file} ]" error t(:linked_file_does_not_exist, file: file, host: host) exit 1 end end end end end namespace :symlink do desc 'Symlink release to current' task :release do on release_roles :all do tmp_current_path = release_path.parent.join(current_path.basename) execute :ln, '-s', release_path, tmp_current_path execute :mv, tmp_current_path, current_path.parent end end desc 'Symlink files and directories from shared to release' task :shared do invoke 'deploy:symlink:linked_files' invoke 'deploy:symlink:linked_dirs' end desc 'Symlink linked directories' task :linked_dirs do next unless any? :linked_dirs on release_roles :all do execute :mkdir, '-p', linked_dir_parents(release_path) fetch(:linked_dirs).each do |dir| target = release_path.join(dir) source = shared_path.join(dir) unless test "[ -L #{target} ]" if test "[ -d #{target} ]" execute :rm, '-rf', target end execute :ln, '-s', source, target end end end end desc 'Symlink linked files' task :linked_files do next unless any? :linked_files on release_roles :all do execute :mkdir, '-p', linked_file_dirs(release_path) fetch(:linked_files).each do |file| target = release_path.join(file) source = shared_path.join(file) unless test "[ -L #{target} ]" if test "[ -f #{target} ]" execute :rm, target end execute :ln, '-s', source, target end end end end end desc 'Clean up old releases' task :cleanup do on release_roles :all do |host| releases = capture(:ls, '-xtr', releases_path).split if releases.count >= fetch(:keep_releases) info t(:keeping_releases, host: host.to_s, keep_releases: fetch(:keep_releases), releases: releases.count) directories = (releases - releases.last(fetch(:keep_releases))) if directories.any? directories_str = directories.map do |release| releases_path.join(release) end.join(" ") execute :rm, '-rf', directories_str else info t(:no_old_releases, host: host.to_s, keep_releases: fetch(:keep_releases)) end end end end desc 'Remove and archive rolled-back release.' task :cleanup_rollback do on release_roles(:all) do last_release = capture(:ls, '-xt', releases_path).split.first last_release_path = releases_path.join(last_release) if test "[ `readlink #{current_path}` != #{last_release_path} ]" execute :tar, '-czf', deploy_path.join("rolled-back-release-#{last_release}.tar.gz"), last_release_path execute :rm, '-rf', last_release_path else debug 'Last release is the current release, skip cleanup_rollback.' end end end desc 'Log details of the deploy' task :log_revision do on release_roles(:all) do within releases_path do execute %{echo "#{revision_log_message}" >> #{revision_log}} end end end desc 'Revert to previous release timestamp' task :revert_release => :rollback_release_path do on release_roles(:all) do set(:revision_log_message, rollback_log_message) end end task :new_release_path do set_release_path end task :rollback_release_path do on release_roles(:all) do releases = capture(:ls, '-xt', releases_path).split if releases.count < 2 error t(:cannot_rollback) exit 1 end last_release = releases[1] set_release_path(last_release) set(:rollback_timestamp, last_release) end end desc "Place a REVISION file with the current revision SHA in the current release path" task :set_current_revision do invoke "#{scm}:set_current_revision" on release_roles(:all) do within release_path do execute :echo, "\"#{fetch(:current_revision)}\" >> REVISION" end end end task :set_previous_revision do on release_roles(:all) do target = release_path.join('REVISION') if test "[ -f #{target} ]" set(:previous_revision, capture(:cat, target, '2>/dev/null')) end end end task :restart task :failed end capistrano-3.4.0/lib/capistrano/tasks/svn.rake0000644000004100000410000000211712511755114021424 0ustar www-datawww-datanamespace :svn do def strategy @strategy ||= Capistrano::Svn.new(self, fetch(:svn_strategy, Capistrano::Svn::DefaultStrategy)) end desc 'Check that the repo is reachable' task :check do on release_roles :all do strategy.check end end desc 'Clone the repo to the cache' task :clone do on release_roles :all do if strategy.test info t(:mirror_exists, at: repo_path) else within deploy_path do strategy.clone end end end end desc 'Pull changes from the remote repo' task :update => :'svn:clone' do on release_roles :all do within repo_path do strategy.update end end end desc 'Copy repo to releases' task :create_release => :'svn:update' do on release_roles :all do within repo_path do strategy.release end end end desc 'Determine the revision that will be deployed' task :set_current_revision do on release_roles :all do within repo_path do set :current_revision, strategy.fetch_revision end end end end capistrano-3.4.0/lib/capistrano/tasks/git.rake0000644000004100000410000000427612511755114021411 0ustar www-datawww-datanamespace :git do def strategy @strategy ||= Capistrano::Git.new(self, fetch(:git_strategy, Capistrano::Git::DefaultStrategy)) end set :git_environmental_variables, ->() { { git_askpass: "/bin/echo", git_ssh: "#{fetch(:tmp_dir)}/#{fetch(:application)}/git-ssh.sh" } } desc 'Upload the git wrapper script, this script guarantees that we can script git without getting an interactive prompt' task :wrapper do on release_roles :all do execute :mkdir, "-p", "#{fetch(:tmp_dir)}/#{fetch(:application)}/" upload! StringIO.new("#!/bin/sh -e\nexec /usr/bin/ssh -o PasswordAuthentication=no -o StrictHostKeyChecking=no \"$@\"\n"), "#{fetch(:tmp_dir)}/#{fetch(:application)}/git-ssh.sh" execute :chmod, "+x", "#{fetch(:tmp_dir)}/#{fetch(:application)}/git-ssh.sh" end end desc 'Check that the repository is reachable' task check: :'git:wrapper' do fetch(:branch) on release_roles :all do with fetch(:git_environmental_variables) do strategy.check end end end desc 'Clone the repo to the cache' task clone: :'git:wrapper' do on release_roles :all do if strategy.test info t(:mirror_exists, at: repo_path) else within deploy_path do with fetch(:git_environmental_variables) do strategy.clone end end end end end desc 'Update the repo mirror to reflect the origin state' task update: :'git:clone' do on release_roles :all do within repo_path do with fetch(:git_environmental_variables) do strategy.update end end end end desc 'Copy repo to releases' task create_release: :'git:update' do on release_roles :all do with fetch(:git_environmental_variables) do within repo_path do execute :mkdir, '-p', release_path strategy.release end end end end desc 'Determine the revision that will be deployed' task :set_current_revision do on release_roles :all do within repo_path do with fetch(:git_environmental_variables) do set :current_revision, strategy.fetch_revision end end end end end capistrano-3.4.0/lib/capistrano/dotfile.rb0000644000004100000410000000012712511755114020577 0ustar www-datawww-datadotfile = Pathname.new(File.join(Dir.home, '.capfile')) load dotfile if dotfile.file? capistrano-3.4.0/lib/capistrano/setup.rb0000644000004100000410000000067012511755114020314 0ustar www-datawww-datainclude Capistrano::DSL namespace :load do task :defaults do load 'capistrano/defaults.rb' end end stages.each do |stage| Rake::Task.define_task(stage) do set(:stage, stage.to_sym) invoke 'load:defaults' load deploy_config_path load stage_config_path.join("#{stage}.rb") load "capistrano/#{fetch(:scm)}.rb" I18n.locale = fetch(:locale, :en) configure_backend end end require 'capistrano/dotfile' capistrano-3.4.0/lib/capistrano/deploy.rb0000644000004100000410000000013012511755114020437 0ustar www-datawww-datarequire 'capistrano/framework' load File.expand_path("../tasks/deploy.rake", __FILE__) capistrano-3.4.0/lib/capistrano/dsl.rb0000644000004100000410000000257512511755114017744 0ustar www-datawww-datarequire 'etc' require 'capistrano/dsl/task_enhancements' require 'capistrano/dsl/paths' require 'capistrano/dsl/stages' require 'capistrano/dsl/env' require 'capistrano/configuration/filter' module Capistrano module DSL include TaskEnhancements include Env include Paths include Stages def invoke(task, *args) Rake::Task[task].invoke(*args) end def t(key, options={}) I18n.t(key, options.merge(scope: :capistrano)) end def scm fetch(:scm) end def sudo(*args) execute :sudo, *args end def revision_log_message fetch(:revision_log_message, t(:revision_log_message, branch: fetch(:branch), user: local_user, sha: fetch(:current_revision), release: fetch(:release_timestamp)) ) end def rollback_log_message t(:rollback_log_message, user: local_user, release: fetch(:rollback_timestamp)) end def local_user fetch(:local_user) end def lock(locked_version) VersionValidator.new(locked_version).verify end def on(hosts, options={}, &block) subset_copy = Marshal.dump(Configuration.env.filter(hosts)) SSHKit::Coordinator.new(Marshal.load(subset_copy)).each(options, &block) end def run_locally(&block) SSHKit::Backend::Local.new(&block).run end end end self.extend Capistrano::DSL capistrano-3.4.0/lib/capistrano/framework.rb0000644000004100000410000000013012511755114021140 0ustar www-datawww-dataload File.expand_path("../tasks/framework.rake", __FILE__) require 'capistrano/install' capistrano-3.4.0/lib/capistrano.rb0000644000004100000410000000000012511755114017137 0ustar www-datawww-datacapistrano-3.4.0/metadata.yml0000644000004100000410000001642012511755114016221 0ustar www-datawww-data--- !ruby/object:Gem::Specification name: capistrano version: !ruby/object:Gem::Version version: 3.4.0 platform: ruby authors: - Tom Clements - Lee Hambley autorequire: bindir: bin cert_chain: [] date: 2015-03-02 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: sshkit requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '1.3' type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '1.3' - !ruby/object:Gem::Dependency name: rake requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: 10.0.0 type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: 10.0.0 - !ruby/object:Gem::Dependency name: i18n requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: rspec requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: mocha requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' description: Capistrano is a utility and framework for executing commands in parallel on multiple remote machines, via SSH. email: - seenmyfate@gmail.com - lee.hambley@gmail.com executables: - cap - capify extensions: [] extra_rdoc_files: [] files: - ".gitignore" - ".travis.yml" - CHANGELOG.md - CONTRIBUTING.md - Gemfile - LICENSE.txt - README.md - Rakefile - bin/cap - bin/capify - capistrano.gemspec - features/configuration.feature - features/deploy.feature - features/deploy_failure.feature - features/installation.feature - features/remote_file_task.feature - features/sshconnect.feature - features/step_definitions/assertions.rb - features/step_definitions/cap_commands.rb - features/step_definitions/setup.rb - features/support/env.rb - features/support/remote_command_helpers.rb - features/support/vagrant_helpers.rb - lib/Capfile - lib/capistrano.rb - lib/capistrano/all.rb - lib/capistrano/application.rb - lib/capistrano/configuration.rb - lib/capistrano/configuration/filter.rb - lib/capistrano/configuration/question.rb - lib/capistrano/configuration/server.rb - lib/capistrano/configuration/servers.rb - lib/capistrano/console.rb - lib/capistrano/defaults.rb - lib/capistrano/deploy.rb - lib/capistrano/dotfile.rb - lib/capistrano/dsl.rb - lib/capistrano/dsl/env.rb - lib/capistrano/dsl/paths.rb - lib/capistrano/dsl/stages.rb - lib/capistrano/dsl/task_enhancements.rb - lib/capistrano/framework.rb - lib/capistrano/git.rb - lib/capistrano/hg.rb - lib/capistrano/i18n.rb - lib/capistrano/install.rb - lib/capistrano/scm.rb - lib/capistrano/setup.rb - lib/capistrano/svn.rb - lib/capistrano/tasks/console.rake - lib/capistrano/tasks/deploy.rake - lib/capistrano/tasks/framework.rake - lib/capistrano/tasks/git.rake - lib/capistrano/tasks/hg.rake - lib/capistrano/tasks/install.rake - lib/capistrano/tasks/svn.rake - lib/capistrano/templates/Capfile - lib/capistrano/templates/deploy.rb.erb - lib/capistrano/templates/stage.rb.erb - lib/capistrano/upload_task.rb - lib/capistrano/version.rb - lib/capistrano/version_validator.rb - spec/integration/dsl_spec.rb - spec/integration_spec_helper.rb - spec/lib/capistrano/application_spec.rb - spec/lib/capistrano/configuration/filter_spec.rb - spec/lib/capistrano/configuration/question_spec.rb - spec/lib/capistrano/configuration/server_spec.rb - spec/lib/capistrano/configuration/servers_spec.rb - spec/lib/capistrano/configuration_spec.rb - spec/lib/capistrano/dsl/paths_spec.rb - spec/lib/capistrano/dsl/task_enhancements_spec.rb - spec/lib/capistrano/dsl_spec.rb - spec/lib/capistrano/git_spec.rb - spec/lib/capistrano/hg_spec.rb - spec/lib/capistrano/scm_spec.rb - spec/lib/capistrano/svn_spec.rb - spec/lib/capistrano/upload_task_spec.rb - spec/lib/capistrano/version_validator_spec.rb - spec/lib/capistrano_spec.rb - spec/spec_helper.rb - spec/support/.gitignore - spec/support/Vagrantfile - spec/support/matchers.rb - spec/support/tasks/database.rake - spec/support/tasks/fail.rake - spec/support/tasks/failed.rake - spec/support/tasks/root.rake - spec/support/test_app.rb homepage: http://capistranorb.com/ licenses: - MIT metadata: {} post_install_message: | Capistrano 3.1 has some breaking changes. Please check the CHANGELOG: http://goo.gl/SxB0lr If you're upgrading Capistrano from 2.x, we recommend to read the upgrade guide: http://goo.gl/4536kB The `deploy:restart` hook for passenger applications is now in a separate gem called capistrano-passenger. Just add it to your Gemfile and require it in your Capfile. rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: 1.9.3 required_rubygems_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: rubygems_version: 2.4.3 signing_key: specification_version: 4 summary: Capistrano - Welcome to easy deployment with Ruby over SSH test_files: - features/configuration.feature - features/deploy.feature - features/deploy_failure.feature - features/installation.feature - features/remote_file_task.feature - features/sshconnect.feature - features/step_definitions/assertions.rb - features/step_definitions/cap_commands.rb - features/step_definitions/setup.rb - features/support/env.rb - features/support/remote_command_helpers.rb - features/support/vagrant_helpers.rb - spec/integration/dsl_spec.rb - spec/integration_spec_helper.rb - spec/lib/capistrano/application_spec.rb - spec/lib/capistrano/configuration/filter_spec.rb - spec/lib/capistrano/configuration/question_spec.rb - spec/lib/capistrano/configuration/server_spec.rb - spec/lib/capistrano/configuration/servers_spec.rb - spec/lib/capistrano/configuration_spec.rb - spec/lib/capistrano/dsl/paths_spec.rb - spec/lib/capistrano/dsl/task_enhancements_spec.rb - spec/lib/capistrano/dsl_spec.rb - spec/lib/capistrano/git_spec.rb - spec/lib/capistrano/hg_spec.rb - spec/lib/capistrano/scm_spec.rb - spec/lib/capistrano/svn_spec.rb - spec/lib/capistrano/upload_task_spec.rb - spec/lib/capistrano/version_validator_spec.rb - spec/lib/capistrano_spec.rb - spec/spec_helper.rb - spec/support/.gitignore - spec/support/Vagrantfile - spec/support/matchers.rb - spec/support/tasks/database.rake - spec/support/tasks/fail.rake - spec/support/tasks/failed.rake - spec/support/tasks/root.rake - spec/support/test_app.rb capistrano-3.4.0/.gitignore0000644000004100000410000000031012511755114015675 0ustar www-datawww-data*.gem *.rbc .bundle .config .yardoc Gemfile.lock InstalledFiles _yardoc coverage doc/ lib/bundler/man pkg rdoc spec/reports test/tmp test/version_tmp tmp .rspec-local .ruby-version _site .rspec *.swp capistrano-3.4.0/CONTRIBUTING.md0000644000004100000410000001177712511755114016161 0ustar www-datawww-data## CONTRIBUTING **The issue tracker is intended exclusively for things that are genuine bugs, or improvements to the code.** If you have a user support query, or you suspect that you might just be holding it wrong, drop us a line at [the mailing list](https://groups.google.com/forum/#!forum/capistrano), [StackOverflow](http://stackoverflow.com/questions/tagged/capistrano) or at [CodersClan](http://codersclan.net/?repo_id=325&source=contributing). The mailing list is moderated to cut down on spam, so please be patient, if you use StackOverflow, make sure to tag your post with "Capistrano". (Not forgetting any other tags which might relate, rvm, rbenv, Ubuntu, etc.) If you have an urgent problem you can use [CodersClan](http://codersclan.net/?repo_id=325&source=contributing) to solve your problem quickly. CodersClan has a community of Capistrano experts dedicated to solve code problems for bounties. Wherever you post please be sure to include the version of Capistrano you are using, which versions of any plugins (*capistrano-rvm*, *capistrano-bundler*, etc.). Proper logs are vital, if you need to redact them, go ahead, but be careful not to remove anything important. Please take care to format logs and code correctly, ideally wrapped to a sane line length, and in a mono spaced font. This all helps us to gather a clear understanding of what is going wrong. **If you really think that you found a bug, or want to enquire about a feature, or send us a patch to add a feature, or fix a bug, please keep a few things in mind:** ## When Submitting An Issue: If you think there's a bug, please make sure it's really a bug in Capistrano. As Capistrano sits on the (sometimes rough) edges between SSH, Git, the network, Ruby, RVM, rbenv, chruby, Bundler, your Linux distribution, countless shell configuration files on your end, and the server… there's a good chance the problem lies somewhere else. Please make sure you have reviewed the FAQs at http://www.capistranorb.com/. It's really important to include as much information as possible, versions of everything involved, anything weird you might be doing that might be having side effects, include as much as you can in a [GitHub Gist](https://gist.github.com/) and link that from the issue, with tools such as Gist, we can link to individual lines and help work out what is going wrong. If you are an experienced Ruby programmer, take a few minutes to get our test suite running, and do what you can to get a test case written that fails, from there we can understand exactly what it takes to reproduce the issue (as it's documented with code) ## When Requesting a Feature: We can't make everyone happy all of the time, and we've been around the block well enough to know when something doesn't work well, or when your proposed fix might impact other things. We prefer to [start with "no"](https://gettingreal.37signals.com/ch05_Start_With_No.php), and help you find a better way to solve your problem, sometimes the solution is to [build faster horses](http://blog.cauvin.org/2010/07/henry-fords-faster-horse-quote.html), sometimes the solution is to work around it in a neat way that you didn't know existed. Please don't be offended if we say no, and don't be afraid to fight your corner, try and avoid being one of the [poisonous people](https://www.youtube.com/watch?v=Q52kFL8zVoM) ## Submitting A Pull Request: Pull requests are awesome, and if they arrive with decent tests, and conform to the guidelines below, we'll merge them in as soon as possible, we'll let you know which release we're planning them for (we adhere to [semver](http://semver.org/) so please don't be upset if we plan your changes for a later release) * The code is MIT licenced, your code will fall under the same license if we merge it. * We can't merge it without a [good commit message](http://robots.thoughtbot.com/5-useful-tips-for-a-better-commit-message). If you do this right, Github will use the commit message as the body of your pull request, double win. * If you are referencing an improvement to an existing issue (if we have not yet merged it ) * Add an entry to the `CHANGELOG` under the `### master` section, but please don't mess with the version. * If you add a new feature, please make sure to document it, open a corresponding pull request in [the documentation](https://github.com/capistrano/documentation) and mention the code change pull request over there, and Github will link everything up. If it's a simple feature, or a new variable, or something changed, it may be appropriate simply to document it in the generated `Capfile` or `deploy.rb`, or in the `README` * Take care to squash your commit into one single commit with a good message, it saves us a lot of work in maintaining the CHANGELOG if we can generate it from the commit messages between the release tags! * Tests! It's tricky to test some parts of Capistrano, but do your best, it might just serve as a starting point for us to build a reliable test on top of, and help us understand where you are coming from. capistrano-3.4.0/CHANGELOG.md0000644000004100000410000003531312511755114015531 0ustar www-datawww-data# Capistrano 3.x Changelog Reverse Chronological Order: ## master https://github.com/capistrano/capistrano/compare/v3.4.0...HEAD ## `3.4.0` https://github.com/capistrano/capistrano/compare/v3.3.5...v3.4.0 * Fixed fetch revision for annotated git tags. (@igorsokolov) * Fixed updating roles when custom user or port is specified. (@ayastreb) * Disables statistics collection. * `bin/` is not suggested to be in `linked_dirs` anymore (@kirs) * bin/ is often checked out into repo * https://github.com/capistrano/bundler/issues/45#issuecomment-69349237 * Bugfix: * release_roles did not honour additional property filtering (@townsen) * Refactored and simplified property filtering code (@townsen) * Breaking Changes * Hosts with the same name are now consolidated into one irrespective of the user and port. This allows multiple declarations of a server to be made safely. The last declared properties will win. See capistrnorb.com Properties documentation for details. * Inside the on() block the host variable is now a copy of the host, so changes can be made within the block (such as dynamically overriding the user) that will not persist. This is very convenient for switching the SSH user temporarily to 'root' for example. * Minor changes * Add role_properties() method (see capistrano.github.io PR for doc) (@townsen) * Add equality syntax ( eg. port: 1234) for property filtering (@townsen) * Add documentation regarding property filtering (@townsen) * Clarify wording and recommendation in stage template. (@Kriechi) * Both available syntaxes provide similar functionality, do not use both for the same server+role combination. * Allow specification of repo_path using stage variable default is as before (@townsen) ## `3.3.5` https://github.com/capistrano/capistrano/compare/v3.3.4...v3.3.5 * Fixed setting properties twice when creating new server. See [issue #1214](https://github.com/capistrano/capistrano/issues/1214) (@ayastreb) ## `3.3.4` https://github.com/capistrano/capistrano/compare/v3.3.3...v3.3.4 * Minor changes: * Rely on a newer version of capistrano-stats with better privacy (@leehambley) * Fix cucumber spec for loading tasks from stage configs (@sponomarev) * Minor documentation fixes (@deeeki, @seuros, @andresilveira) * Spec improvements (@dimitrid, @sponomarev) * Fix to CLI flags for git-ls-remote (@dimitrid) ## `3.3.3` https://github.com/capistrano/capistrano/compare/v3.2.1...v3.3.3 * Enhancement (@townsen) * Added the variable `:repo_tree` which allows the specification of a sub-tree that will be extracted from the repository. This is useful when deploying a project that lives in a subdirectory of a larger repository. Implemented only for git and hg. If not defined then the behaviour is as previously and the whole repository is extracted (subject to git-archive `.gitattributes` of course). * Enhancement (@townsen): Remove unnecessary entries from default backtrace When the `--backtrace` (or `--trace`) command line option is not supplied Rake lowers the noise level in exception backtraces by building a regular expression containing all the system library paths and using it to exclude backtrace entries that match. This does not always go far enough, particularly in RVM environments when many gem paths are added. This commit reverses that approach and _only_ include backtrace entries that fall within the Capfile and list of tasks imported thereafter. This makes reading exceptions much easier on the eye. If the full unexpurgated backtrace is required then the --backtrace and --trace options supply it as before. * Disable loading stages configs on `cap -T` (@sponomarev) * Enhancements (@townsen) * Fix matching on hosts with custom ports or users set * Previously filtering would affect any generated configuration files so that files newly deployed would not be the same as those on the hosts previously deployed (and now excluded by filters). This is almost certainly not what is wanted: the filters should apply only to the on() method and thus any configuration files deployed will be identical across the set of servers making up the stage. * Host and Role filtering now affects only `on()` commands and not the `roles()`, `release_roles()` and `primary()` methods. * This applies to filters defined via the command line, the environment and the :filter variable. * Filtering now supports Regular expressions * This change _could_ cause existing scripts that use filtering and depend on the old behaviour to fail, though it is unlikely. Users who rely on filtering should check that generated configuration files are correct, and where not introduce server properties to do the filtering. For example, if a filter was used to specify an active subset of servers (by hostname), it should be removed and replaced with an 'active' property (set to true or false) on the server definitions. This keeps the stage file as the canonical model of the deployment environment. * See the documentation in the README.md file * Enhancements (@townsen) * Added set_if_empty method to DSL to allow conditional setting * Altered standard Capistrano defaults so that they are not set at the start of a stage if they have been previously set. This allows variables like :default_env to be set in deploy.rb. * Deep copy properties added using the 'roles' keyword * If a property exists on a server when another definition is encountered and is an Array, Set or Hash then add the new values This allows roles to specify properties common to all servers and then for individual servers to modify them, keeping things DRY Breaking Changes: * By using Ruby's noecho method introduced in Ruby version 1.9.3, we dropped support for Ruby versions prior to 1.9.3. See [issue #878](https://github.com/capistrano/capistrano/issues/878) and [PR #1112](https://github.com/capistrano/capistrano/pull/1112) for more information. (@kaikuchn) * Track (anonymous) statistics, see https://github.com/capistrano/stats. This breaks automated deployment on continuous integration servers until the `.capistrano/metrics` file is created (with content `full` to simulate a "yes") via the interactive prompt or manually. * Bug Fixes: * Fixed compatibility with FreeBSD tar (@robbertkl) * remote_file can be used inside a namespace (@mikz) * Minor Changes * Remove -v flag from mkdir call. (@caligo-mentis) * Capistrano now allows to customize `local_user` for revision log. (@sauliusgrigaitis) * Added tests for after/before hooks features (@juanibiapina, @miry) * Added `--force` flag to `svn export` command to fix errors when the release directory already exists. * Improved the output of `cap --help`. (@mbrictson) * Cucumber suite now runs on the latest version of Vagrant (@tpett) * The `ask` method now supports the `echo: false` option. (@mbrictson, @kaikuchn) * Cucumber scenario improvements (@bruno-) * Added suggestion to Capfile to use 'capistrano-passenger' gem, replacing suggestion in config/deploy.rb to re-implement 'deploy:restart' (@betesh) * Updated svn fetch_revision method to use `svnversion` * `cap install` no longer overwrites existing files. (@dmarkow) ## `3.2.1` https://github.com/capistrano/capistrano/compare/v3.2.0...v3.2.1 * Bug Fixes: * 3.2.0 introduced some behaviour to modify the way before/after hooks were called, to allow the optional preservation of arguments to be passed to tasks. This release reverts that commit in order to restore original functionality, and fix (fairly serious) bugs introduced by the refactoring. * Minor changes: * Update dsl#local_user method and add test for it. (@bruno-) * Revert short sha1 revision with git. (@blaugueux) * Changed asking question to more standard format (like common unix commandline tools) (@sponomarev) * Fixed typos in the README. (@sponomarev) * Added `keys` method to Configuration to allow introspection of configuration options. (@juanibiapina) * Improve error message when git:check fails (raise instead of silently `exit 1`) (@mbrictson) ## `3.2.0` The changelog entries here are incomplete, because many authors choose not to be credited for their work, check the tag comparison link for Github. https://github.com/capistrano/capistrano/compare/v3.1.0...v3.2.0 * Minor changes: * Added `keys` method to Server properties to allow introspection of automatically added properties. * Compatibility with Rake 10.2.0 - `ensure_task` is now added to `@top_level_tasks` as a string. (@dmarkow) * Amended the git check command, "ls-remote", to use "-h", limiting the list to refs/heads ## `3.1.0` https://github.com/capistrano/capistrano/compare/v3.0.1...v3.1.0 Breaking changes: * `deploy:restart` task **is no longer run by default**. From this version, developers who restart the app on each deploy need to declare it in their deploy flow (eg `after 'deploy:publishing', 'deploy:restart'`) or, for passenger applications, use the capistrano-passenger gem. Please, check https://github.com/capistrano/capistrano/commit/4e6523e1f50707499cf75eb53dce37a89528a9b0 for more information. (@kirs) * Minor changes * Tasks that used `linked_dirs` and `linked_files` now run on all roles, not just app roles (@mikespokefire) * Tasks `deploy:linked_dirs`, `deploy:make_linked_dirs`, `deploy:linked_files`, `deploy:cleanup_rollback`, `deploy:log_revision` and `deploy:revert_release` now use `release_roles()` not `roles()` meaning that they will only run on servers where the `no_release` property is not falsy. (@leehambley) * Fixed bug when `deploy:cleanup` was executed twice by default (@kirs) * Config location can now be changed with `deploy_config_path` and `stage_config_path` options (@seenmyfate) * `no_release` option is now available (@seenmyfate) * Raise an error if developer tries to define `:all` role, which is reserved (@kirs) * `deploy:failed` hook was added to add some custom behaviour on failed deploy (@seenmyfate) * Correctly infer namespace in task enhancements (@seenmyfate) * Add SHA to revision log (@blackxored) * Allow configuration of multiple servers with same hostname but different ports (@rsslldnphy) * Add command line option to control role filtering (@andytinycat) * Make use of recent changes in Rake to over-ride the application name (@shime) * Readme corrections (@nathanstitt) * Allow roles to be fetched with a variable containing an array (@seenmyfate) * Improve console (@jage) * Add ability to filter tasks to specific servers (host filtering). (@andytinycat) * Add a command line option to control role filter (`--roles`) (@andytinycat) * Use an SCM object with a pluggable strategy (@coffeeaddict) Big thanks to @Kriechi for his help. ## `3.0.1` https://github.com/capistrano/capistrano/compare/v3.0.0...v3.0.1 * `capify` not listed as executable (@leehambley) * Confirm license as MIT (@leehambley) * Move the git ssh helper to application path (@mpapis) ## `3.0.0` https://github.com/capistrano/capistrano/compare/2.15.5...v3.0.0 If you are coming here to wonder why your Capfile doesn't work anymore, please vendor lock your Capistrano at 2.x, whichever version was working for you until today. Capistrano 3 is a ground-up rewrite with modularity, stability, speed and future proofing in mind. It's a big change, but now the code is 10x smaller, runs faster, is easier to read, and quicker to extend. In the reduction we've come up with a great gem based modular system for plugins and we're really proud of this release. The 3.0.0 release contains 38 patches from the following amazing people: * Tom `seenmyfate` Clements: more than 28 patches including cucumber integration tests! Not to mention Rails asset pipeline code, and bundler integrations. * Lee Hambley: Small changes around compatibility and log formatting * Kir Shatrov: for improvements in the core to make it easier to write extensions, for improving documentation, and for effectively building the chruby, rvm and rbenv integrations. * Michael Nikitochkin: Fixing a bug around linked files and directories. * Jack Thorne: for improvements to the default `Capfile` to fix some bad example syntax. * Erik Hetzner: for (what looks like great) work on the Mercurial (Hg) support. The Hg and Git source control mechanisms do not work the same way, but rather lean on the strengths of the underlying tools. (If I missed anyone, I'm sorry, your contributions have been awesome) The 2.x branch of code is now no longer maintained. Towards the end of it's useful life there were an increasing number of features and pieces of code which didn't make sense for certain groups of people, in certain situations, leading a to a ping-pong tennis effect with pull requests every few weeks "fixing" a use-case which had already been "fixed" shortly before. As many of the use-cases are outside the scope of the testing environments I (and by extension the trusted contributors and IRC regulars) were able to test for. There's a more extensive post about my failure to be able to keep up with the demands of maintaining v2 whilst trying to build something which is appropriate for the current landscape. If you are affected by the unsupported 2 branch, please contact me (Lee Hambley) to discuss how my company can help support you. Otherwise, please try v3, we're sure you'll like it, and the code is designed to be so simple that anyone can work on it. ## `3.0.0.pre14` * Thanks to numerous contributors, in particular (@teohm) for a series of improvements. ## `3.0.0.pre13` * Fixed typos in the Capfile. (@teohm) * Allow setting SSH options globally. (@korin) * Change the flow (and hooks) see http://www.capistranorb.com/documentation/getting-started/flow/ for more information. Requires min SSHKit 0.0.34 (@teohm) * Fix sorting releases in lexicographical order (@teohm) ## `3.0.0.pre12` * `capistrano/bundler` now runs bundle on all roles, this addresses the same issue as the related changes in `pre11`. (@leehambley) ## `3.0.0.pre11` * Some deploy.rake tasks now apply to all servers, not expecting a primary(:app) server which may not exist in all deploy environments. (@leehambley). ## `3.0.0.pre10` * Fixes pre9. ## `3.0.0.pre9` * Fixes a syntax error introduced with filtering (with tests) introduced in `pre8`. (@leehambley) ## `3.0.0.pre8` * Fixed a syntax where `roles(:foo, :bar)` was being mistaken as a filter (roles(:foo, :bar => nil). The correct syntax to use is: roles([:foo,:bar]) (@leehambley) ## `3.0.0.pre7` * Fix Git https authentication. (@leehambley) * Capfile template fixes (repo/repo_url) (@teohm) * Readme Fixes (@ffmike, @kejadlen, @dwickwire) * Fix the positioning of the bundler hook, now immediately after finalize. (@teohm) capistrano-3.4.0/README.md0000644000004100000410000001034212511755114015172 0ustar www-datawww-data# Capistrano [![Build Status](https://travis-ci.org/capistrano/capistrano.svg?branch=master)](https://travis-ci.org/capistrano/capistrano) [![Code Climate](http://img.shields.io/codeclimate/github/capistrano/capistrano.svg)](https://codeclimate.com/github/capistrano/capistrano) ## Documentation Check out the [online documentation](http://capistranorb.com) of Capistrano 3 hosted via this [repository](https://github.com/capistrano/capistrano.github.io). ## Support Need help with getting Capistrano up and running? Got a code problem you want to get solved quickly? Get Capistrano support on CodersClan. ## Requirements * Ruby >= 1.9.3 (JRuby and C-Ruby/YARV are supported) Capistrano support these source code version control systems out of the box: * Git 1.8 or higher * Mercurial * SVN Binaries for these VCS might be required on the local and/or the remote systems. ## Installation Add this line to your application's Gemfile: ``` ruby gem 'capistrano', '~> 3.3.0' ``` And then execute: ``` sh $ bundle install ``` Capify: *make sure there's no "Capfile" or "capfile" present* ``` sh $ bundle exec cap install ``` This creates the following files: ``` ├── Capfile ├── config │ ├── deploy │ │ ├── production.rb │ │ └── staging.rb │ └── deploy.rb └── lib └── capistrano └── tasks ``` To create different stages: ``` sh $ bundle exec cap install STAGES=local,sandbox,qa,production ``` ## Usage ``` sh # list all available tasks $ bundle exec cap -T # deploy to the staging environment $ bundle exec cap staging deploy # deploy to the production environment $ bundle exec cap production deploy # simulate deploying to the production environment # does not actually do anything $ bundle exec cap production deploy --dry-run # list task dependencies $ bundle exec cap production deploy --prereqs # trace through task invocations $ bundle exec cap production deploy --trace ``` ## Testing Capistrano has two test suites: an RSpec suite and a Cucumber suite. The RSpec suite handles quick feedback unit specs. The Cucumber features are an integration suite that uses Vagrant to deploy to a real virtual server. In order to run the Cucumber suite you will need to install [Vagrant](http://www.vagrantup.com/) and Vagrant supported virtualization software like [VirtualBox](https://www.virtualbox.org/wiki/Downloads). ``` # To run the RSpec suite $ rake spec # To run the Cucumber suite $ rake features # To run the Cucumber suite and leave the VM running (faster for subsequent runs) $ rake features KEEP_RUNNING=1 ``` ## SSHKit [SSHKit](https://github.com/leehambley/sshkit) is the driver for SSH connections behind the scenes in Capistrano. Depending on how deep you dig, you might run into interfaces that come directly from SSHKit (the configuration is a good example). ## License MIT License (MIT) Copyright (c) 2012-2015 Tom Clements, Lee Hambley Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.