1
0
Fork 0
mirror of https://github.com/capistrano/capistrano synced 2023-03-27 23:21:18 -04:00

Allow each server to have a set of roles

This closes issue #429
This commit is contained in:
seenmyfate 2013-04-28 19:00:52 +01:00
parent 98c7990d60
commit fe10a84418
8 changed files with 229 additions and 212 deletions

View file

@ -1,40 +1,6 @@
# Capistrano [![Build Status](https://travis-ci.org/capistrano/capistrano.png?branch=v3)](https://travis-ci.org/capistrano/capistrano)
wip - aim here is to get 'something' up and running
TODO:
- [x] harness rake for dsl
- [x] create a working capify equivalent
- [x] create Capfile
- [x] create lib/tasks/deploy
- [x] create config/deploy/
- [x] write config/deploy.rb with example configuration
- [x] basic configuration object
- [x] basic 'capistrano/deploy' noop example
- [x] before/after task hooks
- [x] handle multi stage
- [x] pass any necessary configuration from deploy.rb to SSHKit
- [x] support set/fetch/role configuration
- [x] basic deploy
- [x] ask
- [x] add `deploy:check`
- [x] prefer `roles(:all)` over `all_roles`
- [x] simplify default deploy
- [x] support setting default environment variables
- [x] support existing significant configuration variables
- [x] set configuration defaults, add commented out examples to templates
- [x] basic rollback
- [x] support primary servers `on primary :db`
- [x] rails specific tasks (see [here](https://github.com/seenmyfate/capistrano-rails))
- [x] auto load tasks for scm based on variable
- [ ] run locally
- [ ] better descriptions for tasks
- [ ] add examples to README
- [ ] add task packaging run through
TODO
## Installation

View file

@ -1,3 +1,7 @@
require_relative 'configuration/question'
require_relative 'configuration/servers'
require_relative 'configuration/server'
module Capistrano
class Configuration
@ -26,15 +30,15 @@ module Capistrano
end
def role(name, servers)
roles.add_role(name, servers)
servers.add_role(name, servers)
end
def roles_for(names)
roles.fetch_roles(names)
servers.fetch_roles(names)
end
def primary(role)
roles.fetch_primary(role)
servers.fetch_primary(role)
end
def configure_backend
@ -55,8 +59,8 @@ module Capistrano
private
def roles
@roles ||= Roles.new
def servers
@servers ||= Servers.new
end
def config
@ -71,83 +75,6 @@ module Capistrano
end
end
class Question
def initialize(env, key, default)
@env, @key, @default = env, key, default
end
def call
ask_question
save_response
end
private
attr_reader :env, :key, :default
def ask_question
$stdout.puts question
end
def save_response
env.set(key, value)
end
def value
if response.empty?
default
else
response
end
end
def response
@response ||= $stdin.gets.chomp
end
def question
I18n.t(:question, key: key, default_value: default, scope: :capistrano)
end
end
class Roles
include Enumerable
def add_role(name, servers)
roles[name] = servers.map { |server| Server.new(server) }
end
def fetch_roles(names)
roles_for(names).flatten.uniq
end
def fetch_primary(role)
fetch(role).first
end
def each
roles.each { |role| yield role }
end
private
def fetch(name)
roles.fetch(name) { raise "role #{name} is not defined" }
end
def roles_for(names)
if names.include?(:all)
roles.values
else
names.map { |name| fetch name }
end
end
def roles
@roles ||= Hash.new
end
end
class Server < SSHKit::Host;end;
end
end

View file

@ -0,0 +1,42 @@
module Capistrano
class Configuration
class Question
def initialize(env, key, default)
@env, @key, @default = env, key, default
end
def call
ask_question
save_response
end
private
attr_reader :env, :key, :default
def ask_question
$stdout.puts question
end
def save_response
env.set(key, value)
end
def value
if response.empty?
default
else
response
end
end
def response
@response ||= $stdin.gets.chomp
end
def question
I18n.t(:question, key: key, default_value: default, scope: :capistrano)
end
end
end
end

View file

@ -0,0 +1,11 @@
require 'set'
module Capistrano
class Configuration
class Server < SSHKit::Host
def roles
@roles ||= Set.new
end
end
end
end

View file

@ -0,0 +1,50 @@
require 'set'
module Capistrano
class Configuration
class Servers
include Enumerable
def add_role(role, hosts)
hosts.each do |host|
server = server_from_host(host)
server.roles << role
servers << server
end
end
def fetch_roles(names)
roles_for(names)
end
def fetch_primary(role)
fetch(role).first
end
def each
servers.each { |server| yield server }
end
private
def server_from_host(host)
servers.find { |server| server.hostname == host } || Server.new(host)
end
def fetch(name)
servers.find_all { |server| server.roles.include? name }
end
def roles_for(names)
if names.include?(:all)
servers
else
names.flat_map { |name| fetch name }.uniq
end
end
def servers
@servers ||= Set.new
end
end
end
end

View file

@ -0,0 +1,49 @@
require 'spec_helper'
module Capistrano
describe Configuration::Question do
let(:question) { Configuration::Question.new(env, key, default) }
let(:default) { :default }
let(:key) { :branch }
let(:env) { stub }
describe '.new' do
it 'takes a key, default' do
question
end
end
describe '#call' do
subject { question.call }
context 'value is entered' do
let(:branch) { 'branch' }
before do
$stdout.expects(:puts).with('Please enter branch: |default|')
$stdin.expects(:gets).returns(branch)
end
it 'sets the value' do
env.expects(:set).with(key, branch)
question.call
end
end
context 'value is not entered' do
let(:branch) { default }
before do
$stdout.expects(:puts).with('Please enter branch: |default|')
$stdin.expects(:gets).returns('')
end
it 'sets the default as the value' do
env.expects(:set).with(key, branch)
question.call
end
end
end
end
end

View file

@ -0,0 +1,67 @@
require 'spec_helper'
module Capistrano
class Configuration
describe Servers do
let(:servers) { Servers.new }
describe 'adding a role' do
subject { servers.add_role(:app, %w{1 2}) }
it 'adds two new server instances' do
expect{subject}.to change{servers.count}.from(0).to(2)
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.fetch_roles([:app]).collect(&:roles)).to eq [app, web_app, web_app]
expect(servers.fetch_roles([:web]).collect(&:roles)).to eq [web_app, web_app, web]
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.fetch_roles([:app]).map(&:hostname)).to eq %w{1 2}
end
it 'returns the correct web servers' do
expect(servers.fetch_roles([:web]).map(&:hostname)).to eq %w{2 3}
end
it 'returns the correct app and web servers' do
expect(servers.fetch_roles([:app, :web]).map(&:hostname)).to eq %w{1 2 3}
end
it 'returns all servers' do
expect(servers.fetch_roles([:all]).map(&:hostname)).to eq %w{1 2 3}
end
end
end
end
end

View file

@ -1,57 +1,6 @@
require 'spec_helper'
module Capistrano
class Configuration
describe Roles do
let(:roles) { Roles.new }
describe 'adding a role' do
subject { roles.add_role(:app, %w{server1 server2}) }
before do
Server.expects(:new).with('server1')
Server.expects(:new).with('server2')
end
it 'adds the role, and creates new server instances' do
expect{subject}.to change{roles.count}.from(0).to(1)
end
end
describe 'fetching servers' do
let(:server1) { stub }
let(:server2) { stub }
let(:server3) { stub }
before do
Server.stubs(:new).with('server1').returns(server1)
Server.stubs(:new).with('server2').returns(server2)
Server.stubs(:new).with('server3').returns(server3)
roles.add_role(:app, %w{server1 server2})
roles.add_role(:web, %w{server2 server3})
end
it 'returns the correct app servers' do
expect(roles.fetch_roles([:app])).to eq [server1, server2]
end
it 'returns the correct web servers' do
expect(roles.fetch_roles([:web])).to eq [server2, server3]
end
it 'returns the correct app and web servers' do
expect(roles.fetch_roles([:app, :web])).to eq [server1, server2, server3]
end
it 'returns all servers' do
expect(roles.fetch_roles([:all])).to eq [server1, server2, server3]
end
end
end
end
describe Configuration do
let(:config) { Configuration.new }
let(:roles) { stub }
@ -128,48 +77,4 @@ module Capistrano
end
end
describe Configuration::Question do
let(:question) { Configuration::Question.new(env, key, default) }
let(:default) { :default }
let(:key) { :branch }
let(:env) { stub }
describe '.new' do
it 'takes a key, default' do
question
end
end
describe '#call' do
subject { question.call }
context 'value is entered' do
let(:branch) { 'branch' }
before do
$stdout.expects(:puts).with('Please enter branch: |default|')
$stdin.expects(:gets).returns(branch)
end
it 'sets the value' do
env.expects(:set).with(key, branch)
question.call
end
end
context 'value is not entered' do
let(:branch) { default }
before do
$stdout.expects(:puts).with('Please enter branch: |default|')
$stdin.expects(:gets).returns('')
end
it 'sets the default as the value' do
env.expects(:set).with(key, branch)
question.call
end
end
end
end
end