obbistrano 1.0.76

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,9 @@
1
+ h1. Automated Server and application deployment
2
+
3
+ h2. Application Deploy
4
+
5
+
6
+
7
+ h2. Server Initialisation and Setup
8
+
9
+
@@ -0,0 +1,45 @@
1
+ require 'rubygems'
2
+ require "httparty"
3
+
4
+ class GithubApi
5
+ include HTTParty
6
+ base_uri "https://github.com/api/v2/yaml"
7
+
8
+ attr_accessor :format, :login, :token, :repo, :base_uri
9
+
10
+ def initialize(login = nil, token = nil, format = "yaml")
11
+ @format = format
12
+ if login
13
+ @login = login
14
+ @token = token
15
+ end
16
+ end
17
+
18
+ def create_repo(params)
19
+ uri = uri = "#{self.class.base_uri}/repos/create"
20
+ post_params = {"login"=>@login, "token"=>@token}
21
+ self.class.post(uri, :query=>post_params.merge(params))
22
+ end
23
+
24
+ def add_collaborator(user)
25
+ uri = "#{self.class.base_uri}/repos/collaborators/#{@repo}/add/#{user}"
26
+ post_params = {"login"=>@login, "token"=>@token}
27
+ self.class.post(uri, :query=>post_params)
28
+ end
29
+
30
+ def add_key(params)
31
+ uri = "#{self.class.base_uri}/repos/key/#{@repo}/add"
32
+ post_params = {"login"=>@login, "token"=>@token}
33
+ params = post_params.merge(params)
34
+ self.class.post(uri, :query=>post_params.merge(params))
35
+ end
36
+
37
+ def create_issue(params)
38
+ uri = "#{self.class.base_uri}/issues/open/#{@login}/#{@repo}"
39
+ post_params = {"login"=>@login, "token"=>@token}
40
+ params = post_params.merge(params)
41
+ self.class.post(uri, :query=>post_params.merge(params))
42
+ end
43
+
44
+ end
45
+
@@ -0,0 +1,3 @@
1
+ require "slicehost"
2
+ require "githubapi"
3
+ require "obbistrano_tasks"
@@ -0,0 +1,415 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+
3
+ #### Performs the initial setup for tasks ####
4
+ task :config_setup do
5
+ set :root_pass, root rescue nil
6
+ set :environment, environment rescue set :environment, "production"
7
+ end
8
+
9
+
10
+ #### Slicehost Namespace.... Allows Auto Creation of DNS ####
11
+
12
+ namespace :slicehost do
13
+
14
+ desc "Sets up slicehost DNS for each of the servers specified with a role of web."
15
+ task :setup do
16
+ get_slice_ip
17
+ servers = find_servers :roles => :web
18
+ servers.each do |s|
19
+ if !zone = Zone.find(:first, :params => {:origin => "#{s}."})
20
+ zone = Zone.new(:origin => s, :ttl => TTL)
21
+ zone.save
22
+ end
23
+ recordOne = Record.new(:record_type => 'A', :zone_id => zone.id, :name => 'www', :data => "#{slice_ip}")
24
+ recordTwo = Record.new(:record_type => 'A', :zone_id => zone.id, :name => '@', :data => "#{slice_ip}")
25
+ recordThree = Record.new(:record_type => 'A', :zone_id => zone.id, :name => 'beta', :data => "#{slice_ip}")
26
+ recordFour = Record.new(:record_type => 'A', :zone_id => zone.id, :name => zone.origin, :data => "#{slice_ip}")
27
+ recordFive = Record.new(:record_type => 'NS', :zone_id => zone.id, :name => zone.origin, :data => 'ns1.slicehost.net.')
28
+ recordSix = Record.new(:record_type => 'NS', :zone_id => zone.id, :name => zone.origin, :data => 'ns2.slicehost.net.')
29
+ recordSeven = Record.new(:record_type => 'NS', :zone_id => zone.id, :name => zone.origin, :data => 'ns3.slicehost.net.')
30
+ [recordOne, recordTwo, recordThree, recordFour, recordFive, recordSix, recordSeven].each {|r| r.save}
31
+ end
32
+ end
33
+
34
+ task :get_slice_ip do
35
+ set :slice_ip, get_ip(fetch("host", false))
36
+ end
37
+
38
+ desc "Sets up slicehost DNS for Google Apps usage on each of the servers specified with a role of web."
39
+ task :googleapps do
40
+ SLICEHOST_API_PASSWORD = "#{slicehost_api_key}"
41
+ mx_records = <<-RECORD
42
+ ASPMX.L.GOOGLE.COM.
43
+ ALT1.ASPMX.L.GOOGLE.COM.
44
+ ALT2.ASPMX.L.GOOGLE.COM.
45
+ ASPMX2.GOOGLEMAIL.COM.
46
+ ASPMX3.GOOGLEMAIL.COM.
47
+ RECORD
48
+ servers = find_servers :roles => :web
49
+ servers.each do |s|
50
+ mx_aux = %w[5 10 10 20 20 30 ]
51
+ aux_count = 0
52
+ zone = Zone.find(:first, :params => {:origin => "#{s}."})
53
+ mx_records.each do |rec|
54
+ r = Record.new(:record_type => 'MX', :zone_id => zone.id, :name => "#{s}." , :data => "#{rec}", :aux => mx_aux[aux_count])
55
+ r.save
56
+ aux_count =+ 1
57
+ end
58
+ recordOne = Record.new(:record_type => 'CNAME', :zone_id => zone.id, :name => 'mail', :data => "ghs.google.com.")
59
+ recordTwo = Record.new(:record_type => 'CNAME', :zone_id => zone.id, :name => 'docs', :data => "ghs.google.com.")
60
+ [recordOne, recordTwo].each {|r| r.save}
61
+ end
62
+ end
63
+
64
+ end
65
+
66
+
67
+ #### Github Namespace.... Allows Auto Creation of Repository, ssh keys and Repo permissions ####
68
+
69
+ namespace :github do
70
+ task :setup do
71
+ puts "*** You need to specify a github login and token to run this operation" if !defined? "#{github_login}" || !defined? "#{github_token}"
72
+ exit if !defined? "#{github_login}" || !defined? "#{github_token}"
73
+ api = GithubApi.new("#{github_login}", "#{github_token}")
74
+ params = {
75
+ :name =>"#{application}",
76
+ :body =>"Project for #{application}",
77
+ :public =>0
78
+ }
79
+ api.create_repo(params)
80
+ api.repo = "#{application}"
81
+ api.add_collaborator("rossriley")
82
+ api.add_collaborator("Sheldon")
83
+ api.add_collaborator("charlesmarshall")
84
+ api.add_collaborator("MichalNoskovic")
85
+ app:ssh_key
86
+ server_ssh_key = capture("cat .ssh/id_rsa.pub")
87
+ server_ssh_key
88
+ api.add_key({:title=>"#{host}",:key=>server_ssh_key})
89
+ end
90
+
91
+
92
+ end
93
+
94
+ namespace :app do
95
+
96
+ task :config_check do
97
+ config_setup
98
+ databases rescue set(:databases, ["#{application}"])
99
+ aliases rescue set(:aliases, []);
100
+ end
101
+
102
+ task :needs_root do
103
+ config_check
104
+ puts "*** This operation needs root access - Please pass in a root password using -s root=password" if !defined? "#{root_pass}"
105
+ exit if !defined? "#{root_pass}"
106
+ end
107
+
108
+
109
+
110
+ # =============================================================================
111
+ # DEPLOYING APPLICATIONS
112
+ # =============================================================================
113
+
114
+ task :deploy do
115
+ config_check
116
+ deploy_check
117
+ php_wax_deploy if defined? "#{phpwax}"
118
+ cms_deploy if defined? "#{cms}"
119
+ css_build
120
+ js_build
121
+ end
122
+
123
+ task :deploy_check do
124
+ fetch "repository" rescue abort "You have not specified a repository for this application"
125
+ git_deploy if repository.include? "git"
126
+ svn_deploy if repository.include? "svn"
127
+ end
128
+
129
+ task :syncdb do
130
+ logger.level = -1
131
+ run "cd #{deploy_to} && script/syncdb #{environment}"
132
+ logger.level=2
133
+ logger.info "Application database has been synchronised"
134
+ end
135
+
136
+ task :git_deploy do
137
+ logger.level = 2
138
+ logger.info "Deploying application from #{repository} on branch #{branch}"
139
+ logger.level = -1
140
+ begin
141
+ run "ls #{deploy_to}/.git"
142
+ rescue
143
+ run "mkdir -p #{deploy_to}"
144
+ run "cd #{deploy_to} && git init"
145
+ run "cd #{deploy_to} && git remote add origin #{repository}"
146
+ end
147
+ logger.level = 2
148
+ run "cd #{deploy_to} && git fetch"
149
+ begin
150
+ run "cd #{deploy_to} && git checkout -b #{branch} origin/#{branch}"
151
+ rescue
152
+ run "cd #{deploy_to} && git pull origin #{branch}"
153
+ run "cd #{deploy_to} && git checkout #{branch}"
154
+ run "cd #{deploy_to} && git checkout #{commit}" if defined? "#{commit}"
155
+ end
156
+
157
+ logger.info "Application has been updated on branch #{branch}"
158
+ end
159
+
160
+ task :svn_deploy do
161
+ run "svn export #{repository} #{deploy_to} --force"
162
+ end
163
+
164
+ task :cms_deploy do
165
+ logger.level = -1
166
+ run "mkdir -p #{deploy_to}/plugins/cms"
167
+ begin
168
+ run "ls #{deploy_to}/plugins/cms/.git/"
169
+ rescue
170
+ logger.level = 2
171
+ logger.info "Initialising Wildfire Folder"
172
+ run "cd #{deploy_to}/plugins/cms && git init"
173
+ run "cd #{deploy_to}/plugins/cms && git remote add origin git://github.com/phpwax/wildfire.git"
174
+ end
175
+ logger.info "Updating Wildfire Code from remote"
176
+ run "cd #{deploy_to}/plugins/cms && git fetch"
177
+ logger.level = -1
178
+ begin
179
+ run "cd #{deploy_to}/plugins/cms && git checkout -b #{cms} origin/#{cms}"
180
+ rescue
181
+ run "cd #{deploy_to}/plugins/cms && git checkout #{cms}"
182
+ end
183
+ run "cd #{deploy_to}/plugins/cms && git pull origin #{cms}"
184
+ logger.level = 2
185
+ logger.info "Wildfire CMS has been updated on branch #{cms}"
186
+ end
187
+
188
+
189
+ task :php_wax_deploy do
190
+ logger.level = -1
191
+ run "mkdir -p #{deploy_to}/wax"
192
+ begin
193
+ run "ls #{deploy_to}/wax/.git/"
194
+ rescue
195
+ logger.level = 2
196
+ logger.info "Initialising PHP Wax Folder"
197
+ run "cd #{deploy_to}/wax && git init"
198
+ run "cd #{deploy_to}/wax && git remote add origin git://github.com/phpwax/phpwax.git"
199
+ end
200
+ logger.info "Updating PHP Wax Code from remote"
201
+ run "cd #{deploy_to}/wax && git fetch"
202
+ logger.level = -1
203
+ begin
204
+ run "cd #{deploy_to}/wax && git checkout -b #{phpwax} origin/#{phpwax}"
205
+ rescue
206
+ run "cd #{deploy_to}/wax && git checkout #{phpwax}"
207
+ end
208
+ run "cd #{deploy_to}/wax && git pull origin #{phpwax}"
209
+ logger.level = 3
210
+ logger.info "PHP Wax has been updated on branch #{phpwax}"
211
+ end
212
+
213
+
214
+ task :css_build do
215
+ set :css_files, Dir.glob("**/*.css") if !defined? "#{css_files}"
216
+ run "cd #{deploy_to} && rm -f public/stylesheets/build.css"
217
+ css_files.each do |f|
218
+ run "cd #{deploy_to} && cat #{f} >> #{deploy_to}/public/stylesheets/build.css"
219
+ end
220
+ end
221
+
222
+ task :js_build do
223
+ set :js_files, Dir.glob("**/*.js") if !defined? "#{js_files}"
224
+ run "cd #{deploy_to} && rm -f public/javascripts/build.js"
225
+ js_files.each do |f|
226
+ run "cd #{deploy_to} && cat #{f} >> #{deploy_to}/public/javascripts/build.js"
227
+ end
228
+ end
229
+ ####### ##############
230
+
231
+
232
+ # =============================================================================
233
+ # GENERAL ADMIN FOR APPLICATIONS
234
+ # =============================================================================
235
+
236
+ desc "Restarts the Apache Server. Requires root password to access."
237
+ task :restart do
238
+ config_check
239
+ needs_root
240
+ with_user("root", "#{root_pass}") do
241
+ run "/etc/rc.d/init.d/httpd restart"
242
+ end
243
+ end
244
+
245
+ desc "Clears the application's cache files from tmp/cache."
246
+ task :clearcache do
247
+ run "cd #{deploy_to} && rm -f tmp/cache/*"
248
+ end
249
+
250
+ desc "Clears the application's log files from tmp/log."
251
+ task :clearlogs do
252
+ run "cd #{deploy_to} && rm -f tmp/log/*"
253
+ end
254
+
255
+
256
+
257
+ # =============================================================================
258
+ # USER AND APPLICATION SETUP AND INITIALISATION
259
+ # =============================================================================
260
+
261
+ task :setup do
262
+ config_check
263
+ try_login
264
+ setup_mysql
265
+ vhost
266
+ ssh_key
267
+ end
268
+
269
+
270
+ task :setup_user do
271
+ needs_root
272
+ set :user_to_add, "#{user}"
273
+ set :passwd_to_add, "#{password}"
274
+ with_user("root", "#{root_pass}") do
275
+ run "useradd -p `openssl passwd #{passwd_to_add}` #{user_to_add}"
276
+ run "chmod -R 0755 /home/#{user_to_add}"
277
+ end
278
+ end
279
+
280
+ task :setup_mysql do
281
+ needs_root
282
+ set :user_to_add, "#{user}"
283
+ set :passwd_to_add, "#{password}"
284
+ with_user("root", "#{root_pass}") do
285
+ "#{databases}".each do |db|
286
+ begin
287
+ run "mysql -uroot -p#{root_pass} -e \"CREATE USER '#{user_to_add}'@'localhost' IDENTIFIED BY '#{passwd_to_add}';\""
288
+ run "mysql -uroot -p#{root_pass} -e 'CREATE DATABASE #{db}'"
289
+ run "musql -uroot -p#{root_pass} -e \"GRANT ALL PRIVILEGES ON `#{db}` . * TO '#{user_to_add}'@'localhost' IDENTIFIED BY '#{passwd_to_add}';\""
290
+ rescue
291
+ logger.info "Database #{db} already exists"
292
+ end
293
+ end
294
+ end
295
+
296
+ end
297
+
298
+ task :try_login do
299
+ config_check
300
+ begin
301
+ run "ls"
302
+ puts "Logged in ok"
303
+ rescue
304
+ print "==== The user does not yet exist. Would you like to create? [Y/N]"
305
+ line = STDIN.gets.upcase.strip
306
+ puts "*** Could not continue as the login does not exist" if line !="Y"
307
+ exit if line != "Y"
308
+ setup_user
309
+ end
310
+ end
311
+
312
+ desc "Creates or gets an ssh key for the application"
313
+ task :ssh_key do
314
+ config_check
315
+ begin
316
+ run "cat .ssh/id_rsa.pub"
317
+ rescue
318
+ run "mkdir -p .ssh/"
319
+ run "ssh-keygen -t rsa -f .ssh/id_rsa -N ''"
320
+ run "cat .ssh/id_rsa.pub"
321
+ end
322
+ end
323
+
324
+ desc "Creates an Apache virtual host file"
325
+ task :vhost do
326
+ config_check
327
+ needs_root
328
+ with_user("root", "#{root_pass}") do
329
+ public_ip = ""
330
+ run "ifconfig eth0 | grep inet | awk '{print $2}' | sed 's/addr://'" do |_, _, public_ip| end
331
+ public_ip = public_ip.strip
332
+ roles[:web].servers.each do |webserver|
333
+ f = File.open(File.join(File.dirname(__FILE__), 'templates/apache_vhost.erb' ))
334
+ contents = f.read
335
+ f.close
336
+ buffer = ERB.new(contents)
337
+ config = buffer.result(binding())
338
+ put config, "/etc/httpd/conf.d/#{webserver}-apache-vhost.conf"
339
+ end
340
+ end
341
+ restart
342
+ end
343
+
344
+
345
+
346
+ # =============================================================================
347
+ # +MIGRATING+ APPLICATIONS
348
+ # =============================================================================
349
+
350
+ task :copy_site do
351
+ config_check
352
+ needs_root
353
+ backup
354
+ print "==== Which server would you like to copy #{application} to? [Full Domain Name] "
355
+ line = STDIN.gets.strip
356
+ begin
357
+ new_server = options["servers"][line]["domain"]
358
+ rescue
359
+ puts "*** Can't find that new server in the config"
360
+ exit
361
+ end
362
+ with_user("root", "#{root_pass}") do
363
+ run "rsync -avzh . -e ssh root@#{new_server}:/backup/#{application}/ --exclude 'tmp/*' --exclude '.git/*'"
364
+ end
365
+ options["apps"]["#{application}"]["server"] = line
366
+ config_write
367
+ try_login
368
+ restore
369
+ end
370
+
371
+ end
372
+
373
+
374
+ def get_ip(domain)
375
+ require 'socket'
376
+ t = TCPSocket.gethostbyname(domain)
377
+ t[3]
378
+ end
379
+
380
+ def with_user(new_user, new_pass, &block)
381
+ old_user, old_pass = user, password
382
+ set :user, new_user
383
+ set :password, new_pass
384
+ close_sessions
385
+ yield
386
+ set :user, old_user
387
+ set :password, old_pass
388
+ close_sessions
389
+ end
390
+ def close_sessions
391
+ sessions.values.each { |session| session.close }
392
+ sessions.clear
393
+ end
394
+
395
+
396
+ namespace :deploy do
397
+ desc "Uses the specified repository to deploy an application. Also checks for correct versions of PHPWax and plugins."
398
+ task :default do
399
+ logger.level=-1
400
+ app.deploy
401
+ end
402
+ end
403
+
404
+ namespace :setup do
405
+ desc "Sets up the server with a user, home directory and mysql login."
406
+ task :default do
407
+ app.setup
408
+ end
409
+ end
410
+
411
+ end
412
+
413
+
414
+
415
+
@@ -0,0 +1,16 @@
1
+ require 'rubygems'
2
+ require 'activeresource'
3
+
4
+ TTL = 86400
5
+
6
+ class Record < ActiveResource::Base
7
+ self.site = "https://#{SLICEHOST_API_PASSWORD}@api.slicehost.com/"
8
+ end
9
+
10
+ class Zone < ActiveResource::Base
11
+ self.site = "https://#{SLICEHOST_API_PASSWORD}@api.slicehost.com/"
12
+ end
13
+
14
+ class Slice < ActiveResource::Base
15
+ self.site = "https://#{SLICEHOST_API_PASSWORD}@api.slicehost.com/"
16
+ end
@@ -0,0 +1,16 @@
1
+ <VirtualHost <%=public_ip%>:80>
2
+ ServerName <%=webserver%>
3
+ <%aliases.each do |aliass|%>
4
+ ServerAlias <%=aliass%>
5
+ <%end%>
6
+ DocumentRoot /home/<%=application%>/<%=deploy_to%>/public
7
+ DirectoryIndex index.html index.htm index.php
8
+ AddOutputFilterByType DEFLATE text/html text/plain text/xml application/x-javascript text/css
9
+ SetOutputFilter DEFLATE
10
+
11
+ <Directory /home/<%=application%>/<%=deploy_to%>/public>
12
+ Options Indexes IncludesNOEXEC FollowSymLinks
13
+ allow from all
14
+ AllowOverride All
15
+ </Directory>
16
+ </VirtualHost>
@@ -0,0 +1,34 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{obbistrano}
5
+ s.version = "1.0.76"
6
+ s.authors = ["Ross Riley", "One Black Bear"]
7
+ s.date = Time.now
8
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
9
+ s.require_paths = ["lib"]
10
+ s.description = %q{An extension to Capistrano to allow deploys to Slicehost for One Black Bear}
11
+ s.email = %q{ross@oneblackbear.com}
12
+ s.files = ["README.textile", "obbistrano.gemspec", "lib/obbistrano.rb","lib/githubapi.rb", "lib/slicehost.rb", "lib/obbistrano_tasks.rb", "lib/templates/apache_vhost.erb"]
13
+ s.homepage = %q{http://github.com/oneblackbear/obbistrano}
14
+ s.rubygems_version = %q{1.3.0}
15
+ s.summary = %q{Adds extra namespaces to Capistrano to allow simple setup, deploys and maintenance.}
16
+ if s.respond_to? :specification_version then
17
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
18
+ s.specification_version = 2
19
+
20
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
21
+ s.add_runtime_dependency(%q<capistrano>, [">= 2.5"])
22
+ s.add_runtime_dependency(%q<activeresource>, [">= 2"])
23
+ s.add_runtime_dependency(%q<httparty>, [">= 0.4.3"])
24
+ else
25
+ s.add_dependency(%q<capistrano>, [">= 2.5"])
26
+ s.add_dependency(%q<activeresource>, [">= 2"])
27
+ s.add_dependency(%q<httparty>, [">= 0.4.3"])
28
+ end
29
+ else
30
+ s.add_dependency(%q<capistrano>, [">= 2.5"])
31
+ s.add_dependency(%q<activeresource>, [">= 2"])
32
+ s.add_dependency(%q<httparty>, [">= 0.4.3"])
33
+ end
34
+ end
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: obbistrano
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.76
5
+ platform: ruby
6
+ authors:
7
+ - Ross Riley
8
+ - One Black Bear
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2009-10-08 00:00:00 +01:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: capistrano
18
+ type: :runtime
19
+ version_requirement:
20
+ version_requirements: !ruby/object:Gem::Requirement
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: "2.5"
25
+ version:
26
+ - !ruby/object:Gem::Dependency
27
+ name: activeresource
28
+ type: :runtime
29
+ version_requirement:
30
+ version_requirements: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: "2"
35
+ version:
36
+ - !ruby/object:Gem::Dependency
37
+ name: httparty
38
+ type: :runtime
39
+ version_requirement:
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: 0.4.3
45
+ version:
46
+ description: An extension to Capistrano to allow deploys to Slicehost for One Black Bear
47
+ email: ross@oneblackbear.com
48
+ executables: []
49
+
50
+ extensions: []
51
+
52
+ extra_rdoc_files: []
53
+
54
+ files:
55
+ - README.textile
56
+ - obbistrano.gemspec
57
+ - lib/obbistrano.rb
58
+ - lib/githubapi.rb
59
+ - lib/slicehost.rb
60
+ - lib/obbistrano_tasks.rb
61
+ - lib/templates/apache_vhost.erb
62
+ has_rdoc: true
63
+ homepage: http://github.com/oneblackbear/obbistrano
64
+ licenses: []
65
+
66
+ post_install_message:
67
+ rdoc_options: []
68
+
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: "0"
76
+ version:
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: "0"
82
+ version:
83
+ requirements: []
84
+
85
+ rubyforge_project:
86
+ rubygems_version: 1.3.4
87
+ signing_key:
88
+ specification_version: 2
89
+ summary: Adds extra namespaces to Capistrano to allow simple setup, deploys and maintenance.
90
+ test_files: []
91
+