mirror of
https://github.com/capistrano/capistrano
synced 2023-03-27 23:21:18 -04:00
Introduce no_release
server option
In order to provide a way for a server to perform tasks as part of a deploy but without being involved in the standard deploy flow, all included tasks will now prefer `release_roles` over `roles`. For example: on release_roles :all do # end This behaviour is implemented using `exclude`, a new option when selecting roles. `release_roles` is equivalent to: on roles :all, exclude: :no_release do # end Any server defined with `no_release: true` will be excluded from these tasks: server 'localhost', roles: %w{db}, no_release: true `exclude` can also be used in user defined tasks against any attribute, for example: server 'localhost', roles: %w{app web}, inactive: true on roles :app, exclude: :inactive do # end This commit resolves #686
This commit is contained in:
parent
e7fe616c64
commit
97d0ddf0ae
9 changed files with 136 additions and 25 deletions
|
@ -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
|
||||
|
|
|
@ -42,7 +42,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 +80,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 +133,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)
|
||||
|
|
|
@ -7,7 +7,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
|
||||
upload! StringIO.new("#!/bin/sh -e\nexec /usr/bin/ssh -o PasswordAuthentication=no -o StrictHostKeyChecking=no \"$@\"\n"), "#{fetch(:tmp_dir)}/git-ssh.sh"
|
||||
execute :chmod, "+x", "#{fetch(:tmp_dir)}/git-ssh.sh"
|
||||
end
|
||||
|
@ -16,7 +16,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 git_environmental_variables do
|
||||
exit 1 unless test :git, :'ls-remote', repo_url
|
||||
end
|
||||
|
@ -25,7 +25,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
|
||||
|
@ -40,7 +40,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
|
||||
|
@ -49,7 +49,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 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
|
||||
|
|
|
@ -11,16 +11,36 @@ 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 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 multiple roles' do
|
||||
it "does not confuse the last role with options" do
|
||||
expect(dsl.roles(:app, :web).count).to eq 4
|
||||
|
@ -85,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 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) }
|
||||
|
||||
|
|
|
@ -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
|
Loading…
Reference in a new issue