aptible-cli 0.5.15 → 0.6.0

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: a4a414273ca1b43ed9ba77b0d60edf901a10f984
4
- data.tar.gz: a792785c97710d096c958c89cac6cfa78b5da496
3
+ metadata.gz: 0e6d976b32bef3e1b4b34c49be4d7bfc524aa908
4
+ data.tar.gz: b53c2136b9de6bd7f09b87950bdf214f58adfffd
5
5
  SHA512:
6
- metadata.gz: d9b2f63dd6958f2fbdf26aea08d8ceb07a868eb3a67cb86c507293c008cfda491fa70689d63ca294827fd236907f1cba0864c2203612d9a1af87c5b6fdde3d52
7
- data.tar.gz: 3fe1e96e66fdb052f0a3de8bf99b85237a8a75e79a548d416be3dffd58f63c7b45556b7f0d2ac74c7dd923c11d0e37431b8ca8df65b345ee48e72e7395d27428
6
+ metadata.gz: a7300533f684f475ad4e981d9b9534758ec666c1a57c83a4e605da5fe06286f03877b589303a7027b854fcf6470d1b76ba8cb987f0c4bf1423171abfa2f117db
7
+ data.tar.gz: 4b6a7f6c26295bdbacdf9093113e32431a9c9ef73bbec8f2017996a89d0955a0c405305dfeec6e418181b96f326cb68551be16ed24b2b68ef83d8c3c7f268488
@@ -4,7 +4,7 @@ require 'json'
4
4
 
5
5
  require_relative 'helpers/token'
6
6
  require_relative 'helpers/operation'
7
- require_relative 'helpers/account'
7
+ require_relative 'helpers/environment'
8
8
  require_relative 'helpers/app'
9
9
  require_relative 'helpers/env'
10
10
 
@@ -6,19 +6,38 @@ module Aptible
6
6
  module Helpers
7
7
  module App
8
8
  include Helpers::Token
9
+ include Helpers::Environment
10
+
11
+ class HandleFromGitRemote
12
+ PATTERN = %r{
13
+ :((?<environment_handle>[0-9a-z\-_\.]+?)/)?(?<app_handle>[0-9a-z\-_\.]+)\.git
14
+ \z
15
+ }x
16
+
17
+ def self.parse(url)
18
+ PATTERN.match(url)
19
+ end
20
+ end
9
21
 
10
22
  def ensure_app(options = {})
11
23
  remote = options[:remote] || ENV['APTIBLE_REMOTE']
12
- handle = options[:app] ||
13
- handle_from_remote(remote) ||
14
- ensure_default_handle
15
- app = app_from_handle(handle)
24
+ handle = options[:app]
25
+ if handle
26
+ environment = ensure_environment(options)
27
+ else
28
+ handles = handle_from_remote(remote) || ensure_default_handle
29
+ handle = handles[:app_handle]
30
+ env_handle = handles[:environment_handle] || options[:environment]
31
+ environment = ensure_environment(environment: env_handle)
32
+ end
33
+
34
+ app = app_from_handle(handle, environment)
16
35
  return app if app
17
36
  fail Thor::Error, "Could not find app #{handle}"
18
37
  end
19
38
 
20
- def app_from_handle(handle)
21
- Aptible::Api::App.all(token: fetch_token).find do |a|
39
+ def app_from_handle(handle, environment)
40
+ environment.apps.find do |a|
22
41
  a.handle == handle
23
42
  end
24
43
  end
@@ -38,7 +57,7 @@ module Aptible
38
57
  def handle_from_remote(remote_name)
39
58
  git = Git.open(Dir.pwd)
40
59
  aptible_remote = git.remote(remote_name).url || ''
41
- aptible_remote[/:(?<name>.+)\.git/, :name]
60
+ HandleFromGitRemote.parse(aptible_remote)
42
61
  rescue
43
62
  nil
44
63
  end
@@ -0,0 +1,49 @@
1
+ require 'aptible/api'
2
+ require 'git'
3
+
4
+ module Aptible
5
+ module CLI
6
+ module Helpers
7
+ module Environment
8
+ include Helpers::Token
9
+
10
+ def scoped_environments(options)
11
+ if options[:environment]
12
+ if (environment = environment_from_handle(options[:environment]))
13
+ [environment]
14
+ else
15
+ fail Thor::Error, 'Specified account does not exist'
16
+ end
17
+ else
18
+ Aptible::Api::Account.all(token: fetch_token)
19
+ end
20
+ end
21
+
22
+ def ensure_environment(options = {})
23
+ if (handle = options[:environment])
24
+ environment = environment_from_handle(handle)
25
+ return environment if environment
26
+ fail Thor::Error, "Could not find environment #{handle}"
27
+ else
28
+ ensure_default_environment
29
+ end
30
+ end
31
+
32
+ def environment_from_handle(handle)
33
+ Aptible::Api::Account.all(token: fetch_token).find do |a|
34
+ a.handle == handle
35
+ end
36
+ end
37
+
38
+ def ensure_default_environment
39
+ environments = Aptible::Api::Account.all(token: fetch_token)
40
+ return environments.first if environments.count == 1
41
+
42
+ fail Thor::Error, <<-ERR.gsub(/\s+/, ' ').strip
43
+ Multiple environments available, please specify with --environment
44
+ ERR
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -4,15 +4,15 @@ module Aptible
4
4
  module Apps
5
5
  def self.included(thor)
6
6
  thor.class_eval do
7
- include Helpers::Account
7
+ include Helpers::Environment
8
8
  include Helpers::Token
9
9
 
10
10
  desc 'apps', 'List all applications'
11
- option :account
11
+ option :environment
12
12
  def apps
13
- scoped_accounts(options).each do |account|
14
- say "=== #{account.handle}"
15
- account.apps.each do |app|
13
+ scoped_environments(options).each do |env|
14
+ say "=== #{env.handle}"
15
+ env.apps.each do |app|
16
16
  say app.handle
17
17
  end
18
18
  say ''
@@ -20,10 +20,10 @@ module Aptible
20
20
  end
21
21
 
22
22
  desc 'apps:create HANDLE', 'Create a new application'
23
- option :account
23
+ option :environment
24
24
  define_method 'apps:create' do |handle|
25
- account = ensure_account(options)
26
- app = account.create_app(handle: handle)
25
+ environment = ensure_environment(options)
26
+ app = environment.create_app(handle: handle)
27
27
 
28
28
  if app.errors.any?
29
29
  fail Thor::Error, app.errors.full_messages.first
@@ -34,6 +34,7 @@ module Aptible
34
34
 
35
35
  desc 'apps:scale TYPE NUMBER', 'Scale app to NUMBER of instances'
36
36
  option :app
37
+ option :environment
37
38
  define_method 'apps:scale' do |type, n|
38
39
  num = Integer(n)
39
40
  app = ensure_app(options)
@@ -43,6 +44,7 @@ module Aptible
43
44
  end
44
45
 
45
46
  option :app
47
+ option :environment
46
48
  desc 'apps:deprovision', 'Deprovision an app'
47
49
  define_method 'apps:deprovision' do
48
50
  app = ensure_app(options)
@@ -11,21 +11,21 @@ module Aptible
11
11
  include Term::ANSIColor
12
12
 
13
13
  desc 'db:list', 'List all databases'
14
- option :account
14
+ option :environment
15
15
  define_method 'db:list' do
16
- scoped_accounts(options).each do |account|
17
- present_account_databases(account)
16
+ scoped_environments(options).each do |env|
17
+ present_environment_databases(env)
18
18
  end
19
19
  end
20
20
 
21
21
  desc 'db:create HANDLE', 'Create a new database'
22
22
  option :type, default: 'postgresql'
23
23
  option :size, default: 10
24
- option :account
24
+ option :environment
25
25
  define_method 'db:create' do |handle|
26
- account = ensure_account(options)
27
- database = account.create_database(handle: handle,
28
- type: options[:type])
26
+ environment = ensure_environment(options)
27
+ database = environment.create_database(handle: handle,
28
+ type: options[:type])
29
29
 
30
30
  if database.errors.any?
31
31
  fail Thor::Error, database.errors.full_messages.first
@@ -38,28 +38,36 @@ module Aptible
38
38
  end
39
39
 
40
40
  desc 'db:clone SOURCE DEST', 'Clone a database to create a new one'
41
+ option :environment
41
42
  define_method 'db:clone' do |source_handle, dest_handle|
42
- dest = clone_database(source_handle, dest_handle)
43
+ environment = ensure_environment(options)
44
+ dest = clone_database(source_handle, dest_handle, environment)
43
45
  say dest.connection_url
44
46
  end
45
47
 
46
48
  desc 'db:dump HANDLE', 'Dump a remote database to file'
49
+ option :environment
47
50
  define_method 'db:dump' do |handle|
48
- dump_database(handle)
51
+ environment = ensure_environment(options)
52
+ dump_database(handle, environment)
49
53
  end
50
54
 
51
55
  desc 'db:execute HANDLE SQL_FILE', 'Executes sql against a database'
56
+ option :environment
52
57
  define_method 'db:execute' do |handle, sql_path|
53
- execute_local_tunnel(handle) do |url|
58
+ environment = ensure_environment(options)
59
+ execute_local_tunnel(handle, environment) do |url|
54
60
  say "Executing #{sql_path} against #{handle}"
55
61
  `psql #{url} < #{sql_path}`
56
62
  end
57
63
  end
58
64
 
59
65
  desc 'db:tunnel HANDLE', 'Create a local tunnel to a database'
66
+ option :environment
60
67
  option :port, type: :numeric
61
68
  define_method 'db:tunnel' do |handle|
62
- database = database_from_handle(handle)
69
+ environment = ensure_environment(options)
70
+ database = database_from_handle(handle, environment)
63
71
  local_port = options[:port] || random_local_port
64
72
 
65
73
  say 'Creating tunnel...', :green
@@ -77,8 +85,10 @@ module Aptible
77
85
  end
78
86
 
79
87
  desc 'db:deprovision HANDLE', 'Deprovision a database'
88
+ option :environment
80
89
  define_method 'db:deprovision' do |handle|
81
- database = database_from_handle(handle)
90
+ environment = ensure_environment(options)
91
+ database = database_from_handle(handle, environment)
82
92
  say "Deprovisioning #{handle}..."
83
93
  database.update!(status: 'deprovisioned')
84
94
  database.create_operation!(type: 'deprovision')
@@ -86,9 +96,9 @@ module Aptible
86
96
 
87
97
  private
88
98
 
89
- def present_account_databases(account)
90
- say "=== #{account.handle}"
91
- account.databases.each { |db| say db.handle }
99
+ def present_environment_databases(environment)
100
+ say "=== #{environment.handle}"
101
+ environment.databases.each { |db| say db.handle }
92
102
  say ''
93
103
  end
94
104
 
@@ -104,8 +114,10 @@ module Aptible
104
114
  Kernel.exec(command)
105
115
  end
106
116
 
107
- def database_from_handle(handle, options = { postgres_only: false })
108
- all = Aptible::Api::Database.all(token: fetch_token)
117
+ def database_from_handle(handle,
118
+ environment,
119
+ options = { postgres_only: false })
120
+ all = environment.databases
109
121
  database = all.find { |a| a.handle == handle }
110
122
 
111
123
  unless database
@@ -119,16 +131,16 @@ module Aptible
119
131
  database
120
132
  end
121
133
 
122
- def clone_database(source_handle, dest_handle)
123
- source = database_from_handle(source_handle)
134
+ def clone_database(source_handle, dest_handle, environment)
135
+ source = database_from_handle(source_handle, environment)
124
136
  op = source.create_operation(type: 'clone', handle: dest_handle)
125
137
  poll_for_success(op)
126
138
 
127
139
  database_from_handle(dest_handle)
128
140
  end
129
141
 
130
- def dump_database(handle)
131
- execute_local_tunnel(handle) do |url|
142
+ def dump_database(handle, environment)
143
+ execute_local_tunnel(handle, environment) do |url|
132
144
  filename = "#{handle}.dump"
133
145
  say "Dumping to #{filename}"
134
146
  `pg_dump #{url} > #{filename}`
@@ -137,8 +149,10 @@ module Aptible
137
149
 
138
150
  # Creates a local tunnel and yields the url to it
139
151
 
140
- def execute_local_tunnel(handle)
141
- database = database_from_handle(handle, postgres_only: true)
152
+ def execute_local_tunnel(handle, environment)
153
+ database = database_from_handle(handle,
154
+ environment,
155
+ postgres_only: true)
142
156
 
143
157
  local_port = random_local_port
144
158
  pid = fork { establish_connection(database, local_port) }
@@ -11,6 +11,7 @@ module Aptible
11
11
 
12
12
  desc 'domains', "Print an app's current virtual domains"
13
13
  option :app
14
+ option :environment
14
15
  option :verbose, aliases: '-v'
15
16
  option :remote, aliases: '-r'
16
17
  def domains
@@ -1,5 +1,5 @@
1
1
  module Aptible
2
2
  module CLI
3
- VERSION = '0.5.15'
3
+ VERSION = '0.6.0'
4
4
  end
5
5
  end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe Aptible::CLI::Helpers::App::HandleFromGitRemote do
4
+ it 'should parse handle from remote without account' do
5
+ str = 'git@test.aptible.com:test-app.git'
6
+ result = described_class.parse(str)[:app_handle]
7
+ expect(result).not_to be nil
8
+ expect(result).to eql 'test-app'
9
+ end
10
+
11
+ it 'should parse handle from remote with account' do
12
+ str = 'git@test.aptible.com:test-account/test-app.git'
13
+ result = described_class.parse(str)[:app_handle]
14
+ expect(result).not_to be nil
15
+ expect(result).to eql 'test-app'
16
+ end
17
+ end
@@ -21,7 +21,11 @@ describe Aptible::CLI::Agent do
21
21
 
22
22
  let(:service) { Service.new(process_type: 'web') }
23
23
  let(:op) { Operation.new(status: 'succeeded') }
24
- let(:account) { Account.new(bastion_host: 'localhost', dumptruck_port: 1234) }
24
+ let(:account) do
25
+ Account.new(bastion_host: 'localhost',
26
+ dumptruck_port: 1234,
27
+ handle: 'aptible')
28
+ end
25
29
  let(:apps) do
26
30
  [App.new(handle: 'hello', services: [service], account: account)]
27
31
  end
@@ -31,14 +35,27 @@ describe Aptible::CLI::Agent do
31
35
  allow(service).to receive(:create_operation) { op }
32
36
  allow(subject).to receive(:options) { { app: 'hello' } }
33
37
  allow(op).to receive(:resource) { apps.first }
34
- allow(Aptible::Api::App).to receive(:all) { apps }
38
+ allow(Aptible::Api::Account).to receive(:all) { [account] }
39
+ allow(account).to receive(:apps) { apps }
35
40
 
36
41
  subject.send('apps:scale', 'web', 3)
37
42
  end
38
43
 
44
+ it 'should fail if environment is non-existent' do
45
+ allow(subject).to receive(:options) { { environment: 'foo', app: 'web' } }
46
+ allow(service).to receive(:create_operation) { op }
47
+ allow(Aptible::Api::Account).to receive(:all) { [] }
48
+ allow(account).to receive(:apps) { [apps] }
49
+
50
+ expect do
51
+ subject.send('apps:scale', 'web', 3)
52
+ end.to raise_error(Thor::Error)
53
+ end
54
+
39
55
  it 'should fail if app is non-existent' do
40
56
  allow(service).to receive(:create_operation) { op }
41
- allow(Aptible::Api::App).to receive(:all) { apps }
57
+ allow(Aptible::Api::Account).to receive(:all) { [account] }
58
+ allow(account).to receive(:apps) { [] }
42
59
 
43
60
  expect do
44
61
  subject.send('apps:scale', 'web', 3)
@@ -14,6 +14,11 @@ describe Aptible::CLI::Agent do
14
14
  before { subject.stub(:random_local_port) { 4242 } }
15
15
  before { subject.stub(:establish_connection) }
16
16
 
17
+ let(:account) do
18
+ Account.new(bastion_host: 'localhost',
19
+ dumptruck_port: 1234,
20
+ handle: 'aptible')
21
+ end
17
22
  let(:database) do
18
23
  Database.new(
19
24
  type: 'postgresql',
@@ -25,14 +30,16 @@ describe Aptible::CLI::Agent do
25
30
 
26
31
  describe '#db:tunnel' do
27
32
  it 'should fail if database is non-existent' do
28
- allow(Aptible::Api::Database).to receive(:all) { [] }
33
+ allow(Aptible::Api::Account).to receive(:all) { [account] }
34
+ allow(account).to receive(:databases) { [] }
29
35
  expect do
30
36
  subject.send('db:tunnel', 'foobar')
31
37
  end.to raise_error('Could not find database foobar')
32
38
  end
33
39
 
34
40
  it 'should print a message about how to connect' do
35
- allow(Aptible::Api::Database).to receive(:all) { [database] }
41
+ allow(Aptible::Api::Account).to receive(:all) { [account] }
42
+ allow(account).to receive(:databases) { [database] }
36
43
  local_url = 'postgresql://aptible:password@127.0.0.1:4242/db'
37
44
  expect(subject).to receive(:say).with('Creating tunnel...', :green)
38
45
  expect(subject).to receive(:say).with("Connect at #{local_url}", :green)
@@ -66,7 +73,7 @@ describe Aptible::CLI::Agent do
66
73
  setup_prod_and_staging_accounts
67
74
  allow(subject).to receive(:say)
68
75
 
69
- subject.options = { account: 'staging' }
76
+ subject.options = { environment: 'staging' }
70
77
  subject.send('db:list')
71
78
 
72
79
  expect(subject).to have_received(:say).with('=== staging')
@@ -84,7 +91,7 @@ describe Aptible::CLI::Agent do
84
91
  setup_prod_and_staging_accounts
85
92
  allow(subject).to receive(:say)
86
93
 
87
- subject.options = { account: 'foo' }
94
+ subject.options = { environment: 'foo' }
88
95
  expect { subject.send('db:list') }.to raise_error(
89
96
  'Specified account does not exist'
90
97
  )
@@ -22,6 +22,11 @@ describe Aptible::CLI::Agent do
22
22
  let(:op) { Operation.new(status: 'succeeded') }
23
23
  let(:app) { App.new(handle: 'hello', services: [service]) }
24
24
  let(:apps) { [app] }
25
+ let(:account) do
26
+ Account.new(bastion_host: 'localhost',
27
+ dumptruck_port: 1234,
28
+ handle: 'aptible')
29
+ end
25
30
 
26
31
  let(:vhost1) { Vhost.new(virtual_domain: 'domain1', external_host: 'host1') }
27
32
  let(:vhost2) { Vhost.new(virtual_domain: 'domain2', external_host: 'host2') }
@@ -30,7 +35,8 @@ describe Aptible::CLI::Agent do
30
35
  it 'should print out the hostnames' do
31
36
  allow(service).to receive(:create_operation) { op }
32
37
  allow(subject).to receive(:options) { { app: 'hello' } }
33
- allow(Aptible::Api::App).to receive(:all) { apps }
38
+ allow(Aptible::Api::Account).to receive(:all) { [account] }
39
+ allow(account).to receive(:apps) { apps }
34
40
 
35
41
  expect(app).to receive(:vhosts) { [vhost1, vhost2] }
36
42
  expect(subject).to receive(:say).with('domain1')
@@ -41,7 +47,18 @@ describe Aptible::CLI::Agent do
41
47
 
42
48
  it 'should fail if app is non-existent' do
43
49
  allow(service).to receive(:create_operation) { op }
44
- allow(Aptible::Api::App).to receive(:all) { apps }
50
+ allow(Aptible::Api::Account).to receive(:all) { [account] }
51
+ allow(account).to receive(:apps) { apps }
52
+
53
+ expect do
54
+ subject.send('domains')
55
+ end.to raise_error(Thor::Error)
56
+ end
57
+
58
+ it 'should fail if environment is non-existent' do
59
+ allow(service).to receive(:create_operation) { op }
60
+ allow(Aptible::Api::Account).to receive(:all) { [] }
61
+ allow(account).to receive(:apps) { apps }
45
62
 
46
63
  expect do
47
64
  subject.send('domains')
@@ -51,7 +68,8 @@ describe Aptible::CLI::Agent do
51
68
  it 'should print hostnames if -v is passed' do
52
69
  allow(service).to receive(:create_operation) { op }
53
70
  allow(subject).to receive(:options) { { verbose: true, app: 'hello' } }
54
- allow(Aptible::Api::App).to receive(:all) { apps }
71
+ allow(Aptible::Api::Account).to receive(:all) { [account] }
72
+ allow(account).to receive(:apps) { apps }
55
73
 
56
74
  expect(app).to receive(:vhosts) { [vhost1, vhost2] }
57
75
  expect(subject).to receive(:say).with('domain1 -> host1')
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.5.15
4
+ version: 0.6.0
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-01-13 00:00:00.000000000 Z
11
+ date: 2016-02-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aptible-api
@@ -170,9 +170,9 @@ files:
170
170
  - bin/aptible
171
171
  - lib/aptible/cli.rb
172
172
  - lib/aptible/cli/agent.rb
173
- - lib/aptible/cli/helpers/account.rb
174
173
  - lib/aptible/cli/helpers/app.rb
175
174
  - lib/aptible/cli/helpers/env.rb
175
+ - lib/aptible/cli/helpers/environment.rb
176
176
  - lib/aptible/cli/helpers/operation.rb
177
177
  - lib/aptible/cli/helpers/token.rb
178
178
  - lib/aptible/cli/subcommands/apps.rb
@@ -186,6 +186,7 @@ files:
186
186
  - lib/aptible/cli/subcommands/ssh.rb
187
187
  - lib/aptible/cli/version.rb
188
188
  - spec/aptible/cli/agent_spec.rb
189
+ - spec/aptible/cli/helpers/handle_from_git_remote.rb
189
190
  - spec/aptible/cli/subcommands/apps_spec.rb
190
191
  - spec/aptible/cli/subcommands/db_spec.rb
191
192
  - spec/aptible/cli/subcommands/domains_spec.rb
@@ -212,12 +213,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
212
213
  version: '0'
213
214
  requirements: []
214
215
  rubyforge_project:
215
- rubygems_version: 2.2.2
216
+ rubygems_version: 2.4.5
216
217
  signing_key:
217
218
  specification_version: 4
218
219
  summary: Command-line interface for Aptible services
219
220
  test_files:
220
221
  - spec/aptible/cli/agent_spec.rb
222
+ - spec/aptible/cli/helpers/handle_from_git_remote.rb
221
223
  - spec/aptible/cli/subcommands/apps_spec.rb
222
224
  - spec/aptible/cli/subcommands/db_spec.rb
223
225
  - spec/aptible/cli/subcommands/domains_spec.rb
@@ -1,49 +0,0 @@
1
- require 'aptible/api'
2
- require 'git'
3
-
4
- module Aptible
5
- module CLI
6
- module Helpers
7
- module Account
8
- include Helpers::Token
9
-
10
- def scoped_accounts(options)
11
- if options[:account]
12
- if (account = account_from_handle(options[:account]))
13
- [account]
14
- else
15
- fail Thor::Error, 'Specified account does not exist'
16
- end
17
- else
18
- Aptible::Api::Account.all(token: fetch_token)
19
- end
20
- end
21
-
22
- def ensure_account(options = {})
23
- if (handle = options[:account])
24
- account = account_from_handle(handle)
25
- return account if account
26
- fail "Could not find account #{handle}"
27
- else
28
- ensure_default_account
29
- end
30
- end
31
-
32
- def account_from_handle(handle)
33
- Aptible::Api::Account.all(token: fetch_token).find do |a|
34
- a.handle == handle
35
- end
36
- end
37
-
38
- def ensure_default_account
39
- accounts = Aptible::Api::Account.all(token: fetch_token)
40
- return accounts.first if accounts.count == 1
41
-
42
- fail Thor::Error, <<-ERR.gsub(/\s+/, ' ').strip
43
- Multiple accounts available, please specify with --account
44
- ERR
45
- end
46
- end
47
- end
48
- end
49
- end