vmc 0.5.0.beta.7 → 0.5.0.beta.10

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.
Files changed (59) hide show
  1. data/LICENSE +1277 -746
  2. data/Rakefile +22 -23
  3. data/lib/vmc/cli.rb +21 -27
  4. data/lib/vmc/cli/app/push.rb +1 -0
  5. data/lib/vmc/cli/app/push/create.rb +3 -2
  6. data/lib/vmc/cli/app/push/sync.rb +11 -8
  7. data/lib/vmc/cli/app/scale.rb +19 -17
  8. data/lib/vmc/cli/domain/map.rb +55 -0
  9. data/lib/vmc/cli/domain/unmap.rb +56 -0
  10. data/lib/vmc/cli/route/map.rb +74 -0
  11. data/lib/vmc/cli/route/unmap.rb +94 -0
  12. data/lib/vmc/cli/service/create.rb +4 -1
  13. data/lib/vmc/cli/start/base.rb +2 -2
  14. data/lib/vmc/cli/start/login.rb +5 -2
  15. data/lib/vmc/cli/start/target.rb +4 -3
  16. data/lib/vmc/cli/user/base.rb +19 -0
  17. data/lib/vmc/cli/user/passwd.rb +7 -19
  18. data/lib/vmc/cli/{start → user}/register.rb +12 -23
  19. data/lib/vmc/constants.rb +1 -1
  20. data/lib/vmc/test_support.rb +4 -0
  21. data/lib/vmc/test_support/command_helper.rb +38 -0
  22. data/{spec/support → lib/vmc/test_support}/common_input_examples.rb +0 -0
  23. data/lib/vmc/test_support/fake_home_dir.rb +16 -0
  24. data/lib/vmc/test_support/interact_helper.rb +29 -0
  25. data/lib/vmc/version.rb +1 -1
  26. data/spec/features/new_user_flow_spec.rb +43 -51
  27. data/spec/spec_helper.rb +24 -12
  28. data/spec/vmc/cli/app/instances_spec.rb +3 -8
  29. data/spec/vmc/cli/app/push/create_spec.rb +10 -7
  30. data/spec/vmc/cli/app/push_spec.rb +1 -1
  31. data/spec/vmc/cli/app/rename_spec.rb +1 -1
  32. data/spec/vmc/cli/app/scale_spec.rb +81 -0
  33. data/spec/vmc/cli/app/stats_spec.rb +3 -7
  34. data/spec/vmc/cli/domain/map_spec.rb +140 -0
  35. data/spec/vmc/cli/domain/unmap_spec.rb +73 -0
  36. data/spec/vmc/cli/organization/orgs_spec.rb +13 -16
  37. data/spec/vmc/cli/organization/rename_spec.rb +1 -1
  38. data/spec/vmc/cli/route/map_spec.rb +142 -0
  39. data/spec/vmc/cli/route/unmap_spec.rb +215 -0
  40. data/spec/vmc/cli/service/rename_spec.rb +1 -1
  41. data/spec/vmc/cli/space/rename_spec.rb +15 -18
  42. data/spec/vmc/cli/space/spaces_spec.rb +18 -25
  43. data/spec/vmc/cli/start/info_spec.rb +44 -46
  44. data/spec/vmc/cli/start/login_spec.rb +40 -0
  45. data/spec/vmc/cli/user/create_spec.rb +54 -0
  46. data/spec/vmc/cli/user/passwd_spec.rb +7 -14
  47. data/spec/vmc/cli/{start → user}/register_spec.rb +26 -22
  48. data/spec/vmc/cli_spec.rb +164 -6
  49. metadata +46 -39
  50. data/lib/vmc/cli/app/routes.rb +0 -100
  51. data/lib/vmc/cli/domain/add_domain.rb +0 -25
  52. data/lib/vmc/cli/domain/create_domain.rb +0 -28
  53. data/lib/vmc/cli/domain/delete_domain.rb +0 -56
  54. data/lib/vmc/cli/domain/remove_domain.rb +0 -28
  55. data/lib/vmc/cli/route/create_route.rb +0 -49
  56. data/lib/vmc/cli/route/delete.rb +0 -47
  57. data/spec/support/feature_helpers.rb +0 -16
  58. data/spec/support/interact_helpers.rb +0 -27
  59. data/spec/vmc/cli/route/delete_route_spec.rb +0 -162
@@ -0,0 +1,94 @@
1
+ require "vmc/cli/route/base"
2
+
3
+ module VMC::Route
4
+ class Unmap < Base
5
+ desc "Remove a URL mapping"
6
+ group :apps, :info, :hidden => true
7
+ input :url, :desc => "URL to unmap", :argument => :optional,
8
+ :from_given => find_by_name("route") { client.routes }
9
+ input :app, :desc => "Application to remove the URL from",
10
+ :argument => :optional, :from_given => by_name(:app)
11
+ input :delete, :desc => "Delete route", :type => :boolean
12
+ input :all, :desc => "Act on all routes", :type => :boolean
13
+ input :really, :type => :boolean, :forget => true, :hidden => true,
14
+ :default => proc { force? || interact }
15
+ def unmap
16
+ return invoke :v1_unmap, input.inputs, input.given unless v2?
17
+
18
+ if input[:all]
19
+ if input.has?(:app)
20
+ app = target = input[:app]
21
+ return unless !input[:delete] || input[:really, "ALL URLS bound to #{target.name}", :bad]
22
+ else
23
+ target = client
24
+ return unless !input[:delete] || input[:really, "ALL URLS", :bad]
25
+ end
26
+
27
+ target.routes.each do |r|
28
+ begin
29
+ invoke :unmap, :delete => input[:delete], :url => r, :really => true, :app => app
30
+ rescue CFoundry::APIError => e
31
+ err "#{e.class}: #{e.message}"
32
+ end
33
+ end
34
+
35
+ return
36
+ end
37
+
38
+ app = input[:app]
39
+ url = input[:url, app ? app.routes : client.routes]
40
+
41
+ if input[:delete]
42
+ with_progress("Deleting route #{c(url.name, :name)}") do
43
+ url.delete!
44
+ end
45
+ elsif app
46
+ with_progress("Unbinding #{c(url.name, :name)} from #{c(app.name, :name)}") do
47
+ app.remove_route(url)
48
+ end
49
+ else
50
+ fail "Missing either --delete or --app."
51
+ end
52
+ end
53
+
54
+
55
+ desc "V1 ONLY UNMAP YOU SHOULD NOT SEE THIS"
56
+ input :url, :desc => "URL to unmap", :argument => :optional,
57
+ :interact => :v1_ask_url
58
+ input :app, :desc => "Application to remove the URL from",
59
+ :argument => :optional, :from_given => by_name(:app)
60
+ input :all, :desc => "Act on all routes", :type => :boolean
61
+ def v1_unmap
62
+ app = input[:app]
63
+ url = input[:url, app.urls] unless input[:all]
64
+
65
+ with_progress("Updating #{c(app.name, :name)}") do |s|
66
+ if input[:all]
67
+ app.urls = []
68
+ else
69
+ simple = url.sub(/^https?:\/\/(.*)\/?/i, '\1')
70
+
71
+ unless app.urls.delete(simple)
72
+ fail "URL #{url} is not mapped to this application."
73
+ end
74
+ end
75
+
76
+ app.update!
77
+ end
78
+ end
79
+
80
+ private
81
+
82
+ def ask_url(choices)
83
+ ask("Which URL?", :choices => choices.sort_by(&:name), :display => proc(&:name))
84
+ end
85
+
86
+ def v1_ask_url(choices)
87
+ ask("Which URL?", :choices => choices.sort)
88
+ end
89
+
90
+ def ask_really(name, color)
91
+ ask("Really delete #{c(name, color)}?", :default => false)
92
+ end
93
+ end
94
+ end
@@ -34,7 +34,10 @@ module VMC::Service
34
34
  offerings.reject!(&:deprecated?)
35
35
  end
36
36
 
37
- if v2? && plan = input.given(:plan)
37
+ # filter the offerings based on a given plan value, which will be a
38
+ # string if the user provided it with a flag, or a ServicePlan if
39
+ # something invoked this command with a particular plan
40
+ if v2? && plan = input.direct(:plan)
38
41
  offerings.reject! do |s|
39
42
  if plan.is_a?(String)
40
43
  s.service_plans.none? { |p| p.name == plan.upcase }
@@ -37,7 +37,7 @@ module VMC
37
37
  def select_org_and_space(input, info)
38
38
  changed_org = false
39
39
 
40
- if input.given?(:organization) || !org_valid?(info[:organization])
40
+ if input.has?(:organization) || !org_valid?(info[:organization])
41
41
  org = input[:organization]
42
42
  return unless org
43
43
 
@@ -50,7 +50,7 @@ module VMC
50
50
  end
51
51
 
52
52
  # switching org means switching space
53
- if changed_org || input.given?(:space) || !space_valid?(info[:space])
53
+ if changed_org || input.has?(:space) || !space_valid?(info[:space])
54
54
  line if changed_org && !quiet?
55
55
 
56
56
  space = input[:space, org]
@@ -31,6 +31,7 @@ module VMC::Start
31
31
 
32
32
  info = target_info
33
33
 
34
+ auth_token = nil
34
35
  authenticated = false
35
36
  failed = false
36
37
  remaining_attempts = 3
@@ -42,7 +43,7 @@ module VMC::Start
42
43
 
43
44
  with_progress("Authenticating") do |s|
44
45
  begin
45
- info[:token] = client.login(credentials)
46
+ auth_token = client.login(credentials[:username], credentials[:password])
46
47
  authenticated = true
47
48
  rescue CFoundry::Denied
48
49
  return if force?
@@ -55,14 +56,16 @@ module VMC::Start
55
56
  end
56
57
  end
57
58
 
59
+ info.merge!(auth_token.to_hash)
58
60
  save_target_info(info)
59
61
  invalidate_client
60
62
 
61
63
  if v2?
62
64
  line if input.interactive?(:organization) || input.interactive?(:space)
63
65
  select_org_and_space(input, info)
64
- save_target_info(info)
65
66
  end
67
+
68
+ save_target_info(info)
66
69
  ensure
67
70
  exit_status 1 if not authenticated
68
71
  end
@@ -12,13 +12,14 @@ module VMC::Start
12
12
  :from_given => by_name(:space)
13
13
  interactions TargetInteractions
14
14
  def target
15
- if !input.given?(:url) && !input.given?(:organization) && !input.given?(:space)
15
+ unless input.has?(:url) || input.has?(:organization) || \
16
+ input.has?(:space)
16
17
  display_target
17
18
  display_org_and_space unless quiet?
18
19
  return
19
20
  end
20
21
 
21
- if input.given?(:url)
22
+ if input.has?(:url)
22
23
  target = sane_target_url(input[:url])
23
24
  with_progress("Setting target to #{c(target, :name)}") do
24
25
  client(target).info # check that it's valid before setting
@@ -28,7 +29,7 @@ module VMC::Start
28
29
 
29
30
  return unless v2? && client.logged_in?
30
31
 
31
- if input.given?(:organization) || input.given?(:space)
32
+ if input.has?(:organization) || input.has?(:space)
32
33
  info = target_info
33
34
 
34
35
  select_org_and_space(input, info)
@@ -4,6 +4,25 @@ module VMC
4
4
  module User
5
5
  class Base < CLI
6
6
  def precondition
7
+ check_logged_in
8
+ end
9
+
10
+ private
11
+
12
+ def validate_password!(password)
13
+ validate_password_verified!(password)
14
+ validate_password_strength!(password)
15
+ end
16
+
17
+ def validate_password_verified!(password)
18
+ fail "Passwords do not match." unless force? || password == input[:verify]
19
+ end
20
+
21
+ def validate_password_strength!(password)
22
+ strength = client.base.uaa.password_score(password)
23
+ msg = "Your password strength is: #{strength}"
24
+ fail msg if strength == :weak
25
+ line msg
7
26
  end
8
27
  end
9
28
  end
@@ -20,27 +20,15 @@ module VMC::User
20
20
  user = input[:user]
21
21
  password = input[:password] if v2?
22
22
  new_password = input[:new_password]
23
- verify = input[:verify]
24
23
 
25
- if new_password != verify
26
- fail "Passwords do not match."
27
- end
28
-
29
- pw_strength = client.base.uaa.password_score(new_password)
30
- msg = "Your password strength is: #{pw_strength}"
31
-
32
- if pw_strength == :weak
33
- fail msg
34
- else
35
- line msg
24
+ validate_password! new_password
36
25
 
37
- with_progress("Changing password") do
38
- if v2?
39
- user.change_password!(new_password, password)
40
- else
41
- user.password = new_password
42
- user.update!
43
- end
26
+ with_progress("Changing password") do
27
+ if v2?
28
+ user.change_password!(new_password, password)
29
+ else
30
+ user.password = new_password
31
+ user.update!
44
32
  end
45
33
  end
46
34
  end
@@ -1,38 +1,27 @@
1
- require "vmc/cli/start/base"
1
+ require "vmc/cli/user/base"
2
2
 
3
- module VMC::Start
3
+ module VMC::User
4
4
  class Register < Base
5
+ def precondition; end
6
+
5
7
  desc "Create a user and log in"
6
- group :start, :hidden => true
8
+ group :admin, :user, :hidden => true
7
9
  input :email, :desc => "Desired email", :argument => :optional
8
10
  input :password, :desc => "Desired password"
9
11
  input :verify, :desc => "Repeat password"
10
12
  input :login, :desc => "Automatically log in?", :default => true
11
13
  def register
12
- show_context
13
-
14
14
  email = input[:email]
15
15
  password = input[:password]
16
16
 
17
- if !force? && password != input[:verify]
18
- fail "Passwords do not match."
19
- end
20
-
21
- pw_strength = client.base.uaa.password_score(password)
22
- msg = "Your password strength is: #{pw_strength}"
23
-
24
- if pw_strength == :weak
25
- fail msg
26
- else
27
- line msg
17
+ validate_password!(password)
28
18
 
29
- with_progress("Creating user") do
30
- client.register(email, password)
31
- end
19
+ with_progress("Creating user") do
20
+ client.register(email, password)
21
+ end
32
22
 
33
- if input[:login]
34
- invoke :login, :username => email, :password => password
35
- end
23
+ if input[:login]
24
+ invoke :login, :username => email, :password => password
36
25
  end
37
26
  end
38
27
 
@@ -42,7 +31,7 @@ module VMC::Start
42
31
  ask("Email")
43
32
  end
44
33
 
45
- def ask_passsword
34
+ def ask_password
46
35
  ask("Password", :echo => "*", :forget => true)
47
36
  end
48
37
 
@@ -2,7 +2,7 @@ module VMC
2
2
  OLD_TARGET_FILE = "~/.vmc_target".freeze
3
3
  OLD_TOKENS_FILE = "~/.vmc_token".freeze
4
4
 
5
- CONFIG_DIR = (defined?(SPEC_ROOT) ? "#{SPEC_ROOT}/tmp/.vmc" : "~/.vmc").freeze
5
+ CONFIG_DIR = "~/.vmc".freeze
6
6
 
7
7
  LOGS_DIR = "#{CONFIG_DIR}/logs".freeze
8
8
  PLUGINS_FILE = "#{CONFIG_DIR}/plugins.yml".freeze
@@ -0,0 +1,4 @@
1
+ module VMC::TestSupport
2
+ end
3
+
4
+ Dir.glob(File.expand_path("../test_support/*", __FILE__)).each { |file| require file }
@@ -0,0 +1,38 @@
1
+ module VMC::TestSupport::CommandHelper
2
+ def vmc(argv)
3
+ stub(VMC::CLI).exit { |code| code }
4
+ capture_output { VMC::CLI.start(argv + ["--debug"]) }
5
+ end
6
+
7
+ def expect_success
8
+ print_debug_output if status != 0
9
+ expect(status).to eq 0
10
+ end
11
+
12
+ def expect_failure
13
+ print_debug_output if status == 0
14
+ expect(status).to eq 1
15
+ end
16
+
17
+ def bool_flag(flag)
18
+ "#{'no-' unless send(flag)}#{flag.to_s.gsub('_', '-')}"
19
+ end
20
+
21
+ def print_debug_output
22
+ puts stdout.string.strip_progress_dots
23
+ puts stderr.string
24
+ end
25
+
26
+ attr_reader :stdout, :stderr, :status
27
+
28
+ def capture_output
29
+ real_stdout = $stdout
30
+ real_stderr = $stderr
31
+ $stdout = @stdout = StringIO.new
32
+ $stderr = @stderr = StringIO.new
33
+ @status = yield
34
+ ensure
35
+ $stdout = real_stdout
36
+ $stderr = real_stderr
37
+ end
38
+ end
@@ -0,0 +1,16 @@
1
+ module VMC::TestSupport::FakeHomeDir
2
+ def self.included(klass)
3
+ def klass.use_fake_home_dir(&block)
4
+ around do |example|
5
+ dir = instance_exec(&block)
6
+ original_home_dir = ENV['HOME']
7
+ ENV['HOME'] = dir
8
+ begin
9
+ example.call
10
+ ensure
11
+ ENV['HOME'] = original_home_dir
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,29 @@
1
+ module VMC::TestSupport::InteractHelper
2
+ def stub_ask(*args, &block)
3
+ a_stub = nil
4
+ any_instance_of VMC::CLI do |interactive|
5
+ a_stub = stub(interactive).ask(*args, &block)
6
+ end
7
+ a_stub
8
+ end
9
+
10
+ def mock_ask(*args, &block)
11
+ a_mock = nil
12
+ any_instance_of VMC::CLI do |interactive|
13
+ a_mock = mock(interactive).ask(*args, &block)
14
+ end
15
+ a_mock
16
+ end
17
+
18
+ def dont_allow_ask(*args)
19
+ any_instance_of VMC::CLI do |interactive|
20
+ dont_allow(interactive).ask(*args)
21
+ end
22
+ end
23
+
24
+ def mock_with_progress(message)
25
+ any_instance_of VMC::CLI do |interactive|
26
+ mock(interactive).with_progress(message) { |_, block| block.call }
27
+ end
28
+ end
29
+ end
@@ -1,3 +1,3 @@
1
1
  module VMC
2
- VERSION = "0.5.0.beta.7".freeze
2
+ VERSION = "0.5.0.beta.10".freeze
3
3
  end
@@ -1,4 +1,5 @@
1
1
  require 'spec_helper'
2
+ require "webmock/rspec"
2
3
 
3
4
  if ENV['VMC_TEST_USER'] && ENV['VMC_TEST_PASSWORD'] && ENV['VMC_TEST_TARGET']
4
5
  describe 'A new user tries to use VMC against v1 production' do
@@ -8,76 +9,67 @@ if ENV['VMC_TEST_USER'] && ENV['VMC_TEST_PASSWORD'] && ENV['VMC_TEST_TARGET']
8
9
  let(:output) { StringIO.new }
9
10
  let(:out) { output.string.strip_progress_dots }
10
11
 
11
- let(:app) {
12
- fuzz =
13
- if defined? TRAVIS_BUILD_ID
14
- TRAVIS_BUILD_ID
15
- else
16
- Time.new.to_f.to_s.gsub(".", "_")
17
- end
18
-
12
+ let(:app) do
13
+ fuzz = defined?(TRAVIS_BUILD_ID) ? TRAVIS_BUILD_ID : Time.new.to_f.to_s.gsub(".", "_")
19
14
  "hello-sinatra-#{fuzz}"
20
- }
15
+ end
21
16
 
22
17
  before do
23
18
  FileUtils.rm_rf VMC::CONFIG_DIR
24
- stub(VMC::CLI).exit { |code| code }
25
19
  WebMock.allow_net_connect!
26
20
  end
27
21
 
28
- after do
29
- with_output_to { VMC::CLI.start %W(delete #{app} -f) }
30
- end
22
+ after { vmc %W(delete #{app} -f --no-script) }
31
23
 
32
24
  it 'and pushes a simple sinatra app using defaults as much as possible' do
33
- vmc_ok %W(target #{target}) do |out|
34
- expect(out).to eq <<-OUT.strip_heredoc
35
- Setting target to https://#{target}... OK
36
- OUT
37
- end
25
+ vmc %W[target #{target} --no-script]
26
+ expect_success
27
+ expect(stdout.string.strip_progress_dots).to eq <<-OUT.strip_heredoc
28
+ Setting target to https://#{target}... OK
29
+ OUT
38
30
 
39
- vmc_ok %W(login #{username} --password #{password}) do |out|
40
- expect(out).to eq <<-OUT.strip_heredoc
41
- target: https://#{target}
31
+ vmc %W[login #{username} --password #{password} --no-script]
32
+ expect_success
33
+ expect(stdout.string.strip_progress_dots).to eq <<-OUT.strip_heredoc
34
+ target: https://#{target}
42
35
 
43
- Authenticating... OK
44
- OUT
45
- end
36
+ Authenticating... OK
37
+ OUT
46
38
 
47
- vmc_fail %W(app #{app}) do |out|
48
- expect(out).to eq <<-OUT.strip_heredoc
49
- Unknown app '#{app}'.
50
- OUT
51
- end
39
+ vmc %W[app #{app} --no-script]
40
+ expect_failure
41
+ expect(stderr.string).to eq <<-OUT.strip_heredoc
42
+ Unknown app '#{app}'.
43
+ OUT
52
44
 
53
45
  Dir.chdir("#{SPEC_ROOT}/assets/hello-sinatra") do
54
- vmc_ok %W(push #{app} --runtime ruby19 --url #{app}-vmc-test.cloudfoundry.com -f) do |out|
55
- expect(out).to eq <<-OUT.strip_heredoc
56
- Creating #{app}... OK
57
-
58
- Updating #{app}... OK
59
- Uploading #{app}... OK
60
- Starting #{app}... OK
61
- Checking #{app}... OK
62
- OUT
63
- end
46
+ vmc %W[push #{app} --runtime ruby19 --url #{app}-vmc-test.cloudfoundry.com -f --no-script]
47
+ expect_success
48
+ expect(stdout.string.strip_progress_dots).to eq <<-OUT.strip_heredoc
49
+ Creating #{app}... OK
64
50
 
65
- vmc_ok %W(push #{app}) do |out|
66
- expect(out).to eq <<-OUT.strip_heredoc
67
- Uploading #{app}... OK
68
- Stopping #{app}... OK
51
+ Updating #{app}... OK
52
+ Uploading #{app}... OK
53
+ Starting #{app}... OK
54
+ Checking #{app}... OK
55
+ OUT
69
56
 
70
- Starting #{app}... OK
71
- Checking #{app}... OK
72
- OUT
73
- end
74
- end
57
+ vmc %W[push #{app} --no-script]
58
+ expect_success
59
+ expect(stdout.string.strip_progress_dots).to eq <<-OUT.strip_heredoc
60
+ Uploading #{app}... OK
61
+ Stopping #{app}... OK
75
62
 
76
- vmc_ok %W(delete #{app} -f) do |out|
77
- expect(out).to eq <<-OUT.strip_heredoc
78
- Deleting #{app}... OK
63
+ Starting #{app}... OK
64
+ Checking #{app}... OK
79
65
  OUT
80
66
  end
67
+
68
+ vmc %W[delete #{app} -f --no-script]
69
+ expect_success
70
+ expect(stdout.string.strip_progress_dots).to eq <<-OUT.strip_heredoc
71
+ Deleting #{app}... OK
72
+ OUT
81
73
  end
82
74
  end
83
75
  else