mirror of
https://github.com/capistrano/capistrano
synced 2023-03-27 23:21:18 -04:00
Merge branch '3.1.x'
Conflicts: CHANGELOG.md README.md lib/capistrano/tasks/git.rake lib/capistrano/templates/deploy.rb.erb
This commit is contained in:
commit
22a98f30a6
32 changed files with 378 additions and 55 deletions
13
CHANGELOG.md
13
CHANGELOG.md
|
@ -2,9 +2,20 @@
|
|||
|
||||
Reverse Chronological Order:
|
||||
|
||||
## `3.1.0` (not released)
|
||||
|
||||
* `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 (@kirs)
|
||||
* 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:fallback` hook was added to add some custom behaviour on failed deploy (@seenmyfate)
|
||||
* Correctly infer namespace in task enhancements (@seenmyfate)
|
||||
|
||||
## `3.0.1`
|
||||
|
||||
* capify' not listed as executable (@leehambley)
|
||||
* `capify` not listed as executable (@leehambley)
|
||||
* Confirm license as MIT (@leehambley)
|
||||
* Move the git ssh helper to application path (@mpapis)
|
||||
|
||||
|
|
|
@ -126,7 +126,7 @@ This method is widely used.
|
|||
``` ruby
|
||||
desc "Ask about breakfast"
|
||||
task :breakfast do
|
||||
breakfast = ask(:breakfast, "What would you like your colleagues to get you for breakfast?")
|
||||
breakfast = ask(:breakfast, "What would you like your colleagues to bring you for breakfast?")
|
||||
on roles(:all) do |h|
|
||||
execute "echo \"$(whoami) wants #{breakfast} for breakfast!\" | wall"
|
||||
end
|
||||
|
|
15
features/configuration.feature
Normal file
15
features/configuration.feature
Normal file
|
@ -0,0 +1,15 @@
|
|||
Feature: 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
|
|
@ -34,6 +34,7 @@ Feature: Deploy
|
|||
Then the task will be 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
|
||||
|
|
17
features/deploy_failure.feature
Normal file
17
features/deploy_failure.feature
Normal file
|
@ -0,0 +1,17 @@
|
|||
Feature: 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
|
|
@ -88,3 +88,22 @@ end
|
|||
Then(/^it will not recreate the file$/) do
|
||||
#
|
||||
end
|
||||
|
||||
Then(/^the task is successful$/) do
|
||||
expect(@success).to be_true
|
||||
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')
|
||||
!run_vagrant_command(test_file_exists(failed))
|
||||
end
|
||||
|
||||
When(/^an error is raised$/) do
|
||||
error = TestApp.shared_path.join('fail')
|
||||
run_vagrant_command(test_file_exists(error))
|
||||
end
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
When(/^I run cap "(.*?)"$/) do |task|
|
||||
TestApp.cap(task)
|
||||
@success = 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 = TestApp.run(command)
|
||||
end
|
||||
|
||||
|
|
|
@ -23,3 +23,16 @@ Given(/^a custom task to generate a file$/) do
|
|||
TestApp.copy_task_to_test_app('spec/support/tasks/database.cap')
|
||||
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.cap')
|
||||
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.cap')
|
||||
end
|
||||
|
|
|
@ -15,6 +15,10 @@ module RemoteCommandHelpers
|
|||
def exists?(type, path)
|
||||
%{[ -#{type} "#{path}" ] && echo "#{path} exists." || echo "Error: #{path} does not exist."}
|
||||
end
|
||||
|
||||
def safely_remove_file(path)
|
||||
run_vagrant_command("rm #{test_file}") rescue Vagrant::Errors::VagrantError
|
||||
end
|
||||
end
|
||||
|
||||
World(RemoteCommandHelpers)
|
||||
|
|
|
@ -30,6 +30,14 @@ module Capistrano
|
|||
end
|
||||
end
|
||||
|
||||
def exit_because_of_exception(ex)
|
||||
if deploying?
|
||||
exit_deploy_because_of_exception(ex)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# allows the `cap install` task to load without a capfile
|
||||
|
|
|
@ -34,6 +34,10 @@ module Capistrano
|
|||
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
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ module Capistrano
|
|||
end
|
||||
|
||||
def select?(options)
|
||||
selector = Selector.new(options)
|
||||
selector = Selector.for(options)
|
||||
selector.call(self)
|
||||
end
|
||||
|
||||
|
@ -103,6 +103,14 @@ module Capistrano
|
|||
@options = options
|
||||
end
|
||||
|
||||
def self.for(options)
|
||||
if options.has_key?(:exclude)
|
||||
Exclusive
|
||||
else
|
||||
self
|
||||
end.new(options)
|
||||
end
|
||||
|
||||
def callable
|
||||
if key.respond_to?(:call)
|
||||
key
|
||||
|
@ -126,6 +134,17 @@ module Capistrano
|
|||
->(server) { :all }
|
||||
end
|
||||
|
||||
class Exclusive < Selector
|
||||
|
||||
def key
|
||||
options[:exclude]
|
||||
end
|
||||
|
||||
def call(server)
|
||||
!callable.call(server)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -43,6 +43,16 @@ module Capistrano
|
|||
env.roles_for(names)
|
||||
end
|
||||
|
||||
def release_roles(*names)
|
||||
options = { exclude: :no_release }
|
||||
if names.last.is_a? Hash
|
||||
names.last.merge(options)
|
||||
else
|
||||
names << options
|
||||
end
|
||||
roles(*names)
|
||||
end
|
||||
|
||||
def primary(role)
|
||||
env.primary(role)
|
||||
end
|
||||
|
|
|
@ -27,6 +27,14 @@ module Capistrano
|
|||
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'
|
||||
|
|
|
@ -3,7 +3,14 @@ module Capistrano
|
|||
module Stages
|
||||
|
||||
def stages
|
||||
Dir['config/deploy/*.rb'].map { |f| File.basename(f, '.rb') }
|
||||
Dir[stage_definitions].map { |f| File.basename(f, '.rb') }
|
||||
end
|
||||
|
||||
def infer_stages_from_stage_files
|
||||
end
|
||||
|
||||
def stage_definitions
|
||||
stage_config_path.join('*.rb')
|
||||
end
|
||||
|
||||
def stage_set?
|
||||
|
|
|
@ -6,9 +6,10 @@ module Capistrano
|
|||
end
|
||||
|
||||
def after(task, post_task, *args, &block)
|
||||
post_task = Rake::Task.define_task(post_task, *args, &block) if block_given?
|
||||
Rake::Task.define_task(post_task, *args, &block) if block_given?
|
||||
post_task = Rake::Task[post_task]
|
||||
Rake::Task[task].enhance do
|
||||
invoke(post_task)
|
||||
post_task.invoke
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -49,5 +50,15 @@ module Capistrano
|
|||
%w{install}
|
||||
end
|
||||
|
||||
def exit_deploy_because_of_exception(ex)
|
||||
warn t(:deploy_failed, ex: ex.inspect)
|
||||
invoke 'deploy:failed'
|
||||
exit(false)
|
||||
end
|
||||
|
||||
def deploying?
|
||||
fetch(:deploying, false)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,7 +7,6 @@ en = {
|
|||
start: 'Start',
|
||||
update: 'Update',
|
||||
finalize: 'Finalise',
|
||||
restart: 'Restart',
|
||||
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.',
|
||||
|
@ -19,6 +18,7 @@ en = {
|
|||
mirror_exists: "The repository mirror is at %{at}",
|
||||
revision_log_message: 'Branch %{branch} 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'
|
||||
|
|
|
@ -8,11 +8,12 @@ end
|
|||
|
||||
stages.each do |stage|
|
||||
Rake::Task.define_task(stage) do
|
||||
invoke 'load:defaults'
|
||||
load 'config/deploy.rb'
|
||||
load "config/deploy/#{stage}.rb"
|
||||
load "capistrano/#{fetch(:scm)}.rb"
|
||||
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
|
||||
|
|
|
@ -15,7 +15,6 @@ namespace :deploy do
|
|||
|
||||
task :publishing do
|
||||
invoke 'deploy:symlink:release'
|
||||
invoke 'deploy:restart'
|
||||
end
|
||||
|
||||
task :finishing do
|
||||
|
@ -42,7 +41,7 @@ namespace :deploy do
|
|||
namespace :check do
|
||||
desc 'Check shared and release directories exist'
|
||||
task :directories do
|
||||
on roles :all do
|
||||
on release_roles :all do
|
||||
execute :mkdir, '-pv', shared_path, releases_path
|
||||
end
|
||||
end
|
||||
|
@ -80,7 +79,7 @@ namespace :deploy do
|
|||
namespace :symlink do
|
||||
desc 'Symlink release to current'
|
||||
task :release do
|
||||
on roles :all do
|
||||
on release_roles :all do
|
||||
execute :rm, '-rf', current_path
|
||||
execute :ln, '-s', release_path, current_path
|
||||
end
|
||||
|
@ -133,7 +132,7 @@ namespace :deploy do
|
|||
|
||||
desc 'Clean up old releases'
|
||||
task :cleanup do
|
||||
on roles :all do |host|
|
||||
on release_roles :all do |host|
|
||||
releases = capture(:ls, '-x', 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)
|
||||
|
@ -201,4 +200,7 @@ namespace :deploy do
|
|||
end
|
||||
end
|
||||
|
||||
task :restart
|
||||
task :failed
|
||||
|
||||
end
|
||||
|
|
|
@ -57,6 +57,7 @@ end
|
|||
|
||||
desc 'Deploy a new release.'
|
||||
task :deploy do
|
||||
set(:deploying, true)
|
||||
%w{ starting started
|
||||
updating updated
|
||||
publishing published
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace :git do
|
|||
|
||||
desc 'Upload the git wrapper script, this script guarantees that we can script git without getting an interactive prompt'
|
||||
task :wrapper do
|
||||
on roles :all 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"
|
||||
|
@ -19,7 +19,7 @@ namespace :git do
|
|||
desc 'Check that the repository is reachable'
|
||||
task check: :'git:wrapper' do
|
||||
fetch(:branch)
|
||||
on roles :all do
|
||||
on release_roles :all do
|
||||
with fetch(:git_environmental_variables) do
|
||||
exit 1 unless test :git, :'ls-remote', repo_url
|
||||
end
|
||||
|
@ -28,7 +28,7 @@ namespace :git do
|
|||
|
||||
desc 'Clone the repo to the cache'
|
||||
task clone: :'git:wrapper' do
|
||||
on roles :all do
|
||||
on release_roles :all do
|
||||
if test " [ -f #{repo_path}/HEAD ] "
|
||||
info t(:mirror_exists, at: repo_path)
|
||||
else
|
||||
|
@ -43,7 +43,7 @@ namespace :git do
|
|||
|
||||
desc 'Update the repo mirror to reflect the origin state'
|
||||
task update: :'git:clone' do
|
||||
on roles :all do
|
||||
on release_roles :all do
|
||||
within repo_path do
|
||||
execute :git, :remote, :update
|
||||
end
|
||||
|
@ -52,7 +52,7 @@ namespace :git do
|
|||
|
||||
desc 'Copy repo to releases'
|
||||
task create_release: :'git:update' do
|
||||
on roles :all do
|
||||
on release_roles :all do
|
||||
with fetch(:git_environmental_variables) do
|
||||
within repo_path do
|
||||
execute :mkdir, '-p', release_path
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
namespace :hg do
|
||||
desc 'Check that the repo is reachable'
|
||||
task :check do
|
||||
on roles :all do
|
||||
on release_roles :all do
|
||||
execute "hg", "id", repo_url
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Clone the repo to the cache'
|
||||
task :clone do
|
||||
on roles :all do
|
||||
on release_roles :all do
|
||||
if test " [ -d #{repo_path}/.hg ] "
|
||||
info t(:mirror_exists, at: repo_path)
|
||||
else
|
||||
|
@ -21,7 +21,7 @@ namespace :hg do
|
|||
|
||||
desc 'Pull changes from the remote repo'
|
||||
task :update => :'hg:clone' do
|
||||
on roles :all do
|
||||
on release_roles :all do
|
||||
within repo_path do
|
||||
execute "hg", "pull"
|
||||
end
|
||||
|
@ -30,7 +30,7 @@ namespace :hg do
|
|||
|
||||
desc 'Copy repo to releases'
|
||||
task :create_release => :'hg:update' do
|
||||
on roles :all do
|
||||
on release_roles :all do
|
||||
within repo_path do
|
||||
execute "hg", "archive", release_path, "--rev", fetch(:branch)
|
||||
end
|
||||
|
|
|
@ -26,6 +26,8 @@ namespace :deploy do
|
|||
end
|
||||
end
|
||||
|
||||
after :publishing, :restart
|
||||
|
||||
after :restart, :clear_cache do
|
||||
on roles(:web), in: :groups, limit: 3, wait: 10 do
|
||||
# Here we can do anything such as:
|
||||
|
@ -35,6 +37,4 @@ namespace :deploy do
|
|||
end
|
||||
end
|
||||
|
||||
after :finishing, 'deploy:cleanup'
|
||||
|
||||
end
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
set :stage, :<%= stage %>
|
||||
|
||||
# Simple Role Syntax
|
||||
# ==================
|
||||
# Supports bulk-adding hosts to roles, the primary
|
||||
# server in each group is considered to be the first
|
||||
# unless any hosts have the primary property set.
|
||||
# Don't declare `role :all`, it's a meta role
|
||||
role :app, %w{deploy@example.com}
|
||||
role :web, %w{deploy@example.com}
|
||||
role :db, %w{deploy@example.com}
|
||||
|
|
|
@ -11,13 +11,33 @@ describe Capistrano::DSL do
|
|||
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
|
||||
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}
|
||||
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
|
||||
|
||||
|
@ -70,6 +90,14 @@ describe Capistrano::DSL do
|
|||
|
||||
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}
|
||||
|
@ -77,16 +105,37 @@ describe Capistrano::DSL do
|
|||
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}
|
||||
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) }
|
||||
|
||||
|
@ -340,5 +389,53 @@ describe Capistrano::DSL do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'setting deploy configuration path' do
|
||||
subject { dsl.deploy_config_path.to_s }
|
||||
|
||||
context 'where no config path is set' 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 'where a custom 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 'setting stage configuration path' do
|
||||
subject { dsl.stage_config_path.to_s }
|
||||
|
||||
context 'where no config path is set' do
|
||||
|
||||
before do
|
||||
dsl.delete(:stage_config_path)
|
||||
end
|
||||
|
||||
it 'returns "config/deploy"' do
|
||||
expect(subject).to eq 'config/deploy'
|
||||
end
|
||||
end
|
||||
|
||||
context 'where a custom 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
|
||||
end
|
||||
end
|
||||
|
|
|
@ -159,6 +159,11 @@ module Capistrano
|
|||
let(:options) { { select: :active }}
|
||||
it { should be_true }
|
||||
end
|
||||
|
||||
context 'with :exclude' do
|
||||
let(:options) { { exclude: :active }}
|
||||
it { should be_false }
|
||||
end
|
||||
end
|
||||
|
||||
context 'value does not match server properly' do
|
||||
|
@ -171,6 +176,11 @@ module Capistrano
|
|||
let(:options) { { select: :inactive }}
|
||||
it { should be_false }
|
||||
end
|
||||
|
||||
context 'with :exclude' do
|
||||
let(:options) { { exclude: :inactive }}
|
||||
it { should be_true }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -186,6 +196,12 @@ module Capistrano
|
|||
let(:options) { { select: ->(s) { s.properties.active } } }
|
||||
it { should be_true }
|
||||
end
|
||||
|
||||
context 'with :exclude' do
|
||||
let(:options) { { exclude: ->(s) { s.properties.active } } }
|
||||
it { should be_false }
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context 'value does not match server properly' do
|
||||
|
@ -198,6 +214,12 @@ module Capistrano
|
|||
let(:options) { { select: ->(s) { s.properties.inactive } } }
|
||||
it { should be_false }
|
||||
end
|
||||
|
||||
context 'with :exclude' do
|
||||
let(:options) { { exclude: ->(s) { s.properties.inactive } } }
|
||||
it { should be_true }
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -141,6 +141,35 @@ module Capistrano
|
|||
|
||||
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' do
|
||||
|
||||
before do
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
module Capistrano
|
||||
module DSL
|
||||
|
||||
describe Env do
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -20,17 +20,6 @@ module Capistrano
|
|||
end
|
||||
end
|
||||
|
||||
describe '#stages' do
|
||||
before do
|
||||
Dir.expects(:[]).with('config/deploy/*.rb').
|
||||
returns(['config/deploy/staging.rb', 'config/deploy/production.rb'])
|
||||
end
|
||||
|
||||
it 'returns a list of defined stages' do
|
||||
expect(dsl.stages).to eq %w{staging production}
|
||||
end
|
||||
end
|
||||
|
||||
describe '#stage_set?' do
|
||||
subject { dsl.stage_set? }
|
||||
|
||||
|
|
7
spec/support/tasks/fail.cap
Normal file
7
spec/support/tasks/fail.cap
Normal file
|
@ -0,0 +1,7 @@
|
|||
set :fail, proc { fail }
|
||||
before 'deploy:starting', :fail do
|
||||
on roles :all do
|
||||
execute :touch, shared_path.join('fail')
|
||||
end
|
||||
fetch(:fail)
|
||||
end
|
5
spec/support/tasks/failed.cap
Normal file
5
spec/support/tasks/failed.cap
Normal file
|
@ -0,0 +1,5 @@
|
|||
after 'deploy:failed', :failed do
|
||||
on roles :all do
|
||||
execute :touch, shared_path.join('failed')
|
||||
end
|
||||
end
|
|
@ -8,10 +8,9 @@ module TestApp
|
|||
|
||||
def default_config
|
||||
%{
|
||||
set :stage, :#{stage}
|
||||
set :deploy_to, '#{deploy_to}'
|
||||
set :repo_url, 'git://github.com/capistrano/capistrano.git'
|
||||
set :branch, 'v3'
|
||||
set :branch, 'master'
|
||||
set :ssh_options, { keys: "\#{ENV['HOME']}/.vagrant.d/insecure_private_key" }
|
||||
server 'vagrant@localhost:2220', roles: %w{web app}
|
||||
set :linked_files, #{linked_files}
|
||||
|
@ -58,6 +57,14 @@ module TestApp
|
|||
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
|
||||
|
@ -67,9 +74,14 @@ module TestApp
|
|||
end
|
||||
|
||||
def cap(task)
|
||||
run "bundle exec cap #{stage} #{task}"
|
||||
end
|
||||
|
||||
def run(command)
|
||||
Dir.chdir(test_app_path) do
|
||||
%x[bundle exec cap #{stage} #{task}]
|
||||
%x[#{command}]
|
||||
end
|
||||
$?.success?
|
||||
end
|
||||
|
||||
def stage
|
||||
|
@ -135,4 +147,22 @@ module TestApp
|
|||
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
|
||||
|
|
Loading…
Reference in a new issue