airbrussh 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 59f8a8dfe9592ad3823bc7888584fe7be83252cb
4
- data.tar.gz: f87ce479163f998b0b8c05baa26d8979656bad94
3
+ metadata.gz: e0a386319a132a613b48624a83110acc398c36b4
4
+ data.tar.gz: ae0e818ca6931928500bf516bed0a8f542c6a53f
5
5
  SHA512:
6
- metadata.gz: d02fbf942e4fc78aab225897b09e34827ee47759d912ef773b964c05d6a2f536e83b3834561bfb990dcd27a5492557d5660b9a9c7a31845cf26581cd12f356b8
7
- data.tar.gz: f265dda3cc676f575684b56561f760309175a879b5dc6f5439da6a29baaf28ad6dcf2a5e9f008086f537efb9161c25b1cb083e691451f452d61d19a9d02ca15e
6
+ metadata.gz: e372e78dd7f096b2602c998ed5178409978f8f0e6be17a5034c202c8e05a666ab9ccf61ab15a1bed01d9b2f141035c25fbe67b7e605ce5c251d9fe67b14c858c
7
+ data.tar.gz: 771b4bf163c6c2b59bacc25bfc6f4d7fe9931121ba3280587e403b42ee5633518c6c4d0bcd1b3c8dc9d01a6432ade255d48d1f92d3a9e614d11c72f63a971af6
data/.rubocop.yml ADDED
@@ -0,0 +1,35 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
3
+ AllCops:
4
+ Exclude:
5
+ - "*.gemspec"
6
+
7
+ Metrics/AbcSize:
8
+ Exclude:
9
+ - "test/**/*"
10
+
11
+ Metrics/MethodLength:
12
+ Exclude:
13
+ - "test/**/*"
14
+
15
+ Metrics/ClassLength:
16
+ Exclude:
17
+ - "test/**/*"
18
+
19
+ Style/ClassAndModuleChildren:
20
+ Enabled: false
21
+
22
+ Style/Documentation:
23
+ Enabled: false
24
+
25
+ Style/DoubleNegation:
26
+ Enabled: false
27
+
28
+ Style/HashSyntax:
29
+ EnforcedStyle: hash_rockets
30
+
31
+ Style/SpaceAroundEqualsInParameterDefault:
32
+ EnforcedStyle: no_space
33
+
34
+ Style/StringLiterals:
35
+ EnforcedStyle: double_quotes
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,21 @@
1
+ # This configuration was generated by `rubocop --auto-gen-config`
2
+ # on 2015-05-10 16:52:41 -0700 using RuboCop version 0.31.0.
3
+ # The point is for the user to remove these configuration records
4
+ # one by one as the offenses are removed from the code base.
5
+ # Note that changes in the inspected code, or installation of new
6
+ # versions of RuboCop, may require this file to be generated again.
7
+
8
+ # Offense count: 1
9
+ # Configuration parameters: CountComments.
10
+ Metrics/ClassLength:
11
+ Max: 168
12
+
13
+ # Offense count: 5
14
+ # Configuration parameters: CountComments.
15
+ Metrics/MethodLength:
16
+ Max: 15
17
+
18
+ # Offense count: 1
19
+ # Configuration parameters: MinBodyLength.
20
+ Style/GuardClause:
21
+ Enabled: false
data/.travis.yml CHANGED
@@ -1,4 +1,13 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.2.0
3
+ - 1.9
4
+ - 2.0
5
+ - 2.1
6
+ - 2.2
7
+ env:
8
+ - sshkit="master"
9
+ # This is the old master before https://github.com/capistrano/sshkit/pull/257 was merged
10
+ - sshkit="ea211bcbbb71dab0152a18c2774922b7017e4edc"
11
+ - sshkit="= 1.7.1"
12
+ - sshkit="= 1.6.1"
4
13
  before_install: gem install bundler --conservative --version '~> 1.8'
data/CHANGELOG.md CHANGED
@@ -1,29 +1,57 @@
1
- ## Next release
1
+ # Airbrussh Change Log
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ Airbrussh is in a pre-1.0 state. This means that its APIs and behavior are subject to breaking changes without deprecation notices. Until 1.0, version numbers will follow a [Semver][]-ish `0.y.z` format, where `y` is incremented when new features or breaking changes are introduced, and `z` is incremented for lesser changes or bug fixes.
6
+
7
+ ## [Unreleased]
2
8
 
3
9
  * Your contribution here!
4
10
 
5
- ## 0.4.1 (2015-05-06)
11
+ ## [0.5.0][] (2015-06-24)
12
+
13
+ There are no changes to the actual behavior and feature set of Airbrussh in this release.
14
+
15
+ There are, however, many behind-the-scenes changes and improvements to overall code quality. This release also adds support for upcoming versions of SSHKit.
16
+
17
+ * Added Rubocop enforcement to Travis
18
+ * Added Code Climate and Coveralls checks (see badges in the README)
19
+ * Airbrussh now has good test coverage, and is tested by Travis against a matrix of Ruby and SSHKit versions ([@robd](https://github.com/robd))
20
+ * 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))
21
+ * `Airbrussh.reset` has been removed
22
+ * Airbrussh now has its own ANSI color code; it no longer relies on a third-party gem (i.e. `colorize`)
23
+
24
+ ## [0.4.1][] (2015-05-06)
6
25
 
7
26
  * Fix `Marshal.dump` warnings by removing `deep_copy` workaround that it is no longer needed for the latest SSHKit ([#10](https://github.com/mattbrictson/airbrussh/issues/10)).
8
27
 
9
- ## 0.4.0 (2015-05-03)
28
+ ## [0.4.0][] (2015-05-03)
10
29
 
11
30
  * Changes to ensure compatibility with the upcoming version of SSHKit ([ec3122b](https://github.com/mattbrictson/airbrussh/commit/ec3122b101de53f2304723da842d5c8b6f70f4f3)).
12
31
  * Explicitly specify UTF-8 encoding for source files, for Ruby 1.9.3 compatibility ([#9](https://github.com/mattbrictson/airbrussh/issues/9)).
13
32
 
14
- ## 0.3.0 (2015-03-28)
33
+ ## [0.3.0][] (2015-03-28)
15
34
 
16
35
  * New `config.banner` option allows startup message to be disabled or changed (suggestion from [@justindowning](https://github.com/justindowning))
17
36
  * New `config.command_output` option gives full control of whether airbrussh shows or hides the stderr and stdout data received from remote commands; see the usage section of the README for further explanation (suggestion from [@carlesso](https://github.com/carlesso))
18
37
 
19
- ## 0.2.1 (2015-03-02)
38
+ ## [0.2.1][] (2015-03-02)
20
39
 
21
40
  * Un-pin SSHKit dependency now that SSHKit 1.7.1 has been released.
22
41
 
23
- ## 0.2.0 (2015-03-02)
42
+ ## [0.2.0][] (2015-03-02)
24
43
 
25
44
  * Pin SSHKit dependency at `~> 1.6.1` to avoid a [bug in 1.7.0](https://github.com/capistrano/sshkit/issues/226) that causes command exit statuses to be omitted from the log.
26
45
 
27
46
  ## 0.0.1 (2015-02-19)
28
47
 
29
48
  * Initial release
49
+
50
+ [Semver]: http://semver.org
51
+ [Unreleased]: https://github.com/mattbrictson/airbrussh/compare/v0.5.0...HEAD
52
+ [0.5.0]: https://github.com/mattbrictson/airbrussh/compare/v0.4.1...v0.5.0
53
+ [0.4.1]: https://github.com/mattbrictson/airbrussh/compare/v0.4.0...v0.4.1
54
+ [0.4.0]: https://github.com/mattbrictson/airbrussh/compare/v0.3.0...v0.4.0
55
+ [0.3.0]: https://github.com/mattbrictson/airbrussh/compare/v0.2.1...v0.3.0
56
+ [0.2.1]: https://github.com/mattbrictson/airbrussh/compare/v0.2.0...v0.2.1
57
+ [0.2.0]: https://github.com/mattbrictson/airbrussh/compare/v0.0.1...v0.2.0
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,27 @@
1
+ # Contributing to airbrussh
2
+
3
+ Have a feature idea, bug fix, or refactoring suggestion? Contributions are welcome!
4
+
5
+ ## Pull requests
6
+
7
+ 1. Check [Issues][] to see if your contribution has already been discussed and/or implemented.
8
+ 2. If not, open an issue to discuss your contribution. I won't accept all changes and do not want to waste your time.
9
+ 3. Once you have the :thumbsup:, fork the repo, make your changes, and open a PR.
10
+ 4. Don't forget to add your contribution and credit yourself in `CHANGELOG.md`!
11
+
12
+ ## Coding guidelines
13
+
14
+ * This project has a coding style enforced by [RuboCop][]. Use hash rockets and double-quoted strings, and otherwise try to follow the [Ruby style guide][style].
15
+ * Writing tests is strongly encouraged! This project uses Minitest.
16
+
17
+ ## Getting started
18
+
19
+ After checking out the repo, run `bin/setup` to install dependencies.
20
+
21
+ * `rake` executes airbrussh's tests and RuboCop checks
22
+ * `bin/test_all.rb` executes the tests against all versions of SSHKit that airbrussh supports
23
+ * `guard` monitors the filesystem and automatically runs tests as you work
24
+
25
+ [Issues]: https://github.com/mattbrictson/airbrussh/issues
26
+ [RuboCop]: https://github.com/bbatsov/rubocop
27
+ [style]: https://github.com/bbatsov/ruby-style-guide
data/Gemfile CHANGED
@@ -2,3 +2,18 @@ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in airbrussh.gemspec
4
4
  gemspec
5
+
6
+ if (sshkit_version = ENV["sshkit"])
7
+ requirement = begin
8
+ Gem::Dependency.new("sshkit", sshkit_version).requirement
9
+ rescue ArgumentError
10
+ user, branch =
11
+ if sshkit_version.include?("#")
12
+ sshkit_version.split("#")
13
+ else
14
+ ["capistrano", sshkit_version]
15
+ end
16
+ { :github => "#{user}/sshkit", :branch => branch }
17
+ end
18
+ gem "sshkit", requirement
19
+ end
data/Guardfile ADDED
@@ -0,0 +1,6 @@
1
+ guard :minitest do
2
+ # with Minitest::Unit
3
+ watch(%r{^test/(.*)\/?(.*)_test\.rb$})
4
+ watch(%r{^lib/(.*/)?([^/]+)\.rb$}) { |m| "test/#{m[1]}#{m[2]}_test.rb" }
5
+ watch(%r{^test/minitest_helper\.rb$}) { "test" }
6
+ end
data/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/airbrussh.svg)](http://badge.fury.io/rb/airbrussh)
4
4
  [![Build Status](https://travis-ci.org/mattbrictson/airbrussh.svg?branch=master)](https://travis-ci.org/mattbrictson/airbrussh)
5
+ [![Code Climate](https://codeclimate.com/github/mattbrictson/airbrussh/badges/gpa.svg)](https://codeclimate.com/github/mattbrictson/airbrussh)
6
+ [![Coverage Status](https://coveralls.io/repos/mattbrictson/airbrussh/badge.svg?branch=master)](https://coveralls.io/r/mattbrictson/airbrussh?branch=master)
5
7
 
6
8
 
7
9
  **Airbrussh is a replacement log formatter for SSHKit that makes your Capistrano output much easier on the eyes.** Just add it to your Capfile and enjoy concise, useful log output that is easy to read.
@@ -16,7 +18,7 @@ For more details on how exactly Airbrussh changes Capistrano's output and the re
16
18
 
17
19
  **To use Airbrussh with Capistrano, you will need Capistrano 3.** Capistrano 2.x is not supported.
18
20
 
19
- Airbrussh has been tested with MRI 2.2, Capistrano 3.4.0, and SSHKit 1.7.1. Other recent version combinations will probably work; [open an issue on GitHub](https://github.com/mattbrictson/airbrussh/issues/new) if you run into trouble.
21
+ Airbrussh has been tested with MRI 1.9+, Capistrano 3.4.0, and SSHKit 1.6.1+. Refer to the [Travis configuration](.travis.yml) for our latest test matrix. If you run into trouble using airbrussh in your environment, [open an issue on GitHub](https://github.com/mattbrictson/airbrussh/issues/new).
20
22
 
21
23
  Airbrussh's only dependency is SSHKit >= 1.6.1.
22
24
 
@@ -159,12 +161,10 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
159
161
 
160
162
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
161
163
 
164
+ Airbrussh is designed to work against multiple versions of SSHKit and Ruby. In order to test this, we use the environment variable `sshkit` in order to run the tests against a specific version. The combinations of sshkit and ruby we support are specified in [.travis.yml](.travis.yml). To test all the versions locally, there is a `test_all.rb` bin file. This installs the gems and runs the tests for each sshkit version in [.travis.yml](.travis.yml). *Note: this will update your `Gemfile.lock` as each SSHKit gem version is installed. The gem version is restored to the default when the script exits.*
165
+
162
166
  ## Contributing
163
167
 
164
- 1. Fork it ( https://github.com/mattbrictson/airbrussh/fork )
165
- 2. Create your feature branch (`git checkout -b my-new-feature`)
166
- 3. Commit your changes (`git commit -am 'Add some feature'`)
167
- 4. Push to the branch (`git push origin my-new-feature`)
168
- 5. Create a new Pull Request
168
+ Contributions are welcome! Read [CONTRIBUTING.md](CONTRIBUTING.md) to get started.
169
169
 
170
170
  [capistrano-fiftyfive]: https://github.com/mattbrictson/capistrano-fiftyfive
data/Rakefile CHANGED
@@ -1,8 +1,18 @@
1
1
  require "bundler/gem_tasks"
2
- require "rake/testtask"
3
2
 
3
+ require "rake/testtask"
4
4
  Rake::TestTask.new(:test) do |t|
5
5
  t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ end
9
+
10
+ require "rubocop/rake_task"
11
+ RuboCop::RakeTask.new
12
+
13
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.1.0")
14
+ require "chandler/tasks"
15
+ task "release:rubygem_push" => "chandler:push"
6
16
  end
7
17
 
8
- task :default => :test
18
+ task :default => [:test, :rubocop]
data/airbrussh.gemspec CHANGED
@@ -24,7 +24,17 @@ Gem::Specification.new do |spec|
24
24
  spec.add_dependency "sshkit", [">= 1.6.1", "!= 1.7.0"]
25
25
 
26
26
  spec.add_development_dependency "bundler", "~> 1.8"
27
+ spec.add_development_dependency "coveralls"
28
+ spec.add_development_dependency "guard", ">= 2.2.2"
29
+ spec.add_development_dependency "guard-minitest"
27
30
  spec.add_development_dependency "rake", "~> 10.0"
31
+ spec.add_development_dependency "rb-fsevent"
28
32
  spec.add_development_dependency "minitest"
29
33
  spec.add_development_dependency "minitest-reporters"
34
+ spec.add_development_dependency "rubocop", ">= 0.31.0"
35
+ spec.add_development_dependency "terminal-notifier-guard"
36
+
37
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.1.0")
38
+ spec.add_development_dependency "chandler"
39
+ end
30
40
  end
data/bin/test_all.rb ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ require "yaml"
3
+ require "English"
4
+
5
+ YAML.load_file(".travis.yml")["env"].each do |sshkit_version|
6
+ puts "\e[0;34;49m== Running tests against #{sshkit_version} ==\e[0m"
7
+ output = `#{sshkit_version} bundle update`
8
+ fail "bundle update failed: #{output}" unless $CHILD_STATUS.success?
9
+ system("#{sshkit_version} bundle exec rake test")
10
+ end
11
+
12
+ at_exit do
13
+ puts "\e[0;34;49m== Resetting sshkit ==\e[0m"
14
+ system("bundle update")
15
+ end
data/lib/airbrussh.rb CHANGED
@@ -7,10 +7,6 @@ module Airbrussh
7
7
  @configuration ||= Configuration.new
8
8
  end
9
9
 
10
- def self.reset
11
- @configuration = Configuration.new
12
- end
13
-
14
10
  def self.configure
15
11
  yield(configuration)
16
12
  end
@@ -1,5 +1,5 @@
1
1
  require "airbrussh"
2
- require "colorize"
2
+ require "airbrussh/colors"
3
3
  require "sshkit/formatter/airbrussh"
4
4
 
5
5
  # airbrush/capistrano uses a different default configuration
@@ -10,12 +10,12 @@ end
10
10
 
11
11
  # Sanity check!
12
12
  unless defined?(Capistrano) && defined?(:namespace)
13
- $stderr.puts\
14
- "WARNING: airbrussh/capistrano must be loaded by Capistrano in order "\
15
- "to work.\n"\
16
- "Require this gem within your application's Capfile, as described here:\n"\
17
- "https://github.com/mattbrictson/airbrussh#installation"\
18
- .colorize(:red)
13
+ $stderr.puts(
14
+ Airbrussh::Colors.red(
15
+ "WARNING: airbrussh/capistrano must be loaded by Capistrano in order "\
16
+ "to work.\nRequire this gem within your application's Capfile, as "\
17
+ "described here:\nhttps://github.com/mattbrictson/airbrussh#installation"
18
+ ))
19
19
  end
20
20
 
21
21
  # Hook into Capistrano's init process to set the formatter
@@ -0,0 +1,24 @@
1
+ module Airbrussh
2
+ # Very basic support for ANSI color, so that we don't have to rely on
3
+ # any external dependencies.
4
+ module Colors
5
+ ANSI_CODES = {
6
+ :red => 31,
7
+ :green => 32,
8
+ :yellow => 33,
9
+ :blue => 34,
10
+ :gray => 90
11
+ }.freeze
12
+
13
+ module_function
14
+
15
+ # Define red, green, blue, etc. methods that return a copy of the
16
+ # String that is wrapped in the corresponding ANSI color escape
17
+ # sequence.
18
+ ANSI_CODES.each do |name, code|
19
+ define_method(name) do |string|
20
+ "\e[0;#{code};49m#{string}\e[0m"
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,77 @@
1
+ # encoding: UTF-8
2
+ require "airbrussh/colors"
3
+ # rubocop:disable Style/AsciiComments
4
+
5
+ module Airbrussh
6
+ # Decorates an SSHKit::Command to add string output helpers.
7
+ class CommandFormatter < SimpleDelegator
8
+ include Airbrussh::Colors
9
+
10
+ # Prefixes the line with the command number and removes the newline.
11
+ #
12
+ # format_output("hello\n") # => "01 hello"
13
+ #
14
+ def format_output(line)
15
+ "#{number} #{line.chomp}"
16
+ end
17
+
18
+ # Returns the abbreviated command (in yellow) with the number prefix.
19
+ #
20
+ # start_message # => "01 echo hello"
21
+ #
22
+ def start_message
23
+ "#{number} #{yellow(abbreviated)}"
24
+ end
25
+
26
+ # Returns a green (success) or red (failure) message depending on the
27
+ # exit status.
28
+ #
29
+ # exit_message # => "✔ 01 user@host 0.084s"
30
+ # exit_message # => "✘ 01 user@host 0.084s"
31
+ #
32
+ # If `log_file` is specified, it is appended to the message
33
+ # in the failure case.
34
+ #
35
+ # exit_message("out.log")
36
+ # # => "✘ 01 user@host (see out.log for details) 0.084s"
37
+ #
38
+ def exit_message(log_file=nil)
39
+ if failure?
40
+ message = red(failure_message(log_file))
41
+ else
42
+ message = green(success_message)
43
+ end
44
+ message << " #{gray(runtime)}"
45
+ end
46
+
47
+ private
48
+
49
+ def user_at_host
50
+ user_str = user { host.user }
51
+ host_str = host.to_s
52
+ [user_str, host_str].join("@")
53
+ end
54
+
55
+ def runtime
56
+ format("%5.3fs", super)
57
+ end
58
+
59
+ def abbreviated
60
+ to_s.sub(%r{^/usr/bin/env }, "")
61
+ end
62
+
63
+ def number
64
+ format("%02d", position + 1)
65
+ end
66
+
67
+ def success_message
68
+ "✔ #{number} #{user_at_host}"
69
+ end
70
+
71
+ def failure_message(log_file)
72
+ message = "✘ #{number} #{user_at_host}"
73
+ message << " (see #{log_file} for details)" if log_file
74
+ message
75
+ end
76
+ end
77
+ end
@@ -9,8 +9,11 @@ module Airbrussh
9
9
  # an ANSI color-capable console. When a console is not present (e.g. when
10
10
  # running on a CI server) the output will gracefully degrade.
11
11
  class Console
12
- def initialize(output)
12
+ attr_reader :output, :config
13
+
14
+ def initialize(output, config=Airbrussh.configuration)
13
15
  @output = output
16
+ @config = config
14
17
  end
15
18
 
16
19
  # Writes to the IO after first truncating the output to fit the console
@@ -20,21 +23,17 @@ module Airbrussh
20
23
  def print_line(obj="")
21
24
  string = obj.to_s
22
25
 
23
- if console_width
24
- string = truncate_to_console_width(string)
25
- end
26
- unless color_enabled?
27
- string = strip_ascii_color(string)
28
- end
26
+ string = truncate_to_console_width(string) if console_width
27
+ string = strip_ascii_color(string) unless color_enabled?
29
28
 
30
29
  write(string + "\n")
31
- @output.flush
30
+ output.flush
32
31
  end
33
32
 
34
33
  # Writes directly through to the IO with no truncation or color logic.
35
34
  # No newline is added.
36
35
  def write(string)
37
- @output.write(string || "")
36
+ output.write(string || "")
38
37
  end
39
38
  alias_method :<<, :write
40
39
 
@@ -43,9 +42,7 @@ module Airbrussh
43
42
  width = console_width
44
43
 
45
44
  if strip_ascii_color(string).length > width
46
- while strip_ascii_color(string).length >= width
47
- string.chop!
48
- end
45
+ string.chop! while strip_ascii_color(string).length >= width
49
46
  string << "…\e[0m"
50
47
  else
51
48
  string
@@ -57,7 +54,7 @@ module Airbrussh
57
54
  end
58
55
 
59
56
  def console_width
60
- case (truncate = Airbrussh.configuration.truncate)
57
+ case (truncate = config.truncate)
61
58
  when :auto
62
59
  IO.console.winsize.last if @output.tty?
63
60
  when Fixnum
@@ -68,7 +65,7 @@ module Airbrussh
68
65
  private
69
66
 
70
67
  def color_enabled?
71
- case Airbrussh.configuration.color
68
+ case config.color
72
69
  when true
73
70
  true
74
71
  when :auto
@@ -1,44 +1,29 @@
1
- # encoding: UTF-8
1
+ require "airbrussh/colors"
2
+ require "airbrussh/command_formatter"
2
3
  require "airbrussh/command_output"
3
4
  require "airbrussh/console"
4
- require "colorize"
5
- require "ostruct"
5
+ require "airbrussh/rake/command"
6
+ require "airbrussh/rake/context"
6
7
  require "sshkit"
7
8
 
8
9
  module Airbrussh
9
10
  class Formatter < SSHKit::Formatter::Abstract
10
- class << self
11
- attr_accessor :current_rake_task
12
-
13
- def monkey_patch_rake_task!
14
- return unless Airbrussh.configuration.monkey_patch_rake
15
- return if @rake_patched
16
-
17
- eval(<<-EVAL)
18
- class ::Rake::Task
19
- alias_method :_original_execute_airbrussh, :execute
20
- def execute(args=nil)
21
- #{name}.current_rake_task = name
22
- _original_execute_airbrussh(args)
23
- end
24
- end
25
- EVAL
26
-
27
- @rake_patched = true
28
- end
29
- end
11
+ include Airbrussh::Colors
12
+ extend Forwardable
30
13
 
31
- def initialize(io)
32
- super
14
+ attr_reader :config, :context
15
+ def_delegator :context, :current_task_name
33
16
 
34
- self.class.monkey_patch_rake_task!
17
+ def initialize(io, config=Airbrussh.configuration)
18
+ super(io)
35
19
 
36
- @tasks = {}
20
+ @config = config
21
+ @context = Airbrussh::Rake::Context.new(config)
37
22
 
38
23
  @log_file = config.log_file
39
24
  @log_file_formatter = create_log_file_formatter
40
25
 
41
- @console = Airbrussh::Console.new(original_output)
26
+ @console = Airbrussh::Console.new(original_output, config)
42
27
  write_log_file_delimiter
43
28
  write_banner
44
29
  end
@@ -46,14 +31,10 @@ module Airbrussh
46
31
  def create_log_file_formatter
47
32
  return SSHKit::Formatter::BlackHole.new(nil) if @log_file.nil?
48
33
  SSHKit::Formatter::Pretty.new(
49
- ::Logger.new(@log_file, 1, 20971520)
34
+ ::Logger.new(@log_file, 1, 20_971_520)
50
35
  )
51
36
  end
52
37
 
53
- def print_line(string)
54
- @console.print_line(string)
55
- end
56
-
57
38
  def write_banner
58
39
  return unless config.banner
59
40
  if config.banner == :auto
@@ -74,136 +55,101 @@ module Airbrussh
74
55
  @log_file_formatter << SSHKit::LogMessage.new(
75
56
  SSHKit::Logger::INFO,
76
57
  line
77
- )
58
+ )
78
59
  end
79
60
  end
80
61
 
62
+ def log_command_start(command)
63
+ command = decorate(command)
64
+ @log_file_formatter.log_command_start(command)
65
+ write_command_start(command)
66
+ end
67
+
68
+ def log_command_data(command, stream_type, line)
69
+ command = decorate(command)
70
+ @log_file_formatter.log_command_data(command, stream_type, line)
71
+ write_command_output_line(command, stream_type, line)
72
+ end
73
+
74
+ def log_command_exit(command)
75
+ command = decorate(command)
76
+ @log_file_formatter.log_command_exit(command)
77
+ write_command_exit(command)
78
+ end
79
+
81
80
  def write(obj)
82
81
  # SSHKit's :pretty formatter mutates the stdout and stderr data in the
83
82
  # command obj. So we need to dup it to ensure our copy is unscathed.
84
83
  @log_file_formatter << obj.dup
85
84
 
86
85
  case obj
87
- when SSHKit::Command then write_command(obj)
88
- when SSHKit::LogMessage then write_log_message(obj)
86
+ when SSHKit::Command
87
+ command = decorate(obj)
88
+ write_command_start(command)
89
+ write_command_output(command)
90
+ write_command_exit(command) if command.finished?
91
+ when SSHKit::LogMessage
92
+ write_log_message(obj)
89
93
  end
90
94
  end
91
- alias :<< :write
95
+ alias_method :<<, :write
92
96
 
93
97
  def on_deploy_failure
94
98
  return if @log_file.nil?
95
99
  err = Airbrussh::Console.new($stderr)
96
100
  err.print_line
97
101
  err.print_line(red("** DEPLOY FAILED"))
98
- err.print_line(yellow(
99
- "** Refer to #{@log_file} for details. Here are the last 20 lines:"
100
- ))
102
+ err.print_line(yellow("** Refer to #{@log_file} for details. "\
103
+ "Here are the last 20 lines:"))
101
104
  err.print_line
102
105
  system("tail -n 20 #{@log_file.shellescape} 1>&2")
103
106
  end
104
107
 
105
108
  private
106
109
 
110
+ attr_accessor :last_printed_task
111
+
107
112
  def write_log_message(log_message)
108
- return unless log_message.verbosity >= SSHKit::Logger::INFO
113
+ return if debug?(log_message)
109
114
  print_task_if_changed
110
- @console.print_line(light_black(" " + log_message.to_s))
115
+ print_indented_line(gray(log_message.to_s))
111
116
  end
112
117
 
113
- def write_command(command)
114
- return unless command.verbosity > SSHKit::Logger::DEBUG
115
-
118
+ def write_command_start(command)
119
+ return if debug?(command)
116
120
  print_task_if_changed
117
-
118
- ctx = context_for_command(command)
119
- number = '%02d' % ctx.number
120
-
121
- if ctx.first_execution?
122
- description = yellow(ctx.shell_string)
123
- print_line " #{number} #{description}"
124
- end
125
-
126
- write_command_output(command, number)
127
-
128
- if command.finished?
129
- status = format_command_completion_status(command, number)
130
- print_line " #{status}"
131
- end
121
+ print_indented_line(command.start_message) if command.first_execution?
132
122
  end
133
123
 
134
124
  # Prints the data from the stdout and stderr streams of the given command,
135
125
  # but only if enabled (see Airbrussh::Configuration#command_output).
136
- def write_command_output(command, number)
126
+ def write_command_output(command)
137
127
  # Use a bit of meta-programming here, since stderr and stdout logic
138
128
  # are identical except for different method names.
139
129
  %w(stderr stdout).each do |stream|
140
- next unless config.public_send("command_output_#{stream}?")
141
130
  CommandOutput.for(command).each_line(stream) do |line|
142
- print_line " #{number} #{line.chomp}"
131
+ write_command_output_line(command, stream, line)
143
132
  end
144
133
  end
145
134
  end
146
135
 
147
- def print_task_if_changed
148
- status = current_task_status
149
-
150
- if status.changed && !status.task.empty?
151
- print_line "#{clock} #{blue(status.task)}"
152
- end
136
+ def write_command_output_line(command, stream, line)
137
+ hide_command_output = !config.public_send("command_output_#{stream}?")
138
+ return if hide_command_output || debug?(command)
139
+ print_indented_line(command.format_output(line))
153
140
  end
154
141
 
155
- def current_task_status
156
- task = self.class.current_rake_task.to_s
157
- if @tasks[task]
158
- changed = false
159
- else
160
- changed = true
161
- @tasks[task] = []
162
- end
142
+ def print_task_if_changed
143
+ return if current_task_name.nil?
144
+ return if current_task_name == last_printed_task
163
145
 
164
- OpenStruct.new(
165
- :task => task,
166
- :commands => @tasks[task],
167
- :changed => changed
168
- )
146
+ self.last_printed_task = current_task_name
147
+ print_line("#{clock} #{blue(current_task_name)}")
169
148
  end
170
149
 
171
- def context_for_command(command)
172
- status = current_task_status
173
- task_commands = status.commands
174
-
175
- shell_string = command.to_s.sub(%r(^/usr/bin/env ), "")
176
-
177
- if task_commands.include?(shell_string)
178
- first_execution = false
179
- else
180
- first_execution = true
181
- task_commands << shell_string
182
- end
183
-
184
- number = task_commands.index(shell_string) + 1
185
-
186
- OpenStruct.new({
187
- :first_execution? => first_execution,
188
- :number => number,
189
- :shell_string => shell_string
190
- })
191
- end
192
-
193
- def format_command_completion_status(command, number)
194
- user = command.user { command.host.user }
195
- host = command.host.to_s
196
- user_at_host = [user, host].join("@")
197
-
198
- status = if command.failure?
199
- red("✘ #{number} #{user_at_host} (see #{@log_file} for details)")
200
- else
201
- green("✔ #{number} #{user_at_host}")
202
- end
203
-
204
- runtime = light_black("%5.3fs" % command.runtime)
205
-
206
- status + " " + runtime
150
+ def write_command_exit(command)
151
+ return if debug?(command)
152
+ print_indented_line(command.exit_message(@log_file), -2)
207
153
  end
208
154
 
209
155
  def clock
@@ -213,17 +159,24 @@ module Airbrussh
213
159
  minutes = (duration / 60).to_i
214
160
  seconds = (duration - minutes * 60).to_i
215
161
 
216
- "%02d:%02d" % [minutes, seconds]
162
+ format("%02d:%02d", minutes, seconds)
217
163
  end
218
164
 
219
- %w(light_black red blue green yellow).each do |color|
220
- define_method(color) do |string|
221
- string.to_s.colorize(color.to_sym)
222
- end
165
+ def debug?(obj)
166
+ obj.verbosity <= SSHKit::Logger::DEBUG
167
+ end
168
+
169
+ def decorate(command)
170
+ Airbrussh::CommandFormatter.new(@context.decorate_command(command))
171
+ end
172
+
173
+ def print_line(string)
174
+ @console.print_line(string)
223
175
  end
224
176
 
225
- def config
226
- Airbrussh.configuration
177
+ def print_indented_line(string, offset=0)
178
+ indent = " " * (6 + offset)
179
+ print_line([indent, string].join)
227
180
  end
228
181
  end
229
182
  end
@@ -0,0 +1,24 @@
1
+ module Airbrussh
2
+ module Rake
3
+ # Decorates an SSHKit Command to add Rake-specific contextual information:
4
+ #
5
+ # * first_execution? - is this the first time this command has been run in
6
+ # the context of the current rake task?
7
+ # * position - zero-based position of this command in the list of
8
+ # all commands that have been run in the current rake task
9
+ #
10
+ class Command < SimpleDelegator
11
+ attr_reader :first_execution, :position
12
+
13
+ def initialize(command, first_execution, position)
14
+ super(command)
15
+ @first_execution = first_execution
16
+ @position = position
17
+ end
18
+
19
+ def first_execution?
20
+ first_execution
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,73 @@
1
+ require "rake"
2
+ require "airbrussh/rake/command"
3
+
4
+ module Airbrussh
5
+ module Rake
6
+ # Maintains information about what Rake task is currently being invoked,
7
+ # in order to be able to decorate SSHKit commands with additional
8
+ # context-sensitive information. Works via a monkey patch to Rake::Task,
9
+ # which can be disabled via by setting
10
+ # Airbrussh.configuration.monkey_patch_rake = false.
11
+ #
12
+ class Context
13
+ def initialize(config=Airbrussh.configuration)
14
+ @history = []
15
+ @enabled = config.monkey_patch_rake
16
+ self.class.install_monkey_patch if enabled?
17
+ end
18
+
19
+ # Returns the name of the currently-executing rake task, if it can be
20
+ # determined. If monkey patching is disabled, this will be nil.
21
+ def current_task_name
22
+ return nil unless enabled?
23
+ self.class.current_task_name
24
+ end
25
+
26
+ # Decorate an SSHKit Command with Rake::Command to provide additional
27
+ # context-sensitive information.
28
+ def decorate_command(command)
29
+ reset_history_if_task_changed
30
+
31
+ first_execution = !history.include?(command.to_s)
32
+ history << command.to_s
33
+ history.uniq!
34
+
35
+ Airbrussh::Rake::Command.new(
36
+ command,
37
+ first_execution,
38
+ history.index(command.to_s)
39
+ )
40
+ end
41
+
42
+ class << self
43
+ attr_accessor :current_task_name
44
+
45
+ def install_monkey_patch
46
+ return if ::Rake::Task.instance_methods.include?(:_airbrussh_execute)
47
+
48
+ ::Rake::Task.class_exec do
49
+ alias_method :_airbrussh_execute, :execute
50
+ def execute(args=nil) # rubocop:disable Lint/NestedMethodDefinition
51
+ ::Airbrussh::Rake::Context.current_task_name = name.to_s
52
+ _airbrussh_execute(args)
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ attr_reader :history
61
+ attr_accessor :last_task_name
62
+
63
+ def reset_history_if_task_changed
64
+ history.clear if last_task_name != current_task_name
65
+ self.last_task_name = current_task_name
66
+ end
67
+
68
+ def enabled?
69
+ @enabled
70
+ end
71
+ end
72
+ end
73
+ end
@@ -1,3 +1,3 @@
1
1
  module Airbrussh
2
- VERSION = "0.4.1"
2
+ VERSION = "0.5.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: airbrussh
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Brictson
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-05-06 00:00:00.000000000 Z
11
+ date: 2015-06-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sshkit
@@ -44,6 +44,48 @@ dependencies:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
46
  version: '1.8'
47
+ - !ruby/object:Gem::Dependency
48
+ name: coveralls
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: guard
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: 2.2.2
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: 2.2.2
75
+ - !ruby/object:Gem::Dependency
76
+ name: guard-minitest
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
47
89
  - !ruby/object:Gem::Dependency
48
90
  name: rake
49
91
  requirement: !ruby/object:Gem::Requirement
@@ -58,6 +100,20 @@ dependencies:
58
100
  - - "~>"
59
101
  - !ruby/object:Gem::Version
60
102
  version: '10.0'
103
+ - !ruby/object:Gem::Dependency
104
+ name: rb-fsevent
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
61
117
  - !ruby/object:Gem::Dependency
62
118
  name: minitest
63
119
  requirement: !ruby/object:Gem::Requirement
@@ -86,6 +142,48 @@ dependencies:
86
142
  - - ">="
87
143
  - !ruby/object:Gem::Version
88
144
  version: '0'
145
+ - !ruby/object:Gem::Dependency
146
+ name: rubocop
147
+ requirement: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: 0.31.0
152
+ type: :development
153
+ prerelease: false
154
+ version_requirements: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ version: 0.31.0
159
+ - !ruby/object:Gem::Dependency
160
+ name: terminal-notifier-guard
161
+ requirement: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - ">="
171
+ - !ruby/object:Gem::Version
172
+ version: '0'
173
+ - !ruby/object:Gem::Dependency
174
+ name: chandler
175
+ requirement: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ version: '0'
180
+ type: :development
181
+ prerelease: false
182
+ version_requirements: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - ">="
185
+ - !ruby/object:Gem::Version
186
+ version: '0'
89
187
  description: A replacement log formatter for SSHKit that makes Capistrano output much
90
188
  easier on the eyes. Just add Airbrussh to your Capfile and enjoy concise, useful
91
189
  log output that is easy to read.
@@ -96,22 +194,31 @@ extensions: []
96
194
  extra_rdoc_files: []
97
195
  files:
98
196
  - ".gitignore"
197
+ - ".rubocop.yml"
198
+ - ".rubocop_todo.yml"
99
199
  - ".travis.yml"
100
200
  - CHANGELOG.md
201
+ - CONTRIBUTING.md
101
202
  - Gemfile
203
+ - Guardfile
102
204
  - LICENSE.txt
103
205
  - README.md
104
206
  - Rakefile
105
207
  - airbrussh.gemspec
106
208
  - bin/console
107
209
  - bin/setup
210
+ - bin/test_all.rb
108
211
  - demo.gif
109
212
  - lib/airbrussh.rb
110
213
  - lib/airbrussh/capistrano.rb
214
+ - lib/airbrussh/colors.rb
215
+ - lib/airbrussh/command_formatter.rb
111
216
  - lib/airbrussh/command_output.rb
112
217
  - lib/airbrussh/configuration.rb
113
218
  - lib/airbrussh/console.rb
114
219
  - lib/airbrussh/formatter.rb
220
+ - lib/airbrussh/rake/command.rb
221
+ - lib/airbrussh/rake/context.rb
115
222
  - lib/airbrussh/version.rb
116
223
  - lib/sshkit/formatter/airbrussh.rb
117
224
  homepage: https://github.com/mattbrictson/airbrussh
@@ -134,7 +241,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
134
241
  version: '0'
135
242
  requirements: []
136
243
  rubyforge_project:
137
- rubygems_version: 2.4.5
244
+ rubygems_version: 2.4.8
138
245
  signing_key:
139
246
  specification_version: 4
140
247
  summary: Airbrussh pretties up your SSHKit and Capistrano output