engineyard 1.7.0.pre2 → 2.0.0.pre1

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.
@@ -3,6 +3,7 @@ require 'engineyard/error'
3
3
  require 'engineyard/thor'
4
4
  require 'engineyard/deploy_config'
5
5
  require 'engineyard/serverside_runner'
6
+ require 'launchy'
6
7
 
7
8
  module EY
8
9
  class CLI < EY::Thor
@@ -146,7 +147,7 @@ module EY
146
147
  app_env = fetch_app_environment(options[:app], options[:environment], options[:account])
147
148
  deployment = app_env.last_deployment
148
149
  if deployment
149
- ui.say "# Status of last deployment of #{app_env.to_hierarchy_str}:"
150
+ ui.say "# Status of last deployment of #{app_env.hierarchy_name}:"
150
151
  ui.say "#"
151
152
  ui.show_deployment(deployment)
152
153
  ui.say "#"
@@ -177,10 +178,9 @@ module EY
177
178
  :desc => "Show environments matching environment name"
178
179
  def environments
179
180
  if options[:all] && options[:simple]
180
- # just put each env
181
- puts api.environments.map {|env| env.name}
181
+ ui.print_simple_envs api.environments
182
182
  elsif options[:all]
183
- ui.print_envs(api.apps, config.default_environment, options[:simple], config.endpoint)
183
+ ui.print_envs(api.apps)
184
184
  else
185
185
  remotes = nil
186
186
  if options[:app] == ''
@@ -203,14 +203,17 @@ module EY
203
203
 
204
204
  apps = resolver.matches.map { |app_env| app_env.app }.uniq
205
205
 
206
- if apps.size > 1
207
- message = "This git repo matches multiple Applications in EY Cloud:\n"
208
- apps.each { |app| message << "\t#{app.name}\n" }
209
- message << "The following environments contain those applications:\n\n"
210
- ui.warn(message)
206
+ if options[:simple]
207
+ if apps.size > 1
208
+ message = "# This app matches multiple Applications in EY Cloud:\n"
209
+ apps.each { |app| message << "#\t#{app.name}\n" }
210
+ message << "# The following environments contain those applications:\n\n"
211
+ ui.warn(message)
212
+ end
213
+ ui.print_simple_envs(apps.map{ |app| app.environments }.flatten)
214
+ else
215
+ ui.print_envs(apps, config.default_environment)
211
216
  end
212
-
213
- ui.print_envs(apps, config.default_environment, options[:simple], config.endpoint)
214
217
  end
215
218
  end
216
219
  map "envs" => :environments
@@ -263,7 +266,7 @@ module EY
263
266
  env_config = config.environment_config(app_env.environment_name)
264
267
  deploy_config = EY::DeployConfig.new(options, env_config, repo, ui)
265
268
 
266
- ui.info("Rolling back #{app_env.to_hierarchy_str}")
269
+ ui.info("Rolling back #{app_env.hierarchy_name}")
267
270
 
268
271
  runner = serverside_runner(app_env, deploy_config.verbose)
269
272
  runner.rollback do |args|
@@ -1,3 +1,5 @@
1
+ require 'tempfile'
2
+
1
3
  module EY
2
4
  class CLI
3
5
  class Recipes < EY::Thor
@@ -66,10 +68,25 @@ module EY
66
68
  environment.upload_recipes_at_path(filename)
67
69
  ui.say "Recipes file #{filename} uploaded successfully for #{environment.name}"
68
70
  else
69
- environment.tar_and_upload_recipes_in_cookbooks_dir
71
+ path = cookbooks_dir_archive_path
72
+ environment.upload_recipes_at_path(path)
70
73
  ui.say "Recipes in cookbooks/ uploaded successfully for #{environment.name}"
71
74
  end
72
75
  end
76
+
77
+ def cookbooks_dir_archive_path
78
+ unless FileTest.exist?("cookbooks")
79
+ raise EY::Error, "Could not find chef recipes. Please run from the root of your recipes repo."
80
+ end
81
+
82
+ recipes_file = Tempfile.new("recipes")
83
+ cmd = "tar czf '#{recipes_file.path}' cookbooks/"
84
+
85
+ unless system(cmd)
86
+ raise EY::Error, "Could not archive recipes.\nCommand `#{cmd}` exited with an error."
87
+ end
88
+ recipes_file.path
89
+ end
73
90
  end
74
91
 
75
92
  desc "download [--environment ENVIRONMENT]",
@@ -87,9 +104,20 @@ module EY
87
104
  :required => true, :default => '',
88
105
  :desc => "Name of the account in which the environment can be found"
89
106
  def download
107
+ if File.exist?('cookbooks')
108
+ raise EY::Error, "Cannot download recipes, cookbooks directory already exists."
109
+ end
110
+
90
111
  environment = fetch_environment(options[:environment], options[:account])
91
- environment.download_recipes
92
- ui.say "Recipes downloaded successfully for #{environment.name}"
112
+
113
+ recipes = environment.download_recipes
114
+ cmd = "tar xzf '#{recipes.path}' cookbooks"
115
+
116
+ if system(cmd)
117
+ ui.say "Recipes downloaded successfully for #{environment.name}"
118
+ else
119
+ raise EY::Error, "Could not unarchive recipes.\nCommand `#{cmd}` exited with an error."
120
+ end
93
121
  end
94
122
 
95
123
  end
@@ -127,30 +127,32 @@ module EY
127
127
  return ''
128
128
  end
129
129
 
130
- def print_envs(apps, default_env_name = nil, simple = false, endpoint = 'https://cloud.engineyard.com')
131
- if simple
132
- envs = apps.map{ |app| app.environments.to_a }
133
- puts envs.flatten.map{|env| env.name }.uniq
134
- else
135
- apps.each do |app|
136
- puts "#{app.account.name}/#{app.name}"
137
- if app.environments.any?
138
- app.environments.each do |env|
139
- short_name = env.shorten_name_for(app)
140
-
141
- icount = env.instances_count
142
- iname = (icount == 1) ? "instance" : "instances"
143
-
144
- default_text = env.name == default_env_name ? " [default]" : ""
145
-
146
- puts " #{short_name}#{default_text} (#{icount} #{iname})"
147
- end
148
- else
149
- puts " (This application is not in any environments; you can make one at #{endpoint})"
130
+ def print_simple_envs(envs)
131
+ puts envs.map{|env| env.name }.uniq.sort
132
+ end
133
+
134
+ def print_envs(apps, default_env_name = nil)
135
+ apps.sort_by {|app| "#{app.account.name}/#{app.name}" }.each do |app|
136
+ puts "#{app.account.name}/#{app.name}"
137
+ if app.environments.any?
138
+ app.environments.sort_by {|env| env.name }.each do |env|
139
+ icount = env.instances_count
140
+ iname = case icount
141
+ when 0 then "(stopped)"
142
+ when 1 then "1 instance"
143
+ else "#{icount} instances"
144
+ end
145
+
146
+ name = env.name == default_env_name ? "#{env.name} (default)" : env.name
147
+ framework_env = env.framework_env && "[#{env.framework_env.center(12)}]"
148
+
149
+ puts " #{name.ljust(30)} #{framework_env} #{iname}"
150
150
  end
151
-
152
- puts ""
151
+ else
152
+ puts " (No environments)"
153
153
  end
154
+
155
+ puts ""
154
156
  end
155
157
  end
156
158
 
@@ -1,5 +1,6 @@
1
1
  require 'uri'
2
2
  require 'yaml'
3
+ require 'pathname'
3
4
  require 'engineyard/error'
4
5
 
5
6
  module EY
@@ -60,8 +61,44 @@ module EY
60
61
  environments[environment_name] ||= {}
61
62
  environments[environment_name][key] = value
62
63
  ensure_path
64
+ comments = ey_yml_comments
63
65
  @path.open('w') do |f|
64
- YAML.dump(@config, f)
66
+ f.puts comments
67
+ f.puts YAML.dump(@config)
68
+ end
69
+ end
70
+
71
+ EY_YML_HINTS = <<-HINTS
72
+ # ey.yml supports many deploy configuration options when committed in an
73
+ # application's repository.
74
+ #
75
+ # Valid locations: REPO_ROOT/ey.yml or REPO_ROOT/config/ey.yml.
76
+ #
77
+ # Examples options:
78
+ #
79
+ # environments:
80
+ # YOUR_ENVIRONMENT_NAME: # All options pertain only to the named environment
81
+ # migrate: true # Default --migrate choice for ey deploy
82
+ # migration_command: 'rake migrate' # Default migrate command to run when migrations are enabled
83
+ # branch: default_deploy_branch # Branch/ref to be deployed by default during ey deploy
84
+ # bundle_without: development test # The string to pass to bundle install --without ''
85
+ # maintenance_on_migrate: true # Enable maintenance page during migrate action (use with caution) (default: true)
86
+ # maintenance_on_restart: false # Enable maintanence page during every deploy (default: false for unicorn & passenger)
87
+ # ignore_database_adapter_warning: false # Hide the warning shown when the Gemfile does not contain a recognized database adapter (mongodb for example)
88
+ # your_own_custom_key: 'any attribute you put in ey.yml is available in deploy hooks'
89
+ #
90
+ # Further information available here:
91
+ # https://support.cloud.engineyard.com/entries/20996661-customize-your-deployment-on-engine-yard-cloud
92
+ #
93
+ # NOTE: Please commit this file into your git repository.
94
+ #
95
+ HINTS
96
+
97
+ def ey_yml_comments
98
+ if @path.exist?
99
+ existing = @path.readlines.grep(/^#/).join("\n")
100
+ else
101
+ EY_YML_HINTS
65
102
  end
66
103
  end
67
104
 
@@ -70,8 +107,11 @@ module EY
70
107
  unless EY::Repo.exist?
71
108
  raise "Not in application directory. Unable to save configuration."
72
109
  end
73
- @path = Pathname.new('config/ey.yml')
74
- @path.dirname.mkpath
110
+ if Pathname.new('config').exist?
111
+ @path = Pathname.new('config/ey.yml')
112
+ else
113
+ @path = Pathname.new('ey.yml')
114
+ end
75
115
  @path
76
116
  end
77
117
 
@@ -101,12 +101,12 @@ module EY
101
101
  command_from_interaction
102
102
  end
103
103
  ui.say "#{env_config.path}: migrate settings saved for #{env_config.name}."
104
- ui.say "It's a good idea to git commit #{env_config.path} with these new changes."
104
+ ui.info "It's a good idea to git commit #{env_config.path} with these new changes."
105
105
  true
106
106
  rescue Timeout::Error
107
107
  @perform = nil
108
108
  @command = nil
109
- ui.error "Timeout when waiting for input. This is not a terminal."
109
+ ui.error "Timeout when waiting for input. Maybe this is not a terminal?"
110
110
  ui.error "ey deploy no longer migrates when no default is set in ey.yml."
111
111
  ui.error "Run interactively for step-by-step ey.yml migration setup."
112
112
  return false
@@ -1,3 +1,3 @@
1
1
  module EY
2
- VERSION = '1.7.0.pre2'
2
+ VERSION = '2.0.0.pre1'
3
3
  end
@@ -107,43 +107,57 @@ describe "ey deploy" do
107
107
  @ssh_commands.last.should =~ %r{/usr/local/ey_resin/ruby/bin/engineyard-serverside}
108
108
  end
109
109
 
110
- context "without migrate sepecified interactively reads migration command" do
111
- after { File.unlink 'config/ey.yml' }
110
+ context "without migrate sepecified, interactively reads migration command" do
111
+ def clean_ey_yml
112
+ File.unlink 'ey.yml' if File.exist?('ey.yml')
113
+ FileUtils.rm_r 'config' if FileTest.exist?('config')
114
+ end
115
+
116
+ before { clean_ey_yml }
117
+ after { clean_ey_yml }
112
118
 
113
- it "defaults to yes, and then rake db:migrate" do
114
- File.exist?('config/ey.yml').should be_false
119
+ it "defaults to yes, and then rake db:migrate (and installs to config/ey.yml if config/ exists already)" do
120
+ ey_yml = Pathname.new('config/ey.yml')
121
+ File.exist?('ey.yml').should be_false
122
+ ey_yml.dirname.mkpath
123
+ ey_yml.should_not be_exist
115
124
  ey(%w[deploy]) do |input|
116
125
  input.puts('')
117
126
  input.puts('')
118
127
  end
119
128
  @ssh_commands.last.should =~ /engineyard-serverside.*deploy/
120
129
  @ssh_commands.last.should =~ /--migrate 'rake db:migrate'/
121
- env_conf = read_yaml('config/ey.yml')['environments']['giblets']
130
+ File.exist?('ey.yml').should be_false
131
+ ey_yml.should be_exist
132
+ env_conf = read_yaml(ey_yml.to_s)['environments']['giblets']
122
133
  env_conf['migrate'].should == true
123
134
  env_conf['migration_command'].should == 'rake db:migrate'
124
135
  end
125
136
 
126
137
  it "accepts new commands" do
127
- File.exist?('config/ey.yml').should be_false
138
+ File.exist?('ey.yml').should be_false
139
+ FileTest.exist?('config').should be_false
128
140
  ey(%w[deploy], :hide_err => true) do |input|
129
141
  input.puts("y")
130
142
  input.puts("ruby migrate")
131
143
  end
132
144
  @ssh_commands.last.should =~ /engineyard-serverside.*deploy/
133
145
  @ssh_commands.last.should =~ /--migrate 'ruby migrate'/
134
- env_conf = read_yaml('config/ey.yml')['environments']['giblets']
146
+ File.exist?('ey.yml').should be_true
147
+ env_conf = read_yaml('ey.yml')['environments']['giblets']
135
148
  env_conf['migrate'].should == true
136
149
  env_conf['migration_command'].should == 'ruby migrate'
137
150
  end
138
151
 
139
152
  it "doesn't ask for the command if you say no" do
140
- File.exist?('config/ey.yml').should be_false
153
+ File.exist?('ey.yml').should be_false
141
154
  ey(%w[deploy], :hide_err => true) do |input|
142
155
  input.puts("no")
143
156
  end
144
157
  @ssh_commands.last.should =~ /engineyard-serverside.*deploy/
145
158
  @ssh_commands.last.should_not =~ /--migrate/
146
- read_yaml('config/ey.yml')['environments']['giblets']['migrate'].should == false
159
+ File.exist?('ey.yml').should be_true
160
+ read_yaml('ey.yml')['environments']['giblets']['migrate'].should == false
147
161
  end
148
162
  end
149
163
 
@@ -114,7 +114,6 @@ describe "ey environments with an ambiguous git repo" do
114
114
 
115
115
  it "lists environments from all apps using the git repo" do
116
116
  fast_ey %w[environments]
117
- @out.should =~ /git repo matches multiple/i
118
117
  @out.should include("giblets")
119
118
  @out.should include("keycollector_production")
120
119
  end
@@ -9,12 +9,15 @@ describe "ey environments" do
9
9
  end
10
10
 
11
11
  it "outputs the status of the deployment" do
12
+ ey %w[deploy -e giblets --ref HEAD --no-migrate]
12
13
  ey %w[status -e giblets]
13
14
  @out.should =~ /Application:\s+rails232app/
14
15
  @out.should =~ /Environment:\s+giblets/
15
16
  @out.should =~ /Ref:\s+HEAD/
16
- @out.should =~ /Resolved Ref:\s+HEAD/
17
- @out.should =~ /Deployed by:\s+User Name/
17
+ @out.should =~ /Resolved Ref:\s+resolved-HEAD/
18
+ @out.should =~ /Commit:\s+[a-f0-9]{40}/
19
+ @out.should =~ /Migrate:\s+false/
20
+ @out.should =~ /Deployed by:\s+One App Many Envs/
18
21
  @out.should =~ /Started at:/
19
22
  @out.should =~ /Finished at:/
20
23
  @out.should =~ /This deployment was successful/
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: engineyard
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.0.pre2
4
+ version: 2.0.0.pre1
5
5
  prerelease: 6
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-18 00:00:00.000000000 Z
12
+ date: 2012-05-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rest-client
@@ -82,7 +82,7 @@ dependencies:
82
82
  requirements:
83
83
  - - '='
84
84
  - !ruby/object:Gem::Version
85
- version: 1.7.0.pre2
85
+ version: 2.0.0.pre1
86
86
  type: :runtime
87
87
  prerelease: false
88
88
  version_requirements: !ruby/object:Gem::Requirement
@@ -90,7 +90,7 @@ dependencies:
90
90
  requirements:
91
91
  - - '='
92
92
  - !ruby/object:Gem::Version
93
- version: 1.7.0.pre2
93
+ version: 2.0.0.pre1
94
94
  - !ruby/object:Gem::Dependency
95
95
  name: engineyard-cloud-client
96
96
  requirement: !ruby/object:Gem::Requirement
@@ -98,7 +98,7 @@ dependencies:
98
98
  requirements:
99
99
  - - ~>
100
100
  - !ruby/object:Gem::Version
101
- version: 0.1.2
101
+ version: 1.0.1
102
102
  type: :runtime
103
103
  prerelease: false
104
104
  version_requirements: !ruby/object:Gem::Requirement
@@ -106,7 +106,7 @@ dependencies:
106
106
  requirements:
107
107
  - - ~>
108
108
  - !ruby/object:Gem::Version
109
- version: 0.1.2
109
+ version: 1.0.1
110
110
  - !ruby/object:Gem::Dependency
111
111
  name: net-ssh
112
112
  requirement: !ruby/object:Gem::Requirement
@@ -128,17 +128,17 @@ dependencies:
128
128
  requirement: !ruby/object:Gem::Requirement
129
129
  none: false
130
130
  requirements:
131
- - - '='
131
+ - - ~>
132
132
  - !ruby/object:Gem::Version
133
- version: 2.0.5
133
+ version: '2.1'
134
134
  type: :runtime
135
135
  prerelease: false
136
136
  version_requirements: !ruby/object:Gem::Requirement
137
137
  none: false
138
138
  requirements:
139
- - - '='
139
+ - - ~>
140
140
  - !ruby/object:Gem::Version
141
- version: 2.0.5
141
+ version: '2.1'
142
142
  - !ruby/object:Gem::Dependency
143
143
  name: rspec
144
144
  requirement: !ruby/object:Gem::Requirement
@@ -308,7 +308,6 @@ extensions: []
308
308
  extra_rdoc_files: []
309
309
  files:
310
310
  - bin/ey
311
- - lib/engineyard/cli/#recipes.rb#
312
311
  - lib/engineyard/cli/api.rb
313
312
  - lib/engineyard/cli/recipes.rb
314
313
  - lib/engineyard/cli/ui.rb
@@ -413,7 +412,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
413
412
  version: 1.3.1
414
413
  requirements: []
415
414
  rubyforge_project:
416
- rubygems_version: 1.8.21
415
+ rubygems_version: 1.8.24
417
416
  signing_key:
418
417
  specification_version: 3
419
418
  summary: Command-line deployment for the Engine Yard cloud
@@ -1,32 +0,0 @@
1
- module EY
2
- class CLI
3
- class Recipes < EY::Thor
4
- X1gx1GGG desc "recipes apply [ENVIRONMENT]", <<-DESC
5
- Run uploaded chef recipes on specified environment.
6
-
7
- This is similar to '#{banner_base} rebuild' except Engine Yard's main
8
- configuration step is skipped.
9
- DESC
10
-
11
- def apply(name = nil)
12
- environment = fetch_environment(name)
13
- environment.run_custom_recipes
14
- EY.ui.say "Uploaded recipes started for #{environment.name}"
15
- end
16
-
17
- desc "recipes upload [ENVIRONMENT]", <<-DESC
18
- Upload custom chef recipes to specified environment.
19
-
20
- The current directory should contain a subdirectory named "cookbooks" to be
21
- uploaded.
22
- DESC
23
-
24
- def upload(name = nil)
25
- environment = fetch_environment(name)
26
- environment.upload_recipes
27
- EY.ui.say "Recipes uploaded successfully for #{environment.name}"
28
- end
29
- end
30
- end
31
-
32
- end