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

Sign up to get free protection for your applications and to get access to all the features.
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