statistrano 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +7 -0
  2. data/changelog.md +161 -0
  3. data/doc/config/file-permissions.md +33 -0
  4. data/doc/config/log-files.md +32 -0
  5. data/doc/config/task-definitions.md +88 -0
  6. data/doc/getting-started.md +96 -0
  7. data/doc/strategies/base.md +38 -0
  8. data/doc/strategies/branches.md +82 -0
  9. data/doc/strategies/releases.md +110 -0
  10. data/doc/strategies.md +17 -0
  11. data/lib/statistrano/config/configurable.rb +53 -0
  12. data/lib/statistrano/config/rake_task_with_context_creation.rb +43 -0
  13. data/lib/statistrano/config.rb +52 -0
  14. data/lib/statistrano/deployment/log_file.rb +44 -0
  15. data/lib/statistrano/deployment/manifest.rb +88 -0
  16. data/lib/statistrano/deployment/rake_tasks.rb +74 -0
  17. data/lib/statistrano/deployment/registerable.rb +11 -0
  18. data/lib/statistrano/deployment/releaser/revisions.rb +163 -0
  19. data/lib/statistrano/deployment/releaser/single.rb +48 -0
  20. data/lib/statistrano/deployment/releaser.rb +2 -0
  21. data/lib/statistrano/deployment/strategy/base.rb +132 -0
  22. data/lib/statistrano/deployment/strategy/branches/index/template.html.erb +78 -0
  23. data/lib/statistrano/deployment/strategy/branches/index.rb +40 -0
  24. data/lib/statistrano/deployment/strategy/branches/release.rb +73 -0
  25. data/lib/statistrano/deployment/strategy/branches.rb +198 -0
  26. data/lib/statistrano/deployment/strategy/check_git.rb +43 -0
  27. data/lib/statistrano/deployment/strategy/invoke_tasks.rb +58 -0
  28. data/lib/statistrano/deployment/strategy/releases.rb +76 -0
  29. data/lib/statistrano/deployment/strategy.rb +37 -0
  30. data/lib/statistrano/deployment.rb +10 -0
  31. data/lib/statistrano/log/default_logger.rb +105 -0
  32. data/lib/statistrano/log.rb +33 -0
  33. data/lib/statistrano/remote/file.rb +79 -0
  34. data/lib/statistrano/remote.rb +111 -0
  35. data/lib/statistrano/shell.rb +17 -0
  36. data/lib/statistrano/util/file_permissions.rb +34 -0
  37. data/lib/statistrano/util.rb +27 -0
  38. data/lib/statistrano/version.rb +3 -0
  39. data/lib/statistrano.rb +55 -0
  40. data/readme.md +247 -0
  41. data/spec/integration_tests/base_integration_spec.rb +103 -0
  42. data/spec/integration_tests/branches_integration_spec.rb +189 -0
  43. data/spec/integration_tests/releases/deploy_integration_spec.rb +116 -0
  44. data/spec/integration_tests/releases/list_releases_integration_spec.rb +38 -0
  45. data/spec/integration_tests/releases/prune_releases_integration_spec.rb +86 -0
  46. data/spec/integration_tests/releases/rollback_release_integration_spec.rb +46 -0
  47. data/spec/lib/statistrano/config/configurable_spec.rb +88 -0
  48. data/spec/lib/statistrano/config/rake_task_with_context_creation_spec.rb +73 -0
  49. data/spec/lib/statistrano/config_spec.rb +34 -0
  50. data/spec/lib/statistrano/deployment/log_file_spec.rb +75 -0
  51. data/spec/lib/statistrano/deployment/manifest_spec.rb +171 -0
  52. data/spec/lib/statistrano/deployment/rake_tasks_spec.rb +107 -0
  53. data/spec/lib/statistrano/deployment/registerable_spec.rb +19 -0
  54. data/spec/lib/statistrano/deployment/releaser/revisions_spec.rb +486 -0
  55. data/spec/lib/statistrano/deployment/releaser/single_spec.rb +59 -0
  56. data/spec/lib/statistrano/deployment/strategy/base_spec.rb +158 -0
  57. data/spec/lib/statistrano/deployment/strategy/branches_spec.rb +19 -0
  58. data/spec/lib/statistrano/deployment/strategy/check_git_spec.rb +39 -0
  59. data/spec/lib/statistrano/deployment/strategy/invoke_tasks_spec.rb +66 -0
  60. data/spec/lib/statistrano/deployment/strategy/releases_spec.rb +257 -0
  61. data/spec/lib/statistrano/deployment/strategy_spec.rb +76 -0
  62. data/spec/lib/statistrano/deployment_spec.rb +4 -0
  63. data/spec/lib/statistrano/log/default_logger_spec.rb +172 -0
  64. data/spec/lib/statistrano/log_spec.rb +36 -0
  65. data/spec/lib/statistrano/remote/file_spec.rb +166 -0
  66. data/spec/lib/statistrano/remote_spec.rb +226 -0
  67. data/spec/lib/statistrano/util/file_permissions_spec.rb +25 -0
  68. data/spec/lib/statistrano/util_spec.rb +23 -0
  69. data/spec/lib/statistrano_spec.rb +52 -0
  70. data/spec/spec_helper.rb +86 -0
  71. data/spec/support/given.rb +39 -0
  72. metadata +223 -0
@@ -0,0 +1,132 @@
1
+ module Statistrano
2
+ module Deployment
3
+ module Strategy
4
+
5
+ # A Base Deployment Instance
6
+ # it holds the common methods needed
7
+ # to create a deployment
8
+ class Base
9
+ extend Deployment::Registerable
10
+ extend Config::Configurable
11
+ include InvokeTasks
12
+ include CheckGit
13
+
14
+ attr_reader :name
15
+
16
+ register_strategy :base
17
+
18
+ options :remote_dir, :local_dir,
19
+ :hostname, :user, :password, :keys, :forward_agent,
20
+ :build_task, :post_deploy_task,
21
+ :check_git, :git_branch, :repo_url,
22
+ :dir_permissions, :file_permissions, :rsync_flags,
23
+ :log_file_path, :log_file_entry
24
+
25
+ option :remotes, []
26
+ option :dir_permissions, 755
27
+ option :file_permissions, 644
28
+ option :rsync_flags, '-aqz --delete-after'
29
+
30
+ option :verbose, false
31
+
32
+ task :deploy, :deploy, "Deploy to remote"
33
+ task :build, :invoke_build_task, "Run build task"
34
+ task :post_deploy, :invoke_post_deploy_task, "Run post deploy task"
35
+
36
+ # create a new deployment instance
37
+ # @param name [String]
38
+ # @return [Void]
39
+ def initialize name
40
+ @name = name
41
+ end
42
+
43
+ # Standard deployment flow
44
+ # @return [Void]
45
+ def deploy
46
+ unless safe_to_deploy?
47
+ Log.error "exiting due to git check failing"
48
+ abort()
49
+ end
50
+
51
+ build_data = invoke_build_task
52
+ build_data = ensure_data_is_hash build_data
53
+
54
+ unless safe_to_deploy?
55
+ Log.error "exiting due to git check failing",
56
+ "your build task modified checked in files"
57
+ abort()
58
+ end
59
+
60
+ remotes.each do |remote|
61
+ persisted_releaser.create_release remote, build_data
62
+ end
63
+
64
+ post_deploy_data = invoke_post_deploy_task
65
+ post_deploy_data = ensure_data_is_hash post_deploy_data
66
+
67
+ if config.log_file_path
68
+ log_entry = config.log_file_entry.call self, persisted_releaser,
69
+ build_data, post_deploy_data
70
+
71
+ remotes.each do |remote|
72
+ log_file(remote).append! log_entry
73
+ end
74
+ end
75
+
76
+ flush_persisted_releaser!
77
+ end
78
+
79
+ def register_tasks
80
+ RakeTasks.register self
81
+ end
82
+
83
+ def remotes
84
+ return @_remotes if @_remotes
85
+
86
+ @_remotes = config.options[:remotes].map do |remote_options|
87
+ Remote.new Config.new( config.options.dup.merge(remote_options) )
88
+ end
89
+ @_remotes.push Remote.new(config) if @_remotes.empty?
90
+
91
+ return @_remotes
92
+ end
93
+
94
+ def log_file remote=remotes.first
95
+ Deployment::LogFile.new config.log_file_path, remote
96
+ end
97
+
98
+ def persisted_releaser
99
+ @_persisted_releaser ||= releaser
100
+ end
101
+
102
+ def flush_persisted_releaser!
103
+ @_persisted_releaser = nil
104
+ end
105
+
106
+ private
107
+
108
+ def resolve_log_file_path
109
+ if config.log_file_path.start_with? '/'
110
+ config.log_file_path
111
+ else
112
+ File.join( config.remote_dir, config.log_file_path )
113
+ end
114
+ end
115
+
116
+ def ensure_data_is_hash data
117
+ if data.respond_to? :to_hash
118
+ data = data.to_hash
119
+ else
120
+ data = {}
121
+ end
122
+ end
123
+
124
+ def releaser
125
+ Releaser::Single.new
126
+ end
127
+
128
+ end
129
+
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,78 @@
1
+
2
+ <!DOCTYPE html>
3
+ <html role="document">
4
+ <head>
5
+ <meta charset=utf-8>
6
+ <meta content=en name=language>
7
+ <meta content=IE=edge,chrome=1 http-equiv=X-UA-Compatible>
8
+ <meta content=width=device-width name=viewport>
9
+ <style type=text/css>
10
+ body {
11
+ background: #f9f9f9;
12
+ color: #5f5f5f;
13
+ font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
14
+ -webkit-font-smoothing: antialiased;
15
+ margin: 0;
16
+ padding: 0;
17
+ }
18
+ h1 {
19
+ font-size: 3em;
20
+ margin: .5em 0;
21
+ line-height: 1;
22
+ }
23
+ .content {
24
+ max-width: 640px;
25
+ padding: 3em 1em;
26
+ margin: 0 auto;
27
+ text-align: center;
28
+ }
29
+ ul {
30
+ padding: 0;
31
+ outline: 1px solid #a6a6a6;
32
+ list-style: none;
33
+ display: inline-block;
34
+ }
35
+ li {
36
+ padding: 1em 1.5em;
37
+ border-bottom: 1px solid #c2c2c2;
38
+ text-align: left;
39
+ }
40
+ li:last-child {
41
+ border-bottom: none;
42
+ }
43
+ li a {
44
+ margin: 0;
45
+ padding: 0 1em 0 0;
46
+ display: inline-block;
47
+ font-weight: bold;
48
+ text-decoration: none;
49
+ color: inherit;
50
+ -o-transition: color .2s ease;
51
+ -moz-transition: color .2s ease;
52
+ -webkit-transition: color .2s ease;
53
+ transition: color .2s ease;
54
+ }
55
+ li a:hover {
56
+ color: #449A88;
57
+ }
58
+ li small {
59
+ margin: .25em 0 0 0;
60
+ padding: 0;
61
+ font-size: .75em;
62
+ display: inline-block;
63
+ color: #999;
64
+ }
65
+ </style>
66
+ </head>
67
+ <body>
68
+ <section class="content">
69
+ <h1>Branch Index</h1>
70
+ <ul><% releases.each do |release| %>
71
+ <li>
72
+ <a href="<%= release.href %>"><%= release.name %></a>
73
+ <small>updated: <%= Time.at(release.time).strftime('%A %b %d, %Y at %l:%M %P') %></small>
74
+ </li>
75
+ <% end %></ul>
76
+ </section>
77
+ </body>
78
+ </html>
@@ -0,0 +1,40 @@
1
+ require 'erb'
2
+
3
+ module Statistrano
4
+ module Deployment
5
+ module Strategy
6
+ class Branches
7
+
8
+ class Index
9
+
10
+ attr_reader :template, :releases
11
+
12
+ def initialize releases, template_path=nil
13
+ @releases = releases
14
+ @template = IO.read(template_path || File.expand_path("../index/template.html.erb", __FILE__))
15
+ end
16
+
17
+ def to_html
18
+ ERB.new(template).result(ERBContext.new(releases).get_binding)
19
+ end
20
+
21
+ class ERBContext
22
+
23
+ attr_reader :releases
24
+
25
+ def initialize releases
26
+ @releases = releases
27
+ end
28
+
29
+ def get_binding
30
+ binding
31
+ end
32
+
33
+ end
34
+
35
+ end
36
+
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,73 @@
1
+ module Statistrano
2
+ module Deployment
3
+ module Strategy
4
+ class Branches
5
+
6
+ #
7
+ # Manages the state of a single release for the manifest
8
+ #
9
+ class Release
10
+
11
+ attr_reader :name, :config, :options
12
+
13
+ # init a release
14
+ # @param name [String] name of the release
15
+ # @param config [Obj] the config object
16
+ # @param options [Hash] :time, :commit, & :link || :repo_url
17
+ def initialize name, config, options={}
18
+ @name = name
19
+ @config = config
20
+ @options = Util.symbolize_hash_keys options
21
+ end
22
+
23
+ def time
24
+ @_time ||= options.fetch(:time) { Time.now.to_i }
25
+ end
26
+
27
+ def commit
28
+ @_commit ||= options.fetch(:commit) { Asgit.current_commit }
29
+ end
30
+
31
+ def link
32
+ @_link ||= options.fetch(:link) { (options[:repo_url]) ? "#{options[:repo_url]}/tree/#{commit}" : nil }
33
+ end
34
+
35
+ def href
36
+ "http://#{name}.#{config.base_domain}"
37
+ end
38
+
39
+ # # convert the release to an li element
40
+ # # @return [String]
41
+ # def as_li
42
+ # "<li>" +
43
+ # "<a href=\"http://#{name}.#{config.base_domain}\">#{name}</a>" +
44
+ # "<small>updated: #{Time.at(time).strftime('%A %b %d, %Y at %l:%M %P')}</small>" +
45
+ # "</li>"
46
+ # end
47
+
48
+ # def get_binding
49
+ # binding
50
+ # end
51
+
52
+ def to_hash
53
+ hash = {
54
+ name: name,
55
+ time: time,
56
+ commit: commit
57
+ }
58
+ hash.merge({ link: link }) if link
59
+
60
+ return hash
61
+ end
62
+
63
+ # convert the release to a json object
64
+ # @return [String]
65
+ def to_json
66
+ return to_hash.to_json
67
+ end
68
+ end
69
+
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,198 @@
1
+ module Statistrano
2
+ module Deployment
3
+ module Strategy
4
+
5
+ #
6
+ # Branches is for deployments that depend upon the
7
+ # current git branch, eg. doing feature branch deployments
8
+ #
9
+ class Branches < Base
10
+ register_strategy :branches
11
+
12
+ option :base_domain
13
+ option :public_dir, :call, Proc.new { Asgit.current_branch.to_slug }
14
+ option :post_deploy_task, Proc.new { |d|
15
+ d.push_current_release_to_manifest
16
+ d.generate_index
17
+ }
18
+
19
+ task :list, :list_releases, "List branches"
20
+ task :prune, :prune_releases, "Prune a branch"
21
+ task :generate_index, :generate_index, "Generate a branch index"
22
+ task :open, :open_url, "Open the current branch URL"
23
+
24
+ # output a list of the releases in manifest
25
+ # @return [Void]
26
+ def list_releases
27
+ remotes.each do |remote|
28
+ releases_data = sorted_release_data(remote)
29
+ releases_data.map! do |release|
30
+ "#{release[:name]} created at #{Time.at(release[:time]).strftime('%a %b %d, %Y at %l:%M %P')}"
31
+ end
32
+ Log.info remote.config.hostname.to_sym, *releases_data
33
+ end
34
+ end
35
+
36
+ # trim releases not in the manifest,
37
+ # get user input for removal of other releases
38
+ # @return [Void]
39
+ def prune_releases
40
+ candidate_releases = []
41
+ remotes.each do |remote|
42
+ prune_untracked_releases(remote)
43
+ candidate_releases.push *get_releases(remote)
44
+ candidate_releases.uniq!
45
+ end
46
+
47
+ if candidate_releases.length > 0
48
+ pick_and_remove_release candidate_releases
49
+ else
50
+ Log.warn "no releases to prune"
51
+ end
52
+ end
53
+
54
+ # generate an index file for releases in the manifest
55
+ # @return [Void]
56
+ def generate_index
57
+ remotes.each do |remote|
58
+ index_dir = File.join( remote.config.remote_dir, "index" )
59
+ index_path = File.join( index_dir, "index.html" )
60
+ remote.create_remote_dir index_dir
61
+ remote.run "touch #{index_path} && echo '#{release_list_html(remote)}' > #{index_path}"
62
+ end
63
+ end
64
+
65
+ # push the current release into the manifest
66
+ # @return [Void]
67
+ def push_current_release_to_manifest
68
+ remotes.each do |remote|
69
+ mnfst = manifest(remote)
70
+ mnfst.put Release.new( config.public_dir, config ).to_hash, :name
71
+ mnfst.save!
72
+ end
73
+ end
74
+
75
+ private
76
+
77
+ def manifest remote
78
+ @_manifests ||= {}
79
+
80
+ @_manifests.fetch( remote ) do
81
+ Deployment::Manifest.new remote.config.remote_dir, remote
82
+ end
83
+ end
84
+
85
+ def pick_and_remove_release candidate_releases
86
+ picked_release = pick_release_to_remove candidate_releases
87
+ if picked_release
88
+ remotes.each do |remote|
89
+ if get_releases(remote).include? picked_release
90
+ remove_release(remote, picked_release)
91
+ end
92
+ end
93
+ generate_index
94
+ else
95
+ Log.warn "sorry, that isn't one of the releases"
96
+ end
97
+ end
98
+
99
+ def pick_release_to_remove candidate_releases
100
+ list_releases_with_index candidate_releases
101
+
102
+ picked_release = Shell.get_input("select a release to remove: ").gsub(/[^0-9]/, '')
103
+
104
+ if !picked_release.empty? && picked_release.to_i < candidate_releases.length
105
+ return candidate_releases[picked_release.to_i]
106
+ else
107
+ return false
108
+ end
109
+ end
110
+
111
+ def list_releases_with_index releases
112
+ releases.each_with_index do |release,idx|
113
+ Log.info :"[#{idx}]", "#{release}"
114
+ end
115
+ end
116
+
117
+ # removes releases that are on the remote but not in the manifest
118
+ # @return [Void]
119
+ def prune_untracked_releases remote
120
+ get_actual_releases(remote).each do |release|
121
+ remove_release(remote, release) unless get_releases(remote).include? release
122
+ end
123
+ end
124
+
125
+ def release_list_html remote
126
+ releases = sorted_release_data(remote).map do |r|
127
+ name = r.fetch(:name)
128
+ r.merge({ repo_url: config.repo_url }) if config.repo_url
129
+ Release.new( name, config, r )
130
+ end
131
+
132
+ Index.new( releases ).to_html
133
+ end
134
+
135
+ def sorted_release_data remote
136
+ manifest(remote).data.sort_by do |r|
137
+ r[:time]
138
+ end.reverse
139
+ end
140
+
141
+ # remove a release
142
+ # @param name [String]
143
+ # @return [Void]
144
+ def remove_release remote, name
145
+ Log.info remote.config.hostname.to_sym, "Removing release '#{name}'"
146
+ remote.run "rm -rf #{release_path(name, remote)}"
147
+ manifest(remote).remove_if do |r|
148
+ r[:name] == name
149
+ end
150
+ manifest(remote).save!
151
+ end
152
+
153
+ # return array of releases from the manifest
154
+ # @return [Array]
155
+ def get_releases remote
156
+ sorted_release_data(remote).map { |r| r[:name] }
157
+ end
158
+
159
+ # return array of releases on the remote
160
+ # @return [Array]
161
+ def get_actual_releases remote
162
+ remote.run("ls -mp #{remote.config.remote_dir}")
163
+ .stdout.strip.split(',')
164
+ .keep_if { |release| /\/$/.match(release) }
165
+ .map { |release| release.strip.sub(/(\/$)/, '') }
166
+ .keep_if { |release| release != "index" }
167
+ end
168
+
169
+ # path to the current release
170
+ # this is based on the git branch
171
+ # @return [String]
172
+ def current_release_path
173
+ File.join( config.remote_dir, config.public_dir )
174
+ end
175
+
176
+ # path to a specific release
177
+ # @return [String]
178
+ def release_path name, remote
179
+ File.join( remote.config.remote_dir, name )
180
+ end
181
+
182
+ # open the current checked out branch
183
+ # @return [Void]
184
+ def open_url
185
+ if config.base_domain
186
+ url = "http://#{config.public_dir}.#{config.base_domain}"
187
+ system "open #{url}"
188
+ end
189
+ end
190
+
191
+ end
192
+
193
+ end
194
+ end
195
+ end
196
+
197
+ require_relative 'branches/index'
198
+ require_relative 'branches/release'
@@ -0,0 +1,43 @@
1
+ module Statistrano
2
+ module Deployment
3
+ module Strategy
4
+
5
+ module CheckGit
6
+
7
+ # Check if things are safe to deploy
8
+ # @return [Boolean]
9
+ def safe_to_deploy?
10
+
11
+ # if we don't want to check git
12
+ # we're good to go
13
+ if !config.check_git
14
+ return true
15
+ end
16
+
17
+ # are there any uncommited changes?
18
+ if !Asgit.working_tree_clean?
19
+ Log.warn "You need to commit or stash your changes before deploying"
20
+ return false
21
+ end
22
+
23
+ # make sure you're on the branch selected to check against
24
+ if Asgit.current_branch != config.git_branch
25
+ Log.warn "You shouldn't deploy from any branch but #{config.git_branch}"
26
+ return false
27
+ end
28
+
29
+ # make sure you're up to date
30
+ if !Asgit.remote_up_to_date?
31
+ Log.warn "You need to update or push your changes before deploying"
32
+ return false
33
+ end
34
+
35
+ # we passed all the checks
36
+ return true
37
+ end
38
+
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,58 @@
1
+ module Statistrano
2
+ module Deployment
3
+ module Strategy
4
+
5
+ module InvokeTasks
6
+
7
+ # Run the post_deploy_task
8
+ # return [Void]
9
+ def invoke_post_deploy_task
10
+ if config.post_deploy_task
11
+ Log.info :post_deploy, "Running the post deploy task"
12
+ call_or_invoke_task config.post_deploy_task
13
+ end
14
+ end
15
+
16
+ # Run the build_task supplied
17
+ # return [Void]
18
+ def invoke_build_task
19
+ Log.info :build, "Running the build task"
20
+ call_or_invoke_task config.build_task
21
+ end
22
+
23
+ # Run the pre_symlink_task if supplied
24
+ # return [Void]
25
+ def invoke_pre_symlink_task remote
26
+ if !remote.config.pre_symlink_task.nil?
27
+ Log.info :pre_symlink, "Running the pre_symlink task"
28
+ resp = call_or_invoke_task remote.config.pre_symlink_task, remote
29
+ if resp == false
30
+ Log.error :pre_symlink, "exiting due to falsy return"
31
+ abort()
32
+ end
33
+ end
34
+ end
35
+
36
+ def call_or_invoke_task task, arg=nil
37
+ if task.respond_to? :call
38
+ if arg && task.arity == 2
39
+ task.call self, arg
40
+ elsif task.arity == 1
41
+ task.call self
42
+ else
43
+ task.call
44
+ end
45
+ else
46
+ Rake::Task[task].invoke
47
+ end
48
+ rescue Exception => e
49
+ Log.error "exiting due to error in task",
50
+ "#{e.class}: #{e}"
51
+ abort()
52
+ end
53
+
54
+ end
55
+
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,76 @@
1
+ module Statistrano
2
+ module Deployment
3
+ module Strategy
4
+
5
+ # deployment type for running a releases deployment
6
+ # accross multiple remotes
7
+ #
8
+ # @example:
9
+ #
10
+ # define_deployment "multi", :releases do
11
+ # build_task 'deploy:build'
12
+ # local_dir 'build'
13
+ # remote_dir '/var/www/proj'
14
+ #
15
+ # check_git true
16
+ # git_branch 'master'
17
+ #
18
+ # remotes [
19
+ # { hostname: 'web01' },
20
+ # { hostname: 'web02' }
21
+ # ]
22
+ #
23
+ # # each remote gets merged with the global
24
+ # # configs and deployed to individually
25
+ # #
26
+ # end
27
+ #
28
+ class Releases < Base
29
+ register_strategy :releases
30
+
31
+ option :pre_symlink_task, nil
32
+ option :release_count, 5
33
+ option :release_dir, "releases"
34
+ option :public_dir, "current"
35
+
36
+ option :remotes, []
37
+
38
+ task :deploy, :deploy, "Deploy to all remotes"
39
+ task :rollback, :rollback_release, "Rollback to the previous release"
40
+ task :prune, :prune_releases, "Prune releases to release count"
41
+ task :list, :list_releases, "List releases"
42
+
43
+ def initialize name
44
+ @name = name
45
+ end
46
+
47
+ def rollback_release
48
+ remotes.each do |remote|
49
+ releaser.rollback_release remote
50
+ end
51
+ end
52
+
53
+ def prune_releases
54
+ remotes.each do |remote|
55
+ releaser.prune_releases remote
56
+ end
57
+ end
58
+
59
+ def list_releases
60
+ remotes.each do |remote|
61
+ releases = releaser.list_releases(remote).map { |rel| rel[:release] }
62
+ Log.info :"#{remote.config.hostname}", releases
63
+ end
64
+ end
65
+
66
+ private
67
+
68
+ def releaser
69
+ Releaser::Revisions.new
70
+ end
71
+
72
+ end
73
+
74
+ end
75
+ end
76
+ end