aptible-cli 0.7.1 → 0.7.2

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: cf860a7c589c2689289068a00ea10b4a2bb8cd10
4
- data.tar.gz: 30a8504c9fdeddd33c67a23e775e08eae455cae9
3
+ metadata.gz: 9eee8bccf78fd7a0814d5fb48e92c9c31aaef356
4
+ data.tar.gz: 80d7cf361bba1d14c1c50ab1f832de3c46533e72
5
5
  SHA512:
6
- metadata.gz: 709bfbf15f9a1988a3bdbd7d6c04d88a7ac748c0f15d4550afdcdf80bdd11536cd1735ed7437c8188d3272e9890a265880b010f546367135d85bb1d956df6a81
7
- data.tar.gz: 96ac24c260b42100c57639dcd8ee10e57ccbef49dcbf070ce3509f255b98835df0c2a10d9a99cbfe729c7a195adfac21b6070d622017f8cc55a5f40bf0980718
6
+ metadata.gz: 6c51adcf6c82f63b5129674a82070235d6ab079c7ed91fc8b02771ba81f8e243a459d39cf80135687797a6576320942a7ec767a5bec78bfc5155bfacdfca5caf
7
+ data.tar.gz: 2c5ccc49276560307c75d5dff6b6504d87b6f77a4bf9b820910c37900b65059e341ef2676e888870ffca0dbc9ae503ad82d328be7d93f16866b45605330cf78a
@@ -28,6 +28,9 @@ PerceivedComplexity:
28
28
  AbcSize:
29
29
  Enabled: false
30
30
 
31
+ SignalException:
32
+ Enabled: false
33
+
31
34
  AllCops:
32
35
  Include:
33
36
  - !ruby/regexp /\.rb$/
@@ -1,3 +1,7 @@
1
+ sudo: false
2
+
1
3
  rvm:
2
4
  - 2.0.0
5
+ - 2.1.0
6
+ - 2.2.0
3
7
  - 2.3.0
data/Gemfile CHANGED
@@ -1,6 +1,7 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gem 'pry', github: 'fancyremarker/pry', branch: 'aptible'
4
+ gem 'activesupport', '~> 4.0'
4
5
 
5
6
  group :test do
6
7
  gem 'webmock'
data/README.md CHANGED
@@ -10,13 +10,17 @@ Command-line interface for Aptible services.
10
10
 
11
11
  ## Installation
12
12
 
13
+ **NOTE: To install the `aptible` tool as a system-level binary, Aptible
14
+ recommends you install the
15
+ [Aptible Toolbelt](https://support.aptible.com/toolbelt/)**, which is faster
16
+ and more robust.
17
+
13
18
  Add the following line to your application's Gemfile.
14
19
 
15
20
  gem 'aptible-cli'
16
21
 
17
22
  And then run `bundle install`.
18
23
 
19
- *NOTE: To install the `aptible` tool as a system-level binary, consider using the [aptible-toolbelt gem](https://github.com/aptible/aptible-toolbelt), which is performance-optimized through dependency pinning.*
20
24
 
21
25
  ## Usage
22
26
 
@@ -3,12 +3,12 @@ require 'thor'
3
3
  require 'json'
4
4
  require 'chronic_duration'
5
5
 
6
+ require_relative 'helpers/ssh'
6
7
  require_relative 'helpers/token'
7
8
  require_relative 'helpers/operation'
8
9
  require_relative 'helpers/environment'
9
10
  require_relative 'helpers/app'
10
11
  require_relative 'helpers/database'
11
- require_relative 'helpers/env'
12
12
  require_relative 'helpers/tunnel'
13
13
 
14
14
  require_relative 'subcommands/apps'
@@ -1,5 +1,9 @@
1
1
  require 'aptible/api'
2
- require 'git'
2
+
3
+ # Avoid requiring the git gem upfront, since it'll fail to load if git isn't
4
+ # available, whereas we're able to gracefully handle that by requiring the
5
+ # --app and / or --environment flags.
6
+ autoload :Git, 'git'
3
7
 
4
8
  module Aptible
5
9
  module CLI
@@ -6,6 +6,7 @@ module Aptible
6
6
  module Database
7
7
  include Helpers::Token
8
8
  include Helpers::Environment
9
+ include Helpers::Ssh
9
10
 
10
11
  def ensure_database(options = {})
11
12
  db_handle = options[:db]
@@ -54,16 +55,12 @@ module Aptible
54
55
  # Creates a local tunnel and yields the helper
55
56
 
56
57
  def with_local_tunnel(database, port = 0)
57
- env = {
58
- 'ACCESS_TOKEN' => fetch_token,
59
- 'APTIBLE_DATABASE' => database.href
60
- }
61
- command = ['ssh', '-q'] + ssh_args(database)
62
- Helpers::Tunnel.new(env, command).tap do |tunnel_helper|
63
- tunnel_helper.start(port)
64
- yield tunnel_helper
65
- tunnel_helper.stop
66
- end
58
+ tunnel_helper = Helpers::Tunnel.new(ssh_env(database),
59
+ ssh_args(database))
60
+
61
+ tunnel_helper.start(port)
62
+ yield tunnel_helper if block_given?
63
+ tunnel_helper.stop
67
64
  end
68
65
 
69
66
  # Creates a local PG tunnel and yields the url to it
@@ -88,15 +85,18 @@ module Aptible
88
85
  "127.0.0.1:#{local_port}#{uri.path}"
89
86
  end
90
87
 
88
+ def ssh_env(database)
89
+ {
90
+ 'ACCESS_TOKEN' => fetch_token,
91
+ 'APTIBLE_DATABASE' => database.href
92
+ }
93
+ end
94
+
91
95
  def ssh_args(database)
92
- host = database.account.bastion_host
93
- port = database.account.bastion_port
94
-
95
- ['-o', 'SendEnv=APTIBLE_DATABASE',
96
- '-o', 'SendEnv=ACCESS_TOKEN',
97
- '-o', 'StrictHostKeyChecking=no',
98
- '-o', 'UserKnownHostsFile=/dev/null',
99
- '-p', port.to_s, "root@#{host}"]
96
+ broadwayjoe_ssh_command(database.account) + [
97
+ '-o', 'SendEnv=ACCESS_TOKEN',
98
+ '-o', 'SendEnv=APTIBLE_DATABASE'
99
+ ]
100
100
  end
101
101
  end
102
102
  end
@@ -1,5 +1,4 @@
1
1
  require 'aptible/api'
2
- require 'git'
3
2
 
4
3
  module Aptible
5
4
  module CLI
@@ -4,6 +4,8 @@ module Aptible
4
4
  module CLI
5
5
  module Helpers
6
6
  module Operation
7
+ include Helpers::Ssh
8
+
7
9
  POLL_INTERVAL = 1
8
10
 
9
11
  def poll_for_success(operation)
@@ -21,20 +23,22 @@ module Aptible
21
23
  end
22
24
 
23
25
  def attach_to_operation_logs(operation)
24
- host = operation.resource.account.bastion_host
25
- port = operation.resource.account.dumptruck_port
26
+ ENV['ACCESS_TOKEN'] = fetch_token
27
+ ENV['APTIBLE_OPERATION'] = operation.id.to_s
28
+ ENV['APTIBLE_CLI_COMMAND'] = 'oplog'
29
+
30
+ cmd = dumptruck_ssh_command(operation.resource.account) + [
31
+ '-o', 'SendEnv=ACCESS_TOKEN',
32
+ '-o', 'SendEnv=APTIBLE_OPERATION',
33
+ '-o', 'SendEnv=APTIBLE_CLI_COMMAND'
34
+ ]
26
35
 
27
- set_env('ACCESS_TOKEN', fetch_token)
28
- set_env('APTIBLE_OPERATION', operation.id.to_s)
29
- set_env('APTIBLE_CLI_COMMAND', 'oplog')
36
+ success = Kernel.system(*cmd)
30
37
 
31
- opts = " -o 'SendEnv=*' -o StrictHostKeyChecking=no " \
32
- '-o UserKnownHostsFile=/dev/null -o LogLevel=quiet'
33
- result = Kernel.system "ssh #{opts} -p #{port} root@#{host}"
34
38
  # If Dumptruck is down, fall back to polling for success. If the
35
39
  # operation failed, poll_for_success will immediately fall through to
36
40
  # the error message.
37
- poll_for_success(operation) unless result
41
+ poll_for_success(operation) unless success
38
42
  end
39
43
  end
40
44
  end
@@ -0,0 +1,33 @@
1
+ module Aptible
2
+ module CLI
3
+ module Helpers
4
+ module Ssh
5
+ def dumptruck_ssh_command(account)
6
+ base_ssh_command(account, :dumptruck_port)
7
+ end
8
+
9
+ def broadwayjoe_ssh_command(account)
10
+ base_ssh_command(account, :bastion_port)
11
+ end
12
+
13
+ private
14
+
15
+ def base_ssh_command(account, port_method)
16
+ log_level = ENV['APTIBLE_SSH_VERBOSE'] ? 'VERBOSE' : 'ERROR'
17
+
18
+ [
19
+ 'ssh',
20
+ "root@#{account.bastion_host}",
21
+ '-p', account.public_send(port_method).to_s,
22
+ '-o', 'StrictHostKeyChecking=no',
23
+ '-o', 'UserKnownHostsFile=/dev/null',
24
+ '-o', 'TCPKeepAlive=yes',
25
+ '-o', 'KeepAlive=yes',
26
+ '-o', 'ServerAliveInterval=60',
27
+ '-o', "LogLevel=#{log_level}"
28
+ ]
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -4,7 +4,7 @@ module Aptible
4
4
  module CLI
5
5
  module Helpers
6
6
  module Token
7
- TOKEN_ENV_VAR = 'APTIBLE_ACCESS_TOKEN'
7
+ TOKEN_ENV_VAR = 'APTIBLE_ACCESS_TOKEN'.freeze
8
8
 
9
9
  def fetch_token
10
10
  @token ||= ENV[TOKEN_ENV_VAR] ||
@@ -5,44 +5,54 @@ module Aptible
5
5
  module CLI
6
6
  module Helpers
7
7
  class Tunnel
8
- def initialize(env, cmd)
8
+ def initialize(env, ssh_cmd)
9
9
  @env = env
10
- @cmd = cmd
10
+ @ssh_cmd = ssh_cmd
11
11
  end
12
12
 
13
- def start(desired_port = 0, err_fd = $stderr)
13
+ def start(desired_port = 0)
14
14
  @local_port = desired_port
15
- @local_port = random_local_port if @local_port == 0
15
+ @local_port = random_local_port if @local_port.zero?
16
16
 
17
17
  # First, grab a remote port
18
- out, err, status = Open3.capture3(@env, *@cmd)
18
+ out, err, status = Open3.capture3(@env, *@ssh_cmd)
19
19
  fail "Failed to request remote port: #{err}" unless status.success?
20
20
  remote_port = out.chomp
21
21
 
22
- # Then, spin up a SSH session using that port and port forwarding
22
+ # Then, spin up a SSH session using that port and port forwarding.
23
+ # Pass ExitOnForwardFailure to ensure nothing else can be listening
24
+ # on this port (thanks to Diego Argueta for reporting this issue).
23
25
  tunnel_env = @env.merge(
24
26
  'TUNNEL_PORT' => remote_port, # Request a specific port
25
27
  'TUNNEL_SIGNAL_OPEN' => '1' # Request signal when tunnel is up
26
28
  )
27
29
 
28
- tunnel_cmd = @cmd + [
30
+ # TODO: Dynamically compose SendEnv from tunnel_env
31
+ tunnel_cmd = @ssh_cmd + [
29
32
  '-L', "#{@local_port}:localhost:#{remote_port}",
30
33
  '-o', 'SendEnv=TUNNEL_PORT',
31
- '-o', 'SendEnv=TUNNEL_SIGNAL_OPEN'
34
+ '-o', 'SendEnv=TUNNEL_SIGNAL_OPEN',
35
+ '-o', 'ExitOnForwardFailure=yes'
32
36
  ]
33
37
 
34
- r_pipe, w_pipe = IO.pipe
38
+ out_read, out_write = IO.pipe
39
+ err_read, err_write = IO.pipe
35
40
  @pid = Process.spawn(tunnel_env, *tunnel_cmd, in: :close,
36
- out: w_pipe,
37
- err: err_fd)
41
+ out: out_write,
42
+ err: err_write)
38
43
 
39
44
  # Wait for the tunnel to come up before returning. The other end
40
45
  # will send a message on stdout to indicate that the tunnel is ready.
41
- w_pipe.close
46
+ [out_write, err_write].map(&:close)
42
47
  begin
43
- r_pipe.readline
48
+ out_read.readline
44
49
  rescue EOFError
45
- raise 'Server closed the tunnel'
50
+ stop
51
+ e = 'Tunnel did not come up, is something else listening on port ' \
52
+ "#{@local_port}?\n#{err_read.read}"
53
+ raise e
54
+ ensure
55
+ [out_read, err_read].map(&:close)
46
56
  end
47
57
  end
48
58
 
@@ -18,16 +18,17 @@ module Aptible
18
18
  "Have you deployed #{app.handle} yet?"
19
19
  end
20
20
 
21
- host = app.account.bastion_host
22
- port = app.account.dumptruck_port
23
-
24
21
  ENV['ACCESS_TOKEN'] = fetch_token
25
22
  ENV['APTIBLE_APP'] = app.href
26
23
  ENV['APTIBLE_CLI_COMMAND'] = 'logs'
27
24
 
28
- opts = " -o 'SendEnv=*' -o StrictHostKeyChecking=no " \
29
- '-o UserKnownHostsFile=/dev/null'
30
- Kernel.exec "ssh #{opts} -p #{port} root@#{host}"
25
+ cmd = dumptruck_ssh_command(app.account) + [
26
+ '-o', 'SendEnv=ACCESS_TOKEN',
27
+ '-o', 'SendEnv=APTIBLE_APP',
28
+ '-o', 'SendEnv=APTIBLE_CLI_COMMAND'
29
+ ]
30
+
31
+ Kernel.exec(*cmd)
31
32
  end
32
33
  end
33
34
  end
@@ -8,7 +8,6 @@ module Aptible
8
8
  thor.class_eval do
9
9
  include Helpers::Operation
10
10
  include Helpers::App
11
- include Helpers::Env
12
11
 
13
12
  desc 'ps', 'Display running processes for an app - DEPRECATED'
14
13
  app_options
@@ -16,16 +15,17 @@ module Aptible
16
15
  app = ensure_app(options)
17
16
  deprecated('This command is deprecated on Aptible v2 stacks.')
18
17
 
19
- host = app.account.bastion_host
20
- port = app.account.dumptruck_port
18
+ ENV['ACCESS_TOKEN'] = fetch_token
19
+ ENV['APTIBLE_APP'] = app.href
20
+ ENV['APTIBLE_CLI_COMMAND'] = 'ps'
21
21
 
22
- set_env('ACCESS_TOKEN', fetch_token)
23
- set_env('APTIBLE_APP', app.href)
24
- set_env('APTIBLE_CLI_COMMAND', 'ps')
22
+ cmd = dumptruck_ssh_command(app.account) + [
23
+ '-o', 'SendEnv=ACCESS_TOKEN',
24
+ '-o', 'SendEnv=APTIBLE_APP',
25
+ '-o', 'SendEnv=APTIBLE_CLI_COMMAND'
26
+ ]
25
27
 
26
- opts = " -o 'SendEnv=*' -o StrictHostKeyChecking=no " \
27
- '-o UserKnownHostsFile=/dev/null'
28
- Kernel.exec "ssh #{opts} -p #{port} root@#{host}"
28
+ Kernel.exec(*cmd)
29
29
  end
30
30
  end
31
31
  end
@@ -8,6 +8,7 @@ module Aptible
8
8
  thor.class_eval do
9
9
  include Helpers::Operation
10
10
  include Helpers::App
11
+ include Helpers::Ssh
11
12
 
12
13
  desc 'ssh [COMMAND]', 'Run a command against an app'
13
14
  long_desc <<-LONGDESC
@@ -19,17 +20,19 @@ module Aptible
19
20
  option :force_tty, type: :boolean
20
21
  def ssh(*args)
21
22
  app = ensure_app(options)
22
- host = app.account.bastion_host
23
- port = app.account.bastion_port
24
23
 
25
24
  ENV['ACCESS_TOKEN'] = fetch_token
26
- ENV['APTIBLE_COMMAND'] = command_from_args(*args)
27
25
  ENV['APTIBLE_APP'] = app.href
26
+ ENV['APTIBLE_COMMAND'] = command_from_args(*args)
27
+
28
+ cmd = broadwayjoe_ssh_command(app.account) + [
29
+ '-o', 'SendEnv=ACCESS_TOKEN',
30
+ '-o', 'SendEnv=APTIBLE_APP',
31
+ '-o', 'SendEnv=APTIBLE_COMMAND'
32
+ ]
33
+ cmd << '-tt' if options[:force_tty]
28
34
 
29
- opts = options[:force_tty] ? '-t -t' : ''
30
- opts << " -o 'SendEnv=*' -o StrictHostKeyChecking=no " \
31
- '-o UserKnownHostsFile=/dev/null'
32
- Kernel.exec "ssh #{opts} -p #{port} root@#{host}"
35
+ Kernel.exec(*cmd)
33
36
  end
34
37
 
35
38
  private
@@ -1,5 +1,5 @@
1
1
  module Aptible
2
2
  module CLI
3
- VERSION = '0.7.1'
3
+ VERSION = '0.7.2'.freeze
4
4
  end
5
5
  end
@@ -157,4 +157,15 @@ describe Aptible::CLI::Agent do
157
157
  end
158
158
  end
159
159
  end
160
+
161
+ context 'load' do
162
+ it 'loads without git' do
163
+ mocks = File.expand_path('../../../mock', __FILE__)
164
+ bins = File.expand_path('../../../../bin', __FILE__)
165
+ ClimateControl.modify PATH: [mocks, bins, ENV['PATH']].join(':') do
166
+ _, _, status = Open3.capture3('aptible version')
167
+ expect(status).to eq(0)
168
+ end
169
+ end
170
+ end
160
171
  end
@@ -1,61 +1,49 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Aptible::CLI::Helpers::Tunnel do
4
- around do |example|
5
- mocks_path = File.expand_path('../../../../mock', __FILE__)
6
- path = "#{mocks_path}:#{ENV['PATH']}"
7
- ClimateControl.modify PATH: path do
8
- example.run
9
- end
10
- end
4
+ include_context 'mock ssh'
11
5
 
12
- it 'reuses the port it was given' do
6
+ it 'forwards traffic to the remote port given by the server (1234)' do
13
7
  helper = described_class.new({}, ['ssh_mock.rb'])
14
8
 
15
- r, w = IO.pipe
16
- helper.start(0, w)
9
+ helper.start(0)
17
10
  helper.stop
18
11
 
19
- expect(r.readline.chomp).to eq('6')
20
- expect(r.readline.chomp).to eq('-L')
21
- expect(r.readline.chomp).to match(/\d+:localhost:1234$/)
22
- expect(r.readline.chomp).to eq('-o')
23
- expect(r.readline.chomp).to eq('SendEnv=TUNNEL_PORT')
24
- expect(r.readline.chomp).to eq('-o')
25
- expect(r.readline.chomp).to eq('SendEnv=TUNNEL_SIGNAL_OPEN')
26
-
27
- r.close
28
- w.close
12
+ mock_argv = read_mock_argv
13
+ expect(mock_argv.size).to eq(8)
14
+
15
+ expect(mock_argv.shift).to eq('-L')
16
+ expect(mock_argv.shift).to match(/\d+:localhost:1234$/)
17
+ expect(mock_argv.shift).to eq('-o')
18
+ expect(mock_argv.shift).to eq('SendEnv=TUNNEL_PORT')
19
+ expect(mock_argv.shift).to eq('-o')
20
+ expect(mock_argv.shift).to eq('SendEnv=TUNNEL_SIGNAL_OPEN')
21
+ expect(mock_argv.shift).to eq('-o')
22
+ expect(mock_argv.shift).to eq('ExitOnForwardFailure=yes')
29
23
  end
30
24
 
31
- it 'accepts a desired port' do
25
+ it 'accepts a desired local port' do
32
26
  helper = described_class.new({}, ['ssh_mock.rb'])
33
- r, w = IO.pipe
34
- helper.start(5678, w)
27
+ helper.start(5678)
35
28
  helper.stop
36
29
 
37
- expect(r.readline.chomp).to eq('6')
38
- expect(r.readline.chomp).to eq('-L')
39
- expect(r.readline.chomp).to eq('5678:localhost:1234')
40
- expect(r.readline.chomp).to eq('-o')
41
- expect(r.readline.chomp).to eq('SendEnv=TUNNEL_PORT')
42
- expect(r.readline.chomp).to eq('-o')
43
- expect(r.readline.chomp).to eq('SendEnv=TUNNEL_SIGNAL_OPEN')
30
+ mock_argv = read_mock_argv
31
+ expect(mock_argv.size).to eq(8)
44
32
 
45
- r.close
46
- w.close
33
+ expect(mock_argv.shift).to eq('-L')
34
+ expect(mock_argv.shift).to eq('5678:localhost:1234')
47
35
  end
48
36
 
49
37
  it 'captures and displays port discovery errors' do
50
38
  helper = described_class.new({ 'FAIL_PORT' => '1' }, ['ssh_mock.rb'])
51
- expect { helper.start }.to raise_error(/Something went wrong/)
39
+ expect { helper.start }
40
+ .to raise_error(/Failed to request.*Something went wrong/m)
52
41
  end
53
42
 
54
43
  it 'captures and displays tunnel errors' do
55
44
  helper = described_class.new({ 'FAIL_TUNNEL' => '1' }, ['ssh_mock.rb'])
56
- expect do
57
- helper.start(0, File.open(File::NULL, 'w'))
58
- end.to raise_error(/Server closed the tunnel/)
45
+ expect { helper.start(0) }
46
+ .to raise_error(/Tunnel did not come up.*Something went wrong/m)
59
47
  end
60
48
 
61
49
  it 'should fail if #port is called before #start' do
@@ -1,6 +1,8 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Aptible::CLI::Agent do
4
+ include_context 'mock ssh'
5
+
4
6
  let(:account) do
5
7
  Fabricate(:account, bastion_host: 'bastion.com', dumptruck_port: 45022)
6
8
  end
@@ -10,21 +12,25 @@ describe Aptible::CLI::Agent do
10
12
  before { subject.stub(:save_token) }
11
13
  before { subject.stub(:fetch_token) { double 'token' } }
12
14
  before { subject.stub(:ensure_app) { app } }
13
- before { subject.stub(:set_env) }
14
- before { Kernel.stub(:exec) }
15
+
16
+ before do
17
+ allow(Kernel).to receive(:exec) do |*args|
18
+ Kernel.system(*args)
19
+ end
20
+ end
15
21
 
16
22
  describe '#ps' do
17
23
  it 'should set ENV["APTIBLE_CLI_COMMAND"]' do
18
- expect(subject).to receive(:set_env).with('APTIBLE_CLI_COMMAND', 'ps')
19
24
  subject.send('ps')
25
+ expect(read_mock_env['APTIBLE_CLI_COMMAND']).to eq('ps')
20
26
  end
21
27
 
22
28
  it 'should construct a proper SSH call' do
23
- expect(Kernel).to receive(:exec) do |*args|
24
- cmd = args.first
25
- expect(cmd).to match(/ssh.*-p 45022 root@bastion.com/)
26
- end
27
29
  subject.send('ps')
30
+
31
+ mock_argv = read_mock_argv
32
+ expect(mock_argv).to include('root@bastion.com')
33
+ expect(mock_argv).to include('45022')
28
34
  end
29
35
  end
30
36
  end
@@ -0,0 +1,2 @@
1
+ #!/bin/sh
2
+ exit 1
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Emulate server behavior
4
+
5
+ if ENV['TUNNEL_PORT']
6
+ fail 'Something went wrong!' if ENV['FAIL_TUNNEL']
7
+ puts 'TUNNEL READY'
8
+ else
9
+ fail 'Something went wrong!' if ENV['FAIL_PORT']
10
+ puts 1234
11
+ end
12
+
13
+ # Log to SSH_MOCK_OUTFILE
14
+ require 'json'
15
+
16
+ File.open(ENV.fetch('SSH_MOCK_OUTFILE'), 'w') do |f|
17
+ f.write({
18
+ 'argc' => ARGV.size,
19
+ 'argv' => ARGV,
20
+ 'env' => ENV.to_hash
21
+ }.to_json)
22
+ end
@@ -10,9 +10,13 @@ else
10
10
  puts 1234
11
11
  end
12
12
 
13
- # Log to stderr so we can collect in test
13
+ # Log to SSH_MOCK_OUTFILE
14
+ require 'json'
14
15
 
15
- $stderr.puts ARGV.size
16
- ARGV.each do |a|
17
- $stderr.puts a
16
+ File.open(ENV.fetch('SSH_MOCK_OUTFILE'), 'w') do |f|
17
+ f.write({
18
+ 'argc' => ARGV.size,
19
+ 'argv' => ARGV,
20
+ 'env' => ENV.to_hash
21
+ }.to_json)
18
22
  end
@@ -0,0 +1,30 @@
1
+ shared_context 'mock ssh' do
2
+ let(:ssh_mock_outfile) { Tempfile.new('tunnel_spec') }
3
+
4
+ after do
5
+ ssh_mock_outfile.close
6
+ ssh_mock_outfile.unlink
7
+ end
8
+
9
+ around do |example|
10
+ mocks_path = File.expand_path('../../mock', __FILE__)
11
+ env = {
12
+ PATH: "#{mocks_path}:#{ENV['PATH']}",
13
+ SSH_MOCK_OUTFILE: ssh_mock_outfile.path
14
+ }
15
+
16
+ ClimateControl.modify(env) { example.run }
17
+ end
18
+
19
+ def read_mock_argv
20
+ File.open(ssh_mock_outfile) do |f|
21
+ return JSON.load(f.read).fetch('argv')
22
+ end
23
+ end
24
+
25
+ def read_mock_env
26
+ File.open(ssh_mock_outfile) do |f|
27
+ return JSON.load(f.read).fetch('env')
28
+ end
29
+ end
30
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aptible-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.1
4
+ version: 0.7.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Frank Macreery
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-06-30 00:00:00.000000000 Z
11
+ date: 2016-09-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aptible-api
@@ -229,9 +229,9 @@ files:
229
229
  - lib/aptible/cli/agent.rb
230
230
  - lib/aptible/cli/helpers/app.rb
231
231
  - lib/aptible/cli/helpers/database.rb
232
- - lib/aptible/cli/helpers/env.rb
233
232
  - lib/aptible/cli/helpers/environment.rb
234
233
  - lib/aptible/cli/helpers/operation.rb
234
+ - lib/aptible/cli/helpers/ssh.rb
235
235
  - lib/aptible/cli/helpers/token.rb
236
236
  - lib/aptible/cli/helpers/tunnel.rb
237
237
  - lib/aptible/cli/subcommands/apps.rb
@@ -263,7 +263,10 @@ files:
263
263
  - spec/fabricators/operation_fabricator.rb
264
264
  - spec/fabricators/service_fabricator.rb
265
265
  - spec/fabricators/vhost_fabricator.rb
266
+ - spec/mock/git
267
+ - spec/mock/ssh
266
268
  - spec/mock/ssh_mock.rb
269
+ - spec/shared/mock_ssh_context.rb
267
270
  - spec/spec_helper.rb
268
271
  homepage: https://github.com/aptible/aptible-cli
269
272
  licenses:
@@ -285,7 +288,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
285
288
  version: '0'
286
289
  requirements: []
287
290
  rubyforge_project:
288
- rubygems_version: 2.6.4
291
+ rubygems_version: 2.4.5.1
289
292
  signing_key:
290
293
  specification_version: 4
291
294
  summary: Command-line interface for Aptible services
@@ -308,5 +311,8 @@ test_files:
308
311
  - spec/fabricators/operation_fabricator.rb
309
312
  - spec/fabricators/service_fabricator.rb
310
313
  - spec/fabricators/vhost_fabricator.rb
314
+ - spec/mock/git
315
+ - spec/mock/ssh
311
316
  - spec/mock/ssh_mock.rb
317
+ - spec/shared/mock_ssh_context.rb
312
318
  - spec/spec_helper.rb
@@ -1,11 +0,0 @@
1
- module Aptible
2
- module CLI
3
- module Helpers
4
- module Env
5
- def set_env(key, value)
6
- ENV[key] = value
7
- end
8
- end
9
- end
10
- end
11
- end