sshkit 0.0.6 → 0.0.7

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.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: