harrison 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - ruby-head
4
+ - 2.1.1
5
+ - 2.0.0
6
+ - 1.9.3
data/CHANGELOG ADDED
@@ -0,0 +1,10 @@
1
+ 0.1.0
2
+ -------------------
3
+ - Renamed --pkg_dir option of 'package' task to --destination
4
+ - Implemented remote destinations for 'package' task.
5
+ - Implemented remote artifact sources for 'deploy' task.
6
+ - Added a default timeout of 10 seconds when establishing an SSH connection.
7
+
8
+ 0.0.1
9
+ -------------------
10
+ - Initial public release.
data/IDEAS ADDED
@@ -0,0 +1,12 @@
1
+ Ideas:
2
+ ------
3
+ [ ] Allow more elaborate hosts config, e.g.: h.hosts = [ { host: '10.16.18.207', tags: %w(util migrate) } ]
4
+ [ ] Some kind of --dry-run option.
5
+ [ ] Allow deploy_via to include alternate user/connection options.
6
+ [ ] Rename "releases" => "builds" (and "deploys" => "releases"?)
7
+ [ ] Upload artifact to all hosts before the rest of the deployment process begins.
8
+ [ ] --force option for deploy task to overwrite an existing release
9
+ [ ] Something like a "status" command that shows what commit is live for env (on each host?)
10
+ [ ] Move artifacts out of pkg/ (and into like pkg/deployed) once they have been deployed? (Some sort of flag for the significant env?)
11
+ [ ] Include branch name in artifact file name.
12
+ [ ] Make --purge the default behavior for the package step.
data/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  Simple artifact-based deployment for web applications.
4
4
 
5
+ [![Build Status](https://travis-ci.org/scotje/harrison.svg?branch=master)](https://travis-ci.org/scotje/harrison)
6
+
5
7
  ## Installation
6
8
 
7
9
  Add this line to your application's Gemfile:
@@ -35,6 +37,10 @@ Harrison.package do |h|
35
37
  # Things we don't want to package.
36
38
  h.exclude = %w(.git ./config ./coverage ./examples ./log ./pkg ./tmp ./spec)
37
39
 
40
+ # Where to save the artifact by default.
41
+ h.destination = 'pkg' # Local folder
42
+ # h.destination = 'jesse@artifact-host.example.com:/tmp/artifacts' # Remote folder
43
+
38
44
  # Define the build process here.
39
45
  h.run do |h|
40
46
  # Bundle Install
@@ -82,7 +88,7 @@ The `--commit` option understands anything that `git rev-parse` understands. *NO
82
88
  reference must be pushed to the repository referenced as `git_src` in the Harrisonfile before
83
89
  you can build it.*
84
90
 
85
- The packaged release artifact will, by default, be saved into a 'pkg' subfolder:
91
+ The packaged release artifact will, by default, be saved into a local 'pkg' subfolder:
86
92
 
87
93
  ```
88
94
  $ harrison package
@@ -90,6 +96,23 @@ Packaging 5a547d8 for "harrison" on build-server.example.com...
90
96
  Sucessfully packaged 5a547d8 to pkg/20140711170226-5a547d8.tar.gz
91
97
  ```
92
98
 
99
+ You can set the destination on the command line with the `--destination` option, or
100
+ specify a new default in your Harrisonfile:
101
+
102
+ ```
103
+ h.destination = '/tmp'
104
+ ```
105
+
106
+ You can also specify a remote destination:
107
+
108
+ ```
109
+ h.destination = 'jesse@artifact-host.example.com:/tmp/artifacts'
110
+ ```
111
+
112
+ The username is optional and, if omitted, the build user will be used. *NOTE: Your build server
113
+ must have already accepted the SSH host key of the destination server in order to transfer the
114
+ artifact.*
115
+
93
116
  There are some additional options available, run `harrison package --help` to see everything available.
94
117
 
95
118
 
@@ -101,7 +124,16 @@ Use the `harrison deploy` command passing the artifact to be deployed as an argu
101
124
  $ harrison deploy pkg/20140711170226-5a547d8.tar.gz
102
125
  ```
103
126
 
104
- By default, this will deploy to the list of hosts defined in your Harrisonfile.
127
+ You can also deploy from a remote artifact source:
128
+
129
+ ```
130
+ $ harrison deploy jesse@artifact-host.example.com:/tmp/artifacts/20140711170226-5a547d8.tar.gz
131
+ ```
132
+
133
+ *NOTE: Each target server must have already accepted the SSH host key of the source server in order to
134
+ transfer the artifact.*
135
+
136
+ By default, the artifact will be deployed to the list of hosts defined in your Harrisonfile.
105
137
 
106
138
  You can override the target hosts by passing a `--hosts` option:
107
139
 
data/harrison.gemspec CHANGED
@@ -25,7 +25,7 @@ Gem::Specification.new do |spec|
25
25
 
26
26
  spec.add_development_dependency "bundler", "~> 1.6"
27
27
  spec.add_development_dependency "rake"
28
- spec.add_development_dependency "rspec"
28
+ spec.add_development_dependency "rspec", "~> 3.0"
29
29
  spec.add_development_dependency "debugger" if RUBY_VERSION < "2.0.0"
30
30
  spec.add_development_dependency "byebug" if RUBY_VERSION >= "2.0.0"
31
31
  spec.add_development_dependency "sourcify"
data/lib/harrison/base.rb CHANGED
@@ -87,15 +87,22 @@ module Harrison
87
87
  @ssh ||= Harrison::SSH.new(host: @options[:host], user: @options[:user])
88
88
  end
89
89
 
90
+ def remote_regex
91
+ /^(?:(\S+)@)?(\S+):(\S+)$/
92
+ end
93
+
90
94
  def ensure_local_dir(dir)
91
95
  @_ensured_local ||= {}
92
96
  @_ensured_local[dir] || (system("if [ ! -d #{dir} ] ; then mkdir -p #{dir} ; fi") && @_ensured_local[dir] = true) || abort("Error: Unable to create local directory \"#{dir}\".")
93
97
  end
94
98
 
95
- def ensure_remote_dir(host, dir)
99
+ def ensure_remote_dir(dir, with_ssh = nil)
100
+ with_ssh = ssh if with_ssh.nil?
101
+ host = with_ssh.host
102
+
96
103
  @_ensured_remote ||= {}
97
104
  @_ensured_remote[host] ||= {}
98
- @_ensured_remote[host][dir] || (ssh.exec("if [ ! -d #{dir} ] ; then mkdir -p #{dir} ; fi") && @_ensured_remote[host][dir] = true) || abort("Error: Unable to create remote directory \"#{dir}\" on \"#{host}\".")
105
+ @_ensured_remote[host][dir] || (with_ssh.exec("if [ ! -d #{dir} ] ; then mkdir -p #{dir} ; fi") && @_ensured_remote[host][dir] = true) || abort("Error: Unable to create remote directory \"#{dir}\" on \"#{host}\".")
99
106
  end
100
107
  end
101
108
  end
@@ -56,14 +56,22 @@ module Harrison
56
56
  hosts.each do |h|
57
57
  self.host = h
58
58
 
59
- ensure_remote_dir(self.host, "#{remote_project_dir}/deploys")
60
- ensure_remote_dir(self.host, "#{remote_project_dir}/releases")
59
+ ensure_remote_dir("#{remote_project_dir}/deploys", self.ssh)
60
+ ensure_remote_dir("#{remote_project_dir}/releases", self.ssh)
61
61
 
62
62
  # Make folder for release or bail if it already exists.
63
63
  remote_exec("mkdir #{release_dir}")
64
64
 
65
- # Upload artifact to host.
66
- upload(artifact, "#{remote_project_dir}/releases/")
65
+ if match = remote_regex.match(artifact)
66
+ # Copy artifact to host from remote source.
67
+ src_user, src_host, src_path = match.captures
68
+ src_user ||= self.user
69
+
70
+ remote_exec("scp #{src_user}@#{src_host}:#{src_path} #{remote_project_dir}/releases/")
71
+ else
72
+ # Upload artifact to host.
73
+ upload(artifact, "#{remote_project_dir}/releases/")
74
+ end
67
75
 
68
76
  # Unpack.
69
77
  remote_exec("cd #{release_dir} && tar -xzf ../#{File.basename(artifact)}")
@@ -5,7 +5,7 @@ module Harrison
5
5
  self.class.option_helper(:host)
6
6
  self.class.option_helper(:commit)
7
7
  self.class.option_helper(:purge)
8
- self.class.option_helper(:pkg_dir)
8
+ self.class.option_helper(:destination)
9
9
  self.class.option_helper(:remote_dir)
10
10
  self.class.option_helper(:exclude)
11
11
 
@@ -13,7 +13,7 @@ module Harrison
13
13
  arg_opts = [
14
14
  [ :commit, "Specific commit to be packaged. Accepts anything that `git rev-parse` understands.", :type => :string, :default => "HEAD" ],
15
15
  [ :purge, "Remove all previously packaged commits and working copies from the build host when finished.", :type => :boolean, :default => false ],
16
- [ :pkg_dir, "Local folder to save package to.", :type => :string, :default => "pkg" ],
16
+ [ :destination, "Local or remote folder to save package to. Remote syntax is: (user@)host:/path", :type => :string, :default => "pkg" ],
17
17
  [ :remote_dir, "Remote working folder.", :type => :string, :default => "~/.harrison" ],
18
18
  ]
19
19
 
@@ -21,7 +21,7 @@ module Harrison
21
21
  end
22
22
 
23
23
  def remote_exec(cmd)
24
- ensure_remote_dir(self.host, "#{remote_project_dir}/package")
24
+ ensure_remote_dir("#{remote_project_dir}/package")
25
25
 
26
26
  super("cd #{remote_project_dir}/package && #{cmd}")
27
27
  end
@@ -35,7 +35,7 @@ module Harrison
35
35
  puts "Packaging #{commit} for \"#{project}\" on #{host}..."
36
36
 
37
37
  # Make sure the folder to save the artifact to locally exists.
38
- ensure_local_dir(pkg_dir)
38
+ ensure_destination(destination)
39
39
 
40
40
  # Fetch/clone git repo on remote host.
41
41
  remote_exec("if [ -d cached ] ; then cd cached && git fetch origin -p ; else git clone #{git_src} cached ; fi")
@@ -53,14 +53,22 @@ module Harrison
53
53
  # Package build folder into tgz.
54
54
  remote_exec("rm -f #{artifact_name(commit)}.tar.gz && cd #{commit} && tar #{excludes_for_tar} -czf ../#{artifact_name(commit)}.tar.gz .")
55
55
 
56
- # Download (Expand remote path since Net::SCP doesn't expand ~)
57
- download(remote_exec("readlink -m #{artifact_name(commit)}.tar.gz"), "#{pkg_dir}/#{artifact_name(commit)}.tar.gz")
56
+ if match = remote_regex.match(destination)
57
+ # Copy artifact to remote destination.
58
+ dest_user, dest_host, dest_path = match.captures
59
+ dest_user ||= self.user
60
+
61
+ remote_exec("scp #{artifact_name(commit)}.tar.gz #{dest_user}@#{dest_host}:#{dest_path}")
62
+ else
63
+ # Download (Expand remote path since Net::SCP doesn't expand ~)
64
+ download(remote_exec("readlink -m #{artifact_name(commit)}.tar.gz"), "#{destination}/#{artifact_name(commit)}.tar.gz")
65
+ end
58
66
 
59
67
  if purge
60
68
  remote_exec("cd .. && rm -rf package")
61
69
  end
62
70
 
63
- puts "Sucessfully packaged #{commit} to #{pkg_dir}/#{artifact_name(commit)}.tar.gz"
71
+ puts "Sucessfully packaged #{commit} to #{destination}/#{artifact_name(commit)}.tar.gz"
64
72
  end
65
73
 
66
74
  protected
@@ -83,5 +91,16 @@ module Harrison
83
91
  @_timestamp ||= Time.new.utc.strftime('%Y%m%d%H%M%S')
84
92
  "#{@_timestamp}-#{commit}"
85
93
  end
94
+
95
+ def ensure_destination(destination)
96
+ if match = remote_regex.match(destination)
97
+ dest_user, dest_host, dest_path = match.captures
98
+ dest_user ||= self.user
99
+
100
+ ensure_remote_dir(dest_path, Harrison::SSH.new(host: dest_host, user: dest_user))
101
+ else
102
+ ensure_local_dir(destination)
103
+ end
104
+ end
86
105
  end
87
106
  end
data/lib/harrison/ssh.rb CHANGED
@@ -7,46 +7,23 @@ module Harrison
7
7
  def initialize(opts={})
8
8
  if opts[:proxy]
9
9
  @proxy = Net::SSH::Proxy::Command.new("ssh #{opts[:proxy]} \"nc %h %p\" 2>/dev/null")
10
- @conn = Net::SSH.start(opts[:host], opts[:user], forward_agent: true, proxy: @proxy)
10
+ @conn = Net::SSH.start(opts[:host], opts[:user], forward_agent: true, proxy: @proxy, timeout: 10)
11
11
  else
12
- @conn = Net::SSH.start(opts[:host], opts[:user], forward_agent: true)
12
+ @conn = Net::SSH.start(opts[:host], opts[:user], forward_agent: true, timeout: 10)
13
13
  end
14
14
  end
15
15
 
16
- # Helper to catch non-zero exit status and report errors.
17
16
  def exec(command)
18
17
  puts "INFO (ssh-exec #{desc}): #{command}" if Harrison::DEBUG
19
18
 
20
- stdout_data = ""
21
- stderr_data = ""
22
- exit_code = nil
23
-
24
- @conn.open_channel do |channel|
25
- channel.exec(command) do |ch, success|
26
- warn "Couldn't execute command (ssh.channel.exec) on remote host: #{command}" unless success
27
-
28
- channel.on_data do |ch,data|
29
- stdout_data += data
30
- end
31
-
32
- channel.on_extended_data do |ch,type,data|
33
- stderr_data += data
34
- end
19
+ result = invoke(@conn, command)
35
20
 
36
- channel.on_request("exit-status") do |ch,data|
37
- exit_code = data.read_long
38
- end
39
- end
21
+ if Harrison::DEBUG || result[:status] != 0
22
+ warn "STDERR (ssh-exec #{desc}): #{result[:stderr]}" unless result[:stderr].empty?
23
+ warn "STDOUT (ssh-exec #{desc}): #{result[:stdout]}" unless result[:stdout].empty?
40
24
  end
41
25
 
42
- @conn.loop
43
-
44
- if Harrison::DEBUG || exit_code != 0
45
- warn "STDERR (ssh-exec #{desc}): #{stderr_data.strip}" unless stderr_data.empty?
46
- warn "STDOUT (ssh-exec #{desc}): #{stdout_data.strip}" unless stdout_data.empty?
47
- end
48
-
49
- (exit_code == 0) ? stdout_data : nil
26
+ (result[:status] == 0) ? result[:stdout] : nil
50
27
  end
51
28
 
52
29
  def download(remote_path, local_path)
@@ -76,5 +53,40 @@ module Harrison
76
53
  @conn.host
77
54
  end
78
55
  end
56
+
57
+ def host
58
+ @conn.host
59
+ end
60
+
61
+ protected
62
+ # ----------------------------------------
63
+
64
+ def invoke(conn, cmd)
65
+ stdout_data = ""
66
+ stderr_data = ""
67
+ exit_code = nil
68
+
69
+ conn.open_channel do |channel|
70
+ channel.exec(cmd) do |ch, success|
71
+ warn "Couldn't execute command (ssh.channel.exec) on remote host: #{cmd}" unless success
72
+
73
+ channel.on_data do |ch,data|
74
+ stdout_data += data
75
+ end
76
+
77
+ channel.on_extended_data do |ch,type,data|
78
+ stderr_data += data
79
+ end
80
+
81
+ channel.on_request("exit-status") do |ch,data|
82
+ exit_code = data.read_long
83
+ end
84
+ end
85
+ end
86
+
87
+ conn.loop
88
+
89
+ { status: exit_code, stdout: stdout_data.strip, stderr: stderr_data.strip }
90
+ end
79
91
  end
80
92
  end
@@ -1,3 +1,3 @@
1
1
  module Harrison
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
data/spec/spec_helper.rb CHANGED
@@ -5,7 +5,6 @@ require 'harrison'
5
5
 
6
6
  # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
7
  RSpec.configure do |config|
8
- config.treat_symbols_as_metadata_keys_with_true_values = true
9
8
  config.run_all_when_everything_filtered = true
10
9
  config.filter_run :focus
11
10
 
@@ -28,12 +27,12 @@ RSpec::Matchers.define :exit_with_code do |exp_code|
28
27
  actual and actual == exp_code
29
28
  end
30
29
 
31
- failure_message_for_should do |block|
30
+ failure_message do |block|
32
31
  "expected block to call exit(#{exp_code}) but exit" +
33
32
  (actual.nil? ? " not called" : "(#{actual}) was called")
34
33
  end
35
34
 
36
- failure_message_for_should_not do |block|
35
+ failure_message_when_negated do |block|
37
36
  "expected block not to call exit(#{exp_code})"
38
37
  end
39
38
 
@@ -7,17 +7,17 @@ describe Harrison::Base do
7
7
  it 'should persist arg_opts' do
8
8
  instance = Harrison::Base.new(['foo'])
9
9
 
10
- instance.instance_variable_get('@arg_opts').should include('foo')
10
+ expect(instance.instance_variable_get('@arg_opts')).to include('foo')
11
11
  end
12
12
 
13
13
  it 'should add debug to arg_opts' do
14
- instance.instance_variable_get('@arg_opts').to_s.should include(':debug')
14
+ expect(instance.instance_variable_get('@arg_opts').to_s).to include(':debug')
15
15
  end
16
16
 
17
17
  it 'should persist options' do
18
18
  instance = Harrison::Base.new([], testopt: 'foo')
19
19
 
20
- instance.instance_variable_get('@options').should include(testopt: 'foo')
20
+ expect(instance.instance_variable_get('@options')).to include(testopt: 'foo')
21
21
  end
22
22
  end
23
23
 
@@ -26,13 +26,13 @@ describe Harrison::Base do
26
26
  it 'should define a getter instance method for the option' do
27
27
  Harrison::Base.option_helper('foo')
28
28
 
29
- instance.methods.should include(:foo)
29
+ expect(instance.methods).to include(:foo)
30
30
  end
31
31
 
32
32
  it 'should define a setter instance method for the option' do
33
33
  Harrison::Base.option_helper('foo')
34
34
 
35
- instance.methods.should include(:foo=)
35
+ expect(instance.methods).to include(:foo=)
36
36
  end
37
37
  end
38
38
  end
@@ -40,15 +40,15 @@ describe Harrison::Base do
40
40
  describe 'instance methods' do
41
41
  describe '#exec' do
42
42
  it 'should execute a command locally and return the output' do
43
- instance.exec('echo "foo"').should == 'foo'
43
+ expect(instance.exec('echo "foo"')).to eq('foo')
44
44
  end
45
45
 
46
46
  it 'should complain if command returns non-zero' do
47
47
  output = capture(:stderr) do
48
- lambda { instance.exec('cat noexist 2>/dev/null') }.should exit_with_code(1)
48
+ expect(lambda { instance.exec('cat noexist 2>/dev/null') }).to exit_with_code(1)
49
49
  end
50
50
 
51
- output.should include('unable', 'execute', 'local', 'command')
51
+ expect(output).to include('unable', 'execute', 'local', 'command')
52
52
  end
53
53
  end
54
54
 
@@ -61,21 +61,29 @@ describe Harrison::Base do
61
61
  it 'should delegate command to ssh instance' do
62
62
  expect(@mock_ssh).to receive(:exec).and_return('remote_exec_return')
63
63
 
64
- instance.remote_exec('remote exec').should == 'remote_exec_return'
64
+ expect(instance.remote_exec('remote exec')).to eq('remote_exec_return')
65
65
  end
66
66
 
67
67
  it 'should complain if command returns nil' do
68
68
  expect(@mock_ssh).to receive(:exec).and_return(nil)
69
69
 
70
70
  output = capture(:stderr) do
71
- lambda { instance.remote_exec('remote exec fail') }.should exit_with_code(1)
71
+ expect(lambda { instance.remote_exec('remote exec fail') }).to exit_with_code(1)
72
72
  end
73
73
 
74
- output.should include('unable', 'execute', 'remote', 'command')
74
+ expect(output).to include('unable', 'execute', 'remote', 'command')
75
75
  end
76
76
  end
77
77
 
78
78
  describe '#parse' do
79
+ before(:each) do
80
+ Harrison.send(:remove_const, "DEBUG") if Harrison.const_defined?("DEBUG")
81
+ end
82
+
83
+ after(:each) do
84
+ Harrison.send(:remove_const, "DEBUG") if Harrison.const_defined?("DEBUG")
85
+ end
86
+
79
87
  it 'should recognize options from the command line' do
80
88
  instance = Harrison::Base.new([
81
89
  [ :testopt, "Test option.", :type => :string ]
@@ -83,13 +91,13 @@ describe Harrison::Base do
83
91
 
84
92
  instance.parse(%w(test --testopt foozle))
85
93
 
86
- instance.options.should include({testopt: 'foozle'})
94
+ expect(instance.options).to include({testopt: 'foozle'})
87
95
  end
88
96
 
89
97
  it 'should set the debug flag on the module when passed --debug' do
90
98
  instance.parse(%w(test --debug))
91
99
 
92
- Harrison::DEBUG.should be_true
100
+ expect(Harrison::DEBUG).to be true
93
101
  end
94
102
  end
95
103
 
@@ -99,20 +107,20 @@ describe Harrison::Base do
99
107
  test_block = Proc.new { |test| "block_output" }
100
108
  instance.run(&test_block)
101
109
 
102
- instance.instance_variable_get("@run_block").should == test_block
110
+ expect(instance.instance_variable_get("@run_block")).to eq(test_block)
103
111
  end
104
112
  end
105
113
 
106
114
  context 'when not given a block' do
107
115
  it 'should return nil if no block stored' do
108
- instance.run.should == nil
116
+ expect(instance.run).to be_nil
109
117
  end
110
118
 
111
119
  it 'should invoke the previously stored block if it exists' do
112
120
  test_block = Proc.new { |test| "block_output" }
113
121
  instance.run(&test_block)
114
122
 
115
- instance.run.should == "block_output"
123
+ expect(instance.run).to eq("block_output")
116
124
  end
117
125
  end
118
126
  end
@@ -124,9 +132,9 @@ describe Harrison::Base do
124
132
  end
125
133
 
126
134
  it 'should delegate downloads to the SSH class' do
127
- expect(@mock_ssh).to receive(:download).with('remote', 'local').and_return(true)
135
+ expect(@mock_ssh).to receive(:download).with('remote', 'local')
128
136
 
129
- instance.download('remote', 'local').should == true
137
+ instance.download('remote', 'local')
130
138
  end
131
139
  end
132
140
 
@@ -137,9 +145,9 @@ describe Harrison::Base do
137
145
  end
138
146
 
139
147
  it 'should delegate uploads to the SSH class' do
140
- expect(@mock_ssh).to receive(:upload).with('local', 'remote').and_return(true)
148
+ expect(@mock_ssh).to receive(:upload).with('local', 'remote')
141
149
 
142
- instance.upload('local', 'remote').should == true
150
+ instance.upload('local', 'remote')
143
151
  end
144
152
  end
145
153
 
@@ -151,9 +159,9 @@ describe Harrison::Base do
151
159
  end
152
160
 
153
161
  it 'should invoke close on ssh instance' do
154
- expect(@mock_ssh).to receive(:close).and_return(true)
162
+ expect(@mock_ssh).to receive(:close)
155
163
 
156
- instance.close.should == true
164
+ instance.close
157
165
  end
158
166
  end
159
167
  end
@@ -164,7 +172,7 @@ describe Harrison::Base do
164
172
  mock_ssh = double(:ssh)
165
173
  expect(Harrison::SSH).to receive(:new).and_return(mock_ssh)
166
174
 
167
- instance.send(:ssh).should == mock_ssh
175
+ expect(instance.send(:ssh)).to be mock_ssh
168
176
  end
169
177
 
170
178
  it 'should return previously instantiated ssh instance' do
@@ -172,7 +180,21 @@ describe Harrison::Base do
172
180
  instance.instance_variable_set('@ssh', mock_ssh)
173
181
  expect(Harrison::SSH).to_not receive(:new)
174
182
 
175
- instance.send(:ssh).should == mock_ssh
183
+ expect(instance.send(:ssh)).to be mock_ssh
184
+ end
185
+ end
186
+
187
+ describe '#remote_regex' do
188
+ it 'should match a standard remote SCP target without a username' do
189
+ expect(instance.send(:remote_regex)).to match("test_host1:/tmp/target")
190
+ end
191
+
192
+ it 'should match a standard remote SCP target with a username' do
193
+ expect(instance.send(:remote_regex)).to match("testuser@test_host:/tmp/target")
194
+ end
195
+
196
+ it 'should not match a local file path' do
197
+ expect(instance.send(:remote_regex)).not_to match("tmp/target")
176
198
  end
177
199
  end
178
200
 
@@ -180,41 +202,43 @@ describe Harrison::Base do
180
202
  it 'should try to create a directory locally' do
181
203
  expect(instance).to receive(:system).with(/local_dir/).and_return(true)
182
204
 
183
- instance.send(:ensure_local_dir, 'local_dir').should == true
205
+ expect(instance.send(:ensure_local_dir, 'local_dir')).to be true
184
206
  end
185
207
 
186
208
  it 'should only try to create a directory once' do
187
209
  expect(instance).to receive(:system).with(/local_dir/).once.and_return(true)
188
210
 
189
- instance.send(:ensure_local_dir, 'local_dir').should == true
190
- instance.send(:ensure_local_dir, 'local_dir').should == true
211
+ expect(instance.send(:ensure_local_dir, 'local_dir')).to be true
212
+ expect(instance.send(:ensure_local_dir, 'local_dir')).to be true
191
213
  end
192
214
  end
193
215
 
194
216
  describe '#ensure_remote_dir' do
195
217
  before(:each) do
196
- @mock_ssh = double(:ssh)
218
+ @mock_ssh = double(:ssh, host: 'test_host1')
219
+ @mock_ssh2 = double(:ssh, host: 'test_host2')
220
+
197
221
  allow(instance).to receive(:ssh).and_return(@mock_ssh)
198
222
  end
199
223
 
200
224
  it 'should try to create a directory remotely' do
201
225
  expect(@mock_ssh).to receive(:exec).with(/remote_dir/).and_return(true)
202
-
203
- instance.send(:ensure_remote_dir, 'testhost', 'remote_dir').should == true
226
+ expect(instance.send(:ensure_remote_dir, 'remote_dir')).to be true
204
227
  end
205
228
 
206
- it 'should try to create a directory once for each distinct host' do
207
- expect(@mock_ssh).to receive(:exec).with(/remote_dir/).twice.and_return(true)
229
+ it 'should try to create a directory once for each distinct ssh connection' do
230
+ expect(@mock_ssh).to receive(:exec).with(/remote_dir/).once.and_return(true)
231
+ expect(@mock_ssh2).to receive(:exec).with(/remote_dir/).once.and_return(true)
208
232
 
209
- instance.send(:ensure_remote_dir, 'test-host', 'remote_dir').should == true
210
- instance.send(:ensure_remote_dir, 'another-host', 'remote_dir').should == true
233
+ expect(instance.send(:ensure_remote_dir, 'remote_dir')).to be true
234
+ expect(instance.send(:ensure_remote_dir, 'remote_dir', @mock_ssh2)).to be true
211
235
  end
212
236
 
213
- it 'should only try to create a directory once for the same host' do
237
+ it 'should only try to create a directory once for the same ssh connection' do
214
238
  expect(@mock_ssh).to receive(:exec).with(/remote_dir/).once.and_return(true)
215
239
 
216
- instance.send(:ensure_remote_dir, 'test-host', 'remote_dir').should == true
217
- instance.send(:ensure_remote_dir, 'test-host', 'remote_dir').should == true
240
+ expect(instance.send(:ensure_remote_dir, 'remote_dir')).to be true
241
+ expect(instance.send(:ensure_remote_dir, 'remote_dir')).to be true
218
242
  end
219
243
  end
220
244
  end
@@ -10,17 +10,17 @@ describe Harrison::Deploy do
10
10
 
11
11
  describe '.initialize' do
12
12
  it 'should add --hosts to arg_opts' do
13
- instance.instance_variable_get('@arg_opts').to_s.should include(':hosts')
13
+ expect(instance.instance_variable_get('@arg_opts').to_s).to include(':hosts')
14
14
  end
15
15
 
16
16
  it 'should add --env to arg_opts' do
17
- instance.instance_variable_get('@arg_opts').to_s.should include(':env')
17
+ expect(instance.instance_variable_get('@arg_opts').to_s).to include(':env')
18
18
  end
19
19
 
20
20
  it 'should persist options' do
21
21
  instance = Harrison::Deploy.new(testopt: 'foo')
22
22
 
23
- instance.instance_variable_get('@options').should include(testopt: 'foo')
23
+ expect(instance.instance_variable_get('@options')).to include(testopt: 'foo')
24
24
  end
25
25
  end
26
26
 
@@ -28,16 +28,16 @@ describe Harrison::Deploy do
28
28
  describe '#parse' do
29
29
  it 'should require an artifact to be passed in ARGV' do
30
30
  output = capture(:stderr) do
31
- lambda { instance.parse(%w(deploy)) }.should exit_with_code(1)
31
+ expect(lambda { instance.parse(%w(deploy)) }).to exit_with_code(1)
32
32
  end
33
33
 
34
- output.should include('must', 'specify', 'artifact')
34
+ expect(output).to include('must', 'specify', 'artifact')
35
35
  end
36
36
 
37
37
  it 'should use "base_dir" from Harrisonfile if present' do
38
38
  instance.parse(%w(deploy test_artifact.tar.gz))
39
39
 
40
- instance.options.should include({ base_dir: '/hf_basedir' })
40
+ expect(instance.options).to include({ base_dir: '/hf_basedir' })
41
41
  end
42
42
  end
43
43
 
@@ -68,13 +68,13 @@ describe Harrison::Deploy do
68
68
  test_block = Proc.new { |test| "block_output" }
69
69
  instance.run(&test_block)
70
70
 
71
- instance.instance_variable_get("@run_block").should == test_block
71
+ expect(instance.instance_variable_get("@run_block")).to be test_block
72
72
  end
73
73
  end
74
74
 
75
75
  context 'when not passed a block' do
76
76
  before(:each) do
77
- @mock_ssh = double(:ssh, exec: '', upload: true, download: true)
77
+ @mock_ssh = double(:ssh, host: 'test_host1', exec: '', upload: true, download: true)
78
78
  allow(instance).to receive(:ssh).and_return(@mock_ssh)
79
79
 
80
80
  instance.instance_variable_set(:@run_block, Proc.new { |h| "block for #{h.host}" })
@@ -87,9 +87,9 @@ describe Harrison::Deploy do
87
87
  instance.run
88
88
  end
89
89
 
90
- instance.hosts.should == [ 'argv_host1', 'argv_host2' ]
91
- output.should include('argv_host1', 'argv_host2')
92
- output.should_not include('hf_host')
90
+ expect(instance.hosts).to eq([ 'argv_host1', 'argv_host2' ])
91
+ expect(output).to include('argv_host1', 'argv_host2')
92
+ expect(output).to_not include('hf_host')
93
93
  end
94
94
 
95
95
  it 'should use hosts from Harrisonfile if --hosts not passed' do
@@ -97,18 +97,18 @@ describe Harrison::Deploy do
97
97
  instance.run
98
98
  end
99
99
 
100
- instance.hosts.should == [ 'hf_host' ]
101
- output.should include('hf_host')
100
+ expect(instance.hosts).to eq([ 'hf_host' ])
101
+ expect(output).to include('hf_host')
102
102
  end
103
103
 
104
104
  it 'should require hosts to be set somehow' do
105
105
  instance.hosts = nil
106
106
 
107
107
  output = capture(:stderr) do
108
- lambda { instance.run }.should exit_with_code(1)
108
+ expect(lambda { instance.run }).to exit_with_code(1)
109
109
  end
110
110
 
111
- output.should include('must', 'specify', 'hosts')
111
+ expect(output).to include('must', 'specify', 'hosts')
112
112
  end
113
113
 
114
114
  it 'should invoke the previously stored block once for each host' do
@@ -118,7 +118,34 @@ describe Harrison::Deploy do
118
118
  expect { |b| instance.run(&b); instance.run }.to yield_control.exactly(3).times
119
119
  end
120
120
 
121
- output.should include('host1', 'host2', 'host3')
121
+ expect(output).to include('host1', 'host2', 'host3')
122
+ end
123
+
124
+ context 'when deploying from a remote artifact source' do
125
+ before(:each) do
126
+ instance.artifact = 'test_user@test_host1:/tmp/test_artifact.tar.gz'
127
+ end
128
+
129
+ it 'should invoke scp on the remote host' do
130
+ allow(instance).to receive(:remote_exec).and_return('')
131
+ expect(instance).to receive(:remote_exec).with(/scp test_user@test_host1:\/tmp\/test_artifact.tar.gz/).and_return('')
132
+
133
+ output = capture(:stdout) do
134
+ instance.run
135
+ end
136
+
137
+ expect(output).to include('deployed', 'test_user', 'test_host1', '/tmp/test_artifact.tar.gz')
138
+ end
139
+
140
+ it 'should not invoke Harrison::SSH.upload' do
141
+ expect(@mock_ssh).not_to receive(:upload)
142
+
143
+ output = capture(:stdout) do
144
+ instance.run
145
+ end
146
+
147
+ expect(output).to include('deployed', 'test_user', 'test_host1', '/tmp/test_artifact.tar.gz')
148
+ end
122
149
  end
123
150
  end
124
151
  end
@@ -156,7 +183,7 @@ describe Harrison::Deploy do
156
183
 
157
184
  instance.host = 'test_host'
158
185
 
159
- instance.send(:ssh).should == mock_ssh
186
+ expect(instance.send(:ssh)).to be mock_ssh
160
187
  end
161
188
 
162
189
  it 'should reuse an existing connection to self.host' do
@@ -165,7 +192,7 @@ describe Harrison::Deploy do
165
192
 
166
193
  instance.host = :test_host2
167
194
 
168
- instance.send(:ssh).should == mock_ssh
195
+ expect(instance.send(:ssh)).to be mock_ssh
169
196
  end
170
197
  end
171
198
 
@@ -174,7 +201,7 @@ describe Harrison::Deploy do
174
201
  instance.base_dir = '/test_base_dir'
175
202
  instance.project = 'test_project'
176
203
 
177
- instance.send(:remote_project_dir).should include('/test_base_dir', 'test_project')
204
+ expect(instance.send(:remote_project_dir)).to include('/test_base_dir', 'test_project')
178
205
  end
179
206
  end
180
207
  end
@@ -11,25 +11,25 @@ describe Harrison::Package do
11
11
 
12
12
  describe '.initialize' do
13
13
  it 'should add --commit to arg_opts' do
14
- instance.instance_variable_get('@arg_opts').to_s.should include(':commit')
14
+ expect(instance.instance_variable_get('@arg_opts').to_s).to include(':commit')
15
15
  end
16
16
 
17
17
  it 'should add --purge to arg_opts' do
18
- instance.instance_variable_get('@arg_opts').to_s.should include(':purge')
18
+ expect(instance.instance_variable_get('@arg_opts').to_s).to include(':purge')
19
19
  end
20
20
 
21
- it 'should add --pkg-dir to arg_opts' do
22
- instance.instance_variable_get('@arg_opts').to_s.should include(':pkg_dir')
21
+ it 'should add --destination to arg_opts' do
22
+ expect(instance.instance_variable_get('@arg_opts').to_s).to include(':destination')
23
23
  end
24
24
 
25
25
  it 'should add --remote-dir to arg_opts' do
26
- instance.instance_variable_get('@arg_opts').to_s.should include(':remote_dir')
26
+ expect(instance.instance_variable_get('@arg_opts').to_s).to include(':remote_dir')
27
27
  end
28
28
 
29
29
  it 'should persist options' do
30
30
  instance = Harrison::Package.new(testopt: 'foo')
31
31
 
32
- instance.instance_variable_get('@options').should include(testopt: 'foo')
32
+ expect(instance.instance_variable_get('@options')).to include(testopt: 'foo')
33
33
  end
34
34
  end
35
35
 
@@ -57,16 +57,16 @@ describe Harrison::Package do
57
57
  test_block = Proc.new { |test| "block_output" }
58
58
  instance.run(&test_block)
59
59
 
60
- instance.instance_variable_get("@run_block").should == test_block
60
+ expect(instance.instance_variable_get("@run_block")).to be test_block
61
61
  end
62
62
  end
63
63
 
64
64
  context 'when not passed a block' do
65
65
  before(:each) do
66
- @mock_ssh = double(:ssh, exec: '', upload: true, download: true)
66
+ @mock_ssh = double(:ssh, host: 'test_host1', exec: '', upload: true, download: true)
67
67
  allow(instance).to receive(:ssh).at_least(:once).and_return(@mock_ssh)
68
68
 
69
- allow(instance).to receive(:ensure_local_dir).and_return(true)
69
+ allow(instance).to receive(:ensure_destination).and_return(true)
70
70
  allow(instance).to receive(:resolve_commit!).and_return('test')
71
71
  allow(instance).to receive(:excludes_for_tar).and_return('')
72
72
  end
@@ -79,7 +79,7 @@ describe Harrison::Package do
79
79
  instance.run
80
80
  end
81
81
 
82
- output.should include('block for hf_host')
82
+ expect(output).to include('block for hf_host')
83
83
  end
84
84
  end
85
85
  end
@@ -91,7 +91,7 @@ describe Harrison::Package do
91
91
  instance.remote_dir = '~/.harrison'
92
92
  instance.project = 'test_project'
93
93
 
94
- instance.send(:remote_project_dir).should include('~/.harrison', 'test_project')
94
+ expect(instance.send(:remote_project_dir)).to include('~/.harrison', 'test_project')
95
95
  end
96
96
  end
97
97
 
@@ -100,7 +100,7 @@ describe Harrison::Package do
100
100
  instance.commit = 'giant'
101
101
  expect(instance).to receive(:exec).with(/git rev-parse.*giant/).and_return('fef1f0')
102
102
 
103
- instance.send(:resolve_commit!).should == 'fef1f0'
103
+ expect(instance.send(:resolve_commit!)).to eq('fef1f0')
104
104
  end
105
105
  end
106
106
 
@@ -108,19 +108,35 @@ describe Harrison::Package do
108
108
  it 'should return an empty string if exclude is nil' do
109
109
  instance.exclude = nil
110
110
 
111
- instance.send(:excludes_for_tar).should == ''
111
+ expect(instance.send(:excludes_for_tar)).to be_empty
112
112
  end
113
113
 
114
114
  it 'should return an empty string if exclude is empty' do
115
115
  instance.exclude = []
116
116
 
117
- instance.send(:excludes_for_tar).should == ''
117
+ expect(instance.send(:excludes_for_tar)).to be_empty
118
118
  end
119
119
 
120
120
  it 'should return an --exclude option for each member of exclude' do
121
121
  instance.exclude = [ 'fee', 'fi', 'fo', 'fum' ]
122
122
 
123
- instance.send(:excludes_for_tar).scan(/--exclude/).size.should == instance.exclude.size
123
+ expect(instance.send(:excludes_for_tar).scan(/--exclude/).size).to eq(instance.exclude.size)
124
+ end
125
+ end
126
+
127
+ describe '#ensure_destination' do
128
+ it 'should ensure a local destination' do
129
+ expect(instance).to receive(:ensure_local_dir).with('/tmp/test_path').and_return(true)
130
+
131
+ instance.send(:ensure_destination, '/tmp/test_path')
132
+ end
133
+
134
+ it 'should ensure a remote destination' do
135
+ mock_ssh = double(:ssh, host: 'test_host1')
136
+ expect(mock_ssh).to receive(:exec).with(/\/tmp\/test_path/).and_return(true)
137
+ expect(Harrison::SSH).to receive(:new).with({ host: 'test_host1', user: 'test_user' }).and_return(mock_ssh)
138
+
139
+ instance.send(:ensure_destination, 'test_user@test_host1:/tmp/test_path')
124
140
  end
125
141
  end
126
142
  end
@@ -1,5 +1,245 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Harrison::SSH do
4
- pending
4
+ before(:all) do
5
+ Harrison.send(:remove_const, "DEBUG") if Harrison.const_defined?("DEBUG")
6
+ Harrison.const_set("DEBUG", false)
7
+ end
8
+
9
+ after(:all) do
10
+ Harrison.send(:remove_const, "DEBUG") if Harrison.const_defined?("DEBUG")
11
+ end
12
+
13
+ before(:each) do
14
+ @mock_ssh_chan = double(:ssh_channel)
15
+
16
+ @mock_ssh_conn = double(:ssh_conn, host: 'test.example.com')
17
+ allow(@mock_ssh_conn).to receive(:loop)
18
+ allow(@mock_ssh_conn).to receive(:open_channel).and_yield(@mock_ssh_chan)
19
+
20
+ allow(Net::SSH).to receive(:start).and_return(@mock_ssh_conn)
21
+ end
22
+
23
+ let(:instance) { Harrison::SSH.new(host: 'test.example.com', user: 'test_user') }
24
+
25
+ describe 'initialize' do
26
+ it 'should open an SSH connection' do
27
+ expect(Net::SSH).to receive(:start).with('test.example.com', 'test_user', anything).and_return(double(:ssh_conn))
28
+
29
+ Harrison::SSH.new(host: 'test.example.com', user: 'test_user')
30
+ end
31
+
32
+ context 'when passed a :proxy option' do
33
+ it 'should open an SSH connection with a proxy command' do
34
+ proxy = double(:ssh_proxy)
35
+
36
+ expect(Net::SSH::Proxy::Command).to receive(:new).and_return(proxy)
37
+ expect(Net::SSH).to receive(:start).with('test.example.com', 'test_user', { forward_agent: true, proxy: proxy, timeout: 10 }).and_return(double(:ssh_conn))
38
+
39
+ Harrison::SSH.new(host: 'test.example.com', user: 'test_user', proxy: 'test-proxy.example.com')
40
+ end
41
+ end
42
+ end
43
+
44
+ describe '#exec' do
45
+ it 'should exec the passed command on an SSH connection channel' do
46
+ command = "pwd"
47
+ expect(@mock_ssh_chan).to receive(:exec).with(command)
48
+
49
+ instance.exec(command)
50
+ end
51
+
52
+ context 'when the command exits non-zero' do
53
+ before(:each) do
54
+ allow(instance).to receive(:invoke).with(@mock_ssh_conn, anything).and_return({ status: 1, stdout: 'standard output', stderr: 'standard error' })
55
+ end
56
+
57
+ it 'should warn whatever the command emitted to stdout' do
58
+ output = capture(:stderr) do
59
+ instance.exec('cat noexist 2>/dev/null')
60
+ end
61
+
62
+ expect(output).to include('stdout', 'standard output')
63
+ end
64
+
65
+ it 'should warn whatever the command emitted to stderr' do
66
+ output = capture(:stderr) do
67
+ instance.exec('cat noexist 2>/dev/null')
68
+ end
69
+
70
+ expect(output).to include('stderr', 'standard error')
71
+ end
72
+
73
+ it 'should return nil' do
74
+ capture(:stderr) do
75
+ expect(instance.exec('cat noexist 2>/dev/null')).to be_nil
76
+ end
77
+ end
78
+ end
79
+
80
+ context 'when --debug is set' do
81
+ before(:each) do
82
+ allow(instance).to receive(:invoke).with(@mock_ssh_conn, anything).and_return({ status: 0, stdout: 'standard output', stderr: 'standard error' })
83
+ end
84
+
85
+ before(:each) do
86
+ Harrison.send(:remove_const, "DEBUG") if Harrison.const_defined?("DEBUG")
87
+ Harrison.const_set("DEBUG", true)
88
+ end
89
+
90
+ after(:each) do
91
+ Harrison.send(:remove_const, "DEBUG") if Harrison.const_defined?("DEBUG")
92
+ Harrison.const_set("DEBUG", false)
93
+ end
94
+
95
+ it 'should output the command being run' do
96
+ output = capture(:stdout) do
97
+ capture(:stderr) do
98
+ instance.exec('touch testfile')
99
+ end
100
+ end
101
+
102
+ expect(output).to include('info', 'touch testfile')
103
+ end
104
+
105
+ it 'should warn whatever the command emitted to stdout' do
106
+ output = capture(:stderr) do
107
+ capture(:stdout) do
108
+ instance.exec('touch testfile')
109
+ end
110
+ end
111
+
112
+ expect(output).to include('stdout', 'standard output')
113
+ end
114
+
115
+ it 'should warn whatever the command emitted to stderr' do
116
+ output = capture(:stderr) do
117
+ capture(:stdout) do
118
+ instance.exec('touch testfile')
119
+ end
120
+ end
121
+
122
+ expect(output).to include('stderr', 'standard error')
123
+ end
124
+ end
125
+ end
126
+
127
+ describe '#download' do
128
+ before(:each) do
129
+ @mock_scp = double(:net_scp)
130
+ allow(@mock_ssh_conn).to receive(:scp).and_return(@mock_scp)
131
+ end
132
+
133
+ it 'should delegate to net-scp' do
134
+ expect(@mock_scp).to receive(:download!).with('remote', 'local')
135
+
136
+ instance.download('remote', 'local')
137
+ end
138
+
139
+ context 'when --debug is set' do
140
+ before(:each) do
141
+ Harrison.send(:remove_const, "DEBUG") if Harrison.const_defined?("DEBUG")
142
+ Harrison.const_set("DEBUG", true)
143
+ end
144
+
145
+ after(:each) do
146
+ Harrison.send(:remove_const, "DEBUG") if Harrison.const_defined?("DEBUG")
147
+ Harrison.const_set("DEBUG", false)
148
+ end
149
+
150
+ it 'should output what is being downloaded and to where' do
151
+ expect(@mock_scp).to receive(:download!).with('remote', 'local')
152
+
153
+ output = capture(:stdout) do
154
+ instance.download('remote', 'local')
155
+ end
156
+
157
+ expect(output).to include('scp-down', 'local', 'remote')
158
+ end
159
+ end
160
+ end
161
+
162
+ describe '#upload' do
163
+ before(:each) do
164
+ @mock_scp = double(:net_scp)
165
+ allow(@mock_ssh_conn).to receive(:scp).and_return(@mock_scp)
166
+ end
167
+
168
+ it 'should delegate to net-scp' do
169
+ expect(@mock_scp).to receive(:upload!).with('local', 'remote')
170
+
171
+ instance.upload('local', 'remote')
172
+ end
173
+
174
+ context 'when --debug is set' do
175
+ before(:each) do
176
+ Harrison.send(:remove_const, "DEBUG") if Harrison.const_defined?("DEBUG")
177
+ Harrison.const_set("DEBUG", true)
178
+ end
179
+
180
+ after(:each) do
181
+ Harrison.send(:remove_const, "DEBUG") if Harrison.const_defined?("DEBUG")
182
+ Harrison.const_set("DEBUG", false)
183
+ end
184
+
185
+ it 'should output what is being uploaded and to where' do
186
+ expect(@mock_scp).to receive(:upload!).with('local', 'remote')
187
+
188
+ output = capture(:stdout) do
189
+ instance.upload('local', 'remote')
190
+ end
191
+
192
+ expect(output).to include('scp-up', 'local', 'remote')
193
+ end
194
+ end
195
+ end
196
+
197
+ describe '#close' do
198
+ it 'should delegate to net-ssh' do
199
+ expect(@mock_ssh_conn).to receive(:close)
200
+
201
+ instance.close
202
+ end
203
+
204
+ context 'when using a proxy command' do
205
+ before(:each) do
206
+ @proxy = double(:ssh_proxy)
207
+ instance.instance_variable_set(:@proxy, @proxy)
208
+ end
209
+
210
+ it 'should send TERM to the proxy command' do
211
+ allow(@mock_ssh_conn).to receive(:transport).and_return(double(:transport, socket: double(:socket, pid: 100000)))
212
+
213
+ expect(Process).to receive(:kill).with("TERM", 100000)
214
+ expect(@mock_ssh_conn).to receive(:close)
215
+
216
+ instance.close
217
+ end
218
+ end
219
+ end
220
+
221
+ describe '#closed?' do
222
+ it 'should delegate to net-ssh' do
223
+ expect(@mock_ssh_conn).to receive(:closed?)
224
+
225
+ instance.closed?
226
+ end
227
+ end
228
+
229
+ describe '#desc' do
230
+ it 'should include the host connected to' do
231
+ expect(instance.desc).to include('test.example.com')
232
+ end
233
+
234
+ context 'when using a proxy host' do
235
+ before(:each) do
236
+ @proxy = double(:ssh_proxy, command_line: "ssh proxy.example.com arg1 arg2")
237
+ instance.instance_variable_set(:@proxy, @proxy)
238
+ end
239
+
240
+ it 'should include the proxy host' do
241
+ expect(instance.desc).to include('proxy.example.com')
242
+ end
243
+ end
244
+ end
5
245
  end
@@ -16,38 +16,38 @@ describe Harrison do
16
16
  describe '.invoke' do
17
17
  it 'should exit when no args are passed' do
18
18
  output = capture(:stderr) do
19
- lambda { Harrison.invoke([]) }.should exit_with_code(1)
19
+ expect(lambda { Harrison.invoke([]) }).to exit_with_code(1)
20
20
  end
21
21
 
22
- output.should include('no', 'command', 'given')
22
+ expect(output).to include('no', 'command', 'given')
23
23
  end
24
24
 
25
25
  it 'should output base help when first arg is --help' do
26
26
  output = capture(:stdout) do
27
- lambda { Harrison.invoke(['--help']) }.should exit_with_code(0)
27
+ expect(lambda { Harrison.invoke(['--help']) }).to exit_with_code(0)
28
28
  end
29
29
 
30
- output.should include('options', 'debug', 'help')
30
+ expect(output).to include('options', 'debug', 'help')
31
31
  end
32
32
 
33
33
  it 'should look for a Harrisonfile' do
34
34
  expect(Harrison).to receive(:find_harrisonfile).and_return(harrisonfile_fixture_path)
35
35
 
36
36
  output = capture(:stderr) do
37
- lambda { Harrison.invoke(['test']) }.should exit_with_code(1)
37
+ expect(lambda { Harrison.invoke(['test']) }).to exit_with_code(1)
38
38
  end
39
39
 
40
- output.should include('unrecognized', 'command', 'test')
40
+ expect(output).to include('unrecognized', 'command', 'test')
41
41
  end
42
42
 
43
43
  it 'should complain if unable to find a Harrisonfile' do
44
44
  expect(Harrison).to receive(:find_harrisonfile).and_return(nil)
45
45
 
46
46
  output = capture(:stderr) do
47
- lambda { Harrison.invoke(['test']) }.should exit_with_code(1)
47
+ expect(lambda { Harrison.invoke(['test']) }).to exit_with_code(1)
48
48
  end
49
49
 
50
- output.should include('could', 'not', 'find', 'harrisonfile')
50
+ expect(output).to include('could', 'not', 'find', 'harrisonfile')
51
51
  end
52
52
  end
53
53
 
@@ -56,7 +56,7 @@ describe Harrison do
56
56
  mock_config = double(:config)
57
57
  expect(Harrison::Config).to receive(:new).and_return(mock_config)
58
58
 
59
- Harrison.config.should == mock_config
59
+ expect(Harrison.config).to be mock_config
60
60
  end
61
61
 
62
62
  it 'should return existing Harrison::Config if defined' do
@@ -64,7 +64,7 @@ describe Harrison do
64
64
  Harrison.class_variable_set(:@@config, mock_config)
65
65
  expect(Harrison::Config).to_not receive(:new)
66
66
 
67
- Harrison.config.should == mock_config
67
+ expect(Harrison.config).to be mock_config
68
68
  end
69
69
 
70
70
  it 'should yield config if given a block' do
@@ -124,13 +124,13 @@ describe Harrison do
124
124
  it 'should find a Harrisonfile if it exists in pwd' do
125
125
  expect(Dir).to receive(:pwd).and_return(fixture_path)
126
126
 
127
- Harrison.send(:find_harrisonfile).should == harrisonfile_fixture_path
127
+ expect(Harrison.send(:find_harrisonfile)).to eq(harrisonfile_fixture_path)
128
128
  end
129
129
 
130
130
  it 'should find a Harrisonfile if it exists in parent of pwd' do
131
131
  expect(Dir).to receive(:pwd).and_return(fixture_path + '/nested')
132
132
 
133
- Harrison.send(:find_harrisonfile).should == harrisonfile_fixture_path
133
+ expect(Harrison.send(:find_harrisonfile)).to eq(harrisonfile_fixture_path)
134
134
  end
135
135
 
136
136
  it 'should return nil if there is no Harrisonfile in tree' do
@@ -140,7 +140,7 @@ describe Harrison do
140
140
  allow(File).to receive(:expand_path).and_call_original
141
141
  allow(File).to receive(:expand_path).with("..", File.dirname(__FILE__)).and_return(File.dirname(__FILE__))
142
142
 
143
- Harrison.send(:find_harrisonfile).should be_nil
143
+ expect(Harrison.send(:find_harrisonfile)).to be_nil
144
144
  end
145
145
  end
146
146
 
@@ -150,7 +150,7 @@ describe Harrison do
150
150
  Harrison.send(:eval_script, fixture_path + '/eval_script.rb')
151
151
  end
152
152
 
153
- output.should == "this file was eval-led\n"
153
+ expect(output).to eq("this file was eval-led\n")
154
154
  end
155
155
  end
156
156
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: harrison
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-07-21 00:00:00.000000000 Z
12
+ date: 2014-08-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: trollop
@@ -96,17 +96,17 @@ dependencies:
96
96
  requirement: !ruby/object:Gem::Requirement
97
97
  none: false
98
98
  requirements:
99
- - - ! '>='
99
+ - - ~>
100
100
  - !ruby/object:Gem::Version
101
- version: '0'
101
+ version: '3.0'
102
102
  type: :development
103
103
  prerelease: false
104
104
  version_requirements: !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
- - - ! '>='
107
+ - - ~>
108
108
  - !ruby/object:Gem::Version
109
- version: '0'
109
+ version: '3.0'
110
110
  - !ruby/object:Gem::Dependency
111
111
  name: debugger
112
112
  requirement: !ruby/object:Gem::Requirement
@@ -149,11 +149,13 @@ extra_rdoc_files: []
149
149
  files:
150
150
  - .gitignore
151
151
  - .rspec
152
+ - .travis.yml
153
+ - CHANGELOG
152
154
  - Gemfile
155
+ - IDEAS
153
156
  - LICENSE.txt
154
157
  - README.md
155
158
  - Rakefile
156
- - TODO
157
159
  - bin/harrison
158
160
  - harrison.gemspec
159
161
  - lib/harrison.rb
@@ -193,7 +195,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
193
195
  version: '0'
194
196
  segments:
195
197
  - 0
196
- hash: 1981909616735500300
198
+ hash: -1749031995180641465
197
199
  requirements: []
198
200
  rubyforge_project:
199
201
  rubygems_version: 1.8.29
data/TODO DELETED
@@ -1,26 +0,0 @@
1
- Bugs:
2
- -----
3
- [ ] Test that artifact exists before doing anything for deploy task.
4
-
5
- In Progress:
6
- ------------
7
- [ ] Unit Testing
8
-
9
- Definitely:
10
- -----------
11
- [ ] Rollback action.
12
- [ ] Error handling (with automatic rollback/undo)
13
- [ ] Further de-compose actions so that specific parts can be easily overridden.
14
- [ ] When deploying via a proxy, cache artifact on proxy before deploying to hosts.
15
- [ ] Banner text in --help output.
16
- [ ] Improve unit testing, try to minimize coupling to implementation details.
17
- [ ] Include branch name in artifact file name.
18
-
19
- Maybe:
20
- ------
21
- [ ] Allow more elaborate hosts config, e.g.: h.hosts = [ { host: '10.16.18.207', tags: %w(util migrate) } ]
22
- [ ] Some kind of --dry-run option.
23
- [ ] Allow deploy_via to include alternate user/connection options.
24
- [ ] Rename "releases" => "builds" (and "deploys" => "releases"?)
25
- [ ] Upload artifact to all hosts before the rest of the deployment process begins.
26
- [ ] --force option for deploy task to overwrite an existing release