aptible-cli 0.7.4 → 0.7.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/appveyor.yml +31 -0
- data/aptible-cli.gemspec +1 -1
- data/lib/aptible/cli/agent.rb +45 -1
- data/lib/aptible/cli/helpers/tunnel.rb +22 -4
- data/lib/aptible/cli/subcommands/db.rb +1 -1
- data/lib/aptible/cli/version.rb +1 -1
- data/spec/aptible/cli/agent_spec.rb +75 -4
- data/spec/aptible/cli/helpers/git_remote_handle_strategy_spec.rb +5 -3
- data/spec/aptible/cli/helpers/tunnel_spec.rb +4 -4
- data/spec/mock/ssh.bat +2 -0
- data/spec/shared/mock_ssh_context.rb +1 -1
- data/spec/spec_helper.rb +6 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a46c716db34062c50939791b35288542ab1dacc4
|
4
|
+
data.tar.gz: 54293b621aba536d05c4ea25740fe61530e9209f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 35fadaf8062518242be514c26c66f406cb9f3ebf79128986852a4a51ef84365610f5058b90fbdcf426a18e5bfc68d4ec3afd03935b6e08d9955961bc1f24d0bb
|
7
|
+
data.tar.gz: 96a7acb0ac08381a76753035670d6e26f3d72347ce1b5c2f64f7259a960b73ad12de3e35aedd0b30890a7d2701785059f45218a107fc35a6626106875aafe367
|
data/appveyor.yml
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
version: 1.0.{build}-{branch}
|
2
|
+
|
3
|
+
environment:
|
4
|
+
matrix:
|
5
|
+
- RUBY_VERSION: 200
|
6
|
+
- RUBY_VERSION: 21
|
7
|
+
- RUBY_VERSION: 22
|
8
|
+
- RUBY_VERSION: 23
|
9
|
+
|
10
|
+
install:
|
11
|
+
# The SSL_CERT_* environment variables are here since otherwise calls to
|
12
|
+
# codecov.io wtill not work. These variables do have to be set in order for
|
13
|
+
# the gem to make calls to the Aptible API, since otherwise Ruby will fail
|
14
|
+
# with a certificate verification error.
|
15
|
+
- set SSL_CERT_DIR=%PROGRAMFILES%\Git\mingw64\ssl\certs
|
16
|
+
- set SSL_CERT_FILE=%PROGRAMFILES%\Git\mingw64\ssl\cert.pem
|
17
|
+
# Override PATHEXT so our ssh bat file has a higher precedence.
|
18
|
+
- set PATHEXT=.BAT;.COM;.EXE;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
|
19
|
+
- set PATH=C:\Ruby%RUBY_VERSION%-x64\bin;%PATH%
|
20
|
+
- bundle config --local path vendor/bundle
|
21
|
+
- bundle install
|
22
|
+
|
23
|
+
build: off
|
24
|
+
|
25
|
+
before_test:
|
26
|
+
- ruby -v
|
27
|
+
- gem -v
|
28
|
+
- bundle -v
|
29
|
+
|
30
|
+
test_script:
|
31
|
+
- bundle exec rake ci
|
data/aptible-cli.gemspec
CHANGED
@@ -27,7 +27,7 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.add_dependency 'git'
|
28
28
|
spec.add_dependency 'term-ansicolor'
|
29
29
|
spec.add_dependency 'chronic_duration', '~> 0.10.6'
|
30
|
-
|
30
|
+
spec.add_dependency 'win32-process' if Gem.win_platform?
|
31
31
|
spec.add_development_dependency 'bundler', '~> 1.3'
|
32
32
|
spec.add_development_dependency 'aptible-tasks', '>= 0.2.0'
|
33
33
|
spec.add_development_dependency 'rake'
|
data/lib/aptible/cli/agent.rb
CHANGED
@@ -44,9 +44,19 @@ module Aptible
|
|
44
44
|
true
|
45
45
|
end
|
46
46
|
|
47
|
+
def initialize(*)
|
48
|
+
nag_toolbelt unless toolbelt?
|
49
|
+
super
|
50
|
+
end
|
51
|
+
|
47
52
|
desc 'version', 'Print Aptible CLI version'
|
48
53
|
def version
|
49
|
-
|
54
|
+
bits = [
|
55
|
+
'aptible-cli',
|
56
|
+
"v#{Aptible::CLI::VERSION}"
|
57
|
+
]
|
58
|
+
bits << 'toolbelt' if toolbelt?
|
59
|
+
puts bits.join ' '
|
50
60
|
end
|
51
61
|
|
52
62
|
desc 'login', 'Log in to Aptible'
|
@@ -104,6 +114,40 @@ module Aptible
|
|
104
114
|
say "DEPRECATION NOTICE: #{msg}"
|
105
115
|
say 'Please contact support@aptible.com with any questions.'
|
106
116
|
end
|
117
|
+
|
118
|
+
def nag_toolbelt
|
119
|
+
# If you're reading this, it's possible you decided to not use the
|
120
|
+
# toolbelt and are a looking for a way to disable this warning. Look no
|
121
|
+
# further: to do so, edit the file `.aptible/nag_toolbelt` and put a
|
122
|
+
# timestamp far into the future. For example, writing 1577836800 will
|
123
|
+
# disable the warning until 2020.
|
124
|
+
nag_file = File.join ENV['HOME'], '.aptible', 'nag_toolbelt'
|
125
|
+
nag_frequency = 12.hours
|
126
|
+
|
127
|
+
last_nag = begin
|
128
|
+
Integer(File.read(nag_file))
|
129
|
+
rescue Errno::ENOENT, ArgumentError
|
130
|
+
0
|
131
|
+
end
|
132
|
+
|
133
|
+
now = Time.now.utc.to_i
|
134
|
+
|
135
|
+
if last_nag < now - nag_frequency
|
136
|
+
$stderr.puts yellow([
|
137
|
+
'You have installed the Aptible CLI from source.',
|
138
|
+
'This is not recommended: some functionality may not work!',
|
139
|
+
'Review this support topic for more information:',
|
140
|
+
'https://www.aptible.com/support/topics/cli/how-to-install-cli/'
|
141
|
+
].join("\n"))
|
142
|
+
|
143
|
+
FileUtils.mkdir_p(File.dirname(nag_file))
|
144
|
+
File.open(nag_file, 'w', 0o600) { |f| f.write(now.to_s) }
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def toolbelt?
|
149
|
+
ENV['APTIBLE_TOOLBELT']
|
150
|
+
end
|
107
151
|
end
|
108
152
|
end
|
109
153
|
end
|
@@ -1,9 +1,27 @@
|
|
1
1
|
require 'socket'
|
2
2
|
require 'open3'
|
3
|
+
require 'win32-process' if Gem.win_platform?
|
3
4
|
|
4
5
|
module Aptible
|
5
6
|
module CLI
|
6
7
|
module Helpers
|
8
|
+
# The :new_pgroup key specifies the CREATE_NEW_PROCESS_GROUP flag for
|
9
|
+
# CreateProcessW() in the Windows API. This is a Windows only option.
|
10
|
+
# true means the new process is the root process of the new process
|
11
|
+
# group.
|
12
|
+
# This flag is necessary for Process.kill(:SIGINT, pid) on the
|
13
|
+
# subprocess.
|
14
|
+
STOP_SIGNAL = if Gem.win_platform?
|
15
|
+
:SIGINT
|
16
|
+
else
|
17
|
+
:SIGHUP
|
18
|
+
end
|
19
|
+
SPAWN_OPTS = if Gem.win_platform?
|
20
|
+
{ new_pgroup: true }
|
21
|
+
else
|
22
|
+
{}
|
23
|
+
end
|
24
|
+
|
7
25
|
class Tunnel
|
8
26
|
def initialize(env, ssh_cmd)
|
9
27
|
@env = env
|
@@ -37,9 +55,9 @@ module Aptible
|
|
37
55
|
|
38
56
|
out_read, out_write = IO.pipe
|
39
57
|
err_read, err_write = IO.pipe
|
40
|
-
|
41
|
-
|
42
|
-
|
58
|
+
|
59
|
+
@pid = Process.spawn(tunnel_env, *tunnel_cmd, SPAWN_OPTS
|
60
|
+
.merge(in: :close, out: out_write, err: err_write))
|
43
61
|
|
44
62
|
# Wait for the tunnel to come up before returning. The other end
|
45
63
|
# will send a message on stdout to indicate that the tunnel is ready.
|
@@ -59,7 +77,7 @@ module Aptible
|
|
59
77
|
def stop
|
60
78
|
fail 'You must call #start before calling #stop' if @pid.nil?
|
61
79
|
begin
|
62
|
-
Process.kill(
|
80
|
+
Process.kill(STOP_SIGNAL, @pid)
|
63
81
|
rescue Errno::ESRCH
|
64
82
|
nil # Dear Rubocop: I know what I'm doing.
|
65
83
|
end
|
@@ -22,7 +22,7 @@ module Aptible
|
|
22
22
|
|
23
23
|
desc 'db:create HANDLE', 'Create a new database'
|
24
24
|
option :type, default: 'postgresql'
|
25
|
-
option :size, default: 10
|
25
|
+
option :size, default: 10, type: :numeric
|
26
26
|
option :environment
|
27
27
|
define_method 'db:create' do |handle|
|
28
28
|
environment = ensure_environment(options)
|
data/lib/aptible/cli/version.rb
CHANGED
@@ -7,9 +7,19 @@ describe Aptible::CLI::Agent do
|
|
7
7
|
|
8
8
|
describe '#version' do
|
9
9
|
it 'should print the version' do
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
ClimateControl.modify(APTIBLE_TOOLBELT: nil) do
|
11
|
+
version = Aptible::CLI::VERSION
|
12
|
+
expect(STDOUT).to receive(:puts).with "aptible-cli v#{version}"
|
13
|
+
subject.version
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should print the version (with toolbelt)' do
|
18
|
+
ClimateControl.modify(APTIBLE_TOOLBELT: '1') do
|
19
|
+
version = Aptible::CLI::VERSION
|
20
|
+
expect(STDOUT).to receive(:puts).with "aptible-cli v#{version} toolbelt"
|
21
|
+
subject.version
|
22
|
+
end
|
13
23
|
end
|
14
24
|
end
|
15
25
|
|
@@ -158,11 +168,72 @@ describe Aptible::CLI::Agent do
|
|
158
168
|
end
|
159
169
|
end
|
160
170
|
|
171
|
+
describe '#nag_toolbelt' do
|
172
|
+
let!(:work_dir) { Dir.mktmpdir }
|
173
|
+
after { FileUtils.remove_entry work_dir }
|
174
|
+
around { |example| ClimateControl.modify(HOME: work_dir) { example.run } }
|
175
|
+
|
176
|
+
let(:nag_dir) { File.join(work_dir, '.aptible') }
|
177
|
+
let(:nag_file) { File.join(nag_dir, 'nag_toolbelt') }
|
178
|
+
|
179
|
+
it 'warns if the nag file is not present' do
|
180
|
+
expect($stderr).to receive(:puts).at_least(:once)
|
181
|
+
subject.send(:nag_toolbelt)
|
182
|
+
expect(Integer(File.read(nag_file))).to be_within(5).of(Time.now.utc.to_i)
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'warns if the nag file contains an old timestamp' do
|
186
|
+
Dir.mkdir(nag_dir)
|
187
|
+
File.open(nag_file, 'w') do |f|
|
188
|
+
f.write((Time.now.utc.to_i - 1.day).to_i.to_s)
|
189
|
+
end
|
190
|
+
|
191
|
+
expect($stderr).to receive(:puts).at_least(:once)
|
192
|
+
subject.send(:nag_toolbelt)
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'does not warn if the nag file contains a recent timestamp' do
|
196
|
+
Dir.mkdir(nag_dir)
|
197
|
+
File.open(nag_file, 'w') do |f|
|
198
|
+
f.write((Time.now.utc.to_i - 3.hours).to_i.to_s)
|
199
|
+
end
|
200
|
+
|
201
|
+
expect($stderr).not_to receive(:puts)
|
202
|
+
subject.send(:nag_toolbelt)
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'does not warn if the nag file contains a recent timestamp (newline)' do
|
206
|
+
# In case a customer writes to the nag file to disable the nag, they're
|
207
|
+
# likely to add a trailing newline. Let's just make sure we support that.
|
208
|
+
Dir.mkdir(nag_dir)
|
209
|
+
File.open(nag_file, 'w') do |f|
|
210
|
+
f.write("#{(Time.now.utc.to_i - 3.hours).to_i}\n")
|
211
|
+
end
|
212
|
+
|
213
|
+
expect($stderr).not_to receive(:puts)
|
214
|
+
subject.send(:nag_toolbelt)
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'warns if the nag file contains an invalid timestamp' do
|
218
|
+
Dir.mkdir(nag_dir)
|
219
|
+
File.open(nag_file, 'w') { |f| f.write('foobar') }
|
220
|
+
|
221
|
+
expect($stderr).to receive(:puts).at_least(:once)
|
222
|
+
subject.send(:nag_toolbelt)
|
223
|
+
end
|
224
|
+
|
225
|
+
it 'is compatible with itself' do
|
226
|
+
expect($stderr).to receive(:puts).once
|
227
|
+
2.times { subject.send(:nag_toolbelt) }
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
161
231
|
context 'load' do
|
162
232
|
it 'loads without git' do
|
163
233
|
mocks = File.expand_path('../../../mock', __FILE__)
|
164
234
|
bins = File.expand_path('../../../../bin', __FILE__)
|
165
|
-
|
235
|
+
sep = File::PATH_SEPARATOR
|
236
|
+
ClimateControl.modify PATH: [mocks, bins, ENV['PATH']].join(sep) do
|
166
237
|
_, _, status = Open3.capture3('aptible version')
|
167
238
|
expect(status).to eq(0)
|
168
239
|
end
|
@@ -1,9 +1,11 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Aptible::CLI::Helpers::App::GitRemoteHandleStrategy do
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
around do |example|
|
5
|
+
Dir.mktmpdir do |work_dir|
|
6
|
+
Dir.chdir(work_dir) { example.run }
|
7
|
+
end
|
8
|
+
end
|
7
9
|
|
8
10
|
context 'with git repo' do
|
9
11
|
before { `git init` }
|
@@ -4,7 +4,7 @@ describe Aptible::CLI::Helpers::Tunnel do
|
|
4
4
|
include_context 'mock ssh'
|
5
5
|
|
6
6
|
it 'forwards traffic to the remote port given by the server (1234)' do
|
7
|
-
helper = described_class.new({}, ['
|
7
|
+
helper = described_class.new({}, ['ssh'])
|
8
8
|
|
9
9
|
helper.start(0)
|
10
10
|
helper.stop
|
@@ -23,7 +23,7 @@ describe Aptible::CLI::Helpers::Tunnel do
|
|
23
23
|
end
|
24
24
|
|
25
25
|
it 'accepts a desired local port' do
|
26
|
-
helper = described_class.new({}, ['
|
26
|
+
helper = described_class.new({}, ['ssh'])
|
27
27
|
helper.start(5678)
|
28
28
|
helper.stop
|
29
29
|
|
@@ -35,13 +35,13 @@ describe Aptible::CLI::Helpers::Tunnel do
|
|
35
35
|
end
|
36
36
|
|
37
37
|
it 'captures and displays port discovery errors' do
|
38
|
-
helper = described_class.new({ 'FAIL_PORT' => '1' }, ['
|
38
|
+
helper = described_class.new({ 'FAIL_PORT' => '1' }, ['ssh'])
|
39
39
|
expect { helper.start }
|
40
40
|
.to raise_error(/Failed to request.*Something went wrong/m)
|
41
41
|
end
|
42
42
|
|
43
43
|
it 'captures and displays tunnel errors' do
|
44
|
-
helper = described_class.new({ 'FAIL_TUNNEL' => '1' }, ['
|
44
|
+
helper = described_class.new({ 'FAIL_TUNNEL' => '1' }, ['ssh'])
|
45
45
|
expect { helper.start(0) }
|
46
46
|
.to raise_error(/Tunnel did not come up.*Something went wrong/m)
|
47
47
|
end
|
data/spec/mock/ssh.bat
ADDED
@@ -9,7 +9,7 @@ shared_context 'mock ssh' do
|
|
9
9
|
around do |example|
|
10
10
|
mocks_path = File.expand_path('../../mock', __FILE__)
|
11
11
|
env = {
|
12
|
-
PATH: "#{mocks_path}
|
12
|
+
PATH: "#{mocks_path}#{File::PATH_SEPARATOR}#{ENV['PATH']}",
|
13
13
|
SSH_MOCK_OUTFILE: ssh_mock_outfile.path
|
14
14
|
}
|
15
15
|
|
data/spec/spec_helper.rb
CHANGED
@@ -21,4 +21,10 @@ require 'aptible/cli'
|
|
21
21
|
|
22
22
|
RSpec.configure do |config|
|
23
23
|
config.before {}
|
24
|
+
|
25
|
+
# We make the CLI believe it's running in a toolbelt context to avoid running
|
26
|
+
# the toolbelt nag every time it initializes.
|
27
|
+
config.around(:each) do |example|
|
28
|
+
ClimateControl.modify(APTIBLE_TOOLBELT: '1') { example.run }
|
29
|
+
end
|
24
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.
|
4
|
+
version: 0.7.5
|
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-
|
11
|
+
date: 2016-12-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aptible-api
|
@@ -222,6 +222,7 @@ files:
|
|
222
222
|
- LICENSE.md
|
223
223
|
- README.md
|
224
224
|
- Rakefile
|
225
|
+
- appveyor.yml
|
225
226
|
- aptible-cli.gemspec
|
226
227
|
- bin/aptible
|
227
228
|
- codecov.yml
|
@@ -266,6 +267,7 @@ files:
|
|
266
267
|
- spec/fabricators/vhost_fabricator.rb
|
267
268
|
- spec/mock/git
|
268
269
|
- spec/mock/ssh
|
270
|
+
- spec/mock/ssh.bat
|
269
271
|
- spec/mock/ssh_mock.rb
|
270
272
|
- spec/shared/mock_ssh_context.rb
|
271
273
|
- spec/spec_helper.rb
|
@@ -315,6 +317,7 @@ test_files:
|
|
315
317
|
- spec/fabricators/vhost_fabricator.rb
|
316
318
|
- spec/mock/git
|
317
319
|
- spec/mock/ssh
|
320
|
+
- spec/mock/ssh.bat
|
318
321
|
- spec/mock/ssh_mock.rb
|
319
322
|
- spec/shared/mock_ssh_context.rb
|
320
323
|
- spec/spec_helper.rb
|