capistrano 3.3.5 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/CHANGELOG.md +36 -2
- data/README.md +30 -287
- data/capistrano.gemspec +0 -1
- data/features/sshconnect.feature +11 -0
- data/features/step_definitions/assertions.rb +6 -2
- data/features/step_definitions/setup.rb +4 -0
- data/lib/capistrano/configuration.rb +5 -1
- data/lib/capistrano/configuration/filter.rb +2 -2
- data/lib/capistrano/configuration/server.rb +15 -53
- data/lib/capistrano/configuration/servers.rb +26 -7
- data/lib/capistrano/deploy.rb +0 -1
- data/lib/capistrano/dsl.rb +2 -2
- data/lib/capistrano/dsl/env.rb +9 -1
- data/lib/capistrano/dsl/paths.rb +1 -1
- data/lib/capistrano/git.rb +1 -1
- data/lib/capistrano/tasks/deploy.rake +0 -1
- data/lib/capistrano/templates/Capfile +1 -1
- data/lib/capistrano/templates/deploy.rb.erb +3 -3
- data/lib/capistrano/templates/stage.rb.erb +31 -15
- data/lib/capistrano/version.rb +1 -1
- data/spec/integration/dsl_spec.rb +86 -113
- data/spec/lib/capistrano/configuration/filter_spec.rb +9 -3
- data/spec/lib/capistrano/configuration/server_spec.rb +34 -3
- data/spec/lib/capistrano/configuration/servers_spec.rb +37 -1
- data/spec/lib/capistrano/configuration_spec.rb +11 -0
- data/spec/lib/capistrano/dsl/paths_spec.rb +162 -41
- data/spec/support/Vagrantfile +17 -6
- data/spec/support/tasks/root.rake +11 -0
- data/spec/support/test_app.rb +1 -1
- metadata +7 -17
@@ -7,7 +7,8 @@ module Capistrano
|
|
7
7
|
let(:available) { [ Server.new('server1').add_roles([:web,:db]),
|
8
8
|
Server.new('server2').add_role(:web),
|
9
9
|
Server.new('server3').add_role(:redis),
|
10
|
-
Server.new('server4').add_role(:db)
|
10
|
+
Server.new('server4').add_role(:db),
|
11
|
+
Server.new('server5').add_role(:stageweb) ] }
|
11
12
|
|
12
13
|
describe '#new' do
|
13
14
|
it "won't create an invalid type of filter" do
|
@@ -57,7 +58,7 @@ module Capistrano
|
|
57
58
|
end
|
58
59
|
it 'correctly identifies a regex with a comma in' do
|
59
60
|
set = Filter.new(:host, 'server\d{1,3}$').filter(available)
|
60
|
-
expect(set.map(&:hostname)).to eq(%w{server1 server2 server3 server4})
|
61
|
+
expect(set.map(&:hostname)).to eq(%w{server1 server2 server3 server4 server5})
|
61
62
|
end
|
62
63
|
end
|
63
64
|
|
@@ -87,13 +88,18 @@ module Capistrano
|
|
87
88
|
expect(set.size).to eq(3)
|
88
89
|
expect(set.map(&:hostname)).to eq(%w{server1 server2 server4})
|
89
90
|
end
|
91
|
+
it 'returns only hosts for explicit roles' do
|
92
|
+
set = Filter.new(:role, [:web]).filter(available)
|
93
|
+
expect(set.size).to eq(2)
|
94
|
+
expect(set.map(&:hostname)).to eq(%w{server1 server2})
|
95
|
+
end
|
90
96
|
it 'returns hosts with regex role selection' do
|
91
97
|
set = Filter.new(:role, /red/).filter(available)
|
92
98
|
expect(set.map(&:hostname)).to eq(%w{server3})
|
93
99
|
end
|
94
100
|
it 'returns hosts with regex role selection using a string' do
|
95
101
|
set = Filter.new(:role, '/red|web/').filter(available)
|
96
|
-
expect(set.map(&:hostname)).to eq(%w{server1 server2 server3})
|
102
|
+
expect(set.map(&:hostname)).to eq(%w{server1 server2 server3 server5})
|
97
103
|
end
|
98
104
|
it 'returns hosts with combination of string role and regex' do
|
99
105
|
set = Filter.new(:role, 'db,/red/').filter(available)
|
@@ -33,7 +33,7 @@ module Capistrano
|
|
33
33
|
end
|
34
34
|
|
35
35
|
describe 'comparing identity' do
|
36
|
-
subject { server.
|
36
|
+
subject { server.hostname == Server[hostname].hostname }
|
37
37
|
|
38
38
|
context 'with the same user, hostname and port' do
|
39
39
|
let(:hostname) { 'root@hostname:1234' }
|
@@ -42,12 +42,12 @@ module Capistrano
|
|
42
42
|
|
43
43
|
context 'with a different user' do
|
44
44
|
let(:hostname) { 'deployer@hostname:1234' }
|
45
|
-
it { expect(subject).to
|
45
|
+
it { expect(subject).to be_truthy }
|
46
46
|
end
|
47
47
|
|
48
48
|
context 'with a different port' do
|
49
49
|
let(:hostname) { 'root@hostname:5678' }
|
50
|
-
it { expect(subject).to
|
50
|
+
it { expect(subject).to be_truthy }
|
51
51
|
end
|
52
52
|
|
53
53
|
context 'with a different hostname' do
|
@@ -94,6 +94,10 @@ module Capistrano
|
|
94
94
|
it 'sets the user' do
|
95
95
|
expect(server.user).to eq 'tomc'
|
96
96
|
end
|
97
|
+
|
98
|
+
it 'sets the netssh_options user' do
|
99
|
+
expect(server.netssh_options[:user]).to eq 'tomc'
|
100
|
+
end
|
97
101
|
end
|
98
102
|
|
99
103
|
context 'properties contains port' do
|
@@ -171,6 +175,18 @@ module Capistrano
|
|
171
175
|
end
|
172
176
|
end
|
173
177
|
|
178
|
+
context 'value does not match server properly' do
|
179
|
+
context 'with :active true' do
|
180
|
+
let(:options) { { active: true }}
|
181
|
+
it { expect(subject).to be_truthy }
|
182
|
+
end
|
183
|
+
|
184
|
+
context 'with :active false' do
|
185
|
+
let(:options) { { active: false }}
|
186
|
+
it { expect(subject).to be_falsey }
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
174
190
|
context 'value does not match server properly' do
|
175
191
|
context 'with :filter' do
|
176
192
|
let(:options) { { filter: :inactive }}
|
@@ -189,6 +205,18 @@ module Capistrano
|
|
189
205
|
end
|
190
206
|
end
|
191
207
|
|
208
|
+
context 'key is a property' do
|
209
|
+
context 'with :active true' do
|
210
|
+
let(:options) { { active: true }}
|
211
|
+
it { expect(subject).to be_truthy }
|
212
|
+
end
|
213
|
+
|
214
|
+
context 'with :active false' do
|
215
|
+
let(:options) { { active: false }}
|
216
|
+
it { expect(subject).to be_falsey }
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
192
220
|
context 'value is a proc' do
|
193
221
|
context 'value matches server property' do
|
194
222
|
|
@@ -261,6 +289,9 @@ module Capistrano
|
|
261
289
|
it 'contains correct user' do
|
262
290
|
expect(server.netssh_options[:user]).to eq 'another_user'
|
263
291
|
end
|
292
|
+
it 'does not affect server user in host' do
|
293
|
+
expect(server.user).to eq 'user_name'
|
294
|
+
end
|
264
295
|
it 'contains keys' do
|
265
296
|
expect(server.netssh_options[:keys]).to eq %w(/home/another_user/.ssh/id_rsa)
|
266
297
|
end
|
@@ -18,6 +18,12 @@ module Capistrano
|
|
18
18
|
expect(servers.count).to eq 1
|
19
19
|
end
|
20
20
|
|
21
|
+
it 'handles de-duplification within roles with users' do
|
22
|
+
servers.add_role(:app, %w{1}, user: 'nick')
|
23
|
+
servers.add_role(:app, %w{1}, user: 'fred')
|
24
|
+
expect(servers.count).to eq 1
|
25
|
+
end
|
26
|
+
|
21
27
|
it 'accepts instances of server objects' do
|
22
28
|
servers.add_role(:app, [Capistrano::Configuration::Server.new('example.net'), 'example.com'])
|
23
29
|
expect(servers.roles_for([:app]).length).to eq 2
|
@@ -134,7 +140,23 @@ module Capistrano
|
|
134
140
|
servers.add_host('1', roles: [:app, 'web'], test: :value, user: 'root', port: 34)
|
135
141
|
servers.add_host('1', roles: [:app, 'web'], test: :value, user: 'deployer', port: 34)
|
136
142
|
servers.add_host('1', roles: [:app, 'web'], test: :value, user: 'deployer', port: 56)
|
137
|
-
expect(servers.count).to eq(
|
143
|
+
expect(servers.count).to eq(1)
|
144
|
+
end
|
145
|
+
|
146
|
+
describe "with a :user property" do
|
147
|
+
|
148
|
+
it 'sets the server ssh username' do
|
149
|
+
servers.add_host('1', roles: [:app, 'web'], user: 'nick')
|
150
|
+
expect(servers.count).to eq(1)
|
151
|
+
expect(servers.roles_for([:all]).first.user).to eq 'nick'
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'overwrites the value of a user specified in the hostname' do
|
155
|
+
servers.add_host('brian@1', roles: [:app, 'web'], user: 'nick')
|
156
|
+
expect(servers.count).to eq(1)
|
157
|
+
expect(servers.roles_for([:all]).first.user).to eq 'nick'
|
158
|
+
end
|
159
|
+
|
138
160
|
end
|
139
161
|
|
140
162
|
it 'overwrites the value of a previously defined scalar property' do
|
@@ -169,6 +191,20 @@ module Capistrano
|
|
169
191
|
expect(servers.roles_for([:array_test]).first.properties.array_property).to eq [1,2]
|
170
192
|
end
|
171
193
|
|
194
|
+
it 'updates roles when custom user defined' do
|
195
|
+
servers.add_host('1', roles: ['foo'], user: 'custom')
|
196
|
+
servers.add_host('1', roles: ['bar'], user: 'custom')
|
197
|
+
expect(servers.roles_for([:foo]).first.hostname).to eq '1'
|
198
|
+
expect(servers.roles_for([:bar]).first.hostname).to eq '1'
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'updates roles when custom port defined' do
|
202
|
+
servers.add_host('1', roles: ['foo'], port: 1234)
|
203
|
+
servers.add_host('1', roles: ['bar'], port: 1234)
|
204
|
+
expect(servers.roles_for([:foo]).first.hostname).to eq '1'
|
205
|
+
expect(servers.roles_for([:bar]).first.hostname).to eq '1'
|
206
|
+
end
|
207
|
+
|
172
208
|
end
|
173
209
|
|
174
210
|
describe 'selecting roles' do
|
@@ -180,6 +180,17 @@ module Capistrano
|
|
180
180
|
config.backend = :test
|
181
181
|
expect(config.backend).to eq :test
|
182
182
|
end
|
183
|
+
|
184
|
+
describe "ssh_options for Netssh" do
|
185
|
+
it 'merges them with the :ssh_options variable' do
|
186
|
+
config.set :format, :pretty
|
187
|
+
config.set :log_level, :debug
|
188
|
+
config.set :ssh_options, { user: 'albert' }
|
189
|
+
SSHKit::Backend::Netssh.configure do |ssh| ssh.ssh_options = { password: 'einstein' } end
|
190
|
+
config.configure_backend
|
191
|
+
expect(config.backend.config.backend.config.ssh_options).to eq({ user: 'albert', password: 'einstein' })
|
192
|
+
end
|
193
|
+
end
|
183
194
|
end
|
184
195
|
end
|
185
196
|
end
|
@@ -1,69 +1,190 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
|
4
|
-
module DSL
|
3
|
+
describe Capistrano::DSL::Paths do
|
5
4
|
|
6
|
-
|
7
|
-
|
5
|
+
let(:dsl) { Class.new.extend Capistrano::DSL }
|
6
|
+
let(:parent) { Pathname.new('/var/shared') }
|
7
|
+
let(:paths) { Class.new.extend Capistrano::DSL::Paths }
|
8
|
+
|
9
|
+
let(:linked_dirs) { %w{log public/system} }
|
10
|
+
let(:linked_files) { %w{config/database.yml log/my.log} }
|
11
|
+
|
12
|
+
before do
|
13
|
+
dsl.set(:deploy_to, '/var/www')
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#linked_dirs' do
|
17
|
+
subject { paths.linked_dirs(parent) }
|
18
|
+
|
19
|
+
before do
|
20
|
+
paths.expects(:fetch).with(:linked_dirs).returns(linked_dirs)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'returns the full pathnames' do
|
24
|
+
expect(subject).to eq [Pathname.new('/var/shared/log'), Pathname.new('/var/shared/public/system')]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
describe '#linked_files' do
|
30
|
+
subject { paths.linked_files(parent) }
|
31
|
+
|
32
|
+
before do
|
33
|
+
paths.expects(:fetch).with(:linked_files).returns(linked_files)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'returns the full pathnames' do
|
37
|
+
expect(subject).to eq [Pathname.new('/var/shared/config/database.yml'), Pathname.new('/var/shared/log/my.log')]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '#linked_file_dirs' do
|
42
|
+
subject { paths.linked_file_dirs(parent) }
|
43
|
+
|
44
|
+
before do
|
45
|
+
paths.expects(:fetch).with(:linked_files).returns(linked_files)
|
8
46
|
end
|
9
47
|
|
10
|
-
|
11
|
-
|
12
|
-
|
48
|
+
it 'returns the full paths names of the parent dirs' do
|
49
|
+
expect(subject).to eq [Pathname.new('/var/shared/config'), Pathname.new('/var/shared/log')]
|
50
|
+
end
|
51
|
+
end
|
13
52
|
|
14
|
-
|
15
|
-
|
53
|
+
describe '#linked_dir_parents' do
|
54
|
+
subject { paths.linked_dir_parents(parent) }
|
16
55
|
|
56
|
+
before do
|
57
|
+
paths.expects(:fetch).with(:linked_dirs).returns(linked_dirs)
|
58
|
+
end
|
17
59
|
|
18
|
-
|
19
|
-
|
60
|
+
it 'returns the full paths names of the parent dirs' do
|
61
|
+
expect(subject).to eq [Pathname.new('/var/shared'), Pathname.new('/var/shared/public')]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe '#release path' do
|
20
66
|
|
21
|
-
|
22
|
-
paths.expects(:fetch).with(:linked_dirs).returns(linked_dirs)
|
23
|
-
end
|
67
|
+
subject { dsl.release_path }
|
24
68
|
|
25
|
-
|
26
|
-
|
27
|
-
|
69
|
+
context 'where no release path has been set' do
|
70
|
+
before do
|
71
|
+
dsl.delete(:release_path)
|
28
72
|
end
|
29
73
|
|
74
|
+
it 'returns the `current_path` value' do
|
75
|
+
expect(subject.to_s).to eq '/var/www/current'
|
76
|
+
end
|
77
|
+
end
|
30
78
|
|
31
|
-
|
32
|
-
|
79
|
+
context 'where the release path has been set' do
|
80
|
+
before do
|
81
|
+
dsl.set(:release_path,'/var/www/release_path')
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'returns the set `release_path` value' do
|
85
|
+
expect(subject.to_s).to eq '/var/www/release_path'
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
33
89
|
|
34
|
-
|
35
|
-
|
36
|
-
|
90
|
+
describe '#set_release_path' do
|
91
|
+
let(:now) { Time.parse("Oct 21 16:29:00 2015") }
|
92
|
+
subject { dsl.release_path }
|
37
93
|
|
38
|
-
|
39
|
-
|
40
|
-
|
94
|
+
context 'without a timestamp' do
|
95
|
+
before do
|
96
|
+
dsl.env.expects(:timestamp).returns(now)
|
97
|
+
dsl.set_release_path
|
41
98
|
end
|
42
99
|
|
43
|
-
|
44
|
-
subject
|
100
|
+
it 'returns the release path with the current env timestamp' do
|
101
|
+
expect(subject.to_s).to eq '/var/www/releases/20151021162900'
|
102
|
+
end
|
103
|
+
end
|
45
104
|
|
46
|
-
|
47
|
-
|
48
|
-
|
105
|
+
context 'with a timestamp' do
|
106
|
+
before do
|
107
|
+
dsl.set_release_path('timestamp')
|
108
|
+
end
|
49
109
|
|
50
|
-
|
51
|
-
|
52
|
-
end
|
110
|
+
it 'returns the release path with the timestamp' do
|
111
|
+
expect(subject.to_s).to eq '/var/www/releases/timestamp'
|
53
112
|
end
|
113
|
+
end
|
114
|
+
end
|
54
115
|
|
55
|
-
|
56
|
-
|
116
|
+
describe '#deploy_config_path' do
|
117
|
+
subject { dsl.deploy_config_path.to_s }
|
57
118
|
|
58
|
-
|
59
|
-
|
60
|
-
|
119
|
+
context 'when not specified' do
|
120
|
+
before do
|
121
|
+
dsl.delete(:deploy_config_path)
|
122
|
+
end
|
61
123
|
|
62
|
-
|
63
|
-
|
64
|
-
end
|
124
|
+
it 'returns "config/deploy.rb"' do
|
125
|
+
expect(subject).to eq 'config/deploy.rb'
|
65
126
|
end
|
127
|
+
end
|
128
|
+
|
129
|
+
context 'when the variable :deploy_config_path is set' do
|
130
|
+
before do
|
131
|
+
dsl.set(:deploy_config_path, 'my/custom/path.rb')
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'returns the custom path' do
|
135
|
+
expect(subject).to eq 'my/custom/path.rb'
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe '#stage_config_path' do
|
141
|
+
subject { dsl.stage_config_path.to_s }
|
142
|
+
|
143
|
+
context 'when not specified' do
|
144
|
+
|
145
|
+
before do
|
146
|
+
dsl.delete(:stage_config_path)
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'returns "config/deploy"' do
|
150
|
+
expect(subject).to eq 'config/deploy'
|
151
|
+
end
|
152
|
+
end
|
66
153
|
|
154
|
+
context 'when the variable :stage_config_path is set' do
|
155
|
+
before do
|
156
|
+
dsl.set(:stage_config_path, 'my/custom/path')
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'returns the custom path' do
|
160
|
+
expect(subject).to eq 'my/custom/path'
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
describe '#repo_path' do
|
166
|
+
subject { dsl.repo_path.to_s }
|
167
|
+
|
168
|
+
context 'when not specified' do
|
169
|
+
|
170
|
+
before do
|
171
|
+
dsl.delete(:repo_path)
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'returns the default #{deploy_to}/repo' do
|
175
|
+
dsl.set(:deploy_to, '/var/www')
|
176
|
+
expect(subject).to eq '/var/www/repo'
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
context 'when the variable :repo_path is set' do
|
181
|
+
before do
|
182
|
+
dsl.set(:repo_path, 'my/custom/path')
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'returns the custom path' do
|
186
|
+
expect(subject).to eq 'my/custom/path'
|
187
|
+
end
|
67
188
|
end
|
68
189
|
end
|
69
190
|
end
|
data/spec/support/Vagrantfile
CHANGED
@@ -1,13 +1,24 @@
|
|
1
|
-
|
1
|
+
require 'open-uri'
|
2
|
+
|
3
|
+
Vagrant.configure("2") do |config|
|
4
|
+
|
5
|
+
config.ssh.insert_key = false
|
2
6
|
|
3
7
|
[:app].each_with_index do |role, i|
|
4
8
|
config.vm.define(role, primary: true) do |config|
|
5
|
-
config.vm.
|
6
|
-
config.vm.box = 'precise64'
|
7
|
-
config.vm.
|
8
|
-
config.vm.forward_port 22, "222#{i}".to_i
|
9
|
+
config.vm.define role
|
10
|
+
config.vm.box = 'hashicorp/precise64'
|
11
|
+
config.vm.network "forwarded_port", guest: 22, host: "222#{i}".to_i
|
9
12
|
config.vm.provision :shell, inline: 'sudo apt-get -y install git-core'
|
13
|
+
|
14
|
+
vagrantkey = open("https://raw.githubusercontent.com/mitchellh/vagrant/master/keys/vagrant.pub", "r",&:read)
|
15
|
+
|
16
|
+
config.vm.provision :shell,
|
17
|
+
inline: <<-INLINE
|
18
|
+
install -d -m 700 /root/.ssh
|
19
|
+
echo -e "#{vagrantkey}" > /root/.ssh/authorized_keys
|
20
|
+
chmod 0600 /root/.ssh/authorized_keys
|
21
|
+
INLINE
|
10
22
|
end
|
11
23
|
end
|
12
|
-
|
13
24
|
end
|