statistrano 1.2.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 (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