chicken_soup 0.6.1 → 0.8.0
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.
- data/lib/chicken_soup/capabilities/apache/apache-checks.rb +0 -2
- data/lib/chicken_soup/capabilities/apache/apache-defaults.rb +7 -12
- data/lib/chicken_soup/capabilities/bundler/bundler-checks.rb +0 -2
- data/lib/chicken_soup/capabilities/bundler/bundler-defaults.rb +0 -2
- data/lib/chicken_soup/capabilities/bundler/bundler-tasks.rb +0 -2
- data/lib/chicken_soup/capabilities/heroku/heroku-checks.rb +0 -2
- data/lib/chicken_soup/capabilities/heroku/heroku-defaults.rb +0 -2
- data/lib/chicken_soup/capabilities/nginx/nginx-checks.rb +0 -2
- data/lib/chicken_soup/capabilities/nginx/nginx-defaults.rb +7 -8
- data/lib/chicken_soup/capabilities/passenger/passenger-defaults.rb +9 -1
- data/lib/chicken_soup/capabilities/rvm/rvm-checks.rb +0 -2
- data/lib/chicken_soup/capabilities/rvm/rvm-defaults.rb +13 -13
- data/lib/chicken_soup/capabilities/rvm/rvm-tasks.rb +0 -2
- data/lib/chicken_soup/capabilities/shared/db-checks.rb +5 -3
- data/lib/chicken_soup/capabilities/shared/db-defaults.rb +10 -2
- data/lib/chicken_soup/capabilities/shared/db-tasks.rb +67 -15
- data/lib/chicken_soup/capabilities/shared/web_server-defaults.rb +13 -0
- data/lib/chicken_soup/capabilities/shared/web_server-tasks.rb +4 -6
- data/lib/chicken_soup/capabilities/svn/svn-defaults.rb +0 -2
- data/lib/chicken_soup/capabilities/unix/unix-checks.rb +3 -5
- data/lib/chicken_soup/capabilities/unix/unix-defaults.rb +11 -12
- data/lib/chicken_soup/capabilities/unix/unix-tasks.rb +0 -2
- data/lib/chicken_soup/capabilities.rb +0 -2
- data/lib/chicken_soup/environment/checks.rb +3 -6
- data/lib/chicken_soup/environment/defaults.rb +11 -4
- data/lib/chicken_soup/environment/tasks.rb +1 -1
- data/lib/chicken_soup/global.rb +98 -5
- data/lib/chicken_soup/notifiers/email/email-checks.rb +0 -2
- data/lib/chicken_soup/notifiers/email/email-defaults.rb +0 -2
- data/lib/chicken_soup/notifiers/email/presenter.rb +2 -4
- data/lib/chicken_soup/notifiers/git/git-tasks.rb +2 -2
- data/lib/chicken_soup/notifiers.rb +0 -2
- data/lib/chicken_soup/templates/maintenance.html.erb +41 -0
- data/lib/chicken_soup/tools/defaults.rb +41 -0
- data/lib/chicken_soup/tools/log/log-defaults.rb +21 -0
- data/lib/chicken_soup/tools/log/log-tasks.rb +56 -0
- data/lib/chicken_soup/tools/tasks.rb +12 -0
- data/lib/chicken_soup/tools.rb +16 -0
- data/lib/chicken_soup/version.rb +1 -1
- data/lib/chicken_stock.rb +4 -0
- metadata +9 -2
@@ -2,27 +2,22 @@
|
|
2
2
|
# APACHE DEFAULTS #
|
3
3
|
######################################################################
|
4
4
|
module ChickenSoup
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
elsif remote_file_exists?("/usr/sbin/httpd")
|
11
|
-
set :web_server_control_script, "/usr/sbin/httpd"
|
12
|
-
end
|
13
|
-
|
14
|
-
abort "Couldn't figure out how to control your installation of Apache" unless exists?(:web_server_control_script)
|
5
|
+
module WebServer
|
6
|
+
STANDARD_CONTROL_SCRIPTS = ['/usr/sbin/apachectl', '/usr/sbin/apache2', '/usr/sbin/httpd']
|
7
|
+
STANDARD_LOG_LOCATIONS = ['/var/log/apache2', '/var/log/httpd', '/etc/httpd/logs']
|
8
|
+
STANDARD_ERROR_LOGS = ['error_log', 'error.log', 'httpd-error.log']
|
9
|
+
STANDARD_ACCESS_LOGS = ['access_log', 'access.log', 'httpd-access.log']
|
15
10
|
end
|
16
11
|
end
|
17
12
|
|
18
13
|
Capistrano::Configuration.instance(:must_exist).load do
|
19
|
-
|
14
|
+
require 'chicken_soup/capabilities/shared/web_server-defaults'
|
20
15
|
|
21
16
|
namespace :capabilities do
|
22
17
|
namespace :defaults do
|
23
18
|
desc "[internal] Sets intelligent defaults for Apache deployments."
|
24
19
|
task :apache do
|
25
|
-
|
20
|
+
capabilities.defaults.web_server
|
26
21
|
|
27
22
|
if web_server_control_script =~ /apache2/
|
28
23
|
set :apache_enable_script, "a2ensite"
|
@@ -2,8 +2,6 @@
|
|
2
2
|
# BUNDLER DEFAULTS #
|
3
3
|
######################################################################
|
4
4
|
Capistrano::Configuration.instance(:must_exist).load do
|
5
|
-
extend ChickenSoup
|
6
|
-
|
7
5
|
namespace :capabilities do
|
8
6
|
namespace :defaults do
|
9
7
|
desc "[internal] Sets intelligent defaults for Bundler deployments."
|
@@ -2,8 +2,6 @@
|
|
2
2
|
# BUNDLER TASKS #
|
3
3
|
######################################################################
|
4
4
|
Capistrano::Configuration.instance(:must_exist).load do
|
5
|
-
extend ChickenSoup
|
6
|
-
|
7
5
|
before 'gems:install', 'bundler:install'
|
8
6
|
|
9
7
|
run_task 'bundler:install', :as => manager_username
|
@@ -2,8 +2,6 @@
|
|
2
2
|
# HEROKU DEFAULTS #
|
3
3
|
######################################################################
|
4
4
|
Capistrano::Configuration.instance(:must_exist).load do
|
5
|
-
extend ChickenSoup
|
6
|
-
|
7
5
|
namespace :capabilities do
|
8
6
|
namespace :defaults do
|
9
7
|
desc "[internal] Sets intelligent defaults for Heroku deployments"
|
@@ -2,23 +2,22 @@
|
|
2
2
|
# NGINX DEFAULTS #
|
3
3
|
######################################################################
|
4
4
|
module ChickenSoup
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
abort "Couldn't figure out how to control your installation of Nginx" unless exists?(:web_server_control_script)
|
5
|
+
module WebServer
|
6
|
+
STANDARD_CONTROL_SCRIPTS = ['/etc/init.d/nginx']
|
7
|
+
STANDARD_LOG_LOCATIONS = ['/var/log/nginx', '/var/log/nginx/current']
|
8
|
+
STANDARD_ERROR_LOGS = ['error.log']
|
9
|
+
STANDARD_ACCESS_LOGS = ['access.log']
|
11
10
|
end
|
12
11
|
end
|
13
12
|
|
14
13
|
Capistrano::Configuration.instance(:must_exist).load do
|
15
|
-
|
14
|
+
require 'chicken_soup/capabilities/shared/web_server-defaults'
|
16
15
|
|
17
16
|
namespace :capabilities do
|
18
17
|
namespace :defaults do
|
19
18
|
desc "[internal] Checks to see what type of Nginx installation is running on the remote."
|
20
19
|
task :nginx do
|
21
|
-
|
20
|
+
capabilities.defaults.web_server
|
22
21
|
end
|
23
22
|
end
|
24
23
|
end
|
@@ -1,10 +1,18 @@
|
|
1
1
|
######################################################################
|
2
2
|
# PASSENGER DEFAULTS #
|
3
3
|
######################################################################
|
4
|
+
module ChickenSoup
|
5
|
+
module ApplicationServer
|
6
|
+
STANDARD_LOGS = ['passenger_log', 'passenger.log', 'passenger']
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
4
10
|
Capistrano::Configuration.instance(:must_exist).load do
|
5
11
|
namespace :capabilities do
|
6
12
|
namespace :defaults do
|
7
|
-
|
13
|
+
task :passenger do
|
14
|
+
set :application_server_type, :passenger
|
15
|
+
end
|
8
16
|
end
|
9
17
|
end
|
10
18
|
end
|
@@ -6,24 +6,24 @@ module ChickenSoup
|
|
6
6
|
end
|
7
7
|
|
8
8
|
Capistrano::Configuration.instance(:must_exist).load do
|
9
|
-
extend ChickenSoup
|
10
|
-
|
11
9
|
namespace :capabilities do
|
12
10
|
namespace :defaults do
|
13
|
-
|
14
|
-
|
11
|
+
task :rvm do
|
12
|
+
_cset :rvmrc_file, File.join(rails_root, '.rvmrc')
|
13
|
+
set :ruby_version_update_pending, false
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
_cset(:ruby_version) do
|
16
|
+
contents = File.read(rvmrc_file)
|
17
|
+
contents.match(ChickenSoup::RVM_INFO_FORMAT)[2]
|
18
|
+
end
|
20
19
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
20
|
+
_cset(:ruby_gemset) do
|
21
|
+
contents = File.read(rvmrc_file)
|
22
|
+
contents.match(ChickenSoup::RVM_INFO_FORMAT)[3]
|
23
|
+
end
|
25
24
|
|
26
|
-
|
25
|
+
_cset(:full_ruby_environment_string) {ruby_gemset ? "#{ruby_version}@#{ruby_gemset}" : ruby_version}
|
26
|
+
end
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
@@ -2,8 +2,6 @@
|
|
2
2
|
# DB CHECKS #
|
3
3
|
######################################################################
|
4
4
|
Capistrano::Configuration.instance(:must_exist).load do
|
5
|
-
extend ChickenSoup
|
6
|
-
|
7
5
|
namespace :capabilities do
|
8
6
|
namespace :variable do
|
9
7
|
namespace :check do
|
@@ -13,7 +11,11 @@ Capistrano::Configuration.instance(:must_exist).load do
|
|
13
11
|
task :db do
|
14
12
|
required_variables = [
|
15
13
|
:skip_backup_before_migration,
|
16
|
-
:db_backups_path
|
14
|
+
:db_backups_path,
|
15
|
+
:db_backup_file_extension,
|
16
|
+
:autocompress_db_backups,
|
17
|
+
:limit_db_backups,
|
18
|
+
:total_db_backup_limit
|
17
19
|
]
|
18
20
|
|
19
21
|
verify_variables(required_variables)
|
@@ -2,14 +2,22 @@
|
|
2
2
|
# DB DEFAULTS #
|
3
3
|
######################################################################
|
4
4
|
Capistrano::Configuration.instance(:must_exist).load do
|
5
|
-
extend ChickenSoup
|
6
|
-
|
7
5
|
namespace :capabilities do
|
8
6
|
namespace :defaults do
|
9
7
|
desc "[internal] Sets intelligent defaults for DB deployments."
|
10
8
|
task :db do
|
11
9
|
_cset :skip_backup_before_migration, false
|
10
|
+
|
12
11
|
_cset :db_backups_path, "#{shared_path}/db_backups"
|
12
|
+
_cset :db_backup_file_extension, "dump.sql"
|
13
|
+
|
14
|
+
_cset :autocompress_db_backups, true
|
15
|
+
|
16
|
+
set(:latest_db_backup_file) {capture("ls #{db_backups_path} -1t | head -n 1").chomp}
|
17
|
+
set(:latest_db_backup) {"#{db_backups_path}/#{latest_db_backup_file}"}
|
18
|
+
|
19
|
+
_cset :limit_db_backups, true
|
20
|
+
_cset :total_db_backup_limit, 100
|
13
21
|
end
|
14
22
|
end
|
15
23
|
end
|
@@ -2,8 +2,6 @@
|
|
2
2
|
# COMMON DB TASKS #
|
3
3
|
######################################################################
|
4
4
|
Capistrano::Configuration.instance(:must_exist).load do
|
5
|
-
extend ChickenSoup
|
6
|
-
|
7
5
|
_cset(:db_root_password) {Capistrano::CLI.password_prompt("Root Password For DB: ")}
|
8
6
|
_cset(:db_app_password) {Capistrano::CLI.password_prompt("App Password For DB: ")}
|
9
7
|
|
@@ -11,20 +9,71 @@ Capistrano::Configuration.instance(:must_exist).load do
|
|
11
9
|
run_task "db:drop", :as => manager_username
|
12
10
|
|
13
11
|
before "deploy:cleanup", "deploy:migrate"
|
14
|
-
before "deploy:migrate", "db:backup"
|
12
|
+
before "deploy:migrate", "db:backup" unless skip_backup_before_migration
|
15
13
|
|
16
|
-
|
17
|
-
|
18
|
-
Calls the rake task `db:backup` on the server for the given environment.
|
14
|
+
after "db:backup", "db:backup:compress" if autocompress_db_backups
|
15
|
+
after "db:backup", "db:backup:cleanup" if limit_db_backups
|
19
16
|
|
20
|
-
|
21
|
-
directory by default.
|
22
|
-
* The filenames are formatted with the timestamp of the backup.
|
23
|
-
* After export, each file is zipped up using a bzip2 compression format.
|
24
|
-
DESC
|
17
|
+
namespace :db do
|
25
18
|
namespace :backup do
|
19
|
+
desc <<-DESC
|
20
|
+
Calls the rake task `db:backup` on the server for the given environment.
|
21
|
+
|
22
|
+
* The backup file is placed in a directory called `db_backups` under the `shared`
|
23
|
+
directory by default.
|
24
|
+
* The filenames are formatted with the timestamp of the backup.
|
25
|
+
* After export, each file is zipped up using a bzip2 compression format.
|
26
|
+
DESC
|
26
27
|
task :default, :roles => :db, :only => {:primary => true} do
|
27
|
-
run
|
28
|
+
run %Q{cd #{current_path} && BACKUP_DIRECTORY="#{db_backups_path}" BACKUP_FILE="#{release_name}" BACKUP_FILE_EXTENSION="#{db_backup_file_extension}" #{rake} db:backup}
|
29
|
+
end
|
30
|
+
|
31
|
+
desc <<-DESC
|
32
|
+
If the user has decided they would like to limit the number of db backups
|
33
|
+
that can exist on the system, this task is called to clean up any files
|
34
|
+
which are over that limit.
|
35
|
+
|
36
|
+
The oldest files are cleaned up first.
|
37
|
+
DESC
|
38
|
+
task :cleanup, :roles => :db, :only => {:primary => true} do
|
39
|
+
number_of_backups = capture("ls #{db_backups_path} -1 | wc -l").chomp.to_i
|
40
|
+
|
41
|
+
if number_of_backups > total_db_backup_limit
|
42
|
+
backup_files_to_remove = capture("ls #{db_backups_path}/* -1t | tail -n #{number_of_backups - total_db_backup_limit}").chomp.split("\n")
|
43
|
+
|
44
|
+
backup_files_to_remove.each do |file|
|
45
|
+
run "rm -f #{file}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
namespace :compress do
|
51
|
+
desc <<-DESC
|
52
|
+
Compresses the most recent backup if it isn't already compressed.
|
53
|
+
|
54
|
+
The compression format is bzip2.
|
55
|
+
DESC
|
56
|
+
task :default, :roles => :db, :only => {:primary => true} do
|
57
|
+
run "bzip2 -zvck9 #{latest_db_backup} > #{latest_db_backup}.bz2 && rm -f #{latest_db_backup}" unless compressed_file?(latest_db_backup)
|
58
|
+
|
59
|
+
# After compressing, the latest_db_backup is no longer the latest DB
|
60
|
+
# backup so we need to reset it.
|
61
|
+
reset! :latest_db_backup_file
|
62
|
+
reset! :latest_db_backup
|
63
|
+
end
|
64
|
+
|
65
|
+
desc <<-DESC
|
66
|
+
Compresses any uncompressed DB backups to help save space.
|
67
|
+
|
68
|
+
The compression format is bzip2.
|
69
|
+
DESC
|
70
|
+
task :all, :roles => :db, :only => {:primary => true} do
|
71
|
+
uncompressed_backup_files = capture("ls #{db_backups_path}/*.#{db_backup_file_extension} -1tr").chomp.split("\n")
|
72
|
+
|
73
|
+
uncompressed_backup_files.each do |file|
|
74
|
+
run "bzip2 -zvck9 #{file} > #{file}.bz2 && rm -f #{file}"
|
75
|
+
end
|
76
|
+
end
|
28
77
|
end
|
29
78
|
end
|
30
79
|
|
@@ -49,12 +98,15 @@ Capistrano::Configuration.instance(:must_exist).load do
|
|
49
98
|
Just like `db:pull` but doesn't create a new backup first.
|
50
99
|
DESC
|
51
100
|
task :latest, :roles => :db, :only => {:primary => true} do
|
52
|
-
|
101
|
+
download_compressed "#{latest_db_backup}", "#{rails_root}/tmp/#{latest_db_backup_file}", :once => true
|
53
102
|
|
54
|
-
|
103
|
+
latest_local_db_backup = `ls -1t #{rails_root}/tmp/*.#{db_backup_file_extension} | head -n 1`.chomp
|
55
104
|
|
105
|
+
puts 'Running `rake db:drop:all db:create:all` locally'
|
56
106
|
`rake db:drop:all db:create:all`
|
57
|
-
`rails dbconsole development < #{
|
107
|
+
puts "Running `rails dbconsole development < #{latest_local_db_backup}` locally"
|
108
|
+
`rails dbconsole development < #{latest_local_db_backup}`
|
109
|
+
puts "Running `rake db:migrate db:test:prepare` locally"
|
58
110
|
`rake db:migrate db:test:prepare`
|
59
111
|
end
|
60
112
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
######################################################################
|
2
|
+
# WEB SERVER DEFAULTS #
|
3
|
+
######################################################################
|
4
|
+
Capistrano::Configuration.instance(:must_exist).load do
|
5
|
+
namespace :capabilities do
|
6
|
+
namespace :defaults do
|
7
|
+
desc "[internal] Sets common defaults for web servers."
|
8
|
+
task :web_server do
|
9
|
+
_cset(:web_server_control_script) { WebServer::STANDARD_CONTROL_SCRIPTS.detect { |f| remote_directory_exists? f } }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -2,8 +2,6 @@
|
|
2
2
|
# COMMON WEB SERVER TASKS #
|
3
3
|
######################################################################
|
4
4
|
Capistrano::Configuration.instance(:must_exist).load do
|
5
|
-
extend ChickenSoup
|
6
|
-
|
7
5
|
run_task 'web_server:stop', :as => manager_username
|
8
6
|
run_task 'web_server:start', :as => manager_username
|
9
7
|
run_task 'web_server:restart', :as => manager_username
|
@@ -50,7 +48,7 @@ Capistrano::Configuration.instance(:must_exist).load do
|
|
50
48
|
web-accessible again.
|
51
49
|
DESC
|
52
50
|
task :disable, :roles => :web do
|
53
|
-
run "rm #{shared_path}/system
|
51
|
+
run "rm #{shared_path}/system/#{maintenance_basename}.html"
|
54
52
|
end
|
55
53
|
|
56
54
|
desc <<-DESC
|
@@ -70,15 +68,15 @@ Capistrano::Configuration.instance(:must_exist).load do
|
|
70
68
|
Further customization will require that you write your own task.
|
71
69
|
DESC
|
72
70
|
task :enable, :roles => :web do
|
73
|
-
on_rollback { rm "#{shared_path}/system
|
71
|
+
on_rollback { rm "#{shared_path}/system/#{maintenance_basename}.html" }
|
74
72
|
|
75
73
|
require 'erb'
|
76
74
|
deadline, reason = ENV['UNTIL'], ENV['REASON']
|
77
75
|
|
78
|
-
template = File.read(
|
76
|
+
template = File.read(maintenance_filename)
|
79
77
|
maintenance_page = ERB.new(template).result(binding)
|
80
78
|
|
81
|
-
put maintenance_page, "#{shared_path}/system
|
79
|
+
put maintenance_page, "#{shared_path}/system/#{maintenance_basename}.html", :mode => 0644
|
82
80
|
end
|
83
81
|
end
|
84
82
|
end
|
@@ -2,8 +2,6 @@
|
|
2
2
|
# SUBVERSION DEFAULTS #
|
3
3
|
######################################################################
|
4
4
|
Capistrano::Configuration.instance(:must_exist).load do
|
5
|
-
extend ChickenSoup
|
6
|
-
|
7
5
|
namespace :capabilities do
|
8
6
|
namespace :defaults do
|
9
7
|
desc "[internal] Sets intelligent version control defaults for deployments"
|
@@ -2,8 +2,6 @@
|
|
2
2
|
# UNIX CHECKS #
|
3
3
|
######################################################################
|
4
4
|
Capistrano::Configuration.instance(:must_exist).load do
|
5
|
-
extend ChickenSoup
|
6
|
-
|
7
5
|
namespace :capabilities do
|
8
6
|
namespace :variable do
|
9
7
|
namespace :check do
|
@@ -24,9 +22,9 @@ Capistrano::Configuration.instance(:must_exist).load do
|
|
24
22
|
:app_server_ip,
|
25
23
|
:web_server_ip,
|
26
24
|
:db_server_ip,
|
27
|
-
:
|
28
|
-
:
|
29
|
-
:
|
25
|
+
:web_server_name,
|
26
|
+
:app_server_name,
|
27
|
+
:db_server_name
|
30
28
|
]
|
31
29
|
|
32
30
|
verify_variables(required_variables)
|
@@ -2,8 +2,6 @@
|
|
2
2
|
# UNIX SERVER DEFAULTS #
|
3
3
|
######################################################################
|
4
4
|
Capistrano::Configuration.instance(:must_exist).load do
|
5
|
-
extend ChickenSoup
|
6
|
-
|
7
5
|
namespace :capabilities do
|
8
6
|
namespace :defaults do
|
9
7
|
desc "[internal] Sets intelligent defaults for unix server deployments."
|
@@ -19,15 +17,16 @@ Capistrano::Configuration.instance(:must_exist).load do
|
|
19
17
|
_cset :deploy_site_name, domain
|
20
18
|
set :deploy_to, "#{deploy_base_dir}/#{deploy_site_name}"
|
21
19
|
|
22
|
-
_cset :app_server_ip, default_server_ip
|
23
|
-
_cset :web_server_ip, default_server_ip
|
24
|
-
_cset :db_server_ip, default_server_ip
|
25
|
-
|
26
20
|
_cset :default_server_name, domain
|
21
|
+
_cset(:default_server_ip) { lookup_ip_for default_server_name }
|
22
|
+
|
23
|
+
_cset(:app_server_name) { default_server_name }
|
24
|
+
_cset(:web_server_name) { default_server_name }
|
25
|
+
_cset(:db_server_name) { default_server_name }
|
27
26
|
|
28
|
-
_cset(:
|
29
|
-
_cset(:
|
30
|
-
_cset(:
|
27
|
+
_cset(:app_server_ip) { lookup_ip_for app_server_name }
|
28
|
+
_cset(:web_server_ip) { lookup_ip_for web_server_name }
|
29
|
+
_cset(:db_server_ip) { lookup_ip_for db_server_name }
|
31
30
|
|
32
31
|
# Evidently roles can't be assigned in a namespace :-/
|
33
32
|
set_unix_server_roles
|
@@ -37,8 +36,8 @@ Capistrano::Configuration.instance(:must_exist).load do
|
|
37
36
|
|
38
37
|
desc "[internal] This task is only here because `role` cannot be used within a `namespace`"
|
39
38
|
task :set_unix_server_roles do
|
40
|
-
role :web,
|
41
|
-
role :app,
|
42
|
-
role :db,
|
39
|
+
role :web, web_server_name
|
40
|
+
role :app, app_server_name
|
41
|
+
role :db, db_server_name, :primary => true
|
43
42
|
end
|
44
43
|
end
|
@@ -14,8 +14,6 @@
|
|
14
14
|
#
|
15
15
|
######################################################################
|
16
16
|
Capistrano::Configuration.instance(:must_exist).load do
|
17
|
-
extend ChickenSoup
|
18
|
-
|
19
17
|
require 'chicken_soup/capabilities/defaults'
|
20
18
|
require 'chicken_soup/capabilities/checks'
|
21
19
|
require 'chicken_soup/capabilities/tasks'
|
@@ -6,8 +6,8 @@
|
|
6
6
|
# First, an environment MUST be present in order for any deployment
|
7
7
|
# to happen. It's a safety measure that this is explicitly stated.
|
8
8
|
#
|
9
|
-
# It also checks to make sure that the :application
|
10
|
-
#
|
9
|
+
# It also checks to make sure that the :application environment
|
10
|
+
# variable has been set.
|
11
11
|
#
|
12
12
|
# This happens before any of the capabilities have been added to the
|
13
13
|
# deployment and therefore that is all we know to check for at this
|
@@ -15,8 +15,6 @@
|
|
15
15
|
#
|
16
16
|
######################################################################
|
17
17
|
Capistrano::Configuration.instance(:must_exist).load do
|
18
|
-
extend ChickenSoup
|
19
|
-
|
20
18
|
on :start, 'environment:variable:check', :except => ['staging', 'production']
|
21
19
|
before 'deploy', 'environment:deployment:check'
|
22
20
|
before 'deploy:cold', 'environment:deployment:check'
|
@@ -33,8 +31,7 @@ Capistrano::Configuration.instance(:must_exist).load do
|
|
33
31
|
abort "You need to specify a deployment type in your application's 'deploy.rb' file. ie 'set :deployment_type, :heroku'" unless exists?(:deployment_type)
|
34
32
|
|
35
33
|
required_variables = [
|
36
|
-
:application
|
37
|
-
:application_short
|
34
|
+
:application
|
38
35
|
]
|
39
36
|
|
40
37
|
verify_variables(required_variables)
|
@@ -20,23 +20,25 @@
|
|
20
20
|
require 'etc'
|
21
21
|
|
22
22
|
Capistrano::Configuration.instance(:must_exist).load do
|
23
|
-
extend ChickenSoup
|
24
|
-
|
25
23
|
after 'production', 'environment:defaults:production', 'environment:init'
|
26
24
|
after 'staging', 'environment:defaults:staging', 'environment:init'
|
27
25
|
|
28
|
-
after 'environment:defaults', 'capabilities:defaults', 'notifiers:defaults'
|
26
|
+
after 'environment:defaults', 'capabilities:defaults', 'notifiers:defaults', 'tools:defaults'
|
29
27
|
|
30
28
|
namespace :environment do
|
31
29
|
namespace :defaults do
|
32
30
|
desc "[internal] Used to set up the intelligent staging defaults we like for our projects"
|
33
31
|
task :staging do
|
34
32
|
set :rails_env, 'staging'
|
33
|
+
|
34
|
+
_cset(:domain) { "staging.#{application}.com" }
|
35
35
|
end
|
36
36
|
|
37
37
|
desc "[internal] Used to set up the intelligent production defaults we like for our projects"
|
38
38
|
task :production do
|
39
39
|
set :rails_env, 'production'
|
40
|
+
|
41
|
+
_cset(:domain) { "#{application}.com" }
|
40
42
|
end
|
41
43
|
|
42
44
|
desc "[internal] Sets intelligent common defaults for deployments"
|
@@ -51,10 +53,15 @@ Capistrano::Configuration.instance(:must_exist).load do
|
|
51
53
|
|
52
54
|
_cset :global_shared_elements, ["config/database.yml"]
|
53
55
|
|
56
|
+
_cset :maintenance_page_path, 'public'
|
57
|
+
|
54
58
|
_cset :notifiers, []
|
59
|
+
_cset :tools, [:log]
|
55
60
|
|
56
|
-
_cset(:application_short) {application}
|
57
61
|
_cset(:application_underscored) {application.gsub(/-/, "_")}
|
62
|
+
|
63
|
+
_cset(:latest_release_name) {exists?(:deploy_timestamped) ? release_name : releases.last}
|
64
|
+
_cset(:previous_release_name) {releases.length > 1 ? releases[-2] : nil}
|
58
65
|
end
|
59
66
|
end
|
60
67
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
# ENVIRONMENT TASKS #
|
3
3
|
######################################################################
|
4
4
|
Capistrano::Configuration.instance(:must_exist).load do
|
5
|
-
after 'environment:load_tasks', 'capabilities:load_tasks', 'notifiers:load_tasks'
|
5
|
+
after 'environment:load_tasks', 'capabilities:load_tasks', 'notifiers:load_tasks', 'tools:load_tasks'
|
6
6
|
|
7
7
|
namespace :environment do
|
8
8
|
desc "[internal] A helper task used to load the tasks for all of the capabilities."
|
data/lib/chicken_soup/global.rb
CHANGED
@@ -115,7 +115,13 @@ module ChickenSoup
|
|
115
115
|
# remote_file_exists? '/var/www/myappdir/current'
|
116
116
|
#
|
117
117
|
def remote_file_exists?(file)
|
118
|
-
capture("if [[ -d #{file} ]] || [[ -h #{file} ]] || [[ -f #{file} ]]; then echo -n 'exists'; fi;") ==
|
118
|
+
capture("if [[ -d #{file} ]] || [[ -h #{file} ]] || [[ -f #{file} ]]; then echo -n 'exists'; fi;") == 'exists'
|
119
|
+
end
|
120
|
+
|
121
|
+
def remote_directory_exists?(directory, options = {})
|
122
|
+
with_files_check = options[:with_files] ? "&& $(ls -A #{directory})" : ''
|
123
|
+
|
124
|
+
capture("if [[ -d #{directory} #{with_files_check} ]]; then echo -n 'exists'; fi") == 'exists'
|
119
125
|
end
|
120
126
|
|
121
127
|
###
|
@@ -152,16 +158,40 @@ module ChickenSoup
|
|
152
158
|
# download_compressed 'my/remote/file', 'my/local/file', :once => true
|
153
159
|
#
|
154
160
|
def download_compressed(remote, local, options = {})
|
155
|
-
|
156
|
-
|
161
|
+
remote_basename = File.basename(remote)
|
162
|
+
|
163
|
+
unless compressed_file? remote
|
164
|
+
remote_compressed_filename = "#{user_home}/#{remote_basename}.bz2"
|
165
|
+
local_compressed_filename = "#{local}.bz2"
|
166
|
+
|
167
|
+
run "bzip2 -zvck9 #{remote} > #{remote_compressed_filename}"
|
168
|
+
end
|
169
|
+
|
170
|
+
remote_compressed_filename ||= remote
|
171
|
+
local_compressed_filename ||= local
|
157
172
|
|
158
|
-
run "bzip2 -zvck9 #{remote} > #{remote_compressed_filename}"
|
159
173
|
download remote_compressed_filename, local_compressed_filename, options
|
160
174
|
|
161
|
-
run "rm -f #{remote_compressed_filename}"
|
175
|
+
run "rm -f #{remote_compressed_filename}" unless remote_compressed_filename == remote
|
162
176
|
`bunzip2 -f #{local_compressed_filename} && rm -f #{local_compressed_filename}`
|
163
177
|
end
|
164
178
|
|
179
|
+
###
|
180
|
+
# Checks to see if a filename has an extension which would imply that
|
181
|
+
# it is compressed.
|
182
|
+
#
|
183
|
+
# @param [String] filename The filename whose extension will be checked.
|
184
|
+
#
|
185
|
+
# @return [Boolean] the result of whether the file has a compression
|
186
|
+
# extension.
|
187
|
+
#
|
188
|
+
# @example
|
189
|
+
# compressed_file? 'file.bz2'
|
190
|
+
#
|
191
|
+
def compressed_file?(filename)
|
192
|
+
filename =~ /.*\.bz2/
|
193
|
+
end
|
194
|
+
|
165
195
|
###
|
166
196
|
# A stub method which simply passes through to Capistrano's #run. This
|
167
197
|
# method is meant to be overridden when a Ruby manager capability (ie RVM)
|
@@ -195,4 +225,67 @@ module ChickenSoup
|
|
195
225
|
def vc_log
|
196
226
|
nil
|
197
227
|
end
|
228
|
+
|
229
|
+
###
|
230
|
+
# Uses nslookup locally to figure out the IP address of the provided
|
231
|
+
# hostname.
|
232
|
+
#
|
233
|
+
# @param [String] hostname The hostname you would like to retrieve the
|
234
|
+
# IP for.
|
235
|
+
#
|
236
|
+
# @return [String] The IP address of the provided hostname. If no
|
237
|
+
# IP can be retrieved, nil will be returned.
|
238
|
+
#
|
239
|
+
# @example
|
240
|
+
# lookup_ip_for 'google.com'
|
241
|
+
#
|
242
|
+
def lookup_ip_for(hostname)
|
243
|
+
ip = `nslookup #{hostname} | tail -n 2 | head -n 1 | cut -d ' ' -f 2`.chomp
|
244
|
+
ip != '' ? ip : nil
|
245
|
+
end
|
246
|
+
|
247
|
+
def find_all_logs(log_directory, log_filenames)
|
248
|
+
existing_files = []
|
249
|
+
|
250
|
+
log_filenames.each do |standard_file|
|
251
|
+
existing_files << "#{log_directory}/#{application}.#{standard_file}" if remote_file_exists?("#{log_directory}/#{application}.#{standard_file}")
|
252
|
+
existing_files << "#{log_directory}/#{application}-#{standard_file}" if remote_file_exists?("#{log_directory}/#{application}-#{standard_file}")
|
253
|
+
existing_files << "#{log_directory}/#{standard_file}" if remote_file_exists?("#{log_directory}/#{standard_file}")
|
254
|
+
end
|
255
|
+
|
256
|
+
existing_files
|
257
|
+
end
|
258
|
+
|
259
|
+
def log_directory(log_directories)
|
260
|
+
log_directories.detect do |directory|
|
261
|
+
remote_directory_exists? directory, :with_files => true
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
def fetch_log(logs)
|
266
|
+
logs.each do |log|
|
267
|
+
local_log_directory = "#{rails_root}/log/#{rails_env}/#{release_name}"
|
268
|
+
|
269
|
+
`mkdir -p #{local_log_directory}`
|
270
|
+
download log, "#{local_log_directory}/$CAPISTRANO:HOST$-#{File.basename(log)}"
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
def tail_log(logs)
|
275
|
+
run "tail -n #{ENV['lines'] || 20} -f #{logs.join ' '}" do |channel, stream, data|
|
276
|
+
trap("INT") { puts 'Log tailing aborted...'; exit 0; }
|
277
|
+
|
278
|
+
puts # for an extra line break before the host name
|
279
|
+
puts "#{channel[:host]}: #{data}"
|
280
|
+
|
281
|
+
break if stream == :err
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
def maintenance_filename
|
286
|
+
custom_maintenance_path = File.join(rails_root, maintenance_page_path, "#{maintenance_basename}.html.erb")
|
287
|
+
template_maintenance_path = File.join(File.dirname(__FILE__), "templates", "maintenance.html.erb")
|
288
|
+
|
289
|
+
File.exist?(custom_maintenance_path) ? custom_maintenance_path : template_maintenance_path
|
290
|
+
end
|
198
291
|
end
|
@@ -3,8 +3,6 @@ require 'time'
|
|
3
3
|
module ChickenSoup
|
4
4
|
module Email
|
5
5
|
class Presenter
|
6
|
-
include ChickenSoup
|
7
|
-
|
8
6
|
LongDateFormat = "%A, %B %e, %Y at %l:%M%p %Z"
|
9
7
|
|
10
8
|
def initialize(capistrano)
|
@@ -24,11 +22,11 @@ module ChickenSoup
|
|
24
22
|
end
|
25
23
|
|
26
24
|
def deploy_date_in_long_format
|
27
|
-
format_timestamp(@capistrano[:
|
25
|
+
format_timestamp(@capistrano[:latest_release_name], LongDateFormat)
|
28
26
|
end
|
29
27
|
|
30
28
|
def previous_deploy_date_in_long_format
|
31
|
-
format_timestamp(@capistrano[:
|
29
|
+
format_timestamp(@capistrano[:previous_release_name], LongDateFormat)
|
32
30
|
end
|
33
31
|
|
34
32
|
def notifiers
|
@@ -19,9 +19,9 @@ Capistrano::Configuration.instance(:must_exist).load do
|
|
19
19
|
Tag push happens in the background so it won't slow down deployment.
|
20
20
|
DESC
|
21
21
|
task :tag do
|
22
|
-
tag_name = "deployment/#{rails_env}/#{
|
22
|
+
tag_name = "deployment/#{rails_env}/#{latest_release_name}"
|
23
23
|
|
24
|
-
`git tag -a -m "Tagging deploy to #{rails_env} at #{
|
24
|
+
`git tag -a -m "Tagging deploy to #{rails_env} at #{latest_release_name}" #{tag_name} #{branch}`
|
25
25
|
`git push #{remote} --tags > /dev/null 2>&1 &`
|
26
26
|
`git push origin --tags > /dev/null 2>&1 &`
|
27
27
|
end
|
@@ -2,8 +2,6 @@
|
|
2
2
|
# NOTIFIERS SETUP #
|
3
3
|
######################################################################
|
4
4
|
Capistrano::Configuration.instance(:must_exist).load do
|
5
|
-
extend ChickenSoup
|
6
|
-
|
7
5
|
require 'chicken_soup/notifiers/defaults'
|
8
6
|
require "chicken_soup/notifiers/checks"
|
9
7
|
require "chicken_soup/notifiers/tasks"
|
@@ -0,0 +1,41 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
2
|
+
|
3
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
4
|
+
|
5
|
+
<head>
|
6
|
+
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
|
7
|
+
<title>The page you were looking for doesn't exist (404)</title>
|
8
|
+
<style type="text/css">
|
9
|
+
body {
|
10
|
+
background-color: #fff;
|
11
|
+
color: #666;
|
12
|
+
text-align: center;
|
13
|
+
font-family: arial, sans-serif;
|
14
|
+
}
|
15
|
+
|
16
|
+
div.dialog {
|
17
|
+
width: 25em;
|
18
|
+
padding: 0 4em;
|
19
|
+
margin: 4em auto 0 auto;
|
20
|
+
border: 1px solid #ccc;
|
21
|
+
border-right-color: #999;
|
22
|
+
border-bottom-color: #999;
|
23
|
+
}
|
24
|
+
|
25
|
+
h1 {
|
26
|
+
font-size: 100%;
|
27
|
+
color: #f00;
|
28
|
+
line-height: 1.5em;
|
29
|
+
}
|
30
|
+
</style>
|
31
|
+
</head>
|
32
|
+
|
33
|
+
<body>
|
34
|
+
|
35
|
+
<div class="dialog">
|
36
|
+
<h1>The application is currently down for <%= reason || "maintenance" %>.</h1>
|
37
|
+
|
38
|
+
<p>As of <%= Time.now.strftime("%H:%M %Z") %> this application was taken offline. We apologize for the inconvenience and are doing everything we can to have the site back up <%= deadline ? "by #{deadline}" : "shortly" %>.</p>
|
39
|
+
</div>
|
40
|
+
</body>
|
41
|
+
</html>
|
@@ -0,0 +1,41 @@
|
|
1
|
+
######################################################################
|
2
|
+
# DEFAULT TOOLS SETUP
|
3
|
+
#
|
4
|
+
# The 'tools:defaults' task hooks itself into the deployment
|
5
|
+
# stream by attaching an after hook to 'environment:defaults'.
|
6
|
+
#
|
7
|
+
# Prior to execution, all of the tools which were specified in
|
8
|
+
# the deploy.rb file are loaded and then each tool has its
|
9
|
+
# 'defaults' task called.
|
10
|
+
#
|
11
|
+
# All tools's defaults tasks are in the format:
|
12
|
+
# tools:defaults:<tool_name>
|
13
|
+
#
|
14
|
+
# Defaults tasks are there simply to set standard conventional
|
15
|
+
# standards on each tool. In almost all cases, they can
|
16
|
+
# be overridden.
|
17
|
+
#
|
18
|
+
# Defaults are also optional. If a tools doesn't require any
|
19
|
+
# environment variables to be set, it can simply omit a defaults task.
|
20
|
+
#
|
21
|
+
######################################################################
|
22
|
+
Capistrano::Configuration.instance(:must_exist).load do
|
23
|
+
before 'tools:defaults', 'load_tool_defaults'
|
24
|
+
|
25
|
+
namespace :tools do
|
26
|
+
namespace :defaults do
|
27
|
+
desc <<-DESC
|
28
|
+
[internal] Installs all tools for the given deployment type.
|
29
|
+
|
30
|
+
Most of these values can be overridden in each application's deploy.rb file.
|
31
|
+
DESC
|
32
|
+
task :default do
|
33
|
+
if exists?(:tools)
|
34
|
+
fetch(:tools).each do |tool|
|
35
|
+
tools.defaults.send(tool.to_s) if tools.defaults.respond_to?(tool.to_sym)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
######################################################################
|
2
|
+
# LOG DEFAULTS #
|
3
|
+
######################################################################
|
4
|
+
Capistrano::Configuration.instance(:must_exist).load do
|
5
|
+
namespace :tools do
|
6
|
+
namespace :defaults do
|
7
|
+
task :log do
|
8
|
+
_cset(:web_server_error_log_files) { find_all_logs(web_server_log_directory, ChickenSoup::WebServer::STANDARD_ERROR_LOGS) }
|
9
|
+
_cset(:web_server_access_log_files) { find_all_logs(web_server_log_directory, ChickenSoup::WebServer::STANDARD_ACCESS_LOGS) }
|
10
|
+
_cset(:web_server_log_files) { web_server_access_log_files + web_server_error_log_files }
|
11
|
+
_cset(:web_server_log_directory) { log_directory(ChickenSoup::WebServer::STANDARD_LOG_LOCATIONS) }
|
12
|
+
|
13
|
+
_cset(:app_server_log_files) { find_all_logs(web_server_log_directory, ChickenSoup::ApplicationServer::STANDARD_LOGS) }
|
14
|
+
|
15
|
+
_cset(:rails_log_files) { ["#{shared_path}/log/#{rails_env}.log"] }
|
16
|
+
|
17
|
+
_cset(:log_files) { rails_log_files + app_server_log_files + web_server_log_files }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
######################################################################
|
2
|
+
# LOG TASKS #
|
3
|
+
######################################################################
|
4
|
+
Capistrano::Configuration.instance(:must_exist).load do
|
5
|
+
namespace :log do
|
6
|
+
desc <<-DESC
|
7
|
+
Begins tailing the Rails log file within the specified environment.
|
8
|
+
|
9
|
+
* Pass lines=<number> to give you a bigger look back at what has
|
10
|
+
recently happened. ie: cap staging log lines=50
|
11
|
+
DESC
|
12
|
+
task :default, :roles => :app do
|
13
|
+
log.all.tail
|
14
|
+
end
|
15
|
+
|
16
|
+
namespace :application do
|
17
|
+
task :fetch, :roles => :app do
|
18
|
+
fetch_log(rails_log_files)
|
19
|
+
end
|
20
|
+
|
21
|
+
task :tail, :roles => :app do
|
22
|
+
tail_log(rails_log_files)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
namespace :app_server do
|
27
|
+
task :fetch, :roles => :app do
|
28
|
+
fetch_log(app_server_log_files)
|
29
|
+
end
|
30
|
+
|
31
|
+
task :tail, :roles => :app do
|
32
|
+
tail_log(app_server_log_files)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
namespace :web_server do
|
37
|
+
task :fetch, :roles => :web do
|
38
|
+
fetch_log(web_server_log_files)
|
39
|
+
end
|
40
|
+
|
41
|
+
task :tail, :roles => :web do
|
42
|
+
tail_log(web_server_log_files)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
namespace :all do
|
47
|
+
task :fetch, :roles => [:app, :web] do
|
48
|
+
fetch_log(log_files)
|
49
|
+
end
|
50
|
+
|
51
|
+
task :tail, :roles => [:app, :web] do
|
52
|
+
tail_log(log_files)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
Capistrano::Configuration.instance(:must_exist).load do
|
2
|
+
before 'tools:load_tasks', 'load_tool_tasks'
|
3
|
+
|
4
|
+
namespace :tools do
|
5
|
+
desc <<-DESC
|
6
|
+
[internal] A helper task used to load all of the tasks associated with the
|
7
|
+
requested tools.
|
8
|
+
DESC
|
9
|
+
task :load_tasks do
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
######################################################################
|
2
|
+
# TOOLS SETUP #
|
3
|
+
######################################################################
|
4
|
+
Capistrano::Configuration.instance(:must_exist).load do
|
5
|
+
require "chicken_soup/tools/defaults"
|
6
|
+
require "chicken_soup/tools/tasks"
|
7
|
+
|
8
|
+
['defaults', 'checks', 'tasks'].each do |method|
|
9
|
+
desc "[internal] This task is only here because `require` cannot be used within a `namespace`"
|
10
|
+
task "load_tool_#{method}".to_sym do
|
11
|
+
fetch(:tools).each do |tool|
|
12
|
+
require_if_exists "chicken_soup/tools/#{tool}/#{tool}-#{method}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/chicken_soup/version.rb
CHANGED
data/lib/chicken_stock.rb
CHANGED
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: chicken_soup
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.
|
5
|
+
version: 0.8.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- thekompanee
|
@@ -11,7 +11,7 @@ autorequire:
|
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
13
|
|
14
|
-
date: 2011-08-
|
14
|
+
date: 2011-08-20 00:00:00 -05:00
|
15
15
|
default_executable:
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
@@ -119,6 +119,7 @@ files:
|
|
119
119
|
- lib/chicken_soup/capabilities/shared/db-checks.rb
|
120
120
|
- lib/chicken_soup/capabilities/shared/db-defaults.rb
|
121
121
|
- lib/chicken_soup/capabilities/shared/db-tasks.rb
|
122
|
+
- lib/chicken_soup/capabilities/shared/web_server-defaults.rb
|
122
123
|
- lib/chicken_soup/capabilities/shared/web_server-tasks.rb
|
123
124
|
- lib/chicken_soup/capabilities/svn/svn-defaults.rb
|
124
125
|
- lib/chicken_soup/capabilities/svn/svn-tasks.rb
|
@@ -144,6 +145,12 @@ files:
|
|
144
145
|
- lib/chicken_soup/notifiers/tasks.rb
|
145
146
|
- lib/chicken_soup/templates/client_email.html.erb
|
146
147
|
- lib/chicken_soup/templates/internal_email.html.erb
|
148
|
+
- lib/chicken_soup/templates/maintenance.html.erb
|
149
|
+
- lib/chicken_soup/tools.rb
|
150
|
+
- lib/chicken_soup/tools/defaults.rb
|
151
|
+
- lib/chicken_soup/tools/log/log-defaults.rb
|
152
|
+
- lib/chicken_soup/tools/log/log-tasks.rb
|
153
|
+
- lib/chicken_soup/tools/tasks.rb
|
147
154
|
- lib/chicken_soup/version.rb
|
148
155
|
- lib/chicken_stock.rb
|
149
156
|
- spec/support/focused.rb
|