capistrano 3.0.0.pre14 → 3.0.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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +42 -0
  3. data/README.md +1 -1
  4. data/bin/cap +1 -1
  5. data/capistrano.gemspec +3 -0
  6. data/features/deploy.feature +52 -0
  7. data/features/installation.feature +16 -0
  8. data/features/remote_file_task.feature +14 -0
  9. data/features/step_definitions/assertions.rb +90 -0
  10. data/features/step_definitions/cap_commands.rb +8 -0
  11. data/features/step_definitions/setup.rb +25 -0
  12. data/features/support/env.rb +12 -0
  13. data/features/support/remote_command_helpers.rb +20 -0
  14. data/lib/Capfile +1 -0
  15. data/lib/capistrano.rb +0 -14
  16. data/lib/capistrano/all.rb +16 -0
  17. data/lib/capistrano/application.rb +1 -10
  18. data/lib/capistrano/configuration.rb +4 -0
  19. data/lib/capistrano/configuration/server.rb +44 -6
  20. data/lib/capistrano/configuration/servers.rb +14 -51
  21. data/lib/capistrano/configuration/servers/role_filter.rb +86 -0
  22. data/lib/capistrano/defaults.rb +0 -8
  23. data/lib/capistrano/dsl.rb +1 -1
  24. data/lib/capistrano/dsl/env.rb +6 -2
  25. data/lib/capistrano/dsl/paths.rb +7 -4
  26. data/lib/capistrano/dsl/task_enhancements.rb +38 -0
  27. data/lib/capistrano/hg.rb +1 -0
  28. data/lib/capistrano/i18n.rb +1 -1
  29. data/lib/capistrano/setup.rb +7 -3
  30. data/lib/capistrano/tasks/deploy.rake +39 -9
  31. data/lib/capistrano/tasks/framework.rake +0 -2
  32. data/lib/capistrano/tasks/git.rake +3 -6
  33. data/lib/capistrano/tasks/hg.rake +39 -0
  34. data/lib/capistrano/templates/Capfile +2 -23
  35. data/lib/capistrano/templates/deploy.rb.erb +23 -0
  36. data/lib/capistrano/templates/stage.rb.erb +1 -1
  37. data/lib/capistrano/version.rb +1 -1
  38. data/spec/integration/dsl_spec.rb +71 -0
  39. data/spec/lib/capistrano/configuration/server_spec.rb +69 -0
  40. data/spec/lib/capistrano/configuration/servers/role_filter_spec.rb +140 -0
  41. data/spec/lib/capistrano/configuration/servers_spec.rb +46 -9
  42. data/spec/lib/capistrano/configuration_spec.rb +11 -0
  43. data/spec/spec_helper.rb +1 -2
  44. data/spec/support/.gitignore +1 -0
  45. data/spec/support/Vagrantfile +13 -0
  46. data/spec/support/tasks/database.cap +11 -0
  47. data/spec/support/test_app.rb +55 -6
  48. metadata +74 -16
  49. data/lib/capistrano/bundler.rb +0 -1
  50. data/lib/capistrano/tasks/bundler.rake +0 -13
  51. data/spec/integration/deploy_finalize_spec.rb +0 -34
  52. data/spec/integration/deploy_finished_spec.rb +0 -36
  53. data/spec/integration/deploy_started_spec.rb +0 -74
  54. data/spec/integration/deploy_update_spec.rb +0 -45
  55. data/spec/integration/installation_spec.rb +0 -76
@@ -0,0 +1,39 @@
1
+ namespace :hg do
2
+ desc 'Check that the repo is reachable'
3
+ task :check do
4
+ on roles :all do
5
+ execute "hg", "id", repo_url
6
+ end
7
+ end
8
+
9
+ desc 'Clone the repo to the cache'
10
+ task :clone do
11
+ on roles :all do
12
+ if test " [ -d #{repo_path}/.hg ] "
13
+ info t(:mirror_exists, at: repo_path)
14
+ else
15
+ within deploy_path do
16
+ execute "hg", "clone", "--noupdate", repo_url, repo_path
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ desc 'Pull changes from the remote repo'
23
+ task :update => :'hg:clone' do
24
+ on roles :all do
25
+ within repo_path do
26
+ execute "hg", "pull"
27
+ end
28
+ end
29
+ end
30
+
31
+ desc 'Copy repo to releases'
32
+ task :create_release => :'hg:update' do
33
+ on roles :all do
34
+ within repo_path do
35
+ execute "hg", "archive", release_path, "--rev", fetch(:branch)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -10,38 +10,17 @@ require 'capistrano/deploy'
10
10
  #
11
11
  # https://github.com/capistrano/rvm
12
12
  # https://github.com/capistrano/rbenv
13
+ # https://github.com/capistrano/chruby
13
14
  # https://github.com/capistrano/bundler
14
15
  # https://github.com/capistrano/rails/tree/master/assets
15
16
  # https://github.com/capistrano/rails/tree/master/migrations
16
17
  #
17
18
  # require 'capistrano/rvm'
18
19
  # require 'capistrano/rbenv'
20
+ # require 'capistrano/chruby'
19
21
  # require 'capistrano/bundler'
20
22
  # require 'capistrano/rails/assets'
21
23
  # require 'capistrano/rails/migrations'
22
24
 
23
25
  # Loads custom tasks from `lib/capistrano/tasks' if you have any defined.
24
26
  Dir.glob('lib/capistrano/tasks/*.cap').each { |r| import r }
25
-
26
- namespace :deploy do
27
-
28
- desc 'Restart application'
29
- task :restart do
30
- on roles(:app), in: :sequence, wait: 5 do
31
- # Your restart mechanism here, for example:
32
- # execute :touch, release_path.join('tmp/restart.txt')
33
- end
34
- end
35
-
36
- after :restart, :clear_cache do
37
- on roles(:web), in: :groups, limit: 3, wait: 10 do
38
- # Here we can do anything such as:
39
- # within latest_release_path do
40
- # execute :rake, 'cache:clear'
41
- # end
42
- end
43
- end
44
-
45
- after :finishing, 'deploy:cleanup'
46
-
47
- end
@@ -15,3 +15,26 @@ set :repo_url, 'git@example.com:me/my_repo.git'
15
15
 
16
16
  # set :default_env, { path: "/opt/ruby/bin:$PATH" }
17
17
  # set :keep_releases, 5
18
+
19
+ namespace :deploy do
20
+
21
+ desc 'Restart application'
22
+ task :restart do
23
+ on roles(:app), in: :sequence, wait: 5 do
24
+ # Your restart mechanism here, for example:
25
+ # execute :touch, release_path.join('tmp/restart.txt')
26
+ end
27
+ end
28
+
29
+ after :restart, :clear_cache do
30
+ on roles(:web), in: :groups, limit: 3, wait: 10 do
31
+ # Here we can do anything such as:
32
+ # within release_path do
33
+ # execute :rake, 'cache:clear'
34
+ # end
35
+ end
36
+ end
37
+
38
+ after :finishing, 'deploy:cleanup'
39
+
40
+ end
@@ -39,4 +39,4 @@ server 'example.com', user: 'deploy', roles: %w{web app}, my_property: :my_value
39
39
  # }
40
40
  # setting per server overrides global ssh_options
41
41
 
42
- # fetch(:default_env).merge!(:rails_env, :<%= stage %>)
42
+ # fetch(:default_env).merge!(rails_env: :<%= stage %>)
@@ -1,3 +1,3 @@
1
1
  module Capistrano
2
- VERSION = "3.0.0.pre14"
2
+ VERSION = "3.0.0"
3
3
  end
@@ -165,6 +165,20 @@ describe Capistrano::DSL do
165
165
  end
166
166
  end
167
167
 
168
+ context 'with a block' do
169
+ context 'when the variables is defined' do
170
+ it 'returns the variable' do
171
+ expect(dsl.fetch(:scm) { :svn }).to eq :git
172
+ end
173
+ end
174
+
175
+ context 'when the variables is undefined' do
176
+ it 'calls the block' do
177
+ expect(dsl.fetch(:source_control) { :svn }).to eq :svn
178
+ end
179
+ end
180
+ end
181
+
168
182
  end
169
183
 
170
184
  describe 'asking for a variable' do
@@ -270,4 +284,61 @@ describe Capistrano::DSL do
270
284
 
271
285
  end
272
286
 
287
+ describe 'release path' do
288
+
289
+ before do
290
+ dsl.set(:deploy_to, '/var/www')
291
+ end
292
+
293
+ describe 'fetching release path' do
294
+ subject { dsl.release_path }
295
+
296
+ context 'where no release path has been set' do
297
+ before do
298
+ dsl.delete(:release_path)
299
+ end
300
+
301
+ it 'returns the `current_path` value' do
302
+ expect(subject.to_s).to eq '/var/www/current'
303
+ end
304
+ end
305
+
306
+ context 'where the release path has been set' do
307
+ before do
308
+ dsl.set(:release_path, '/var/www/release_path')
309
+ end
310
+
311
+ it 'returns the set `release_path` value' do
312
+ expect(subject.to_s).to eq '/var/www/release_path'
313
+ end
314
+ end
315
+ end
316
+
317
+ describe 'setting release path' do
318
+ let(:now) { Time.parse("Oct 21 16:29:00 2015") }
319
+ subject { dsl.release_path }
320
+
321
+ context 'without a timestamp' do
322
+ before do
323
+ dsl.env.expects(:timestamp).returns(now)
324
+ dsl.set_release_path
325
+ end
326
+
327
+ it 'returns the release path with the current env timestamp' do
328
+ expect(subject.to_s).to eq '/var/www/releases/20151021162900'
329
+ end
330
+ end
331
+
332
+ context 'with a timestamp' do
333
+ before do
334
+ dsl.set_release_path('timestamp')
335
+ end
336
+
337
+ it 'returns the release path with the timestamp' do
338
+ expect(subject.to_s).to eq '/var/www/releases/timestamp'
339
+ end
340
+ end
341
+ end
342
+
343
+ end
273
344
  end
@@ -134,6 +134,75 @@ module Capistrano
134
134
  end
135
135
  end
136
136
 
137
+ describe '#include?' do
138
+ let(:options) { {} }
139
+
140
+ subject { server.select?(options) }
141
+
142
+ before do
143
+ server.properties.active = true
144
+ end
145
+
146
+ context 'options are empty' do
147
+ it { should be_true }
148
+ end
149
+
150
+ context 'value is a symbol' do
151
+ context 'value matches server property' do
152
+
153
+ context 'with :filter' do
154
+ let(:options) { { filter: :active }}
155
+ it { should be_true }
156
+ end
157
+
158
+ context 'with :select' do
159
+ let(:options) { { select: :active }}
160
+ it { should be_true }
161
+ end
162
+ end
163
+
164
+ context 'value does not match server properly' do
165
+ context 'with :filter' do
166
+ let(:options) { { filter: :inactive }}
167
+ it { should be_false }
168
+ end
169
+
170
+ context 'with :select' do
171
+ let(:options) { { select: :inactive }}
172
+ it { should be_false }
173
+ end
174
+ end
175
+ end
176
+
177
+ context 'value is a proc' do
178
+ context 'value matches server property' do
179
+
180
+ context 'with :filter' do
181
+ let(:options) { { filter: ->(s) { s.properties.active } } }
182
+ it { should be_true }
183
+ end
184
+
185
+ context 'with :select' do
186
+ let(:options) { { select: ->(s) { s.properties.active } } }
187
+ it { should be_true }
188
+ end
189
+ end
190
+
191
+ context 'value does not match server properly' do
192
+ context 'with :filter' do
193
+ let(:options) { { filter: ->(s) { s.properties.inactive } } }
194
+ it { should be_false }
195
+ end
196
+
197
+ context 'with :select' do
198
+ let(:options) { { select: ->(s) { s.properties.inactive } } }
199
+ it { should be_false }
200
+ end
201
+ end
202
+ end
203
+
204
+ end
205
+
137
206
  describe 'assign ssh_options' do
138
207
  let(:server) { Server.new('user_name@hostname') }
139
208
 
@@ -0,0 +1,140 @@
1
+ require 'spec_helper'
2
+
3
+ module Capistrano
4
+ class Configuration
5
+ class Servers
6
+
7
+ describe RoleFilter do
8
+ let(:role_filter) { RoleFilter.new(required, available) }
9
+ let(:required) { [] }
10
+ let(:available) { [:web, :app, :db] }
11
+
12
+ describe '#new' do
13
+ it 'takes two arrays of role names' do
14
+ expect(role_filter)
15
+ end
16
+ end
17
+
18
+ describe '.for' do
19
+
20
+ subject { RoleFilter.for(required, available) }
21
+
22
+ context 'without env vars' do
23
+ context ':all required' do
24
+ let(:required) { [:all] }
25
+
26
+ it 'returns all available names' do
27
+ expect(subject).to eq available
28
+ end
29
+ end
30
+
31
+ context 'role names required' do
32
+ let(:required) { [:web, :app] }
33
+ it 'returns all required names' do
34
+ expect(subject).to eq required
35
+ end
36
+ end
37
+ end
38
+
39
+ context 'with ENV vars' do
40
+ before do
41
+ ENV.stubs(:[]).with('ROLES').returns('app,web')
42
+ end
43
+
44
+ context ':all required' do
45
+ let(:required) { [:all] }
46
+
47
+ it 'returns available names defined in ROLES' do
48
+ expect(subject).to eq [:app, :web]
49
+ end
50
+ end
51
+
52
+ context 'role names required' do
53
+ let(:required) { [:web, :db] }
54
+ it 'returns all required names defined in ROLES' do
55
+ expect(subject).to eq [:web]
56
+ end
57
+ end
58
+ end
59
+
60
+ context 'with configuration filters' do
61
+ before do
62
+ Configuration.env.set(:filter, roles: %w{app web})
63
+ end
64
+
65
+ context ':all required' do
66
+ let(:required) { [:all] }
67
+
68
+ it 'returns available names defined in the filter' do
69
+ expect(subject).to eq [:app, :web]
70
+ end
71
+ end
72
+
73
+ context 'role names required' do
74
+ let(:required) { [:web, :db] }
75
+ it 'returns all required names defined in the filter' do
76
+ expect(subject).to eq [:web]
77
+ end
78
+ end
79
+
80
+ after do
81
+ Configuration.env.delete(:filter)
82
+ end
83
+ end
84
+
85
+ context 'with a single configuration filter' do
86
+ before do
87
+ Configuration.env.set(:filter, roles: 'web')
88
+ end
89
+
90
+ context ':all required' do
91
+ let(:required) { [:all] }
92
+
93
+ it 'returns available names defined in the filter' do
94
+ expect(subject).to eq [:web]
95
+ end
96
+ end
97
+
98
+ context 'role names required' do
99
+ let(:required) { [:web, :db] }
100
+ it 'returns all required names defined in the filter' do
101
+ expect(subject).to eq [:web]
102
+ end
103
+ end
104
+
105
+ after do
106
+ Configuration.env.delete(:filter)
107
+ end
108
+ end
109
+
110
+ context 'with configuration filters and ENV vars' do
111
+ before do
112
+ Configuration.env.set(:filter, roles: %w{app})
113
+ ENV.stubs(:[]).with('ROLES').returns('web')
114
+ end
115
+
116
+ context ':all required' do
117
+ let(:required) { [:all] }
118
+
119
+ it 'returns available names defined in the filter' do
120
+ expect(subject).to eq [:web, :app]
121
+ end
122
+ end
123
+
124
+ context 'role names required' do
125
+ let(:required) { [:web, :db] }
126
+ it 'returns all required names defined in the filter' do
127
+ expect(subject).to eq [:web]
128
+ end
129
+ end
130
+
131
+ after do
132
+ Configuration.env.delete(:filter)
133
+ end
134
+ end
135
+ end
136
+ end
137
+
138
+ end
139
+ end
140
+ end
@@ -108,16 +108,15 @@ module Capistrano
108
108
 
109
109
  end
110
110
 
111
- describe '#roles' do
111
+ describe 'selecting roles' do
112
112
 
113
113
  before do
114
114
  servers.add_host('1', roles: :app, active: true)
115
115
  servers.add_host('2', roles: :app)
116
116
  end
117
117
 
118
- it 'raises if the filter would remove all matching hosts' do
119
- I18n.expects(:t)
120
- expect { servers.roles_for([:app, select: :inactive]) }.to raise_error
118
+ it 'is empty if the filter would remove all matching hosts' do
119
+ expect(servers.roles_for([:app, select: :inactive])).to be_empty
121
120
  end
122
121
 
123
122
  it 'can filter hosts by properties on the host object using symbol as shorthand' do
@@ -129,19 +128,57 @@ module Capistrano
129
128
  end
130
129
 
131
130
  it 'can filter hosts by properties on the host using a regular proc' do
132
- expect(servers.roles_for([:app, filter: lambda { |h| h.properties.active }]).length).to eq 1
131
+ expect(servers.roles_for([:app, filter: ->(h) { h.properties.active }]).length).to eq 1
133
132
  end
134
133
 
135
134
  it 'can select hosts by properties on the host using a regular proc' do
136
- expect(servers.roles_for([:app, select: lambda { |h| h.properties.active }]).length).to eq 1
135
+ expect(servers.roles_for([:app, select: ->(h) { h.properties.active }]).length).to eq 1
137
136
  end
138
137
 
139
- it 'raises if the regular proc filter would remove all matching hosts' do
140
- I18n.expects(:t)
141
- expect { servers.roles_for([:app, select: lambda { |h| h.properties.inactive }])}.to raise_error
138
+ it 'is empty if the regular proc filter would remove all matching hosts' do
139
+ expect(servers.roles_for([:app, select: ->(h) { h.properties.inactive }])).to be_empty
142
140
  end
143
141
 
144
142
  end
143
+
144
+ describe 'filtering roles' do
145
+
146
+ before do
147
+ ENV.stubs(:[]).with('ROLES').returns('web,db')
148
+ servers.add_host('1', roles: :app, active: true)
149
+ servers.add_host('2', roles: :app)
150
+ servers.add_host('3', roles: :web)
151
+ servers.add_host('4', roles: :web)
152
+ servers.add_host('5', roles: :db)
153
+ end
154
+
155
+ subject { servers.roles_for(roles).map(&:hostname) }
156
+
157
+ context 'when selecting all roles' do
158
+ let(:roles) { [:all] }
159
+
160
+ it 'returns the roles specified by ROLE' do
161
+ expect(subject).to eq %w{3 4 5}
162
+ end
163
+ end
164
+
165
+ context 'when selecting roles included in ROLE' do
166
+ let(:roles) { [:app, :web] }
167
+
168
+ it 'returns only roles that match ROLE' do
169
+ expect(subject).to eq %w{3 4}
170
+ end
171
+ end
172
+
173
+ context 'when selecting roles not included in ROLE' do
174
+ let(:roles) { [:app] }
175
+
176
+ it 'is empty' do
177
+ expect(subject).to be_empty
178
+ end
179
+ end
180
+ end
181
+
145
182
  end
146
183
  end
147
184
  end