engineyard-serverside 2.5.0 → 2.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -181,10 +181,10 @@ module EY
181
181
  begin
182
182
  yield servers, config, shell
183
183
  rescue EY::Serverside::RemoteFailure => e
184
- shell.exception "#{e.message}"
184
+ shell.fatal e.message
185
185
  raise
186
186
  rescue Exception => e
187
- shell.exception "#{e.backtrace[0]}: #{e.message} (#{e.class})"
187
+ shell.fatal "#{e.backtrace[0]}: #{e.message} (#{e.class})"
188
188
  raise
189
189
  end
190
190
  end
@@ -77,6 +77,7 @@ module EY
77
77
 
78
78
  def_option :precompile_assets, 'detect'
79
79
  def_option :precompile_assets_task, 'assets:precompile'
80
+ def_option(:precompile_assets_command) { "rake #{precompile_assets_task} RAILS_GROUPS=assets" }
80
81
  def_option :asset_strategy, 'shifting'
81
82
  def_option :asset_dependencies, %w[app/assets lib/assets vendor/assets Gemfile.lock config/routes.rb config/application.rb]
82
83
  def_option :asset_roles, [:app_master, :app, :solo]
@@ -101,8 +102,6 @@ module EY
101
102
  def_option :services_check_command, "which /usr/local/ey_resin/ruby/bin/ey-services-setup >/dev/null 2>&1"
102
103
  def_option(:services_setup_command) { "/usr/local/ey_resin/ruby/bin/ey-services-setup #{app}" }
103
104
 
104
- def_option :restart_groups, 1
105
-
106
105
  DEFAULT_KEEP_RELEASES = 3
107
106
 
108
107
  def_option :keep_releases, DEFAULT_KEEP_RELEASES
@@ -114,14 +113,20 @@ module EY
114
113
  def_boolean_option :precompile_unchanged_assets, false
115
114
  def_boolean_option :ignore_database_adapter_warning, false
116
115
  def_boolean_option :ignore_gemfile_lock_warning, false
116
+ def_boolean_option :shared_tmp, true
117
117
  def_boolean_option :eydeploy_rb, true
118
118
  def_boolean_option :maintenance_on_migrate, true
119
119
  def_boolean_option(:maintenance_on_restart) { required_downtime_stack? }
120
120
 
121
+ # experimental, need feedback from people using it, feature implementation subject to change or removal
122
+ def_option :restart_groups, 1
123
+ def_boolean_option :experimental_sync_assets, false
124
+
121
125
  alias app_name app
122
126
  alias environment framework_env # legacy because it would be nice to have less confusion around "environment"
123
127
  alias migration_command migrate
124
128
  alias repo git
129
+ alias ref branch # ref is used for input to cli, so it should work here.
125
130
 
126
131
  def initialize(options)
127
132
  opts = string_keys(options)
@@ -296,8 +301,8 @@ module EY
296
301
  # The nodatabase.yml file is dropped by server configuration when there is
297
302
  # no database in the cluster.
298
303
  def has_database?
299
- paths.shared_config.join('database.yml').exist? &&
300
- !paths.shared_config.join('nodatabase.yml').exist?
304
+ paths.path(:shared_config, 'database.yml').exist? &&
305
+ !paths.path(:shared_config, 'nodatabase.yml').exist?
301
306
  end
302
307
 
303
308
  def check_database_adapter?
@@ -32,9 +32,10 @@ module EY
32
32
  create_revision_file
33
33
  run_with_callbacks(:bundle)
34
34
  setup_services
35
+ configure_platform
35
36
  symlink_configs
36
37
  setup_sqlite3_if_necessary
37
- run_with_callbacks(:compile_assets) # defined in RailsAssetSupport
38
+ run_with_callbacks(:compile_assets)
38
39
  enable_maintenance_page
39
40
  run_with_callbacks(:migrate)
40
41
  callback(:before_symlink)
@@ -341,25 +342,78 @@ YML
341
342
  end
342
343
  end
343
344
 
345
+ def configure_platform
346
+ run configure_command
347
+ end
348
+
349
+ def configure_command
350
+ ENV['EY_SERVERSIDE_CONFIGURE_COMMAND'] || begin
351
+ configure_script = "/engineyard/bin/app_#{config.app}_configure"
352
+ return <<-CONFIGURE
353
+ if [ -x "#{configure_script}" ] || which "#{configure_script}" >/dev/null 2>&1; then
354
+ EY_DEPLOY_APP='#{config.app}' EY_DEPLOY_RELEASE_PATH='#{paths.active_release.to_s}' #{configure_script};
355
+ fi
356
+ CONFIGURE
357
+ end
358
+ end
359
+
344
360
  def symlink_configs
345
361
  shell.status "Preparing shared resources for release."
362
+
363
+ shell.substatus "Set group write permissions"
364
+ run "chmod -R g+w #{paths.active_release}"
365
+
366
+ setup_shared_tmp
367
+
346
368
  symlink_tasks.each do |what, cmd|
347
369
  shell.substatus what
348
370
  run(cmd)
349
371
  end
350
372
  end
351
373
 
374
+ def setup_shared_tmp
375
+ if config.shared_tmp?
376
+ shell.substatus "Creating and symlinking shared tmp directory if empty"
377
+ run <<-SETUP_TMP
378
+ if [ -e "#{paths.active_tmp}" ] && [ ! "$(ls #{paths.active_tmp} 2>&1)" ]; then
379
+ rm -rf #{paths.active_tmp};
380
+ fi;
381
+ if [ ! -e "#{paths.active_tmp}" ]; then
382
+ mkdir -p #{paths.shared_tmp} && ln -nfs #{paths.shared_tmp} #{paths.active_tmp};
383
+ fi
384
+ SETUP_TMP
385
+
386
+ unless paths.active_tmp.symlink?
387
+ note = "This application's repository has tmp/ with contents committed.\n"
388
+ if config.precompile_assets?
389
+ note << "Asset precompile speed can be increased by sharing tmp across releases.\n"
390
+ end
391
+ note << <<-NOTICE
392
+ Enable shared tmp with the follow git command (if applicable):
393
+
394
+ $ git rm -r tmp/* && echo '*' > tmp/.gitignore
395
+
396
+ Or, disable this feature via ey.yml configuration as follows:
397
+
398
+ defaults:
399
+ shared_tmp: false
400
+ NOTICE
401
+ shell.notice note
402
+ end
403
+ else
404
+ shell.substatus "Prepare shared pids directory"
405
+ run "rm -rf #{paths.active_tmp}/pids"
406
+ end
407
+ end
408
+
352
409
  def symlink_tasks
353
410
  [
354
- ["Set group write permissions", "chmod -R g+w #{paths.active_release}"],
411
+ ["Symlink shared pids directory", "ln -nfs #{paths.shared}/pids #{paths.active_tmp}/pids"],
412
+ ["Symlink shared log directory", "rm -rf #{paths.active_log} && ln -nfs #{paths.shared_log} #{paths.active_log}"],
355
413
  ["Remove public/system if symlinked", "if [ -L \"#{paths.public_system}\" ]; then rm -rf #{paths.public_system}; fi"],
356
- ["Remove symlinked shared directories", "rm -rf #{paths.active_log} #{paths.active_release}/tmp/pids"],
357
- ["Create tmp directory", "mkdir -p #{paths.active_release}/tmp"],
358
414
  ["Create public directory", "mkdir -p #{paths.public}"],
359
- ["Create config directory", "mkdir -p #{paths.active_release_config}"],
360
- ["Symlink shared log directory", "ln -nfs #{paths.shared_log} #{paths.active_log}"],
361
415
  ["Symlink public system directory", "if [ ! -e \"#{paths.public_system}\" ]; then ln -ns #{paths.shared_system} #{paths.public_system}; fi"],
362
- ["Symlink shared pids directory", "ln -nfs #{paths.shared}/pids #{paths.active_release}/tmp/pids"],
416
+ ["Create config directory", "mkdir -p #{paths.active_release_config}"],
363
417
  ["Symlink other shared config files", "find #{paths.shared_config} -maxdepth 1 -type f -not -name 'database.yml' -exec ln -s {} #{paths.active_release_config} \\;"],
364
418
  ["Symlink database.yml if needed", "if [ -f \"#{paths.shared_config}/database.yml\" ]; then ln -nfs #{paths.shared_config}/database.yml #{paths.active_release_config}/database.yml; fi"],
365
419
  ["Symlink newrelic.yml if needed", "if [ -f \"#{paths.shared_config}/newrelic.yml\" ]; then ln -nfs #{paths.shared_config}/newrelic.yml #{paths.active_release_config}/newrelic.yml; fi"],
@@ -51,8 +51,10 @@ module EY
51
51
  end
52
52
 
53
53
  # Load a path given a root and more parts
54
+ # Pathname#join is extremely inefficient.
55
+ # This implementation uses much less memory and way fewer objects.
54
56
  def path(root, *parts)
55
- send(root).join(*parts)
57
+ Pathname.new(File.join(send(root).to_s, *parts))
56
58
  end
57
59
 
58
60
  attr_reader :home, :deploy_root
@@ -64,6 +66,7 @@ module EY
64
66
  def_path :releases_failed, [:deploy_root, 'releases_failed']
65
67
  def_path :shared, [:deploy_root, 'shared']
66
68
  def_path :shared_log, [:shared, 'log']
69
+ def_path :shared_tmp, [:shared, 'tmp']
67
70
  def_path :shared_config, [:shared, 'config']
68
71
  def_path :shared_system, [:shared, 'system']
69
72
  def_path :default_repository_cache, [:shared, 'cached-copy']
@@ -79,6 +82,7 @@ module EY
79
82
  def_path :gemfile, [:active_release, 'Gemfile']
80
83
  def_path :gemfile_lock, [:active_release, 'Gemfile.lock']
81
84
  def_path :public, [:active_release, 'public']
85
+ def_path :deploy_hooks, [:active_release, 'deploy']
82
86
  def_path :public_assets, [:public, 'assets']
83
87
  def_path :public_system, [:public, 'system']
84
88
  def_path :package_json, [:active_release, 'package.json']
@@ -86,6 +90,7 @@ module EY
86
90
  def_path :composer_lock, [:active_release, 'composer.lock']
87
91
  def_path :active_release_config, [:active_release, 'config']
88
92
  def_path :active_log, [:active_release, 'log']
93
+ def_path :active_tmp, [:active_release, 'tmp']
89
94
 
90
95
  def initialize(opts)
91
96
  @opts = opts
@@ -118,11 +123,11 @@ module EY
118
123
  end
119
124
 
120
125
  def deploy_hook(hook_name)
121
- path(:active_release, 'deploy', "#{hook_name}.rb")
126
+ path(:deploy_hooks, "#{hook_name}.rb")
122
127
  end
123
128
 
124
129
  def executable_deploy_hook(hook_name)
125
- path(:active_release, 'deploy', "#{hook_name}")
130
+ path(:deploy_hooks, "#{hook_name}")
126
131
  end
127
132
 
128
133
  def repository_cache
@@ -130,7 +135,7 @@ module EY
130
135
  end
131
136
 
132
137
  def all_releases
133
- @all_releases ||= Pathname.glob(releases.join('*')).sort
138
+ @all_releases ||= Pathname.glob(path(:releases,'*')).sort
134
139
  end
135
140
 
136
141
  # deploy_root/releases/<release before argument release path>
@@ -19,7 +19,8 @@ module EY
19
19
  def_delegators :config,
20
20
  :paths, :asset_dependencies, :asset_roles,
21
21
  :framework_envs, :precompile_assets?, :skip_precompile_assets?,
22
- :precompile_unchanged_assets?, :precompile_assets_task
22
+ :precompile_unchanged_assets?, :precompile_assets_task,
23
+ :precompile_assets_command
23
24
 
24
25
  def detect_and_compile
25
26
  runner.roles asset_roles do
@@ -43,7 +44,7 @@ module EY
43
44
  elsif paths.public_assets.exist?
44
45
  shell.status "Skipping asset precompilation. ('public/assets' directory already exists.)"
45
46
  else
46
- shell.status "Precompiling assets. ('#{app_assets}' exists, 'public/assets' not found, not disabled in config.)"
47
+ shell.status "Precompiling assets. ('app/assets' exists, 'public/assets' not found, not disabled in config.)"
47
48
  precompile_detected_assets
48
49
  end
49
50
  end
@@ -52,8 +53,20 @@ module EY
52
53
  def run_precompile_assets_task
53
54
  asset_strategy.prepare do
54
55
  cd = "cd #{paths.active_release}"
55
- task = "PATH=#{paths.binstubs}:$PATH #{framework_envs} rake #{precompile_assets_task} RAILS_GROUPS=assets"
56
- runner.run "#{cd} && #{task}"
56
+ task = "PATH=#{paths.binstubs}:$PATH #{framework_envs} #{precompile_assets_command}"
57
+
58
+ # This is a hack right now, but I haven't iterated over it enough for a good solution yet.
59
+ if config.experimental_sync_assets?
60
+ shell.status "Compiling assets once on localhost (experimental_sync_assets: true)"
61
+ shell.logged_system("sh -l -c '#{cd} && #{task}'")
62
+
63
+ shell.status "Syncing assets to other remote servers (experimental_sync_assets: true)"
64
+ runner.servers.remote.run_for_each do |server|
65
+ server.sync_directory_command(paths.public_assets)
66
+ end
67
+ else
68
+ runner.run "#{cd} && #{task}"
69
+ end
57
70
  end
58
71
  end
59
72
 
@@ -139,15 +152,11 @@ ACTION REQUIRED: Add precompile_assets option to ey.yml.
139
152
  end
140
153
 
141
154
  def application_rb_path
142
- paths.active_release.join('config','application.rb')
143
- end
144
-
145
- def app_assets
146
- File.join('app','assets')
155
+ paths.path(:active_release,'config','application.rb')
147
156
  end
148
157
 
149
158
  def app_assets_path
150
- paths.active_release.join(app_assets)
159
+ paths.path(:active_release,'app','assets')
151
160
  end
152
161
 
153
162
  def asset_strategy
@@ -48,7 +48,7 @@ module EY
48
48
  # deploy_root/current/public/last_assets/assets -> deploy_root/releases/<prev>/public/assets
49
49
  def prepare
50
50
  if previous_assets_path
51
- last = paths.public.join('last_assets')
51
+ last = paths.path(:public,'last_assets')
52
52
  run "mkdir -p #{last} && ln -nfs #{previous_assets_path} #{last.join('assets')}"
53
53
  end
54
54
 
@@ -1,19 +1,27 @@
1
1
  require 'logger'
2
2
  require 'pathname'
3
- require 'open3'
4
3
  require 'engineyard-serverside/shell/formatter'
5
4
  require 'engineyard-serverside/shell/yieldio'
6
5
 
7
6
  module EY
8
7
  module Serverside
9
8
  class Shell
10
- attr_reader :logger
9
+ STATUS_PREFIX = '~> '.freeze
10
+ SUBSTATUS_PREFIX = ' ~ '.freeze
11
+ IMPORTANT_PREFIX = '!> '.freeze
12
+ CMD_PREFIX = ' $ '.freeze
13
+ CMD_CONTINUE = ' > '.freeze
14
+ CMD_INDENT = ' '.freeze
15
+ BOL = /^/.freeze
16
+
17
+ include Logger::Severity
18
+
19
+ attr_reader :logger, :start_time
11
20
 
12
21
  def initialize(options)
13
- @start_time = options[:start_time]
22
+ @start_time = options[:start_time] || Time.now
14
23
  @verbose = options[:verbose]
15
24
 
16
-
17
25
  @stdout = options[:stdout] || $stdout
18
26
  @stderr = options[:stderr] || $stderr
19
27
 
@@ -28,39 +36,35 @@ module EY
28
36
  @verbose
29
37
  end
30
38
 
31
- def start_time
32
- @start_time ||= Time.now
33
- end
34
-
35
39
  # a nice info outputter that prepends spermy operators for some reason.
36
40
  def status(msg)
37
41
  if msg.respond_to?(:force_encoding)
38
- msg.force_encoding("UTF-8")
42
+ msg.force_encoding(Encoding::UTF_8)
39
43
  end
40
- info msg.gsub(/^/, '~> ')
44
+ info msg.gsub(BOL, STATUS_PREFIX)
41
45
  end
42
46
 
43
47
  def substatus(msg)
44
- debug msg.gsub(/^/, ' ~ ')
48
+ debug msg.gsub(BOL, SUBSTATUS_PREFIX)
45
49
  end
46
50
 
47
- def fatal(msg) logger.fatal "FATAL: #{msg}" end
48
- def error(msg) logger.error "ERROR: #{msg}" end
51
+ def fatal(msg) logger.fatal "FATAL: #{msg}" end
52
+ def error(msg) logger.error "ERROR: #{msg}" end
49
53
  def warning(msg) logger.warn "WARNING: #{msg}" end
54
+ alias warn warning
50
55
  def notice(msg) logger.warn msg end
51
56
  def info(msg) logger.info msg end
52
57
  def debug(msg) logger.debug msg end
53
58
  def unknown(msg) logger.unknown msg end
54
59
 
55
- def exception(msg) error msg end
56
60
  # a debug outputter that displays a command being run
57
61
  # Formatis like this:
58
62
  # $ cmd blah do \
59
63
  # > something more
60
64
  # > end
61
- def command_show(cmd) debug cmd.gsub(/^/,' > ').sub(/>/, '$') end
62
- def command_out(msg) debug msg.gsub(/^/,' ') end
63
- def command_err(msg) unknown msg.gsub(/^/,' ') end
65
+ def command_show(cmd) debug cmd.gsub(BOL,CMD_CONTINUE).sub(CMD_CONTINUE, CMD_PREFIX) end
66
+ def command_out(msg) debug msg.gsub(BOL,CMD_INDENT) end
67
+ def command_err(msg) unknown msg.gsub(BOL,CMD_INDENT) end
64
68
 
65
69
  def logged_system(cmd, server = nil)
66
70
  EY::Serverside::Spawner.run(cmd, self, server)
@@ -2,6 +2,22 @@ module EY
2
2
  module Serverside
3
3
  class Shell
4
4
  class Formatter
5
+ FATAL = 'ERROR'.freeze
6
+ ERROR = 'ERROR'.freeze
7
+ WARN = 'WARN'.freeze
8
+ INFO = 'INFO'.freeze
9
+ DEBUG = 'DEBUG'.freeze
10
+ IMPORTANT = [WARN, ERROR, FATAL].freeze
11
+
12
+ SECONDS_FORMAT = '+ %02ds '.freeze
13
+ MINUTES_FORMAT = '+%2dm %02ds '.freeze
14
+
15
+ STATUS_PREFIX = '~> '.freeze
16
+ SUBSTATUS_PREFIX = ' ~ '.freeze
17
+ IMPORTANT_PREFIX = '!> '.freeze
18
+
19
+ NL = "\n".freeze
20
+
5
21
  def initialize(stdout, stderr, start_time, verbose)
6
22
  @stdout, @stderr = stdout, stderr
7
23
  @start = start_time.to_i
@@ -15,35 +31,42 @@ module EY
15
31
  end
16
32
 
17
33
  def build_message(severity, stamp, message)
18
- if %w[WARN ERROR FATAL].include?(severity)
19
- prepend("#{stamp}!> ", "#{message}")
20
- elsif severity == "INFO"
34
+ if IMPORTANT.include?(severity)
35
+ prepend("#{stamp}#{IMPORTANT_PREFIX}", message)
36
+ elsif INFO == severity
21
37
  prepend(stamp, message)
22
38
  else
23
- prepend(' ' * stamp.size, message)
39
+ prepend(stamp, message)
24
40
  end
25
41
  end
26
42
 
27
43
  def prepend(pre, str)
28
- str.gsub(/^/, pre).sub(/\n?\z/m,"\n")
44
+ str.gsub(/^/, pre).sub(/\n?\z/m,NL)
29
45
  end
30
46
 
31
47
  def put_to_io(severity, msg)
32
48
  case severity
33
- when "DEBUG"
49
+ when DEBUG
34
50
  if @verbose
35
51
  @stdout << msg
36
52
  @stdout.flush
37
53
  end
38
- when "INFO"
54
+ when INFO
39
55
  # Need to differentiate info messages more when we're running in verbose mode
40
- @stdout << (@verbose && msg.index('~>') ? "\n#{thor_shell.set_color(msg, :white, true)}" : msg)
56
+ if @verbose && msg.index(STATUS_PREFIX)
57
+ @stdout.puts
58
+ @stdout << thor_shell.set_color(msg, :white, true)
59
+ else
60
+ @stdout << msg
61
+ end
41
62
  @stdout.flush
42
- when "WARN"
43
- @stderr << "\n" << thor_shell.set_color(msg, :yellow, true)
63
+ when WARN
64
+ @stderr.puts
65
+ @stderr << thor_shell.set_color(msg, :yellow, true)
44
66
  @stderr.flush
45
- when "ERROR"
46
- @stderr << "\n" << thor_shell.set_color(msg, :red, true)
67
+ when ERROR
68
+ @stderr.puts
69
+ @stderr << thor_shell.set_color(msg, :red, true)
47
70
  @stderr.flush
48
71
  else
49
72
  @stderr << msg
@@ -56,9 +79,9 @@ module EY
56
79
  diff = 0 if diff < 0
57
80
  div, mod = diff.divmod(60)
58
81
  if div.zero?
59
- "+ %02ds " % mod
82
+ SECONDS_FORMAT % mod
60
83
  else
61
- "+%2dm %02ds " % [div,mod]
84
+ MINUTES_FORMAT % [div,mod]
62
85
  end
63
86
  end
64
87
 
@@ -1,5 +1,5 @@
1
1
  module EY
2
2
  module Serverside
3
- VERSION = '2.5.0'
3
+ VERSION = '2.6.0'
4
4
  end
5
5
  end
@@ -20,7 +20,7 @@ describe "Deploying a simple application" do
20
20
  args.instances = [{ :hostname => "localhost", :roles => ["solo"], :name => "single" }]
21
21
  args.serverside_version = Gem::Version.create(EY::Serverside::VERSION.dup).release
22
22
  args.config = {
23
- "deploy_to" => deploy_dir,
23
+ "deploy_to" => deploy_dir.to_s,
24
24
  "group" => GROUP
25
25
  }
26
26
  end
@@ -40,9 +40,8 @@ describe "Deploying an application that uses Bundler" do
40
40
  end
41
41
 
42
42
  it "generates bundler binstubs" do
43
- pending "doesn't work with mocked bundler" do
44
- expect(deploy_dir.join('current', 'ey_bundler_binstubs', 'rake')).to exist
45
- end
43
+ pending "doesn't work with mocked bundler"
44
+ expect(deploy_dir.join('current', 'ey_bundler_binstubs', 'rake')).to exist
46
45
  end
47
46
  end
48
47
 
@@ -111,7 +110,7 @@ describe "Deploying an application that uses Bundler" do
111
110
  context "without a Gemfile.lock and ignoring the warning" do
112
111
  before(:all) do
113
112
  deploy_test_application('no_gemfile_lock', 'config' => {'ignore_gemfile_lock_warning' => true})
114
- expect(@config.ignore_gemfile_lock_warning).to be_true
113
+ expect(@config.ignore_gemfile_lock_warning).to be_truthy
115
114
  @install_bundler_command = @deployer.commands.grep(/gem install bundler/).first
116
115
  @bundle_install_command = @deployer.commands.grep(/bundle _#{VERSION_PATTERN}_ install/).first
117
116
  end
@@ -15,6 +15,7 @@ describe EY::Serverside::Deploy::Configuration do
15
15
  expect(@config.migrate).to eq(nil)
16
16
  expect(@config.migrate?).to eq(false)
17
17
  expect(@config.branch).to eq("master")
18
+ expect(@config.ref).to eq("master")
18
19
  expect(@config.maintenance_on_migrate).to eq(true)
19
20
  expect(@config.maintenance_on_restart).to eq(true)
20
21
  expect(@config.required_downtime_stack?).to eq(true)
@@ -49,7 +49,7 @@ describe "deploy hooks" do
49
49
  end
50
50
 
51
51
  it 'runs the hook' do
52
- deploy_dir.join('current', 'before_restart.ran').should exist
52
+ expect(deploy_dir.join('current', 'before_restart.ran')).to exist
53
53
  end
54
54
  end
55
55
 
@@ -59,7 +59,7 @@ describe "deploy hooks" do
59
59
  end
60
60
 
61
61
  it 'does not run the hook' do
62
- deploy_dir.join('current', 'before_restart.ran').should_not exist
62
+ expect(deploy_dir.join('current', 'before_restart.ran')).not_to exist
63
63
  end
64
64
 
65
65
  it 'outputs a message about the hook not being executable' do
@@ -83,7 +83,7 @@ describe "deploy hooks" do
83
83
 
84
84
  context "#run" do
85
85
  it "is available" do
86
- expect(deploy_hook.eval_hook('respond_to?(:run)')).to be_true
86
+ expect(deploy_hook.eval_hook('respond_to?(:run)')).to be_truthy
87
87
  end
88
88
 
89
89
  it "runs commands like the shell does" do
@@ -96,8 +96,8 @@ describe "deploy hooks" do
96
96
  end
97
97
 
98
98
  it "returns true/false to indicate the command's success" do
99
- expect(deploy_hook.eval_hook('run("true")')).to be_true
100
- expect(deploy_hook.eval_hook('run("false")')).to be_false
99
+ expect(deploy_hook.eval_hook('run("true")')).to be_truthy
100
+ expect(deploy_hook.eval_hook('run("false")')).to be_falsey
101
101
  end
102
102
 
103
103
  it "raises when the bang method alternative is used" do
@@ -113,7 +113,7 @@ describe "deploy hooks" do
113
113
 
114
114
  context "#sudo" do
115
115
  it "is available" do
116
- expect(deploy_hook.eval_hook('respond_to?(:sudo)')).to be_true
116
+ expect(deploy_hook.eval_hook('respond_to?(:sudo)')).to be_truthy
117
117
  end
118
118
 
119
119
  it "runs things with sudo" do
@@ -139,18 +139,18 @@ describe "deploy hooks" do
139
139
 
140
140
  context "capistrano-ish methods" do
141
141
  it "has them" do
142
- expect(deploy_hook.eval_hook('respond_to?(:latest_release) ')).to be_true
143
- expect(deploy_hook.eval_hook('respond_to?(:previous_release) ')).to be_true
144
- expect(deploy_hook.eval_hook('respond_to?(:all_releases) ')).to be_true
145
- expect(deploy_hook.eval_hook('respond_to?(:current_path) ')).to be_true
146
- expect(deploy_hook.eval_hook('respond_to?(:shared_path) ')).to be_true
147
- expect(deploy_hook.eval_hook('respond_to?(:release_dir) ')).to be_true
148
- expect(deploy_hook.eval_hook('respond_to?(:failed_release_dir)')).to be_true
149
- expect(deploy_hook.eval_hook('respond_to?(:release_path) ')).to be_true
142
+ expect(deploy_hook.eval_hook('respond_to?(:latest_release) ')).to be_truthy
143
+ expect(deploy_hook.eval_hook('respond_to?(:previous_release) ')).to be_truthy
144
+ expect(deploy_hook.eval_hook('respond_to?(:all_releases) ')).to be_truthy
145
+ expect(deploy_hook.eval_hook('respond_to?(:current_path) ')).to be_truthy
146
+ expect(deploy_hook.eval_hook('respond_to?(:shared_path) ')).to be_truthy
147
+ expect(deploy_hook.eval_hook('respond_to?(:release_dir) ')).to be_truthy
148
+ expect(deploy_hook.eval_hook('respond_to?(:failed_release_dir)')).to be_truthy
149
+ expect(deploy_hook.eval_hook('respond_to?(:release_path) ')).to be_truthy
150
150
  end
151
151
 
152
152
  it "shows a deprecation warning that asks you to use config to access these variables" do
153
- expect(deploy_hook.eval_hook('shared_path.nil?')).to be_false
153
+ expect(deploy_hook.eval_hook('shared_path.nil?')).to be_falsey
154
154
  out = read_output
155
155
  expect(out).to include("Use of `shared_path` (via method_missing) is deprecated in favor of `config.shared_path` for improved error messages and compatibility.")
156
156
  expect(out).to match(%r|in .*/deploy/fake_test_hook.rb|)
@@ -189,7 +189,7 @@ describe "deploy hooks" do
189
189
  end
190
190
 
191
191
  it "is deprecated through the @node ivar" do
192
- expect(deploy_hook.eval_hook('@node.nil?')).to be_false
192
+ expect(deploy_hook.eval_hook('@node.nil?')).to be_falsey
193
193
  out = read_output
194
194
  expect(out).to match(%r|Use of `@node` in deploy hooks is deprecated.|)
195
195
  expect(out).to match(%r|Please use `config.node`, which provides access to the same object.|)
@@ -197,7 +197,7 @@ describe "deploy hooks" do
197
197
  end
198
198
 
199
199
  it "is available" do
200
- expect(deploy_hook.eval_hook('config.node.nil?')).to be_false
200
+ expect(deploy_hook.eval_hook('config.node.nil?')).to be_falsey
201
201
  end
202
202
 
203
203
  it "has indifferent access" do
@@ -214,11 +214,11 @@ describe "deploy hooks" do
214
214
 
215
215
  context "config" do
216
216
  it "is available" do
217
- expect(deploy_hook.eval_hook('config.nil?')).to be_false
217
+ expect(deploy_hook.eval_hook('config.nil?')).to be_falsey
218
218
  end
219
219
 
220
220
  it "is deprecated through the @configuration ivar" do
221
- expect(deploy_hook.eval_hook('@configuration.nil?')).to be_false
221
+ expect(deploy_hook.eval_hook('@configuration.nil?')).to be_falsey
222
222
  out = read_output
223
223
  expect(out).to match(%r|Use of `@configuration` in deploy hooks is deprecated.|)
224
224
  expect(out).to match(%r|Please use `config`, which provides access to the same object.|)
@@ -244,7 +244,7 @@ describe "deploy hooks" do
244
244
  :revision,
245
245
  :environment].each do |attribute|
246
246
  it "has the #{attribute.inspect} attribute for compatibility with chef-deploy" do
247
- expect(deploy_hook.eval_hook("config.has_key?(#{attribute.inspect})")).to be_true
247
+ expect(deploy_hook.eval_hook("config.has_key?(#{attribute.inspect})")).to be_truthy
248
248
  end
249
249
  end
250
250
  end
@@ -351,11 +351,11 @@ describe "deploy hooks" do
351
351
  end
352
352
 
353
353
  it "has info, warning, debug, logged_system, and access to shell" do
354
- expect(deploy_hook.eval_hook('respond_to?(:info) ')).to be_true
355
- expect(deploy_hook.eval_hook('respond_to?(:warning) ')).to be_true
356
- expect(deploy_hook.eval_hook('respond_to?(:debug) ')).to be_true
357
- expect(deploy_hook.eval_hook('respond_to?(:logged_system)')).to be_true
358
- expect(deploy_hook.eval_hook('respond_to?(:shell) ')).to be_true
354
+ expect(deploy_hook.eval_hook('respond_to?(:info) ')).to be_truthy
355
+ expect(deploy_hook.eval_hook('respond_to?(:warning) ')).to be_truthy
356
+ expect(deploy_hook.eval_hook('respond_to?(:debug) ')).to be_truthy
357
+ expect(deploy_hook.eval_hook('respond_to?(:logged_system)')).to be_truthy
358
+ expect(deploy_hook.eval_hook('respond_to?(:shell) ')).to be_truthy
359
359
  end
360
360
  end
361
361
  end
@@ -2,4 +2,5 @@ environments:
2
2
  env:
3
3
  precompile_assets: true
4
4
  asset_roles: :all
5
+ precompile_assets_command: script/assets
5
6
  ignore_database_adapter_warning: true
@@ -0,0 +1,5 @@
1
+ #!/bin/sh
2
+ touch public/assets/custom_compiled_asset
3
+ touch custom_compiled
4
+ # mirror the behavior of compiling using asset caches in tmp
5
+ [ -e tmp/cache ] && touch cache_compiled || touch tmp/cache
@@ -0,0 +1 @@
1
+ This file obstructs the sharing of the tmp dir.
@@ -3,5 +3,6 @@ task 'assets:precompile' do
3
3
  sh "mkdir -p #{File.expand_path('../public/assets', __FILE__)}"
4
4
  sh "touch #{File.expand_path('../public/assets/compiled_asset', __FILE__)}"
5
5
  sh 'touch precompiled'
6
+ sh '[ -e tmp/cache ] && touch cache_compiled || touch tmp/cache' # mirror the behavior of compiling using asset caches in tmp
6
7
  end
7
8
 
@@ -59,27 +59,27 @@ describe "the bundler version retrieved from the lockfile" do
59
59
 
60
60
  context "checking for gems in the dependencies" do
61
61
  it "does not have any database adapters in a gemfile lock without them" do
62
- expect(get_parser('1.0.6-no-bundler').any_database_adapter?).to be_false
62
+ expect(get_parser('1.0.6-no-bundler').any_database_adapter?).to be_falsey
63
63
  end
64
64
 
65
65
  it "has a database adapter in a Gemfile.lock with do_mysql" do
66
- expect(get_parser('1.0.18-do_mysql').any_database_adapter?).to be_true
66
+ expect(get_parser('1.0.18-do_mysql').any_database_adapter?).to be_truthy
67
67
  end
68
68
 
69
69
  it "has a database adapter in a Gemfile.lock with mysql" do
70
- expect(get_parser('1.0.18-mysql').any_database_adapter?).to be_true
70
+ expect(get_parser('1.0.18-mysql').any_database_adapter?).to be_truthy
71
71
  end
72
72
 
73
73
  it "has a database adapter in a Gemfile.lock with mysql2" do
74
- expect(get_parser('1.0.18-mysql2').any_database_adapter?).to be_true
74
+ expect(get_parser('1.0.18-mysql2').any_database_adapter?).to be_truthy
75
75
  end
76
76
 
77
77
  it "has a database adapter in a Gemfile.lock with pg" do
78
- expect(get_parser('1.0.18-pg').any_database_adapter?).to be_true
78
+ expect(get_parser('1.0.18-pg').any_database_adapter?).to be_truthy
79
79
  end
80
80
 
81
81
  it "has a database adapter in a Gemfile.lock with do_postgres" do
82
- expect(get_parser('1.0.18-do_postgres').any_database_adapter?).to be_true
82
+ expect(get_parser('1.0.18-do_postgres').any_database_adapter?).to be_truthy
83
83
  end
84
84
  end
85
85
 
@@ -23,22 +23,22 @@ describe EY::Serverside::Maintenance do
23
23
  it "lets you know if the app is in maintenance mode" do
24
24
  maintenance_status
25
25
  maintenance_output = read_output.split("\n").select{|l| l.match("Maintenance")}
26
- maintenance_output.count.should == 1
27
- maintenance_output.first.should match(/Maintenance page: down$/)
26
+ expect(maintenance_output.count).to eq(1)
27
+ expect(maintenance_output.first).to match(/Maintenance page: down$/)
28
28
 
29
29
  enable_maintenance
30
30
 
31
31
  maintenance_status
32
32
  maintenance_output = read_output.split("\n").select{|l| l.match("Maintenance")}
33
- maintenance_output.count.should == 1
34
- maintenance_output.first.should match(/Maintenance page: up$/)
33
+ expect(maintenance_output.count).to eq(1)
34
+ expect(maintenance_output.first).to match(/Maintenance page: up$/)
35
35
 
36
36
  disable_maintenance
37
37
 
38
38
  maintenance_status
39
39
  maintenance_output = read_output.split("\n").select{|l| l.match("Maintenance")}
40
- maintenance_output.count.should == 1
41
- maintenance_output.first.should match(/Maintenance page: down$/)
40
+ expect(maintenance_output.count).to eq(1)
41
+ expect(maintenance_output.first).to match(/Maintenance page: down$/)
42
42
  end
43
43
  end
44
44
  end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Deploying an application with platform configure command" do
4
+ describe "configure script does not exist" do
5
+ before do
6
+ @releases_failed = deploy_dir.join('releases_failed')
7
+ deploy_test_application('default')
8
+ end
9
+
10
+ it "works without warning" do
11
+ expect(read_output).not_to match(/WARNING/)
12
+
13
+ expect(@releases_failed).not_to exist
14
+ end
15
+ end
16
+
17
+ describe "a succesful deploy" do
18
+ before do
19
+ @releases_failed = deploy_dir.join('releases_failed')
20
+ ENV['EY_SERVERSIDE_CONFIGURE_COMMAND'] = "echo platform_configure_command_ran >&2"
21
+ deploy_test_application('default')
22
+ end
23
+
24
+ after do
25
+ ENV.delete('EY_SERVERSIDE_CONFIGURE_COMMAND')
26
+ end
27
+
28
+ it "runs the configure_command during deploy and finishes successfully" do
29
+ expect(read_output).to match(/platform_configure_command_ran/)
30
+
31
+ expect(@releases_failed).not_to exist
32
+
33
+ restart = deploy_dir.join('current', 'restart')
34
+ expect(restart).to exist
35
+ end
36
+ end
37
+
38
+ describe "a failed configure command" do
39
+
40
+ before do
41
+ ENV['EY_SERVERSIDE_CONFIGURE_COMMAND'] = "echo platform_configure_command_failed >&2 && false"
42
+ end
43
+
44
+ after do
45
+ ENV.delete('EY_SERVERSIDE_CONFIGURE_COMMAND')
46
+ end
47
+
48
+ it "aborts the deplo when it fails, preventing the app from being restarted" do
49
+ @releases_failed = deploy_dir.join('releases_failed')
50
+ expect(@releases_failed).not_to exist
51
+
52
+ begin
53
+ deploy_test_application('default')
54
+ rescue
55
+ end
56
+ expect(read_output).to match(/platform_configure_command_failed/)
57
+
58
+ expect(@releases_failed.entries).not_to be_empty
59
+ end
60
+ end
61
+ end
@@ -34,6 +34,9 @@ describe "Deploying a Rails 3.1 application" do
34
34
  expect(deploy_dir.join('current', 'precompiled')).to exist
35
35
  expect(deploy_dir.join('current', 'public', 'assets')).to exist
36
36
  expect(deploy_dir.join('current', 'public', 'assets', 'compiled_asset')).to exist
37
+ expect(deploy_dir.join('current', 'tmp', 'cache')).to exist
38
+ expect(deploy_dir.join('current', 'tmp')).to be_a_symlink
39
+ expect(deploy_dir.join('current', 'cache_compiled')).not_to exist
37
40
  expect(read_output).to include("Precompiling assets. (precompile_assets: true)")
38
41
 
39
42
  # changing the ref stands in for actually having assets change (see Strategies::IntegrationSpec#same?)
@@ -41,6 +44,9 @@ describe "Deploying a Rails 3.1 application" do
41
44
  expect(deploy_dir.join('current', 'precompiled')).to exist # it does runs the task
42
45
  expect(deploy_dir.join('current', 'public', 'assets')).to exist
43
46
  expect(deploy_dir.join('current', 'public', 'assets', 'compiled_asset')).to exist
47
+ expect(deploy_dir.join('current', 'tmp')).to be_a_symlink
48
+ expect(deploy_dir.join('current', 'tmp', 'cache')).to exist # preserves tmp dir
49
+ expect(deploy_dir.join('current', 'cache_compiled')).to exist # uses tmp/cache to compile assets faster
44
50
  expect(read_output).not_to match(%r#Reusing existing assets#)
45
51
  end
46
52
 
@@ -97,14 +103,22 @@ describe "Deploying a Rails 3.1 application" do
97
103
  end
98
104
  end
99
105
 
100
- context "with asset compilation enabled in ey.yml, and asset_roles is set to :all" do
106
+ context "with asset compilation enabled in ey.yml, and asset_roles is set to :all, and a custom compile command" do
101
107
  before(:all) do
102
108
  deploy_test_application('assets_enabled_all')
103
109
  end
104
110
 
105
- it "precompiles assets" do
106
- expect(deploy_dir.join('current', 'precompiled')).to exist
111
+ it "precompiles assets but never shares the tmp cache because the repository has a committed tmp dir with contents" do
112
+ expect(deploy_dir.join('current', 'custom_compiled')).to exist
113
+ expect(deploy_dir.join('current', 'cache_compiled')).not_to exist
114
+ expect(deploy_dir.join('current', 'tmp', 'cache')).to exist
115
+ expect(deploy_dir.join('current', 'tmp')).not_to be_a_symlink
107
116
  expect(read_output).to include("Precompiling assets. (precompile_assets: true)")
117
+
118
+ redeploy_test_application('config' => {'precompile_unchanged_assets' => 'true'})
119
+ expect(deploy_dir.join('current', 'tmp', 'cache')).to exist
120
+ expect(deploy_dir.join('current', 'cache_compiled')).not_to exist
121
+ expect(deploy_dir.join('current', 'tmp')).not_to be_a_symlink
108
122
  end
109
123
  end
110
124
 
data/spec/shell_spec.rb CHANGED
@@ -35,24 +35,23 @@ describe EY::Serverside::Shell do
35
35
  tstp_1 = "+ 00s "
36
36
  tstp_2 = "+ 3m 05s "
37
37
  tstp_3 = "+10m 25s "
38
- notstp = " "
39
38
  output.rewind
40
39
  expect(output.read).to eq <<-OUTPUT
41
- #{notstp} debug
40
+ #{tstp_1} debug
42
41
 
43
42
  \e[1m\e[33m#{tstp_1} !> notice
44
43
  \e[0m
45
44
  \e[1m\e[37m#{tstp_2} ~> STATUS
46
- \e[0m#{notstp} multi
47
- #{notstp} line
48
- #{notstp} debug
45
+ \e[0m#{tstp_2} multi
46
+ #{tstp_2} line
47
+ #{tstp_2} debug
49
48
 
50
49
  \e[1m\e[33m#{tstp_2} !> WARNING: multi
51
50
  #{tstp_2} !> line
52
51
  #{tstp_2} !> warning
53
- \e[0m#{notstp} ~ multi
54
- #{notstp} ~ line
55
- #{notstp} ~ substatus
52
+ \e[0m#{tstp_3} ~ multi
53
+ #{tstp_3} ~ line
54
+ #{tstp_3} ~ substatus
56
55
  OUTPUT
57
56
  end
58
57
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: engineyard-serverside
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.5.0
4
+ version: 2.6.0
5
5
  prerelease:
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: 2014-09-23 00:00:00.000000000 Z
12
+ date: 2014-12-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -341,8 +341,9 @@ files:
341
341
  - spec/fixtures/repos/assets_enabled_all/config/ey.yml
342
342
  - spec/fixtures/repos/assets_enabled_all/Gemfile
343
343
  - spec/fixtures/repos/assets_enabled_all/Gemfile.lock
344
- - spec/fixtures/repos/assets_enabled_all/Rakefile
345
344
  - spec/fixtures/repos/assets_enabled_all/README
345
+ - spec/fixtures/repos/assets_enabled_all/script/assets
346
+ - spec/fixtures/repos/assets_enabled_all/tmp/obstruction
346
347
  - spec/fixtures/repos/assets_enabled_in_ey_yml/config/ey.yml
347
348
  - spec/fixtures/repos/assets_enabled_in_ey_yml/Gemfile
348
349
  - spec/fixtures/repos/assets_enabled_in_ey_yml/Gemfile.lock
@@ -451,6 +452,7 @@ files:
451
452
  - spec/multi_dependency_manager_spec.rb
452
453
  - spec/nodejs_deploy_spec.rb
453
454
  - spec/php_deploy_spec.rb
455
+ - spec/platform_configure_spec.rb
454
456
  - spec/rails31_deploy_spec.rb
455
457
  - spec/restart_spec.rb
456
458
  - spec/rollback_spec.rb
@@ -480,7 +482,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
480
482
  version: '0'
481
483
  segments:
482
484
  - 0
483
- hash: 1515425711168251653
485
+ hash: 696469692367855217
484
486
  required_rubygems_version: !ruby/object:Gem::Requirement
485
487
  none: false
486
488
  requirements:
@@ -553,8 +555,9 @@ test_files:
553
555
  - spec/fixtures/repos/assets_enabled_all/config/ey.yml
554
556
  - spec/fixtures/repos/assets_enabled_all/Gemfile
555
557
  - spec/fixtures/repos/assets_enabled_all/Gemfile.lock
556
- - spec/fixtures/repos/assets_enabled_all/Rakefile
557
558
  - spec/fixtures/repos/assets_enabled_all/README
559
+ - spec/fixtures/repos/assets_enabled_all/script/assets
560
+ - spec/fixtures/repos/assets_enabled_all/tmp/obstruction
558
561
  - spec/fixtures/repos/assets_enabled_in_ey_yml/config/ey.yml
559
562
  - spec/fixtures/repos/assets_enabled_in_ey_yml/Gemfile
560
563
  - spec/fixtures/repos/assets_enabled_in_ey_yml/Gemfile.lock
@@ -663,6 +666,7 @@ test_files:
663
666
  - spec/multi_dependency_manager_spec.rb
664
667
  - spec/nodejs_deploy_spec.rb
665
668
  - spec/php_deploy_spec.rb
669
+ - spec/platform_configure_spec.rb
666
670
  - spec/rails31_deploy_spec.rb
667
671
  - spec/restart_spec.rb
668
672
  - spec/rollback_spec.rb
@@ -1,6 +0,0 @@
1
- desc 'Precompile yar assetz'
2
- task 'assets:precompile' do
3
- sh "touch #{File.expand_path('../public/assets/compiled_asset', __FILE__)}"
4
- sh 'touch precompiled'
5
- end
6
-