engineyard 1.4.29 → 1.7.0.pre2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/README.rdoc +139 -4
  2. data/bin/ey +1 -7
  3. data/lib/engineyard.rb +1 -22
  4. data/lib/engineyard/cli.rb +192 -94
  5. data/lib/engineyard/cli/#recipes.rb# +32 -0
  6. data/lib/engineyard/cli/api.rb +42 -28
  7. data/lib/engineyard/cli/recipes.rb +13 -6
  8. data/lib/engineyard/cli/ui.rb +103 -42
  9. data/lib/engineyard/cli/web.rb +16 -10
  10. data/lib/engineyard/config.rb +92 -18
  11. data/lib/engineyard/deploy_config.rb +66 -0
  12. data/lib/engineyard/deploy_config/migrate.rb +125 -0
  13. data/lib/engineyard/deploy_config/ref.rb +56 -0
  14. data/lib/engineyard/error.rb +38 -78
  15. data/lib/engineyard/repo.rb +75 -27
  16. data/lib/engineyard/serverside_runner.rb +133 -0
  17. data/lib/engineyard/thor.rb +110 -18
  18. data/lib/engineyard/version.rb +1 -1
  19. data/spec/engineyard/cli/api_spec.rb +10 -16
  20. data/spec/engineyard/cli_spec.rb +0 -11
  21. data/spec/engineyard/config_spec.rb +1 -8
  22. data/spec/engineyard/deploy_config_spec.rb +203 -0
  23. data/spec/engineyard/eyrc_spec.rb +2 -0
  24. data/spec/engineyard/repo_spec.rb +57 -34
  25. data/spec/ey/deploy_spec.rb +102 -52
  26. data/spec/ey/list_environments_spec.rb +69 -14
  27. data/spec/ey/login_spec.rb +11 -7
  28. data/spec/ey/logout_spec.rb +4 -4
  29. data/spec/ey/logs_spec.rb +6 -6
  30. data/spec/ey/recipes/apply_spec.rb +1 -1
  31. data/spec/ey/recipes/download_spec.rb +1 -1
  32. data/spec/ey/recipes/upload_spec.rb +6 -6
  33. data/spec/ey/rollback_spec.rb +3 -3
  34. data/spec/ey/ssh_spec.rb +9 -9
  35. data/spec/ey/status_spec.rb +2 -2
  36. data/spec/ey/whoami_spec.rb +9 -8
  37. data/spec/spec_helper.rb +18 -15
  38. data/spec/support/{fake_awsm.rb → git_repos.rb} +0 -14
  39. data/spec/support/helpers.rb +84 -28
  40. data/spec/support/matchers.rb +0 -16
  41. data/spec/support/shared_behavior.rb +83 -103
  42. metadata +65 -51
  43. data/lib/engineyard/api.rb +0 -117
  44. data/lib/engineyard/collection.rb +0 -7
  45. data/lib/engineyard/collection/abstract.rb +0 -71
  46. data/lib/engineyard/collection/apps.rb +0 -8
  47. data/lib/engineyard/collection/environments.rb +0 -8
  48. data/lib/engineyard/model.rb +0 -12
  49. data/lib/engineyard/model/account.rb +0 -8
  50. data/lib/engineyard/model/api_struct.rb +0 -33
  51. data/lib/engineyard/model/app.rb +0 -32
  52. data/lib/engineyard/model/deployment.rb +0 -90
  53. data/lib/engineyard/model/environment.rb +0 -194
  54. data/lib/engineyard/model/instance.rb +0 -166
  55. data/lib/engineyard/model/log.rb +0 -9
  56. data/lib/engineyard/model/user.rb +0 -6
  57. data/lib/engineyard/resolver.rb +0 -134
  58. data/lib/engineyard/rest_client_ext.rb +0 -9
  59. data/lib/engineyard/ruby_ext.rb +0 -9
  60. data/spec/engineyard/api_spec.rb +0 -39
  61. data/spec/engineyard/collection/apps_spec.rb +0 -16
  62. data/spec/engineyard/collection/environments_spec.rb +0 -16
  63. data/spec/engineyard/model/api_struct_spec.rb +0 -41
  64. data/spec/engineyard/model/environment_spec.rb +0 -198
  65. data/spec/engineyard/model/instance_spec.rb +0 -27
  66. data/spec/engineyard/resolver_spec.rb +0 -112
  67. data/spec/support/fake_awsm.ru +0 -245
  68. data/spec/support/scenarios.rb +0 -417
@@ -0,0 +1,133 @@
1
+ require 'escape'
2
+ require 'net/ssh'
3
+ require 'engineyard-serverside-adapter'
4
+
5
+ module EY
6
+ class ServersideRunner
7
+ def initialize(bridge, app, environment, verbose)
8
+ @verbose = verbose || ENV['DEBUG']
9
+ @adapter = load_adapter(bridge, app, environment)
10
+ @username = environment.username
11
+ @hostname = bridge
12
+ @command = nil
13
+ end
14
+
15
+ def deploy(&block)
16
+ @command = @adapter.deploy(&block)
17
+ self
18
+ end
19
+
20
+ def rollback(&block)
21
+ @command = @adapter.rollback(&block)
22
+ self
23
+ end
24
+
25
+ def put_up_maintenance_page(&block)
26
+ @command = @adapter.enable_maintenance_page(&block)
27
+ self
28
+ end
29
+
30
+ def take_down_maintenance_page(&block)
31
+ @command = @adapter.disable_maintenance_page(&block)
32
+ self
33
+ end
34
+
35
+ def call(out, err)
36
+ raise "No command!" unless @command
37
+ @command.call do |cmd|
38
+ run cmd, out, err
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def load_adapter(bridge, app, environment)
45
+ EY::Serverside::Adapter.new("/usr/local/ey_resin/ruby/bin") do |args|
46
+ args.app = app.name
47
+ args.repo = app.repository_uri
48
+ args.instances = instances_data(environment.deploy_to_instances, bridge)
49
+ args.stack = environment.app_server_stack_name
50
+ args.framework_env = environment.framework_env
51
+ args.environment_name = environment.name
52
+ args.account_name = app.account.name
53
+ args.verbose = @verbose
54
+ end
55
+ end
56
+
57
+ # If we tell engineyard-serverside to use 'localhost', it'll run
58
+ # commands on the instance directly (#system). If we give it the
59
+ # instance's actual hostname, it'll SSH to itself.
60
+ #
61
+ # Using 'localhost' instead of its EC2 hostname speeds up
62
+ # deploys on solos and single-app-server clusters significantly.
63
+ def instances_data(instances, bridge)
64
+ instances.map do |i|
65
+ {
66
+ :hostname => i.hostname == bridge ? 'localhost' : i.hostname,
67
+ :roles => [i.role],
68
+ :name => i.name,
69
+ }
70
+ end
71
+ end
72
+
73
+ def run(remote_command, out, err)
74
+ cmd = Escape.shell_command(['bash', '-lc', remote_command])
75
+
76
+ if cmd.respond_to?(:encoding) && cmd.respond_to?(:force_encoding)
77
+ out << "Encoding: #{cmd.encoding.name}" if @verbose
78
+ cmd.force_encoding('binary')
79
+ out << " => #{cmd.encoding.name}; __ENCODING__: #{__ENCODING__.name}; LANG: #{ENV['LANG']}; LC_CTYPE: #{ENV['LC_CTYPE']}\n" if @verbose
80
+ end
81
+
82
+ out << "Running command on #{@username}@#{@hostname}.\n"
83
+ out << cmd << "\n" if @verbose
84
+
85
+ if ENV["NO_SSH"]
86
+ out << "NO_SSH is set. No output.\n"
87
+ true
88
+ else
89
+ begin
90
+ ssh(cmd, @hostname, @username, out, err)
91
+ rescue Net::SSH::AuthenticationFailed
92
+ raise EY::Error, "Authentication Failed: Please add your environment's ssh key with: ssh-add path/to/key"
93
+ end
94
+ end
95
+ end
96
+
97
+ def ssh(cmd, hostname, username, out, err)
98
+ exit_code = 1
99
+ options_for_ssh = {:paranoid => false}
100
+ options_for_ssh[:verbose] = ENV["DEBUG"].downcase.to_sym if ENV["DEBUG"]
101
+ Net::SSH.start(hostname, username, options_for_ssh) do |net_ssh|
102
+ net_ssh.open_channel do |channel|
103
+ channel.exec cmd do |_, success|
104
+ unless success
105
+ err << "Remote command execution failed"
106
+ return false
107
+ end
108
+
109
+ channel.on_data do |_, data|
110
+ out << data
111
+ end
112
+
113
+ channel.on_extended_data do |_, _, data|
114
+ err << data
115
+ end
116
+
117
+ channel.on_request("exit-status") do |_, data|
118
+ exit_code = data.read_long
119
+ end
120
+
121
+ channel.on_request("exit-signal") do |_, data|
122
+ exit_code = 255
123
+ end
124
+ end
125
+ end
126
+
127
+ net_ssh.loop
128
+ end
129
+ exit_code.zero?
130
+ end
131
+
132
+ end
133
+ end
@@ -4,33 +4,125 @@ module EY
4
4
  module UtilityMethods
5
5
  protected
6
6
  def api
7
- @api ||= EY::CLI::API.new
7
+ @api ||= EY::CLI::API.new(config.endpoint, ui)
8
+ end
9
+
10
+ def config
11
+ @config ||= EY::Config.new
12
+ end
13
+
14
+ def ui
15
+ @ui ||= load_ui
16
+ end
17
+
18
+ def load_ui
19
+ Thor::Base.shell = EY::CLI::UI
20
+ EY::CLI::UI.new
21
+ end
22
+
23
+ def in_repo?
24
+ EY::Repo.exist?
8
25
  end
9
26
 
10
27
  def repo
11
28
  @repo ||= EY::Repo.new
12
29
  end
13
30
 
14
- def fetch_environment(environment_name, account_name=nil)
15
- environment_name ||= EY.config.default_environment
16
- options = {
31
+ def serverside_runner(app_env, verbose)
32
+ ServersideRunner.new(app_env.environment.bridge!.hostname, app_env.app, app_env.environment, verbose)
33
+ end
34
+
35
+ def use_default_environment
36
+ if env = config.default_environment
37
+ ui.say "Using default environment #{config.default_environment.inspect} from ey.yml."
38
+ env
39
+ end
40
+ end
41
+
42
+ def fetch_environment(environment_name, account_name)
43
+ environment_name ||= use_default_environment
44
+ remotes = repo.remotes if in_repo?
45
+ constraints = {
17
46
  :environment_name => environment_name,
18
- :account_name => account_name
47
+ :account_name => account_name,
48
+ :remotes => remotes,
19
49
  }
20
- options.merge! :repo => repo if repo.exist?
21
- api.resolver.environment(options)
50
+
51
+ resolver = api.resolve_environments(constraints)
52
+
53
+ resolver.one_match { |match| return match }
54
+
55
+ resolver.no_matches do |errors, suggestions|
56
+ raise_no_matches(errors, suggestions)
57
+ end
58
+
59
+ resolver.many_matches do |matches|
60
+ if environment_name
61
+ message = "Multiple environments possible, please be more specific:\n\n"
62
+ matches.each do |env|
63
+ message << "\t#{env.name.ljust(25)} # ey <command> --environment='#{env.name}' --account='#{env.account.name}'\n"
64
+ end
65
+ raise EY::MultipleMatchesError.new(message)
66
+ else
67
+ raise EY::AmbiguousEnvironmentGitUriError.new(matches)
68
+ end
69
+ end
22
70
  end
23
71
 
24
- def fetch_app_and_environment(app_name = nil, environment_name = nil, account_name=nil)
25
- options = {
26
- :app_name => app_name,
72
+ def fetch_app_environment(app_name, environment_name, account_name)
73
+ environment_name ||= use_default_environment
74
+ remotes = repo.remotes if in_repo?
75
+ constraints = {
76
+ :app_name => app_name,
27
77
  :environment_name => environment_name,
28
- :account_name => account_name
78
+ :account_name => account_name,
79
+ :remotes => remotes,
29
80
  }
30
- options.merge! :repo => repo if repo.exist?
31
- api.resolver.app_and_environment(options)
81
+
82
+ if constraints.all? { |k,v| v.nil? || v.empty? || v.to_s.empty? }
83
+ raise EY::NoMatchesError.new <<-ERROR
84
+ Unable to find application without a git remote URI or app name.
85
+
86
+ Please specify --app app_name or add this application at #{config.endpoint}"
87
+ ERROR
88
+ end
89
+
90
+ resolver = api.resolve_app_environments(constraints)
91
+
92
+ resolver.one_match { |match| return match }
93
+ resolver.no_matches do |errors, suggestions|
94
+ raise_no_matches(errors, suggestions)
95
+ end
96
+ resolver.many_matches do |app_envs|
97
+ raise EY::MultipleMatchesError.new(too_many_app_environments_error(app_envs))
98
+ end
99
+ end
100
+
101
+ def raise_no_matches(errors, suggestions)
102
+ message = "We found the following suggestions:\n" if suggestions.any?
103
+
104
+ suggestions.each do |suggest|
105
+ message << " # ey <command> --account='#{suggest['account_name']}' --app='#{suggest['app_name']}' --environment='#{suggest['env_name']}'\n"
106
+ end
107
+
108
+ raise EY::NoMatchesError.new([errors,message].compact.join("\n").strip)
32
109
  end
33
110
 
111
+ def too_many_app_environments_error(app_envs)
112
+ message = "Multiple application environments possible, please be more specific:\n\n"
113
+
114
+ app_envs.group_by do |app_env|
115
+ [app_env.account_name, app_env.app_name]
116
+ end.sort_by { |k,v| k.join }.each do |(account_name, app_name), grouped_app_envs|
117
+ message << "\n"
118
+ message << account_name << "/" << app_name << "\n"
119
+ grouped_app_envs.map { |ae| ae.environment_name }.uniq.sort.each do |env_name|
120
+ message << "\t#{env_name.ljust(25)}"
121
+ message << " # ey <command> --account='#{account_name}' --app='#{app_name}' --environment='#{env_name}'\n"
122
+ end
123
+ end
124
+ message
125
+ end
34
126
  end # UtilityMethods
35
127
 
36
128
  class Thor < ::Thor
@@ -44,13 +136,13 @@ module EY
44
136
  class_eval <<-RUBY
45
137
  def help(*args)
46
138
  if args.empty?
47
- EY.ui.say "usage: #{banner_base} #{cmd} COMMAND"
48
- EY.ui.say
139
+ ui.say "usage: #{banner_base} #{cmd} COMMAND"
140
+ ui.say
49
141
  subcommands = self.class.printable_tasks.sort_by{|s| s[0] }
50
142
  subcommands.reject!{|t| t[0] =~ /#{cmd} help$/}
51
- EY.ui.print_help(subcommands)
52
- EY.ui.say self.class.send(:class_options_help, EY.ui)
53
- EY.ui.say "See #{banner_base} #{cmd} help COMMAND" +
143
+ ui.print_help(subcommands)
144
+ ui.say self.class.send(:class_options_help, ui)
145
+ ui.say "See #{banner_base} #{cmd} help COMMAND" +
54
146
  " for more information on a specific subcommand." if args.empty?
55
147
  else
56
148
  super
@@ -1,3 +1,3 @@
1
1
  module EY
2
- VERSION = '1.4.29'
2
+ VERSION = '1.7.0.pre2'
3
3
  end
@@ -2,42 +2,36 @@ require 'spec_helper'
2
2
  require 'engineyard/cli'
3
3
 
4
4
  describe EY::CLI::API do
5
- before(:all) do
6
- EY.ui = EY::CLI::UI.new
7
- end
8
-
9
- after(:all) do
10
- EY.ui = EY::UI.new
11
- end
12
-
13
5
  it "gets the api token from ~/.eyrc if possible" do
14
6
  write_eyrc({"api_token" => "asdf"})
15
- EY::CLI::API.new.should == EY::CLI::API.new("asdf")
7
+ EY::CLI::API.new('http://fake.local', EY::CLI::UI.new).token.should == "asdf"
8
+ clean_eyrc
16
9
  end
17
10
 
18
11
  it "uses the token from $ENGINEYARD_API_TOKEN if set" do
19
12
  ENV['ENGINEYARD_API_TOKEN'] = 'envtoken'
20
- EY::CLI::API.new.token.should == 'envtoken'
13
+ EY::CLI::API.new('http://fake.local', EY::CLI::UI.new).token.should == 'envtoken'
21
14
  ENV.delete('ENGINEYARD_API_TOKEN')
22
15
  end
23
16
 
24
17
  context "without saved api token" do
25
18
  before(:each) do
26
- FakeWeb.register_uri(:post, "https://cloud.engineyard.com/api/v2/authenticate", :body => %|{"api_token": "asdf"}|, :content_type => 'application/json')
19
+ clean_eyrc
20
+ FakeWeb.register_uri(:post, "http://fake.local/api/v2/authenticate", :body => %|{"api_token": "asdf"}|, :content_type => 'application/json')
27
21
 
28
22
  EY::CLI::UI::Prompter.enable_mock!
29
- EY::CLI::UI::Prompter.backend.next_answer = "my@email.example.com"
30
- EY::CLI::UI::Prompter.backend.next_answer = "secret"
23
+ EY::CLI::UI::Prompter.add_answer "my@email.example.com"
24
+ EY::CLI::UI::Prompter.add_answer "secret"
31
25
 
32
- @api = EY::CLI::API.new
26
+ @api = EY::CLI::API.new('http://fake.local', EY::CLI::UI.new)
33
27
  end
34
28
 
35
29
  it "asks you for your credentials" do
36
- EY::CLI::UI::Prompter.backend.questions.should == ["Email: ","Password: "]
30
+ EY::CLI::UI::Prompter.questions.should == ["Email: ","Password: "]
37
31
  end
38
32
 
39
33
  it "gets the api token" do
40
- @api.should == EY::CLI::API.new("asdf")
34
+ @api.token.should == "asdf"
41
35
  end
42
36
 
43
37
  it "saves the api token to ~/.eyrc" do
@@ -3,15 +3,6 @@ require 'engineyard/cli'
3
3
 
4
4
  describe EY::CLI do
5
5
 
6
- it "sets up EY.ui" do
7
- EY.instance_eval{ @ui = nil }
8
- EY.ui.should be_an(EY::UI)
9
- capture_stdout do
10
- EY::CLI.start(["help"])
11
- end
12
- EY.ui.should be_an(EY::CLI::UI)
13
- end
14
-
15
6
  it "provides help" do
16
7
  out = capture_stdout do
17
8
  EY::CLI.start(["help"])
@@ -31,8 +22,6 @@ describe EY::CLI do
31
22
  end
32
23
 
33
24
  it "provides error classes" do
34
- EY::EnvironmentError.should be
35
- EY::BranchMismatchError.should be
36
25
  EY::DeployArgumentError.should be
37
26
  end
38
27
 
@@ -23,14 +23,7 @@ describe EY::Config do
23
23
 
24
24
  it "loads the endpoint from $CLOUD_URL" do
25
25
  ENV['CLOUD_URL'] = "http://fake.local/"
26
- EY::Config.new.endpoint.should == URI.parse('http://fake.local')
27
- ENV.delete('CLOUD_URL')
28
- end
29
-
30
- it "raises on an invalid endpoint" do
31
- ENV['CLOUD_URL'] = "non/absolute"
32
- lambda { EY::Config.new.endpoint }.
33
- should raise_error(EY::Config::ConfigurationError)
26
+ EY::Config.new.endpoint.should == 'http://fake.local/'
34
27
  ENV.delete('CLOUD_URL')
35
28
  end
36
29
  end
@@ -0,0 +1,203 @@
1
+ require 'spec_helper'
2
+
3
+ describe EY::DeployConfig::Migrate do
4
+ before do
5
+ @parent = mock('parent config mock')
6
+ @parent.stub!(:set_environment_option)
7
+ @parent.stub!(:path).and_return('path')
8
+ @ui = EY::CLI::UI.new
9
+ EY::CLI::UI::Prompter.enable_mock!
10
+ @repo = mock('repo')
11
+ end
12
+
13
+ def env_config(opts=nil)
14
+ @env_config ||= EY::Config::EnvironmentConfig.new(opts, 'envname', @parent)
15
+ end
16
+
17
+ def deploy_config(cli_options)
18
+ EY::DeployConfig.new(cli_options, env_config, @repo, @ui)
19
+ end
20
+
21
+ context "inside a repository" do
22
+ context "no migrate options set (interactive)" do
23
+ it "prompts migrate and command by default" do
24
+ EY::CLI::UI::Prompter.add_answer "" # default
25
+ EY::CLI::UI::Prompter.add_answer ""
26
+ @parent.should_receive(:set_environment_option).with('envname', 'migrate', true)
27
+ @parent.should_receive(:set_environment_option).with('envname', 'migration_command', 'rake db:migrate')
28
+ dc = deploy_config({})
29
+ dc.migrate.should be_true
30
+ dc.migrate_command.should == 'rake db:migrate'
31
+ end
32
+
33
+ it "prompts migration_command if first answer is yes" do
34
+ EY::CLI::UI::Prompter.add_answer "yes" # default
35
+ EY::CLI::UI::Prompter.add_answer "ruby script/migrate"
36
+ @parent.should_receive(:set_environment_option).with('envname', 'migrate', true)
37
+ @parent.should_receive(:set_environment_option).with('envname', 'migration_command', 'ruby script/migrate')
38
+ dc = deploy_config({})
39
+ dc.migrate.should be_true
40
+ dc.migrate_command.should == 'ruby script/migrate'
41
+ end
42
+
43
+ it "doesn't prompt migration_command if first answer is no" do
44
+ EY::CLI::UI::Prompter.add_answer "no" # default
45
+ @parent.should_receive(:set_environment_option).with('envname', 'migrate', false)
46
+ dc = deploy_config({})
47
+ dc.migrate.should be_false
48
+ dc.migrate_command.should be_nil
49
+ end
50
+ end
51
+
52
+ context "with the migrate cli option" do
53
+ it "returns the default migration command when is true" do
54
+ dc = deploy_config({'migrate' => true})
55
+ dc.migrate.should be_true
56
+ dc.migrate_command.should == 'rake db:migrate'
57
+ end
58
+
59
+ it "returns false when nil" do
60
+ dc = deploy_config({'migrate' => nil})
61
+ dc.migrate.should be_false
62
+ dc.migrate_command.should be_nil
63
+ end
64
+
65
+ it "return the custom migration command when is a string" do
66
+ dc = deploy_config({'migrate' => 'foo migrate'})
67
+ dc.migrate.should be_true
68
+ dc.migrate_command.should == 'foo migrate'
69
+ end
70
+ end
71
+
72
+ context "with the migrate option in the global configuration" do
73
+ it "return the default migration command when the option is true" do
74
+ env_config('migrate' => true, 'migration_command' => 'bar migrate')
75
+ dc = deploy_config({})
76
+ dc.migrate.should be_true
77
+ dc.migrate_command.should == 'bar migrate'
78
+ end
79
+
80
+ it "return the false when migrate is false" do
81
+ env_config('migrate' => false, 'migration_command' => 'bar migrate')
82
+ dc = deploy_config({})
83
+ dc.migrate.should be_false
84
+ dc.migrate_command.should be_nil
85
+ end
86
+
87
+ it "return the default migration command when the option is true" do
88
+ env_config('migrate' => true)
89
+ dc = deploy_config({})
90
+ dc.migrate.should be_true
91
+ dc.migrate_command.should == 'rake db:migrate'
92
+ end
93
+
94
+ it "return the ey.yml migration_command when command line option --migrate is passed" do
95
+ env_config('migrate' => false, 'migration_command' => 'bar migrate')
96
+ dc = deploy_config({'migrate' => true})
97
+ dc.migrate.should be_true
98
+ dc.migrate_command.should == 'bar migrate'
99
+ end
100
+ end
101
+
102
+ describe "ref" do
103
+ it "returns the passed ref" do
104
+ deploy_config({'ref' => 'master'}).ref.should == 'master'
105
+ end
106
+
107
+ it "returns the passed force_ref" do
108
+ deploy_config({'force_ref' => 'force'}).ref.should == 'force'
109
+ end
110
+
111
+ it "returns the ref if force_ref is true" do
112
+ deploy_config({'ref' => 'master', 'force_ref' => true}).ref.should == 'master'
113
+ end
114
+
115
+ it "overrides the ref if force_ref is set to a string" do
116
+ deploy_config({'ref' => 'master', 'force_ref' => 'force'}).ref.should == 'force'
117
+ end
118
+
119
+ context "with a default branch" do
120
+ before { env_config('branch' => 'default') }
121
+
122
+ it "uses the configured default if ref is not passed" do
123
+ deploy_config({}).ref.should == 'default'
124
+ end
125
+
126
+ it "raises if a default is set and --ref is passed on the cli (and they don't match)" do
127
+ lambda { deploy_config({'ref' => 'master'}).ref }.should raise_error(EY::BranchMismatchError)
128
+ end
129
+
130
+ it "returns the default if a default is set and --ref is the same" do
131
+ deploy_config({'ref' => 'default'}).ref.should == 'default'
132
+ end
133
+
134
+ it "returns the ref if force_ref is set" do
135
+ deploy_config({'ref' => 'master', 'force_ref' => true}).ref.should == 'master'
136
+ end
137
+
138
+ it "returns the ref if force_ref is a branch" do
139
+ deploy_config({'force_ref' => 'master'}).ref.should == 'master'
140
+ end
141
+ end
142
+
143
+ context "no options, no default" do
144
+ it "uses the repo's current branch" do
145
+ @repo.should_receive(:current_branch).and_return('current')
146
+ deploy_config({}).ref.should == 'current'
147
+ end
148
+ end
149
+ end
150
+ end
151
+
152
+ context "when outside of a repo" do
153
+ describe "migrate" do
154
+ it "returns the default migration command when migrate is true" do
155
+ dc = deploy_config({'app' => 'app', 'migrate' => true})
156
+ dc.migrate.should be_true
157
+ dc.migrate_command.should == 'rake db:migrate'
158
+ end
159
+
160
+ it "returns false when nil" do
161
+ dc = deploy_config({'app' => 'app', 'migrate' => nil})
162
+ dc.migrate.should be_false
163
+ dc.migrate_command.should be_nil
164
+ end
165
+
166
+ it "return the custom migration command when is a string" do
167
+ dc = deploy_config({'app' => 'app', 'migrate' => 'foo migrate'})
168
+ dc.migrate.should be_true
169
+ dc.migrate_command.should == 'foo migrate'
170
+ end
171
+
172
+ it "raises if migrate is not passed" do
173
+ lambda { deploy_config({'app' => 'app'}).migrate }.should raise_error(EY::RefAndMigrateRequiredOutsideRepo)
174
+ end
175
+ end
176
+
177
+ describe "ref" do
178
+ it "returns the passed ref" do
179
+ dc = deploy_config({'app' => 'app', 'ref' => 'master'})
180
+ dc.ref.should == 'master'
181
+ end
182
+
183
+ it "returns the passed force_ref" do
184
+ dc = deploy_config({'app' => 'app', 'force_ref' => 'force'})
185
+ dc.ref.should == 'force'
186
+ end
187
+
188
+ it "returns the ref if force_ref is true" do
189
+ dc = deploy_config({'app' => 'app', 'ref' => 'master', 'force_ref' => true})
190
+ dc.ref.should == 'master'
191
+ end
192
+
193
+ it "overrides the ref if force_ref is set to a string" do
194
+ dc = deploy_config({'app' => 'app', 'ref' => 'master', 'force_ref' => 'force'})
195
+ dc.ref.should == 'force'
196
+ end
197
+
198
+ it "raises if ref is not passed" do
199
+ lambda { deploy_config({'app' => 'app'}).ref }.should raise_error(EY::RefAndMigrateRequiredOutsideRepo)
200
+ end
201
+ end
202
+ end
203
+ end