From f9a866b504ed80a8419cca5f3d521169b6938e7e Mon Sep 17 00:00:00 2001 From: Matt Brictson Date: Tue, 23 Jun 2015 21:03:44 -0700 Subject: [PATCH 1/5] Add Colors mixin --- lib/airbrussh/colors.rb | 24 ++++++++++++++++++++++++ test/airbrussh/colors_test.rb | 26 ++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 lib/airbrussh/colors.rb create mode 100644 test/airbrussh/colors_test.rb diff --git a/lib/airbrussh/colors.rb b/lib/airbrussh/colors.rb new file mode 100644 index 0000000..fe3d29b --- /dev/null +++ b/lib/airbrussh/colors.rb @@ -0,0 +1,24 @@ +module Airbrussh + # Very basic support for ANSI color, so that we don't have to rely on + # any external dependencies. + module Colors + ANSI_CODES = { + :red => 31, + :green => 32, + :yellow => 33, + :blue => 34, + :gray => 90 + }.freeze + + private + + # Define red, green, blue, etc. methods that return a copy of the + # String that is wrapped in the corresponding ANSI color escape + # sequence. + ANSI_CODES.each do |name, code| + define_method(name) do |string| + "\e[0;#{code};49m#{string}\e[0m" + end + end + end +end diff --git a/test/airbrussh/colors_test.rb b/test/airbrussh/colors_test.rb new file mode 100644 index 0000000..f1b5782 --- /dev/null +++ b/test/airbrussh/colors_test.rb @@ -0,0 +1,26 @@ +require "minitest_helper" +require "airbrussh/colors" + +class Airbrussh::ColorsTest < Minitest::Test + include Airbrussh::Colors + + def test_red + assert_equal("\e[0;31;49mhello\e[0m", red("hello")) + end + + def test_green + assert_equal("\e[0;32;49mhello\e[0m", green("hello")) + end + + def test_yellow + assert_equal("\e[0;33;49mhello\e[0m", yellow("hello")) + end + + def test_blue + assert_equal("\e[0;34;49mhello\e[0m", blue("hello")) + end + + def test_gray + assert_equal("\e[0;90;49mhello\e[0m", gray("hello")) + end +end From 606f4c660e92b2e8b0e257f92a5097e00a5da938 Mon Sep 17 00:00:00 2001 From: Matt Brictson Date: Tue, 23 Jun 2015 21:08:03 -0700 Subject: [PATCH 2/5] Use Airbrussh::Colors instead of colorize --- lib/airbrussh/capistrano.rb | 14 +++++++------- lib/airbrussh/colors.rb | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/airbrussh/capistrano.rb b/lib/airbrussh/capistrano.rb index 800505b..e7f98cd 100644 --- a/lib/airbrussh/capistrano.rb +++ b/lib/airbrussh/capistrano.rb @@ -1,5 +1,5 @@ require "airbrussh" -require "colorize" +require "airbrussh/colors" require "sshkit/formatter/airbrussh" # airbrush/capistrano uses a different default configuration @@ -10,12 +10,12 @@ # Sanity check! unless defined?(Capistrano) && defined?(:namespace) - $stderr.puts\ - "WARNING: airbrussh/capistrano must be loaded by Capistrano in order "\ - "to work.\n"\ - "Require this gem within your application's Capfile, as described here:\n"\ - "https://github.com/mattbrictson/airbrussh#installation"\ - .colorize(:red) + $stderr.puts( + Airbrussh::Colors.red( + "WARNING: airbrussh/capistrano must be loaded by Capistrano in order "\ + "to work.\nRequire this gem within your application's Capfile, as "\ + "described here:\nhttps://github.com/mattbrictson/airbrussh#installation" + )) end # Hook into Capistrano's init process to set the formatter diff --git a/lib/airbrussh/colors.rb b/lib/airbrussh/colors.rb index fe3d29b..4ec43d2 100644 --- a/lib/airbrussh/colors.rb +++ b/lib/airbrussh/colors.rb @@ -10,7 +10,7 @@ module Colors :gray => 90 }.freeze - private + module_function # Define red, green, blue, etc. methods that return a copy of the # String that is wrapped in the corresponding ANSI color escape From ba2f4e109ec929fab302c47be0e9271a57f6b7e2 Mon Sep 17 00:00:00 2001 From: Matt Brictson Date: Tue, 23 Jun 2015 21:24:45 -0700 Subject: [PATCH 3/5] Move most formatting into CommandFormatter class --- lib/airbrussh/command_formatter.rb | 76 ++++++++++++++++++++++++ lib/airbrussh/formatter.rb | 64 ++++++-------------- test/airbrussh/command_formatter_test.rb | 42 +++++++++++++ 3 files changed, 136 insertions(+), 46 deletions(-) create mode 100644 lib/airbrussh/command_formatter.rb create mode 100644 test/airbrussh/command_formatter_test.rb diff --git a/lib/airbrussh/command_formatter.rb b/lib/airbrussh/command_formatter.rb new file mode 100644 index 0000000..80f138b --- /dev/null +++ b/lib/airbrussh/command_formatter.rb @@ -0,0 +1,76 @@ +require "airbrussh/colors" +# rubocop:disable Style/AsciiComments + +module Airbrussh + # Decorates an SSHKit::Command to add string output helpers. + class CommandFormatter < SimpleDelegator + include Airbrussh::Colors + + # Prefixes the line with the command number and removes the newline. + # + # format_output("hello\n") # => "01 hello" + # + def format_output(line) + "#{number} #{line.chomp}" + end + + # Returns the abbreviated command (in yellow) with the number prefix. + # + # start_message # => "01 echo hello" + # + def start_message + "#{number} #{yellow(abbreviated)}" + end + + # Returns a green (success) or red (failure) message depending on the + # exit status. + # + # exit_message # => "✔ 01 user@host 0.084s" + # exit_message # => "✘ 01 user@host 0.084s" + # + # If `log_file` is specified, it is appended to the message + # in the failure case. + # + # exit_message("out.log") + # # => "✘ 01 user@host (see out.log for details) 0.084s" + # + def exit_message(log_file=nil) + if failure? + message = red(failure_message(log_file)) + else + message = green(success_message) + end + message << " #{gray(runtime)}" + end + + private + + def user_at_host + user_str = user { host.user } + host_str = host.to_s + [user_str, host_str].join("@") + end + + def runtime + format("%5.3fs", super) + end + + def abbreviated + to_s.sub(%r{^/usr/bin/env }, "") + end + + def number + format("%02d", position + 1) + end + + def success_message + "✔ #{number} #{user_at_host}" + end + + def failure_message(log_file) + message = "✘ #{number} #{user_at_host}" + message << " (see #{log_file} for details)" if log_file + message + end + end +end diff --git a/lib/airbrussh/formatter.rb b/lib/airbrussh/formatter.rb index b1a6ef6..1ce4d74 100644 --- a/lib/airbrussh/formatter.rb +++ b/lib/airbrussh/formatter.rb @@ -1,15 +1,17 @@ # encoding: UTF-8 +require "airbrussh/colors" +require "airbrussh/command_formatter" require "airbrussh/command_output" require "airbrussh/console" require "airbrussh/rake/command" require "airbrussh/rake/context" -require "colorize" -require "ostruct" require "sshkit" module Airbrussh class Formatter < SSHKit::Formatter::Abstract + include Airbrussh::Colors extend Forwardable + attr_reader :config, :context def_delegator :context, :current_task_name @@ -34,10 +36,6 @@ def create_log_file_formatter ) end - def print_line(string) - @console.print_line(string) - end - def write_banner return unless config.banner if config.banner == :auto @@ -115,17 +113,13 @@ def on_deploy_failure def write_log_message(log_message) return if debug?(log_message) print_task_if_changed - @console.print_line(light_black(" " + log_message.to_s)) + print_indented_line(gray(log_message.to_s)) end def write_command_start(command) return if debug?(command) print_task_if_changed - - if command.first_execution? - shell_string = shell_string(command) - print_line " #{command_number(command)} #{yellow(shell_string)}" - end + print_indented_line(command.start_message) if command.first_execution? end # Prints the data from the stdout and stderr streams of the given command, @@ -143,7 +137,7 @@ def write_command_output(command) def write_command_output_line(command, stream, line) hide_command_output = !config.public_send("command_output_#{stream}?") return if hide_command_output || debug?(command) - print_line " #{command_number(command)} #{line.chomp}" + print_indented_line(command.format_output(line)) end def print_task_if_changed @@ -156,32 +150,7 @@ def print_task_if_changed def write_command_exit(command) return if debug?(command) - print_line " #{format_exit_status(command)} #{runtime(command)}" - end - - def format_exit_status(command) - user = command.user { command.host.user } - host = command.host.to_s - user_at_host = [user, host].join("@") - number = command_number(command) - - if command.failure? - red("✘ #{number} #{user_at_host} (see #{@log_file} for details)") - else - green("✔ #{number} #{user_at_host}") - end - end - - def runtime(command) - light_black(format("%5.3fs", command.runtime)) - end - - def shell_string(command) - command.to_s.sub(%r{^/usr/bin/env }, "") - end - - def command_number(command) - format("%02d", command.position + 1) + print_indented_line(command.exit_message(@log_file), -2) end def clock @@ -194,18 +163,21 @@ def clock format("%02d:%02d", minutes, seconds) end - %w(light_black red blue green yellow).each do |color| - define_method(color) do |string| - string.to_s.colorize(color.to_sym) - end - end - def debug?(obj) obj.verbosity <= SSHKit::Logger::DEBUG end def decorate(command) - @context.decorate_command(command) + Airbrussh::CommandFormatter.new(@context.decorate_command(command)) + end + + def print_line(string) + @console.print_line(string) + end + + def print_indented_line(string, offset=0) + indent = " " * (6 + offset) + print_line([indent, string].join) end end end diff --git a/test/airbrussh/command_formatter_test.rb b/test/airbrussh/command_formatter_test.rb new file mode 100644 index 0000000..d5b04d0 --- /dev/null +++ b/test/airbrussh/command_formatter_test.rb @@ -0,0 +1,42 @@ +require "minitest_helper" +require "ostruct" +require "airbrussh/command_formatter" + +class Airbrussh::CommandFormatterTest < Minitest::Test + def setup + sshkit_command = OpenStruct.new( + :host => "12.34.56.78", + :user => "deployer", + :runtime => 1.23456, + :position => 0, + :failure? => false + ) + def sshkit_command.to_s + "/usr/bin/env echo hello" + end + @command = Airbrussh::CommandFormatter.new(sshkit_command) + end + + def test_format_output + assert_equal("01 hello", @command.format_output("hello\n")) + end + + def test_start_message + assert_equal("01 \e[0;33;49mecho hello\e[0m", @command.start_message) + end + + def test_exit_message_success + assert_equal( + "\e[0;32;49m✔ 01 deployer@12.34.56.78\e[0m \e[0;90;49m1.235s\e[0m", + @command.exit_message) + end + + def test_exit_message_failure + @command.stub(:failure?, true) do + assert_equal( + "\e[0;31;49m✘ 01 deployer@12.34.56.78 (see out.log for details)\e[0m "\ + "\e[0;90;49m1.235s\e[0m", + @command.exit_message("out.log")) + end + end +end From 3455fad7a1729c269563a1e48ad2c4e575d7c77c Mon Sep 17 00:00:00 2001 From: Matt Brictson Date: Tue, 23 Jun 2015 21:36:10 -0700 Subject: [PATCH 4/5] Ruby 1.9 compatibility --- lib/airbrussh/command_formatter.rb | 1 + lib/airbrussh/formatter.rb | 1 - test/airbrussh/command_formatter_test.rb | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/airbrussh/command_formatter.rb b/lib/airbrussh/command_formatter.rb index 80f138b..791b0f1 100644 --- a/lib/airbrussh/command_formatter.rb +++ b/lib/airbrussh/command_formatter.rb @@ -1,3 +1,4 @@ +# encoding: UTF-8 require "airbrussh/colors" # rubocop:disable Style/AsciiComments diff --git a/lib/airbrussh/formatter.rb b/lib/airbrussh/formatter.rb index 1ce4d74..2ee2dbd 100644 --- a/lib/airbrussh/formatter.rb +++ b/lib/airbrussh/formatter.rb @@ -1,4 +1,3 @@ -# encoding: UTF-8 require "airbrussh/colors" require "airbrussh/command_formatter" require "airbrussh/command_output" diff --git a/test/airbrussh/command_formatter_test.rb b/test/airbrussh/command_formatter_test.rb index d5b04d0..a23dd5f 100644 --- a/test/airbrussh/command_formatter_test.rb +++ b/test/airbrussh/command_formatter_test.rb @@ -1,3 +1,4 @@ +# encoding: UTF-8 require "minitest_helper" require "ostruct" require "airbrussh/command_formatter" From 1a08c6b8215f7afb7f5bc0d07025255f9fd31740 Mon Sep 17 00:00:00 2001 From: Matt Brictson Date: Wed, 24 Jun 2015 09:36:13 -0700 Subject: [PATCH 5/5] Add recent changes to the CHANGELOG --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bfccf04..9551889 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,9 +8,11 @@ Airbrussh is in a pre-1.0 state. This means that its APIs and behavior are subje * Your contribution here! * Added Rubocop enforcement to Travis -* Airbrussh now has decent test coverage, and is tested by Travis against a matrix of Ruby and SSHKit versions ([@robd](https://github.com/robd)) +* Added Code Climate and Coveralls checks (see badges in the README) +* Airbrussh now has good test coverage, and is tested by Travis against a matrix of Ruby and SSHKit versions ([@robd](https://github.com/robd)) * Changes to support the new SSHKit formatter API, as introduced in [SSHKit #257](https://github.com/capistrano/sshkit/pull/257) ([@robd](https://github.com/robd)) * `Airbrussh.reset` has been removed +* Airbrussh now has its own ANSI color code; it no longer relies on a third-party gem (i.e. `colorize`) ## [0.4.1][] (2015-05-06)