dusty-basic_deploy 0.0.1

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 (3) hide show
  1. data/README.txt +48 -0
  2. data/lib/basic_deploy.rb +274 -0
  3. metadata +54 -0
data/README.txt ADDED
@@ -0,0 +1,48 @@
1
+ # Dusty's basic capistrano deploy script
2
+
3
+ ## Installation
4
+
5
+ # gem sources -a http://gems.github.com/
6
+ # gem install dusty-sinatra_deploy
7
+
8
+ ## Usage
9
+
10
+ Open your application's `Capfile` and make it look like this, the last three lines are the magic. also you can safely remove line two if you won't be loading additional plugin files. (this is a railsism):
11
+
12
+ load 'deploy' if respond_to?(:namespace) # cap2 differentiator
13
+ # Dir['vendor/plugins/*/recipes/*.rb'].each { |plugin| load(plugin) }
14
+
15
+ require 'rubygems'
16
+ require 'railsless-deploy'
17
+ load 'config/deploy'
18
+
19
+ You should then be able to proceed as you would usually, you may want to familiarise yourself with the truncated list of tasks, you can get a full list with:
20
+
21
+ $ cap -T
22
+
23
+ ## What's in the box?
24
+
25
+ If you want to try before you buy, here's the list of tasks included with this version of the deploy recipe:
26
+
27
+ cap deploy # Deploys your project.
28
+ cap deploy:check # Test deployment dependencies.
29
+ cap deploy:cleanup # Clean up old releases.
30
+ cap deploy:cold # Deploys and starts a `cold' application.
31
+ cap deploy:pending # Displays the commits since your last deploy.
32
+ cap deploy:pending:diff # Displays the `diff' since your last deploy.
33
+ cap deploy:rollback # Rolls back to a previous version and restarts.
34
+ cap deploy:rollback:code # Rolls back to the previously deployed version.
35
+ cap deploy:setup # Prepares one or more servers for deployment.
36
+ cap deploy:symlink # Updates the symlink to the most recently deployed ...
37
+ cap deploy:update # Copies your project and updates the symlink.
38
+ cap deploy:update_code # Copies your project to the remote servers.
39
+ cap deploy:upload # Copy files to the currently deployed version.
40
+ cap invoke # Invoke a single command on the remote servers.
41
+ cap shell # Begin an interactive Capistrano session.
42
+
43
+
44
+ ## Bugs & Feedback
45
+
46
+ Via my Github profile please:
47
+
48
+ http://github.com/leehambley
@@ -0,0 +1,274 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+
3
+ require 'capistrano/recipes/deploy/scm'
4
+ require 'capistrano/recipes/deploy/strategy'
5
+
6
+ def _cset(name, *args, &block)
7
+ unless exists?(name)
8
+ set(name, *args, &block)
9
+ end
10
+ end
11
+
12
+ # =========================================================================
13
+ # These variables MUST be set in the client capfiles. If they are not set,
14
+ # the deploy will fail with an error.
15
+ # =========================================================================
16
+
17
+ _cset(:application) { abort "Please specify the name of your application, set :application, 'foo'" }
18
+ _cset(:repository) { abort "Please specify the repository that houses your application's code, set :repository, 'foo'" }
19
+
20
+ # =========================================================================
21
+ # These variables may be set in the client capfile if their default values
22
+ # are not sufficient.
23
+ # =========================================================================
24
+
25
+ _cset :scm, :subversion
26
+ _cset :deploy_via, :checkout
27
+
28
+ _cset(:deploy_to) { "/var/www/apps/#{application}" }
29
+ _cset(:revision) { source.head }
30
+
31
+ # =========================================================================
32
+ # These variables should NOT be changed unless you are very confident in
33
+ # what you are doing. Make sure you understand all the implications of your
34
+ # changes if you do decide to muck with these!
35
+ # =========================================================================
36
+
37
+ _cset(:source) { Capistrano::Deploy::SCM.new(scm, self) }
38
+ _cset(:real_revision) { source.local.query_revision(revision) { |cmd| with_env("LC_ALL", "C") { run_locally(cmd) } } }
39
+
40
+ _cset(:strategy) { Capistrano::Deploy::Strategy.new(deploy_via, self) }
41
+
42
+ _cset(:release_name) { set :deploy_timestamped, true; Time.now.utc.strftime("%Y%m%d%H%M%S") }
43
+
44
+ _cset :version_dir, "releases"
45
+ _cset :shared_dir, "shared"
46
+ _cset :shared_children, %w(log tmp gems)
47
+ _cset :current_dir, "current"
48
+
49
+ _cset(:releases_path) { File.join(deploy_to, version_dir) }
50
+ _cset(:shared_path) { File.join(deploy_to, shared_dir) }
51
+ _cset(:current_path) { File.join(deploy_to, current_dir) }
52
+ _cset(:release_path) { File.join(releases_path, release_name) }
53
+
54
+ _cset(:releases) { capture("ls -xt #{releases_path}").split.reverse }
55
+ _cset(:current_release) { File.join(releases_path, releases.last) }
56
+ _cset(:previous_release) { releases.length > 1 ? File.join(releases_path, releases[-2]) : nil }
57
+
58
+ _cset(:current_revision) { capture("cat #{current_path}/REVISION").chomp }
59
+ _cset(:latest_revision) { capture("cat #{current_release}/REVISION").chomp }
60
+ _cset(:previous_revision) { capture("cat #{previous_release}/REVISION").chomp }
61
+
62
+ _cset(:run_method) { fetch(:use_sudo, true) ? :sudo : :run }
63
+
64
+ # some tasks, like symlink, need to always point at the latest release, but
65
+ # they can also (occassionally) be called standalone. In the standalone case,
66
+ # the timestamped release_path will be inaccurate, since the directory won't
67
+ # actually exist. This variable lets tasks like symlink work either in the
68
+ # standalone case, or during deployment.
69
+ _cset(:latest_release) { exists?(:deploy_timestamped) ? release_path : current_release }
70
+
71
+ # =========================================================================
72
+ # These are helper methods that will be available to your recipes.
73
+ # =========================================================================
74
+
75
+ # Temporarily sets an environment variable, yields to a block, and restores
76
+ # the value when it is done.
77
+ def with_env(name, value)
78
+ saved, ENV[name] = ENV[name], value
79
+ yield
80
+ ensure
81
+ ENV[name] = saved
82
+ end
83
+
84
+ # logs the command then executes it locally.
85
+ # returns the command output as a string
86
+ def run_locally(cmd)
87
+ logger.trace "executing locally: #{cmd.inspect}" if logger
88
+ `#{cmd}`
89
+ end
90
+
91
+ # If a command is given, this will try to execute the given command, as
92
+ # described below. Otherwise, it will return a string for use in embedding in
93
+ # another command, for executing that command as described below.
94
+ #
95
+ # If :run_method is :sudo (or :use_sudo is true), this executes the given command
96
+ # via +sudo+. Otherwise is uses +run+. If :as is given as a key, it will be
97
+ # passed as the user to sudo as, if using sudo. If the :as key is not given,
98
+ # it will default to whatever the value of the :admin_runner variable is,
99
+ # which (by default) is unset.
100
+ #
101
+ # THUS, if you want to try to run something via sudo, and what to use the
102
+ # root user, you'd just to try_sudo('something'). If you wanted to try_sudo as
103
+ # someone else, you'd just do try_sudo('something', :as => "bob"). If you
104
+ # always wanted sudo to run as a particular user, you could do
105
+ # set(:admin_runner, "bob").
106
+ def try_sudo(*args)
107
+ options = args.last.is_a?(Hash) ? args.pop : {}
108
+ command = args.shift
109
+ raise ArgumentError, "too many arguments" if args.any?
110
+
111
+ as = options.fetch(:as, fetch(:admin_runner, nil))
112
+ via = fetch(:run_method, :sudo)
113
+ if command
114
+ invoke_command(command, :via => via, :as => as)
115
+ elsif via == :sudo
116
+ sudo(:as => as)
117
+ else
118
+ ""
119
+ end
120
+ end
121
+
122
+ # Same as sudo, but tries sudo with :as set to the value of the :runner
123
+ # variable (which defaults to "app").
124
+ def try_runner(*args)
125
+ options = args.last.is_a?(Hash) ? args.pop : {}
126
+ args << options.merge(:as => fetch(:runner, "app"))
127
+ try_sudo(*args)
128
+ end
129
+
130
+ # =========================================================================
131
+ # These are the tasks that are available to help with deploying web apps,
132
+ # and specifically, Rails applications. You can have cap give you a summary
133
+ # of them with `cap -T'.
134
+ # =========================================================================
135
+
136
+ namespace :deploy do
137
+ desc 'Deploy your project'
138
+ task :default do
139
+ update
140
+ end
141
+
142
+ desc 'Setup the project for deployment'
143
+ task :setup, :except => { :no_release => true } do
144
+ dirs = [deploy_to, releases_path, shared_path]
145
+ dirs += shared_children.map { |d| File.join(shared_path, d) }
146
+ run "#{try_sudo} mkdir -p #{dirs.join(' ')} && #{try_sudo} chmod g+w #{dirs.join(' ')}"
147
+ end
148
+
149
+ desc 'Update the code of your project and the symlinks'
150
+ task :update do
151
+ transaction do
152
+ update_code
153
+ symlink
154
+ end
155
+ end
156
+
157
+ desc 'Update the code of your project'
158
+ task :update_code, :except => { :no_release => true } do
159
+ on_rollback { run "rm -rf #{release_path}; true" }
160
+ strategy.deploy!
161
+ finalize_update
162
+ end
163
+
164
+ desc 'Update permissions and symlinks in project'
165
+ task :finalize_update, :except => { :no_release => true } do
166
+ run "chmod -R g+w #{latest_release}" if fetch(:group_writable, true)
167
+ shared_children.each do |child|
168
+ run "ln -nfs #{shared_path}/#{child} #{latest_release}"
169
+ end
170
+ end
171
+
172
+ desc 'Updates the symlink of current to point to the newest release'
173
+ task :symlink, :except => { :no_release => true } do
174
+ on_rollback do
175
+ if previous_release
176
+ run "rm -f #{current_path}; ln -s #{previous_release} #{current_path}; true"
177
+ else
178
+ logger.important "no previous release to rollback to, rollback of symlink skipped"
179
+ end
180
+ end
181
+
182
+ run "rm -f #{current_path} && ln -s #{latest_release} #{current_path}"
183
+ end
184
+
185
+ desc <<-DESC
186
+ Copy files to the currently deployed version.
187
+ $ cap deploy:upload FILES=templates,controller.rb
188
+ $ cap deploy:upload FILES='config/apache/*.conf'
189
+ DESC
190
+ task :upload, :except => { :no_release => true } do
191
+ files = (ENV["FILES"] || "").split(",").map { |f| Dir[f.strip] }.flatten
192
+ abort "Please specify at least one file or directory to update (via the FILES environment variable)" if files.empty?
193
+ files.each { |file| top.upload(file, File.join(current_path, file)) }
194
+ end
195
+
196
+ namespace :rollback do
197
+ desc <<-DESC
198
+ [internal] Points the current symlink at the previous revision.
199
+ This is called by the rollback sequence, and should rarely (if ever) need to
200
+ be called directly.
201
+ DESC
202
+ task :revision, :except => { :no_release => true } do
203
+ if previous_release
204
+ run "rm #{current_path}; ln -s #{previous_release} #{current_path}"
205
+ else
206
+ abort "could not rollback the code because there is no prior release"
207
+ end
208
+ end
209
+
210
+ desc <<-DESC
211
+ [internal] Removes the most recently deployed release.
212
+ This is called by the rollback sequence, and should rarely (if ever) need to
213
+ be called directly.
214
+ DESC
215
+ task :cleanup, :except => { :no_release => true } do
216
+ run "if [ `readlink #{current_path}` != #{current_release} ]; then rm -rf #{current_release}; fi"
217
+ end
218
+
219
+ desc <<-DESC
220
+ Rolls back to the previously deployed version. The `current' symlink will
221
+ be updated to point at the previously deployed version, and then the
222
+ current release will be removed from the servers.
223
+ DESC
224
+ task :code, :except => { :no_release => true } do
225
+ revision
226
+ cleanup
227
+ end
228
+
229
+ desc <<-DESC
230
+ Rolls back to a previous version and restarts. This is handy if you ever
231
+ discover that you've deployed a lemon; `cap rollback' and you're right
232
+ back where you were, on the previously deployed version.
233
+ DESC
234
+ task :default do
235
+ revision
236
+ cleanup
237
+ end
238
+ end
239
+
240
+ desc <<-DESC
241
+ Clean up old releases. By default, the last 5 releases are kept on each
242
+ server (though you can change this with the keep_releases variable). All
243
+ other deployed revisions are removed from the servers.
244
+ DESC
245
+ task :cleanup, :except => { :no_release => true } do
246
+ count = fetch(:keep_releases, 5).to_i
247
+ if count >= releases.length
248
+ logger.important "no old releases to clean up"
249
+ else
250
+ logger.info "keeping #{count} of #{releases.length} deployed releases"
251
+
252
+ directories = (releases - releases.last(count)).map { |release|
253
+ File.join(releases_path, release) }.join(" ")
254
+
255
+ try_sudo "rm -rf #{directories}"
256
+ end
257
+ end
258
+
259
+ namespace :pending do
260
+ desc 'Displays the diff since your last deploy'
261
+ task :diff, :except => { :no_release => true } do
262
+ system(source.local.diff(current_revision))
263
+ end
264
+
265
+ desc 'Displays the commits since your last deploy'
266
+ task :default, :except => { :no_release => true } do
267
+ from = source.next_revision(current_revision)
268
+ system(source.local.log(from))
269
+ end
270
+ end
271
+
272
+ end
273
+
274
+ end # Capistrano::Configuration.instance(:must_exist).load do
metadata ADDED
@@ -0,0 +1,54 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dusty-basic_deploy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Dusty Doris
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-05-16 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: github@dusty.name
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - README.txt
26
+ - lib/basic_deploy.rb
27
+ has_rdoc: false
28
+ homepage: http://code.dusty.name
29
+ post_install_message:
30
+ rdoc_options: []
31
+
32
+ require_paths:
33
+ - lib
34
+ required_ruby_version: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: "0"
39
+ version:
40
+ required_rubygems_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: "0"
45
+ version:
46
+ requirements: []
47
+
48
+ rubyforge_project: none
49
+ rubygems_version: 1.2.0
50
+ signing_key:
51
+ specification_version: 2
52
+ summary: Basic deploy script for capistrano
53
+ test_files: []
54
+