sshkit 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -3,6 +3,32 @@
3
3
  This file is written in reverse chronological order, newer releases will
4
4
  appear at the top.
5
5
 
6
+ ## 0.0.7
7
+
8
+ * DSL method `execute()` will now raise `SSHKit::Command::Failed` when the
9
+ exit status is non-zero. The message of the exception will be whatever the
10
+ process had written to stdout.
11
+ * New DSL method `test()` behaves as `execute()` used to until this version.
12
+ * `Command` now raises an error in `#exit_status=()` if the exit status given
13
+ is not zero. (see below)
14
+ * All errors raised by error conditions of SSHKit are defined as subclasses of
15
+ `SSHKit::StandardError` which is itself a subclass of `StandardError`.
16
+
17
+ The `Command` objects can be set to not raise, by passing `raise_on_non_zero_exit: false`
18
+ when instantiating them, this is exactly what `test()` does internally.
19
+
20
+ Example:
21
+
22
+ on hosts do |host
23
+ if test "[ -d /opt/sites ]" do
24
+ within "/opt/sites" do
25
+ execute :git, :pull
26
+ end
27
+ else
28
+ execute :git, :clone, 'some-repository', '/opt/sites'
29
+ end
30
+ end
31
+
6
32
  ## 0.0.6
7
33
 
8
34
  * Support arbitrary properties on Host objects. (see below)
data/EXAMPLES.md CHANGED
@@ -43,7 +43,7 @@ This will output:
43
43
  **Note:** This example is a bit misleading, as the `www-data` user doesn't
44
44
  have a shell defined, one cannot switch to that user.
45
45
 
46
- ## Stack directory nestings:
46
+ ## Stack directory nestings
47
47
 
48
48
  on hosts do
49
49
  in "/var" do
@@ -65,7 +65,7 @@ leading slashes. It may be misleading as the `File.join()` is performed on the
65
65
  machine running the code, if that's a Windows box, the paths may be incorrectly
66
66
  joined according to the expectations of the machine receiving the commands.
67
67
 
68
- ## Do not care about the host block:
68
+ ## Do not care about the host block
69
69
 
70
70
  on hosts do
71
71
  # The |host| argument is optional, it will
@@ -76,7 +76,7 @@ joined according to the expectations of the machine receiving the commands.
76
76
 
77
77
  SSHKit.config.output = File.open('/dev/null')
78
78
 
79
- ## Implement a dirt-simple formatter class:
79
+ ## Implement a dirt-simple formatter class
80
80
 
81
81
  class MyFormatter < SSHKit::Formatter::Abstract
82
82
  def write(obj)
@@ -99,16 +99,32 @@ joined according to the expectations of the machine receiving the commands.
99
99
  puts capture(:echo, "I don't care about security!")
100
100
  end
101
101
 
102
- ## Execute and raise an error if something goes wrong:
102
+ ## Execute and raise an error if something goes wrong
103
103
 
104
104
  on hosts do |host|
105
105
  execute!(:echo, '"Example Message!" 1>&2; false')
106
106
  end
107
107
 
108
- This will raise `SSHKit::CommandUncleanExit.new("Example Message!")` which
109
- will cause the command to abort.
108
+ This will raise `SSHKit::Command:Failed` with the `#message` "Example Message!"`
109
+ which will cause the command to abort.
110
110
 
111
- ## Do something different on one host, or another depending on a host property:
111
+ ## Make a test, or run a command which may fail without raising an error:
112
+
113
+ on hosts do |host
114
+ if test "[ -d /opt/sites ]" do
115
+ within "/opt/sites" do
116
+ execute :git, :pull
117
+ end
118
+ else
119
+ execute :git, :clone, 'some-repository', '/opt/sites'
120
+ end
121
+ end
122
+
123
+ The `test()` command behaves exactly the same as execute however will return
124
+ false if the command exits with a non-zero exit (as `man 1 test` does). As ti
125
+ returns boolean it can be used to direct the control flow within the block.
126
+
127
+ ## Do something different on one host, or another depending on a host property
112
128
 
113
129
  host1 = SSHKit::Host.new 'user@example.com'
114
130
  host2 = SSHKit::Host.new 'user@example.org'
@@ -123,7 +139,7 @@ will cause the command to abort.
123
139
  execute! :git, :clone, "git@git.#{host.hostname}", target
124
140
  end
125
141
 
126
- ## Connect to a host in the easiest possible way:
142
+ ## Connect to a host in the easiest possible way
127
143
 
128
144
  on 'example.com' do |host|
129
145
  execute :uptime
@@ -133,7 +149,7 @@ This will resolve the `example.com` hostname into a `SSHKit::Host` object, and
133
149
  try to pull up the correct configuration for it.
134
150
 
135
151
 
136
- ## Run a command without it being command-mapped:
152
+ ## Run a command without it being command-mapped
137
153
 
138
154
  If the command you attempt to call contains a space character it won't be
139
155
  mapped:
data/lib/sshkit.rb CHANGED
@@ -1,8 +1,7 @@
1
- require 'thread'
2
- require_relative 'sshkit/all'
3
-
4
1
  module SSHKit
5
2
 
3
+ StandardError = Class.new(::StandardError)
4
+
6
5
  class << self
7
6
  attr_accessor :config
8
7
  end
@@ -25,3 +24,5 @@ module SSHKit
25
24
  end
26
25
 
27
26
  end
27
+
28
+ require_relative 'sshkit/all'
@@ -1,7 +1,7 @@
1
1
  module SSHKit
2
2
  module Backend
3
3
 
4
- MethodUnavailableError = Class.new(RuntimeError)
4
+ MethodUnavailableError = Class.new(SSHKit::StandardError)
5
5
 
6
6
  class Abstract
7
7
 
@@ -25,6 +25,10 @@ module SSHKit
25
25
  raise MethodUnavailableError
26
26
  end
27
27
 
28
+ def test(command, args=[])
29
+ raise MethodUnavailableError
30
+ end
31
+
28
32
  def execute(command, args=[])
29
33
  raise MethodUnavailableError
30
34
  end
@@ -71,7 +75,8 @@ module SSHKit
71
75
  private
72
76
 
73
77
  def command(*args)
74
- SSHKit::Command.new(*args, in: @pwd.nil? ? nil : File.join(@pwd), env: @env, host: @host, user: @user)
78
+ options = args.extract_options!
79
+ SSHKit::Command.new(*[*args, options.merge({in: @pwd.nil? ? nil : File.join(@pwd), env: @env, host: @host, user: @user})])
75
80
  end
76
81
 
77
82
  def connection
@@ -11,6 +11,11 @@ module SSHKit
11
11
  instance_exec(host, &@block)
12
12
  end
13
13
 
14
+ def test(*args)
15
+ options = args.extract_options!.merge(raise_on_non_zero_exit: false)
16
+ _execute(*[*args, options]).success?
17
+ end
18
+
14
19
  def execute(*args)
15
20
  _execute(*args).success?
16
21
  end
@@ -31,6 +31,8 @@ module SSHKit
31
31
  # @author Lee Hambley
32
32
  class Command
33
33
 
34
+ Failed = Class.new(SSHKit::StandardError)
35
+
34
36
  attr_reader :command, :args, :options, :started_at, :started, :exit_status
35
37
 
36
38
  attr_accessor :stdout, :stderr
@@ -44,7 +46,7 @@ module SSHKit
44
46
  #
45
47
  def initialize(*args)
46
48
  raise ArgumentError, "May not pass no arguments to Command.new" if args.empty?
47
- @options = args.extract_options!
49
+ @options = default_options.merge(args.extract_options!)
48
50
  @command = args.shift.to_s.strip.to_sym
49
51
  @args = args
50
52
  @options.symbolize_keys!
@@ -83,6 +85,9 @@ module SSHKit
83
85
  def exit_status=(new_exit_status)
84
86
  @finished_at = Time.now
85
87
  @exit_status = new_exit_status
88
+ if options[:raise_on_non_zero_exit] && exit_status > 0
89
+ raise Failed, stderr.empty? ? "No messages written to stderr" : stderr.strip
90
+ end
86
91
  end
87
92
 
88
93
  def runtime
@@ -136,6 +141,10 @@ module SSHKit
136
141
 
137
142
  private
138
143
 
144
+ def default_options
145
+ { raise_on_non_zero_exit: true }
146
+ end
147
+
139
148
  def sanitize_command!
140
149
  command.to_s.strip!
141
150
  if command.to_s.match("\n")
data/lib/sshkit/host.rb CHANGED
@@ -2,7 +2,7 @@ require 'ostruct'
2
2
 
3
3
  module SSHKit
4
4
 
5
- UnparsableHostStringError = Class.new(StandardError)
5
+ UnparsableHostStringError = Class.new(SSHKit::StandardError)
6
6
 
7
7
  class Host
8
8
 
@@ -1,3 +1,5 @@
1
+ require 'thread'
2
+
1
3
  module SSHKit
2
4
 
3
5
  module Runner
@@ -1,3 +1,3 @@
1
1
  module SSHKit
2
- VERSION = "0.0.6"
2
+ VERSION = "0.0.7"
3
3
  end
data/test/helper.rb CHANGED
@@ -9,7 +9,7 @@ rescue Bundler::BundlerError => e
9
9
  end
10
10
  require 'tempfile'
11
11
  require 'minitest/unit'
12
- require 'mocha'
12
+ require 'mocha/setup'
13
13
  require 'turn'
14
14
  require 'unindent'
15
15
  require 'debugger'
@@ -17,7 +17,12 @@ module SSHKit
17
17
  end
18
18
  end
19
19
 
20
- class TestPrinter < FunctionalTest
20
+ class TestNetssh < FunctionalTest
21
+
22
+ def setup
23
+ super
24
+ SSHKit.config.output = SSHKit::Formatter::BlackHole.new($stdout)
25
+ end
21
26
 
22
27
  def block_to_run
23
28
  lambda do |host|
@@ -70,26 +75,19 @@ module SSHKit
70
75
  end
71
76
  end
72
77
 
73
- def test_exit_status
74
-
78
+ def test_execute_raises_on_non_zero_exit_status_and_captures_stderr
79
+ err = assert_raises SSHKit::Command::Failed do
80
+ Netssh.new(a_host) do |host|
81
+ execute :echo, "'Test capturing stderr' 1>&2; false"
82
+ end.run
83
+ end
84
+ assert_equal "Test capturing stderr", err.message
75
85
  end
76
86
 
77
- def test_raising_an_error_if_a_command_returns_a_bad_exit_status
78
- skip "Where to implement this?"
79
- # NOTE: I think that it might be wise to have Command raise when
80
- # Command#exit_status=() is called, it would allow an option to
81
- # be passed to command (raise_errors: false), which could also be
82
- # inherited through Backend#command and specified on the (not yet
83
- # existing) backend configurations.
84
- assert_raises RuntimeError do
85
- File.open('/dev/null', 'w') do |dnull|
86
- SSHKit.capture_output(dnull) do
87
- Netssh.new(a_host) do |host|
88
- execute :false
89
- end.run
90
- end
91
- end
92
- end
87
+ def test_test_does_not_raise_on_non_zero_exit_status
88
+ Netssh.new(a_host) do |host|
89
+ test :false
90
+ end.run
93
91
  end
94
92
 
95
93
  end
@@ -1,4 +1,5 @@
1
1
  require 'helper'
2
+ require 'sshkit'
2
3
 
3
4
  module SSHKit
4
5
  class TestCommand < UnitTest
@@ -51,7 +52,7 @@ module SSHKit
51
52
  end
52
53
 
53
54
  def test_complete?
54
- c = Command.new(:whoami)
55
+ c = Command.new(:whoami, raise_on_non_zero_exit: false)
55
56
  refute c.complete?
56
57
  c.exit_status = 1
57
58
  assert c.complete?
@@ -69,7 +70,7 @@ module SSHKit
69
70
  end
70
71
 
71
72
  def test_failure?
72
- c = Command.new(:whoami)
73
+ c = Command.new(:whoami, raise_on_non_zero_exit: false)
73
74
  refute c.failure?
74
75
  refute c.failed?
75
76
  c.exit_status = 1
@@ -93,7 +94,7 @@ module SSHKit
93
94
  end
94
95
 
95
96
  def test_setting_exit_status
96
- c = Command.new(:whoami)
97
+ c = Command.new(:whoami, raise_on_non_zero_exit: false)
97
98
  assert_equal nil, c.exit_status
98
99
  assert c.exit_status = 1
99
100
  assert_equal 1, c.exit_status
@@ -109,5 +110,12 @@ module SSHKit
109
110
  end
110
111
  end
111
112
 
113
+ def test_command_raises_command_failed_error_when_non_zero_exit
114
+ error = assert_raises SSHKit::Command::Failed do
115
+ Command.new(:whoami).exit_status = 1
116
+ end
117
+ assert_equal "No messages written to stderr", error.message
118
+ end
119
+
112
120
  end
113
121
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sshkit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors: