tugboat 0.2.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +5 -4
  4. data/CHANGELOG.md +325 -102
  5. data/CHANGELOG_old.md +150 -0
  6. data/Gemfile +6 -0
  7. data/README.md +12 -6
  8. data/Rakefile +7 -3
  9. data/features/step_definitions/steps.rb +0 -0
  10. data/features/support/env.rb +9 -0
  11. data/features/vagrant-adam/config_current_directory.feature +27 -0
  12. data/lib/tugboat/cli.rb +31 -3
  13. data/lib/tugboat/config.rb +13 -5
  14. data/lib/tugboat/middleware.rb +8 -0
  15. data/lib/tugboat/middleware/ask_for_credentials.rb +5 -4
  16. data/lib/tugboat/middleware/authentication_middleware.rb +2 -2
  17. data/lib/tugboat/middleware/config.rb +29 -0
  18. data/lib/tugboat/middleware/custom_logger.rb +2 -2
  19. data/lib/tugboat/middleware/find_droplet.rb +4 -0
  20. data/lib/tugboat/middleware/info_droplet.rb +5 -0
  21. data/lib/tugboat/middleware/inject_client.rb +1 -1
  22. data/lib/tugboat/middleware/list_droplets.rb +5 -1
  23. data/lib/tugboat/middleware/list_regions.rb +2 -2
  24. data/lib/tugboat/middleware/ssh_droplet.rb +17 -2
  25. data/lib/tugboat/version.rb +1 -1
  26. data/spec/cli/add_key_spec.rb +9 -9
  27. data/spec/cli/authorize_cli_spec.rb +76 -52
  28. data/spec/cli/create_cli_spec.rb +39 -4
  29. data/spec/cli/debug_cli_spec.rb +44 -0
  30. data/spec/cli/destroy_cli_spec.rb +30 -11
  31. data/spec/cli/destroy_image_cli_spec.rb +11 -11
  32. data/spec/cli/droplets_cli_spec.rb +6 -6
  33. data/spec/cli/halt_cli_spec.rb +9 -9
  34. data/spec/cli/images_cli_spec.rb +6 -6
  35. data/spec/cli/info_cli_spec.rb +42 -7
  36. data/spec/cli/info_image_cli_spec.rb +6 -6
  37. data/spec/cli/keys_cli_spec.rb +1 -1
  38. data/spec/cli/password_reset_cli_spec.rb +8 -8
  39. data/spec/cli/rebuild_cli_spec.rb +49 -49
  40. data/spec/cli/regions_cli_spec.rb +4 -4
  41. data/spec/cli/resize_cli_spec.rb +8 -8
  42. data/spec/cli/restart_cli_spec.rb +8 -8
  43. data/spec/cli/sizes_cli_spec.rb +1 -1
  44. data/spec/cli/snapshot_cli_spec.rb +7 -7
  45. data/spec/cli/ssh_cli_spec.rb +4 -4
  46. data/spec/cli/start_cli_spec.rb +7 -7
  47. data/spec/cli/verify_cli_spec.rb +10 -2
  48. data/spec/cli/wait_cli_spec.rb +6 -6
  49. data/spec/fixtures/500.html +68 -0
  50. data/spec/fixtures/show_droplet.json +1 -0
  51. data/spec/fixtures/show_droplet_fuzzy.json +13 -0
  52. data/spec/fixtures/show_droplet_inactive.json +1 -0
  53. data/spec/fixtures/show_droplets.json +2 -0
  54. data/spec/fixtures/show_droplets_fuzzy.json +35 -0
  55. data/spec/fixtures/show_droplets_inactive.json +2 -0
  56. data/spec/fixtures/show_regions.json +9 -6
  57. data/spec/middleware/base_spec.rb +1 -1
  58. data/spec/middleware/check_credentials_spec.rb +1 -1
  59. data/spec/middleware/inject_client_spec.rb +29 -0
  60. data/spec/middleware/inject_configuration_spec.rb +1 -1
  61. data/spec/middleware/ssh_droplet_spec.rb +30 -7
  62. data/spec/shared/environment.rb +1 -0
  63. data/spec/spec_helper.rb +11 -4
  64. data/tugboat.gemspec +9 -7
  65. metadata +64 -33
data/CHANGELOG_old.md ADDED
@@ -0,0 +1,150 @@
1
+ ## 0.2.1 (UNRELEASED)
2
+
3
+
4
+ ## 0.2.0 (Feburary 15, 2014)
5
+
6
+ FEATURES:
7
+
8
+ - [Pierre](https://github.com/spearway) added an `info-image` and `destroy-image`
9
+ command, letting you deal with your images from Tugboat. It's great. [GH-91]
10
+ - [Pierre](https://github.com/spearway) also added a `rebuild` command,
11
+ letting you take an existing droplet and recreate it from scratch. [GH-90]
12
+
13
+ IMPROVEMENTS:
14
+
15
+ - [Dale](https://github.com/Vel0x) made it so fuzzy name searching
16
+ is case insensitive. We wonder why we didn't do this earlier, really. [GH-88]
17
+ - There is now a `--quiet/-q` flag, which makes Tugboat be silent, as it
18
+ can get a little obnoxious. [GH-87]
19
+ - [Andrew](https://github.com/4n3w) hooked up a `backups_enabled` option
20
+ for creating droplets. [GH-82]
21
+
22
+
23
+ ## 0.0.9 (December 24, 2013)
24
+
25
+ FEATURES:
26
+
27
+ - [Pete](https://github.com/petems) added the ability to add an
28
+ ssh key to your account. [GH-64]
29
+ - [Caleb](https://github.com/calebreach) gave us an easy way
30
+ to pass a command through to a machine with the `-c` command. [GH-73]
31
+
32
+ IMPROVEMENTS:
33
+
34
+ - [Andrew](https://github.com/4n3w) added a private networking option. [GH-75]
35
+
36
+ BUG FIXES:
37
+
38
+ - [Zo](https://github.com/obradovic) made our default image 13.04 [GH-76]
39
+ - Issues with the JSON dependency in 2.0.0 were resolved. [GH-80]
40
+
41
+
42
+ ## 0.0.8 (September 7, 2013)
43
+
44
+ FEATURES:
45
+
46
+ - [Pete](https://github.com/petems) added configuration defaults
47
+ that you can set. [GH-61]
48
+ - [Pete](https://github.com/petems) added log filtering to debug output.
49
+ `DEBUG=1` now gives you filtered logs, `DEBUG=2`, raw. [GH-58]
50
+
51
+ IMPROVEMENTS:
52
+
53
+ - Error messages are now caught at the Faraday level and displayed
54
+ back to the user.
55
+
56
+ BUG FIXES:
57
+
58
+ - [Ørjan](https://github.com/blom) added a color reset on the `list`
59
+ command. [GH-57]
60
+
61
+ ## 0.0.7 (August 2, 2013)
62
+
63
+ IMPROVEMENTS:
64
+
65
+ - [Pete](https://github.com/petems) made it clearer to the user
66
+ if they don't have any droplets or images. [GH-48], [GH-49]
67
+
68
+ BUG FIXES:
69
+
70
+ - Fix the initial check for authorization after `authorize` [GH-41]
71
+
72
+ ## 0.0.6 (June 25, 2013)
73
+
74
+ FEATURES:
75
+
76
+ - [Ørjan](https://github.com/blom) added a `start` command, which
77
+ let's you start a droplet. [GH-30]
78
+ - [Ørjan](https://github.com/blom) added a `resize` command, which
79
+ let's you resize a droplet. [GH-40]
80
+ - [Ørjan](https://github.com/blom) added a `password-reset` command
81
+ [GH-45]
82
+ - Added a the `wait` command, allowing you to "wait" for a droplet
83
+ to enter a state. [GH-46]
84
+
85
+ IMPROVEMENTS:
86
+
87
+ - [Ørjan](https://github.com/blom) added an `--ssh-opts` flag, for the
88
+ `ssh` command. [GH-38]
89
+ - Droplet state is checked for some commands. For example, a droplet
90
+ can't be started if it's active. [GH-31]
91
+
92
+ BUG FIXES:
93
+
94
+ - DigitalOcean changed their `image_id`'s, so the defaults for `create`
95
+ were updated. [GH-39]
96
+
97
+ ## 0.0.5 (May 4, 2013)
98
+
99
+ FEATURES:
100
+
101
+ - [Ørjan](https://github.com/blom) added a `regions` command, which
102
+ returns a list of available DigitalOcean regions. You can specify
103
+ which region to use while creating: `tugboat create foobar -r 2`. [GH-18]
104
+ - [Ørjan](https://github.com/blom) added an ssh_user option to the
105
+ `ssh` command. This lets you specify the user to connect as on
106
+ a per-command basis, as well as in your `.tugboat`.
107
+ - [Ørjan](https://github.com/blom) added a `sizes` command, which
108
+ returns a list of available sizes. You can specify which size to
109
+ use while creating: `tugboat create foobar -s 66` [GH-19]
110
+ - [Ørjan](https://github.com/blom) added a `hard` flag to
111
+ `halt` and `restart`. This cycles the Droplet's power. `tugboat restart --hard` [GH-27]
112
+
113
+ IMPROVEMENTS:
114
+
115
+ - Tugboat now returns proper status codes for successes and failures.
116
+ [GH-21]
117
+ - Support for MRI 1.8.7
118
+ - CTRL+C's, SIG-INT's are now caught and quietly kill Tugboat without
119
+ a stacktrace.
120
+
121
+ ## 0.0.4 (April 23, 2013)
122
+
123
+ BUG FIXES:
124
+
125
+ - Fix a syntax error caused by the order of arguments on `snapshot`.
126
+ This changes the argument order and is a breaking change [GH-10].
127
+ - Fix an issue with looking up a droplet by it's `--name`. A variable
128
+ was changed, and because it was shadowed passed inspection.
129
+
130
+ IMPROVEMENTS:
131
+
132
+ - Added a warning for snapshotting a droplet in a non-powered off
133
+ state. DigitalOcean currently doesn't return an error from their API.
134
+ - Added a `--confirm` or `-c` to confirmed actions, like destroy. [GH-7]
135
+ - [Ørjan](https://github.com/blom) added a `--version` command to see
136
+ what version of Tugboat you're using.
137
+ - Substantially more test coverage - all of the commands (except `ssh` are
138
+ now integration tested. [GH-15]
139
+
140
+ FEATURES:
141
+
142
+ - Optionally add a list of ssh_key_ids when creating a droplet. These
143
+ SSH keys will automatically be added to your droplet.
144
+ - Show a list of SSH keys on your account with `tugboat keys`
145
+ - [Phil](https://github.com/PhilETaylor) added the ability to specify
146
+ an `--ssh-port` on `tugboat ssh`, as well as set a default in your `.tugboat` [GH-13]
147
+
148
+ ## 0.0.3 (April 15, 2013)
149
+
150
+ Initial release.
data/Gemfile CHANGED
@@ -2,3 +2,9 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in tugboat.gemspec
4
4
  gemspec
5
+
6
+ group :development do
7
+ # Random order is not in the Aruba Cucumber yet...
8
+ gem 'cucumber', git: 'https://github.com/cucumber/cucumber.git', tag: 'v2.0.0.beta.2'
9
+ gem 'cucumber-core', git: 'https://github.com/cucumber/cucumber-core.git', tag: 'v1.0.0.beta.2'
10
+ end
data/README.md CHANGED
@@ -8,10 +8,12 @@ A command line tool for interacting with your [DigitalOcean](https://www.digital
8
8
 
9
9
  gem install tugboat
10
10
 
11
+ Please note that Tugboat version 0.2.0 and up requires Ruby 1.9 or higher.
12
+
11
13
  ## Configuration
12
14
 
13
15
  Run the configuration utility, `tugboat authorize`. You can grab your keys
14
- [here](https://www.digitalocean.com/api_access).
16
+ [here](https://cloud.digitalocean.com/api_access).
15
17
 
16
18
  $ tugboat authorize
17
19
  Enter your client key: foo
@@ -30,6 +32,10 @@ Run the configuration utility, `tugboat authorize`. You can grab your keys
30
32
 
31
33
  Authentication with DigitalOcean was successful!
32
34
 
35
+ This will create a .tugboat file in your home folder (eg. ~/.tugboat).
36
+
37
+ Tugboat will look for a .tugboat config file first in the current directory you're running it in, then will look for one in the home directory.
38
+
33
39
  ## Usage
34
40
 
35
41
  ### Retrieve a list of your droplets
@@ -153,9 +159,9 @@ Optionally, list images provided by DigitalOcean as well.
153
159
 
154
160
  $ tugboat regions
155
161
  Regions:
156
- New York 1 (id: 1)
157
- Amsterdam 1 (id: 2)
158
- San Francisco 1 (id: 3)
162
+ New York 1 (id: 1) (slug: nyc1)
163
+ Amsterdam 1 (id: 2) (slug: ams1)
164
+ San Francisco 1 (id: 3) (slug: sfo1)
159
165
 
160
166
  ### List SSH Keys
161
167
 
@@ -188,9 +194,9 @@ ask tugboat about it.
188
194
  For a complete overview of all of the available commands, run:
189
195
 
190
196
  $ tugboat help
191
-
192
197
 
193
- Depending on your local configuration, you may need to install a CA bundle (OS X only) using [homebrew](http://brew.sh/) to commmunicate with DigitalOcean through SSL/TLS:
198
+
199
+ Depending on your local configuration, you may need to install a CA bundle (OS X only) using [homebrew](http://brew.sh/) to communicate with DigitalOcean through SSL/TLS:
194
200
 
195
201
  $ brew install curl-ca-bundle
196
202
 
data/Rakefile CHANGED
@@ -1,7 +1,11 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler/gem_tasks'
2
2
  require 'rspec/core/rake_task'
3
-
3
+ require 'cucumber/rake/task'
4
4
 
5
5
  RSpec::Core::RakeTask.new(:spec)
6
6
 
7
- task :default => :spec
7
+ Cucumber::Rake::Task.new(:features) do |t|
8
+ t.cucumber_opts = %w(--format pretty --order random)
9
+ end
10
+
11
+ task :default => [:spec, :features]
File without changes
@@ -0,0 +1,9 @@
1
+ require 'aruba/cucumber'
2
+
3
+ Before do
4
+
5
+ end
6
+
7
+ After do
8
+
9
+ end
@@ -0,0 +1,27 @@
1
+ Feature: config
2
+ In order to easily load DigitalOcean config
3
+ As a user
4
+ I should be able to load tugboat config from a .tugboat in the current directory
5
+
6
+ Scenario:
7
+ Given a file named ".tugboat" with:
8
+ """
9
+ ---
10
+ authentication:
11
+ client_key: FOO
12
+ api_key: BAR
13
+ ssh:
14
+ ssh_user: janedoe
15
+ ssh_key_path: "/Users/janedoe/.ssh/id_rsa"
16
+ ssh_port: '22'
17
+ defaults:
18
+ region: '8'
19
+ image: '9801950'
20
+ size: '66'
21
+ ssh_key: ''
22
+ private_networking: 'false'
23
+ backups_enabled: 'false'
24
+ """
25
+ When I run `tugboat config`
26
+ Then the exit status should not be 1
27
+ And the output should contain "ssh_user: janedoe"
data/lib/tugboat/cli.rb CHANGED
@@ -28,7 +28,7 @@ module Tugboat
28
28
  details to tugboat. First, you are asked for your API and Client keys,
29
29
  which are stored in ~/.tugboat.
30
30
 
31
- You can retrieve your credentials from digitalocean.com/api_access.
31
+ You can retrieve your credentials from https://cloud.digitalocean.com/api_access
32
32
 
33
33
  Optionally, you can configure the default SSH key path and username
34
34
  used for `tugboat ssh`. These default to '~/.ssh/id_rsa' and the
@@ -40,6 +40,21 @@ module Tugboat
40
40
  })
41
41
  end
42
42
 
43
+ desc "config", "Show your current config information"
44
+ long_desc "This shows the current information in the .tugboat config
45
+ being used by the app
46
+ "
47
+ method_option "hide",
48
+ :type => :boolean,
49
+ :default => true,
50
+ :aliases => "-h",
51
+ :desc => "Hide your API keys"
52
+ def config
53
+ Middleware.sequence_config.call({
54
+ "user_hide_keys" => options[:hide],
55
+ })
56
+ end
57
+
43
58
  desc "verify", "Check your DigitalOcean credentials"
44
59
  long_desc "This tests that your credentials created by the \`authorize\`
45
60
  command that are stored in ~/.tugboat are correct and allow you to connect
@@ -58,7 +73,7 @@ module Tugboat
58
73
  })
59
74
  end
60
75
 
61
- desc "images", "Retrieve a list of your images"
76
+ desc "images [OPTIONS]", "Retrieve a list of your images"
62
77
  method_option "global",
63
78
  :type => :boolean,
64
79
  :default => false,
@@ -84,6 +99,10 @@ module Tugboat
84
99
  :type => :string,
85
100
  :aliases => "-p",
86
101
  :desc => "The custom SSH Port to connect to"
102
+ method_option "use_public_ip",
103
+ :type => :boolean,
104
+ :aliases => "-e",
105
+ :desc => "Use public IP while private IP is present"
87
106
  method_option "ssh_user",
88
107
  :type => :string,
89
108
  :aliases => "-u",
@@ -103,6 +122,7 @@ module Tugboat
103
122
  "user_droplet_fuzzy_name" => name,
104
123
  "user_droplet_ssh_port" => options[:ssh_port],
105
124
  "user_droplet_ssh_user" => options[:ssh_user],
125
+ "user_droplet_use_public_ip" => options[:use_public_ip],
106
126
  "user_droplet_ssh_opts" => options[:ssh_opts],
107
127
  "user_droplet_ssh_command" => options[:ssh_command],
108
128
  "user_quiet" => options[:quiet]
@@ -136,6 +156,11 @@ module Tugboat
136
156
  :desc => "Enable backups on the droplet"
137
157
 
138
158
  def create(name)
159
+ if name =~ /^(-{0,2}help|-{1,2}h)/
160
+ help('create')
161
+ return
162
+ end
163
+
139
164
  Middleware.sequence_create_droplet.call({
140
165
  "create_droplet_size_id" => options[:size],
141
166
  "create_droplet_image_id" => options[:image],
@@ -334,7 +359,10 @@ module Tugboat
334
359
  Middleware.sequence_ssh_keys.call({})
335
360
  end
336
361
 
337
- desc "add-key NAME", "Upload an ssh public key."
362
+ desc "add-key KEY-NAME", "Upload an ssh public key to DigitalOcean, to be assigned to a droplet later"
363
+ long_desc "This uploads a ssh-key to DigitalOcean, which you can then assign to a droplet at
364
+ creation time so you can connect to it with the key rather than a password.
365
+ "
338
366
  method_option "key",
339
367
  :type => :string,
340
368
  :aliases => "-k",
@@ -12,15 +12,19 @@ module Tugboat
12
12
  FILE_NAME = '.tugboat'
13
13
  DEFAULT_SSH_KEY_PATH = '.ssh/id_rsa'
14
14
  DEFAULT_SSH_PORT = '22'
15
- DEFAULT_REGION = '1'
16
- DEFAULT_IMAGE = '350076'
15
+ DEFAULT_REGION = '8'
16
+ DEFAULT_IMAGE = '9801950'
17
17
  DEFAULT_SIZE = '66'
18
18
  DEFAULT_SSH_KEY = ''
19
19
  DEFAULT_PRIVATE_NETWORKING = 'false'
20
20
  DEFAULT_BACKUPS_ENABLED = 'false'
21
21
 
22
+ # Load config file from current directory, if not exit load from user's home directory
22
23
  def initialize
23
- @path = ENV["TUGBOAT_CONFIG_PATH"] || File.join(File.expand_path("~"), FILE_NAME)
24
+ @path = File.join(File.expand_path("."), FILE_NAME)
25
+ unless File.exists?(@path)
26
+ @path = ( ENV["TUGBOAT_CONFIG_PATH"] || File.join(File.expand_path("~"), FILE_NAME) )
27
+ end
24
28
  @data = self.load_config_file
25
29
  end
26
30
 
@@ -53,6 +57,10 @@ module Tugboat
53
57
  @data['ssh']['ssh_port']
54
58
  end
55
59
 
60
+ def use_public_ip
61
+ @data['use_public_ip']
62
+ end
63
+
56
64
  def default_region
57
65
  @data['defaults'].nil? ? DEFAULT_REGION : @data['defaults']['region']
58
66
  end
@@ -91,11 +99,11 @@ module Tugboat
91
99
  def create_config_file(client, api, ssh_key_path, ssh_user, ssh_port, region, image, size, ssh_key, private_networking, backups_enabled)
92
100
  # Default SSH Key path
93
101
  if ssh_key_path.empty?
94
- ssh_key_path = File.join(File.expand_path("~"), DEFAULT_SSH_KEY_PATH)
102
+ ssh_key_path = File.join("~", DEFAULT_SSH_KEY_PATH)
95
103
  end
96
104
 
97
105
  if ssh_user.empty?
98
- ssh_user = ENV['USER']
106
+ ssh_user = 'root'
99
107
  end
100
108
 
101
109
  if ssh_port.empty?
@@ -9,6 +9,7 @@ module Tugboat
9
9
  autoload :CheckCredentials, "tugboat/middleware/check_credentials"
10
10
  autoload :CheckDropletActive, "tugboat/middleware/check_droplet_active"
11
11
  autoload :CheckDropletInactive, "tugboat/middleware/check_droplet_inactive"
12
+ autoload :Config, "tugboat/middleware/config"
12
13
  autoload :ConfirmAction, "tugboat/middleware/confirm_action"
13
14
  autoload :CreateDroplet, "tugboat/middleware/create_droplet"
14
15
  autoload :RebuildDroplet, "tugboat/middleware/rebuild_droplet"
@@ -267,6 +268,13 @@ module Tugboat
267
268
  end
268
269
  end
269
270
 
271
+ # Returns current used config
272
+ def self.sequence_config
273
+ ::Middleware::Builder.new do
274
+ use Config
275
+ end
276
+ end
277
+
270
278
  # Wait for a droplet to enter a desired state
271
279
  def self.sequence_wait
272
280
  ::Middleware::Builder.new do
@@ -3,19 +3,20 @@ module Tugboat
3
3
  # Ask for user credentials from the command line, then write them out.
4
4
  class AskForCredentials < Base
5
5
  def call(env)
6
- say "Note: You can get this information from digitalocean.com/api_access", :yellow
6
+ say "Note: You can get this information from https://cloud.digitalocean.com/api_access", :yellow
7
+ say "Also Note: Tugboat is setup to work with v1 of the Digital Ocean API (https://developers.digitalocean.com/v1/)", :yellow
7
8
  say
8
9
  client_key = ask "Enter your client key:"
9
10
  api_key = ask "Enter your API key:"
10
11
  ssh_key_path = ask "Enter your SSH key path (optional, defaults to ~/.ssh/id_rsa):"
11
- ssh_user = ask "Enter your SSH user (optional, defaults to #{ENV['USER']}):"
12
+ ssh_user = ask "Enter your SSH user (optional, defaults to root):"
12
13
  ssh_port = ask "Enter your SSH port number (optional, defaults to 22):"
13
14
  say
14
15
  say "To retrieve region, image, size and key ID's, you can use the corresponding tugboat command, such as `tugboat images`."
15
16
  say "Defaults can be changed at any time in your ~/.tugboat configuration file."
16
17
  say
17
- region = ask "Enter your default region ID (optional, defaults to 1 (New York)):"
18
- image = ask "Enter your default image ID (optional, defaults to 350076 (Ubuntu 13.04 x64)):"
18
+ region = ask "Enter your default region ID (optional, defaults to 8 (New York 3)):"
19
+ image = ask "Enter your default image ID (optional, defaults to 9801950 (Ubuntu 14.04 x64)):"
19
20
  size = ask "Enter your default size ID (optional, defaults to 66 (512MB)):"
20
21
  ssh_key = ask "Enter your default ssh key ID (optional, defaults to none):"
21
22
  private_networking = ask "Enter your default for private networking (optional, defaults to false):"
@@ -21,10 +21,10 @@ module Tugboat
21
21
  @app.call(env)
22
22
  rescue Faraday::Error::ClientError => e
23
23
  puts "#{RED}#{e}!#{CLEAR}\n"
24
- if env[:body].status == "ERROR"
24
+ if env[:body].is_a?(Hashie::Rash)
25
25
  puts "\n#{RED}#{env[:body].error_message}#{CLEAR}\n\n"
26
26
  end
27
- puts "Double-check your parameters and configuration (in your ~/.tugboat file)"
27
+ puts "Double-check your parameters and configuration (in your ~/.tugboat file)" if env[:status] == 401
28
28
  exit 1
29
29
  end
30
30
  end