engineyard 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/engineyard.rb +1 -1
- data/lib/engineyard/api.rb +12 -1
- data/lib/engineyard/cli.rb +116 -48
- data/lib/engineyard/cli/recipes.rb +37 -7
- data/lib/engineyard/cli/ui.rb +8 -0
- data/lib/engineyard/cli/web.rb +41 -0
- data/lib/engineyard/error.rb +8 -1
- data/lib/engineyard/model/environment.rb +32 -6
- data/lib/engineyard/model/instance.rb +39 -20
- data/lib/engineyard/repo.rb +7 -3
- data/lib/engineyard/thor.rb +55 -2
- data/spec/engineyard/api_spec.rb +2 -2
- data/spec/engineyard/cli/api_spec.rb +1 -1
- data/spec/engineyard/model/environment_spec.rb +8 -6
- data/spec/ey/deploy_spec.rb +46 -81
- data/spec/ey/ey_spec.rb +2 -2
- data/spec/ey/list_environments_spec.rb +1 -1
- data/spec/ey/logs_spec.rb +11 -21
- data/spec/ey/rebuild_spec.rb +8 -33
- data/spec/ey/recipes/apply_spec.rb +8 -33
- data/spec/ey/recipes/download_spec.rb +29 -0
- data/spec/ey/recipes/upload_spec.rb +8 -25
- data/spec/ey/rollback_spec.rb +10 -40
- data/spec/ey/ssh_spec.rb +17 -34
- data/spec/ey/web/disable_spec.rb +18 -0
- data/spec/ey/web/enable_spec.rb +18 -0
- data/spec/spec_helper.rb +7 -3
- data/spec/support/fake_awsm.ru +18 -0
- data/spec/support/helpers.rb +13 -0
- data/spec/support/shared_behavior.rb +132 -0
- metadata +8 -3
@@ -3,7 +3,7 @@ require 'escape'
|
|
3
3
|
module EY
|
4
4
|
module Model
|
5
5
|
class Instance < ApiStruct.new(:id, :role, :status, :amazon_id, :public_hostname, :environment)
|
6
|
-
EYSD_VERSION = "~>0.4.
|
6
|
+
EYSD_VERSION = "~>0.4.1"
|
7
7
|
CHECK_SCRIPT = <<-SCRIPT
|
8
8
|
require "rubygems"
|
9
9
|
requirement = Gem::Requirement.new("#{EYSD_VERSION}")
|
@@ -29,7 +29,8 @@ exit(17) # required_version < current_version
|
|
29
29
|
|
30
30
|
alias :hostname :public_hostname
|
31
31
|
|
32
|
-
|
32
|
+
|
33
|
+
def deploy(app, ref, migration_command=nil, extra_configuration=nil)
|
33
34
|
deploy_cmd = [eysd_path, 'deploy', '--app', app.name, '--branch', ref]
|
34
35
|
|
35
36
|
if extra_configuration
|
@@ -43,18 +44,42 @@ exit(17) # required_version < current_version
|
|
43
44
|
ssh Escape.shell_command(deploy_cmd)
|
44
45
|
end
|
45
46
|
|
46
|
-
def
|
47
|
+
def rollback(app, extra_configuration=nil)
|
48
|
+
deploy_cmd = [eysd_path, 'deploy', 'rollback', '--app', app.name]
|
49
|
+
|
50
|
+
if extra_configuration
|
51
|
+
deploy_cmd << '--config' << extra_configuration.to_json
|
52
|
+
end
|
53
|
+
|
54
|
+
ssh Escape.shell_command(deploy_cmd)
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
def put_up_maintenance_page(app)
|
59
|
+
ssh Escape.shell_command([
|
60
|
+
eysd_path, 'deploy', 'enable_maintenance_page', '--app', app.name
|
61
|
+
])
|
62
|
+
end
|
63
|
+
|
64
|
+
def take_down_maintenance_page(app)
|
65
|
+
ssh Escape.shell_command([
|
66
|
+
eysd_path, 'deploy', 'disable_maintenance_page', '--app', app.name
|
67
|
+
])
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
def ensure_eysd_present
|
47
72
|
case ey_deploy_check
|
48
73
|
when :ssh_failed
|
49
74
|
raise EnvironmentError, "SSH connection to #{hostname} failed"
|
50
75
|
when :eysd_missing
|
51
76
|
yield :installing if block_given?
|
52
|
-
install_ey_deploy
|
77
|
+
install_ey_deploy
|
53
78
|
when :too_new
|
54
79
|
raise EnvironmentError, "server-side component too new; please upgrade your copy of the engineyard gem."
|
55
80
|
when :too_old
|
56
81
|
yield :upgrading if block_given?
|
57
|
-
upgrade_ey_deploy
|
82
|
+
upgrade_ey_deploy
|
58
83
|
when :ok
|
59
84
|
# no action needed
|
60
85
|
else
|
@@ -66,26 +91,20 @@ exit(17) # required_version < current_version
|
|
66
91
|
require 'base64'
|
67
92
|
encoded_script = Base64.encode64(CHECK_SCRIPT).gsub(/\n/, '')
|
68
93
|
ssh "#{ruby_path} -r base64 -e \"eval Base64.decode64(ARGV[0])\" #{encoded_script}", false
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
ssh(Escape.shell_command(['sudo', gem_path, 'install', 'ey-deploy', '-v', EYSD_VERSION]))
|
74
|
-
end
|
75
|
-
|
76
|
-
def rollback!(app, extra_configuration=nil)
|
77
|
-
deploy_cmd = [eysd_path, 'deploy', 'rollback', '--app', app.name]
|
78
|
-
|
79
|
-
if extra_configuration
|
80
|
-
deploy_cmd << '--config' << extra_configuration.to_json
|
94
|
+
if ENV["NO_SSH"]
|
95
|
+
:ok
|
96
|
+
else
|
97
|
+
EXIT_STATUS[$?.exitstatus]
|
81
98
|
end
|
99
|
+
end
|
82
100
|
|
83
|
-
|
101
|
+
def install_ey_deploy
|
102
|
+
ssh(Escape.shell_command(['sudo', gem_path, 'install', 'ey-deploy', '--no-rdoc', '--no-ri', '-v', EYSD_VERSION]))
|
84
103
|
end
|
85
104
|
|
86
|
-
def upgrade_ey_deploy
|
105
|
+
def upgrade_ey_deploy
|
87
106
|
ssh "sudo #{gem_path} uninstall -a -x ey-deploy"
|
88
|
-
install_ey_deploy
|
107
|
+
install_ey_deploy
|
89
108
|
end
|
90
109
|
|
91
110
|
private
|
data/lib/engineyard/repo.rb
CHANGED
@@ -6,9 +6,13 @@ module EY
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def current_branch
|
9
|
-
|
10
|
-
|
11
|
-
head
|
9
|
+
if File.directory?(File.join(@path, ".git"))
|
10
|
+
head = File.read(File.join(@path, ".git/HEAD")).chomp
|
11
|
+
if head.gsub!("ref: refs/heads/", "")
|
12
|
+
head
|
13
|
+
else
|
14
|
+
nil
|
15
|
+
end
|
12
16
|
else
|
13
17
|
nil
|
14
18
|
end
|
data/lib/engineyard/thor.rb
CHANGED
@@ -9,17 +9,56 @@ module EY
|
|
9
9
|
end
|
10
10
|
|
11
11
|
no_tasks do
|
12
|
-
def
|
13
|
-
@@
|
12
|
+
def self.subcommands
|
13
|
+
@@subcommands ||= {}
|
14
14
|
end
|
15
15
|
|
16
16
|
def self.subcommand(subcommand, subcommand_class)
|
17
|
+
subcommand = subcommand.to_s
|
18
|
+
subcommands[subcommand] = subcommand_class
|
19
|
+
subcommand_class.subcommand_help subcommand
|
17
20
|
define_method(subcommand) { |*_| subcommand_class.start(subcommand_args) }
|
18
21
|
end
|
22
|
+
|
23
|
+
def self.subcommand_help(cmd)
|
24
|
+
desc "help #{cmd} [SUBCOMMAND]", "Describe all subcommands or one specific subcommand."
|
25
|
+
|
26
|
+
class_eval <<-RUBY
|
27
|
+
def help(*args)
|
28
|
+
super
|
29
|
+
if args.empty?
|
30
|
+
banner = "See '" + self.class.send(:banner_base) + " help #{cmd} [SUBCOMMAND]' "
|
31
|
+
text = "for more information on a specific subcommand."
|
32
|
+
EY.ui.say banner + text
|
33
|
+
end
|
34
|
+
end
|
35
|
+
RUBY
|
36
|
+
end
|
37
|
+
|
38
|
+
def subcommand_args
|
39
|
+
@@original_args[1..-1]
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.printable_tasks(all=true)
|
43
|
+
(all ? all_tasks : tasks).map do |_, task|
|
44
|
+
item = []
|
45
|
+
item << banner(task)
|
46
|
+
item << (task.description ? "# #{task.description.gsub(/\n.*/,'')}" : "")
|
47
|
+
item
|
48
|
+
end
|
49
|
+
end
|
19
50
|
end
|
20
51
|
|
21
52
|
protected
|
22
53
|
|
54
|
+
def self.handle_no_task_error(task)
|
55
|
+
if self.banner_base == "thor"
|
56
|
+
raise UndefinedTaskError, "Could not find command #{task.inspect} in #{namespace.inspect} namespace."
|
57
|
+
else
|
58
|
+
raise UndefinedTaskError, "Could not find command #{task.inspect}."
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
23
62
|
def self.exit_on_failure?
|
24
63
|
true
|
25
64
|
end
|
@@ -32,6 +71,20 @@ module EY
|
|
32
71
|
@repo ||= EY::Repo.new
|
33
72
|
end
|
34
73
|
|
74
|
+
def loudly_check_eysd(environment)
|
75
|
+
environment.ensure_eysd_present do |action|
|
76
|
+
case action
|
77
|
+
when :installing
|
78
|
+
EY.ui.warn "Instance does not have server-side component installed"
|
79
|
+
EY.ui.info "Installing server-side component..."
|
80
|
+
when :upgrading
|
81
|
+
EY.ui.info "Upgrading server-side component..."
|
82
|
+
else
|
83
|
+
# nothing slow is happening, so there's nothing to say
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
35
88
|
# if an app is supplied, it is used as a constraint for implied environment lookup
|
36
89
|
def fetch_environment(env_name, app = nil)
|
37
90
|
env_name ||= EY.config.default_environment
|
data/spec/engineyard/api_spec.rb
CHANGED
@@ -8,7 +8,7 @@ describe EY::API do
|
|
8
8
|
|
9
9
|
context "fetching the token from EY cloud" do
|
10
10
|
before(:each) do
|
11
|
-
FakeWeb.register_uri(:post, "https://cloud.engineyard.com/api/v2/authenticate", :body => %|{"api_token": "asdf"}
|
11
|
+
FakeWeb.register_uri(:post, "https://cloud.engineyard.com/api/v2/authenticate", :body => %|{"api_token": "asdf"}|, :content_type => 'application/json')
|
12
12
|
@token = EY::API.fetch_token("a@b.com", "foo")
|
13
13
|
end
|
14
14
|
|
@@ -46,7 +46,7 @@ describe EY::API do
|
|
46
46
|
end
|
47
47
|
|
48
48
|
it "raises InvalidCredentials when the credentials are invalid" do
|
49
|
-
FakeWeb.register_uri(:post, "https://cloud.engineyard.com/api/v2/authenticate", :status => 401)
|
49
|
+
FakeWeb.register_uri(:post, "https://cloud.engineyard.com/api/v2/authenticate", :status => 401, :content_type => 'application/json')
|
50
50
|
|
51
51
|
lambda {
|
52
52
|
EY::API.fetch_token("a@b.com", "foo")
|
@@ -20,7 +20,7 @@ describe EY::CLI::API do
|
|
20
20
|
|
21
21
|
context "without saved api token" do
|
22
22
|
before(:each) do
|
23
|
-
FakeWeb.register_uri(:post, "https://cloud.engineyard.com/api/v2/authenticate", :body => %|{"api_token": "asdf"}
|
23
|
+
FakeWeb.register_uri(:post, "https://cloud.engineyard.com/api/v2/authenticate", :body => %|{"api_token": "asdf"}|, :content_type => 'application/json')
|
24
24
|
|
25
25
|
capture_stdio("\n\n") do
|
26
26
|
@token = EY::CLI::API.new
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe "EY::Model::Environment#rebuild" do
|
4
|
-
|
4
|
+
given "it has an api"
|
5
5
|
|
6
6
|
it "hits the rebuild action in the API" do
|
7
7
|
env = EY::Model::Environment.from_hash({
|
@@ -22,7 +22,7 @@ describe "EY::Model::Environment#rebuild" do
|
|
22
22
|
end
|
23
23
|
|
24
24
|
describe "EY::Model::Environment#run_custom_recipes" do
|
25
|
-
|
25
|
+
given "it has an api"
|
26
26
|
|
27
27
|
it "hits the rebuild action in the API" do
|
28
28
|
env = EY::Model::Environment.from_hash({
|
@@ -33,7 +33,8 @@ describe "EY::Model::Environment#run_custom_recipes" do
|
|
33
33
|
FakeWeb.register_uri(
|
34
34
|
:put,
|
35
35
|
"https://cloud.engineyard.com/api/v2/environments/#{env.id}/run_custom_recipes",
|
36
|
-
:body => ''
|
36
|
+
:body => '',
|
37
|
+
:content_type => 'application/json'
|
37
38
|
)
|
38
39
|
|
39
40
|
env.run_custom_recipes
|
@@ -56,7 +57,7 @@ describe "EY::Model::Environment.from_array" do
|
|
56
57
|
end
|
57
58
|
|
58
59
|
describe "EY::Model::Environment#instances" do
|
59
|
-
|
60
|
+
given "it has an api"
|
60
61
|
|
61
62
|
it "returns instances" do
|
62
63
|
env = EY::Model::Environment.from_hash({
|
@@ -72,8 +73,9 @@ describe "EY::Model::Environment#instances" do
|
|
72
73
|
}
|
73
74
|
FakeWeb.register_uri(:get,
|
74
75
|
"https://cloud.engineyard.com/api/v2/environments/#{env.id}/instances",
|
75
|
-
:body => {"instances" => [instance_data]}.to_json
|
76
|
-
|
76
|
+
:body => {"instances" => [instance_data]}.to_json,
|
77
|
+
:content_type => 'application/json'
|
78
|
+
)
|
77
79
|
|
78
80
|
env.should have(1).instances
|
79
81
|
env.instances.first.should == EY::Model::Instance.from_hash(instance_data.merge(:environment => env))
|
data/spec/ey/deploy_spec.rb
CHANGED
@@ -2,7 +2,7 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe "ey deploy without an eyrc file" do
|
4
4
|
|
5
|
-
|
5
|
+
given "integration without an eyrc file"
|
6
6
|
|
7
7
|
before(:each) do
|
8
8
|
FileUtils.rm_rf(ENV['EYRC'])
|
@@ -22,8 +22,27 @@ describe "ey deploy without an eyrc file" do
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
+
|
25
26
|
describe "ey deploy" do
|
26
|
-
|
27
|
+
given "integration"
|
28
|
+
|
29
|
+
def command_to_run(options)
|
30
|
+
cmd = "deploy"
|
31
|
+
cmd << " -e #{options[:env]}" if options[:env]
|
32
|
+
cmd
|
33
|
+
end
|
34
|
+
|
35
|
+
def verify_ran(scenario)
|
36
|
+
@out.should match(/Running deploy for '#{scenario[:environment]}'/)
|
37
|
+
end
|
38
|
+
|
39
|
+
# common behavior
|
40
|
+
it_should_behave_like "it takes an environment name"
|
41
|
+
it_should_behave_like "it invokes eysd"
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "ey deploy" do
|
45
|
+
given "integration"
|
27
46
|
|
28
47
|
context "with invalid input" do
|
29
48
|
it "complains when there is no app" do
|
@@ -32,15 +51,9 @@ describe "ey deploy" do
|
|
32
51
|
@err.should include(%|no application configured|)
|
33
52
|
end
|
34
53
|
|
35
|
-
it "complains when you specify a nonexistent environment" do
|
36
|
-
api_scenario "one app, one environment"
|
37
|
-
ey "deploy typo-happens-here master", :expect_failure => true
|
38
|
-
@err.should match(/no environment named 'typo-happens-here'/i)
|
39
|
-
end
|
40
|
-
|
41
54
|
it "complains when the specified environment does not contain the app" do
|
42
55
|
api_scenario "one app, one environment, not linked"
|
43
|
-
ey "deploy giblets master", :expect_failure => true
|
56
|
+
ey "deploy -e giblets -r master", :expect_failure => true
|
44
57
|
@err.should match(/does not run this application/i)
|
45
58
|
end
|
46
59
|
|
@@ -52,19 +65,12 @@ describe "ey deploy" do
|
|
52
65
|
|
53
66
|
it "complains when the app master is in a non-running state" do
|
54
67
|
api_scenario "one app, one environment, app master red"
|
55
|
-
ey "deploy giblets master", :expect_failure => true
|
68
|
+
ey "deploy --environment giblets --ref master", :expect_failure => true
|
56
69
|
@err.should_not match(/No running instances/i)
|
57
70
|
@err.should match(/running.*\(green\)/)
|
58
71
|
end
|
59
72
|
end
|
60
73
|
|
61
|
-
it "runs when environment is known" do
|
62
|
-
api_scenario "one app, one environment"
|
63
|
-
ey "deploy", :hide_err => true
|
64
|
-
@out.should match(/running deploy/i)
|
65
|
-
@err.should be_empty
|
66
|
-
end
|
67
|
-
|
68
74
|
context "migration command" do
|
69
75
|
before(:each) do
|
70
76
|
api_scenario "one app, one environment"
|
@@ -86,11 +92,6 @@ describe "ey deploy" do
|
|
86
92
|
@ssh_commands.last.should =~ /eysd deploy/
|
87
93
|
@ssh_commands.last.should_not =~ /--migrate/
|
88
94
|
end
|
89
|
-
|
90
|
-
it "can be disabled with --no-migrate in the middle of the command line" do
|
91
|
-
ey "deploy --no-migrate giblets master"
|
92
|
-
@ssh_commands.last.should_not =~ /--migrate/
|
93
|
-
end
|
94
95
|
end
|
95
96
|
|
96
97
|
context "choosing something to deploy" do
|
@@ -120,14 +121,24 @@ describe "ey deploy" do
|
|
120
121
|
end
|
121
122
|
|
122
123
|
it "deploys another branch if given" do
|
123
|
-
ey "deploy
|
124
|
+
ey "deploy --ref master"
|
124
125
|
@ssh_commands.last.should =~ /--branch master/
|
125
126
|
end
|
126
127
|
|
127
128
|
it "deploys a tag if given" do
|
128
|
-
ey "deploy
|
129
|
+
ey "deploy --ref v1"
|
129
130
|
@ssh_commands.last.should =~ /--branch v1/
|
130
131
|
end
|
132
|
+
|
133
|
+
it "allows using --branch to specify a branch" do
|
134
|
+
ey "deploy --branch master"
|
135
|
+
@ssh_commands.last.should match(/--branch master/)
|
136
|
+
end
|
137
|
+
|
138
|
+
it "allows using --tag to specify the tag" do
|
139
|
+
ey "deploy --tag v1"
|
140
|
+
@ssh_commands.last.should match(/--branch v1/)
|
141
|
+
end
|
131
142
|
end
|
132
143
|
|
133
144
|
context "when there is extra configuration" do
|
@@ -160,12 +171,12 @@ describe "ey deploy" do
|
|
160
171
|
end
|
161
172
|
|
162
173
|
it "complains about a non-default branch without --force" do
|
163
|
-
ey "deploy
|
174
|
+
ey "deploy -r current-branch", :expect_failure => true
|
164
175
|
@err.should =~ /deploy branch is set to "master"/
|
165
176
|
end
|
166
177
|
|
167
178
|
it "deploys a non-default branch with --force" do
|
168
|
-
ey "deploy
|
179
|
+
ey "deploy -r current-branch --force"
|
169
180
|
@ssh_commands.last.should =~ /--branch current-branch/
|
170
181
|
end
|
171
182
|
end
|
@@ -176,72 +187,26 @@ describe "ey deploy" do
|
|
176
187
|
api_scenario "one app, many similarly-named environments"
|
177
188
|
end
|
178
189
|
|
179
|
-
it "lets you choose by unambiguous substring" do
|
180
|
-
ey "deploy prod"
|
181
|
-
@out.should match(/Running deploy for 'railsapp_production'/)
|
182
|
-
end
|
183
|
-
|
184
190
|
it "lets you choose by complete name even if the complete name is ambiguous" do
|
185
|
-
ey "deploy railsapp_staging"
|
191
|
+
ey "deploy --environment railsapp_staging"
|
186
192
|
@out.should match(/Running deploy for 'railsapp_staging'/)
|
187
193
|
end
|
188
|
-
|
189
|
-
it "complains when given an ambiguous substring" do
|
190
|
-
# NB: there's railsapp_staging and railsapp_staging_2
|
191
|
-
ey "deploy staging", :hide_err => true, :expect_failure => true
|
192
|
-
@err.should match(/'staging' is ambiguous/)
|
193
|
-
end
|
194
194
|
end
|
195
195
|
|
196
|
-
context "
|
196
|
+
context "specifying the application" do
|
197
197
|
before(:all) do
|
198
198
|
api_scenario "one app, one environment"
|
199
|
+
Dir.chdir(File.expand_path("~"))
|
199
200
|
end
|
200
201
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
after(:each) do
|
206
|
-
ENV['NO_SSH'] = "true"
|
207
|
-
end
|
208
|
-
|
209
|
-
def exiting_ssh(exit_code)
|
210
|
-
"#!/usr/bin/env ruby\n exit!(#{exit_code}) if ARGV.to_s =~ /Base64.decode64/"
|
211
|
-
end
|
212
|
-
|
213
|
-
it "raises an error if SSH fails" do
|
214
|
-
ey "deploy", :prepend_to_path => {'ssh' => exiting_ssh(255)}, :expect_failure => true
|
215
|
-
@err.should =~ /SSH connection to \S+ failed/
|
216
|
-
end
|
217
|
-
|
218
|
-
it "installs ey-deploy if it's missing" do
|
219
|
-
ey "deploy", :prepend_to_path => {'ssh' => exiting_ssh(104)}
|
220
|
-
|
221
|
-
gem_install_command = @ssh_commands.find do |command|
|
222
|
-
command =~ /gem install ey-deploy/
|
223
|
-
end
|
224
|
-
gem_install_command.should =~ %r{/usr/local/ey_resin/ruby/bin/gem install}
|
225
|
-
end
|
226
|
-
|
227
|
-
it "upgrades ey-deploy if it's too old" do
|
228
|
-
ey "deploy", :prepend_to_path => {'ssh' => exiting_ssh(70)}
|
229
|
-
@ssh_commands.should have_command_like(/gem uninstall -a -x ey-deploy/)
|
230
|
-
@ssh_commands.should have_command_like(/gem install ey-deploy/)
|
231
|
-
end
|
232
|
-
|
233
|
-
it "raises an error if ey-deploy is too new" do
|
234
|
-
ey "deploy", :prepend_to_path => {'ssh' => exiting_ssh(17)}, :expect_failure => true
|
235
|
-
@ssh_commands.should_not have_command_like(/gem install ey-deploy/)
|
236
|
-
@ssh_commands.should_not have_command_like(/eysd deploy/)
|
237
|
-
@err.should match(/too new/i)
|
202
|
+
it "allows you to specify an app when not in a directory" do
|
203
|
+
ey "deploy --app rails232app --ref master"
|
204
|
+
@ssh_commands.last.should match(/deploy --app rails232app --branch master --migrate 'rake db:migrate'/)
|
238
205
|
end
|
239
206
|
|
240
|
-
it "
|
241
|
-
ey "deploy", :
|
242
|
-
@
|
243
|
-
@ssh_commands.should_not have_command_like(/gem uninstall.* ey-deploy/)
|
244
|
-
@ssh_commands.should have_command_like(/eysd deploy/)
|
207
|
+
it "requires that you specify a ref when specifying the application" do
|
208
|
+
ey "deploy --app rails232app", :expect_failure => true
|
209
|
+
@err.should match(/you must also specify the ref to deploy/)
|
245
210
|
end
|
246
211
|
end
|
247
212
|
end
|