tugboat 3.1.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -1
  3. data/CODE_OF_CONDUCT.md +46 -0
  4. data/lib/tugboat/cli.rb +7 -1
  5. data/lib/tugboat/config.rb +11 -1
  6. data/lib/tugboat/middleware.rb +2 -0
  7. data/lib/tugboat/middleware/ask_for_credentials.rb +2 -1
  8. data/lib/tugboat/middleware/base.rb +31 -13
  9. data/lib/tugboat/middleware/check_snapshot_parameters.rb +16 -0
  10. data/lib/tugboat/middleware/info_droplet.rb +2 -2
  11. data/lib/tugboat/middleware/inject_client.rb +10 -1
  12. data/lib/tugboat/middleware/list_droplets.rb +5 -3
  13. data/lib/tugboat/version.rb +1 -1
  14. data/spec/cli/add_key_spec.rb +7 -9
  15. data/spec/cli/authorize_cli_spec.rb +4 -34
  16. data/spec/cli/config_cli_spec.rb +10 -5
  17. data/spec/cli/create_cli_spec.rb +20 -17
  18. data/spec/cli/debug_cli_spec.rb +11 -12
  19. data/spec/cli/destroy_cli_spec.rb +35 -12
  20. data/spec/cli/destroy_image_cli_spec.rb +12 -10
  21. data/spec/cli/droplets_cli_spec.rb +74 -48
  22. data/spec/cli/env_variable_spec.rb +4 -4
  23. data/spec/cli/halt_cli_spec.rb +16 -13
  24. data/spec/cli/help_cli_spec.rb +4 -4
  25. data/spec/cli/images_cli_spec.rb +9 -7
  26. data/spec/cli/info_cli_spec.rb +120 -50
  27. data/spec/cli/info_image_cli_spec.rb +24 -23
  28. data/spec/cli/keys_cli_spec.rb +3 -3
  29. data/spec/cli/password_reset_cli_spec.rb +12 -12
  30. data/spec/cli/rebuild_cli_spec.rb +31 -24
  31. data/spec/cli/regions_cli_spec.rb +3 -3
  32. data/spec/cli/resize_cli_spec.rb +16 -16
  33. data/spec/cli/restart_cli_spec.rb +32 -11
  34. data/spec/cli/sizes_cli_spec.rb +3 -3
  35. data/spec/cli/snapshot_cli_spec.rb +25 -9
  36. data/spec/cli/ssh_cli_spec.rb +10 -10
  37. data/spec/cli/start_cli_spec.rb +15 -15
  38. data/spec/cli/verify_cli_spec.rb +4 -7
  39. data/spec/cli/version_cli_spec.rb +1 -2
  40. data/spec/cli/wait_cli_spec.rb +16 -16
  41. data/spec/config_spec.rb +7 -1
  42. data/spec/fixtures/show_droplets.json +7 -4
  43. data/spec/fixtures/show_droplets_paginated_first.json +10 -7
  44. data/spec/fixtures/show_droplets_paginated_last.json +11 -5
  45. data/spec/fixtures/show_droplets_private_ip.json +7 -4
  46. data/spec/middleware/base_spec.rb +1 -2
  47. data/spec/middleware/check_configuration_spec.rb +1 -1
  48. data/spec/middleware/check_credentials_spec.rb +1 -1
  49. data/spec/middleware/check_droplet_active_spec.rb +1 -1
  50. data/spec/middleware/check_droplet_inactive_spec.rb +1 -1
  51. data/spec/middleware/find_droplet_spec.rb +3 -5
  52. data/spec/middleware/find_image_spec.rb +3 -5
  53. data/spec/middleware/ssh_droplet_spec.rb +5 -10
  54. data/spec/shared/environment.rb +2 -18
  55. data/tugboat.gemspec +1 -2
  56. metadata +8 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5b8787d22acda9fd2e2ac560566728409455b1bf
4
- data.tar.gz: 1e500c05d736053ed3ace1361be8ccf2ccdf8a78
3
+ metadata.gz: fbcf98dca8237e5bfd743b99bff3f3a328adef69
4
+ data.tar.gz: 8a9d169c00582cc9c71de34f38573d35cfe1fee5
5
5
  SHA512:
6
- metadata.gz: 8289a445f4e81da10750403d750d78ae98a434131a4423e0bb4bb2acaf39912af9b9671b8e18f60f9696f8ab805e2cfa9b8acfd1a4e79eae6325829f5fcd9815
7
- data.tar.gz: 180d935cb0b0690b60971e253212525978a2a87d8655e7b941a09ec056f956b268857576c243c1fb50277cb12090f4d5210ded93fc7503b42d6a32fc30ca3b5e
6
+ metadata.gz: 8cce0f1c41b15927f149aa687b5f9e2f3edf05e50da812f54cac4ba69253f64a92bc792f9a77d79e8a09103e4c804f20172c121bc1da5337465b82ff1304a9aa
7
+ data.tar.gz: e0dc3a1f73e12a0da367269228fbcb79edcd58c995f1186e642f7be8283cf0a11a0924308e3ef05337deb471a131942ec5c1d30bcedf23bd91df3344891398c7
data/CHANGELOG.md CHANGED
@@ -2,6 +2,27 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [v4.0.0](https://github.com/petems/tugboat/tree/v4.0.0) (2017-12-03)
6
+ [Full Changelog](https://github.com/petems/tugboat/compare/v3.1.0...v4.0.0)
7
+
8
+ **Fixed bugs:**
9
+
10
+ - snapshot not working [\#280](https://github.com/petems/tugboat/issues/280)
11
+ - Release Tugboat for 2.4.1 support [\#279](https://github.com/petems/tugboat/issues/279)
12
+ - Timeout while executing tugboat wait [\#71](https://github.com/petems/tugboat/issues/71)
13
+
14
+ **Merged pull requests:**
15
+
16
+ - Removing `Assigned but unused variable` warnings [\#292](https://github.com/petems/tugboat/pull/292) ([petems](https://github.com/petems))
17
+ - Adds helper for showing snapshot parameter [\#290](https://github.com/petems/tugboat/pull/290) ([petems](https://github.com/petems))
18
+ - Updates Faraday middleware gem [\#289](https://github.com/petems/tugboat/pull/289) ([petems](https://github.com/petems))
19
+ - Create CODE\_OF\_CONDUCT.md [\#288](https://github.com/petems/tugboat/pull/288) ([petems](https://github.com/petems))
20
+ - Add Size Slug [\#287](https://github.com/petems/tugboat/pull/287) ([petems](https://github.com/petems))
21
+ - Changes debug output to allow multiple regex [\#286](https://github.com/petems/tugboat/pull/286) ([petems](https://github.com/petems))
22
+ - Switches `$stdout` redirection to rspec method [\#285](https://github.com/petems/tugboat/pull/285) ([petems](https://github.com/petems))
23
+ - Change listing droplets to use DK [\#284](https://github.com/petems/tugboat/pull/284) ([petems](https://github.com/petems))
24
+ - Add configurable timeout to config file [\#283](https://github.com/petems/tugboat/pull/283) ([petems](https://github.com/petems))
25
+
5
26
  ## [v3.1.0](https://github.com/petems/tugboat/tree/v3.1.0) (2017-07-13)
6
27
  [Full Changelog](https://github.com/petems/tugboat/compare/v3.0.0...v3.1.0)
7
28
 
@@ -334,7 +355,7 @@ All notable changes to this project will be documented in this file.
334
355
 
335
356
  - destroy and info command [\#91](https://github.com/petems/tugboat/pull/91) ([PierreFrisch](https://github.com/PierreFrisch))
336
357
  - Add rebuild command [\#90](https://github.com/petems/tugboat/pull/90) ([PierreFrisch](https://github.com/PierreFrisch))
337
- - Fuzzy name searching is now case insensitive [\#88](https://github.com/petems/tugboat/pull/88) ([Vel0x](https://github.com/Vel0x))
358
+ - Fuzzy name searching is now case insensitive [\#88](https://github.com/petems/tugboat/pull/88) ([dalemyers](https://github.com/dalemyers))
338
359
  - global: add a -q/--quiet flag [\#87](https://github.com/petems/tugboat/pull/87) ([pearkes](https://github.com/pearkes))
339
360
  - Add backups\_enabled option on droplet creation \(-b true\) [\#82](https://github.com/petems/tugboat/pull/82) ([4n3w](https://github.com/4n3w))
340
361
 
@@ -0,0 +1,46 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6
+
7
+ ## Our Standards
8
+
9
+ Examples of behavior that contributes to creating a positive environment include:
10
+
11
+ * Using welcoming and inclusive language
12
+ * Being respectful of differing viewpoints and experiences
13
+ * Gracefully accepting constructive criticism
14
+ * Focusing on what is best for the community
15
+ * Showing empathy towards other community members
16
+
17
+ Examples of unacceptable behavior by participants include:
18
+
19
+ * The use of sexualized language or imagery and unwelcome sexual attention or advances
20
+ * Trolling, insulting/derogatory comments, and personal or political attacks
21
+ * Public or private harassment
22
+ * Publishing others' private information, such as a physical or electronic address, without explicit permission
23
+ * Other conduct which could reasonably be considered inappropriate in a professional setting
24
+
25
+ ## Our Responsibilities
26
+
27
+ Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28
+
29
+ Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30
+
31
+ ## Scope
32
+
33
+ This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34
+
35
+ ## Enforcement
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at webmaster@petersouter.co.uk. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38
+
39
+ Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40
+
41
+ ## Attribution
42
+
43
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44
+
45
+ [homepage]: http://contributor-covenant.org
46
+ [version]: http://contributor-covenant.org/version/1/4/
data/lib/tugboat/cli.rb CHANGED
@@ -66,11 +66,17 @@ module Tugboat
66
66
  default: false,
67
67
  aliases: '-i',
68
68
  desc: 'Include URLs for the droplets (can be opened in a browser)'
69
+ method_option 'per_page',
70
+ type: :boolean,
71
+ default: 20,
72
+ aliases: '-p',
73
+ desc: 'Chose how many results to fetch from the DigitalOcean API (larger is slower)'
69
74
  desc 'droplets [OPTIONS]', 'Retrieve a list of your droplets'
70
75
  def droplets
71
76
  Middleware.sequence_list_droplets.call('tugboat_action' => __method__,
72
77
  'user_quiet' => options[:quiet],
73
- 'include_urls' => options['include_urls'])
78
+ 'include_urls' => options['include_urls'],
79
+ 'per_page' => options['per_page'],)
74
80
  end
75
81
 
76
82
  desc 'images [OPTIONS]', 'Retrieve a list of images'
@@ -20,6 +20,7 @@ module Tugboat
20
20
  DEFAULT_PRIVATE_NETWORKING = 'false'.freeze
21
21
  DEFAULT_BACKUPS_ENABLED = 'false'.freeze
22
22
  DEFAULT_USER_DATA = nil
23
+ DEFAULT_TIMEOUT = 10
23
24
 
24
25
  # Load config file from current directory, if not exit load from user's home directory
25
26
  def initialize
@@ -95,6 +96,10 @@ module Tugboat
95
96
  ENV['DO_API_TOKEN'] unless ENV['DO_API_TOKEN'].to_s.empty?
96
97
  end
97
98
 
99
+ def timeout
100
+ @data['connection'].nil? || @data['connection']['timeout'].nil? ? DEFAULT_TIMEOUT : @data['connection']['timeout']
101
+ end
102
+
98
103
  # Re-runs initialize
99
104
  def reset!
100
105
  send(:initialize)
@@ -106,7 +111,7 @@ module Tugboat
106
111
  end
107
112
 
108
113
  # Writes a config file
109
- def create_config_file(access_token, ssh_key_path, ssh_user, ssh_port, region, image, size, ssh_key, private_networking, backups_enabled, ip6)
114
+ def create_config_file(access_token, ssh_key_path, ssh_user, ssh_port, region, image, size, ssh_key, private_networking, backups_enabled, ip6, timeout)
110
115
  # Default SSH Key path
111
116
  ssh_key_path = File.join('~', DEFAULT_SSH_KEY_PATH) if ssh_key_path.empty?
112
117
 
@@ -130,12 +135,17 @@ module Tugboat
130
135
 
131
136
  ip6 = DEFAULT_IP6 if ip6.empty?
132
137
 
138
+ timeout = DEFAULT_TIMEOUT if timeout.empty?
139
+
133
140
  require 'yaml'
134
141
  File.open(@path, File::RDWR | File::TRUNC | File::CREAT, 0o600) do |file|
135
142
  data = {
136
143
  'authentication' => {
137
144
  'access_token' => access_token
138
145
  },
146
+ 'connection' => {
147
+ 'timeout' => timeout
148
+ },
139
149
  'ssh' => {
140
150
  'ssh_user' => ssh_user,
141
151
  'ssh_key_path' => ssh_key_path,
@@ -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 :CheckSnapshotParameters, 'tugboat/middleware/check_snapshot_parameters'
12
13
  autoload :Config, 'tugboat/middleware/config'
13
14
  autoload :ConfirmAction, 'tugboat/middleware/confirm_action'
14
15
  autoload :CreateDroplet, 'tugboat/middleware/create_droplet'
@@ -197,6 +198,7 @@ module Tugboat
197
198
  # Snapshot a droplet
198
199
  def self.sequence_snapshot_droplet
199
200
  ::Middleware::Builder.new do
201
+ use CheckSnapshotParameters
200
202
  use InjectConfiguration
201
203
  use CheckConfiguration
202
204
  use InjectClient
@@ -6,6 +6,7 @@ module Tugboat
6
6
  say 'Note: You can get your Access Token from https://cloud.digitalocean.com/settings/tokens/new', :yellow
7
7
  say
8
8
  access_token = ask 'Enter your access token:'
9
+ timeout = ask 'Enter your default timeout for connections in seconds (optional, defaults to 10):'
9
10
  access_token.strip!
10
11
  ssh_key_path = ask 'Enter your SSH key path (optional, defaults to ~/.ssh/id_rsa):'
11
12
  ssh_user = ask 'Enter your SSH user (optional, defaults to root):'
@@ -23,7 +24,7 @@ module Tugboat
23
24
  ip6 = ask 'Enter your default for IPv6 (optional, defaults to false):'
24
25
 
25
26
  # Write the config file.
26
- env['config'].create_config_file(access_token, ssh_key_path, ssh_user, ssh_port, region, image, size, ssh_key, private_networking, backups_enabled, ip6)
27
+ env['config'].create_config_file(access_token, ssh_key_path, ssh_user, ssh_port, region, image, size, ssh_key, private_networking, backups_enabled, ip6, timeout)
27
28
  env['config'].reload!
28
29
 
29
30
  @app.call(env)
@@ -31,18 +31,29 @@ module Tugboat
31
31
 
32
32
  def verify_credentials(ocean, say_success = false)
33
33
  begin
34
- response = ocean.droplet.all(per_page: '1', page: '1')
34
+ if ocean.is_a?(DropletKit::Client)
35
+ response = ocean.droplets.all(per_page: '1', page: '1')
36
+
37
+ begin
38
+ response.first
39
+ rescue DropletKit::Error => e
40
+ say "Failed to connect to DigitalOcean. Reason given from API:\n#{e}", :red
41
+ exit 1
42
+ end
43
+ else
44
+ response = ocean.droplet.all(per_page: '1', page: '1')
45
+
46
+ unless response.success?
47
+ say "Failed to connect to DigitalOcean. Reason given from API: #{response.id} - #{response.message}", :red
48
+ exit 1
49
+ end
50
+ end
35
51
  rescue Faraday::ClientError => e
36
52
  say 'Authentication with DigitalOcean failed at an early stage'
37
53
  say "Error was: #{e}"
38
54
  exit 1
39
55
  end
40
56
 
41
- unless response.success?
42
- say "Failed to connect to DigitalOcean. Reason given from API: #{response.id} - #{response.message}", :red
43
- exit 1
44
- end
45
-
46
57
  say 'Authentication with DigitalOcean was successful.', :green if say_success
47
58
  end
48
59
 
@@ -80,19 +91,26 @@ module Tugboat
80
91
  end
81
92
 
82
93
  # Get all pages of droplets
83
- def get_droplet_list(ocean)
94
+ def get_droplet_list(ocean, per_page = 20)
84
95
  verify_credentials(ocean)
85
96
 
86
- page = ocean.droplet.all(per_page: 200, page: 1)
87
- return page.droplets unless page.paginated?
97
+ # Allow both Barge and DropletKit usage
98
+ if ocean.is_a?(DropletKit::Client)
99
+ # DropletKit self-paginates
100
+ ocean.droplets.all(per_page: per_page)
101
+ else
102
+ page = ocean.droplet.all(per_page: 200, page: 1)
103
+ return page.droplets unless page.paginated?
88
104
 
89
- Enumerator.new do |enum|
90
- page.droplets.each { |drop| enum.yield drop }
91
- for page_num in 2..page.last_page
92
- page = ocean.droplet.all(per_page: 200, page: page_num)
105
+ Enumerator.new do |enum|
93
106
  page.droplets.each { |drop| enum.yield drop }
107
+ for page_num in 2..page.last_page
108
+ page = ocean.droplet.all(per_page: 200, page: page_num)
109
+ page.droplets.each { |drop| enum.yield drop }
110
+ end
94
111
  end
95
112
  end
113
+
96
114
  end
97
115
  end
98
116
  end
@@ -0,0 +1,16 @@
1
+ module Tugboat
2
+ module Middleware
3
+ # Check if the droplet in the environment is active
4
+ class CheckSnapshotParameters < Base
5
+ def call(env)
6
+ unless env['user_droplet_id'] || env['user_droplet_name'] || env['user_droplet_fuzzy_name']
7
+ say 'You must provide a snapshot name followed by the droplet\'s name.', :red
8
+ say "For example: `tugboat snapshot #{env['user_snapshot_name']} example-node.com`", :green
9
+ exit 1
10
+ end
11
+
12
+ @app.call(env)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -23,7 +23,7 @@ module Tugboat
23
23
 
24
24
  attribute = env['user_attribute']
25
25
 
26
- droplet_ip4_public = droplet.networks.v4.find { |address| address.type == 'public' }.ip_address
26
+ droplet_ip4_public = droplet.networks.v4.find { |address| address.type == 'public' }.ip_address unless droplet.networks.v4.empty?
27
27
  droplet_ip6_public = droplet.networks.v6.find { |address| address.type == 'public' }.ip_address unless droplet.networks.v6.empty?
28
28
  check_private_ip = droplet.networks.v4.find { |address| address.type == 'private' }
29
29
  droplet_private_ip = check_private_ip.ip_address if check_private_ip
@@ -59,7 +59,7 @@ module Tugboat
59
59
  say "Name: #{droplet.name}"
60
60
  say "ID: #{droplet.id}"
61
61
  say "Status: #{status_color}#{droplet.status}#{CLEAR}"
62
- say "IP4: #{droplet_ip4_public}"
62
+ say "IP4: #{droplet_ip4_public}" unless droplet.networks.v4.empty?
63
63
  say "IP6: #{droplet_ip6_public}" unless droplet.networks.v6.empty?
64
64
 
65
65
  say "Private IP: #{droplet_private_ip}" if droplet_private_ip
@@ -10,13 +10,22 @@ module Tugboat
10
10
  # Sets the digital ocean client into the environment for use
11
11
  # later.
12
12
  @access_token = env['config'].access_token
13
+ config_timeout = env['config'].timeout
14
+
15
+ env['barge'] = Barge::Client.new(access_token: @access_token,
16
+ timeout: config_timeout,
17
+ open_timeout: config_timeout)
13
18
 
14
- env['barge'] = Barge::Client.new(access_token: @access_token)
15
19
  env['droplet_kit'] = DropletKit::Client.new(access_token: @access_token)
16
20
 
21
+ env['droplet_kit'].connection.options.timeout = config_timeout.to_i
22
+ env['droplet_kit'].connection.options.open_timeout = config_timeout.to_i
23
+
17
24
  env['barge'].faraday.use CustomLogger if ENV['DEBUG']
18
25
  env['droplet_kit'].connection.use CustomLogger if ENV['DEBUG']
19
26
 
27
+ env['droplet_kit'].connection
28
+
20
29
  @app.call(env)
21
30
  end
22
31
  end
@@ -3,13 +3,14 @@ module Tugboat
3
3
  # Check if the client has set-up configuration yet.
4
4
  class ListDroplets < Base
5
5
  def call(env)
6
- ocean = env['barge']
6
+ ocean = env['droplet_kit']
7
7
 
8
8
  verify_credentials(ocean)
9
9
 
10
- droplet_list = get_droplet_list ocean
10
+ droplet_list = get_droplet_list(ocean, env['per_page'])
11
11
 
12
12
  has_one = false
13
+
13
14
  droplet_list.each do |droplet|
14
15
  has_one = true
15
16
 
@@ -25,7 +26,8 @@ module Tugboat
25
26
  end
26
27
 
27
28
  public_addr = droplet.networks.v4.find { |address| address.type == 'public' }
28
- say "#{droplet.name} (ip: #{public_addr.ip_address}#{private_ip}, status: #{status_color}#{droplet.status}#{CLEAR}, region: #{droplet.region.slug}, id: #{droplet.id}#{env['include_urls'] ? droplet_id_to_url(droplet.id) : ''})"
29
+
30
+ say "#{droplet.name} (ip: #{public_addr.ip_address}#{private_ip}, status: #{status_color}#{droplet.status}#{CLEAR}, region: #{droplet.region.slug}, size: #{droplet.size_slug}, id: #{droplet.id}#{env['include_urls'] ? droplet_id_to_url(droplet.id) : ''})"
29
31
  end
30
32
 
31
33
  unless has_one
@@ -1,3 +1,3 @@
1
1
  module Tugboat
2
- VERSION = '3.1.0'.freeze
2
+ VERSION = '4.0.0'.freeze
3
3
  end
@@ -23,15 +23,16 @@ describe Tugboat::CLI do
23
23
  to_return(status: 201, body: fixture('create_ssh_key'), headers: {})
24
24
 
25
25
  cli.options = cli.options.merge(key: ssh_public_key.to_s)
26
- cli.add_key(ssh_key_name)
27
26
 
28
- expect($stdout.string).to eq <<-eos
27
+ add_key_with_name_and_keystring = <<-eos
29
28
  Queueing upload of SSH key 'macbook_pro'...SSH Key uploaded
30
29
 
31
30
  Name: macbook_pro
32
31
  ID: 3
33
32
  eos
34
33
 
34
+ expect { cli.add_key(ssh_key_name) }.to output(add_key_with_name_and_keystring).to_stdout
35
+
35
36
  expect(a_request(:post, 'https://api.digitalocean.com/v2/account/keys')).to have_been_made
36
37
  end
37
38
 
@@ -52,23 +53,20 @@ ID: 3
52
53
  headers: { 'Accept' => '*/*', 'Authorization' => 'Bearer foo', 'Content-Type' => 'application/json' }).
53
54
  to_return(status: 201, body: fixture('create_ssh_key_from_file'), headers: {})
54
55
 
55
- expect($stdout).to receive(:print).exactly(4).times
56
- expect($stdout).to receive(:print).with('Enter the path to your SSH key: ')
57
- expect($stdout).to receive(:print).with("Queueing upload of SSH key '#{ssh_key_name}'...")
58
56
  expect($stdin).to receive(:gets).and_return("#{fake_home}/.ssh/id_rsa.pub")
59
57
 
60
- cli.add_key(ssh_key_name)
61
-
62
- expect($stdout.string).to eq <<-eos
58
+ with_name_prompts_from_file_folder_stdout = <<-eos
63
59
  Possible public key paths from #{fake_home}/.ssh:
64
60
 
65
61
  #{fake_home}/.ssh/id_rsa.pub
66
62
 
67
- SSH Key uploaded
63
+ Enter the path to your SSH key: Queueing upload of SSH key 'macbook_pro'...SSH Key uploaded
68
64
 
69
65
  Name: cool_key
70
66
  ID: 5
71
67
  eos
68
+
69
+ expect { cli.add_key(ssh_key_name) }.to output(with_name_prompts_from_file_folder_stdout).to_stdout
72
70
  end
73
71
 
74
72
  after do
@@ -14,35 +14,20 @@ describe Tugboat::CLI do
14
14
  with(headers: { 'Accept' => '*/*', 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Authorization' => 'Bearer foo', 'Content-Type' => 'application/json', 'User-Agent' => 'Faraday v0.9.2' }).
15
15
  to_return(status: 200, body: fixture('show_droplets'), headers: {})
16
16
 
17
- expect($stdout).to receive(:print).exactly(6).times
18
- expect($stdout).to receive(:print).with('Enter your access token: ')
19
17
  expect($stdin).to receive(:gets).and_return(access_token)
20
- expect($stdout).to receive(:print).with('Enter your SSH key path (optional, defaults to ~/.ssh/id_rsa): ')
18
+ expect($stdin).to receive(:gets).and_return(timeout)
21
19
  expect($stdin).to receive(:gets).and_return(ssh_key_path)
22
- expect($stdout).to receive(:print).with('Enter your SSH user (optional, defaults to root): ')
23
20
  expect($stdin).to receive(:gets).and_return(ssh_user)
24
- expect($stdout).to receive(:print).with('Enter your SSH port number (optional, defaults to 22): ')
25
21
  expect($stdin).to receive(:gets).and_return(ssh_port)
26
- expect($stdout).to receive(:print).with('Enter your default region (optional, defaults to nyc1): ')
27
22
  expect($stdin).to receive(:gets).and_return(region)
28
- expect($stdout).to receive(:print).with('Enter your default image ID or image slug (optional, defaults to ubuntu-14-04-x64): ')
29
23
  expect($stdin).to receive(:gets).and_return(image)
30
- expect($stdout).to receive(:print).with('Enter your default size (optional, defaults to 512mb)): ')
31
24
  expect($stdin).to receive(:gets).and_return(size)
32
- expect($stdout).to receive(:print).with("Enter your default ssh key IDs (optional, defaults to none, array of IDs of ssh keys eg. ['1234']): ")
33
25
  expect($stdin).to receive(:gets).and_return(ssh_key_id)
34
- expect($stdout).to receive(:print).with('Enter your default for private networking (optional, defaults to false): ')
35
26
  expect($stdin).to receive(:gets).and_return(private_networking)
36
- expect($stdout).to receive(:print).with('Enter your default for enabling backups (optional, defaults to false): ')
37
27
  expect($stdin).to receive(:gets).and_return(backups_enabled)
38
- expect($stdout).to receive(:print).with('Enter your default for IPv6 (optional, defaults to false): ')
39
28
  expect($stdin).to receive(:gets).and_return(ip6)
40
29
 
41
- cli.authorize
42
-
43
- expect($stdout.string).to include('Note: You can get your Access Token from https://cloud.digitalocean.com/settings/tokens/new')
44
- expect($stdout.string).to include("To retrieve region, image, size and key ID's, you can use the corresponding tugboat command, such as `tugboat images`.")
45
- expect($stdout.string).to include('Defaults can be changed at any time in your ~/.tugboat configuration file.')
30
+ expect { cli.authorize }.to output(/Note: You can get your Access Token from https:\/\/cloud.digitalocean.com\/settings\/tokens\/new/).to_stdout
46
31
 
47
32
  config = YAML.load_file(tmp_path)
48
33
 
@@ -63,35 +48,20 @@ describe Tugboat::CLI do
63
48
  with(headers: { 'Accept' => '*/*', 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Authorization' => %r{Bearer}, 'Content-Type' => 'application/json', 'User-Agent' => 'Faraday v0.9.2' }).
64
49
  to_return(status: 200, body: fixture('show_droplets'), headers: {})
65
50
 
66
- expect($stdout).to receive(:print).exactly(6).times
67
- expect($stdout).to receive(:print).with('Enter your access token: ')
68
51
  expect($stdin).to receive(:gets).and_return('')
69
- expect($stdout).to receive(:print).with('Enter your SSH key path (optional, defaults to ~/.ssh/id_rsa): ')
70
52
  expect($stdin).to receive(:gets).and_return('')
71
- expect($stdout).to receive(:print).with('Enter your SSH user (optional, defaults to root): ')
72
53
  expect($stdin).to receive(:gets).and_return('')
73
- expect($stdout).to receive(:print).with('Enter your SSH port number (optional, defaults to 22): ')
74
54
  expect($stdin).to receive(:gets).and_return('')
75
- expect($stdout).to receive(:print).with('Enter your default region (optional, defaults to nyc1): ')
76
55
  expect($stdin).to receive(:gets).and_return('')
77
- expect($stdout).to receive(:print).with('Enter your default image ID or image slug (optional, defaults to ubuntu-14-04-x64): ')
78
56
  expect($stdin).to receive(:gets).and_return('')
79
- expect($stdout).to receive(:print).with('Enter your default size (optional, defaults to 512mb)): ')
80
57
  expect($stdin).to receive(:gets).and_return('')
81
- expect($stdout).to receive(:print).with("Enter your default ssh key IDs (optional, defaults to none, array of IDs of ssh keys eg. ['1234']): ")
82
58
  expect($stdin).to receive(:gets).and_return('')
83
- expect($stdout).to receive(:print).with('Enter your default for private networking (optional, defaults to false): ')
84
59
  expect($stdin).to receive(:gets).and_return('')
85
- expect($stdout).to receive(:print).with('Enter your default for enabling backups (optional, defaults to false): ')
86
60
  expect($stdin).to receive(:gets).and_return('')
87
- expect($stdout).to receive(:print).with('Enter your default for IPv6 (optional, defaults to false): ')
61
+ expect($stdin).to receive(:gets).and_return('')
88
62
  expect($stdin).to receive(:gets).and_return('')
89
63
 
90
- cli.authorize
91
-
92
- expect($stdout.string).to include('Note: You can get your Access Token from https://cloud.digitalocean.com/settings/tokens/new')
93
- expect($stdout.string).to include("To retrieve region, image, size and key ID's, you can use the corresponding tugboat command, such as `tugboat images`.")
94
- expect($stdout.string).to include('Defaults can be changed at any time in your ~/.tugboat configuration file.')
64
+ expect { cli.authorize }.to output(/Note: You can get your Access Token from https:\/\/cloud.digitalocean.com\/settings\/tokens\/new/).to_stdout
95
65
 
96
66
  config = YAML.load_file(tmp_path)
97
67