chicken_soup 0.6.1 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|