aptible-cli 0.7.1 → 0.7.2

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