recipes_matic 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/CHANGELOG.md +6 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +66 -0
- data/Rakefile +1 -0
- data/lib/generators/recipes_matic/install_generator.rb +15 -0
- data/lib/generators/recipes_matic/templates/config/deploy.rb +41 -0
- data/lib/generators/recipes_matic/templates/config/deploy/production.rb +4 -0
- data/lib/generators/recipes_matic/templates/config/deploy/recipes/assets.rb +11 -0
- data/lib/generators/recipes_matic/templates/config/deploy/recipes/backup.rb +40 -0
- data/lib/generators/recipes_matic/templates/config/deploy/recipes/base.rb +78 -0
- data/lib/generators/recipes_matic/templates/config/deploy/recipes/check.rb +13 -0
- data/lib/generators/recipes_matic/templates/config/deploy/recipes/db.rb +15 -0
- data/lib/generators/recipes_matic/templates/config/deploy/recipes/monit.rb +37 -0
- data/lib/generators/recipes_matic/templates/config/deploy/recipes/nginx.rb +36 -0
- data/lib/generators/recipes_matic/templates/config/deploy/recipes/postgresql.rb +34 -0
- data/lib/generators/recipes_matic/templates/config/deploy/recipes/symlinks.rb +8 -0
- data/lib/generators/recipes_matic/templates/config/deploy/recipes/templates/backup_model.erb +35 -0
- data/lib/generators/recipes_matic/templates/config/deploy/recipes/templates/database.yml.erb +11 -0
- data/lib/generators/recipes_matic/templates/config/deploy/recipes/templates/maintenance.html.erb +33 -0
- data/lib/generators/recipes_matic/templates/config/deploy/recipes/templates/monit/monitrc.erb +26 -0
- data/lib/generators/recipes_matic/templates/config/deploy/recipes/templates/monit/nginx.erb +5 -0
- data/lib/generators/recipes_matic/templates/config/deploy/recipes/templates/monit/postgresql.erb +5 -0
- data/lib/generators/recipes_matic/templates/config/deploy/recipes/templates/monit/unicorn.erb +3 -0
- data/lib/generators/recipes_matic/templates/config/deploy/recipes/templates/nginx.production.erb +36 -0
- data/lib/generators/recipes_matic/templates/config/deploy/recipes/templates/nginx.staging.erb +36 -0
- data/lib/generators/recipes_matic/templates/config/deploy/recipes/templates/unicorn.rb.erb +36 -0
- data/lib/generators/recipes_matic/templates/config/deploy/recipes/templates/unicorn_init.erb +75 -0
- data/lib/generators/recipes_matic/templates/config/deploy/recipes/unicorn.rb +28 -0
- data/lib/generators/recipes_matic/templates/config/deploy/recipes/whenever.rb +16 -0
- data/lib/generators/recipes_matic/templates/config/deploy/staging.rb +4 -0
- data/lib/recipes_matic.rb +5 -0
- data/lib/recipes_matic/version.rb +3 -0
- data/recipes_matic.gemspec +23 -0
- metadata +107 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: beb3dbd6e6ce20b2c2641bc6c58da6220575a1f8
|
4
|
+
data.tar.gz: 6e642ff59b08a3719ddb9aaeef0b8fac44b8eb17
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 37955c402aa8207abc84ad104520a7423611977da39ca4d15c6e78473162869149ab98b01299d7e2dd64f627f31f3d2e11f271b7ed3ea6eabbc3ea315909439f
|
7
|
+
data.tar.gz: dc9f6f7c39522c815d683f2bb01cfa506c6c2797d6d4c6017ac87629ad524c9121f5f409af1bf24abdc772cfc2f1d139684fb392f9a55d342c55228d3665ba6f
|
data/.gitignore
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 lab2023 – internet technologies
|
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,66 @@
|
|
1
|
+
# RecipesMatic
|
2
|
+
|
3
|
+
Copy beautiful recipes into project
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'recipes_matic'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install recipes_matic
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
Add following gem to Gemfile
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
gem 'capistrano', '~> 2.15.5'
|
25
|
+
gem 'capistrano-ext', '~> 1.2.1'
|
26
|
+
gem 'unicorn', '~> 4.6.3'
|
27
|
+
```
|
28
|
+
|
29
|
+
And then execute
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
bundle install
|
33
|
+
capify .
|
34
|
+
rails g recipes_matic:install
|
35
|
+
```
|
36
|
+
|
37
|
+
Now edit `config/deploy.rb`, `config/deploy/staging.rb` and `config/deploy/production.rb`
|
38
|
+
|
39
|
+
If install server package for ruby and rails run the following command
|
40
|
+
`cap deploy:install`
|
41
|
+
|
42
|
+
and execute
|
43
|
+
|
44
|
+
`cap staging deploy:setup`
|
45
|
+
`cap staging deploy:cold`
|
46
|
+
|
47
|
+
Finish...
|
48
|
+
|
49
|
+
## Contributing
|
50
|
+
|
51
|
+
1. Fork it
|
52
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
53
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
54
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
55
|
+
5. Create new Pull Request
|
56
|
+
|
57
|
+
## Credits
|
58
|
+
|
59
|
+
- Cybele is maintained and funded by [lab2023 - internet technologies](http://lab2023.com/)
|
60
|
+
- Thank you to all the [contributors!](https://github.com/kebab-project/recipes_matic/graphs/contributors)
|
61
|
+
- The names and logos for lab2023 are trademarks of lab2023, inc.
|
62
|
+
|
63
|
+
## License
|
64
|
+
|
65
|
+
Copyright 2013 lab2023 – internet technologies
|
66
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
require 'rails/generators/base'
|
3
|
+
module RecipesMatic
|
4
|
+
module Generators
|
5
|
+
class InstallGenerator < ::Rails::Generators::Base
|
6
|
+
desc 'Copy recipes into project'
|
7
|
+
source_root File.expand_path('../templates', __FILE__)
|
8
|
+
|
9
|
+
def copy_deploy_file
|
10
|
+
directory 'config/deploy', 'config/deploy'
|
11
|
+
copy_file 'config/deploy.rb', 'config/deploy.rb'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'bundler/capistrano'
|
2
|
+
require 'capistrano/ext/multistage'
|
3
|
+
#require 'whenever/capistrano'
|
4
|
+
|
5
|
+
load 'config/deploy/recipes/base'
|
6
|
+
load 'config/deploy/recipes/backup'
|
7
|
+
load 'config/deploy/recipes/check'
|
8
|
+
load 'config/deploy/recipes/db'
|
9
|
+
load 'config/deploy/recipes/nginx'
|
10
|
+
load 'config/deploy/recipes/symlinks'
|
11
|
+
load 'config/deploy/recipes/unicorn'
|
12
|
+
load 'config/deploy/recipes/assets'
|
13
|
+
load 'config/deploy/recipes/postgresql'
|
14
|
+
#load 'config/deploy/recipes/whenever'
|
15
|
+
load 'config/deploy/recipes/monit'
|
16
|
+
|
17
|
+
set :stages, %w(staging production)
|
18
|
+
|
19
|
+
set :default_stage, 'production'
|
20
|
+
|
21
|
+
default_run_options[:pty] = true
|
22
|
+
|
23
|
+
set :application, 'application_name'
|
24
|
+
set :user, 'server user name' # We use deployer
|
25
|
+
set :deploy_to, "/home/#{user}/apps/#{application}"
|
26
|
+
|
27
|
+
set :deploy_via, :remote_cache
|
28
|
+
set :use_sudo, false
|
29
|
+
|
30
|
+
set :scm, "git"
|
31
|
+
set :repository, "git@github.com:username/#{application}.git"
|
32
|
+
|
33
|
+
default_run_options[:pty] = true
|
34
|
+
ssh_options[:forward_agent] = true
|
35
|
+
|
36
|
+
set :maintenance_template_path, File.expand_path('../deploy/recipes/templates/maintenance.html.erb', __FILE__)
|
37
|
+
|
38
|
+
# Production
|
39
|
+
set :default_environment, {
|
40
|
+
'PATH' => '$HOME/.rbenv/shims:$HOME/.rbenv/bin:$PATH'
|
41
|
+
}
|
@@ -0,0 +1,11 @@
|
|
1
|
+
namespace :assets do
|
2
|
+
desc 'Run precompile.'
|
3
|
+
task :precompile do
|
4
|
+
|
5
|
+
puts 'Running assets:precompile'
|
6
|
+
run "cd #{current_path}/ && rake assets:precompile RAILS_ENV=#{rails_env}"
|
7
|
+
end
|
8
|
+
|
9
|
+
after 'deploy', 'assets:precompile'
|
10
|
+
after 'deploy:cold', 'assets:precompile'
|
11
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
namespace :backup do
|
2
|
+
desc 'Setup backup.'
|
3
|
+
task :setup do
|
4
|
+
transaction do
|
5
|
+
on_rollback do
|
6
|
+
puts 'I can not setup backup.'
|
7
|
+
end
|
8
|
+
|
9
|
+
puts 'Installing backup gem.'
|
10
|
+
run 'gem install backup --no-ri --no-rdoc'
|
11
|
+
|
12
|
+
puts 'Creating backup model.'
|
13
|
+
full_path = "/home/deployer/Backup/models/#{application}.rb"
|
14
|
+
if 'true' == capture("if [ -e #{full_path} ]; then echo 'true'; fi").strip
|
15
|
+
run "mv #{full_path} #{full_path}.#{Time.now.to_i}"
|
16
|
+
end
|
17
|
+
|
18
|
+
run "backup generate:model -t #{application} --storages='local' --compressors='gzip' --databases='postgresql'"
|
19
|
+
run "rm #{full_path}"
|
20
|
+
template 'backup_model.erb', full_path
|
21
|
+
puts "Now edit #{full_path}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
after 'deploy:setup', 'backup:setup'
|
26
|
+
|
27
|
+
desc 'Get backup.'
|
28
|
+
task :perform do
|
29
|
+
transaction do
|
30
|
+
on_rollback do
|
31
|
+
puts 'I can not backup.'
|
32
|
+
end
|
33
|
+
|
34
|
+
puts 'Performing backup.'
|
35
|
+
run "backup perform --trigger #{application}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
before 'deploy', 'backup:perform'
|
40
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
def set_default(name, *args, &block)
|
2
|
+
set(name, *args, &block) unless exists?(name)
|
3
|
+
end
|
4
|
+
|
5
|
+
def template(from, to)
|
6
|
+
erb = File.read(File.expand_path("../templates/#{from}", __FILE__))
|
7
|
+
put ERB.new(erb).result(binding), to
|
8
|
+
end
|
9
|
+
|
10
|
+
#set :whenever_command, 'bundle exec whenever'
|
11
|
+
namespace :deploy do
|
12
|
+
desc 'Install dependencies library for rails'
|
13
|
+
task :install do
|
14
|
+
#
|
15
|
+
|
16
|
+
run "#{sudo} apt-get -y update && #{sudo} apt-get -y upgrade"
|
17
|
+
|
18
|
+
run "#{sudo} apt-get -y install python-software-properties && #{sudo} apt-get -y install software-properties-common"
|
19
|
+
|
20
|
+
run "export LANGUAGE=en_US.UTF-8 && export LANG=en_US.UTF-8 && export LC_ALL=en_US.UTF-8 && locale-gen en_US.UTF-8 && #{sudo} dpkg-reconfigure locales"
|
21
|
+
|
22
|
+
#run "bash <(curl -s https://gist.github.com/muhammetdilek/7138112/raw/c9af34bbda8df7ebf7f30d5daab18b8bc80326c6/removepackage.sh)"
|
23
|
+
|
24
|
+
run "#{sudo} apt-get -y install htop"
|
25
|
+
|
26
|
+
run "#{sudo} apt-get -y install curl git-core"
|
27
|
+
|
28
|
+
#run "ssh-keygen -t rsa -C 'user@example.com' << EOF \n \n \n \n"
|
29
|
+
|
30
|
+
# Ruby dependencies package
|
31
|
+
run "#{sudo} apt-get -y install zlib1g-dev openssl libopenssl-ruby1.9.1 libssl-dev libruby1.9.1 libreadline-dev git-core make make-doc"
|
32
|
+
|
33
|
+
# Rvm install
|
34
|
+
run "cd ~ && git clone git://github.com/sstephenson/rbenv.git .rbenv"
|
35
|
+
|
36
|
+
run "echo 'export PATH=\"$HOME/.rbenv/bin:$PATH\"' >> ~/.bashrc"
|
37
|
+
run "echo 'eval \"$(rbenv init -)\"' >> ~/.bashrc"
|
38
|
+
|
39
|
+
run 'mkdir -p ~/.rbenv/plugins'
|
40
|
+
run 'cd ~/.rbenv/plugins && git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build && git clone https://github.com/sstephenson/rbenv-gem-rehash.git ~/.rbenv/plugins/rbenv-gem-rehash'
|
41
|
+
run 'rbenv install 2.0.0-p247 && rbenv rehash && rbenv global 2.0.0-p247'
|
42
|
+
|
43
|
+
# Update rubygems
|
44
|
+
run 'gem update --system'
|
45
|
+
|
46
|
+
# No rdoc
|
47
|
+
run "echo 'gem: --no-rdoc --no-ri' >> ~/.gemrc"
|
48
|
+
|
49
|
+
# Install bundler
|
50
|
+
run 'gem install bundler --no-ri --no-rdoc && rbenv rehash'
|
51
|
+
|
52
|
+
#Update rake
|
53
|
+
#run 'gem update rake'
|
54
|
+
|
55
|
+
# Node js
|
56
|
+
run "#{sudo} add-apt-repository -y ppa:chris-lea/node.js && #{sudo} apt-get -y update && #{sudo} apt-get -y install nodejs"
|
57
|
+
|
58
|
+
# For nokogiri gem
|
59
|
+
run "#{sudo} apt-get -y install libxslt-dev libxml2-dev"
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
desc 'Install bundler'
|
64
|
+
task :install_bundler, :roles => :app do
|
65
|
+
run 'type -P bundle &>/dev/null || { gem install bundler --no-rdoc --no-ri; }'
|
66
|
+
end
|
67
|
+
|
68
|
+
desc 'Resque QUEUE Start'
|
69
|
+
task :resque_setup, :roles => :db do
|
70
|
+
run "cd #{release_path} && resque:work QUEUE='*'"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
before 'deploy:setup', 'deploy:install'
|
75
|
+
after 'deploy', 'deploy:cleanup'
|
76
|
+
before 'deploy:cold', 'deploy:install_bundler'
|
77
|
+
before 'deploy', 'deploy:web:disable'
|
78
|
+
after 'deploy', 'deploy:web:enable'
|
@@ -0,0 +1,13 @@
|
|
1
|
+
namespace :check do
|
2
|
+
desc 'Make sure local git is in sync with remote.'
|
3
|
+
task :revision, roles: :web do
|
4
|
+
unless `git rev-parse HEAD` == `git rev-parse origin/#{branch}`
|
5
|
+
puts "WARNING: HEAD is not the same as origin/#{branch}"
|
6
|
+
puts 'Run `git push` to sync changes.'
|
7
|
+
exit
|
8
|
+
end
|
9
|
+
end
|
10
|
+
before 'deploy', 'check:revision'
|
11
|
+
before 'deploy:migrations', 'check:revision'
|
12
|
+
before 'deploy:cold', 'check:revision'
|
13
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
namespace :db do
|
2
|
+
desc 'Setup db configuration.'
|
3
|
+
task :setup do
|
4
|
+
run "mkdir -p #{shared_path}/config"
|
5
|
+
template 'database.yml.erb', "#{shared_path}/config/database.yml"
|
6
|
+
end
|
7
|
+
|
8
|
+
desc 'rake db:migrate.'
|
9
|
+
task :migrate do
|
10
|
+
run "cd #{current_path} && rake db:migrate RAILS_ENV=#{rails_env}"
|
11
|
+
end
|
12
|
+
|
13
|
+
after 'deploy', 'db:migrate'
|
14
|
+
after 'deploy:setup', 'db:setup'
|
15
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
namespace :monit do
|
2
|
+
desc 'Install Monit'
|
3
|
+
task :install do
|
4
|
+
run "#{sudo} apt-get -y install monit"
|
5
|
+
end
|
6
|
+
after 'deploy:install', 'monit:install'
|
7
|
+
|
8
|
+
desc 'Setup all Monit configuration'
|
9
|
+
task :setup do
|
10
|
+
monit_config 'monitrc', '/etc/monit/monitrc'
|
11
|
+
nginx
|
12
|
+
postgresql
|
13
|
+
unicorn
|
14
|
+
syntax
|
15
|
+
reload
|
16
|
+
end
|
17
|
+
after 'deploy:setup', 'monit:setup'
|
18
|
+
|
19
|
+
task(:nginx, roles: :web) { monit_config "nginx" }
|
20
|
+
#task(:postgresql, roles: :db) { monit_config "postgresql" }
|
21
|
+
task(:unicorn, roles: :app) { monit_config "unicorn" }
|
22
|
+
|
23
|
+
%w[start stop restart syntax reload].each do |command|
|
24
|
+
desc "Run Monit #{command} script"
|
25
|
+
task command do
|
26
|
+
run "#{sudo} service monit #{command}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def monit_config(name, destination = nil)
|
32
|
+
destination ||= "/etc/monit/conf.d/#{name}.conf"
|
33
|
+
template "monit/#{name}.erb", "/tmp/monit_#{name}"
|
34
|
+
run "#{sudo} mv /tmp/monit_#{name} #{destination}"
|
35
|
+
run "#{sudo} chown root #{destination}"
|
36
|
+
run "#{sudo} chmod 600 #{destination}"
|
37
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
set_default(:project_domain) { Capistrano::CLI.ui.ask 'Project Domain=> ' }
|
2
|
+
|
3
|
+
namespace :nginx do
|
4
|
+
desc 'Install nginx'
|
5
|
+
task :install do
|
6
|
+
run "#{sudo} add-apt-repository -y ppa:nginx/stable"
|
7
|
+
run "#{sudo} apt-get -y update"
|
8
|
+
run "#{sudo} apt-get -y install nginx"
|
9
|
+
run "#{sudo} service nginx start"
|
10
|
+
end
|
11
|
+
|
12
|
+
after 'deploy:install', 'nginx:install'
|
13
|
+
|
14
|
+
desc 'Nginx setup.'
|
15
|
+
task :setup do
|
16
|
+
puts "Creating #{shared_path}/config/nginx.#{rails_env}.conf"
|
17
|
+
template "nginx.#{rails_env}.erb", "#{shared_path}/config/nginx.#{rails_env}.conf"
|
18
|
+
|
19
|
+
puts "Symlinks #{shared_path}/config/nginx.#{rails_env}.conf to /etc/nginx/sites-enabled/#{application}"
|
20
|
+
sudo "ln -nfs #{shared_path}/config/nginx.#{rails_env}.conf /etc/nginx/sites-enabled/#{application}"
|
21
|
+
|
22
|
+
puts 'Removing /etc/nginx/sites-enabled/default'
|
23
|
+
sudo 'rm /etc/nginx/sites-enabled/default'
|
24
|
+
end
|
25
|
+
|
26
|
+
%w[start stop restart reload].each do |command|
|
27
|
+
desc "Nginx #{command}"
|
28
|
+
|
29
|
+
task command, role: :web do
|
30
|
+
sudo "service nginx #{command}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
after 'deploy:setup', 'nginx:setup'
|
35
|
+
after 'deploy:setup', 'nginx:reload'
|
36
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
set_default(:postgresql_host) { Capistrano::CLI.ui.ask 'Postgresql Host=> ' }
|
2
|
+
set_default(:postgresql_port, '5432') #{ Capistrano::CLI.ui.ask 'Postgresql Port=> ' }
|
3
|
+
set_default(:postgresql_user) { Capistrano::CLI.ui.ask 'Postgresql User=> ' }
|
4
|
+
set_default(:postgresql_password) { Capistrano::CLI.password_prompt "Password for #{postgresql_user}:" }
|
5
|
+
set_default(:postgresql_database) { Capistrano::CLI.ui.ask 'Postgresql Database=> ' }
|
6
|
+
set_default(:postgresql_pid) { "/var/run/postgresql/9.1-main.pid" }
|
7
|
+
|
8
|
+
namespace :postgresql do
|
9
|
+
desc 'Install the latest stable release of PostgreSQL.'
|
10
|
+
task :install, roles: :db, only: {primary: true} do
|
11
|
+
run "#{sudo} add-apt-repository -y ppa:pitti/postgresql"
|
12
|
+
run "#{sudo} apt-get -y update"
|
13
|
+
run "#{sudo} apt-get -y install postgresql libpq-dev"
|
14
|
+
end
|
15
|
+
|
16
|
+
after "deploy:install", "postgresql:install"
|
17
|
+
|
18
|
+
desc 'Create a database for this application.'
|
19
|
+
task :create_database, roles: :db, only: {primary: true} do
|
20
|
+
puts 'Creating user with password'
|
21
|
+
run %Q{#{sudo} -u postgres psql -c "create user #{postgresql_user} with password '#{postgresql_password}';"}
|
22
|
+
|
23
|
+
puts 'Creating database with owner'
|
24
|
+
run %Q{#{sudo} -u postgres psql -c "create database #{postgresql_database} owner #{postgresql_user} encoding 'UTF8' LC_COLLATE = 'en_US.UTF-8' LC_CTYPE = 'en_US.UTF-8' TEMPLATE template0;"}
|
25
|
+
end
|
26
|
+
|
27
|
+
desc 'Restart postgresql'
|
28
|
+
task :restart do
|
29
|
+
|
30
|
+
puts 'Postgresql restarting'
|
31
|
+
sudo 'service postgresql restart'
|
32
|
+
end
|
33
|
+
after 'deploy:setup', 'postgresql:create_database'
|
34
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
Backup::Model.new(:<%= application %>, '<%= application %> backup') do
|
2
|
+
##
|
3
|
+
# Split [Splitter]
|
4
|
+
#
|
5
|
+
# Split the backup file in to chunks of 250 megabytes
|
6
|
+
# if the backup file size exceeds 250 megabytes
|
7
|
+
#
|
8
|
+
split_into_chunks_of 500
|
9
|
+
|
10
|
+
##
|
11
|
+
# PostgreSQL [Database]
|
12
|
+
#
|
13
|
+
database PostgreSQL do |db|
|
14
|
+
# To dump all databases, set `db.name = :all` (or leave blank)
|
15
|
+
db.name = "<%= postgresql_database %>"
|
16
|
+
db.username = "<%= postgresql_user %>"
|
17
|
+
db.password = "<%= postgresql_password %>"
|
18
|
+
db.host = "<%= postgresql_host %>"
|
19
|
+
db.port = "<%= postgresql_port %>"
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# Local (Copy) [Storage]
|
24
|
+
#
|
25
|
+
store_with Local do |local|
|
26
|
+
local.path = "~/backups/"
|
27
|
+
local.keep = 5
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
# Gzip [Compressor]
|
32
|
+
#
|
33
|
+
compress_with Gzip
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<%= rails_env %>:
|
2
|
+
adapter: postgresql
|
3
|
+
username: <%= postgresql_user %>
|
4
|
+
password: <%= postgresql_password %>
|
5
|
+
database: <%= postgresql_database %>
|
6
|
+
encoding: utf8
|
7
|
+
min_messages: warning
|
8
|
+
pool: 5
|
9
|
+
timeout: 5000
|
10
|
+
host: <%= postgresql_host %>
|
11
|
+
port: <%= postgresql_port %>
|
data/lib/generators/recipes_matic/templates/config/deploy/recipes/templates/maintenance.html.erb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Maintenance Page For Your Application</title>
|
5
|
+
<style type="text/css">
|
6
|
+
html, body {
|
7
|
+
background-color: #4B7399;
|
8
|
+
font-family: Verdana, Helvetica, Arial;
|
9
|
+
font-size: 14px;
|
10
|
+
}
|
11
|
+
|
12
|
+
a {
|
13
|
+
color: #0000FF;
|
14
|
+
img { border: none; }
|
15
|
+
}
|
16
|
+
|
17
|
+
#container {
|
18
|
+
width: 80%;
|
19
|
+
margin: 0 auto;
|
20
|
+
background-color: #FFF;
|
21
|
+
padding: 20px 40px;
|
22
|
+
border: solid 1px black;
|
23
|
+
margin-top: 20px;
|
24
|
+
}
|
25
|
+
</style>
|
26
|
+
</head>
|
27
|
+
<body>
|
28
|
+
<div id="container">
|
29
|
+
<h1>The system is down for <%= reason ? reason : "maintenance" %></h1>
|
30
|
+
<p>It will be back <%= deadline ? deadline : "soon" %></p>
|
31
|
+
</div>
|
32
|
+
</body>
|
33
|
+
</html>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
set daemon 30
|
2
|
+
|
3
|
+
set logfile /var/log/monit.log
|
4
|
+
set idfile /var/lib/monit/id
|
5
|
+
set statefile /var/lib/monit/state
|
6
|
+
|
7
|
+
set eventqueue
|
8
|
+
basedir /var/lib/monit/events
|
9
|
+
slots 100
|
10
|
+
|
11
|
+
#set mailserver smtp.gmail.com port 587
|
12
|
+
# username "foo@example.com" password "secret"
|
13
|
+
# using tlsv1
|
14
|
+
# with timeout 30 seconds
|
15
|
+
|
16
|
+
set alert muhammet.dilek@lab2023.com
|
17
|
+
|
18
|
+
set httpd port 2812
|
19
|
+
allow admin:"secret"
|
20
|
+
|
21
|
+
check system server
|
22
|
+
if loadavg(5min) > 2 for 2 cycles then alert
|
23
|
+
if memory > 75% for 2 cycles then alert
|
24
|
+
if cpu(user) > 75% for 2 cycles then alert
|
25
|
+
|
26
|
+
include /etc/monit/conf.d/*
|
data/lib/generators/recipes_matic/templates/config/deploy/recipes/templates/nginx.production.erb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
upstream <%= application %> {
|
2
|
+
server unix:/tmp/unicorn.<%= application %>.sock fail_timeout=0;
|
3
|
+
}
|
4
|
+
|
5
|
+
server {
|
6
|
+
listen 80;
|
7
|
+
server_name *.<%= project_domain %> <%= project_domain %>;
|
8
|
+
root <%= current_path %>/public;
|
9
|
+
|
10
|
+
location ^~ /assets/ {
|
11
|
+
gzip_static on;
|
12
|
+
expires max;
|
13
|
+
add_header Cache-Control public;
|
14
|
+
}
|
15
|
+
|
16
|
+
try_files $uri/index.html $uri @<%= application %>;
|
17
|
+
location @<%= application %> {
|
18
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
19
|
+
proxy_set_header Host $http_host;
|
20
|
+
proxy_redirect off;
|
21
|
+
proxy_pass http://<%= application %>;
|
22
|
+
}
|
23
|
+
|
24
|
+
error_page 500 502 504 /500.html;
|
25
|
+
client_max_body_size 4G;
|
26
|
+
keepalive_timeout 10;
|
27
|
+
|
28
|
+
if (-f $document_root/system/maintenance.html) {
|
29
|
+
return 503;
|
30
|
+
}
|
31
|
+
error_page 503 @maintenance;
|
32
|
+
location @maintenance {
|
33
|
+
rewrite ^(.*)$ /system/maintenance.html last;
|
34
|
+
break;
|
35
|
+
}
|
36
|
+
}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
upstream <%= application %> {
|
2
|
+
server unix:/tmp/unicorn.<%= application %>.sock fail_timeout=0;
|
3
|
+
}
|
4
|
+
|
5
|
+
server {
|
6
|
+
listen 80;
|
7
|
+
server_name stage.<%= project_domain %>;
|
8
|
+
root <%= current_path %>/public;
|
9
|
+
|
10
|
+
location ^~ /assets/ {
|
11
|
+
gzip_static on;
|
12
|
+
expires max;
|
13
|
+
add_header Cache-Control public;
|
14
|
+
}
|
15
|
+
|
16
|
+
try_files $uri/index.html $uri @<%= application %>;
|
17
|
+
location @<%= application %> {
|
18
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
19
|
+
proxy_set_header Host $http_host;
|
20
|
+
proxy_redirect off;
|
21
|
+
proxy_pass http://<%= application %>;
|
22
|
+
}
|
23
|
+
|
24
|
+
error_page 500 502 504 /500.html;
|
25
|
+
client_max_body_size 4G;
|
26
|
+
keepalive_timeout 10;
|
27
|
+
|
28
|
+
if (-f $document_root/system/maintenance.html) {
|
29
|
+
return 503;
|
30
|
+
}
|
31
|
+
error_page 503 @maintenance;
|
32
|
+
location @maintenance {
|
33
|
+
rewrite ^(.*)$ /system/maintenance.html last;
|
34
|
+
break;
|
35
|
+
}
|
36
|
+
}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
working_directory "<%= current_path %>"
|
2
|
+
pid "<%= unicorn_pid %>"
|
3
|
+
stderr_path "<%= unicorn_log %>"
|
4
|
+
stdout_path "<%= unicorn_log %>"
|
5
|
+
|
6
|
+
listen "/tmp/unicorn.<%= application %>.sock"
|
7
|
+
worker_processes <%= unicorn_workers %>
|
8
|
+
timeout 30
|
9
|
+
|
10
|
+
preload_app true
|
11
|
+
|
12
|
+
before_fork do |server, worker|
|
13
|
+
# Disconnect since the database connection will not carry over
|
14
|
+
if defined? ActiveRecord::Base
|
15
|
+
ActiveRecord::Base.connection.disconnect!
|
16
|
+
end
|
17
|
+
|
18
|
+
# Quit the old unicorn process
|
19
|
+
old_pid = "#{server.config[:pid]}.oldbin"
|
20
|
+
if File.exists?(old_pid) && server.pid != old_pid
|
21
|
+
begin
|
22
|
+
Process.kill("QUIT", File.read(old_pid).to_i)
|
23
|
+
rescue Errno::ENOENT, Errno::ESRCH
|
24
|
+
# someone else did our job for us
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
after_fork do |server, worker|
|
30
|
+
# Start up the database connection again in the worker
|
31
|
+
if defined?(ActiveRecord::Base)
|
32
|
+
ActiveRecord::Base.establish_connection
|
33
|
+
end
|
34
|
+
child_pid = server.config[:pid].sub(".pid", ".#{worker.nr}.pid")
|
35
|
+
system("echo #{Process.pid} > #{child_pid}")
|
36
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
set -e
|
3
|
+
|
4
|
+
# Feel free to change any of the following variables for your app:
|
5
|
+
TIMEOUT=${TIMEOUT-60}
|
6
|
+
APP_ROOT=<%= current_path %>
|
7
|
+
PID=<%= unicorn_pid %>
|
8
|
+
CMD="cd $APP_ROOT; bundle exec unicorn -D -c <%= unicorn_config %> -E <%= rails_env %>"
|
9
|
+
AS_USER=<%= unicorn_user %>
|
10
|
+
set -u
|
11
|
+
|
12
|
+
OLD_PIN="$PID.oldbin"
|
13
|
+
|
14
|
+
sig () {
|
15
|
+
test -s "$PID" && kill -$1 `cat $PID`
|
16
|
+
}
|
17
|
+
|
18
|
+
oldsig () {
|
19
|
+
test -s $OLD_PIN && kill -$1 `cat $OLD_PIN`
|
20
|
+
}
|
21
|
+
|
22
|
+
run () {
|
23
|
+
if [ "$(id -un)" = "$AS_USER" ]; then
|
24
|
+
eval $1
|
25
|
+
else
|
26
|
+
su -c "$1" - $AS_USER
|
27
|
+
fi
|
28
|
+
}
|
29
|
+
|
30
|
+
case "$1" in
|
31
|
+
start)
|
32
|
+
sig 0 && echo >&2 "Already running" && exit 0
|
33
|
+
run "$CMD"
|
34
|
+
;;
|
35
|
+
stop)
|
36
|
+
sig QUIT && exit 0
|
37
|
+
echo >&2 "Not running"
|
38
|
+
;;
|
39
|
+
force-stop)
|
40
|
+
sig TERM && exit 0
|
41
|
+
echo >&2 "Not running"
|
42
|
+
;;
|
43
|
+
restart|reload)
|
44
|
+
sig HUP && echo reloaded OK && exit 0
|
45
|
+
echo >&2 "Couldn't reload, starting '$CMD' instead"
|
46
|
+
run "$CMD"
|
47
|
+
;;
|
48
|
+
upgrade)
|
49
|
+
if sig USR2 && sleep 2 && sig 0 && oldsig QUIT
|
50
|
+
then
|
51
|
+
n=$TIMEOUT
|
52
|
+
while test -s $OLD_PIN && test $n -ge 0
|
53
|
+
do
|
54
|
+
printf '.' && sleep 1 && n=$(( $n - 1 ))
|
55
|
+
done
|
56
|
+
echo
|
57
|
+
|
58
|
+
if test $n -lt 0 && test -s $OLD_PIN
|
59
|
+
then
|
60
|
+
echo >&2 "$OLD_PIN still exists after $TIMEOUT seconds"
|
61
|
+
exit 1
|
62
|
+
fi
|
63
|
+
exit 0
|
64
|
+
fi
|
65
|
+
echo >&2 "Couldn't upgrade, starting '$CMD' instead"
|
66
|
+
run "$CMD"
|
67
|
+
;;
|
68
|
+
reopen-logs)
|
69
|
+
sig USR1
|
70
|
+
;;
|
71
|
+
*)
|
72
|
+
echo >&2 "Usage: $0 <start|stop|restart|upgrade|force-stop|reopen-logs>"
|
73
|
+
exit 1
|
74
|
+
;;
|
75
|
+
esac
|
@@ -0,0 +1,28 @@
|
|
1
|
+
set_default(:unicorn_user) { user }
|
2
|
+
set_default(:unicorn_pid) { "#{current_path}/tmp/pids/unicorn.pid" }
|
3
|
+
set_default(:unicorn_config) { "#{shared_path}/config/unicorn.rb" }
|
4
|
+
set_default(:unicorn_log) { "#{shared_path}/log/unicorn.log" }
|
5
|
+
set_default(:unicorn_workers, 2)
|
6
|
+
|
7
|
+
namespace :unicorn do
|
8
|
+
desc 'Unicorn setup'
|
9
|
+
task :setup do
|
10
|
+
run "mkdir -p #{shared_path}/config"
|
11
|
+
template 'unicorn.rb.erb', unicorn_config
|
12
|
+
|
13
|
+
template 'unicorn_init.erb', "#{shared_path}/config/unicorn_init.sh"
|
14
|
+
run "chmod +x #{shared_path}/config/unicorn_init.sh"
|
15
|
+
sudo "ln -nfs #{shared_path}/config/unicorn_init.sh /etc/init.d/unicorn_#{application}"
|
16
|
+
end
|
17
|
+
|
18
|
+
%w[start stop restart].each do |command|
|
19
|
+
desc "Unicorn server #{command}."
|
20
|
+
task command, except: {no_release: true} do
|
21
|
+
run "/etc/init.d/unicorn_#{application} #{command}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
after 'deploy:setup', 'unicorn:setup'
|
26
|
+
after 'deploy:cold', 'unicorn:restart'
|
27
|
+
after 'assets:precompile', 'unicorn:restart'
|
28
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
namespace :whenever do
|
2
|
+
desc 'Whenever gem installing.'
|
3
|
+
task :setup do
|
4
|
+
run 'gem install whenever --no-ri --no-rdoc'
|
5
|
+
end
|
6
|
+
|
7
|
+
desc 'Update the crontab file'
|
8
|
+
task :update_crontab, :roles => :db do
|
9
|
+
run "cd #{current_path} && whenever --update-crontab #{application}"
|
10
|
+
end
|
11
|
+
|
12
|
+
after 'deploy:setup', 'whenever:setup'
|
13
|
+
|
14
|
+
after 'deploy', 'whenever:update_crontab'
|
15
|
+
after 'deploy:cold', 'whenever:update_crontab'
|
16
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'recipes_matic/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'recipes_matic'
|
8
|
+
spec.version = RecipesMatic::VERSION
|
9
|
+
spec.authors = ['lab2023']
|
10
|
+
spec.email = %w(info@lab2023.com)
|
11
|
+
spec.description = %q{Copy beautiful recipes into project}
|
12
|
+
spec.summary = %q{Copy beautiful recipes into project}
|
13
|
+
spec.homepage = 'http://github.com/kebab-project/recipes_matic'
|
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 = %w(lib)
|
20
|
+
|
21
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
22
|
+
spec.add_development_dependency 'rake'
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: recipes_matic
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- lab2023
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-10-29 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: Copy beautiful recipes into project
|
42
|
+
email:
|
43
|
+
- info@lab2023.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- .gitignore
|
49
|
+
- CHANGELOG.md
|
50
|
+
- Gemfile
|
51
|
+
- LICENSE.txt
|
52
|
+
- README.md
|
53
|
+
- Rakefile
|
54
|
+
- lib/generators/recipes_matic/install_generator.rb
|
55
|
+
- lib/generators/recipes_matic/templates/config/deploy.rb
|
56
|
+
- lib/generators/recipes_matic/templates/config/deploy/production.rb
|
57
|
+
- lib/generators/recipes_matic/templates/config/deploy/recipes/assets.rb
|
58
|
+
- lib/generators/recipes_matic/templates/config/deploy/recipes/backup.rb
|
59
|
+
- lib/generators/recipes_matic/templates/config/deploy/recipes/base.rb
|
60
|
+
- lib/generators/recipes_matic/templates/config/deploy/recipes/check.rb
|
61
|
+
- lib/generators/recipes_matic/templates/config/deploy/recipes/db.rb
|
62
|
+
- lib/generators/recipes_matic/templates/config/deploy/recipes/monit.rb
|
63
|
+
- lib/generators/recipes_matic/templates/config/deploy/recipes/nginx.rb
|
64
|
+
- lib/generators/recipes_matic/templates/config/deploy/recipes/postgresql.rb
|
65
|
+
- lib/generators/recipes_matic/templates/config/deploy/recipes/symlinks.rb
|
66
|
+
- lib/generators/recipes_matic/templates/config/deploy/recipes/templates/backup_model.erb
|
67
|
+
- lib/generators/recipes_matic/templates/config/deploy/recipes/templates/database.yml.erb
|
68
|
+
- lib/generators/recipes_matic/templates/config/deploy/recipes/templates/maintenance.html.erb
|
69
|
+
- lib/generators/recipes_matic/templates/config/deploy/recipes/templates/monit/monitrc.erb
|
70
|
+
- lib/generators/recipes_matic/templates/config/deploy/recipes/templates/monit/nginx.erb
|
71
|
+
- lib/generators/recipes_matic/templates/config/deploy/recipes/templates/monit/postgresql.erb
|
72
|
+
- lib/generators/recipes_matic/templates/config/deploy/recipes/templates/monit/unicorn.erb
|
73
|
+
- lib/generators/recipes_matic/templates/config/deploy/recipes/templates/nginx.production.erb
|
74
|
+
- lib/generators/recipes_matic/templates/config/deploy/recipes/templates/nginx.staging.erb
|
75
|
+
- lib/generators/recipes_matic/templates/config/deploy/recipes/templates/unicorn.rb.erb
|
76
|
+
- lib/generators/recipes_matic/templates/config/deploy/recipes/templates/unicorn_init.erb
|
77
|
+
- lib/generators/recipes_matic/templates/config/deploy/recipes/unicorn.rb
|
78
|
+
- lib/generators/recipes_matic/templates/config/deploy/recipes/whenever.rb
|
79
|
+
- lib/generators/recipes_matic/templates/config/deploy/staging.rb
|
80
|
+
- lib/recipes_matic.rb
|
81
|
+
- lib/recipes_matic/version.rb
|
82
|
+
- recipes_matic.gemspec
|
83
|
+
homepage: http://github.com/kebab-project/recipes_matic
|
84
|
+
licenses:
|
85
|
+
- MIT
|
86
|
+
metadata: {}
|
87
|
+
post_install_message:
|
88
|
+
rdoc_options: []
|
89
|
+
require_paths:
|
90
|
+
- lib
|
91
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - '>='
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- - '>='
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0'
|
101
|
+
requirements: []
|
102
|
+
rubyforge_project:
|
103
|
+
rubygems_version: 2.0.6
|
104
|
+
signing_key:
|
105
|
+
specification_version: 4
|
106
|
+
summary: Copy beautiful recipes into project
|
107
|
+
test_files: []
|