ratchetify 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/Capfile.example +22 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +48 -0
- data/Rakefile +2 -0
- data/bin/rat +3 -0
- data/lib/ratchetify/base.rb +23 -0
- data/lib/ratchetify/domain.rb +23 -0
- data/lib/ratchetify/help.rb +74 -0
- data/lib/ratchetify/helpers.rb +69 -0
- data/lib/ratchetify/rails.rb +127 -0
- data/lib/ratchetify/ruby.rb +30 -0
- data/lib/ratchetify/service.rb +118 -0
- data/lib/ratchetify/setup.rb +61 -0
- data/lib/ratchetify/undeploy.rb +31 -0
- data/lib/ratchetify/update.rb +46 -0
- data/lib/ratchetify/version.rb +3 -0
- data/lib/ratchetify/wordpress.rb +79 -0
- data/lib/ratchetify.rb +31 -0
- data/ratchetify.gemspec +25 -0
- metadata +95 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4ec4df90fc1d35e8dbc3e926941de1b4ddf40131
|
4
|
+
data.tar.gz: f83dc562279ef6e25fd6096d3b64f6bf24d8b988
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fa70a0efa1a00b16758a182ba0453fc864ae859124f0ce3b41412cb14f3fb2db1e1b7404b74a7277f62eb5e157fad72fca14db48ac2770c00471b514bcd39c5d
|
7
|
+
data.tar.gz: 1c924f17be19a6de26379b7b2014ab8ae890cd78afdd0a9bead9abce262015548fde636dd3c13fe29445cdb82aa25d74ce595be6792ce85205164f5da8d3befa
|
data/.gitignore
ADDED
data/Capfile.example
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# ratchetify recipes
|
2
|
+
require 'ratchetify'
|
3
|
+
|
4
|
+
# the application's name
|
5
|
+
set :application, 'yourapp'
|
6
|
+
set :host, 'www'
|
7
|
+
set :domain, 'yourapp.com'
|
8
|
+
|
9
|
+
# SSH user/password
|
10
|
+
set :user, 'uberspace_user'
|
11
|
+
set :password, 'uberspace_user_password'
|
12
|
+
|
13
|
+
role :web, "some_server.uberspace.de" # Your HTTP server, Apache/etc
|
14
|
+
role :db, "some_server.uberspace.de"
|
15
|
+
|
16
|
+
set :repo, "https://github.com/you/yourapp.git"
|
17
|
+
set :repo_password, 'your_github_password'
|
18
|
+
set :branch, 'master'
|
19
|
+
|
20
|
+
set :daemon_port, 76543 # a random port. Make sure no one else uses it
|
21
|
+
|
22
|
+
# there are a couple more attributes, but normally you don't need to change them. See lib/ratchetify.rb and lib/ratchetify/base.rb for details.
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Michael Kuehl, michael@ratchet.cc
|
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,48 @@
|
|
1
|
+
# Ratchetify
|
2
|
+
|
3
|
+
Ratchetify helps you deploy a Ruby on Rails app on Uberspace (uberspace.de), a really cool shared hosting provider.
|
4
|
+
|
5
|
+
All the magic is built into a couple nice Capistrano scripts. Ratchetify will create an environment for your app, run it in standalone mode, monitor it using Daemontools, and configure Apache to reverse-proxy to it. Ratchetify will also retrieve your MySQL password, create a dedicated database for your app and create a `database.yml`.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's `Gemfile`:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'ratchetify', :git => 'https://github.com/ratchetcc/ratchetify.git'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
This will install ratchetify, Capistrano 2.x and all dependent gems for you.
|
20
|
+
|
21
|
+
## How to use ratchetify
|
22
|
+
|
23
|
+
There is a sample [capfile](https://github.com/ratchetcc/ratchetify/blob/master/Capfile.example) that shows the most important settings you need to get started. In addition to the
|
24
|
+
attributes used in the Capfile, there are more attributes pre-set in lib/ratchetify.rb and lib/ratchetify/base.rb but usually there is no need to change any of these.
|
25
|
+
|
26
|
+
This tools is highly opinionated i.e. all the settings, the way how I run the app etc. are THE WAY I LIKE IT. This does not mean it can not be done differently or that it is the best way to do it ...
|
27
|
+
|
28
|
+
## Credits
|
29
|
+
|
30
|
+
The original gem was created by [Jan Schulz-Hofen](https://github.com/yeah/uberspacify).
|
31
|
+
|
32
|
+
## License
|
33
|
+
|
34
|
+
MIT; Copyright (c) 2014 ratchet.cc
|
35
|
+
|
36
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
37
|
+
|
38
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
39
|
+
|
40
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
41
|
+
|
42
|
+
## Contributing
|
43
|
+
|
44
|
+
1. Fork it
|
45
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
46
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
47
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
48
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/bin/rat
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
require 'bundler/capistrano'
|
3
|
+
|
4
|
+
def abort_red(msg)
|
5
|
+
abort " * \e[#{1};31mERROR: #{msg}\e[0m"
|
6
|
+
end
|
7
|
+
|
8
|
+
Capistrano::Configuration.instance.load do
|
9
|
+
|
10
|
+
# required variables
|
11
|
+
_cset(:user) { abort_red "Please configure your Uberspace user using 'set :user, <username>'" }
|
12
|
+
_cset(:repository) { abort_red "Please configure your code repository using 'set :repository, <repo uri>'" }
|
13
|
+
|
14
|
+
# other variables
|
15
|
+
_cset(:deploy_via) { :remote_cache }
|
16
|
+
_cset(:branch) { 'master' }
|
17
|
+
|
18
|
+
# internal variables, don't mess with them unsless you know what you do !
|
19
|
+
set(:use_sudo) { false }
|
20
|
+
ssh_options[:forward_agent] = true # use the keys for the person running the cap command to check out the app
|
21
|
+
default_run_options[:pty] = true # needed for git password prompts
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
Capistrano::Configuration.instance.load do
|
3
|
+
|
4
|
+
require 'capistrano'
|
5
|
+
require 'ratchetify/helpers'
|
6
|
+
|
7
|
+
desc "Tasks to add/remove domains (web only)"
|
8
|
+
namespace :domain do
|
9
|
+
|
10
|
+
desc "Add a fully qualified domain and wildcard domain if specified"
|
11
|
+
task :add do
|
12
|
+
run "uberspace-add-domain -d #{fetch :host}.#{fetch :domain} -w"
|
13
|
+
run "uberspace-add-domain -d #{fetch :domain} -w" unless (wildcard_domain == false)
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "Removes a fully qualified domain and wildcard domain if specified"
|
17
|
+
task :remove do
|
18
|
+
run "uberspace-del-domain -d #{fetch :host}.#{fetch :domain} -w"
|
19
|
+
run "uberspace-del-domain -d #{fetch :domain} -w" unless (wildcard_domain == false)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Capistrano
|
2
|
+
class CLI
|
3
|
+
module Help
|
4
|
+
|
5
|
+
def task_list(config, pattern = true) #:nodoc:
|
6
|
+
tool_output = options[:tool]
|
7
|
+
|
8
|
+
if pattern.is_a?(String)
|
9
|
+
tasks = config.task_list(:all).select {|t| t.fully_qualified_name =~ /#{pattern}/}
|
10
|
+
end
|
11
|
+
if tasks.nil? || tasks.length == 0
|
12
|
+
warn "Pattern '#{pattern}' not found. Listing all tasks.\n\n" if !tool_output && !pattern.is_a?(TrueClass)
|
13
|
+
tasks = config.task_list(:all)
|
14
|
+
end
|
15
|
+
|
16
|
+
if tasks.empty?
|
17
|
+
warn "There are no tasks available. Please specify a recipe file to load." unless tool_output
|
18
|
+
else
|
19
|
+
all_tasks_length = tasks.length
|
20
|
+
if options[:verbose].to_i < 1
|
21
|
+
tasks = tasks.reject { |t| t.description.empty? || t.description =~ /^\[internal\]/ }
|
22
|
+
end
|
23
|
+
|
24
|
+
tasks = tasks.sort_by { |task| task.fully_qualified_name }
|
25
|
+
|
26
|
+
longest = tasks.map { |task| task.fully_qualified_name.length }.max
|
27
|
+
max_length = output_columns - longest - LINE_PADDING
|
28
|
+
max_length = MIN_MAX_LEN if max_length < MIN_MAX_LEN
|
29
|
+
|
30
|
+
tasks.each do |task|
|
31
|
+
if tool_output
|
32
|
+
puts "rat #{task.fully_qualified_name}" # monkey patched
|
33
|
+
else
|
34
|
+
puts "rat %-#{longest}s # %s" % [task.fully_qualified_name, task.brief_description(max_length)] # monkey patched
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
unless tool_output
|
39
|
+
if all_tasks_length > tasks.length
|
40
|
+
puts
|
41
|
+
puts "Some tasks were not listed, either because they have no description,"
|
42
|
+
puts "or because they are only used internally by other tasks. To see all"
|
43
|
+
puts "tasks, type `#{File.basename($0)} -vT'."
|
44
|
+
end
|
45
|
+
|
46
|
+
puts
|
47
|
+
puts "Extended help may be available for these tasks."
|
48
|
+
puts "Type `#{File.basename($0)} -e taskname' to view it."
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def explain_task(config, name) #:nodoc:
|
54
|
+
task = config.find_task(name)
|
55
|
+
if task.nil?
|
56
|
+
warn "The task `#{name}' does not exist."
|
57
|
+
else
|
58
|
+
puts "-" * HEADER_LEN
|
59
|
+
puts "rat #{name}" # monkey patched
|
60
|
+
puts "-" * HEADER_LEN
|
61
|
+
|
62
|
+
if task.description.empty?
|
63
|
+
puts "There is no description for this task."
|
64
|
+
else
|
65
|
+
puts format_text(task.description)
|
66
|
+
end
|
67
|
+
|
68
|
+
puts
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
#
|
2
|
+
# usefull methods that make life easier
|
3
|
+
#
|
4
|
+
|
5
|
+
#
|
6
|
+
# dirs and other constants
|
7
|
+
#
|
8
|
+
|
9
|
+
def webroot_dir
|
10
|
+
"/var/www/virtual/#{user}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def deploy_root
|
14
|
+
"#{webroot_dir}/apps"
|
15
|
+
end
|
16
|
+
|
17
|
+
def deploy_dir
|
18
|
+
"#{deploy_root}/#{application}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def conf_dir
|
22
|
+
"/home/#{user}/aconf"
|
23
|
+
end
|
24
|
+
|
25
|
+
def daemon_service
|
26
|
+
"run-#{application}"
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# file and dir handling
|
31
|
+
#
|
32
|
+
|
33
|
+
def file_exists?(full_path)
|
34
|
+
'true' == capture("if [ -e #{full_path} ]; then echo 'true'; fi").strip
|
35
|
+
end
|
36
|
+
|
37
|
+
def dir_exists?(full_path)
|
38
|
+
'true' == capture("if [ -d #{full_path} ]; then echo 'true'; fi").strip
|
39
|
+
end
|
40
|
+
|
41
|
+
def create_dir(full_path, owner=nil)
|
42
|
+
run "mkdir #{full_path} -p"
|
43
|
+
if owner
|
44
|
+
run "chown #{owner} #{full_path}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def delete_dir(full_path)
|
49
|
+
if dir_exists? full_path
|
50
|
+
run "rm -Rf #{full_path}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def delete_file(full_path)
|
55
|
+
if file_exists? full_path
|
56
|
+
run "rm #{full_path}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
#
|
61
|
+
# working with git
|
62
|
+
#
|
63
|
+
def branch?(full_path)
|
64
|
+
capture("cd #{full_path} && git branch | grep '*'")
|
65
|
+
end
|
66
|
+
|
67
|
+
def on_branch?(full_path, branch)
|
68
|
+
branch?(full_path).include? branch
|
69
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
|
2
|
+
Capistrano::Configuration.instance.load do
|
3
|
+
|
4
|
+
require 'capistrano'
|
5
|
+
require 'ratchetify/helpers'
|
6
|
+
require 'ratchetify/setup'
|
7
|
+
require 'ratchetify/domain'
|
8
|
+
require 'ratchetify/service'
|
9
|
+
|
10
|
+
before "create:rails", "setup:environment"
|
11
|
+
after "create:rails", "service:create"
|
12
|
+
after "create:rails", "domain:add"
|
13
|
+
|
14
|
+
desc "Deploy an app for the first time"
|
15
|
+
namespace :create do
|
16
|
+
|
17
|
+
desc "Deploy an RAILS app to uberspace"
|
18
|
+
task :rails do
|
19
|
+
create_repo
|
20
|
+
create_and_configure_database
|
21
|
+
create_reverse_proxy
|
22
|
+
config_rails_app
|
23
|
+
finalize
|
24
|
+
end
|
25
|
+
|
26
|
+
task :create_repo do
|
27
|
+
# clone the repo first
|
28
|
+
git_cmd = "cd #{deploy_root} && git clone #{fetch :repo} #{fetch :application}"
|
29
|
+
|
30
|
+
run git_cmd do |channel, stream, out|
|
31
|
+
if out =~ /Password:/
|
32
|
+
channel.send_data("#{fetch :repo_password}\n")
|
33
|
+
else
|
34
|
+
puts out
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# switch to the specified branch
|
39
|
+
run "cd #{deploy_dir} && git checkout -b #{fetch :branch}" unless on_branch? deploy_dir, "#{fetch :branch}"
|
40
|
+
|
41
|
+
end # task :create_repo
|
42
|
+
|
43
|
+
task :create_and_configure_database do
|
44
|
+
|
45
|
+
# extract user & password
|
46
|
+
my_cnf = capture('cat ~/.my.cnf')
|
47
|
+
|
48
|
+
my_cnf.match(/^user=(\w+)/)
|
49
|
+
mysql_user = $1
|
50
|
+
my_cnf.match(/^password=(\w+)/)
|
51
|
+
mysql_pwd = $1
|
52
|
+
|
53
|
+
# create the database
|
54
|
+
mysql_database = "#{user}_#{application}" # 'application' MUST NOT contain any '-' !!!
|
55
|
+
run "mysql -e 'CREATE DATABASE IF NOT EXISTS #{mysql_database} CHARACTER SET utf8 COLLATE utf8_general_ci;'"
|
56
|
+
|
57
|
+
# create the database.yml file
|
58
|
+
database_yml = <<-EOF
|
59
|
+
production:
|
60
|
+
adapter: mysql2
|
61
|
+
encoding: utf8
|
62
|
+
database: #{mysql_database}
|
63
|
+
pool: 15
|
64
|
+
username: #{mysql_user}
|
65
|
+
password: #{mysql_pwd}
|
66
|
+
host: localhost
|
67
|
+
socket: /var/lib/mysql/mysql.sock
|
68
|
+
timeout: 10000
|
69
|
+
|
70
|
+
EOF
|
71
|
+
# upload the database.yml file
|
72
|
+
put database_yml, "#{deploy_dir}/config/database.yml"
|
73
|
+
|
74
|
+
end # task :create_and_configure_database
|
75
|
+
|
76
|
+
task :create_reverse_proxy do
|
77
|
+
|
78
|
+
# .htaccess
|
79
|
+
htaccess = <<-EOF
|
80
|
+
RewriteEngine On
|
81
|
+
RewriteBase /
|
82
|
+
RewriteCond %{REQUEST_FILENAME} !-f
|
83
|
+
RewriteRule ^(.*)$ http://localhost:#{daemon_port}/$1 [P]
|
84
|
+
EOF
|
85
|
+
|
86
|
+
# place the .htaccess file
|
87
|
+
put htaccess, "#{deploy_dir}/.htaccess"
|
88
|
+
run "chmod +r #{deploy_dir}/.htaccess"
|
89
|
+
|
90
|
+
end # task :create_reverse_proxy
|
91
|
+
|
92
|
+
task :config_rails_app do
|
93
|
+
# run bundle install first
|
94
|
+
run "cd #{deploy_dir} && bundle install --path ~/.gem"
|
95
|
+
|
96
|
+
# application.yml should normally be on the .gitignore list, however you application might need
|
97
|
+
# a basic configuration file to e.g. load seed data. Provide such a basic file as 'application.example.yml'
|
98
|
+
# and it will be used to configure the app initially.
|
99
|
+
|
100
|
+
# create a default application.yml file if non was provided
|
101
|
+
if not file_exists? "#{deploy_dir}/config/application.yml"
|
102
|
+
if file_exists? "#{deploy_dir}/config/application.example.yml"
|
103
|
+
run "cd #{deploy_dir}/config && cp application.example.yml application.yml"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# run rake db:migrate to create all tables etc
|
108
|
+
run "cd #{deploy_dir} && bundle exec rake db:migrate RAILS_ENV=#{fetch :environment}"
|
109
|
+
|
110
|
+
# run rake db:seed to load seed data
|
111
|
+
run "cd #{deploy_dir} && bundle exec rake db:seed RAILS_ENV=#{fetch :environment}"
|
112
|
+
|
113
|
+
# compile assets from the asset pipeline
|
114
|
+
run "cd #{deploy_dir} && bundle exec rake assets:precompile RAILS_ENV=#{fetch :environment}"
|
115
|
+
|
116
|
+
# create symbolic links so that apache will find the assets
|
117
|
+
run "cd #{deploy_dir} && ln -s public/assets assets"
|
118
|
+
end
|
119
|
+
|
120
|
+
task :finalize do
|
121
|
+
# create symbolic links..
|
122
|
+
run "cd #{webroot_dir} && ln -s #{deploy_dir} #{fetch :host}.#{fetch :domain}"
|
123
|
+
run "cd #{webroot_dir} && ln -s #{deploy_dir} #{fetch :domain}" unless (wildcard_domain == false)
|
124
|
+
end
|
125
|
+
|
126
|
+
end # namespace
|
127
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
|
2
|
+
Capistrano::Configuration.instance.load do
|
3
|
+
|
4
|
+
desc "Setup ruby interpreter and tools"
|
5
|
+
namespace :setup do
|
6
|
+
desc "Setup ruby interpreter and tools"
|
7
|
+
task :ruby do
|
8
|
+
|
9
|
+
# script to setup ruby
|
10
|
+
ruby_script = <<-EOF
|
11
|
+
|
12
|
+
# ruby #{ruby_version} environment
|
13
|
+
export PATH=/package/host/localhost/ruby-#{ruby_version}/bin:$PATH
|
14
|
+
export PATH=$HOME/.gem/ruby/#{ruby_version}/bin:$PATH
|
15
|
+
EOF
|
16
|
+
|
17
|
+
# setup the ruby environment
|
18
|
+
put ruby_script, "/home/#{user}/ruby_scrip"
|
19
|
+
run "cat /home/#{user}/ruby_scrip >> /home/#{user}/.bashrc"
|
20
|
+
|
21
|
+
# configure ruby
|
22
|
+
run "echo 'gem: --user-install --no-rdoc --no-ri' > ~/.gemrc"
|
23
|
+
run "gem install bundler"
|
24
|
+
|
25
|
+
# cleanup
|
26
|
+
run "rm /home/#{user}/ruby_scrip"
|
27
|
+
|
28
|
+
end # task :ruby
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
|
2
|
+
Capistrano::Configuration.instance.load do
|
3
|
+
|
4
|
+
require 'capistrano'
|
5
|
+
require 'ratchetify/helpers'
|
6
|
+
|
7
|
+
desc "Tasks to start/stop/restart the app server"
|
8
|
+
namespace :service do
|
9
|
+
desc "Start the app server"
|
10
|
+
task :start do
|
11
|
+
run "svc -u ~/service/#{daemon_service}"
|
12
|
+
end
|
13
|
+
|
14
|
+
desc "Stop the app server"
|
15
|
+
task :stop do
|
16
|
+
run "svc -d ~/service/#{daemon_service}"
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "Restart the app server"
|
20
|
+
task :restart do
|
21
|
+
run "svc -du ~/service/#{daemon_service}"
|
22
|
+
end
|
23
|
+
|
24
|
+
task :create do
|
25
|
+
create_service_thin # the only option for now
|
26
|
+
|
27
|
+
# register the service
|
28
|
+
run "uberspace-setup-service #{daemon_service} ~/bin/#{daemon_service}"
|
29
|
+
|
30
|
+
end # task :create_service
|
31
|
+
|
32
|
+
task :create_service_thin do
|
33
|
+
# script to start thin
|
34
|
+
script = <<-EOF
|
35
|
+
#!/bin/bash
|
36
|
+
export HOME=/home/#{user}
|
37
|
+
source $HOME/.bash_profile
|
38
|
+
cd #{deploy_dir}
|
39
|
+
exec /home/#{user}/.gem/ruby/#{ruby_version}/bin/bundle exec thin start -p #{daemon_port} -e production 2>&1
|
40
|
+
EOF
|
41
|
+
|
42
|
+
# upload the run script
|
43
|
+
put script, "/home/#{user}/bin/#{daemon_service}"
|
44
|
+
run "chmod 755 /home/#{user}/bin/#{daemon_service}"
|
45
|
+
|
46
|
+
end # task :create_service_thin
|
47
|
+
|
48
|
+
task :create_service_unicorn do
|
49
|
+
# script to start unicorn
|
50
|
+
script = <<-EOF
|
51
|
+
#!/bin/bash
|
52
|
+
export HOME=/home/#{user}
|
53
|
+
source $HOME/.bash_profile
|
54
|
+
cd #{deploy_dir}
|
55
|
+
exec /home/#{user}/.gem/ruby/#{ruby_version}/bin/bundle exec unicorn -p #{daemon_port} -c ./config/unicorn.rb -E #{environment} 2>&1
|
56
|
+
EOF
|
57
|
+
|
58
|
+
# upload the run script
|
59
|
+
put script, "/home/#{user}/bin/#{daemon_service}"
|
60
|
+
run "chmod 755 /home/#{user}/bin/#{daemon_service}"
|
61
|
+
|
62
|
+
# script to configure unicorn
|
63
|
+
unicorn_rb = <<-EOF
|
64
|
+
# config/unicorn.rb
|
65
|
+
worker_processes 3
|
66
|
+
timeout 15
|
67
|
+
preload_app true
|
68
|
+
|
69
|
+
before_fork do |server, worker|
|
70
|
+
Signal.trap 'TERM' do
|
71
|
+
puts 'Unicorn master intercepting TERM and sending myself QUIT instead'
|
72
|
+
Process.kill 'QUIT', Process.pid
|
73
|
+
end
|
74
|
+
|
75
|
+
defined?(ActiveRecord::Base) and
|
76
|
+
ActiveRecord::Base.connection.disconnect!
|
77
|
+
end
|
78
|
+
|
79
|
+
after_fork do |server, worker|
|
80
|
+
Signal.trap 'TERM' do
|
81
|
+
puts 'Unicorn worker intercepting TERM and doing nothing. Wait for master to send QUIT'
|
82
|
+
end
|
83
|
+
|
84
|
+
defined?(ActiveRecord::Base) and
|
85
|
+
ActiveRecord::Base.establish_connection
|
86
|
+
end
|
87
|
+
EOF
|
88
|
+
|
89
|
+
# upload the unicorn config file, if it does not exist
|
90
|
+
put unicorn_rb, "#{deploy_dir}/config/unicorn.rb" unless file_exists? "#{deploy_dir}/config/unicorn.rb"
|
91
|
+
|
92
|
+
end # task :create_service_unicorn
|
93
|
+
|
94
|
+
desc "Remove the service"
|
95
|
+
task :remove do
|
96
|
+
script = <<-EOF
|
97
|
+
cd ~/service/#{daemon_service}
|
98
|
+
rm ~/service/#{daemon_service}
|
99
|
+
svc -dx . log
|
100
|
+
rm -rf ~/etc/run-#{daemon_service}
|
101
|
+
EOF
|
102
|
+
|
103
|
+
unless not file_exists? "~/etc/run-#{daemon_service}"
|
104
|
+
# upload script
|
105
|
+
put script, "/home/#{user}/rm-#{daemon_service}"
|
106
|
+
run "chmod 755 /home/#{user}/rm-#{daemon_service}"
|
107
|
+
|
108
|
+
# remove the service
|
109
|
+
run ". ~/rm-#{daemon_service}"
|
110
|
+
|
111
|
+
# cleanup
|
112
|
+
run "rm /home/#{user}/rm-#{daemon_service}"
|
113
|
+
end
|
114
|
+
|
115
|
+
end # task :remove
|
116
|
+
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
|
2
|
+
Capistrano::Configuration.instance.load do
|
3
|
+
|
4
|
+
require 'capistrano'
|
5
|
+
require 'ratchetify/helpers'
|
6
|
+
require 'ratchetify/ruby'
|
7
|
+
|
8
|
+
desc "Prepare a new uberspace for deployment"
|
9
|
+
namespace :setup do
|
10
|
+
|
11
|
+
desc "Prepare an uberspace for deployment"
|
12
|
+
task :default do
|
13
|
+
environment
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "Create dirs, configure ruby, activate daemontools, ..."
|
17
|
+
task :environment do
|
18
|
+
|
19
|
+
unless file_exists? '.ratchet'
|
20
|
+
|
21
|
+
puts "Initializing uberspace '#{user}'"
|
22
|
+
|
23
|
+
# save the current .bashrc
|
24
|
+
run "cp .bashrc bashrc.bak"
|
25
|
+
|
26
|
+
# create the necessary folders
|
27
|
+
create_dir deploy_root unless dir_exists? deploy_root
|
28
|
+
create_dir conf_dir unless dir_exists? conf_dir
|
29
|
+
run "ln -s #{deploy_root} apps"
|
30
|
+
|
31
|
+
# dummy main
|
32
|
+
create_dir "#{deploy_root}/main"
|
33
|
+
|
34
|
+
# remove default html and symbolic link
|
35
|
+
run "rm -rf #{webroot_dir}/html"
|
36
|
+
run "rm -rf /home/#{user}/html"
|
37
|
+
|
38
|
+
# enable ruby
|
39
|
+
ruby
|
40
|
+
# activate the daemontools
|
41
|
+
run "uberspace-setup-svscan" unless dir_exists? 'service'
|
42
|
+
|
43
|
+
# done
|
44
|
+
run "touch .ratchet"
|
45
|
+
end
|
46
|
+
end # task :environment
|
47
|
+
|
48
|
+
desc "Cleans the uberspace, removes (most) changes, restores the uberspace as much as possible"
|
49
|
+
task :restore do
|
50
|
+
run "mv bashrc.bak .bashrc"
|
51
|
+
run "rm -rf .gem .gemrc .ratchet"
|
52
|
+
|
53
|
+
# restore old html folder etc
|
54
|
+
create_dir "#{webroot_dir}/html"
|
55
|
+
run "ln -s #{webroot_dir}/html html/"
|
56
|
+
|
57
|
+
# keep ./apps and ./aconf for now ...
|
58
|
+
end # task :clean
|
59
|
+
|
60
|
+
end # namespace
|
61
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
|
2
|
+
Capistrano::Configuration.instance.load do
|
3
|
+
|
4
|
+
require 'capistrano'
|
5
|
+
require 'ratchetify/helpers'
|
6
|
+
require 'ratchetify/service'
|
7
|
+
|
8
|
+
before "undeploy", "service:remove"
|
9
|
+
|
10
|
+
desc "Undeploy an app from uberspace"
|
11
|
+
namespace :undeploy do
|
12
|
+
|
13
|
+
desc "Undeploy an app from uberspace"
|
14
|
+
task :default do
|
15
|
+
drop_database
|
16
|
+
remove_repo
|
17
|
+
end
|
18
|
+
|
19
|
+
task :drop_database do
|
20
|
+
mysql_database = "#{user}_#{application}" # 'application' MUST NOT contain any '-' !!!
|
21
|
+
run "mysql -e 'DROP DATABASE IF EXISTS #{mysql_database};'"
|
22
|
+
end
|
23
|
+
|
24
|
+
task :remove_repo do
|
25
|
+
run "cd #{deploy_root} && rm -rf #{fetch :application}"
|
26
|
+
run "cd #{webroot_dir} && rm -rf #{fetch :host}.#{fetch :domain}"
|
27
|
+
run "cd #{webroot_dir} && rm -rf #{fetch :domain}" unless (wildcard_domain == false)
|
28
|
+
end
|
29
|
+
|
30
|
+
end # namespace
|
31
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
|
2
|
+
Capistrano::Configuration.instance.load do
|
3
|
+
|
4
|
+
require 'capistrano'
|
5
|
+
require 'ratchetify/helpers'
|
6
|
+
require 'ratchetify/service'
|
7
|
+
|
8
|
+
before :update, "service:stop"
|
9
|
+
after :update, "service:start"
|
10
|
+
|
11
|
+
desc "Tasks to update an app"
|
12
|
+
namespace :update do
|
13
|
+
|
14
|
+
desc "Stop the service, update the app then restart"
|
15
|
+
task :default do
|
16
|
+
# switch to the specified branch
|
17
|
+
run "cd #{deploy_dir} && git checkout -b #{fetch :branch}" unless on_branch? deploy_dir, "#{fetch :branch}"
|
18
|
+
|
19
|
+
# update the repo
|
20
|
+
git_cmd = "cd #{deploy_dir} && git pull origin #{fetch :branch}"
|
21
|
+
|
22
|
+
run git_cmd do |channel, stream, out|
|
23
|
+
if out =~ /Password:/
|
24
|
+
channel.send_data("#{fetch :repo_password}\n")
|
25
|
+
else
|
26
|
+
puts out
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
#
|
31
|
+
# typical RAILS stuff to finalize
|
32
|
+
#
|
33
|
+
|
34
|
+
# run bundle install first
|
35
|
+
run "cd #{deploy_dir} && bundle install --path ~/.gem"
|
36
|
+
|
37
|
+
# run rake db:migrate to create all tables etc
|
38
|
+
run "cd #{deploy_dir} && bundle exec rake db:migrate RAILS_ENV=#{fetch :environment}"
|
39
|
+
|
40
|
+
# compile assets from the asset pipeline
|
41
|
+
run "cd #{deploy_dir} && bundle exec rake assets:precompile RAILS_ENV=#{fetch :environment}"
|
42
|
+
|
43
|
+
end # end task :default
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
|
2
|
+
Capistrano::Configuration.instance.load do
|
3
|
+
|
4
|
+
require 'capistrano'
|
5
|
+
require 'ratchetify/helpers'
|
6
|
+
require 'ratchetify/setup'
|
7
|
+
require 'ratchetify/domain'
|
8
|
+
|
9
|
+
before "create:wordpress", "setup:environment"
|
10
|
+
after "create:wordpress", "domain:add"
|
11
|
+
|
12
|
+
desc "Deploy an app for the first time"
|
13
|
+
namespace :create do
|
14
|
+
|
15
|
+
desc "Deploy an wordpress blog to uberspace"
|
16
|
+
task :wordpress do
|
17
|
+
create_web_dir
|
18
|
+
create_database
|
19
|
+
finalize
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
task :create_web_dir do
|
24
|
+
# download the worpress .tar
|
25
|
+
unless dir_exists? deploy_dir
|
26
|
+
# download wp and unpack it
|
27
|
+
run "cd #{webroot_dir} && curl -O https://s3-eu-west-1.amazonaws.com/ratchetp/wordpress-3.8.1.tar.gz"
|
28
|
+
#run "cd #{deploy_root} && mkdir wp_tmp"
|
29
|
+
run "cd #{webroot_dir} && tar xfz wordpress* -C #{deploy_root}"
|
30
|
+
run "cd #{deploy_root} && mv wordpress #{application}"
|
31
|
+
|
32
|
+
# cleanup
|
33
|
+
#run "cd #{deploy_root} && rm wordpress*"
|
34
|
+
run "cd #{webroot_dir} && rm -rf wordpress*"
|
35
|
+
|
36
|
+
# rename word press to -> :application
|
37
|
+
#run "cd #{deploy_root} && mv ./wordpress #{application}"
|
38
|
+
end
|
39
|
+
|
40
|
+
end # task :create_dir
|
41
|
+
|
42
|
+
task :create_database do
|
43
|
+
|
44
|
+
# extract user & password
|
45
|
+
my_cnf = capture('cat ~/.my.cnf')
|
46
|
+
|
47
|
+
my_cnf.match(/^user=(\w+)/)
|
48
|
+
mysql_user = $1
|
49
|
+
my_cnf.match(/^password=(\w+)/)
|
50
|
+
mysql_pwd = $1
|
51
|
+
my_cnf.match(/^port=(\w+)/)
|
52
|
+
mysql_port = $1
|
53
|
+
|
54
|
+
# create the database
|
55
|
+
mysql_database = "#{user}_#{application}" # 'application' MUST NOT contain any '-' !!!
|
56
|
+
run "mysql -e 'CREATE DATABASE IF NOT EXISTS #{mysql_database} CHARACTER SET utf8 COLLATE utf8_general_ci;'"
|
57
|
+
|
58
|
+
database_yml = <<-EOF
|
59
|
+
database: #{mysql_database}
|
60
|
+
username: #{mysql_user}
|
61
|
+
password: #{mysql_pwd}
|
62
|
+
host: localhost
|
63
|
+
port: #{mysql_port}
|
64
|
+
|
65
|
+
EOF
|
66
|
+
|
67
|
+
# upload the database.yml file
|
68
|
+
put database_yml, "#{deploy_dir}/database.yml"
|
69
|
+
|
70
|
+
end # task :create_database
|
71
|
+
|
72
|
+
task :finalize do
|
73
|
+
# create symbolic links..
|
74
|
+
run "cd #{webroot_dir} && ln -s #{deploy_dir} #{fetch :host}.#{fetch :domain}"
|
75
|
+
run "cd #{webroot_dir} && ln -s #{deploy_dir} #{fetch :domain}" unless (wildcard_domain == false)
|
76
|
+
end # task :finalize
|
77
|
+
|
78
|
+
end # namespace
|
79
|
+
end
|
data/lib/ratchetify.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'ratchetify/version'
|
2
|
+
|
3
|
+
Capistrano::Configuration.instance.load do
|
4
|
+
|
5
|
+
require 'capistrano'
|
6
|
+
require 'ratchetify/helpers'
|
7
|
+
require 'ratchetify/setup'
|
8
|
+
require 'ratchetify/ruby'
|
9
|
+
require 'ratchetify/service'
|
10
|
+
require 'ratchetify/undeploy'
|
11
|
+
require 'ratchetify/domain'
|
12
|
+
require 'ratchetify/rails'
|
13
|
+
require 'ratchetify/wordpress'
|
14
|
+
require 'ratchetify/update'
|
15
|
+
require 'ratchetify/help' # monkey patched from capistrano
|
16
|
+
|
17
|
+
# host and domain for the new app
|
18
|
+
set :domain, nil
|
19
|
+
set :host, nil
|
20
|
+
set :wildcard_domain, false
|
21
|
+
|
22
|
+
# random port used for the reverse proxy
|
23
|
+
set :daemon_port, rand(61000-32768+1)+32768 # random port
|
24
|
+
set :type, :rails # supported types are: :rails, :wordpress,
|
25
|
+
|
26
|
+
# internal variables, should not be changed in the cap file
|
27
|
+
set :ruby_version, "2.0.0"
|
28
|
+
set :environment, 'production'
|
29
|
+
set :is_main, false
|
30
|
+
|
31
|
+
end
|
data/ratchetify.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/ratchetify/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Michael Kuehl"]
|
6
|
+
gem.license = 'MIT'
|
7
|
+
gem.email = ["michael@ratchet.cc"]
|
8
|
+
gem.description = %q{Deploy Rails apps on Uberspace}
|
9
|
+
gem.summary = %q{Ratchetify helps you deploy a Ruby on Rails app on uberspace.de, a popular German shared hosting provider.}
|
10
|
+
gem.homepage = "https://github.com/ratchetcc/ratchetify"
|
11
|
+
|
12
|
+
gem.files = `git ls-files`.split($\)
|
13
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
14
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
15
|
+
gem.name = "ratchetify"
|
16
|
+
gem.require_paths = ["lib"]
|
17
|
+
gem.version = Ratchetify::VERSION
|
18
|
+
|
19
|
+
# dependencies for capistrano
|
20
|
+
gem.add_dependency 'capistrano', '2.12.0'
|
21
|
+
|
22
|
+
# dependency for mysql on Uberspace
|
23
|
+
gem.add_dependency 'mysql2', '>=0.3.11'
|
24
|
+
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ratchetify
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Michael Kuehl
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-04-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: capistrano
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.12.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.12.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: mysql2
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.3.11
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.3.11
|
41
|
+
description: Deploy Rails apps on Uberspace
|
42
|
+
email:
|
43
|
+
- michael@ratchet.cc
|
44
|
+
executables:
|
45
|
+
- rat
|
46
|
+
extensions: []
|
47
|
+
extra_rdoc_files: []
|
48
|
+
files:
|
49
|
+
- ".gitignore"
|
50
|
+
- Capfile.example
|
51
|
+
- Gemfile
|
52
|
+
- LICENSE
|
53
|
+
- README.md
|
54
|
+
- Rakefile
|
55
|
+
- bin/rat
|
56
|
+
- lib/ratchetify.rb
|
57
|
+
- lib/ratchetify/base.rb
|
58
|
+
- lib/ratchetify/domain.rb
|
59
|
+
- lib/ratchetify/help.rb
|
60
|
+
- lib/ratchetify/helpers.rb
|
61
|
+
- lib/ratchetify/rails.rb
|
62
|
+
- lib/ratchetify/ruby.rb
|
63
|
+
- lib/ratchetify/service.rb
|
64
|
+
- lib/ratchetify/setup.rb
|
65
|
+
- lib/ratchetify/undeploy.rb
|
66
|
+
- lib/ratchetify/update.rb
|
67
|
+
- lib/ratchetify/version.rb
|
68
|
+
- lib/ratchetify/wordpress.rb
|
69
|
+
- ratchetify.gemspec
|
70
|
+
homepage: https://github.com/ratchetcc/ratchetify
|
71
|
+
licenses:
|
72
|
+
- MIT
|
73
|
+
metadata: {}
|
74
|
+
post_install_message:
|
75
|
+
rdoc_options: []
|
76
|
+
require_paths:
|
77
|
+
- lib
|
78
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
requirements: []
|
89
|
+
rubyforge_project:
|
90
|
+
rubygems_version: 2.2.2
|
91
|
+
signing_key:
|
92
|
+
specification_version: 4
|
93
|
+
summary: Ratchetify helps you deploy a Ruby on Rails app on uberspace.de, a popular
|
94
|
+
German shared hosting provider.
|
95
|
+
test_files: []
|