capistrano_webfaction_recipes 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in capistrano_webfaction_recipes.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Fire-Dragon-DoL
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,38 @@
1
+ # CapistranoWebfactionRecipes
2
+
3
+ This is a simple gem that provides some useful capistrano recipes to handle a Webfaction shared hosting.
4
+
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'capistrano_webfaction_recipes'
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ Or install it yourself as:
17
+
18
+ $ gem install capistrano_webfaction_recipes
19
+
20
+ ## Usage
21
+
22
+ Require the gem files in your deploy.rb file:
23
+
24
+ require 'capistrano_webfaction_recipes/all'
25
+
26
+ Or (better) create a deploy.rb file through the generator by running:
27
+
28
+ rails generate webfaction:install
29
+
30
+ Fill the options interactively, this will generate a nice deploy.rb file, ready to be used.
31
+
32
+ ## Contributing
33
+
34
+ 1. Fork it
35
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
36
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
37
+ 4. Push to the branch (`git push origin my-new-feature`)
38
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'capistrano_webfaction_recipes/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "capistrano_webfaction_recipes"
8
+ spec.version = CapistranoWebfactionRecipes::VERSION
9
+ spec.authors = ["Fire-Dragon-DoL"]
10
+ spec.email = []
11
+ spec.description = "Gem container for some nice webfaction recipes plus a standard deploy file that can be created with a generator"
12
+ spec.summary = "A collection of recipes to handle webfaction shared hosting"
13
+ spec.homepage = "https://github.com/Fire-Dragon-DoL/capistrano_webfaction_recipes"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+ spec.required_ruby_version = '>= 1.9.3'
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.3"
23
+ spec.add_development_dependency "rake"
24
+ spec.add_dependency "capistrano", "2.15.4"
25
+ spec.add_dependency "rails", "~> 3.2.13"
26
+ spec.add_dependency "colored", "~> 1.2"
27
+ end
@@ -0,0 +1,3 @@
1
+ require File.expand_path("../recipes/helpers", __FILE__)
2
+ require File.expand_path("../recipes/tasks", __FILE__)
3
+ require File.expand_path("../recipes/webfaction", __FILE__)
@@ -0,0 +1,46 @@
1
+ # encoding: utf-8
2
+ require 'active_support/all'
3
+ require 'action_pack'
4
+ require 'action_view'
5
+
6
+ module Helpers
7
+
8
+ extend ::ActionView::Helpers::NumberHelper
9
+
10
+ module Characters
11
+
12
+ def self.success
13
+ "✓ "
14
+ end
15
+
16
+ def self.success_fat
17
+ "✔ "
18
+ end
19
+
20
+ def self.failure
21
+ "✕ "
22
+ end
23
+
24
+ def self.failure_fat
25
+ "✖ "
26
+ end
27
+
28
+ def self.up
29
+ "↑"
30
+ end
31
+
32
+ def self.down
33
+ "↓"
34
+ end
35
+
36
+ def self.left
37
+ "←"
38
+ end
39
+
40
+ def self.right
41
+ "→"
42
+ end
43
+
44
+ end
45
+
46
+ end
@@ -0,0 +1,194 @@
1
+ require 'colored'
2
+ require 'active_support/all'
3
+ require File.expand_path("../helpers", __FILE__)
4
+
5
+ Capistrano::Configuration.instance(:must_exist).load do
6
+
7
+ namespace :server_performance do
8
+ desc "Get CPU and RAM usage"
9
+ task :default do
10
+ cpu_usage = capture("ps --no-headers -u #{fetch(:user)} -o pcpu | awk '{cpu += $1} END {print cpu}'").to_i
11
+ ram_usage = capture("ps --no-headers -u #{fetch(:user)} -o rss | awk '{rss += $1} END {print rss}'").to_i.kilobytes
12
+ puts "CPU usage: #{ Helpers.number_to_percentage(cpu_usage, precision: 0) }".bold
13
+ puts "RAM usage: #{ Helpers.number_to_human_size(ram_usage) }".bold
14
+ # run "echo CPU and RAM: `ps --no-headers -u #{fetch(:user)} -o pcpu,rss | awk '{cpu += $1; rss += $2} END {print cpu, rss}'`"
15
+ end
16
+
17
+ desc "Get CPU and RAM usage with process table"
18
+ task :full do
19
+ server_performance
20
+ run "ps -u #{fetch(:user)} -o rss,etime,pid,command" do
21
+ |channel, stream, data|
22
+ print data.to_s
23
+ end
24
+ server_performance.default
25
+ end
26
+ end
27
+
28
+ desc "Load schema from schema.rb"
29
+ task :schema_load do
30
+ run "cd #{fetch(:current_path)}; bundle exec rake db:schema:load RAILS_ENV=#{fetch(:rails_env)}"
31
+ end
32
+
33
+ desc "Seed the database"
34
+ task :db_seed do
35
+ run "cd #{fetch(:current_path)}; bundle exec rake db:seed RAILS_ENV=#{fetch(:rails_env)} RAILS_RAKE_TASK=1"
36
+ end
37
+
38
+ desc "Symlink an external assets directory, uploaded through FTP for example"
39
+ task :external_assets_symlink do
40
+ on_rollback do
41
+ # Deletes the symlink
42
+ if exists?(:external_assets_path)
43
+ fetch(:external_assets_path).each do |external_path|
44
+ assets_basename = File.basename(external_path)
45
+ run "rm -rf #{fetch(:current_path)}/public/#{assets_basename}"
46
+ end
47
+ end
48
+ end
49
+
50
+ if exists?(:external_assets_path)
51
+ fetch(:external_assets_path).each do |external_path|
52
+ assets_basename = File.basename(external_path)
53
+ run "rm -rf #{fetch(:current_path)}/public/#{assets_basename}"
54
+ run "ln -s #{external_path} #{fetch(:current_path)}/public/#{assets_basename}"
55
+ end
56
+ else
57
+ print "No external asset path available"
58
+ end
59
+ end
60
+ after 'deploy:create_symlink', 'external_assets_symlink'
61
+
62
+ desc "Display shell environment variables"
63
+ task :show_env do
64
+ if exists?(:default_environment)
65
+ biggest_key_size = 0
66
+ fetch(:default_environment).each do |key, value|
67
+ str_key = key.to_s
68
+ biggest_key_size = str_key.size if biggest_key_size < str_key.size
69
+ end
70
+
71
+ real_environment = {}
72
+ fetch(:default_environment).each do |key, value|
73
+ real_environment[key] = capture("echo $#{ key }")
74
+ end
75
+ real_environment.each do |key, value|
76
+ print "#{ key }".ljust(biggest_key_size)
77
+ puts " = #{ value }"
78
+ end
79
+ else
80
+ puts "No environment set"
81
+ end
82
+ end
83
+
84
+ desc "Install given gem name"
85
+ task :gem_install do
86
+ if exists?(:name)
87
+ run "gem install #{fetch(:name)}" do |channel, stream, data|
88
+ print data.to_s
89
+ end
90
+ else
91
+ puts 'To install gem you must use -S name=value'
92
+ end
93
+ end
94
+
95
+ namespace :logs do
96
+
97
+ desc "Read the production log file interactively"
98
+ task :watch do
99
+ if exists?(:log_file_path)
100
+ stream("tail -f #{fetch(:log_file_path)}")
101
+ else
102
+ print "No log_file_path set\n"
103
+ end
104
+ end
105
+
106
+ end
107
+
108
+ desc "Display local gemfile path"
109
+ task :show_gemfile_path do
110
+ puts "Local: #{fetch(:local_gemfile_path)}".bold
111
+ puts "Remote: #{fetch(:deploy_to)}/Gemfile".bold
112
+ end
113
+
114
+ # XXX: Everything is commented because the install is already implemented, while
115
+ # the update tasks require to setup the rails environment and other variables
116
+ # namespace :bundle do
117
+
118
+ # desc "Run update with bundle"
119
+ # task :update do
120
+ # run "cd #{fetch(:current_path)}; bundle update"
121
+ # end
122
+
123
+ # desc "Run bundle install and update"
124
+ # task :default do
125
+ # bundle.install
126
+ # bundle.update
127
+ # end
128
+ # end
129
+
130
+ namespace :deploy do
131
+
132
+ desc "Print paths"
133
+ task :paths do
134
+ puts fetch(:deploy_to).to_s
135
+ puts fetch(:current_path).to_s
136
+ end
137
+
138
+ desc "Cleanup everything, deleting old releases"
139
+ task :cleanup_all do
140
+ set :keep_releases, 0
141
+ cleanup
142
+ end
143
+
144
+ desc "Cleanup everything except last"
145
+ task :cleanup_all_but_one do
146
+ set :keep_releases, 1
147
+ cleanup
148
+ end
149
+
150
+ # FIXME: Some recipes here are not behaving correctly
151
+ # desc "Setup the project and loads the database"
152
+ # task :cold do
153
+ # transaction do
154
+ # update
155
+ # schema_load
156
+ # start
157
+ # end
158
+ # end
159
+
160
+ # namespace :full do
161
+ # desc "Install gems, setup database with load, restart server"
162
+ # task :default do
163
+ # transaction do
164
+ # update
165
+ # bundle
166
+ # schema_load
167
+ # start
168
+ # end
169
+ # end
170
+
171
+ # desc "Install gems, setup database with load, seed database, restart server"
172
+ # task :seed do
173
+ # transaction do
174
+ # update
175
+ # bundle
176
+ # schema_load
177
+ # db_seed
178
+ # start
179
+ # end
180
+ # end
181
+
182
+ # desc "Run migrate instead of load"
183
+ # task :migrate do
184
+ # transaction do
185
+ # update
186
+ # bundle
187
+ # migrate
188
+ # start
189
+ # end
190
+ # end
191
+ # end
192
+ end
193
+
194
+ end
@@ -0,0 +1,79 @@
1
+ require 'colored'
2
+ require 'active_support/all'
3
+ require File.expand_path("../helpers", __FILE__)
4
+
5
+ Capistrano::Configuration.instance(:must_exist).load do
6
+ set(:log_file_path) { "#{fetch(:deploy_to)}/nginx/logs/error.log" }
7
+
8
+ desc "String usable to print in shell for SSH variable sets"
9
+ task :env_command do
10
+ puts "export PATH=$PWD/bin:$PATH; export GEM_HOME=$PWD/gems; export RUBYLIB=$PWD/lib"
11
+ end
12
+
13
+ namespace :webapp do
14
+
15
+ desc "Prepare webapp for capistrano deployment"
16
+ task :prepare do
17
+ # Replace hello_world in current
18
+ run "cd #{fetch(:deploy_to)}; rm -rf hello_world/"
19
+ run "cd #{fetch(:deploy_to)}/nginx/conf; sed -i 's/hello_world/current/g' nginx.conf"
20
+ end
21
+
22
+ end
23
+
24
+ namespace :deploy do
25
+
26
+ desc "Restart server"
27
+ task :restart do
28
+ run "#{fetch(:deploy_to)}/bin/restart"
29
+ end
30
+
31
+ desc "Start server"
32
+ task :start do
33
+ run "#{fetch(:deploy_to)}/bin/start"
34
+ end
35
+
36
+ desc "Stop server"
37
+ task :stop do
38
+ run "#{fetch(:deploy_to)}/bin/stop"
39
+ end
40
+
41
+ namespace :webfaction do
42
+
43
+ desc "Setup the application, deploy it, migrate database"
44
+ task :setup do
45
+ webapp.prepare
46
+ bundle.install_without_deploy
47
+ end
48
+
49
+ desc "Setup the application, deploy it, migrate database"
50
+ task :full do
51
+ webapp.prepare
52
+ deploy.full.default
53
+ end
54
+
55
+ end
56
+
57
+ end
58
+
59
+ namespace :bundle do
60
+
61
+ desc "Install bundle without deploy"
62
+ task :install_without_deploy do
63
+ if exists?(:local_gemfile_path)
64
+ upload(fetch(:local_gemfile_path), "#{fetch(:deploy_to)}/Gemfile")
65
+ env_to_ignore = ""
66
+ if exists?(:bundle_without)
67
+ env_to_ignore = " --without #{fetch(:bundle_without).join(' ')}"
68
+ end
69
+ run "cd #{fetch(:deploy_to)}; bundle install#{env_to_ignore}; rm -f Gemfile; rm -f Gemfile.lock" do |channel, stream, data|
70
+ print data.to_s
71
+ end
72
+ else
73
+ puts 'Requires :local_gemfile_path to be set'
74
+ end
75
+ end
76
+
77
+ end
78
+
79
+ end
@@ -0,0 +1,3 @@
1
+ module CapistranoWebfactionRecipes
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1 @@
1
+ require "capistrano_webfaction_recipes/version"
@@ -0,0 +1,33 @@
1
+ require 'rails'
2
+ require 'active_support/all'
3
+
4
+ module Webfaction
5
+ module Generators
6
+ class InstallGenerator < Rails::Generators::Base
7
+
8
+ source_root File.expand_path('../templates', __FILE__)
9
+
10
+ desc "Creates a deploy file that is well organized and makes easy webfaction task usage"
11
+
12
+ def copy_deploy
13
+ target_file = 'config/deploy.rb'
14
+ if File.exists?(target_file)
15
+ unless yes?('Deploy file already exists and will be overwritten, would you like to continue?')
16
+ puts 'Operation aborted'
17
+ return
18
+ end
19
+ remove_file(target_file)
20
+ end
21
+ @rails_app_root_dir_name = File.basename(Dir.pwd)
22
+ @server_ssh_user = ask('Insert your server ssh username')
23
+ @server_ssh_user = 'PUT_SERVER_SSH_USER' if @server_ssh_user.blank?
24
+ @remote_rails_app_root_dir_name = ask('Insert your remote rails application root directory name')
25
+ @remote_rails_app_root_dir_name = 'PUT_REMOTE_RAILS_APP_ROOT_DIR_NAME' if @remote_rails_app_root_dir_name.blank?
26
+ @bitbucket_user = ask('Insert your bitbucket username')
27
+ @bitbucket_user = 'PUT_BITBUCKET_USER' if @bitbucket_user.blank?
28
+ template "deploy.rb.erb", target_file
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,46 @@
1
+ require 'bundler/capistrano'
2
+ require 'capistrano_webfaction_recipes/all'
3
+
4
+ # Webfaction settings
5
+ set :application, '<%= @rails_app_root_dir_name %>'
6
+ set :user, '<%= @server_ssh_user %>'
7
+ set :branch, :master
8
+ set :ssh_options, { forward_agent: true }
9
+ set :app_short, '<%= @remote_rails_app_root_dir_name %>'
10
+ set :external_assets_path, []
11
+ set :local_gemfile_path, File.expand_path('../../Gemfile', __FILE__)
12
+ set :bitbucket, '<%= @bitbucket_user %>'
13
+ set :uploaded_assets_paths, []
14
+
15
+ # Calculated options
16
+ # logger.level = Capistrano::Logger::INFO
17
+ default_run_options[:pty] = true
18
+
19
+ set(:repository) { "git@bitbucket.org:#{fetch(:bitbucket)}/#{fetch(:application)}.git" }
20
+ set(:deploy_to) { "/home/#{fetch(:user)}/webapps/#{fetch(:app_short)}" }
21
+ set(:scm_username) { fetch(:user) }
22
+
23
+ set :deploy_via, :remote_cache
24
+
25
+ set :stages, %w(production staging)
26
+ set :default_stage, 'production'
27
+ require 'capistrano/ext/multistage'
28
+
29
+ set :scm, :git
30
+ set :migrate_env, '' # Not using :production because of a capistrano issue
31
+ set :bundle_without, [:development, :test]
32
+ set :use_sudo, false
33
+ set(:default_environment) do
34
+ {
35
+ 'RAILS_ENV' => fetch(:migrate_env).to_s,
36
+ 'PATH' => "#{fetch(:deploy_to)}/bin:$PATH",
37
+ 'GEM_HOME' => "#{fetch(:deploy_to)}/gems",
38
+ 'RUBYLIB' => "#{fetch(:deploy_to)}/lib"
39
+ }
40
+ end
41
+ if exists?(:uploaded_assets_paths)
42
+ set(:shared_children, []) unless exists?(:shared_children)
43
+ set(:shared_children, fetch(:shared_children) + fetch(:uploaded_assets_paths))
44
+ end
45
+
46
+ server "#{fetch(:user)}.webfactional.com", :web, :app, :db, primary: true
metadata ADDED
@@ -0,0 +1,140 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: capistrano_webfaction_recipes
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Fire-Dragon-DoL
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-06-09 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.3'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.3'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: capistrano
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - '='
52
+ - !ruby/object:Gem::Version
53
+ version: 2.15.4
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 2.15.4
62
+ - !ruby/object:Gem::Dependency
63
+ name: rails
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 3.2.13
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 3.2.13
78
+ - !ruby/object:Gem::Dependency
79
+ name: colored
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: '1.2'
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: '1.2'
94
+ description: Gem container for some nice webfaction recipes plus a standard deploy
95
+ file that can be created with a generator
96
+ email: []
97
+ executables: []
98
+ extensions: []
99
+ extra_rdoc_files: []
100
+ files:
101
+ - .gitignore
102
+ - Gemfile
103
+ - LICENSE.txt
104
+ - README.md
105
+ - Rakefile
106
+ - capistrano_webfaction_recipes.gemspec
107
+ - lib/capistrano_webfaction_recipes.rb
108
+ - lib/capistrano_webfaction_recipes/all.rb
109
+ - lib/capistrano_webfaction_recipes/recipes/helpers.rb
110
+ - lib/capistrano_webfaction_recipes/recipes/tasks.rb
111
+ - lib/capistrano_webfaction_recipes/recipes/webfaction.rb
112
+ - lib/capistrano_webfaction_recipes/version.rb
113
+ - lib/generators/webfaction/install/install_generator.rb
114
+ - lib/generators/webfaction/install/templates/deploy.rb.erb
115
+ homepage: https://github.com/Fire-Dragon-DoL/capistrano_webfaction_recipes
116
+ licenses:
117
+ - MIT
118
+ post_install_message:
119
+ rdoc_options: []
120
+ require_paths:
121
+ - lib
122
+ required_ruby_version: !ruby/object:Gem::Requirement
123
+ none: false
124
+ requirements:
125
+ - - ! '>='
126
+ - !ruby/object:Gem::Version
127
+ version: 1.9.3
128
+ required_rubygems_version: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ requirements: []
135
+ rubyforge_project:
136
+ rubygems_version: 1.8.23
137
+ signing_key:
138
+ specification_version: 3
139
+ summary: A collection of recipes to handle webfaction shared hosting
140
+ test_files: []