capistrano-demonz 0.0.5

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.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in capistrano-demonz.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Chinthaka Godawita
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Capistrano::Demonz
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'capistrano-demonz'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install capistrano-demonz
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'demonz/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "capistrano-demonz"
8
+ gem.version = Capistrano::Demonz::VERSION
9
+ gem.authors = ["Chinthaka Godawita"]
10
+ gem.email = ["chinthaka.godawita@demonzmedia.com"]
11
+ gem.description = "Demonz Media recipes for Capistrano"
12
+ gem.summary = "Useful task libraries for Demonz Media recipes for Capistrano"
13
+ gem.homepage = "https://github.com/demonz/capistrano-demonz"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency "railsless-deploy", ">= 1.0.2"
21
+ gem.add_dependency "capistrano", ">= 2.13.5"
22
+ end
@@ -0,0 +1,7 @@
1
+ require "capistrano-demonz/version"
2
+
3
+ module Capistrano
4
+ module Demonz
5
+ # Your code goes here...
6
+ end
7
+ end
@@ -0,0 +1,541 @@
1
+ # Capistrano2 differentiator
2
+ load 'deploy' if respond_to?(:namespace)
3
+ Dir['vendor/plugins/*/recipes/*.rb'].each { |plugin| load(plugin) }
4
+
5
+ # Required gems/libraries
6
+ require 'rubygems'
7
+ require 'demonz/common'
8
+ require 'capistrano/ext/multistage'
9
+
10
+ # Bootstrap Capistrano instance
11
+ configuration = Capistrano::Configuration.respond_to?(:instance) ?
12
+ Capistrano::Configuration.instance(:must_exist) :
13
+ Capistrano.configuration(:must_exist)
14
+
15
+ configuration.load do
16
+
17
+ # Set default stages
18
+ set :stages, %w(staging production)
19
+ set :default_stage, "staging"
20
+
21
+ # Set shared path to be inside app directory
22
+ set :shared_path, File.join(deploy_to, 'shared')
23
+
24
+ # --------------------------------------------
25
+ # Task chains
26
+ # --------------------------------------------
27
+ after "multistage:ensure", "demonz:set_release_history"
28
+ before "deploy", "demonz:set_release_info"
29
+ before "deploy:finalize_update", "demonz:add_release_tracking"
30
+ after "deploy:setup", "deploy:setup_shared"
31
+ after "deploy:setup_shared", "deploy:setup_backup"
32
+ after "deploy:finalize_update", "demonz:htaccess"
33
+ after "deploy", "deploy:cleanup"
34
+ after "deploy:cleanup", "demonz:cleanup_release_tracking"
35
+ before "deploy:rollback", "demonz:set_rollback_release"
36
+ after "deploy:rollback", "demonz:update_release_tracking_for_rollback"
37
+
38
+ # --------------------------------------------
39
+ # Default variables
40
+ # --------------------------------------------
41
+ # SSH
42
+ set :user, proc{text_prompt("SSH username: ")}
43
+ set :group, :user
44
+ set :password, proc{Capistrano::CLI.password_prompt("SSH password for '#{user}':")}
45
+
46
+ # Database
47
+ # set :dbuser, proc{text_prompt("Database username: ")}
48
+ # set :dbpass, proc{Capistrano::CLI.password_prompt("Database password for '#{dbuser}':")}
49
+ # set :dbname, proc{text_prompt("Database name: ")}
50
+ _cset :mysqldump, "mysqldump"
51
+ _cset :dump_options, "--single-transaction --create-options --quick"
52
+
53
+ # Source Control
54
+ set :group_writable, true
55
+ set :use_sudo, false
56
+ set :scm, :git
57
+ set :scm_verbose, true
58
+ set :scm_username, proc{text_prompt("Git username: ")}
59
+ set :scm_password, proc{Capistrano::CLI.password_prompt("Git password for '#{scm_username}': ")}
60
+ set :deploy_via, :remote_cache
61
+ set :copy_strategy, :checkout
62
+ set :copy_compression, :bz2
63
+ set :copy_exclude, [".svn", ".DS_Store", "*.sample", "LICENSE*", "Capfile",
64
+ "RELEASE*", "*.rb", "*.sql", "nbproject", "_template", "*.sublime*"]
65
+
66
+ # Backups Path
67
+ _cset(:backups_path) { File.join(deploy_to, "backups") }
68
+ _cset(:tmp_backups_path) { File.join("#{backups_path}", "tmp") }
69
+ _cset(:backups) { capture("ls -x #{backups_path}", :except => { :no_release => true }).split.sort }
70
+
71
+ # Define which files or directories you want to exclude from being backed up
72
+ _cset(:backup_exclude) { [] }
73
+ set :exclude_string, ''
74
+
75
+ # show password requests on windows
76
+ # (http://weblog.jamisbuck.org/2007/10/14/capistrano-2-1)
77
+ default_run_options[:pty] = true
78
+
79
+ # Release tracking
80
+ set :release_file, File.join(shared_path, "RELEASES")
81
+
82
+ # SASS compilation support (via compass)
83
+ set :uses_sass, false
84
+
85
+ # Add a dependency on compass and :themes if required
86
+ if uses_sass
87
+ depend :remote, :gem, "compass", ">=0.12"
88
+ _cset(:themes) { abort "Please specify themes on this site, set :themes, ['theme1', 'theme2']" }
89
+ end
90
+
91
+ # We need PHP and gzip
92
+ depend :remote, :command, "php"
93
+ depend :remote, :command, "gzip"
94
+
95
+ # --------------------------------------------
96
+ # Overloaded tasks
97
+ # --------------------------------------------
98
+ namespace :deploy do
99
+ desc <<-DESC
100
+ Prepares one or more servers for deployment. Before you can use any \
101
+ of the Capistrano deployment tasks with your project, you will need to \
102
+ make sure all of your servers have been prepared with `cap deploy:setup'. When \
103
+ you add a new server to your cluster, you can easily run the setup task \
104
+ on just that server by specifying the HOSTS environment variable:
105
+
106
+ $ cap HOSTS=new.server.com deploy:setup
107
+
108
+ It is safe to run this task on servers that have already been set up; it \
109
+ will not destroy any deployed revisions or data.
110
+ DESC
111
+ task :setup, :except => { :no_release => true } do
112
+ dirs = [deploy_to, releases_path, shared_path]
113
+ dirs += shared_children.map { |d| File.join(shared_path, d.split('/').last) }
114
+ run "#{try_sudo} mkdir -p #{dirs.join(' ')}"
115
+ run "#{try_sudo} chmod 775 #{dirs.join(' ')}" if fetch(:group_writable, true)
116
+ run "#{try_sudo} touch #{release_file}"
117
+ run "#{try_sudo} chmod g+w #{release_file}" if fetch(:group_writable, true)
118
+ run "#{try_sudo} chown -R #{user}:#{group} #{deploy_to}"
119
+ end
120
+
121
+ desc "Setup backup directory for database and web files"
122
+ task :setup_backup, :except => { :no_release => true } do
123
+ run "#{try_sudo} mkdir -p #{backups_path} #{tmp_backups_path} && #{try_sudo} chmod 775 #{backups_path} && #{try_sudo} chmod 775 #{tmp_backups_path}"
124
+ end
125
+
126
+ desc <<-DESC
127
+ Clean up old releases. By default, the last 5 releases are kept on each \
128
+ server (though you can change this with the keep_releases variable). All \
129
+ other deployed revisions are removed from the servers. By default, this \
130
+ will use sudo to clean up the old releases, but if sudo is not available \
131
+ for your environment, set the :use_sudo variable to false instead. \
132
+
133
+ Overridden to set/reset file and directory permissions
134
+ DESC
135
+ task :cleanup, :except => { :no_release => true } do
136
+ count = fetch(:keep_releases, 5).to_i
137
+ local_releases = get_release_history(release_file).split.reverse
138
+ if count >= local_releases.length
139
+ logger.important "no old releases to clean up"
140
+ else
141
+ logger.info "keeping #{count} of #{local_releases.length} deployed releases"
142
+ set :cleanup_releases, (local_releases - local_releases.last(count))
143
+ directories = cleanup_releases.map { |release|
144
+ File.join(releases_path, release) }.join(" ")
145
+
146
+ directories.split(" ").each do |dir|
147
+ set_perms_dirs(dir)
148
+ set_perms_files(dir)
149
+ end
150
+
151
+ try_sudo "rm -rf #{directories}"
152
+ end
153
+ end
154
+
155
+ desc "Show deployment release history"
156
+ task :history do
157
+ logger.important "Previous deployments (in ascending order)"
158
+ history = get_release_history(release_file)
159
+
160
+ if history.empty?
161
+ logger.info "No previous deployments found"
162
+ else
163
+ logger.info history
164
+ end
165
+ end
166
+ end
167
+
168
+ # --------------------------------------------
169
+ # Demonz tasks
170
+ # --------------------------------------------
171
+ namespace :demonz do
172
+ desc "[internal] Set release history"
173
+ task :set_release_history, :roles => :web, :except => { :no_release => true } do
174
+ set :releases, get_release_history(release_file).split
175
+ end
176
+
177
+ desc "Set standard permissions for Demonz servers"
178
+ task :fixperms, :roles => :web, :except => { :no_release => true } do
179
+ # chmod the files and directories.
180
+ set_perms_dirs("#{latest_release}")
181
+ set_perms_files("#{latest_release}")
182
+ end
183
+
184
+ desc "Test: Task used to verify Capistrano is working. Prints operating system name."
185
+ task :uname do
186
+ run "uname -a"
187
+ end
188
+
189
+ desc "Test: Task used to verify Capistrano is working. Prints environment of Capistrano user."
190
+ task :getpath do
191
+ run "echo $PATH"
192
+ end
193
+
194
+ desc 'Copy distribution htaccess file'
195
+ task :htaccess, :roles => :web do
196
+ case true
197
+ when remote_file_exists?("#{latest_release}/htaccess.#{stage}.dist")
198
+ run "#{try_sudo} mv #{latest_release}/htaccess.#{stage}.dist #{latest_release}/.htaccess"
199
+ when remote_file_exists?("#{latest_release}/htaccess.#{stage}")
200
+ run "#{try_sudo} mv #{latest_release}/htaccess.#{stage} #{latest_release}/.htaccess"
201
+ when remote_file_exists?("#{latest_release}/htaccess.dist")
202
+ run "#{try_sudo} mv #{latest_release}/htaccess.dist #{latest_release}/.htaccess"
203
+ else
204
+ logger.important "Failed to move the .htaccess file in #{latest_release} because an unknown pattern was used"
205
+ end
206
+ end
207
+
208
+ # Modified from https://gist.github.com/2016396
209
+ desc "Push local changes to Git repository"
210
+ task :push do
211
+ # Check we are on the right branch, so we can't forget to merge before deploying
212
+ branch = %x(git branch --no-color 2>/dev/null | sed -e '/^[^*]/d' -e 's/* \\(.*\\)/\\1/').chomp
213
+ if branch != "#{branch}" && !ENV["IGNORE_BRANCH"]
214
+ raise Capistrano::Error, "Not on #{branch} branch (set IGNORE_BRANCH=1 to ignore)"
215
+ end
216
+
217
+ # Push the changes
218
+ if ! system "git push --tags #{fetch(:repository)} #{branch}"
219
+ raise Capistrano::Error, "Failed to push changes to #{fetch(:repository)}"
220
+ end
221
+ end
222
+
223
+ desc "[internal] Set release info (such as release name and git tag)"
224
+ task :set_release_info, :roles => :web, :except => { :no_release => true } do
225
+ # Get all Git tags from local repository
226
+ all_tags = %x[git for-each-ref --sort='*authordate' --format='%(refname:short)' refs/tags].split
227
+
228
+ # Error out if not tags
229
+ # if all_tags.empty?
230
+ # raise Capistrano::Error, "No Git tags found, please define some before attempting deployment"
231
+ # end
232
+
233
+ # We're not using pure timestamps to track deployment anymore
234
+ set :deploy_timestamped, false
235
+
236
+ if variables.include?(:tag) && !all_tags.empty? && all_tags.include?(tag)
237
+ logger.info "deploying using Git tag '#{tag}'"
238
+
239
+ # Set revision to the commit that :tag points to
240
+ set :revision, run_locally("git rev-list #{tag} | head -n 1")
241
+
242
+ # Slashes are bad in directory names
243
+ clean_tag = tag.gsub("/", "-")
244
+ else
245
+ logger.important "no valid Git tag specified, continuing with HEAD instead"
246
+
247
+ # Get tag from user
248
+ tag = text_prompt("Please specify a tag name for this release (this will be created): ")
249
+ logger.info "setting release tag to #{tag}"
250
+
251
+ # Slashes are bad in directory names
252
+ clean_tag = tag.gsub("/", "-")
253
+
254
+ # Try to add tag to git
255
+ if ! system "git tag #{release_name}"
256
+ raise Capistrano::Error, "Failed to Git tag: #{release_name}"
257
+ end
258
+ end
259
+
260
+ # If the release directory already exists, append timestamp
261
+ if remote_file_exists?(File.join(releases_path, clean_tag, 'REVISION'))
262
+ clean_tag += '-' + Time.now.utc.strftime("%Y%m%d%H%M%S")
263
+ logger.important "previous deployment with this tag found, setting current release name to #{clean_tag}"
264
+ end
265
+
266
+ set :release_name, clean_tag
267
+ set :latest_release, release_path
268
+ end
269
+
270
+ desc "[internal] Keep track of the current release"
271
+ task :add_release_tracking, :roles => :web, :except => { :no_release => true } do
272
+ on_rollback { remove_release_from_history(release_name, release_file) }
273
+ run "#{try_sudo} echo #{release_name} >> #{release_file}"
274
+ end
275
+
276
+ desc "[internal] Cleanup release tracking"
277
+ task :cleanup_release_tracking, :roles => :web, :except => { :no_release => true } do
278
+ if variables.include?(:cleanup_releases)
279
+ cleanup_releases = fetch(:cleanup_releases, nil)
280
+
281
+ if !cleanup_releases.nil?
282
+ files_backups = cleanup_releases.map { |release|
283
+ remove_release_from_history(release, release_file) }
284
+ end
285
+ end
286
+ end
287
+
288
+ desc "[internal] Set last release name for rollback"
289
+ task :set_rollback_release, :except => { :no_release => true } do
290
+ set :release_name, releases.last
291
+ end
292
+
293
+ desc "[internal] Remove rollback release from release tracking"
294
+ task :update_release_tracking_for_rollback, :except => { :no_release => true } do
295
+ remove_release_from_history(release_name, release_file)
296
+ end
297
+ end
298
+
299
+ # --------------------------------------------
300
+ # PHP tasks
301
+ # --------------------------------------------
302
+ namespace :php do
303
+ namespace :apc do
304
+ desc "Disable the APC administrative panel"
305
+ task :disable, :roles => :web, :except => { :no_release => true } do
306
+ run "#{try_sudo} rm #{current_path}/apc.php"
307
+ end
308
+
309
+ desc "Enable the APC administrative panel"
310
+ task :enable, :roles => :web, :except => { :no_release => true } do
311
+ run "#{try_sudo} ln -s /usr/local/lib/php/apc.php #{current_path}/apc.php"
312
+ end
313
+ end
314
+ end
315
+
316
+ # --------------------------------------------
317
+ # Remote/Local database migration tasks
318
+ # --------------------------------------------
319
+ namespace :db do
320
+ desc "Migrate remote application database to local server"
321
+ task :to_local, :roles => :db, :except => { :no_release => true } do
322
+ remote_export
323
+ remote_download
324
+ local_import
325
+ end
326
+
327
+ desc "Migrate local application database to remote server"
328
+ task :to_remote, :roles => :db, :except => { :no_release => true } do
329
+ local_export
330
+ local_upload
331
+ remote_import
332
+ end
333
+
334
+ desc "Handles importing a MySQL database dump file. Uncompresses the file, does regex replacements, and imports."
335
+ task :local_import, :roles => :db do
336
+ # check for compressed file and decompress
337
+ if local_file_exists?("#{db_remote_name}.sql.gz")
338
+ system "gunzip -f #{db_remote_name}.sql.gz"
339
+ end
340
+
341
+ if local_file_exists?("#{db_remote_name}.sql")
342
+ # import into database
343
+ system "mysql -h#{db_local_host} -u#{db_local_user} -p#{db_local_pass} #{db_local_name} < #{db_remote_name}.sql"
344
+ # remove used file
345
+ run "#{try_sudo} rm -f #{deploy_to}/#{db_remote_name}.sql.gz"
346
+ system "#{try_sudo} rm -f #{db_remote_name}.sql"
347
+ end
348
+ end
349
+
350
+ task :local_export do
351
+ mysqldump = fetch(:mysqldump, "mysqldump")
352
+ dump_options = fetch(:dump_options, "--single-transaction --create-options --quick")
353
+
354
+ system "#{try_sudo} #{mysqldump} #{dump_options} --opt -h#{db_local_host} -u#{db_local_user} -p#{db_local_pass} #{db_local_name} | gzip -c --best > #{db_local_name}.sql.gz"
355
+ end
356
+
357
+ desc "Upload locally created MySQL dumpfile to remote server via SCP"
358
+ task :local_upload, :roles => :db do
359
+ upload "#{db_local_name}.sql.gz", "#{deploy_to}/#{db_local_name}.sql.gz", :via => :scp
360
+ end
361
+
362
+ desc "Handles importing a MySQL database dump file. Uncompresses the file, does regex replacements, and imports."
363
+ task :remote_import, :roles => :db do
364
+ # check for compressed file and decompress
365
+ if remote_file_exists?("#{deploy_to}/#{db_local_name}.sql.gz")
366
+ run "gunzip -f #{deploy_to}/#{db_local_name}.sql.gz"
367
+ end
368
+
369
+ if remote_file_exists?("#{deploy_to}/#{db_local_name}.sql")
370
+ # import into database
371
+ run "mysql -h#{db_remote_host} -u#{db_remote_user} -p#{db_remote_pass} #{db_remote_name} < #{deploy_to}/#{db_local_name}.sql"
372
+ # remove used file
373
+ run "#{try_sudo} rm -f #{deploy_to}/#{db_local_name}.sql"
374
+ system "#{try_sudo} rm -rf #{db_local_name}.sql.gz"
375
+ end
376
+ end
377
+
378
+ desc "Create a compressed MySQL dumpfile of the remote database"
379
+ task :remote_export, :roles => :db do
380
+ mysqldump = fetch(:mysqldump, "mysqldump")
381
+ dump_options = fetch(:dump_options, "--single-transaction --create-options --quick")
382
+
383
+ run "#{try_sudo} #{mysqldump} #{dump_options} --opt -h#{db_remote_host} -u#{db_remote_user} -p#{db_remote_pass} #{db_remote_name} | gzip -c --best > #{deploy_to}/#{db_remote_name}.sql.gz"
384
+ end
385
+
386
+ desc "Download remotely created MySQL dumpfile to local machine via SCP"
387
+ task :remote_download, :roles => :db do
388
+ download "#{deploy_to}/#{db_remote_name}.sql.gz", "#{db_remote_name}.sql.gz", :via => :scp
389
+ end
390
+ end
391
+
392
+ # --------------------------------------------
393
+ # Backup tasks
394
+ # --------------------------------------------
395
+ namespace :backup do
396
+ desc "Perform a backup of web and database files"
397
+ task :default do
398
+ deploy.setup_backup
399
+ db
400
+ web
401
+ cleanup
402
+ end
403
+
404
+ desc <<-DESC
405
+ Requires the rsync package to be installed.
406
+
407
+ Performs a file-level backup of the application and any assets \
408
+ from the shared directory that have been symlinked into the \
409
+ applications root or sub-directories.
410
+
411
+ You can specify which files or directories to exclude from being \
412
+ backed up (i.e., log files, sessions, cache) by setting the \
413
+ :backup_exclude variable
414
+ set(:backup_exclude) { [ "var/", "tmp/", logs/debug.log ] }
415
+ DESC
416
+ task :web, :roles => :web do
417
+ if previous_release
418
+ logger.info "Backing up web files (user uploaded content and previous release)"
419
+
420
+ if !backup_exclude.nil? && !backup_exclude.empty?
421
+ logger.debug "processing backup exclusions..."
422
+ backup_exclude.each do |pattern|
423
+ exclude_string << "--exclude '#{pattern}' "
424
+ end
425
+ logger.debug "Exclude string = #{exclude_string}"
426
+ end
427
+
428
+ # Copy the previous release to the /tmp directory
429
+ logger.debug "Copying previous release to the #{tmp_backups_path}/#{release_name} directory"
430
+ run "rsync -avzrtpL #{exclude_string} #{current_path}/ #{tmp_backups_path}/#{release_name}/"
431
+
432
+ # --------------------------
433
+ # SET/RESET PERMISSIONS
434
+ # --------------------------
435
+ set_perms_dirs("#{tmp_backups_path}/#{release_name}", 755)
436
+ set_perms_files("#{tmp_backups_path}/#{release_name}", 644)
437
+
438
+ # create the tarball of the previous release
439
+ set :archive_name, "release_B4_#{release_name}.tar.gz"
440
+ logger.debug "Creating a Tarball of the previous release in #{backups_path}/#{archive_name}"
441
+ run "cd #{tmp_backups_path} && tar -cvpf - ./#{release_name}/ | gzip -c --best > #{backups_path}/#{archive_name}"
442
+
443
+ # remove the the temporary copy
444
+ logger.debug "Removing the tempory copy"
445
+ run "rm -rf #{tmp_backups_path}/#{release_name}"
446
+ else
447
+ logger.important "no previous release to backup; backup of files skipped"
448
+ end
449
+ end
450
+
451
+ desc "Perform a backup of database files"
452
+ task :db, :roles => :db do
453
+ if previous_release
454
+ mysqldump = fetch(:mysqldump, "mysqldump")
455
+ dump_options = fetch(:dump_options, "--single-transaction --create-options --quick")
456
+
457
+ logger.info "Backing up the database now and putting dump file in the previous release directory"
458
+ # define the filename (include the current_path so the dump file will be within the directory)
459
+ filename = "#{current_path}/#{dbname}_dump-#{Time.now.to_s.gsub(/ /, "_")}.sql.gz"
460
+ # dump the database for the proper environment
461
+ run "#{mysqldump} #{dump_options} -u #{dbuser} -p #{dbname} | gzip -c --best > #{filename}" do |ch, stream, out|
462
+ ch.send_data "#{dbpass}\n" if out =~ /^Enter password:/
463
+ end
464
+ else
465
+ logger.important "no previous release to backup to; backup of database skipped"
466
+ end
467
+ end
468
+
469
+ desc <<-DESC
470
+ Clean up old backups. By default, the last 10 backups are kept on each \
471
+ server (though you can change this with the keep_backups variable). All \
472
+ other backups are removed from the servers. By default, this \
473
+ will use sudo to clean up the old backups, but if sudo is not available \
474
+ for your environment, set the :use_sudo variable to false instead.
475
+ DESC
476
+ task :cleanup, :except => { :no_release => true } do
477
+ count = fetch(:keep_backups, 10).to_i
478
+ if count >= backups.length
479
+ logger.important "no old backups to clean up"
480
+ else
481
+ logger.info "keeping #{count} of #{backups.length} backups"
482
+
483
+ archives = (backups - backups.last(count)).map { |backup|
484
+ File.join(backups_path, backup) }.join(" ")
485
+
486
+ # fix permissions on the the files and directories before removing them
487
+ archives.split(" ").each do |backup|
488
+ set_perms_dirs("#{backup}", 755)
489
+ set_perms_files("#{backup}", 644)
490
+ end
491
+
492
+ try_sudo "rm -rf #{archives}"
493
+ end
494
+ end
495
+ end
496
+
497
+ # --------------------------------------------
498
+ # Remote File/Directory test tasks
499
+ # --------------------------------------------
500
+ namespace :remote do
501
+ namespace :file do
502
+ desc "Test: Task to test existence of missing file"
503
+ task :missing do
504
+ if remote_file_exists?('/dev/mull')
505
+ logger.info "FAIL - Why does the '/dev/mull' path exist???"
506
+ else
507
+ logger.info "GOOD - Verified the '/dev/mull' path does not exist!"
508
+ end
509
+ end
510
+
511
+ desc "Test: Task used to test existence of a present file"
512
+ task :exists do
513
+ if remote_file_exists?('/dev/null')
514
+ logger.info "GOOD - Verified the '/dev/null' path exists!"
515
+ else
516
+ logger.info "FAIL - WHAT happened to the '/dev/null' path???"
517
+ end
518
+ end
519
+ end
520
+
521
+ namespace :dir do
522
+ desc "Test: Task to test existence of missing dir"
523
+ task :missing do
524
+ if remote_dir_exists?('/etc/fake_dir')
525
+ logger.info "FAIL - Why does the '/etc/fake_dir' dir exist???"
526
+ else
527
+ logger.info "GOOD - Verified the '/etc/fake_dir' dir does not exist!"
528
+ end
529
+ end
530
+
531
+ desc "Test: Task used to test existence of an existing directory"
532
+ task :exists do
533
+ if remote_dir_exists?('/etc')
534
+ logger.info "GOOD - Verified the '/etc' dir exists!"
535
+ else
536
+ logger.info "FAIL - WHAT happened to the '/etc' dir???"
537
+ end
538
+ end
539
+ end
540
+ end
541
+ end
@@ -0,0 +1,128 @@
1
+ # Prompts user entry
2
+ # Params:
3
+ # +prompt+
4
+ def text_prompt(prompt="Value: ")
5
+ Capistrano::CLI.ui.ask(prompt) { |q| q.echo = true }
6
+ end
7
+
8
+ # Check if a local file exists
9
+ def local_file_exists?(full_path)
10
+ File.exists?(full_path)
11
+ end
12
+
13
+ # Check if a local directory exists
14
+ def local_dir_exists?(full_path)
15
+ File.directory?(full_path)
16
+ end
17
+
18
+ # From http://stackoverflow.com/a/1662001/356237
19
+ # Needs full remote path
20
+ def remote_file_exists?(full_path)
21
+ 'true' == capture("if [ -e #{full_path} ]; then echo 'true'; fi").strip
22
+ end
23
+
24
+ # Sames as above but with directories
25
+ def remote_dir_exists?(dir_path)
26
+ 'true' == capture("if [[ -d #{dir_path} ]]; then echo 'true'; fi").strip
27
+ end
28
+
29
+ # Recursively set file permissions in a directory
30
+ def set_perms_files(dir_path, perm = 644)
31
+ try_sudo "find #{dir_path} -type f -exec chmod #{perm} {} \\;"
32
+ end
33
+ def create_database
34
+ create_sql = <<-SQL
35
+ CREATE DATABASE #{db_name};
36
+ SQL
37
+
38
+ run "mysql --user=#{db_admin_user} --password=#{db_admin_password} --execute=\"#{create_sql}\""
39
+ end
40
+ # Recursively set directory permissions in a directory
41
+ def set_perms_dirs(dir_path, perm = 755)
42
+ try_sudo "find #{dir_path} -type d -exec chmod #{perm} {} \\;"
43
+ end
44
+
45
+ # Get release history from server as string
46
+ def get_release_history(release_file)
47
+ release_history = capture("cat #{release_file}").strip
48
+ release_history
49
+ end
50
+
51
+ # Remove a particular release from history
52
+ def remove_release_from_history(release, release_file)
53
+ release_history = capture("cat #{release_file}").split
54
+
55
+ # Remove release if it exists
56
+ release_history.delete_at release_history.index(release) unless release_history.index(release).nil?
57
+
58
+ # Save
59
+ release_history.join("\n")
60
+ try_sudo "echo #{release_history} > #{release_file}"
61
+ end
62
+
63
+ # Get the database name given an application and release name
64
+ def get_db_name(application, release)
65
+ db_name = "#{application}__#{release_name}"
66
+ # Remove characters that may cause MySQL issues
67
+ db_name.downcase.gsub(/([\.\-\/])/, '_')
68
+ end
69
+
70
+ # Get the regex pattern to extract details from the mysql connection string
71
+ def db_string_regex(type)
72
+ "--#{type}='?([a-zA-Z0-9!@\#$%^&*-=+]+)'?\s"
73
+ end
74
+
75
+ # Check if a MySQL database exists
76
+ # Modified from http://www.grahambrooks.com/blog/create-mysql-database-with-capistrano/
77
+ def database_exists?(connection_string, db_name)
78
+ exists = false
79
+
80
+ run "#{connection_string} --execute=\"show databases;\"" do |channel, stream, data|
81
+ exists = exists || data.include?(db_name)
82
+ end
83
+
84
+ exists
85
+ end
86
+
87
+ # Create a MySQL database
88
+ # From http://www.grahambrooks.com/blog/create-mysql-database-with-capistrano/
89
+ def create_database(connection_string, db_name)
90
+ create_sql = <<-SQL
91
+ CREATE DATABASE #{db_name};
92
+ SQL
93
+
94
+ run "#{connection_string} --execute=\"#{create_sql}\""
95
+ end
96
+
97
+ # Delete a MySQL database
98
+ def delete_database(connection_string, db_name)
99
+ drop_sql = <<-SQL
100
+ DROP DATABASE #{db_name};
101
+ SQL
102
+
103
+ run "#{connection_string} --execute=\"#{drop_sql}\""
104
+ end
105
+
106
+ # Set permissions for a MySQL database
107
+ # From http://www.grahambrooks.com/blog/create-mysql-database-with-capistrano/
108
+ def setup_database_permissions(connection_string, db_name)
109
+ # We tack on a space at the end to help regex matches
110
+ connection_string += " "
111
+
112
+ db_admin_user = connection_string.match db_string_regex('user')
113
+ db_admin_user = db_admin_user[1]
114
+
115
+ db_admin_password = connection_string.match db_string_regex('password')
116
+ db_admin_password = db_admin_password[1]
117
+
118
+ grant_sql = <<-SQL
119
+ GRANT ALL PRIVILEGES ON #{db_name}.* TO #{db_admin_user}@localhost IDENTIFIED BY '#{db_admin_password}';
120
+ SQL
121
+
122
+ run "#{connection_string} --execute=\"#{grant_sql}\""
123
+ end
124
+
125
+ # Updates the Drupal settings file with the new database name
126
+ def update_db_in_settings_file(settings_file, db_name)
127
+ run "sed -ri \"/^[ \\t]*(#|\\*|\\/)/! s/'database' => ''/'database' => '#{db_name}'/1\" #{settings_file}"
128
+ end
@@ -0,0 +1,312 @@
1
+ # Require our base library.
2
+ require 'demonz/base'
3
+ require 'railsless-deploy'
4
+
5
+ configuration = Capistrano::Configuration.respond_to?(:instance) ?
6
+ Capistrano::Configuration.instance(:must_exist) :
7
+ Capistrano.configuration(:must_exist)
8
+
9
+ configuration.load do
10
+
11
+ # --------------------------------------------
12
+ # Setting defaults
13
+ # --------------------------------------------
14
+ set :drush_bin, "drush"
15
+ _cset :dump_options, "" # blank options b/c of MYISAM engine (unless anyone knows options that should be included)
16
+
17
+ # Boost module support (Drupal)
18
+ set :uses_boost, true
19
+
20
+ # --------------------------------------------
21
+ # Calling our Methods
22
+ # --------------------------------------------
23
+ after "deploy:setup", "deploy:setup_local"
24
+ after "deploy:finalize_update", "demonz:fixperms"
25
+ before "deploy:create_symlink", "drupal:symlink"
26
+ before "deploy:create_symlink", "drupal:protect"
27
+ before "deploy:create_symlink", "drupal:backup_files_dir"
28
+ before "deploy:create_symlink", "drupal:migrate"
29
+ before "deploy:create_symlink", "drupal:clearcache"
30
+
31
+ after "deploy:cleanup", "drupal:cleanup_files_backups"
32
+
33
+ # rollback the database and files directory during a rollback too
34
+ before "deploy:rollback:revision", "drupal:rollback_db"
35
+ after "drupal:rollback_db", "drupal:rollback_files_dir"
36
+
37
+ # --------------------------------------------
38
+ # Overloaded Methods
39
+ # --------------------------------------------
40
+ namespace :deploy do
41
+ desc "Setup local files necessary for deployment"
42
+ task :setup_local do
43
+ logger.important "make sure you copy over your files directory and settings files now"
44
+ # attempt to create files needed for proper deployment
45
+ if local_file_exists?('.htaccess')
46
+ system("cp .htaccess htaccess.dist")
47
+ system("git add htaccess.dist")
48
+ puts "Please commit htaccess.dist to your source control repository."
49
+ end
50
+ end
51
+
52
+ desc "Setup shared application directories and permissions after initial setup"
53
+ task :setup_shared do
54
+ uses_boost = fetch(:uses_boost, false)
55
+
56
+ # remove Capistrano specific directories
57
+ run "#{try_sudo} rm -Rf #{shared_path}/log"
58
+ run "#{try_sudo} rm -Rf #{shared_path}/pids"
59
+ run "#{try_sudo} rm -Rf #{shared_path}/system"
60
+
61
+ # create shared directories
62
+ run "#{try_sudo} mkdir -p #{shared_path}/default/files"
63
+ if uses_boost
64
+ run "#{try_sudo} mkdir -p #{shared_path}/boost/cache/normal"
65
+ end
66
+
67
+ # set correct permissions
68
+ run "#{try_sudo} chmod -R 777 #{shared_path}/*"
69
+ end
70
+
71
+ desc "[internal] Touches up the released code. This is called by update_code after the basic deploy finishes."
72
+ task :finalize_update, :roles => :web, :except => { :no_release => true } do
73
+ run "#{try_sudo} rm -Rf #{latest_release}/sites/default/files"
74
+ end
75
+
76
+ namespace :web do
77
+ desc "Disable the application and show a message screen"
78
+ task :disable, :roles => :web do
79
+ run "#{drush_bin} -r #{latest_release} vset --yes site_offline 1"
80
+ end
81
+
82
+ desc "Enable the application and remove the message screen"
83
+ task :enable, :roles => :web do
84
+ run "#{drush_bin} -r #{latest_release} vdel --yes site_offline"
85
+ end
86
+ end
87
+ end
88
+
89
+ # --------------------------------------------
90
+ # Remote/Local database migration tasks
91
+ # --------------------------------------------
92
+ namespace :db do
93
+ task :local_export do
94
+ mysqldump = fetch(:mysqldump, "mysqldump")
95
+ dump_options = fetch(:dump_options, "")
96
+
97
+ system "#{mysqldump} #{dump_options} --opt -h#{db_local_host} -u#{db_local_user} -p#{db_local_pass} #{db_local_name} | gzip -c --best > #{db_local_name}.sql.gz"
98
+ end
99
+
100
+ desc "Create a compressed MySQL dumpfile of the remote database"
101
+ task :remote_export, :roles => :db do
102
+ mysqldump = fetch(:mysqldump, "mysqldump")
103
+ dump_options = fetch(:dump_options, "")
104
+
105
+ run "#{mysqldump} #{dump_options} --opt -h#{db_remote_host} -u#{db_remote_user} -p#{db_remote_pass} #{db_remote_name} | gzip -c --best > #{deploy_to}/#{db_remote_name}.sql.gz"
106
+ end
107
+
108
+ end
109
+
110
+ namespace :backup do
111
+ desc "Perform a backup of database files"
112
+ task :db, :roles => :db do
113
+ if releases.last.nil?
114
+ logger.important "no previous release to backup; backup of database skipped"
115
+ else
116
+ logger.info "Backing up the database now and putting dump file in the previous release directory"
117
+ # define the filename (include the current_path so the dump file will be within the directory)
118
+ filename = "#{current_path}/default_dump-#{Time.now.to_s.gsub(/ /, "_")}.sql.gz"
119
+ # dump the database for the proper environment
120
+ run "#{drush_bin} -r #{current_path} sql-dump | gzip -c --best > #{filename}"
121
+ end
122
+ end
123
+ end
124
+
125
+ # --------------------------------------------
126
+ # Drupal-specific methods
127
+ # --------------------------------------------
128
+ namespace :drupal do
129
+ desc "Create database"
130
+ task :create_db, :roles => :web, :except => { :no_release => true } do
131
+ drupal_app_site_dir = File.join(latest_release, 'sites', 'default')
132
+ settings_file = File.join(drupal_app_site_dir, 'settings.php')
133
+
134
+ # Check if the base settings.php file exists first (we need this for db details)
135
+ if !remote_file_exists?(settings_file)
136
+ raise Capistrano::Error, "A settings.php file was not found, please create one before continuing. See previous errors for more info."
137
+ end
138
+
139
+ # Get database name
140
+ set :clean_db_name, get_db_name(application, release_name)
141
+
142
+ # Get MySQL connection string from drush (don't need a full bootstrap)
143
+ mysql_connection = capture("#{drush_bin} -r #{latest_release} sql-connect").chomp
144
+
145
+ # Only create if database doesn't exist
146
+ if !database_exists?(mysql_connection, clean_db_name)
147
+ # Remove DB on rollback
148
+ on_rollback { delete_database(mysql_connection, clean_db_name) }
149
+
150
+ create_database(mysql_connection, clean_db_name)
151
+ setup_database_permissions(mysql_connection, clean_db_name)
152
+ end
153
+
154
+ # Add the database name to the settings file.
155
+ update_db_in_settings_file(settings_file, clean_db_name)
156
+ end
157
+
158
+ desc "Copy old database to new one"
159
+ task :copy_old_to_new_db, :roles => :web, :except => { :no_release => true } do
160
+ if releases.last.nil?
161
+ # Ask user to upload a gzipped SQL file
162
+ logger.important "no previous release found, please specify a (gzipped) sql file I can use instead"
163
+ db_file_path = text_prompt("Full path to SQL file: ")
164
+
165
+ # Error out if file doesn't exist
166
+ raise Capistrano::Error, "File '#{db_file_path}' not found" unless local_file_exists?(db_file_path)
167
+
168
+ db_file_parts = File.split(db_file_path)
169
+ db_file = db_file_parts[1]
170
+
171
+ # Upload file to temp directory
172
+ remote_db_file = File.join(tmp_backups_path, db_file)
173
+ top.upload(db_file_path, remote_db_file)
174
+
175
+ # Just incase the command after fails, remove the upload file
176
+ on_rollback { run "#{try_sudo} rm #{remote_db_file}" }
177
+
178
+ run "gzip -fd #{remote_db_file} -c | #{drush_bin} -r #{latest_release} sqlc"
179
+
180
+ # We don't need the upload file anymore
181
+ run "#{try_sudo} rm #{remote_db_file}"
182
+ else
183
+ # Use current release as base
184
+ run "#{drush_bin} -r #{current_release} sql-dump | #{drush_bin} -r #{latest_release} sqlc"
185
+ end
186
+ end
187
+
188
+ desc "Run any update scripts for this release"
189
+ task :run_update_scripts, :roles => :web, :except => { :no_release => true } do
190
+ update_script_file = File.join(latest_release, 'sites', 'all', 'scripts', release_name, 'update.sh')
191
+
192
+ if remote_file_exists?(update_script_file)
193
+ run update_script_file
194
+ end
195
+ end
196
+
197
+ desc "Symlink shared directories"
198
+ task :symlink, :roles => :web, :except => { :no_release => true } do
199
+ uses_boost = fetch(:uses_boost, false)
200
+ # copies the appropriate environment's settings.php file
201
+ copy_config_file
202
+
203
+ run "#{try_sudo} ln -nfs #{shared_path}/default/files #{latest_release}/sites/default/files"
204
+ # run "#{drush_bin} -r #{latest_release} vset --yes file_directory_path sites/default/files"
205
+
206
+ # Symlink boost cache directory
207
+ if uses_boost
208
+ run "#{try_sudo} ln -nfs #{shared_path}/boost/cache #{latest_release}/cache"
209
+ end
210
+ end
211
+
212
+ desc <<-DESC
213
+ Copies the appropriate environment's settings file within the proper sites directory
214
+
215
+ Assumes the environment's settings file will be in the following format:
216
+ settings.<environment>.php
217
+ DESC
218
+ task :copy_config_file, :roles => :web, :except => { :no_release => true} do
219
+ drupal_app_site_dir = " #{latest_release}/sites/default"
220
+
221
+ case true
222
+ when remote_file_exists?("#{shared_path}/settings.#{stage}.php")
223
+ run "#{try_sudo} cp -fL #{shared_path}/settings.#{stage}.php #{drupal_app_site_dir}/settings.php"
224
+ when remote_file_exists?("#{drupal_app_site_dir}/settings.#{stage}.php")
225
+ run "#{try_sudo} cp -fL #{drupal_app_site_dir}/settings.#{stage}.php #{drupal_app_site_dir}/settings.php"
226
+ else
227
+ logger.important "Failed to symlink the settings.php file in #{drupal_app_site_dir} because an unknown pattern was used"
228
+ end
229
+ end
230
+
231
+ desc "Migrate old database to new release"
232
+ task :migrate, :roles => :web, :except => { :no_release => true } do
233
+ create_db
234
+ copy_old_to_new_db
235
+ run_update_scripts
236
+ # Run drush updb just incase
237
+ run "#{drush_bin} -r #{latest_release} updb"
238
+ end
239
+
240
+ desc "Backup the shared 'files' directory"
241
+ task :backup_files_dir, :roles => :web, :except => { :no_release => true } do
242
+ set :archive_name, "files_before_#{release_name}.tar.gz"
243
+ set :files_dir_location, File.join(shared_path, 'default')
244
+ logger.debug "Creating a Tarball of the files directory in #{backups_path}/#{archive_name}"
245
+ run "cd #{files_dir_location} && tar -cvpf - files | gzip -c --best > #{backups_path}/#{archive_name}"
246
+ end
247
+
248
+ desc "Clear all Drupal cache"
249
+ task :clearcache, :roles => :web, :except => { :no_release => true } do
250
+ run "#{drush_bin} -r #{latest_release} cache-clear all"
251
+ # Remove the 'styles' imagecache directory
252
+ image_styles_path = File.join(shared_path, 'default', 'files', 'styles')
253
+ run "#{try_sudo} rm -rf #{image_styles_path}" if remote_dir_exists?(image_styles_path)
254
+ # Also clear boost cache if set
255
+ boost_path = File.join(shared_path, 'boost', 'cache', 'normal', '*')
256
+ run "#{try_sudo} rm -rf #{boost_path}" if fetch(:uses_boost, false)
257
+ end
258
+
259
+ desc "Protect system files"
260
+ task :protect, :roles => :web, :except => { :no_release => true } do
261
+ run "#{try_sudo} chmod 644 #{latest_release}/sites/default/settings.php*"
262
+ end
263
+
264
+ desc "[internal] Delete latest version of DB"
265
+ task :rollback_db, :except => { :no_release => true } do
266
+ if previous_release
267
+ clean_db_name = get_db_name(application, releases.last)
268
+ mysql_connection = capture("#{drush_bin} -r #{latest_release} sql-connect").chomp
269
+ delete_database(mysql_connection, clean_db_name)
270
+ else
271
+ abort "could not rollback the code because there is no prior release"
272
+ end
273
+ end
274
+
275
+ desc "[internal] Rollback shared files directory"
276
+ task :rollback_files_dir, :except => { :no_release => true } do
277
+ if previous_release
278
+ old_release = releases.last
279
+ files_backup_file = File.join(backups_path, "files_before_#{old_release}.tar.gz")
280
+
281
+ if remote_file_exists?(files_backup_file)
282
+ files_dir_location = File.join(shared_path, 'default')
283
+ files_dir = File.join(files_dir_location, 'files')
284
+ files_dir_backup_archive = "files_after_#{old_release}_OLD"
285
+
286
+ on_rollback {
287
+ run "#{try_sudo} rm #{files_dir}" if remote_file_exists?(files_dir_backup_archive) && remote_dir_exists?(files_dir)
288
+ run "#{try_sudo} tar -xvzf #{files_dir_backup_archive} -C #{files_dir_location}" if remote_file_exists?(files_dir_backup_archive)
289
+ }
290
+
291
+ run "cd #{files_dir_location} && tar -cvpf - files | gzip -c --best > #{backups_path}/#{files_dir_backup_archive}"
292
+ run "#{try_sudo} tar -xvzf #{files_backup_file} -C #{files_dir_location}"
293
+ end
294
+ else
295
+ abort "could not rollback the code because there is no prior release"
296
+ end
297
+ end
298
+
299
+ desc "[internal] Remove old file directory backups"
300
+ task :cleanup_files_backups, :roles => :web, :except => { :no_release => true } do
301
+ if variables.include?(:cleanup_releases)
302
+ cleanup_releases = fetch(:cleanup_releases, nil)
303
+
304
+ if !cleanup_releases.nil?
305
+ files_backups = cleanup_releases.map { |release|
306
+ File.join(backups_path, "file_before_#{release}.tar.gz") }.join(" ")
307
+ try_sudo "rm -rf #{files_backups}"
308
+ end
309
+ end
310
+ end
311
+ end
312
+ end
@@ -0,0 +1,5 @@
1
+ module Capistrano
2
+ module Demonz
3
+ VERSION = "0.0.5"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: capistrano-demonz
3
+ version: !ruby/object:Gem::Version
4
+ hash: 21
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 5
10
+ version: 0.0.5
11
+ platform: ruby
12
+ authors:
13
+ - Chinthaka Godawita
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-12-21 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: railsless-deploy
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 19
29
+ segments:
30
+ - 1
31
+ - 0
32
+ - 2
33
+ version: 1.0.2
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: capistrano
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 49
45
+ segments:
46
+ - 2
47
+ - 13
48
+ - 5
49
+ version: 2.13.5
50
+ type: :runtime
51
+ version_requirements: *id002
52
+ description: Demonz Media recipes for Capistrano
53
+ email:
54
+ - chinthaka.godawita@demonzmedia.com
55
+ executables: []
56
+
57
+ extensions: []
58
+
59
+ extra_rdoc_files: []
60
+
61
+ files:
62
+ - Gemfile
63
+ - LICENSE.txt
64
+ - README.md
65
+ - Rakefile
66
+ - capistrano-demonz.gemspec
67
+ - lib/capistrano-demonz.rb
68
+ - lib/demonz/base.rb
69
+ - lib/demonz/common.rb
70
+ - lib/demonz/drupal.rb
71
+ - lib/demonz/version.rb
72
+ homepage: https://github.com/demonz/capistrano-demonz
73
+ licenses: []
74
+
75
+ post_install_message:
76
+ rdoc_options: []
77
+
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ hash: 3
86
+ segments:
87
+ - 0
88
+ version: "0"
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ hash: 3
95
+ segments:
96
+ - 0
97
+ version: "0"
98
+ requirements: []
99
+
100
+ rubyforge_project:
101
+ rubygems_version: 1.8.24
102
+ signing_key:
103
+ specification_version: 3
104
+ summary: Useful task libraries for Demonz Media recipes for Capistrano
105
+ test_files: []
106
+