capistrano 2.12.0 → 2.13.5
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/CHANGELOG +29 -1
- data/README.mdown +3 -2
- data/bin/capify +1 -3
- data/capistrano.gemspec +3 -3
- data/lib/capistrano/command.rb +1 -0
- data/lib/capistrano/configuration.rb +6 -1
- data/lib/capistrano/configuration/actions/inspect.rb +2 -2
- data/lib/capistrano/configuration/actions/invocation.rb +7 -0
- data/lib/capistrano/configuration/callbacks.rb +22 -4
- data/lib/capistrano/configuration/execution.rb +2 -3
- data/lib/capistrano/configuration/log_formatters.rb +71 -0
- data/lib/capistrano/configuration/namespaces.rb +20 -13
- data/lib/capistrano/logger.rb +98 -4
- data/lib/capistrano/recipes/deploy.rb +45 -83
- data/lib/capistrano/recipes/deploy/assets.rb +1 -1
- data/lib/capistrano/recipes/deploy/scm/git.rb +0 -1
- data/lib/capistrano/recipes/deploy/scm/none.rb +7 -0
- data/lib/capistrano/recipes/deploy/strategy/base.rb +1 -1
- data/lib/capistrano/shell.rb +4 -4
- data/lib/capistrano/version.rb +2 -7
- data/test/command_test.rb +8 -0
- data/test/configuration/actions/inspect_test.rb +13 -2
- data/test/configuration/actions/invocation_test.rb +6 -1
- data/test/configuration/callbacks_test.rb +24 -0
- data/test/configuration/namespace_dsl_test.rb +2 -2
- data/test/configuration_test.rb +1 -1
- data/test/deploy/scm/git_test.rb +1 -1
- data/test/deploy/strategy/copy_test.rb +2 -1
- data/test/logger_formatting_test.rb +94 -0
- data/test/logger_test.rb +12 -1
- metadata +51 -19
- data/lib/capistrano/recipes/deploy/templates/maintenance.rhtml +0 -53
- data/lib/capistrano/recipes/templates/maintenance.rhtml +0 -53
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'benchmark'
|
2
2
|
require 'yaml'
|
3
|
+
require 'shellwords'
|
3
4
|
require 'capistrano/recipes/deploy/scm'
|
4
5
|
require 'capistrano/recipes/deploy/strategy'
|
5
6
|
|
@@ -22,7 +23,7 @@ _cset(:repository) { abort "Please specify the repository that houses your appl
|
|
22
23
|
# are not sufficient.
|
23
24
|
# =========================================================================
|
24
25
|
|
25
|
-
_cset
|
26
|
+
_cset(:scm) { scm_default }
|
26
27
|
_cset :deploy_via, :checkout
|
27
28
|
|
28
29
|
_cset(:deploy_to) { "/u/apps/#{application}" }
|
@@ -31,9 +32,6 @@ _cset(:revision) { source.head }
|
|
31
32
|
_cset :rails_env, "production"
|
32
33
|
_cset :rake, "rake"
|
33
34
|
|
34
|
-
_cset :maintenance_basename, "maintenance"
|
35
|
-
_cset(:maintenance_template_path) { File.join(File.dirname(__FILE__), "templates", "maintenance.rhtml") }
|
36
|
-
|
37
35
|
# =========================================================================
|
38
36
|
# These variables should NOT be changed unless you are very confident in
|
39
37
|
# what you are doing. Make sure you understand all the implications of your
|
@@ -79,6 +77,33 @@ _cset(:latest_release) { exists?(:deploy_timestamped) ? release_path : current_r
|
|
79
77
|
# These are helper methods that will be available to your recipes.
|
80
78
|
# =========================================================================
|
81
79
|
|
80
|
+
# Checks known version control directories to intelligently set the version
|
81
|
+
# control in-use. For example, if a .svn directory exists in the project,
|
82
|
+
# it will set the :scm variable to :subversion, if a .git directory exists
|
83
|
+
# in the project, it will set the :scm variable to :git and so on. If no
|
84
|
+
# directory is found, it will default to :git.
|
85
|
+
def scm_default
|
86
|
+
if File.exist? '.git'
|
87
|
+
:git
|
88
|
+
elsif File.exist? '.accurev'
|
89
|
+
:accurev
|
90
|
+
elsif File.exist? '.bzr'
|
91
|
+
:bzr
|
92
|
+
elsif File.exist? '.cvs'
|
93
|
+
:cvs
|
94
|
+
elsif File.exist? '_darcs'
|
95
|
+
:darcs
|
96
|
+
elsif File.exist? '.hg'
|
97
|
+
:mercurial
|
98
|
+
elsif File.exist? '.perforce'
|
99
|
+
:perforce
|
100
|
+
elsif File.exist? '.svn'
|
101
|
+
:subversion
|
102
|
+
else
|
103
|
+
:none
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
82
107
|
# Auxiliary helper method for the `deploy:check' task. Lets you set up your
|
83
108
|
# own dependencies.
|
84
109
|
def depend(location, type, *args)
|
@@ -240,23 +265,29 @@ namespace :deploy do
|
|
240
265
|
using the :public_children variable.
|
241
266
|
DESC
|
242
267
|
task :finalize_update, :except => { :no_release => true } do
|
243
|
-
|
268
|
+
escaped_release = latest_release.to_s.shellescape
|
269
|
+
commands = []
|
270
|
+
commands << "chmod -R -- g+w #{escaped_release}" if fetch(:group_writable, true)
|
244
271
|
|
245
272
|
# mkdir -p is making sure that the directories are there for some SCM's that don't
|
246
273
|
# save empty folders
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
274
|
+
shared_children.map do |dir|
|
275
|
+
d = dir.shellescape
|
276
|
+
if (dir.rindex('/')) then
|
277
|
+
commands += ["rm -rf -- #{escaped_release}/#{d}",
|
278
|
+
"mkdir -p -- #{escaped_release}/#{dir.slice(0..(dir.rindex('/'))).shellescape}"]
|
279
|
+
else
|
280
|
+
commands << "rm -rf -- #{escaped_release}/#{d}"
|
281
|
+
end
|
282
|
+
commands << "ln -s -- #{shared_path}/#{dir.split('/').last.shellescape} #{escaped_release}/#{d}"
|
254
283
|
end
|
255
284
|
|
285
|
+
run commands.join(' && ') if commands.any?
|
286
|
+
|
256
287
|
if fetch(:normalize_asset_timestamps, true)
|
257
288
|
stamp = Time.now.utc.strftime("%Y%m%d%H%M.%S")
|
258
|
-
asset_paths = fetch(:public_children, %w(images stylesheets javascripts)).map { |p| "#{
|
259
|
-
run
|
289
|
+
asset_paths = fetch(:public_children, %w(images stylesheets javascripts)).map { |p| "#{escaped_release}/public/#{p}" }
|
290
|
+
run("find #{asset_paths.join(" ").shellescape} -exec touch -t -- #{stamp} {} ';'; true", :env => { "TZ" => "UTC" }) if asset_paths.any?
|
260
291
|
end
|
261
292
|
end
|
262
293
|
|
@@ -522,73 +553,4 @@ namespace :deploy do
|
|
522
553
|
system(source.local.log(from))
|
523
554
|
end
|
524
555
|
end
|
525
|
-
|
526
|
-
namespace :web do
|
527
|
-
desc <<-DESC
|
528
|
-
Present a maintenance page to visitors. Disables your application's web \
|
529
|
-
interface by writing a "#{maintenance_basename}.html" file to each web server. The \
|
530
|
-
servers must be configured to detect the presence of this file, and if \
|
531
|
-
it is present, always display it instead of performing the request.
|
532
|
-
|
533
|
-
By default, the maintenance page will just say the site is down for \
|
534
|
-
"maintenance", and will be back "shortly", but you can customize the \
|
535
|
-
page by specifying the REASON and UNTIL environment variables:
|
536
|
-
|
537
|
-
$ cap deploy:web:disable \\
|
538
|
-
REASON="hardware upgrade" \\
|
539
|
-
UNTIL="12pm Central Time"
|
540
|
-
|
541
|
-
You can use a different template for the maintenance page by setting the \
|
542
|
-
:maintenance_template_path variable in your deploy.rb file. The template file \
|
543
|
-
should either be a plaintext or an erb file.
|
544
|
-
|
545
|
-
Further customization will require that you write your own task.
|
546
|
-
DESC
|
547
|
-
task :disable, :roles => :web, :except => { :no_release => true } do
|
548
|
-
require 'erb'
|
549
|
-
on_rollback { run "rm -f #{shared_path}/system/#{maintenance_basename}.html" }
|
550
|
-
|
551
|
-
warn <<-EOHTACCESS
|
552
|
-
|
553
|
-
# Please add something like this to your site's Apache htaccess to redirect users to the maintenance page.
|
554
|
-
# More Info: http://www.shiftcommathree.com/articles/make-your-rails-maintenance-page-respond-with-a-503
|
555
|
-
|
556
|
-
ErrorDocument 503 /system/#{maintenance_basename}.html
|
557
|
-
RewriteEngine On
|
558
|
-
RewriteCond %{REQUEST_URI} !\.(css|gif|jpg|png)$
|
559
|
-
RewriteCond %{DOCUMENT_ROOT}/system/#{maintenance_basename}.html -f
|
560
|
-
RewriteCond %{SCRIPT_FILENAME} !#{maintenance_basename}.html
|
561
|
-
RewriteRule ^.*$ - [redirect=503,last]
|
562
|
-
|
563
|
-
# Or if you are using Nginx add this to your server config:
|
564
|
-
|
565
|
-
if (-f $document_root/system/maintenance.html) {
|
566
|
-
return 503;
|
567
|
-
}
|
568
|
-
error_page 503 @maintenance;
|
569
|
-
location @maintenance {
|
570
|
-
rewrite ^(.*)$ /system/maintenance.html last;
|
571
|
-
break;
|
572
|
-
}
|
573
|
-
EOHTACCESS
|
574
|
-
|
575
|
-
reason = ENV['REASON']
|
576
|
-
deadline = ENV['UNTIL']
|
577
|
-
|
578
|
-
template = File.read(maintenance_template_path)
|
579
|
-
result = ERB.new(template).result(binding)
|
580
|
-
|
581
|
-
put result, "#{shared_path}/system/#{maintenance_basename}.html", :mode => 0644
|
582
|
-
end
|
583
|
-
|
584
|
-
desc <<-DESC
|
585
|
-
Makes the application web-accessible again. Removes the \
|
586
|
-
"#{maintenance_basename}.html" page generated by deploy:web:disable, which (if your \
|
587
|
-
web servers are configured correctly) will make your application \
|
588
|
-
web-accessible again.
|
589
|
-
DESC
|
590
|
-
task :enable, :roles => :web, :except => { :no_release => true } do
|
591
|
-
run "rm -f #{shared_path}/system/#{maintenance_basename}.html"
|
592
|
-
end
|
593
|
-
end
|
594
556
|
end
|
@@ -16,7 +16,7 @@ namespace :deploy do
|
|
16
16
|
for the assets directory. Assets are shared across deploys to avoid \
|
17
17
|
mid-deploy mismatches between old application html asking for assets \
|
18
18
|
and getting a 404 file not found error. The assets cache is shared \
|
19
|
-
for efficiency. If you
|
19
|
+
for efficiency. If you customize the assets path prefix, override the \
|
20
20
|
:assets_prefix variable to match.
|
21
21
|
DESC
|
22
22
|
task :symlink, :roles => assets_role, :except => { :no_release => true } do
|
@@ -190,7 +190,6 @@ module Capistrano
|
|
190
190
|
|
191
191
|
if variable(:git_enable_submodules)
|
192
192
|
execute << "#{git} submodule #{verbose} init"
|
193
|
-
execute << "for mod in `#{git} submodule status | awk '{ print $2 }'`; do #{git} config -f .git/config submodule.${mod}.url `#{git} config -f .gitmodules --get submodule.${mod}.url` && echo Synced $mod; done"
|
194
193
|
execute << "#{git} submodule #{verbose} sync"
|
195
194
|
if false == variable(:git_submodules_recursive)
|
196
195
|
execute << "#{git} submodule #{verbose} update --init"
|
@@ -73,7 +73,7 @@ module Capistrano
|
|
73
73
|
private
|
74
74
|
|
75
75
|
def logger
|
76
|
-
@logger ||= configuration
|
76
|
+
@logger ||= configuration.logger || Capistrano::Logger.new(:output => STDOUT)
|
77
77
|
end
|
78
78
|
|
79
79
|
# The revision to deploy. Must return a real revision identifier,
|
data/lib/capistrano/shell.rb
CHANGED
@@ -251,10 +251,10 @@ HELP
|
|
251
251
|
puts "scoping #{scope_type} #{scope_value}"
|
252
252
|
end
|
253
253
|
end
|
254
|
-
end
|
255
254
|
|
256
|
-
|
257
|
-
|
258
|
-
|
255
|
+
# All open sessions, needed to satisfy the Command::Processable include
|
256
|
+
def sessions
|
257
|
+
configuration.sessions.values
|
258
|
+
end
|
259
259
|
end
|
260
260
|
end
|
data/lib/capistrano/version.rb
CHANGED
data/test/command_test.rb
CHANGED
@@ -254,6 +254,14 @@ class CommandTest < Test::Unit::TestCase
|
|
254
254
|
Capistrano::Command.new("echo $CAPISTRANO:OTHER$", [session])
|
255
255
|
end
|
256
256
|
|
257
|
+
def test_input_stream_closed_when_eof_option_is_true
|
258
|
+
channel = nil
|
259
|
+
session = setup_for_extracting_channel_action { |ch| channel = ch }
|
260
|
+
channel.expects(:eof!)
|
261
|
+
Capistrano::Command.new("cat", [session], :data => "here we go", :eof => true)
|
262
|
+
assert_equal({ :data => 'here we go', :eof => true }, channel[:options])
|
263
|
+
end
|
264
|
+
|
257
265
|
private
|
258
266
|
|
259
267
|
def mock_session(channel=nil)
|
@@ -9,13 +9,19 @@ class ConfigurationActionsInspectTest < Test::Unit::TestCase
|
|
9
9
|
def setup
|
10
10
|
@config = MockConfig.new
|
11
11
|
@config.stubs(:logger).returns(stub_everything)
|
12
|
+
@config.stubs(:sudo).returns('sudo')
|
12
13
|
end
|
13
14
|
|
14
15
|
def test_stream_should_pass_options_through_to_run
|
15
|
-
@config.expects(:invoke_command).with("tail -f foo.log", :once => true)
|
16
|
+
@config.expects(:invoke_command).with("tail -f foo.log", :once => true, :eof => true)
|
16
17
|
@config.stream("tail -f foo.log", :once => true)
|
17
18
|
end
|
18
19
|
|
20
|
+
def test_stream_with_sudo_should_avoid_closing_stdin
|
21
|
+
@config.expects(:invoke_command).with("sudo tail -f foo.log", :once => true, :eof => false)
|
22
|
+
@config.stream("sudo tail -f foo.log", :once => true)
|
23
|
+
end
|
24
|
+
|
19
25
|
def test_stream_should_emit_stdout_via_puts
|
20
26
|
@config.expects(:invoke_command).yields(mock("channel"), :out, "something streamed")
|
21
27
|
@config.expects(:puts).with("something streamed")
|
@@ -33,10 +39,15 @@ class ConfigurationActionsInspectTest < Test::Unit::TestCase
|
|
33
39
|
end
|
34
40
|
|
35
41
|
def test_capture_should_pass_options_merged_with_once_to_run
|
36
|
-
@config.expects(:invoke_command).with("hostname", :foo => "bar", :once => true)
|
42
|
+
@config.expects(:invoke_command).with("hostname", :foo => "bar", :once => true, :eof => true)
|
37
43
|
@config.capture("hostname", :foo => "bar")
|
38
44
|
end
|
39
45
|
|
46
|
+
def test_capture_with_sudo_should_avoid_closing_stdin
|
47
|
+
@config.expects(:invoke_command).with("sudo hostname", :foo => "bar", :once => true, :eof => false)
|
48
|
+
@config.capture("sudo hostname", :foo => "bar")
|
49
|
+
end
|
50
|
+
|
40
51
|
def test_capture_with_stderr_should_emit_stderr_via_warn
|
41
52
|
ch = mock("channel")
|
42
53
|
ch.expects(:[]).with(:server).returns(server("capistrano"))
|
@@ -45,7 +45,7 @@ class ConfigurationActionsInvocationTest < Test::Unit::TestCase
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def test_run_options_should_be_passed_to_execute_on_servers
|
48
|
-
@config.expects(:execute_on_servers).with(:foo => "bar")
|
48
|
+
@config.expects(:execute_on_servers).with(:foo => "bar", :eof => true)
|
49
49
|
@config.run "ls", :foo => "bar"
|
50
50
|
end
|
51
51
|
|
@@ -115,6 +115,11 @@ class ConfigurationActionsInvocationTest < Test::Unit::TestCase
|
|
115
115
|
@config.sudo "ls"
|
116
116
|
end
|
117
117
|
|
118
|
+
def test_sudo_should_keep_input_stream_open
|
119
|
+
@config.expects(:execute_on_servers).with(:foo => "bar")
|
120
|
+
@config.sudo "ls", :foo => "bar"
|
121
|
+
end
|
122
|
+
|
118
123
|
def test_sudo_should_use_sudo_variable_definition
|
119
124
|
@config.expects(:run).with("/opt/local/bin/sudo -p 'sudo password: ' ls", {})
|
120
125
|
@config.options[:sudo] = "/opt/local/bin/sudo"
|
@@ -39,11 +39,35 @@ class ConfigurationCallbacksTest < Test::Unit::TestCase
|
|
39
39
|
@config.before :bar, :foo, "bing:blang", :zip => :zing
|
40
40
|
end
|
41
41
|
|
42
|
+
def test_before_should_map_before_deploy_symlink
|
43
|
+
@config.before "deploy:symlink", "bing:blang", "deploy:symlink"
|
44
|
+
assert_equal "bing:blang", @config.callbacks[:before][0].source
|
45
|
+
assert_equal "deploy:create_symlink", @config.callbacks[:before][1].source
|
46
|
+
assert_equal ["deploy:create_symlink"], @config.callbacks[:before][1].only
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_before_should_map_before_deploy_symlink_array
|
50
|
+
@config.before ["deploy:symlink", "bingo:blast"], "bing:blang"
|
51
|
+
assert_equal ["deploy:create_symlink", "bingo:blast"], @config.callbacks[:before].last.only
|
52
|
+
end
|
53
|
+
|
42
54
|
def test_after_should_delegate_to_on
|
43
55
|
@config.expects(:on).with(:after, :foo, "bing:blang", {:only => :bar, :zip => :zing})
|
44
56
|
@config.after :bar, :foo, "bing:blang", :zip => :zing
|
45
57
|
end
|
46
58
|
|
59
|
+
def test_after_should_map_before_deploy_symlink
|
60
|
+
@config.after "deploy:symlink", "bing:blang", "deploy:symlink"
|
61
|
+
assert_equal "bing:blang", @config.callbacks[:after][0].source
|
62
|
+
assert_equal "deploy:create_symlink", @config.callbacks[:after][1].source
|
63
|
+
assert_equal ["deploy:create_symlink"], @config.callbacks[:after][1].only
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_after_should_map_before_deploy_symlink_array
|
67
|
+
@config.after ["deploy:symlink", "bingo:blast"], "bing:blang"
|
68
|
+
assert_equal ["deploy:create_symlink", "bingo:blast"], @config.callbacks[:after].last.only
|
69
|
+
end
|
70
|
+
|
47
71
|
def test_on_with_single_reference_should_add_task_callback
|
48
72
|
@config.on :before, :a_test
|
49
73
|
assert_equal 1, @config.callbacks[:before].length
|
@@ -321,7 +321,7 @@ class ConfigurationNamespacesDSLTest < Test::Unit::TestCase
|
|
321
321
|
Kernel.module_eval do
|
322
322
|
def some_weird_method() 'kernel' end
|
323
323
|
end
|
324
|
-
|
324
|
+
|
325
325
|
@config.namespace(:clash2) {}
|
326
326
|
namespace = @config.namespaces[:clash2]
|
327
327
|
assert_equal 'config', namespace.some_weird_method
|
@@ -329,4 +329,4 @@ class ConfigurationNamespacesDSLTest < Test::Unit::TestCase
|
|
329
329
|
Kernel.send :remove_method, :some_weird_method
|
330
330
|
@config.class.send :remove_method, :some_weird_method
|
331
331
|
end
|
332
|
-
end
|
332
|
+
end
|
data/test/configuration_test.rb
CHANGED
@@ -16,7 +16,7 @@ class ConfigurationTest < Test::Unit::TestCase
|
|
16
16
|
process_args = Proc.new do |tree, session, opts|
|
17
17
|
tree.fallback.command == "echo 'hello world'" &&
|
18
18
|
session == [:session] &&
|
19
|
-
opts == { :logger => @config.logger }
|
19
|
+
opts == { :logger => @config.logger, :eof => true }
|
20
20
|
end
|
21
21
|
|
22
22
|
Capistrano::Command.expects(:process).with(&process_args)
|
data/test/deploy/scm/git_test.rb
CHANGED
@@ -127,7 +127,7 @@ class DeploySCMGitTest < Test::Unit::TestCase
|
|
127
127
|
|
128
128
|
# with submodules
|
129
129
|
@config[:git_enable_submodules] = true
|
130
|
-
assert_equal "cd #{dest} && #{git} fetch -q origin && #{git} fetch --tags -q origin && #{git} reset -q --hard #{rev} && #{git} submodule -q init &&
|
130
|
+
assert_equal "cd #{dest} && #{git} fetch -q origin && #{git} fetch --tags -q origin && #{git} reset -q --hard #{rev} && #{git} submodule -q init && #{git} submodule -q sync && export GIT_RECURSIVE=$([ ! \"`#{git} --version`\" \\< \"git version 1.6.5\" ] && echo --recursive) && #{git} submodule -q update --init $GIT_RECURSIVE && #{git} clean -q -d -x -f", @source.sync(rev, dest)
|
131
131
|
end
|
132
132
|
|
133
133
|
def test_sync_with_remote
|
@@ -6,10 +6,11 @@ require 'stringio'
|
|
6
6
|
class DeployStrategyCopyTest < Test::Unit::TestCase
|
7
7
|
def setup
|
8
8
|
@config = { :application => "captest",
|
9
|
-
:logger => Capistrano::Logger.new(:output => StringIO.new),
|
10
9
|
:releases_path => "/u/apps/test/releases",
|
11
10
|
:release_path => "/u/apps/test/releases/1234567890",
|
12
11
|
:real_revision => "154" }
|
12
|
+
@config.stubs(:logger).returns(stub_everything)
|
13
|
+
|
13
14
|
@source = mock("source")
|
14
15
|
@config.stubs(:source).returns(@source)
|
15
16
|
@strategy = Capistrano::Deploy::Strategy::Copy.new(@config)
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require File.expand_path("../utils", __FILE__)
|
2
|
+
require 'capistrano/logger'
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
Capistrano::Logger.class_eval do
|
6
|
+
# Allows formatters to be changed during tests
|
7
|
+
def self.formatters=(formatters)
|
8
|
+
@formatters = formatters
|
9
|
+
@sorted_formatters = nil
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class LoggerFormattingTest < Test::Unit::TestCase
|
14
|
+
def setup
|
15
|
+
@io = StringIO.new
|
16
|
+
@io.stubs(:tty?).returns(true)
|
17
|
+
@logger = Capistrano::Logger.new(:output => @io, :level => 3)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_matching_with_style_and_color
|
21
|
+
Capistrano::Logger.formatters = [{ :match => /^err ::/, :color => :red, :style => :underscore, :level => 0 }]
|
22
|
+
@logger.log(0, "err :: Error Occurred")
|
23
|
+
assert @io.string.include? "\e[4;31merr :: Error Occurred\e[0m"
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_style_without_color
|
27
|
+
Capistrano::Logger.formatters = [{ :match => /.*/, :style => :underscore, :level => 0 }]
|
28
|
+
@logger.log(0, "test message")
|
29
|
+
# Default color should be blank (0m)
|
30
|
+
assert @io.string.include? "\e[4;0mtest message\e[0m"
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_prepending_text
|
34
|
+
Capistrano::Logger.formatters = [{ :match => /^executing/, :level => 0, :prepend => '== Currently ' }]
|
35
|
+
@logger.log(0, "executing task")
|
36
|
+
assert @io.string.include? '== Currently executing task'
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_replacing_matched_text
|
40
|
+
Capistrano::Logger.formatters = [{ :match => /^executing/, :level => 0, :replace => 'running' }]
|
41
|
+
@logger.log(0, "executing task")
|
42
|
+
assert @io.string.include? 'running task'
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_prepending_timestamps
|
46
|
+
Capistrano::Logger.formatters = [{ :match => /.*/, :level => 0, :timestamp => true }]
|
47
|
+
@logger.log(0, "test message")
|
48
|
+
assert @io.string.match /\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} test message/
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_formatter_priorities
|
52
|
+
Capistrano::Logger.formatters = [
|
53
|
+
{ :match => /.*/, :color => :red, :level => 0, :priority => -10 },
|
54
|
+
{ :match => /.*/, :color => :blue, :level => 0, :priority => -20, :prepend => '###' }
|
55
|
+
]
|
56
|
+
|
57
|
+
@logger.log(0, "test message")
|
58
|
+
# Only the red formatter (color 31) should be applied.
|
59
|
+
assert @io.string.include? "\e[31mtest message"
|
60
|
+
# The blue formatter should not have prepended $$$
|
61
|
+
assert !@io.string.include?('###')
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_no_formatting_if_no_color_or_style
|
65
|
+
Capistrano::Logger.formatters = []
|
66
|
+
@logger.log(0, "test message")
|
67
|
+
assert @io.string.include? "*** test message"
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_formatter_log_levels
|
71
|
+
Capistrano::Logger.formatters = [{ :match => /.*/, :color => :blue, :level => 3 }]
|
72
|
+
@logger.log(0, "test message")
|
73
|
+
# Should not match log level
|
74
|
+
assert @io.string.include? "*** test message"
|
75
|
+
|
76
|
+
clear_logger
|
77
|
+
@logger.log(3, "test message")
|
78
|
+
# Should match log level and apply blue color
|
79
|
+
assert @io.string.include? "\e[34mtest message"
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def colorize(message, color, style = nil)
|
85
|
+
style = "#{style};" if style
|
86
|
+
"\e[#{style}#{color}m" + message + "\e[0m"
|
87
|
+
end
|
88
|
+
|
89
|
+
def clear_logger
|
90
|
+
@io = StringIO.new
|
91
|
+
@io.stubs(:tty?).returns(true)
|
92
|
+
@logger.device = @io
|
93
|
+
end
|
94
|
+
end
|