capistrano 3.0.0.pre2 → 3.0.0.pre3
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/.gitignore +1 -0
- data/.travis.yml +5 -0
- data/README.md +108 -4
- data/lib/capistrano/application.rb +16 -1
- data/lib/capistrano/configuration.rb +12 -17
- data/lib/capistrano/configuration/server.rb +68 -3
- data/lib/capistrano/configuration/servers.rb +71 -28
- data/lib/capistrano/dsl.rb +2 -0
- data/lib/capistrano/dsl/env.rb +7 -4
- data/lib/capistrano/i18n.rb +2 -1
- data/lib/capistrano/tasks/deploy.rake +3 -6
- data/lib/capistrano/templates/Capfile +4 -0
- data/lib/capistrano/version.rb +1 -1
- data/spec/integration/deploy_finalize_spec.rb +34 -0
- data/spec/integration/deploy_finished_spec.rb +36 -0
- data/spec/integration/deploy_started_spec.rb +74 -0
- data/spec/integration/deploy_update_spec.rb +45 -0
- data/spec/integration/dsl_spec.rb +254 -0
- data/spec/integration/installation_spec.rb +76 -0
- data/spec/integration_spec_helper.rb +7 -0
- data/spec/lib/capistrano/application_spec.rb +61 -0
- data/spec/lib/capistrano/configuration/server_spec.rb +91 -0
- data/spec/lib/capistrano/configuration/servers_spec.rb +79 -11
- data/spec/lib/capistrano/configuration_spec.rb +12 -2
- data/spec/lib/capistrano/dsl/env_spec.rb +0 -73
- data/spec/spec_helper.rb +2 -0
- data/spec/support/matchers.rb +5 -0
- data/spec/support/test_app.rb +89 -0
- metadata +24 -2
data/lib/capistrano/dsl.rb
CHANGED
data/lib/capistrano/dsl/env.rb
CHANGED
@@ -12,7 +12,7 @@ module Capistrano
|
|
12
12
|
|
13
13
|
def any?(key)
|
14
14
|
value = fetch(key)
|
15
|
-
if value.respond_to?(:any)
|
15
|
+
if value && value.respond_to?(:any?)
|
16
16
|
value.any?
|
17
17
|
else
|
18
18
|
!fetch(key).nil?
|
@@ -27,8 +27,12 @@ module Capistrano
|
|
27
27
|
env.ask(key, value)
|
28
28
|
end
|
29
29
|
|
30
|
-
def role(name, servers)
|
31
|
-
env.role(name, servers)
|
30
|
+
def role(name, servers, options={})
|
31
|
+
env.role(name, servers, options)
|
32
|
+
end
|
33
|
+
|
34
|
+
def server(name, properties={})
|
35
|
+
env.server(name, properties)
|
32
36
|
end
|
33
37
|
|
34
38
|
def roles(*names)
|
@@ -54,4 +58,3 @@ module Capistrano
|
|
54
58
|
end
|
55
59
|
end
|
56
60
|
end
|
57
|
-
|
data/lib/capistrano/i18n.rb
CHANGED
@@ -13,11 +13,12 @@ en = {
|
|
13
13
|
stage_not_set: 'Stage not set, please call something such as `cap production deploy`, where production is a stage you have defined.',
|
14
14
|
written_file: 'create %{file}',
|
15
15
|
question: 'Please enter %{key}: |%{default_value}|',
|
16
|
-
keeping_releases: 'Keeping %{keep_releases} of %{releases} deployed releases',
|
16
|
+
keeping_releases: 'Keeping %{keep_releases} of %{releases} deployed releases on %{host}',
|
17
17
|
linked_file_does_not_exist: 'linked file %{file} does not exist on %{host}',
|
18
18
|
mirror_exists: "The repository mirror is at %{at}",
|
19
19
|
revision_log_message: 'Branch %{branch} deployed as release %{release} by %{user}',
|
20
20
|
rollback_log_message: '%{user} rolled back to release %{release}',
|
21
|
+
filter_removes_all_servers: 'Your filter `:%{filter}` would remove all matching servers',
|
21
22
|
console: {
|
22
23
|
welcome: 'capistrano console - enter command to execute on %{stage}',
|
23
24
|
bye: 'bye'
|
@@ -112,13 +112,10 @@ namespace :deploy do
|
|
112
112
|
|
113
113
|
desc 'Clean up old releases'
|
114
114
|
task :cleanup do
|
115
|
-
|
116
|
-
capture(:ls, '-xt', releases_path).split.reverse
|
117
|
-
end
|
118
|
-
|
119
|
-
on roles :all do
|
115
|
+
on roles :all do |host|
|
116
|
+
releases = capture(:ls, '-xt', releases_path).split.reverse
|
120
117
|
if releases.count >= fetch(:keep_releases)
|
121
|
-
info t(:keeping_releases, keep_releases: fetch(:keep_releases), releases: releases.count)
|
118
|
+
info t(:keeping_releases, host: host.to_s, keep_releases: fetch(:keep_releases), releases: releases.count)
|
122
119
|
directories = (releases - releases.last(fetch(:keep_releases))).map { |release|
|
123
120
|
releases_path.join(release) }.join(" ")
|
124
121
|
execute :rm, '-rf', directories
|
@@ -8,10 +8,14 @@ require 'capistrano/deploy'
|
|
8
8
|
#
|
9
9
|
# For documentation on these, see for example:
|
10
10
|
#
|
11
|
+
# https://github.com/capistrano/rvm
|
12
|
+
# https://github.com/capistrano/rbenv
|
11
13
|
# https://github.com/capistrano/bundler
|
12
14
|
# https://github.com/capistrano/rails/tree/master/assets
|
13
15
|
# https://github.com/capistrano/rails/tree/master/migrations
|
14
16
|
#
|
17
|
+
# require 'capistrano/rvm'
|
18
|
+
# require 'capistrano/rbenv'
|
15
19
|
# require 'capistrano/bundler'
|
16
20
|
# require 'capistrano/rails/assets'
|
17
21
|
# require 'capistrano/rails/migrations'
|
data/lib/capistrano/version.rb
CHANGED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'integration_spec_helper'
|
2
|
+
|
3
|
+
describe 'cap deploy:finished', slow: true do
|
4
|
+
before do
|
5
|
+
install_test_app_with(config)
|
6
|
+
end
|
7
|
+
|
8
|
+
describe 'deploy' do
|
9
|
+
let(:config) {
|
10
|
+
%{
|
11
|
+
set :stage, :#{stage}
|
12
|
+
set :deploy_to, '#{deploy_to}'
|
13
|
+
set :repo, 'git://github.com/capistrano/capistrano.git'
|
14
|
+
set :branch, 'v3'
|
15
|
+
server 'localhost', roles: %w{web app}, user: '#{current_user}'
|
16
|
+
set :linked_files, %w{config/database.yml}
|
17
|
+
set :linked_dirs, %w{bin log public/system vendor/bundle}
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
describe 'log_revision' do
|
22
|
+
before do
|
23
|
+
cap 'deploy:started'
|
24
|
+
cap 'deploy:update'
|
25
|
+
cap 'deploy:finalize'
|
26
|
+
cap 'deploy:finished'
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'writes the log file' do
|
30
|
+
expect(deploy_to.join('revisions.log')).to be_a_file
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'integration_spec_helper'
|
2
|
+
|
3
|
+
describe 'cap deploy:finished', slow: true do
|
4
|
+
before do
|
5
|
+
install_test_app_with(config)
|
6
|
+
end
|
7
|
+
|
8
|
+
describe 'deploy' do
|
9
|
+
let(:config) {
|
10
|
+
%{
|
11
|
+
set :stage, :#{stage}
|
12
|
+
set :deploy_to, '#{deploy_to}'
|
13
|
+
set :repo, 'git://github.com/capistrano/capistrano.git'
|
14
|
+
set :branch, 'v3'
|
15
|
+
server 'localhost', roles: %w{web app}, user: '#{current_user}'
|
16
|
+
set :linked_files, %w{config/database.yml}
|
17
|
+
set :linked_dirs, %w{bin log public/system vendor/bundle}
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
describe 'symlink' do
|
22
|
+
before do
|
23
|
+
cap 'deploy:started'
|
24
|
+
cap 'deploy:update'
|
25
|
+
cap 'deploy:finalize'
|
26
|
+
end
|
27
|
+
|
28
|
+
describe 'release' do
|
29
|
+
it 'symlinks the release to `current`' do
|
30
|
+
expect(File.symlink?(current_path)).to be_true
|
31
|
+
expect(File.readlink(current_path)).to match /\/tmp\/test_app\/deploy_to\/releases\/\d{14}/
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'integration_spec_helper'
|
2
|
+
|
3
|
+
describe 'cap deploy:started', slow: true do
|
4
|
+
before do
|
5
|
+
install_test_app_with(config)
|
6
|
+
end
|
7
|
+
|
8
|
+
describe 'deploy:check' do
|
9
|
+
let(:config) {
|
10
|
+
%{
|
11
|
+
set :stage, :#{stage}
|
12
|
+
set :deploy_to, '#{deploy_to}'
|
13
|
+
set :repo, 'git://github.com/capistrano/capistrano.git'
|
14
|
+
set :branch, 'v3'
|
15
|
+
server 'localhost', roles: %w{web app}, user: '#{current_user}'
|
16
|
+
set :linked_files, %w{config/database.yml}
|
17
|
+
set :linked_dirs, %w{bin log public/system vendor/bundle}
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
describe 'directories' do
|
22
|
+
before do
|
23
|
+
cap 'deploy:check:directories'
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'ensures the directory structure' do
|
27
|
+
expect(shared_path).to be_a_directory
|
28
|
+
expect(releases_path).to be_a_directory
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'linked_dirs' do
|
33
|
+
before do
|
34
|
+
cap 'deploy:check:linked_dirs'
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'ensure directories to be linked in `shared`' do
|
38
|
+
[
|
39
|
+
shared_path.join('bin'),
|
40
|
+
shared_path.join('log'),
|
41
|
+
shared_path.join('public/system'),
|
42
|
+
shared_path.join('vendor/bundle'),
|
43
|
+
].each do |dir|
|
44
|
+
expect(dir).to be_a_directory
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe 'linked_files' do
|
50
|
+
|
51
|
+
subject { cap 'deploy:check:linked_files' }
|
52
|
+
|
53
|
+
context 'file does not exist' do
|
54
|
+
it 'fails' do
|
55
|
+
expect(subject).to match 'config/database.yml does not exist'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'file exists' do
|
60
|
+
before do
|
61
|
+
create_shared_directory('config')
|
62
|
+
create_shared_file('config/database.yml')
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'suceeds' do
|
66
|
+
expect(subject).not_to match 'config/database.yml does not exist'
|
67
|
+
expect(subject).to match 'successful'
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'integration_spec_helper'
|
2
|
+
|
3
|
+
describe 'cap deploy:update', slow: true do
|
4
|
+
before do
|
5
|
+
install_test_app_with(config)
|
6
|
+
end
|
7
|
+
|
8
|
+
describe 'deploy' do
|
9
|
+
let(:config) {
|
10
|
+
%{
|
11
|
+
set :stage, :#{stage}
|
12
|
+
set :deploy_to, '#{deploy_to}'
|
13
|
+
set :repo, 'git://github.com/capistrano/capistrano.git'
|
14
|
+
set :branch, 'v3'
|
15
|
+
server 'localhost', roles: %w{web app}, user: '#{current_user}'
|
16
|
+
set :linked_files, %w{config/database.yml}
|
17
|
+
set :linked_dirs, %w{bin log public/system vendor/bundle}
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
describe 'symlink' do
|
22
|
+
before do
|
23
|
+
cap 'deploy:started'
|
24
|
+
create_shared_directory('config')
|
25
|
+
create_shared_file('config/database.yml')
|
26
|
+
cap 'deploy:symlink:shared'
|
27
|
+
end
|
28
|
+
|
29
|
+
describe 'linked_dirs' do
|
30
|
+
it 'symlinks the directories in shared to `current`' do
|
31
|
+
%w{bin log public/system vendor/bundle}.each do |dir|
|
32
|
+
expect(release_path.join(dir)).to be_a_symlink_to shared_path.join(dir)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe 'linked_files' do
|
38
|
+
it 'symlinks the files in shared to `current`' do
|
39
|
+
file = 'config/database.yml'
|
40
|
+
expect(release_path.join(file)).to be_a_symlink_to shared_path.join(file)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,254 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Capistrano::DSL do
|
4
|
+
|
5
|
+
let(:dsl) { Class.new.extend Capistrano::DSL }
|
6
|
+
|
7
|
+
describe 'setting and fetching hosts' do
|
8
|
+
describe 'when defining a host using the `server` syntax' do
|
9
|
+
before do
|
10
|
+
dsl.server 'example1.com', roles: %w{web}, active: true
|
11
|
+
dsl.server 'example2.com', roles: %w{web}
|
12
|
+
dsl.server 'example3.com', roles: %w{app web}, active: true
|
13
|
+
dsl.server 'example4.com', roles: %w{app}, primary: true
|
14
|
+
end
|
15
|
+
|
16
|
+
describe 'fetching all servers' do
|
17
|
+
subject { dsl.roles(:all) }
|
18
|
+
|
19
|
+
it 'returns all servers' do
|
20
|
+
expect(subject.map(&:hostname)).to eq %w{example1.com example2.com example3.com example4.com}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe 'fetching servers by role' do
|
25
|
+
subject { dsl.roles(:app) }
|
26
|
+
|
27
|
+
it 'returns the servers' do
|
28
|
+
expect(subject.map(&:hostname)).to eq %w{example3.com example4.com}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'fetching filtered servers by role' do
|
33
|
+
subject { dsl.roles(:app, filter: :active) }
|
34
|
+
|
35
|
+
it 'returns the servers' do
|
36
|
+
expect(subject.map(&:hostname)).to eq %w{example3.com}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe 'fetching selected servers by role' do
|
41
|
+
subject { dsl.roles(:app, select: :active) }
|
42
|
+
|
43
|
+
it 'returns the servers' do
|
44
|
+
expect(subject.map(&:hostname)).to eq %w{example3.com}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe 'fetching the primary server by role' do
|
49
|
+
context 'when inferring primary status based on order' do
|
50
|
+
subject { dsl.primary(:web) }
|
51
|
+
it 'returns the servers' do
|
52
|
+
expect(subject.hostname).to eq 'example1.com'
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'when the attribute `primary` is explicity set' do
|
57
|
+
subject { dsl.primary(:app) }
|
58
|
+
it 'returns the servers' do
|
59
|
+
expect(subject.hostname).to eq 'example4.com'
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
describe 'when defining hosts using the `role` syntax' do
|
67
|
+
before do
|
68
|
+
dsl.role :web, %w{example1.com example2.com example3.com}
|
69
|
+
dsl.role :web, %w{example1.com}, active: true
|
70
|
+
dsl.role :app, %w{example3.com example4.com}
|
71
|
+
dsl.role :app, %w{example3.com}, active: true
|
72
|
+
dsl.role :app, %w{example4.com}, primary: true
|
73
|
+
end
|
74
|
+
|
75
|
+
describe 'fetching all servers' do
|
76
|
+
subject { dsl.roles(:all) }
|
77
|
+
|
78
|
+
it 'returns all servers' do
|
79
|
+
expect(subject.map(&:hostname)).to eq %w{example1.com example2.com example3.com example4.com}
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe 'fetching servers by role' do
|
84
|
+
subject { dsl.roles(:app) }
|
85
|
+
|
86
|
+
it 'returns the servers' do
|
87
|
+
expect(subject.map(&:hostname)).to eq %w{example3.com example4.com}
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe 'fetching filtered servers by role' do
|
92
|
+
subject { dsl.roles(:app, filter: :active) }
|
93
|
+
|
94
|
+
it 'returns the servers' do
|
95
|
+
expect(subject.map(&:hostname)).to eq %w{example3.com}
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe 'fetching selected servers by role' do
|
100
|
+
subject { dsl.roles(:app, select: :active) }
|
101
|
+
|
102
|
+
it 'returns the servers' do
|
103
|
+
expect(subject.map(&:hostname)).to eq %w{example3.com}
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe 'fetching the primary server by role' do
|
108
|
+
context 'when inferring primary status based on order' do
|
109
|
+
subject { dsl.primary(:web) }
|
110
|
+
it 'returns the servers' do
|
111
|
+
expect(subject.hostname).to eq 'example1.com'
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'when the attribute `primary` is explicity set' do
|
116
|
+
subject { dsl.primary(:app) }
|
117
|
+
it 'returns the servers' do
|
118
|
+
expect(subject.hostname).to eq 'example4.com'
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
describe 'setting and fetching variables' do
|
128
|
+
|
129
|
+
before do
|
130
|
+
dsl.set :scm, :git
|
131
|
+
end
|
132
|
+
|
133
|
+
context 'without a default' do
|
134
|
+
context 'when the variables is defined' do
|
135
|
+
it 'returns the variable' do
|
136
|
+
expect(dsl.fetch(:scm)).to eq :git
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
context 'when the variables is undefined' do
|
141
|
+
it 'returns nil' do
|
142
|
+
expect(dsl.fetch(:source_control)).to be_nil
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
context 'with a default' do
|
148
|
+
context 'when the variables is defined' do
|
149
|
+
it 'returns the variable' do
|
150
|
+
expect(dsl.fetch(:scm, :svn)).to eq :git
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context 'when the variables is undefined' do
|
155
|
+
it 'returns the default' do
|
156
|
+
expect(dsl.fetch(:source_control, :svn)).to eq :svn
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
|
163
|
+
describe 'asking for a variable' do
|
164
|
+
before do
|
165
|
+
dsl.ask(:scm, :svn)
|
166
|
+
$stdout.stubs(:puts)
|
167
|
+
end
|
168
|
+
|
169
|
+
context 'variable is provided' do
|
170
|
+
before do
|
171
|
+
$stdin.expects(:gets).returns('git')
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'sets the input as the variable' do
|
175
|
+
expect(dsl.fetch(:scm)).to eq 'git'
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
context 'variable is not provided' do
|
180
|
+
before do
|
181
|
+
$stdin.expects(:gets).returns('')
|
182
|
+
end
|
183
|
+
|
184
|
+
it 'sets the variable as the default' do
|
185
|
+
expect(dsl.fetch(:scm)).to eq :svn
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
describe 'checking for presence' do
|
191
|
+
subject { dsl.any? :linked_files }
|
192
|
+
|
193
|
+
before do
|
194
|
+
dsl.set(:linked_files, linked_files)
|
195
|
+
end
|
196
|
+
|
197
|
+
context 'variable is an non-empty array' do
|
198
|
+
let(:linked_files) { %w{1} }
|
199
|
+
|
200
|
+
it { should be_true }
|
201
|
+
end
|
202
|
+
|
203
|
+
context 'variable is an empty array' do
|
204
|
+
let(:linked_files) { [] }
|
205
|
+
it { should be_false }
|
206
|
+
end
|
207
|
+
|
208
|
+
context 'variable exists, is not an array' do
|
209
|
+
let(:linked_files) { stub }
|
210
|
+
it { should be_true }
|
211
|
+
end
|
212
|
+
|
213
|
+
context 'variable is nil' do
|
214
|
+
let(:linked_files) { nil }
|
215
|
+
it { should be_false }
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
describe 'configuration SSHKit' do
|
220
|
+
let(:config) { SSHKit.config }
|
221
|
+
let(:backend) { SSHKit.config.backend.config }
|
222
|
+
let(:default_env) { { rails_env: :production } }
|
223
|
+
|
224
|
+
before do
|
225
|
+
dsl.set(:format, :dot)
|
226
|
+
dsl.set(:log_level, :debug)
|
227
|
+
dsl.set(:default_env, default_env)
|
228
|
+
dsl.set(:pty, true)
|
229
|
+
dsl.set(:connection_timeout, 10)
|
230
|
+
dsl.configure_backend
|
231
|
+
end
|
232
|
+
|
233
|
+
it 'sets the output' do
|
234
|
+
expect(config.output).to be_a SSHKit::Formatter::Dot
|
235
|
+
end
|
236
|
+
|
237
|
+
it 'sets the output verbosity' do
|
238
|
+
expect(config.output_verbosity).to eq 0
|
239
|
+
end
|
240
|
+
|
241
|
+
it 'sets the default env' do
|
242
|
+
expect(config.default_env).to eq default_env
|
243
|
+
end
|
244
|
+
|
245
|
+
it 'sets the backend pty' do
|
246
|
+
expect(backend.pty).to be_true
|
247
|
+
end
|
248
|
+
|
249
|
+
it 'sets the backend connection timeout' do
|
250
|
+
expect(backend.connection_timeout).to eq 10
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
end
|