magic_recipes_two 0.0.30 → 0.0.31
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.
- checksums.yaml +13 -5
- data/lib/capistrano/magic_recipes/version.rb +1 -1
- data/lib/capistrano/tasks/monit.rake +48 -72
- data/lib/capistrano/tasks/nginx.rake +7 -9
- data/lib/capistrano/tasks/secrets.rake +10 -1
- data/lib/capistrano/tasks/thin.rake +6 -3
- data/lib/generators/capistrano/magic_recipes/templates/monit/nginx.erb +1 -0
- data/lib/generators/capistrano/magic_recipes/templates/monit/postgresql.erb +1 -0
- data/lib/generators/capistrano/magic_recipes/templates/monit/redis.erb +1 -0
- data/lib/generators/capistrano/magic_recipes/templates/monit/sidekiq.erb +1 -0
- data/lib/generators/capistrano/magic_recipes/templates/monit/thin.erb +1 -0
- metadata +17 -17
checksums.yaml
CHANGED
@@ -1,7 +1,15 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MWVhMzk1NzEzYTA3NTMyYzZhNzk4NjhhMjVkNjA5MTVjODY0MzRjMg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
YzExOTY3MDAzYWNkZTM2Y2I4NjE2MjQyYzc4MWI1ZjhlYTQ5MTIxMg==
|
5
7
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NDUwYWM0NzE2MWUxZWNlMjMzMTBiODRiOTYxM2JkN2Q3MmYxYzgxMGZhMGRh
|
10
|
+
NzU4Yjc5YzllYzlkODg3NWJkYmJkZmFmNGY0ZmUyZmI2ODNjNzI3NDQwN2Yx
|
11
|
+
M2Q1MmRjZGQxNzA0MWM3ODM2NjUyMjMxMzZlMzBjZjg4NjRkOTU=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZTk1NjNmYmE4MmMzNGExYjg5OTg2N2Q1ZTFlY2Q2Y2M3Yjk5M2ExZjY2Mjk2
|
14
|
+
OTRiYmZjODE2NjFlZDY3ZTE3ZDVmNmM0MGY1YzA3MTc2OGI4MGYwNjZkZWQx
|
15
|
+
MWFhNjZkMzA3OTIwODg1OWRhY2NlZjNkNDc4YjcxZjUxNGI2ZTY=
|
@@ -6,9 +6,14 @@ namespace :load do
|
|
6
6
|
set :monit_roles, -> { :web }
|
7
7
|
set :monit_interval, -> { 30 }
|
8
8
|
set :monit_bin, -> { '/usr/bin/monit' }
|
9
|
-
|
9
|
+
## Monit default: '/var/log/monit.log'
|
10
|
+
set :monit_logfile, -> { "#{shared_path}/log/monit.log" }
|
10
11
|
set :monit_idfile, -> { '/var/lib/monit/id' }
|
11
12
|
set :monit_statefile, -> { '/var/lib/monit/state' }
|
13
|
+
## Status
|
14
|
+
set :monit_active, -> { true }
|
15
|
+
# set :monit_processes, -> { %w[nginx postgresql redis sidekiq thin] }
|
16
|
+
set :monit_processes, -> { %w[nginx postgresql thin] }
|
12
17
|
## Mailer
|
13
18
|
set :monit_mail_server, -> { "smtp.gmail.com" }
|
14
19
|
set :monit_mail_port, -> { 587 }
|
@@ -56,9 +61,8 @@ namespace :monit do
|
|
56
61
|
# invoke "monit:redis"
|
57
62
|
# invoke "monit:thin"
|
58
63
|
# invoke "monit:configure_website"
|
59
|
-
|
60
64
|
%w[nginx postgresql redis sidekiq thin].each do |command|
|
61
|
-
invoke "monit:configure_#{command}"
|
65
|
+
invoke "monit:configure_#{command}" if Array(fetch(:monit_processes)).include?(command)
|
62
66
|
end
|
63
67
|
end
|
64
68
|
invoke "monit:syntax"
|
@@ -66,79 +70,50 @@ namespace :monit do
|
|
66
70
|
end
|
67
71
|
# after "deploy:setup", "monit:setup"
|
68
72
|
|
69
|
-
# task(:nginx, roles: :web) { monit_config "nginx" }
|
70
|
-
# task(:postgresql, roles: :db) { monit_config "postgresql" }
|
71
|
-
# task(:unicorn, roles: :app) { monit_config "unicorn" }
|
72
|
-
|
73
|
-
## Server specific tasks (gets overwritten by other environments!)
|
74
|
-
|
75
73
|
|
76
74
|
%w[nginx postgresql redis sidekiq thin].each do |process|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
75
|
+
if Array(fetch(:monit_processes)).include?(process)
|
76
|
+
|
77
|
+
%w[monitor unmonitor start stop restart].each do |command|
|
78
|
+
desc "#{command} monit-service for: #{process}"
|
79
|
+
task "#{command}_#{process}" do
|
80
|
+
on roles(fetch(:sidekiq_roles)) do
|
81
|
+
if process == "sidekiq"
|
82
|
+
fetch(:sidekiq_processes).times do |idx|
|
83
|
+
sudo "#{fetch(:monit_bin)} #{command} #{sidekiq_service_name(idx)}"
|
84
|
+
end
|
85
|
+
elsif process == "thin"
|
86
|
+
fetch(:app_instances).times do |idx|
|
87
|
+
sudo "#{fetch(:monit_bin)} #{command} #{fetch(:application)}_#{fetch(:stage)}_thin_#{idx}"
|
88
|
+
end
|
89
|
+
else
|
90
|
+
sudo "#{fetch(:monit_bin)} #{command} #{process}"
|
89
91
|
end
|
90
|
-
else
|
91
|
-
sudo "#{fetch(:monit_bin)} #{command} #{process}"
|
92
92
|
end
|
93
93
|
end
|
94
94
|
end
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
95
|
+
|
96
|
+
if %w[nginx postgresql redis].include?(process)
|
97
|
+
## Server specific tasks (gets overwritten by other environments!)
|
98
|
+
desc "Upload Monit #{process} config file (server specific)"
|
99
|
+
task "configure_#{process}" do
|
100
|
+
on release_roles fetch("#{process}_roles".to_sym) do |role|
|
101
|
+
monit_config( process, nil, role )
|
102
|
+
end
|
103
103
|
end
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
104
|
+
elsif %w[sidekiq thin].include?(process)
|
105
|
+
## App specific tasks (unique for app and environment)
|
106
|
+
desc "Upload Monit #{process} config file (app specific)"
|
107
|
+
task "configure_#{process}" do
|
108
|
+
on release_roles fetch("#{process}_roles".to_sym) do |role|
|
109
|
+
monit_config process, "/etc/monit/conf.d/#{fetch(:application)}_#{fetch(:stage)}_#{process}.conf", role
|
110
|
+
end
|
111
111
|
end
|
112
112
|
end
|
113
|
+
|
113
114
|
end
|
114
|
-
|
115
115
|
end
|
116
116
|
|
117
|
-
# => desc "Upload Monit website config file (server specific)"
|
118
|
-
# => task :configure_website do
|
119
|
-
# => on release_roles :web do |role|
|
120
|
-
# => monit_config( "website", nil, role )
|
121
|
-
# => end
|
122
|
-
# => end
|
123
|
-
|
124
|
-
# => %w[nginx postgresql redis].each do |command|
|
125
|
-
# => desc "Upload Monit #{command} config file (server specific)"
|
126
|
-
# => task command do
|
127
|
-
# => on release_roles fetch("#{command}_roles".to_sym) do |role|
|
128
|
-
# => monit_config( command, nil, role )
|
129
|
-
# => end
|
130
|
-
# => end
|
131
|
-
# => end
|
132
|
-
# =>
|
133
|
-
# => ## App specific tasks (unique for app and environment)
|
134
|
-
# => %w[sidekiq thin].each do |command|
|
135
|
-
# => desc "Upload Monit #{command} config file (app specific)"
|
136
|
-
# => task command do
|
137
|
-
# => on release_roles fetch("#{command}_roles".to_sym) do |role|
|
138
|
-
# => monit_config command, "/etc/monit/conf.d/#{fetch(:application)}_#{fetch(:stage)}_#{command}.conf", role
|
139
|
-
# => end
|
140
|
-
# => end
|
141
|
-
# => end
|
142
117
|
|
143
118
|
%w[start stop restart syntax reload].each do |command|
|
144
119
|
desc "Run Monit #{command} script"
|
@@ -159,12 +134,6 @@ def monit_config( name, destination = nil, role = nil )
|
|
159
134
|
@role = role
|
160
135
|
destination ||= "/etc/monit/conf.d/#{name}.conf"
|
161
136
|
template_with_role "monit/#{name}", "/tmp/monit_#{name}", @role
|
162
|
-
# erb = File.read(File.expand_path("../../../../config/deploy/templates/monit/#{name}.erb", __FILE__))
|
163
|
-
# config = ERB.new(erb).result(binding)
|
164
|
-
# upload! StringIO.new(config), "/tmp/monit_#{name}"
|
165
|
-
# run "#{sudo} mv /tmp/monit_#{name} #{destination}"
|
166
|
-
# run "#{sudo} chown root #{destination}"
|
167
|
-
# run "#{sudo} chmod 600 #{destination}"
|
168
137
|
execute :sudo, "mv /tmp/monit_#{name} #{destination}"
|
169
138
|
execute :sudo, "chown root #{destination}"
|
170
139
|
execute :sudo, "chmod 600 #{destination}"
|
@@ -174,12 +143,19 @@ end
|
|
174
143
|
namespace :deploy do
|
175
144
|
before :starting, :stop_monitoring do
|
176
145
|
%w[sidekiq thin].each do |command|
|
177
|
-
|
146
|
+
if fetch(:monit_active) && Array(fetch(:monit_processes)).include?(command)
|
147
|
+
invoke "monit:unmonitor_#{command}"
|
148
|
+
end
|
178
149
|
end
|
179
150
|
end
|
180
151
|
after :finished, :restart_monitoring do
|
181
152
|
%w[sidekiq thin].each do |command|
|
182
|
-
|
153
|
+
if fetch(:monit_active) && Array(fetch(:monit_processes)).include?(command)
|
154
|
+
invoke "monit:monitor_#{command}"
|
155
|
+
end
|
183
156
|
end
|
184
157
|
end
|
158
|
+
after :finished, :setup_monit_configs do
|
159
|
+
invoke "monit:setup" if fetch(:monit_active)
|
160
|
+
end
|
185
161
|
end
|
@@ -24,6 +24,7 @@ namespace :load do
|
|
24
24
|
set :nginx_ssl_certificate_key, -> { "#{fetch(:application)}.crt" }
|
25
25
|
set :nginx_ssl_certificate_key_path, -> { '/etc/ssl/private' }
|
26
26
|
set :app_server_ip, -> { "127.0.0.1" }
|
27
|
+
set :nginx_hooks, -> { true }
|
27
28
|
## NginX Proxy-Caching
|
28
29
|
# Cache Rails
|
29
30
|
set :proxy_cache_rails, -> { false }
|
@@ -83,15 +84,10 @@ namespace :nginx do
|
|
83
84
|
within fetch(:sites_available) do
|
84
85
|
config_file = fetch(:nginx_template)
|
85
86
|
if config_file == :default
|
86
|
-
# config_file = File.expand_path("../../../../config/deploy/templates/nginx.conf.erb", __FILE__)
|
87
87
|
magic_template("nginx.conf", '/tmp/nginx.conf')
|
88
88
|
else
|
89
89
|
template(config_file, '/tmp/nginx.conf')
|
90
90
|
end
|
91
|
-
# config = ERB.new(File.read(config_file)).result(binding)
|
92
|
-
# upload! StringIO.new(config), '/tmp/nginx.conf'
|
93
|
-
|
94
|
-
|
95
91
|
execute :sudo, :mv, '/tmp/nginx.conf', "#{fetch(:application)}_#{fetch(:stage)}"
|
96
92
|
end
|
97
93
|
end
|
@@ -134,10 +130,12 @@ end
|
|
134
130
|
|
135
131
|
|
136
132
|
namespace :deploy do
|
137
|
-
after 'deploy:
|
138
|
-
|
139
|
-
|
140
|
-
|
133
|
+
after 'deploy:finishing', :restart_nginx_app do
|
134
|
+
if fetch(:nginx_hooks)
|
135
|
+
invoke "nginx:site:add"
|
136
|
+
invoke "nginx:site:enable"
|
137
|
+
invoke "nginx:restart"
|
138
|
+
end
|
141
139
|
end
|
142
140
|
end
|
143
141
|
|
@@ -9,6 +9,7 @@ namespace :load do
|
|
9
9
|
set :secrets_key_name, -> { "#{ fetch(:application) }_#{ fetch(:stage) }_SECRET_KEY_BASE".gsub(/-/, "_").gsub(/[^a-zA-Z_]/, "").upcase }
|
10
10
|
set :secrets_user_path, -> { "/home/#{fetch(:user)}" }
|
11
11
|
set :secrets_set_both, -> { false }
|
12
|
+
set :secrets_hooks, -> { true }
|
12
13
|
end
|
13
14
|
end
|
14
15
|
|
@@ -79,4 +80,12 @@ namespace :secrets do
|
|
79
80
|
after 'deploy:started', 'secrets:secrets_yml_symlink'
|
80
81
|
|
81
82
|
|
82
|
-
end
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
|
87
|
+
|
88
|
+
desc 'Server setup tasks'
|
89
|
+
task :setup do
|
90
|
+
invoke "secrets:setup" if fetch(:secrets_hooks)
|
91
|
+
end
|
@@ -13,6 +13,7 @@ namespace :load do
|
|
13
13
|
set :thin_require, -> { [] }
|
14
14
|
set :thin_wait, -> { 90 }
|
15
15
|
set :thin_onebyone, -> { true }
|
16
|
+
set :thin_hooks, -> { true }
|
16
17
|
|
17
18
|
end
|
18
19
|
end
|
@@ -58,9 +59,11 @@ end
|
|
58
59
|
|
59
60
|
|
60
61
|
namespace :deploy do
|
61
|
-
|
62
|
-
|
63
|
-
|
62
|
+
after 'deploy:published', :restart_thin_apps do
|
63
|
+
if fetch(:thin_hooks)
|
64
|
+
invoke "thin:reconf"
|
65
|
+
invoke "thin:restart"
|
66
|
+
end
|
64
67
|
end
|
65
68
|
end
|
66
69
|
|
@@ -2,6 +2,7 @@
|
|
2
2
|
check process nginx with pidfile /var/run/nginx.pid
|
3
3
|
start program = "/etc/init.d/nginx start"
|
4
4
|
stop program = "/etc/init.d/nginx stop"
|
5
|
+
if does not exist then alert
|
5
6
|
if children > 250 then restart
|
6
7
|
if failed host 127.0.0.1 port 80 then restart
|
7
8
|
if cpu is greater than 40% for 2 cycles then alert
|
@@ -2,5 +2,6 @@
|
|
2
2
|
check process postgresql with pidfile <%= fetch(:postgresql_pid) %>
|
3
3
|
start program = "/etc/init.d/postgresql start"
|
4
4
|
stop program = "/etc/init.d/postgresql stop"
|
5
|
+
if does not exist then alert
|
5
6
|
if failed host localhost port 5432 protocol pgsql then restart
|
6
7
|
if 5 restarts within 5 cycles then timeout
|
@@ -2,6 +2,7 @@
|
|
2
2
|
check process redis with pidfile <%= fetch(:redis_pid) %>
|
3
3
|
start program = "/etc/init.d/redis-server start"
|
4
4
|
stop program = "/etc/init.d/redis-server stop"
|
5
|
+
if does not exist then alert
|
5
6
|
if 2 restarts within 3 cycles then timeout
|
6
7
|
if totalmem > 100 Mb then alert
|
7
8
|
if children > 255 for 5 cycles then stop
|
@@ -22,6 +22,7 @@ check process <%= sidekiq_service_name(idx) %>
|
|
22
22
|
start program = "/bin/su - <%= @role.user %> -c 'cd <%= current_path %> ; bundle exec sidekiq <%= args.join(" ") %>'" with timeout 30 seconds
|
23
23
|
stop program = "/bin/su - <%= @role.user %> -c 'cd <%= current_path %> ; bundle exec sidekiqctl stop <%= pid_file %>' " with timeout <%= fetch(:sidekiq_timeout).to_i + 10 %> seconds
|
24
24
|
group <%= fetch(:sidekiq_monit_group, fetch(:application)) %>-sidekiq
|
25
|
+
if does not exist then alert
|
25
26
|
if totalmem is greater than 200 MB for 2 cycles then restart
|
26
27
|
if 3 restarts within 5 cycles then timeout
|
27
28
|
alert <%= fetch(:monit_mail_to) %> only on { pid }
|
@@ -5,6 +5,7 @@
|
|
5
5
|
group thin-<%= fetch(:stage) %>
|
6
6
|
start program = "/bin/su - <%= @role.user %> -c 'cd <%= current_path %> ;<% if fetch(:monit_thin_with_secret) %> export SECRET_KEY_BASE=<%= fetch(:secrets_key_base) %>; export <%= fetch(:secrets_key_name) %>=<%= fetch(:secrets_key_base) %>;<% end %> bundle exec thin start -C config/thin_app_<%= fetch(:stage) %>.yml -o <%= n %>' "
|
7
7
|
stop program = "/bin/su - <%= @role.user %> -c 'cd <%= current_path %> ; bundle exec thin stop -C config/thin_app_<%= fetch(:stage) %>.yml -o <%= n %>' "
|
8
|
+
if does not exist then alert
|
8
9
|
if mem > 200.0 MB for 1 cycles then restart
|
9
10
|
if cpu > 50% for 3 cycles then restart
|
10
11
|
if 5 restarts within 5 cycles then timeout
|
metadata
CHANGED
@@ -1,69 +1,69 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: magic_recipes_two
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.31
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Torsten Wetzel
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-05-
|
11
|
+
date: 2016-05-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ! '>='
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '3.2'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ! '>='
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '3.2'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: capistrano
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ! '>='
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '3.2'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ! '>='
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '3.2'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: capistrano-bundler
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ! '>='
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '1.1'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ! '>='
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '1.1'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: capistrano-rails
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ! '>='
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '1.1'
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - ! '>='
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '1.1'
|
69
69
|
- !ruby/object:Gem::Dependency
|
@@ -84,28 +84,28 @@ dependencies:
|
|
84
84
|
name: capistrano-postgresql
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- -
|
87
|
+
- - ! '>='
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: '4.2'
|
90
90
|
type: :runtime
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- -
|
94
|
+
- - ! '>='
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '4.2'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: sqlite3
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- -
|
101
|
+
- - ! '>='
|
102
102
|
- !ruby/object:Gem::Version
|
103
103
|
version: '0'
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- -
|
108
|
+
- - ! '>='
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
111
|
description: MagicRecipesTwo contains our most used deployment recipes for Capistrano-3.
|
@@ -165,17 +165,17 @@ require_paths:
|
|
165
165
|
- lib
|
166
166
|
required_ruby_version: !ruby/object:Gem::Requirement
|
167
167
|
requirements:
|
168
|
-
- -
|
168
|
+
- - ! '>='
|
169
169
|
- !ruby/object:Gem::Version
|
170
170
|
version: '0'
|
171
171
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
172
172
|
requirements:
|
173
|
-
- -
|
173
|
+
- - ! '>='
|
174
174
|
- !ruby/object:Gem::Version
|
175
175
|
version: '0'
|
176
176
|
requirements: []
|
177
177
|
rubyforge_project:
|
178
|
-
rubygems_version: 2.
|
178
|
+
rubygems_version: 2.4.8
|
179
179
|
signing_key:
|
180
180
|
specification_version: 4
|
181
181
|
summary: Some recipes for rails-4 and capistrano-3.
|