engineyard 0.3.3 → 0.4.0
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.
- data/lib/engineyard.rb +1 -1
- data/lib/engineyard/api.rb +6 -2
- data/lib/engineyard/cli.rb +52 -7
- data/lib/engineyard/cli/api.rb +0 -4
- data/lib/engineyard/cli/recipes.rb +13 -5
- data/lib/engineyard/collection/environments.rb +1 -2
- data/lib/engineyard/error.rb +24 -35
- data/lib/engineyard/model/environment.rb +38 -1
- data/lib/engineyard/model/instance.rb +30 -1
- data/lib/engineyard/thor.rb +10 -4
- data/spec/engineyard/model/environment_spec.rb +64 -2
- data/spec/ey/deploy_spec.rb +24 -51
- data/spec/ey/ey_spec.rb +1 -1
- data/spec/ey/recipes/apply_spec.rb +42 -0
- data/spec/ey/recipes/upload_spec.rb +40 -0
- data/spec/ey/rollback_spec.rb +50 -0
- data/spec/ey/ssh_spec.rb +8 -3
- data/spec/spec_helper.rb +9 -0
- data/spec/support/fake_awsm.ru +19 -2
- data/spec/support/git_repo.rb +21 -0
- data/spec/support/helpers.rb +25 -14
- metadata +8 -6
- data/lib/engineyard/cli/action/deploy.rb +0 -120
- data/spec/ey/upload_recipes_spec.rb +0 -54
data/lib/engineyard.rb
CHANGED
data/lib/engineyard/api.rb
CHANGED
@@ -34,6 +34,10 @@ module EY
|
|
34
34
|
apps.find{|a| repo.urls.include?(a.repository_uri) }
|
35
35
|
end
|
36
36
|
|
37
|
+
def app_for_repo!(repo)
|
38
|
+
app_for_repo(repo) || raise(NoAppError.new(repo))
|
39
|
+
end
|
40
|
+
|
37
41
|
class InvalidCredentials < EY::Error; end
|
38
42
|
class RequestFailed < EY::Error; end
|
39
43
|
|
@@ -69,8 +73,8 @@ module EY
|
|
69
73
|
raise RequestFailed, "SSL is misconfigured on your cloud"
|
70
74
|
end
|
71
75
|
|
72
|
-
if resp.
|
73
|
-
data =
|
76
|
+
if resp.body.empty?
|
77
|
+
data = ''
|
74
78
|
else
|
75
79
|
begin
|
76
80
|
data = JSON.parse(resp.body)
|
data/lib/engineyard/cli.rb
CHANGED
@@ -21,11 +21,39 @@ module EY
|
|
21
21
|
method_option :migrate, :type => :string, :aliases => %w(-m),
|
22
22
|
:default => 'rake db:migrate',
|
23
23
|
:desc => "Run migrations via [MIGRATE], defaults to 'rake db:migrate'; use --no-migrate to avoid running migrations"
|
24
|
-
method_option :install_eysd, :type => :boolean, :aliases => %(-s),
|
25
|
-
:desc => "Force remote install of eysd"
|
26
24
|
def deploy(env_name = nil, branch = nil)
|
27
|
-
|
28
|
-
|
25
|
+
app = api.app_for_repo!(repo)
|
26
|
+
environment = fetch_environment(env_name, app)
|
27
|
+
deploy_branch = environment.resolve_branch(branch, options[:force]) ||
|
28
|
+
repo.current_branch ||
|
29
|
+
raise(DeployArgumentError)
|
30
|
+
|
31
|
+
EY.ui.info "Connecting to the server..."
|
32
|
+
|
33
|
+
environment.ensure_eysd_present! do |action|
|
34
|
+
case action
|
35
|
+
when :installing
|
36
|
+
EY.ui.warn "Instance does not have server-side component installed"
|
37
|
+
EY.ui.info "Installing server-side component..."
|
38
|
+
when :upgrading
|
39
|
+
EY.ui.info "Upgrading server-side component..."
|
40
|
+
else
|
41
|
+
# nothing slow is happening, so there's nothing to say
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
EY.ui.info "Running deploy for '#{environment.name}' on server..."
|
46
|
+
|
47
|
+
if environment.deploy!(app, deploy_branch, options[:migrate])
|
48
|
+
EY.ui.info "Deploy complete"
|
49
|
+
else
|
50
|
+
raise EY::Error, "Deploy failed"
|
51
|
+
end
|
52
|
+
|
53
|
+
rescue NoEnvironmentError => e
|
54
|
+
# Give better feedback about why we couldn't find the environment.
|
55
|
+
exists = api.environments.named(env_name)
|
56
|
+
raise exists ? EnvironmentUnlinkedError.new(env_name) : e
|
29
57
|
end
|
30
58
|
|
31
59
|
desc "environments [--all]", "List cloud environments for this app, or all environments"
|
@@ -37,14 +65,31 @@ module EY
|
|
37
65
|
end
|
38
66
|
map "envs" => :environments
|
39
67
|
|
40
|
-
desc "rebuild [
|
68
|
+
desc "rebuild [ENVIRONMENT]", "Rebuild environment (ensure configuration is up-to-date)"
|
41
69
|
def rebuild(name = nil)
|
42
70
|
env = fetch_environment(name)
|
43
71
|
EY.ui.debug("Rebuilding #{env.name}")
|
44
72
|
env.rebuild
|
45
73
|
end
|
46
74
|
|
47
|
-
desc "
|
75
|
+
desc "rollback [ENVIRONMENT]", "Rollback to the previous deploy"
|
76
|
+
def rollback(name = nil)
|
77
|
+
app = api.app_for_repo!(repo)
|
78
|
+
env = fetch_environment(name)
|
79
|
+
|
80
|
+
if env.app_master
|
81
|
+
EY.ui.info("Rolling back #{env.name}")
|
82
|
+
if env.rollback!(app)
|
83
|
+
EY.ui.info "Rollback complete"
|
84
|
+
else
|
85
|
+
raise EY::Error, "Rollback failed"
|
86
|
+
end
|
87
|
+
else
|
88
|
+
raise NoAppMaster.new(env.name)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
desc "ssh [ENVIRONMENT]", "Open an ssh session to the environment's application server"
|
48
93
|
def ssh(name = nil)
|
49
94
|
env = fetch_environment(name)
|
50
95
|
|
@@ -55,7 +100,7 @@ module EY
|
|
55
100
|
end
|
56
101
|
end
|
57
102
|
|
58
|
-
desc "logs [
|
103
|
+
desc "logs [ENVIRONMENT]", "Retrieve the latest logs for an environment"
|
59
104
|
def logs(name = nil)
|
60
105
|
fetch_environment(name).logs.each do |log|
|
61
106
|
EY.ui.info log.instance_name
|
data/lib/engineyard/cli/api.rb
CHANGED
@@ -23,10 +23,6 @@ module EY
|
|
23
23
|
@token = self.class.fetch_token
|
24
24
|
end
|
25
25
|
|
26
|
-
def fetch_app_for_repo(repo)
|
27
|
-
app_for_repo(repo) || raise(NoAppError.new(repo))
|
28
|
-
end
|
29
|
-
|
30
26
|
def self.fetch_token
|
31
27
|
EY.ui.warn("The engineyard gem is prerelease software. Please do not use")
|
32
28
|
EY.ui.warn("this tool to deploy to mission-critical environments, yet.")
|
@@ -1,14 +1,22 @@
|
|
1
1
|
module EY
|
2
2
|
class CLI
|
3
3
|
class Recipes < EY::Thor
|
4
|
+
|
5
|
+
desc "recipes apply [ENV]", "Apply uploaded chef recipes on ENV"
|
6
|
+
def apply(name = nil)
|
7
|
+
environment = fetch_environment(name)
|
8
|
+
environment.run_custom_recipes
|
9
|
+
EY.ui.say "Uploaded recipes started for #{environment.name}"
|
10
|
+
end
|
11
|
+
|
4
12
|
desc "recipes upload [ENV]", "Upload custom chef recipes from the current directory to ENV"
|
5
13
|
def upload(name = nil)
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
EY.ui.error "Recipes upload failed"
|
10
|
-
end
|
14
|
+
environment = fetch_environment(name)
|
15
|
+
environment.upload_recipes
|
16
|
+
EY.ui.say "Recipes uploaded successfully for #{environment.name}"
|
11
17
|
end
|
18
|
+
|
12
19
|
end
|
13
20
|
end
|
21
|
+
|
14
22
|
end
|
@@ -18,8 +18,7 @@ module EY
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def match_one!(name_part)
|
21
|
-
match_one(name_part) or raise
|
22
|
-
"Environment containing '#{name_part}' can't be found\nYou can create it at #{EY.config.endpoint}"
|
21
|
+
match_one(name_part) or raise NoEnvironmentError.new(name_part)
|
23
22
|
end
|
24
23
|
|
25
24
|
private
|
data/lib/engineyard/error.rb
CHANGED
@@ -9,76 +9,65 @@ module EY
|
|
9
9
|
|
10
10
|
class NoAppError < Error
|
11
11
|
def initialize(repo)
|
12
|
-
@repo = repo
|
13
|
-
end
|
14
|
-
|
15
|
-
def message
|
16
12
|
error = [%|There is no application configured for any of the following remotes:|]
|
17
|
-
|
13
|
+
repo.urls.each{|url| error << %|\t#{url}| }
|
18
14
|
error << %|You can add this application at #{EY.config.endpoint}|
|
19
|
-
|
15
|
+
super error.join("\n")
|
20
16
|
end
|
21
17
|
end
|
22
18
|
|
23
19
|
class NoAppMaster < EY::Error
|
24
20
|
def initialize(env_name)
|
25
|
-
|
21
|
+
super "The environment '#{env_name}' does not have a master instance."
|
26
22
|
end
|
23
|
+
end
|
27
24
|
|
28
|
-
|
29
|
-
|
25
|
+
class BadAppMasterStatus < EY::Error
|
26
|
+
def initialize(master_status)
|
27
|
+
super "Application master's status is not \"running\" (green); it is \"#{master_status}\"."
|
30
28
|
end
|
31
29
|
end
|
32
30
|
|
33
31
|
class EnvironmentError < EY::Error
|
34
32
|
end
|
35
33
|
|
36
|
-
class AmbiguousEnvironmentName < EY::
|
34
|
+
class AmbiguousEnvironmentName < EY::EnvironmentError
|
37
35
|
def initialize(name, matches)
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
def message
|
42
|
-
pretty_names = @matches.map {|x| "'#{x}'"}.join(', ')
|
43
|
-
"The name '#{@name}' is ambiguous; it matches all of the following environment names: #{pretty_names}.\nPlease use a longer, unambiguous substring or the entire environment name."
|
36
|
+
pretty_names = matches.map {|x| "'#{x}'"}.join(', ')
|
37
|
+
super "The name '#{name}' is ambiguous; it matches all of the following environment names: #{pretty_names}.\n" +
|
38
|
+
"Please use a longer, unambiguous substring or the entire environment name."
|
44
39
|
end
|
45
40
|
end
|
46
41
|
|
47
|
-
class NoSingleEnvironmentError < EY::
|
42
|
+
class NoSingleEnvironmentError < EY::EnvironmentError
|
48
43
|
def initialize(app)
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
def message
|
53
|
-
"Unable to determine a single environment for the current application (found #{@envs.size} environments)"
|
44
|
+
size = app.environments.size
|
45
|
+
super "Unable to determine a single environment for the current application (found #{size} environments)"
|
54
46
|
end
|
55
47
|
end
|
56
48
|
|
57
|
-
class NoEnvironmentError < EY::
|
49
|
+
class NoEnvironmentError < EY::EnvironmentError
|
58
50
|
def initialize(env_name=nil)
|
59
|
-
|
51
|
+
super "No environment named '#{env_name}'\nYou can create one at #{EY.config.endpoint}"
|
60
52
|
end
|
53
|
+
end
|
61
54
|
|
62
|
-
|
63
|
-
|
55
|
+
class EnvironmentUnlinkedError < EY::Error
|
56
|
+
def initialize(env_name)
|
57
|
+
super "Environment '#{env_name}' exists but does not run this application."
|
64
58
|
end
|
65
59
|
end
|
66
60
|
|
67
61
|
class BranchMismatch < EY::Error
|
68
62
|
def initialize(default_branch, branch)
|
69
|
-
super
|
70
|
-
|
71
|
-
end
|
72
|
-
|
73
|
-
def message
|
74
|
-
%|Your deploy branch is set to "#{@default_branch}".\n| +
|
75
|
-
%|If you want to deploy branch "#{@branch}", use --force.|
|
63
|
+
super %|Your deploy branch is set to "#{default_branch}".\n| +
|
64
|
+
%|If you want to deploy branch "#{branch}", use --force.|
|
76
65
|
end
|
77
66
|
end
|
78
67
|
|
79
68
|
class DeployArgumentError < EY::Error
|
80
|
-
def
|
81
|
-
%|"deploy" was called incorrectly. Call as "deploy [ENVIRONMENT] [BRANCH]"\n| +
|
69
|
+
def initialize
|
70
|
+
super %|"deploy" was called incorrectly. Call as "deploy [ENVIRONMENT] [BRANCH]"\n| +
|
82
71
|
%|You can set default environments and branches in ey.yml|
|
83
72
|
end
|
84
73
|
end
|
@@ -21,10 +21,36 @@ module EY
|
|
21
21
|
Instance.from_array(api_get("/environments/#{id}/instances")["instances"], :environment => self)
|
22
22
|
end
|
23
23
|
|
24
|
+
def app_master!
|
25
|
+
master = app_master
|
26
|
+
if master.nil?
|
27
|
+
raise NoAppMaster.new(name)
|
28
|
+
elsif master.status != "running"
|
29
|
+
raise BadAppMasterStatus.new(master.status)
|
30
|
+
end
|
31
|
+
master
|
32
|
+
end
|
33
|
+
|
34
|
+
def ensure_eysd_present!(&blk)
|
35
|
+
app_master!.ensure_eysd_present!(&blk)
|
36
|
+
end
|
37
|
+
|
38
|
+
def deploy!(app, ref, migration_command=nil)
|
39
|
+
app_master!.deploy!(app, ref, migration_command, config)
|
40
|
+
end
|
41
|
+
|
42
|
+
def rollback!(app)
|
43
|
+
app_master!.rollback!(app, config)
|
44
|
+
end
|
45
|
+
|
24
46
|
def rebuild
|
25
47
|
api.request("/environments/#{id}/rebuild", :method => :put)
|
26
48
|
end
|
27
49
|
|
50
|
+
def run_custom_recipes
|
51
|
+
api.request("/environments/#{id}/run_custom_recipes", :method => :put)
|
52
|
+
end
|
53
|
+
|
28
54
|
def upload_recipes(file_to_upload = recipe_file)
|
29
55
|
api.request("/environments/#{id}/recipes",
|
30
56
|
:method => :post,
|
@@ -39,7 +65,7 @@ module EY
|
|
39
65
|
end
|
40
66
|
|
41
67
|
tmp = Tempfile.new("recipes")
|
42
|
-
cmd = "
|
68
|
+
cmd = "tar czf '#{tmp.path}' cookbooks/"
|
43
69
|
|
44
70
|
unless system(cmd)
|
45
71
|
raise EY::Error, "Could not archive recipes.\nCommand `#{cmd}` exited with an error."
|
@@ -48,11 +74,22 @@ module EY
|
|
48
74
|
tmp
|
49
75
|
end
|
50
76
|
|
77
|
+
def resolve_branch(branch, allow_non_default_branch=false)
|
78
|
+
if !allow_non_default_branch && branch && default_branch && (branch != default_branch)
|
79
|
+
raise BranchMismatch.new(default_branch, branch)
|
80
|
+
end
|
81
|
+
branch || default_branch
|
82
|
+
end
|
83
|
+
|
51
84
|
def configuration
|
52
85
|
EY.config.environments[self.name]
|
53
86
|
end
|
54
87
|
alias_method :config, :configuration
|
55
88
|
|
89
|
+
def default_branch
|
90
|
+
EY.config.default_branch(name)
|
91
|
+
end
|
92
|
+
|
56
93
|
def shorten_name_for(app)
|
57
94
|
name.gsub(/^#{Regexp.quote(app.name)}_/, '')
|
58
95
|
end
|
@@ -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.
|
6
|
+
EYSD_VERSION = "~>0.4.0"
|
7
7
|
CHECK_SCRIPT = <<-SCRIPT
|
8
8
|
require "rubygems"
|
9
9
|
requirement = Gem::Requirement.new("#{EYSD_VERSION}")
|
@@ -43,6 +43,25 @@ exit(17) # required_version < current_version
|
|
43
43
|
ssh Escape.shell_command(deploy_cmd)
|
44
44
|
end
|
45
45
|
|
46
|
+
def ensure_eysd_present!
|
47
|
+
case ey_deploy_check
|
48
|
+
when :ssh_failed
|
49
|
+
raise EnvironmentError, "SSH connection to #{hostname} failed"
|
50
|
+
when :eysd_missing
|
51
|
+
yield :installing if block_given?
|
52
|
+
install_ey_deploy!
|
53
|
+
when :too_new
|
54
|
+
raise EnvironmentError, "server-side component too new; please upgrade your copy of the engineyard gem."
|
55
|
+
when :too_old
|
56
|
+
yield :upgrading if block_given?
|
57
|
+
upgrade_ey_deploy!
|
58
|
+
when :ok
|
59
|
+
# no action needed
|
60
|
+
else
|
61
|
+
raise EY::Error, "Internal error: Unexpected status from Instance#ey_deploy_check; got #{eysd_status.inspect}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
46
65
|
def ey_deploy_check
|
47
66
|
require 'base64'
|
48
67
|
encoded_script = Base64.encode64(CHECK_SCRIPT).gsub(/\n/, '')
|
@@ -54,6 +73,16 @@ exit(17) # required_version < current_version
|
|
54
73
|
ssh(Escape.shell_command(['sudo', gem_path, 'install', 'ey-deploy', '-v', EYSD_VERSION]))
|
55
74
|
end
|
56
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
|
81
|
+
end
|
82
|
+
|
83
|
+
ssh Escape.shell_command(deploy_cmd)
|
84
|
+
end
|
85
|
+
|
57
86
|
def upgrade_ey_deploy!
|
58
87
|
ssh "sudo #{gem_path} uninstall -a -x ey-deploy"
|
59
88
|
install_ey_deploy!
|
data/lib/engineyard/thor.rb
CHANGED
@@ -20,6 +20,10 @@ module EY
|
|
20
20
|
|
21
21
|
protected
|
22
22
|
|
23
|
+
def self.exit_on_failure?
|
24
|
+
true
|
25
|
+
end
|
26
|
+
|
23
27
|
def api
|
24
28
|
@api ||= EY::CLI::API.new
|
25
29
|
end
|
@@ -28,11 +32,13 @@ module EY
|
|
28
32
|
@repo ||= EY::Repo.new
|
29
33
|
end
|
30
34
|
|
31
|
-
|
32
|
-
|
33
|
-
|
35
|
+
# if an app is supplied, it is used as a constraint for implied environment lookup
|
36
|
+
def fetch_environment(env_name, app = nil)
|
37
|
+
env_name ||= EY.config.default_environment
|
38
|
+
if env_name
|
39
|
+
(app || api).environments.match_one!(env_name)
|
34
40
|
else
|
35
|
-
api.
|
41
|
+
(app || api.app_for_repo!(repo)).sole_environment!
|
36
42
|
end
|
37
43
|
end
|
38
44
|
|
@@ -9,9 +9,11 @@ describe "EY::Model::Environment#rebuild" do
|
|
9
9
|
"api" => @api,
|
10
10
|
})
|
11
11
|
|
12
|
-
FakeWeb.register_uri(
|
12
|
+
FakeWeb.register_uri(
|
13
|
+
:put,
|
13
14
|
"https://cloud.engineyard.com/api/v2/environments/#{env.id}/rebuild",
|
14
|
-
:body =>
|
15
|
+
:body => ''
|
16
|
+
)
|
15
17
|
|
16
18
|
env.rebuild
|
17
19
|
|
@@ -19,6 +21,27 @@ describe "EY::Model::Environment#rebuild" do
|
|
19
21
|
end
|
20
22
|
end
|
21
23
|
|
24
|
+
describe "EY::Model::Environment#run_custom_recipes" do
|
25
|
+
it_should_behave_like "it has an api"
|
26
|
+
|
27
|
+
it "hits the rebuild action in the API" do
|
28
|
+
env = EY::Model::Environment.from_hash({
|
29
|
+
"id" => 46534,
|
30
|
+
"api" => @api,
|
31
|
+
})
|
32
|
+
|
33
|
+
FakeWeb.register_uri(
|
34
|
+
:put,
|
35
|
+
"https://cloud.engineyard.com/api/v2/environments/#{env.id}/run_custom_recipes",
|
36
|
+
:body => ''
|
37
|
+
)
|
38
|
+
|
39
|
+
env.run_custom_recipes
|
40
|
+
|
41
|
+
FakeWeb.should have_requested(:put, "https://cloud.engineyard.com/api/v2/environments/#{env.id}/run_custom_recipes")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
22
45
|
describe "EY::Model::Environment.from_array" do
|
23
46
|
it "returns a smart collection, not just a dumb array" do
|
24
47
|
api_data = [
|
@@ -57,6 +80,45 @@ describe "EY::Model::Environment#instances" do
|
|
57
80
|
end
|
58
81
|
end
|
59
82
|
|
83
|
+
describe "EY::Model::Environment#app_master!" do
|
84
|
+
def make_env_with_master(app_master)
|
85
|
+
if app_master
|
86
|
+
app_master = {
|
87
|
+
"id" => 44206,
|
88
|
+
"role" => "solo",
|
89
|
+
}.merge(app_master)
|
90
|
+
end
|
91
|
+
|
92
|
+
EY::Model::Environment.from_hash({
|
93
|
+
"id" => 11830,
|
94
|
+
"name" => "guinea-pigs-are-delicious",
|
95
|
+
"app_master" => app_master,
|
96
|
+
"instances" => [app_master],
|
97
|
+
})
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
it "returns the app master if it's present and running" do
|
102
|
+
env = make_env_with_master("status" => "running")
|
103
|
+
env.app_master!.should_not be_nil
|
104
|
+
env.app_master!.id.should == 44206
|
105
|
+
end
|
106
|
+
|
107
|
+
it "raises an error if the app master is in a non-running state" do
|
108
|
+
env = make_env_with_master("status" => "error")
|
109
|
+
lambda {
|
110
|
+
env.app_master!
|
111
|
+
}.should raise_error(EY::BadAppMasterStatus)
|
112
|
+
end
|
113
|
+
|
114
|
+
it "raises an error if the app master is absent" do
|
115
|
+
env = make_env_with_master(nil)
|
116
|
+
lambda {
|
117
|
+
env.app_master!
|
118
|
+
}.should raise_error(EY::NoAppMaster)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
60
122
|
describe "EY::Model::Environment#shorten_name_for(app)" do
|
61
123
|
def short(environment_name, app_name)
|
62
124
|
env = EY::Model::Environment.from_hash({:name => environment_name})
|
data/spec/ey/deploy_spec.rb
CHANGED
@@ -41,13 +41,13 @@ describe "ey deploy" do
|
|
41
41
|
it "complains when the specified environment does not contain the app" do
|
42
42
|
api_scenario "one app, one environment, not linked"
|
43
43
|
ey "deploy giblets master", :expect_failure => true
|
44
|
-
@err.should match(/
|
44
|
+
@err.should match(/does not run this application/i)
|
45
45
|
end
|
46
46
|
|
47
|
-
it "complains when environment is
|
47
|
+
it "complains when environment is not specified and app is in >1 environment" do
|
48
48
|
api_scenario "one app, two environments"
|
49
49
|
ey "deploy", :expect_failure => true
|
50
|
-
@err.should match(/
|
50
|
+
@err.should match(/single environment.*2/i)
|
51
51
|
end
|
52
52
|
|
53
53
|
it "complains when the app master is in a non-running state" do
|
@@ -94,48 +94,23 @@ describe "ey deploy" do
|
|
94
94
|
end
|
95
95
|
|
96
96
|
context "choosing something to deploy" do
|
97
|
-
|
98
|
-
|
99
|
-
|
97
|
+
define_git_repo('deploy test') do
|
98
|
+
# we'll have one commit on master
|
99
|
+
system("echo 'source :gemcutter' > Gemfile")
|
100
|
+
system("git add Gemfile")
|
101
|
+
system("git commit -m 'initial commit' >/dev/null 2>&1")
|
100
102
|
|
101
|
-
|
102
|
-
|
103
|
-
Dir.tmpdir,
|
104
|
-
"ey_test_git_#{Time.now.tv_sec}_#{Time.now.tv_usec}_#{$$}")
|
105
|
-
|
106
|
-
Dir.mkdir(@local_git_dir)
|
107
|
-
|
108
|
-
Dir.chdir(@local_git_dir) do
|
109
|
-
[
|
110
|
-
# initial repo setup
|
111
|
-
'git init >/dev/null 2>&1',
|
112
|
-
'git config user.email deploy@spec.test',
|
113
|
-
'git config user.name "Deploy Spec"',
|
114
|
-
'git remote add origin "user@git.host/path/to/repo.git"',
|
115
|
-
|
116
|
-
# we'll have one commit on master
|
117
|
-
"echo 'source :gemcutter' > Gemfile",
|
118
|
-
"git add Gemfile",
|
119
|
-
"git commit -m 'initial commit' >/dev/null 2>&1",
|
120
|
-
|
121
|
-
# and a tag
|
122
|
-
"git tag -a -m 'version one' v1",
|
123
|
-
|
124
|
-
# and we need a non-master branch
|
125
|
-
"git checkout -b current-branch >/dev/null 2>&1",
|
126
|
-
].each do |cmd|
|
127
|
-
system("#{cmd}") or raise "#{cmd} failed"
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
103
|
+
# and a tag
|
104
|
+
system("git tag -a -m 'version one' v1")
|
131
105
|
|
132
|
-
|
133
|
-
|
134
|
-
Dir.chdir(@local_git_dir)
|
106
|
+
# and we need a non-master branch
|
107
|
+
system("git checkout -b current-branch >/dev/null 2>&1")
|
135
108
|
end
|
136
109
|
|
137
|
-
|
138
|
-
|
110
|
+
use_git_repo('deploy test')
|
111
|
+
|
112
|
+
before(:all) do
|
113
|
+
api_scenario "one app, one environment", "user@git.host:path/to/repo.git"
|
139
114
|
end
|
140
115
|
|
141
116
|
context "without a configured default branch" do
|
@@ -156,13 +131,12 @@ describe "ey deploy" do
|
|
156
131
|
end
|
157
132
|
|
158
133
|
context "when there is extra configuration" do
|
159
|
-
before(:
|
160
|
-
write_yaml({"environments" => {"giblets" => {"bert" => "ernie"}}}
|
161
|
-
File.join(@local_git_dir, "ey.yml"))
|
134
|
+
before(:each) do
|
135
|
+
write_yaml({"environments" => {"giblets" => {"bert" => "ernie"}}})
|
162
136
|
end
|
163
137
|
|
164
|
-
after(:
|
165
|
-
File.unlink(
|
138
|
+
after(:each) do
|
139
|
+
File.unlink("ey.yml")
|
166
140
|
end
|
167
141
|
|
168
142
|
it "gets passed along to eysd" do
|
@@ -172,13 +146,12 @@ describe "ey deploy" do
|
|
172
146
|
end
|
173
147
|
|
174
148
|
context "with a configured default branch" do
|
175
|
-
before(:
|
176
|
-
write_yaml({"environments" => {"giblets" => {"branch" => "master"}}}
|
177
|
-
File.join(@local_git_dir, "ey.yml"))
|
149
|
+
before(:each) do
|
150
|
+
write_yaml({"environments" => {"giblets" => {"branch" => "master"}}})
|
178
151
|
end
|
179
152
|
|
180
|
-
after(:
|
181
|
-
File.unlink
|
153
|
+
after(:each) do
|
154
|
+
File.unlink "ey.yml"
|
182
155
|
end
|
183
156
|
|
184
157
|
it "deploys the default branch by default" do
|
data/spec/ey/ey_spec.rb
CHANGED
@@ -9,7 +9,7 @@ describe "ey" do
|
|
9
9
|
|
10
10
|
context "run with an argument that is not a command" do
|
11
11
|
it "tells the user that is not a command" do
|
12
|
-
ey "foobarbaz", :
|
12
|
+
ey "foobarbaz", :expect_failure => true
|
13
13
|
@err.should include("Could not find task")
|
14
14
|
end
|
15
15
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "ey recipes apply" do
|
4
|
+
it_should_behave_like "an integration test"
|
5
|
+
|
6
|
+
before(:all) do
|
7
|
+
api_scenario "one app, one environment"
|
8
|
+
end
|
9
|
+
|
10
|
+
it "works when the environment name is valid" do
|
11
|
+
ey "recipes apply giblets", :debug => true
|
12
|
+
@out.should =~ /Uploaded recipes started for giblets/i
|
13
|
+
end
|
14
|
+
|
15
|
+
it "runs recipes for the current environment by default" do
|
16
|
+
ey "recipes apply", :debug => true
|
17
|
+
@out.should =~ /Uploaded recipes started for giblets/i
|
18
|
+
end
|
19
|
+
|
20
|
+
it "fails when the environment name is bogus" do
|
21
|
+
ey "recipes apply typo", :expect_failure => true
|
22
|
+
@err.should match(/'typo'/)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "ey recipes apply ENV" do
|
27
|
+
it_should_behave_like "an integration test"
|
28
|
+
|
29
|
+
before(:all) do
|
30
|
+
api_scenario "one app, many similarly-named environments"
|
31
|
+
end
|
32
|
+
|
33
|
+
it "works when given an unambiguous substring" do
|
34
|
+
ey "recipes apply prod", :debug => true
|
35
|
+
@out.should =~ /Uploaded recipes started for railsapp_production/
|
36
|
+
end
|
37
|
+
|
38
|
+
it "complains when given an ambiguous substring" do
|
39
|
+
ey "recipes apply staging", :hide_err => true, :expect_failure => true
|
40
|
+
@err.should =~ /'staging' is ambiguous/
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "ey recipes upload" do
|
4
|
+
it_should_behave_like "an integration test"
|
5
|
+
|
6
|
+
define_git_repo('+cookbooks') do |git_dir|
|
7
|
+
git_dir.join("cookbooks").mkdir
|
8
|
+
File.open(git_dir.join("cookbooks/file"), "w"){|f| f << "boo" }
|
9
|
+
end
|
10
|
+
|
11
|
+
use_git_repo('+cookbooks')
|
12
|
+
|
13
|
+
it "posts the recipes to the correct url" do
|
14
|
+
api_scenario "one app, one environment"
|
15
|
+
ey "recipes upload giblets", :debug => true
|
16
|
+
|
17
|
+
@out.should =~ /Recipes uploaded successfully for giblets/i
|
18
|
+
end
|
19
|
+
|
20
|
+
it "errors correctly on bogus env name" do
|
21
|
+
api_scenario "one app, one environment"
|
22
|
+
ey "recipes upload bogusenv", :expect_failure => true
|
23
|
+
|
24
|
+
@err.should =~ /No environment named 'bogusenv'/
|
25
|
+
end
|
26
|
+
|
27
|
+
it "can infer the environment from the current application" do
|
28
|
+
api_scenario "one app, one environment"
|
29
|
+
|
30
|
+
ey "recipes upload", :debug => true
|
31
|
+
@out.should =~ /Recipes uploaded successfully for giblets/i
|
32
|
+
end
|
33
|
+
|
34
|
+
it "complains when it can't infer the environment from the current application" do
|
35
|
+
api_scenario "one app, one environment, not linked"
|
36
|
+
|
37
|
+
ey "recipes upload", :debug => true, :expect_failure => true
|
38
|
+
@err.should =~ /single environment/i
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "ey rollback" do
|
4
|
+
it_should_behave_like "an integration test"
|
5
|
+
|
6
|
+
before(:all) do
|
7
|
+
api_scenario "one app, one environment"
|
8
|
+
end
|
9
|
+
|
10
|
+
it "works when the environment name is valid" do
|
11
|
+
ey "rollback giblets", :debug => true
|
12
|
+
@out.should match(/rolling back giblets/i)
|
13
|
+
@err.should be_empty
|
14
|
+
@ssh_commands.last.should match(/eysd deploy rollback --app rails232app/)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "rollback the current environment by default" do
|
18
|
+
ey "rollback", :debug => true
|
19
|
+
@out.should match(/rolling back giblets/i)
|
20
|
+
@err.should be_empty
|
21
|
+
@ssh_commands.last.should match(/eysd deploy rollback --app rails232app/)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "fails when the environment name is bogus" do
|
25
|
+
ey "rollback typo", :expect_failure => true
|
26
|
+
@err.should match(/'typo'/)
|
27
|
+
@ssh_commands.should be_empty
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "ey rollback ENV" do
|
32
|
+
it_should_behave_like "an integration test"
|
33
|
+
|
34
|
+
before(:all) do
|
35
|
+
api_scenario "one app, many similarly-named environments"
|
36
|
+
end
|
37
|
+
|
38
|
+
it "works when given an unambiguous substring" do
|
39
|
+
ey "rollback prod", :debug => true
|
40
|
+
@out.should match(/Rolling back railsapp_production/i)
|
41
|
+
@err.should be_empty
|
42
|
+
@ssh_commands.last.should match(/eysd deploy rollback --app rails232app/)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "complains when given an ambiguous substring" do
|
46
|
+
ey "rollback staging", :hide_err => true, :expect_failure => true
|
47
|
+
@err.should =~ /'staging' is ambiguous/
|
48
|
+
@ssh_commands.should be_empty
|
49
|
+
end
|
50
|
+
end
|
data/spec/ey/ssh_spec.rb
CHANGED
@@ -52,12 +52,17 @@ describe "ey ssh ENV" do
|
|
52
52
|
end
|
53
53
|
|
54
54
|
it "works when given an unambiguous substring" do
|
55
|
-
|
56
|
-
|
57
|
-
ey "ssh prod", :prepend_to_path => {'ssh' => print_my_args}
|
55
|
+
ey "ssh prod", :prepend_to_path => {'ssh' => print_my_args_ssh}
|
58
56
|
@raw_ssh_commands.should == ["ssh turkey@174.129.198.124"]
|
59
57
|
end
|
60
58
|
|
59
|
+
it "doesn't require you to be in any app's directory if the name is unambiguous" do
|
60
|
+
Dir.chdir(Dir.tmpdir) do
|
61
|
+
ey "ssh prod", :prepend_to_path => {'ssh' => print_my_args_ssh}
|
62
|
+
@raw_ssh_commands.should == ["ssh turkey@174.129.198.124"]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
61
66
|
it "complains when given an ambiguous substring" do
|
62
67
|
ey "ssh staging", :hide_err => true, :expect_failure => true
|
63
68
|
@err.should match(/'staging' is ambiguous/)
|
data/spec/spec_helper.rb
CHANGED
@@ -29,6 +29,7 @@ support.each{|helper| require helper }
|
|
29
29
|
|
30
30
|
Spec::Runner.configure do |config|
|
31
31
|
config.include Spec::Helpers
|
32
|
+
config.extend Spec::GitRepo
|
32
33
|
|
33
34
|
config.before(:all) do
|
34
35
|
FakeWeb.allow_net_connect = false
|
@@ -58,7 +59,15 @@ Spec::Matchers.define :have_command_like do |regex|
|
|
58
59
|
end
|
59
60
|
end
|
60
61
|
|
62
|
+
EY.define_git_repo("default") do |git_dir|
|
63
|
+
system("echo 'source :gemcutter' > Gemfile")
|
64
|
+
system("git add Gemfile")
|
65
|
+
system("git commit -m 'initial commit' >/dev/null 2>&1")
|
66
|
+
end
|
67
|
+
|
61
68
|
shared_examples_for "an integration test without an eyrc file" do
|
69
|
+
use_git_repo('default')
|
70
|
+
|
62
71
|
before(:all) do
|
63
72
|
FakeFS.deactivate!
|
64
73
|
ENV['EYRC'] = "/tmp/eyrc"
|
data/spec/support/fake_awsm.ru
CHANGED
@@ -55,11 +55,28 @@ class FakeAwsm < Sinatra::Base
|
|
55
55
|
end
|
56
56
|
|
57
57
|
post "/api/v2/environments/:env_id/recipes" do
|
58
|
-
|
58
|
+
if params[:file][:tempfile]
|
59
|
+
files = `tar --list -z -f "#{params[:file][:tempfile].path}"`.split(/\n/)
|
60
|
+
if files.empty?
|
61
|
+
status(400)
|
62
|
+
"No files in uploaded tarball"
|
63
|
+
else
|
64
|
+
status(204)
|
65
|
+
""
|
66
|
+
end
|
67
|
+
else
|
68
|
+
status(400)
|
69
|
+
"Recipe file not uploaded"
|
70
|
+
end
|
59
71
|
end
|
60
72
|
|
61
73
|
put "/api/v2/environments/:env_id/rebuild" do
|
62
|
-
status(
|
74
|
+
status(202)
|
75
|
+
""
|
76
|
+
end
|
77
|
+
|
78
|
+
put "/api/v2/environments/:env_id/run_custom_recipes" do
|
79
|
+
status(202)
|
63
80
|
""
|
64
81
|
end
|
65
82
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Spec
|
2
|
+
module GitRepo
|
3
|
+
def define_git_repo(name, &setup)
|
4
|
+
# EY's ivars don't get cleared between examples, so we can keep
|
5
|
+
# a git repo around longer (and thus make our tests faster)
|
6
|
+
EY.define_git_repo(name, &setup)
|
7
|
+
end
|
8
|
+
|
9
|
+
def use_git_repo(repo_name)
|
10
|
+
before(:each) do
|
11
|
+
@_original_wd ||= []
|
12
|
+
@_original_wd << Dir.getwd
|
13
|
+
Dir.chdir(EY.git_repo_dir(repo_name))
|
14
|
+
end
|
15
|
+
|
16
|
+
after(:each) do
|
17
|
+
Dir.chdir(@_original_wd.pop)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/spec/support/helpers.rb
CHANGED
@@ -17,7 +17,6 @@ module Spec
|
|
17
17
|
ZeroExitStatus = Class.new(UnexpectedExit)
|
18
18
|
|
19
19
|
def ey(cmd = nil, options = {}, &block)
|
20
|
-
require "open3"
|
21
20
|
hide_err = options.has_key?(:hide_err) ? options[:hide_err] : options[:expect_failure]
|
22
21
|
path_prepends = options[:prepend_to_path]
|
23
22
|
|
@@ -75,23 +74,11 @@ module Spec
|
|
75
74
|
@out
|
76
75
|
end
|
77
76
|
|
78
|
-
def api_scenario(scenario, remote =
|
77
|
+
def api_scenario(scenario, remote = "user@git.host:path/to/repo.git")
|
79
78
|
response = ::RestClient.put(EY.fake_awsm + '/scenario', {"scenario" => scenario, "remote" => remote}, {})
|
80
79
|
raise "Setting scenario failed: #{response.inspect}" unless response.code == 200
|
81
80
|
end
|
82
81
|
|
83
|
-
def local_git_remote
|
84
|
-
remotes = []
|
85
|
-
`git remote -v`.each_line do |line|
|
86
|
-
parts = line.split(/\t/)
|
87
|
-
# the remote will look like
|
88
|
-
# "git@github.com:engineyard/engineyard.git (fetch)\n"
|
89
|
-
# so we need to chop it up a bit
|
90
|
-
remotes << parts[1].gsub(/\s.*$/, "") if parts[1]
|
91
|
-
end
|
92
|
-
remotes.first
|
93
|
-
end
|
94
|
-
|
95
82
|
def read_yaml(file="ey.yml")
|
96
83
|
YAML.load_file(File.expand_path(file))
|
97
84
|
end
|
@@ -137,5 +124,29 @@ module EY
|
|
137
124
|
end
|
138
125
|
end
|
139
126
|
alias_method :start_fake_awsm, :fake_awsm
|
127
|
+
|
128
|
+
def define_git_repo(name, &setup)
|
129
|
+
@git_repo_setup ||= {}
|
130
|
+
raise "Attempted to redefine git repo #{name}; don't do that!" if @git_repo_setup.has_key?(name)
|
131
|
+
@git_repo_setup[name] = setup
|
132
|
+
end
|
133
|
+
|
134
|
+
def git_repo_dir(name)
|
135
|
+
@git_repo_dir_cache ||= {}
|
136
|
+
return @git_repo_dir_cache[name] if @git_repo_dir_cache.has_key?(name)
|
137
|
+
raise ArgumentError, "No definition for git repo #{name}" unless @git_repo_setup[name]
|
138
|
+
|
139
|
+
git_dir = Pathname.new("/tmp/engineyard_test_repo_#{Time.now.tv_sec}_#{Time.now.tv_usec}_#{$$}")
|
140
|
+
git_dir.mkdir
|
141
|
+
Dir.chdir(git_dir) do
|
142
|
+
system("git init -q")
|
143
|
+
system('git config user.email ey@spec.test')
|
144
|
+
system('git config user.name "EY Specs"')
|
145
|
+
system("git remote add testremote user@git.host:path/to/repo.git")
|
146
|
+
@git_repo_setup[name].call(git_dir)
|
147
|
+
end
|
148
|
+
@git_repo_dir_cache[name] = git_dir
|
149
|
+
end
|
150
|
+
|
140
151
|
end
|
141
152
|
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 4
|
8
|
+
- 0
|
9
|
+
version: 0.4.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- EY Cloud Team
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-06-
|
17
|
+
date: 2010-06-11 00:00:00 -07:00
|
18
18
|
default_executable: ey
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -109,7 +109,6 @@ extra_rdoc_files: []
|
|
109
109
|
files:
|
110
110
|
- bin/ey
|
111
111
|
- lib/engineyard/api.rb
|
112
|
-
- lib/engineyard/cli/action/deploy.rb
|
113
112
|
- lib/engineyard/cli/api.rb
|
114
113
|
- lib/engineyard/cli/recipes.rb
|
115
114
|
- lib/engineyard/cli/thor_fixes.rb
|
@@ -177,10 +176,13 @@ test_files:
|
|
177
176
|
- spec/ey/list_environments_spec.rb
|
178
177
|
- spec/ey/logs_spec.rb
|
179
178
|
- spec/ey/rebuild_spec.rb
|
179
|
+
- spec/ey/recipes/apply_spec.rb
|
180
|
+
- spec/ey/recipes/upload_spec.rb
|
181
|
+
- spec/ey/rollback_spec.rb
|
180
182
|
- spec/ey/ssh_spec.rb
|
181
|
-
- spec/ey/upload_recipes_spec.rb
|
182
183
|
- spec/spec_helper.rb
|
183
184
|
- spec/support/bundled_ey
|
184
185
|
- spec/support/fake_awsm.ru
|
186
|
+
- spec/support/git_repo.rb
|
185
187
|
- spec/support/helpers.rb
|
186
188
|
- spec/support/ruby_ext.rb
|
@@ -1,120 +0,0 @@
|
|
1
|
-
module EY
|
2
|
-
class CLI
|
3
|
-
module Action
|
4
|
-
class Deploy
|
5
|
-
|
6
|
-
EYSD_VERSION = "~>0.3.0"
|
7
|
-
|
8
|
-
def self.call(env_name, branch, options)
|
9
|
-
env_name ||= EY.config.default_environment
|
10
|
-
|
11
|
-
app = fetch_app
|
12
|
-
env = fetch_environment(env_name, app)
|
13
|
-
branch = fetch_branch(env.name, branch, options[:force])
|
14
|
-
master = fetch_app_master(env)
|
15
|
-
|
16
|
-
EY.ui.info "Connecting to the server..."
|
17
|
-
ensure_eysd_present(master, options[:install_eysd])
|
18
|
-
|
19
|
-
EY.ui.info "Running deploy for '#{env.name}' on server..."
|
20
|
-
deployed = master.deploy!(app, branch, options[:migrate], env.config)
|
21
|
-
|
22
|
-
if deployed
|
23
|
-
EY.ui.info "Deploy complete"
|
24
|
-
else
|
25
|
-
raise EY::Error, "Deploy failed"
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
def self.fetch_app_master(env)
|
32
|
-
master = env.app_master
|
33
|
-
|
34
|
-
if !master
|
35
|
-
raise EnvironmentError, "No running instances for environment #{env.name}\nStart one at #{EY.config.endpoint}"
|
36
|
-
elsif master.status != "running"
|
37
|
-
raise EnvironmentError, "Cannot deploy: application master's status is not \"running\" (green); it is \"#{master.status}\"."
|
38
|
-
end
|
39
|
-
|
40
|
-
master
|
41
|
-
end
|
42
|
-
|
43
|
-
def self.api
|
44
|
-
@api ||= EY::CLI::API.new
|
45
|
-
end
|
46
|
-
|
47
|
-
def self.repo
|
48
|
-
@repo ||= EY::Repo.new
|
49
|
-
end
|
50
|
-
|
51
|
-
def self.fetch_app
|
52
|
-
app = api.app_for_repo(repo)
|
53
|
-
raise NoAppError.new(repo) unless app
|
54
|
-
app
|
55
|
-
end
|
56
|
-
|
57
|
-
def self.fetch_environment(env_name, app)
|
58
|
-
# if the name's not specified and there's not exactly one
|
59
|
-
# environment, we can't figure out which environment to deploy
|
60
|
-
raise DeployArgumentError if !env_name && app.environments.size != 1
|
61
|
-
|
62
|
-
env = if env_name
|
63
|
-
app.environments.match_one(env_name)
|
64
|
-
else
|
65
|
-
app.environments.first
|
66
|
-
end
|
67
|
-
|
68
|
-
# the environment exists, but doesn't have this app
|
69
|
-
if !env && api.environments.named(env_name)
|
70
|
-
raise EnvironmentError, "Environment '#{env_name}' doesn't run this application\nYou can add it at #{EY.config.endpoint}"
|
71
|
-
end
|
72
|
-
|
73
|
-
if !env
|
74
|
-
raise NoEnvironmentError.new(env_name)
|
75
|
-
end
|
76
|
-
|
77
|
-
env
|
78
|
-
end
|
79
|
-
|
80
|
-
def self.fetch_branch(env_name, user_specified_branch, force)
|
81
|
-
default_branch = EY.config.default_branch(env_name)
|
82
|
-
|
83
|
-
branch = if user_specified_branch
|
84
|
-
if default_branch && (user_specified_branch != default_branch) && !force
|
85
|
-
raise BranchMismatch.new(default_branch, user_specified_branch)
|
86
|
-
end
|
87
|
-
user_specified_branch
|
88
|
-
else
|
89
|
-
default_branch || repo.current_branch
|
90
|
-
end
|
91
|
-
|
92
|
-
raise DeployArgumentError unless branch
|
93
|
-
branch
|
94
|
-
end
|
95
|
-
|
96
|
-
def self.ensure_eysd_present(instance, install_eysd)
|
97
|
-
eysd_status = instance.ey_deploy_check
|
98
|
-
case eysd_status
|
99
|
-
when :ssh_failed
|
100
|
-
raise EnvironmentError, "SSH connection to #{instance.hostname} failed"
|
101
|
-
when :eysd_missing
|
102
|
-
EY.ui.warn "Instance does not have server-side component installed"
|
103
|
-
EY.ui.info "Installing server-side component..."
|
104
|
-
instance.install_ey_deploy!
|
105
|
-
when :too_new
|
106
|
-
raise EnvironmentError, "server-side component too new; please upgrade your copy of the engineyard gem."
|
107
|
-
when :too_old
|
108
|
-
EY.ui.info "Upgrading server-side component..."
|
109
|
-
instance.upgrade_ey_deploy!
|
110
|
-
when :ok
|
111
|
-
# no action needed
|
112
|
-
else
|
113
|
-
raise EY::Error, "Internal error: Unexpected status from Instance#ey_deploy_check; got #{eysd_status.inspect}"
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
@@ -1,54 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe "ey recipes upload" do
|
4
|
-
it_should_behave_like "an integration test"
|
5
|
-
|
6
|
-
before(:all) do
|
7
|
-
@recipe_dir = Pathname.new("/tmp/#{$$}")
|
8
|
-
@recipe_dir.mkdir
|
9
|
-
Dir.chdir(@recipe_dir) do
|
10
|
-
@recipe_dir.join("cookbooks").mkdir
|
11
|
-
File.open(@recipe_dir.join("cookbooks/file"), "w"){|f| f << "boo" }
|
12
|
-
`git init`
|
13
|
-
`git add .`
|
14
|
-
`git commit -m "OMG"`
|
15
|
-
`git remote add testremote user@host.tld:path/to/repo.git`
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
it "posts the recipes to the correct url" do
|
20
|
-
api_scenario "one app, one environment"
|
21
|
-
Dir.chdir(@recipe_dir) do
|
22
|
-
ey "recipes upload giblets", :debug => true
|
23
|
-
end
|
24
|
-
|
25
|
-
@out.should =~ /recipes uploaded successfully/i
|
26
|
-
end
|
27
|
-
|
28
|
-
it "errors correctly on bogus env name" do
|
29
|
-
api_scenario "one app, one environment"
|
30
|
-
ey "recipes upload bogusenv", :expect_failure => true
|
31
|
-
|
32
|
-
@err.should =~ /can't be found/i
|
33
|
-
end
|
34
|
-
|
35
|
-
it "can infer the environment from the current application" do
|
36
|
-
api_scenario "one app, one environment", "user@host.tld:path/to/repo.git"
|
37
|
-
|
38
|
-
Dir.chdir(@recipe_dir) do
|
39
|
-
ey "recipes upload", :debug => true
|
40
|
-
end
|
41
|
-
|
42
|
-
@out.should =~ /recipes uploaded successfully/i
|
43
|
-
end
|
44
|
-
|
45
|
-
it "complains when it can't infer the environment from the current application" do
|
46
|
-
api_scenario "one app, one environment, not linked", "user@host.tld:path/to/repo.git"
|
47
|
-
|
48
|
-
Dir.chdir(@recipe_dir) do
|
49
|
-
ey "recipes upload", :debug => true, :expect_failure => true
|
50
|
-
end
|
51
|
-
|
52
|
-
@err.should =~ /single environment/i
|
53
|
-
end
|
54
|
-
end
|