capistrano 3.0.0.pre14 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -1,4 +1,5 @@
1
1
  require 'set'
2
+ require_relative 'servers/role_filter'
2
3
  module Capistrano
3
4
  class Configuration
4
5
  class Servers
@@ -40,17 +41,21 @@ module Capistrano
40
41
  servers.find_all { |server| server.has_role? role}
41
42
  end
42
43
 
43
- def fetch_roles(names, options)
44
- if Array(names).flatten.map(&:to_sym).include?(:all)
45
- filter(servers, options)
46
- else
47
- role_servers = Array(names).flat_map { |name| fetch name }.uniq
48
- filter(role_servers, options)
49
- end
44
+ def fetch_roles(required, options)
45
+ filter_roles = RoleFilter.for(required, available_roles)
46
+ select(servers_with_roles(filter_roles), options)
47
+ end
48
+
49
+ def servers_with_roles(roles)
50
+ roles.flat_map { |role| fetch role }.uniq
51
+ end
52
+
53
+ def select(servers, options)
54
+ servers.select { |server| server.select?(options) }
50
55
  end
51
56
 
52
- def filter(servers, options)
53
- Filter.new(servers, options).filtered_servers
57
+ def available_roles
58
+ servers.flat_map { |server| server.roles_array }.uniq
54
59
  end
55
60
 
56
61
  def servers
@@ -60,48 +65,6 @@ module Capistrano
60
65
  def extract_options(array)
61
66
  array.last.is_a?(::Hash) ? array.pop : {}
62
67
  end
63
-
64
- class Filter
65
- def initialize(servers, options)
66
- @servers, @options = servers, options
67
- end
68
-
69
- def filtered_servers
70
- if servers_with_filter.any?
71
- servers_with_filter
72
- else
73
- fail I18n.t(:filter_removes_all_servers, scope: :capistrano, filter: key || '(no filter)' )
74
- end
75
- end
76
-
77
- private
78
- attr_reader :options, :servers
79
-
80
- def servers_with_filter
81
- @servers_with_filter ||= servers.select(&filter)
82
- end
83
-
84
- def key
85
- options[:filter] || options[:select]
86
- end
87
-
88
- def filter_option
89
- key || all
90
- end
91
-
92
- def filter
93
- if filter_option.respond_to?(:call)
94
- filter_option
95
- else
96
- lambda { |server| server.fetch(filter_option) }
97
- end
98
- end
99
-
100
- def all
101
- lambda { |server| :all }
102
- end
103
-
104
- end
105
68
  end
106
69
  end
107
70
  end
@@ -0,0 +1,86 @@
1
+ module Capistrano
2
+ class Configuration
3
+ class Servers
4
+ class RoleFilter
5
+
6
+ def initialize(required, available)
7
+ @required, @available = required, available
8
+ end
9
+
10
+ def self.for(required, available)
11
+ new(required, available).roles
12
+ end
13
+
14
+ def roles
15
+ if required.include?(:all)
16
+ available
17
+ else
18
+ required.select { |name| available.include? name }
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def required
25
+ Array(@required).flat_map(&:to_sym)
26
+ end
27
+
28
+ def available
29
+ if role_filter.any?
30
+ role_filter
31
+ else
32
+ @available
33
+ end
34
+ end
35
+
36
+ def role_filter
37
+ env_filter | configuration_filter
38
+ end
39
+
40
+ def configuration_filter
41
+ ConfigurationFilter.new.roles
42
+ end
43
+
44
+ def env_filter
45
+ EnvFilter.new.roles
46
+ end
47
+
48
+ class ConfigurationFilter
49
+
50
+ def roles
51
+ if filter
52
+ Array(filter.fetch(:roles, [])).map(&:to_sym)
53
+ else
54
+ []
55
+ end
56
+ end
57
+
58
+ def config
59
+ Configuration.env
60
+ end
61
+
62
+ def filter
63
+ config.fetch(:filter) || config.fetch(:select)
64
+ end
65
+ end
66
+
67
+
68
+ class EnvFilter
69
+
70
+ def roles
71
+ if filter
72
+ filter.split(',').map(&:to_sym)
73
+ else
74
+ []
75
+ end
76
+ end
77
+
78
+ def filter
79
+ ENV['ROLES']
80
+ end
81
+ end
82
+
83
+ end
84
+ end
85
+ end
86
+ end
@@ -11,11 +11,3 @@ set :log_level, :debug
11
11
 
12
12
  set :pty, true
13
13
 
14
- namespace :deploy do
15
- task :ensure_stage do
16
- unless stage_set?
17
- puts t(:stage_not_set)
18
- exit 1
19
- end
20
- end
21
- end
@@ -32,7 +32,7 @@ module Capistrano
32
32
  end
33
33
 
34
34
  def rollback_log_message
35
- t(:rollback_log_message, user: local_user, release: release_timestamp)
35
+ t(:rollback_log_message, user: local_user, release: fetch(:rollback_timestamp))
36
36
  end
37
37
 
38
38
  def local_user
@@ -6,8 +6,8 @@ module Capistrano
6
6
  env.configure_backend
7
7
  end
8
8
 
9
- def fetch(key, default=nil)
10
- env.fetch(key, default)
9
+ def fetch(key, default=nil, &block)
10
+ env.fetch(key, default, &block)
11
11
  end
12
12
 
13
13
  def any?(key)
@@ -23,6 +23,10 @@ module Capistrano
23
23
  env.set(key, value)
24
24
  end
25
25
 
26
+ def delete(key)
27
+ env.delete(key)
28
+ end
29
+
26
30
  def ask(key, value)
27
31
  env.ask(key, value)
28
32
  end
@@ -20,7 +20,11 @@ module Capistrano
20
20
  end
21
21
 
22
22
  def release_path
23
- releases_path.join(release_timestamp)
23
+ fetch(:release_path, current_path)
24
+ end
25
+
26
+ def set_release_path(timestamp=now)
27
+ set(:release_path, releases_path.join(timestamp))
24
28
  end
25
29
 
26
30
  def repo_url
@@ -52,9 +56,8 @@ module Capistrano
52
56
  deploy_path.join('revisions.log')
53
57
  end
54
58
 
55
- def release_timestamp
56
- fetch(:rollback_release_timestamp,
57
- env.timestamp.strftime("%Y%m%d%H%M%S"))
59
+ def now
60
+ env.timestamp.strftime("%Y%m%d%H%M%S")
58
61
  end
59
62
 
60
63
  def asset_timestamp
@@ -11,5 +11,43 @@ module Capistrano
11
11
  invoke(post_task)
12
12
  end
13
13
  end
14
+
15
+ def remote_file(task)
16
+ target_roles = task.delete(:roles) { :all }
17
+ define_remote_file_task(task, target_roles)
18
+ end
19
+
20
+ def define_remote_file_task(task, target_roles)
21
+ Rake::Task.define_task(task) do |t|
22
+ prerequisite_file = t.prerequisites.first
23
+ file = shared_path.join(t.name)
24
+
25
+ on roles(target_roles) do
26
+ unless test "[ -f #{file} ]"
27
+ info "Uploading #{prerequisite_file} to #{file}"
28
+ upload! File.open(prerequisite_file), file
29
+ end
30
+ end
31
+
32
+ end
33
+ end
34
+
35
+ def ensure_stage
36
+ Rake::Task.define_task(:ensure_stage) do
37
+ unless stage_set?
38
+ puts t(:stage_not_set)
39
+ exit 1
40
+ end
41
+ end
42
+ end
43
+
44
+ def tasks_without_stage_dependency
45
+ stages + default_tasks
46
+ end
47
+
48
+ def default_tasks
49
+ %w{install}
50
+ end
51
+
14
52
  end
15
53
  end
@@ -0,0 +1 @@
1
+ load File.expand_path("../tasks/hg.rake", __FILE__)
@@ -14,11 +14,11 @@ en = {
14
14
  written_file: 'create %{file}',
15
15
  question: 'Please enter %{key}: |%{default_value}|',
16
16
  keeping_releases: 'Keeping %{keep_releases} of %{releases} deployed releases on %{host}',
17
+ no_old_releases: 'No old releases (keeping newest %{keep_releases}) on %{host}',
17
18
  linked_file_does_not_exist: 'linked file %{file} does not exist on %{host}',
18
19
  mirror_exists: "The repository mirror is at %{at}",
19
20
  revision_log_message: 'Branch %{branch} deployed as release %{release} by %{user}',
20
21
  rollback_log_message: '%{user} rolled back to release %{release}',
21
- filter_removes_all_servers: 'Your filter `%{filter}` would remove all matching servers',
22
22
  console: {
23
23
  welcome: 'capistrano console - enter command to execute on %{stage}',
24
24
  bye: 'bye'
@@ -1,10 +1,15 @@
1
1
  include Capistrano::DSL
2
2
 
3
- load 'capistrano/defaults.rb'
3
+ namespace :load do
4
+ task :defaults do
5
+ load 'capistrano/defaults.rb'
6
+ end
7
+ end
4
8
 
5
9
  stages.each do |stage|
6
10
  Rake::Task.define_task(stage) do
7
- load "config/deploy.rb"
11
+ invoke 'load:defaults'
12
+ load 'config/deploy.rb'
8
13
  load "config/deploy/#{stage}.rb"
9
14
  load "capistrano/#{fetch(:scm)}.rb"
10
15
  set(:stage, stage.to_sym)
@@ -13,5 +18,4 @@ stages.each do |stage|
13
18
  end
14
19
  end
15
20
 
16
-
17
21
  require 'capistrano/dotfile'
@@ -4,7 +4,7 @@ namespace :deploy do
4
4
  invoke 'deploy:check'
5
5
  end
6
6
 
7
- task :updating do
7
+ task :updating => :new_release_path do
8
8
  invoke "#{scm}:create_release"
9
9
  invoke 'deploy:symlink:shared'
10
10
  end
@@ -35,6 +35,7 @@ namespace :deploy do
35
35
  invoke "#{scm}:check"
36
36
  invoke 'deploy:check:directories'
37
37
  invoke 'deploy:check:linked_dirs'
38
+ invoke 'deploy:check:make_linked_dirs'
38
39
  invoke 'deploy:check:linked_files'
39
40
  end
40
41
 
@@ -53,12 +54,19 @@ namespace :deploy do
53
54
  execute :mkdir, '-pv', linked_dirs(shared_path)
54
55
  end
55
56
  end
57
+
58
+ desc 'Check directories of files to be linked exist in shared'
59
+ task :make_linked_dirs do
60
+ next unless any? :linked_files
61
+ on roles :app do |host|
62
+ execute :mkdir, '-pv', linked_file_dirs(shared_path)
63
+ end
64
+ end
56
65
 
57
66
  desc 'Check files to be linked exist in shared'
58
67
  task :linked_files do
59
68
  next unless any? :linked_files
60
69
  on roles :app do |host|
61
- execute :mkdir, '-pv', linked_file_dirs(shared_path)
62
70
  linked_files(shared_path).each do |file|
63
71
  unless test "[ -f #{file} ]"
64
72
  error t(:linked_file_does_not_exist, file: file, host: host)
@@ -129,9 +137,15 @@ namespace :deploy do
129
137
  releases = capture(:ls, '-x', releases_path).split
130
138
  if releases.count >= fetch(:keep_releases)
131
139
  info t(:keeping_releases, host: host.to_s, keep_releases: fetch(:keep_releases), releases: releases.count)
132
- directories = (releases - releases.last(fetch(:keep_releases))).map { |release|
133
- releases_path.join(release) }.join(" ")
134
- execute :rm, '-rf', directories
140
+ directories = (releases - releases.last(fetch(:keep_releases)))
141
+ if directories.any?
142
+ directories_str = directories.map do |release|
143
+ releases_path.join(release)
144
+ end.join(" ")
145
+ execute :rm, '-rf', directories_str
146
+ else
147
+ info t(:no_old_releases, host: host.to_s, keep_releases: fetch(:keep_releases))
148
+ end
135
149
  end
136
150
  end
137
151
  end
@@ -162,13 +176,29 @@ namespace :deploy do
162
176
  end
163
177
 
164
178
  desc 'Revert to previous release timestamp'
165
- task :revert_release do
179
+ task :revert_release => :rollback_release_path do
166
180
  on roles(:all) do
167
- last_release = capture(:ls, '-xr', releases_path).split[1]
168
- set(:rollback_release_timestamp, last_release)
169
- set(:branch, last_release)
170
181
  set(:revision_log_message, rollback_log_message)
171
182
  end
172
183
  end
173
184
 
185
+ task :new_release_path do
186
+ set_release_path
187
+ end
188
+
189
+ task :last_release_path do
190
+ on roles(:all) do
191
+ last_release = capture(:ls, '-xr', releases_path).split[1]
192
+ set_release_path(last_release)
193
+ end
194
+ end
195
+
196
+ task :rollback_release_path do
197
+ on roles(:all) do
198
+ last_release = capture(:ls, '-xr', releases_path).split[1]
199
+ set_release_path(last_release)
200
+ set(:rollback_timestamp, last_release)
201
+ end
202
+ end
203
+
174
204
  end
@@ -44,8 +44,6 @@ namespace :deploy do
44
44
  task :finished do
45
45
  end
46
46
 
47
- before :starting, :ensure_stage
48
-
49
47
  desc 'Rollback to previous release.'
50
48
  task :rollback do
51
49
  %w{ starting started
@@ -18,7 +18,7 @@ namespace :git do
18
18
  fetch(:branch)
19
19
  on roles :all do
20
20
  with git_environmental_variables do
21
- execute :git, :'ls-remote', repo_url
21
+ exit 1 unless test :git, :'ls-remote', repo_url
22
22
  end
23
23
  end
24
24
  end
@@ -52,11 +52,8 @@ namespace :git do
52
52
  on roles :all do
53
53
  with git_environmental_variables do
54
54
  within repo_path do
55
- execute :git, :clone, '--branch', fetch(:branch), \
56
- '--depth 1', \
57
- '--recursive', \
58
- '--no-hardlinks', \
59
- repo_path, release_path
55
+ execute :mkdir, '-p', release_path
56
+ execute :git, :archive, fetch(:branch), '| tar -x -C', release_path
60
57
  end
61
58
  end
62
59
  end