engineyard-serverside 2.7.8pre2 → 2.8.0.pre

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.
Files changed (96) hide show
  1. data/bin/engineyard-serverside +1 -1
  2. data/bin/engineyard-serverside-execute-hook +1 -1
  3. data/bin/engineyard-serverside-execute-service-hook +35 -0
  4. data/lib/engineyard-serverside.rb +0 -1
  5. data/lib/engineyard-serverside/about.rb +11 -8
  6. data/lib/engineyard-serverside/callbacks.rb +11 -0
  7. data/lib/engineyard-serverside/callbacks/collection.rb +17 -0
  8. data/lib/engineyard-serverside/callbacks/collection/base.rb +79 -0
  9. data/lib/engineyard-serverside/callbacks/collection/combined.rb +45 -0
  10. data/lib/engineyard-serverside/callbacks/collection/deploy_hooks.rb +21 -0
  11. data/lib/engineyard-serverside/callbacks/collection/service_hooks.rb +17 -0
  12. data/lib/engineyard-serverside/callbacks/collection/service_hooks/collection.rb +24 -0
  13. data/lib/engineyard-serverside/callbacks/collection/service_hooks/combined.rb +40 -0
  14. data/lib/engineyard-serverside/callbacks/distributor.rb +21 -0
  15. data/lib/engineyard-serverside/callbacks/distributor/remote.rb +76 -0
  16. data/lib/engineyard-serverside/callbacks/distributor/viability_filter.rb +66 -0
  17. data/lib/engineyard-serverside/callbacks/executor.rb +23 -0
  18. data/lib/engineyard-serverside/callbacks/executor/base.rb +44 -0
  19. data/lib/engineyard-serverside/callbacks/executor/executable.rb +123 -0
  20. data/lib/engineyard-serverside/callbacks/executor/ruby.rb +20 -0
  21. data/lib/engineyard-serverside/callbacks/executor/ruby/context.rb +81 -0
  22. data/lib/engineyard-serverside/callbacks/executor/ruby/executor.rb +118 -0
  23. data/{spec/fixtures/gitrepo/bar → lib/engineyard-serverside/callbacks/hooks.rb} +0 -0
  24. data/lib/engineyard-serverside/callbacks/hooks/app.rb +21 -0
  25. data/lib/engineyard-serverside/callbacks/hooks/base.rb +43 -0
  26. data/lib/engineyard-serverside/callbacks/hooks/service.rb +28 -0
  27. data/lib/engineyard-serverside/callbacks/service_hook.rb +20 -0
  28. data/lib/engineyard-serverside/cli.rb +4 -225
  29. data/lib/engineyard-serverside/cli/app.rb +136 -0
  30. data/lib/engineyard-serverside/cli/helpers.rb +58 -0
  31. data/lib/engineyard-serverside/cli/server_hash_extractor.rb +49 -0
  32. data/lib/engineyard-serverside/cli/workflows.rb +45 -0
  33. data/lib/engineyard-serverside/cli/workflows/base.rb +78 -0
  34. data/lib/engineyard-serverside/cli/workflows/calling_deploy_hooks.rb +31 -0
  35. data/lib/engineyard-serverside/cli/workflows/deploying_applications.rb +28 -0
  36. data/lib/engineyard-serverside/cli/workflows/disabling_maintenance.rb +29 -0
  37. data/lib/engineyard-serverside/cli/workflows/enabling_maintenance.rb +29 -0
  38. data/lib/engineyard-serverside/cli/workflows/errors.rb +13 -0
  39. data/lib/engineyard-serverside/cli/workflows/helpers.rb +21 -0
  40. data/lib/engineyard-serverside/cli/workflows/integrating_servers.rb +71 -0
  41. data/lib/engineyard-serverside/cli/workflows/restarting_applications.rb +36 -0
  42. data/lib/engineyard-serverside/cli/workflows/rolling_back_applications.rb +28 -0
  43. data/lib/engineyard-serverside/cli/workflows/showing_maintenance_status.rb +28 -0
  44. data/lib/engineyard-serverside/configuration.rb +1 -0
  45. data/lib/engineyard-serverside/dependency_manager/bundler.rb +46 -18
  46. data/lib/engineyard-serverside/dependency_manager/npm.rb +12 -1
  47. data/lib/engineyard-serverside/deploy.rb +7 -45
  48. data/lib/engineyard-serverside/maintenance.rb +1 -9
  49. data/lib/engineyard-serverside/paths.rb +11 -0
  50. data/lib/engineyard-serverside/propagator.rb +59 -0
  51. data/lib/engineyard-serverside/rails_assets.rb +2 -1
  52. data/lib/engineyard-serverside/slug.rb +7 -0
  53. data/lib/engineyard-serverside/slug/distributor.rb +58 -0
  54. data/lib/engineyard-serverside/slug/enabler.rb +100 -0
  55. data/lib/engineyard-serverside/slug/failure_handler.rb +24 -0
  56. data/lib/engineyard-serverside/slug/finalizer.rb +86 -0
  57. data/lib/engineyard-serverside/slug/generator.rb +29 -0
  58. data/lib/engineyard-serverside/slug/migrator.rb +41 -0
  59. data/lib/engineyard-serverside/slug/restarter.rb +103 -0
  60. data/lib/engineyard-serverside/slug/source.rb +16 -0
  61. data/lib/engineyard-serverside/slug/source/updater.rb +194 -0
  62. data/lib/engineyard-serverside/version.rb +1 -1
  63. data/lib/railway.rb +43 -0
  64. data/lib/result.rb +7 -0
  65. data/lib/result/base.rb +41 -0
  66. data/lib/result/dsl.rb +16 -0
  67. data/lib/result/failure.rb +29 -0
  68. data/lib/result/success.rb +24 -0
  69. data/lib/runner.rb +34 -0
  70. data/spec/archive_deploy_spec.rb +1 -1
  71. data/spec/bundler_deploy_spec.rb +22 -1
  72. data/spec/configuration_spec.rb +1 -0
  73. data/spec/deploy_hook_spec.rb +148 -132
  74. data/spec/fixtures/lockfiles/1.15.1-no-bundler +51 -0
  75. data/spec/fixtures/repos/assets_error/Gemfile +5 -0
  76. data/spec/fixtures/repos/assets_error/Gemfile.lock +88 -0
  77. data/spec/fixtures/repos/assets_error/README +1 -0
  78. data/spec/fixtures/repos/assets_error/Rakefile +4 -0
  79. data/spec/fixtures/{gitrepo/foo → repos/assets_error/app/assets/empty} +0 -0
  80. data/spec/fixtures/repos/assets_error/config/application.rb +5 -0
  81. data/spec/fixtures/repos/assets_error/config/ey.yml +4 -0
  82. data/spec/fixtures/repos/bundler_old/Gemfile +5 -0
  83. data/spec/fixtures/repos/bundler_old/Gemfile.lock +15 -0
  84. data/spec/fixtures/repos/bundler_old/README +1 -0
  85. data/spec/fixtures/repos/no_ey_config_no_warning/Gemfile +3 -0
  86. data/spec/fixtures/repos/no_ey_config_no_warning/Gemfile.lock +10 -0
  87. data/spec/fixtures/repos/no_ey_config_no_warning/README +1 -0
  88. data/spec/fixtures/repos/no_ey_config_no_warning/ey.yml +5 -0
  89. data/spec/lockfile_parser_spec.rb +5 -1
  90. data/spec/rails31_deploy_spec.rb +8 -0
  91. data/spec/rollback_spec.rb +1 -1
  92. data/spec/services_deploy_spec.rb +12 -0
  93. data/spec/spec_helper.rb +14 -8
  94. metadata +488 -429
  95. data/lib/engineyard-serverside/cli_helpers.rb +0 -53
  96. data/lib/engineyard-serverside/deploy_hook.rb +0 -142
@@ -0,0 +1,16 @@
1
+ require 'engineyard-serverside/slug/source/updater'
2
+
3
+ module EY
4
+ module Serverside
5
+ module Slug
6
+ module Source
7
+
8
+ def self.update(data = {})
9
+ Updater.new(data).update
10
+ end
11
+
12
+
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,194 @@
1
+ require 'railway'
2
+ require 'runner'
3
+
4
+ module EY
5
+ module Serverside
6
+ module Slug
7
+ module Source
8
+
9
+ class Updater
10
+ include Railway
11
+ include Runner
12
+
13
+ step :create_source_cache
14
+ step :ensure_ssh_wrapper
15
+ step :determine_if_clone_needed
16
+ step :clone_if_necessary
17
+ step :prune_source_cache
18
+ step :fetch_updates
19
+ step :clean_local_branch
20
+ step :calculate_requested_revision
21
+ step :checkout_requested_revision
22
+ step :sync_submodules
23
+ step :update_submodules
24
+ step :clean_source_cache
25
+
26
+ attr_reader :source_cache, :uri, :git, :quiet, :ref, :config
27
+
28
+ def initialize(input = {})
29
+ @input = input
30
+ @config = input[:config]
31
+ source = input[:config].source
32
+ @source_cache = source.source_cache
33
+ @uri = source.uri
34
+ @quiet = source.opts[:verbose] ? '' : '--quiet'
35
+ @ref = source.ref
36
+ @git = "#{wrapped_git} --git-dir #{source_cache}/.git --work-tree #{source_cache}"
37
+ end
38
+
39
+ def update
40
+ call(@input)
41
+ end
42
+
43
+ private
44
+
45
+ def wrapped_git
46
+ "GIT_SSH=#{paths.ssh_wrapper} git"
47
+ end
48
+
49
+ def create_source_cache(input = {})
50
+ begin
51
+ source_cache.mkpath
52
+ rescue
53
+ return Failure(:error => "Could not create #{source_cache}")
54
+ end
55
+
56
+ Success(input)
57
+ end
58
+
59
+ def ensure_ssh_wrapper(input = {})
60
+ wrapper_location = paths.ssh_wrapper
61
+
62
+ return Success(input) if File.executable?(wrapper_location)
63
+
64
+ begin
65
+ wrapper = File.open(wrapper_location, 'w', 0700)
66
+ wrapper.write <<-WRAPPER
67
+ #!/bin/sh
68
+
69
+ unset SSH_AUTH_SOCK
70
+
71
+ command=$(wcho "$*" | sed -e 's/^-batch //')
72
+
73
+ ssh -o CheckHostIP=no -o StrictHostKeyChecking=no -o PasswordAuthentication=no -o LogLevel=INFO -o IdentityFile=#{paths.deploy_key} -o IdentitiesOnly=yes ${command}
74
+ WRAPPER
75
+ wrapper.close
76
+ rescue => e
77
+ return Failure(input.merge(:error => e))
78
+ end
79
+
80
+ Success(input)
81
+ end
82
+
83
+ def determine_if_clone_needed(input = {})
84
+
85
+ check =
86
+ source_cache.directory? &&
87
+ run_and_output("#{git} remote -v | grep original").include?(uri)
88
+
89
+ Success(input.merge(:clone_needed => !check))
90
+ end
91
+
92
+ def clone_if_necessary(input = {})
93
+ if input[:clone_needed]
94
+ unless run_and_success?("rm -rf #{source_cache} && git clone #{quiet} #{uri} #{source_cache} 2>&1")
95
+
96
+ return Failure(
97
+ input.merge(:error => "Could not clone #{uri} to #{source_cache}")
98
+ )
99
+ end
100
+ end
101
+
102
+ Success(input)
103
+ end
104
+
105
+ def prune_source_cache(input = {})
106
+ return Failure(
107
+ input.merge(:error => "Could not prune #{source_cache}")
108
+ ) unless run_and_success?("#{git} remote prune origin 2>&1")
109
+
110
+ Success(input)
111
+ end
112
+
113
+ def fetch_updates(input = {})
114
+ return Failure(
115
+ input.merge(:error => "Could not fetch #{source_cache}")
116
+ ) unless run_and_success?("#{git} fetch --force --prune --update-head-ok #{quiet} origin '+refs/heads/*:refs/remotes/origin/*' '+refs/tags/*:refs/tags/*' 2>&1")
117
+
118
+ Success(input)
119
+ end
120
+
121
+ def clean_local_branch(input = {})
122
+ run_and_success?("#{git} show-branch #{ref} > /dev/null 2>&1 && #{git} branch -D #{ref} > /dev/null 2>&1")
123
+
124
+ Success(input)
125
+ end
126
+
127
+ def calculate_requested_revision(input = {})
128
+ remote_branch = Dir.chdir(source_cache) do
129
+ run_and_success?("#{git} show-branch origin/#{ref} > /dev/null 2>&1")
130
+ end
131
+
132
+ Success(
133
+ input.merge(
134
+ :requested_branch => remote_branch ? "origin/#{ref}" : ref
135
+ )
136
+ )
137
+ end
138
+
139
+ def checkout_requested_revision(input = {})
140
+ requested_branch = input[:requested_branch]
141
+
142
+ Dir.chdir(source_cache) {
143
+ run_and_success?(
144
+ "git checkout --force #{quiet} '#{requested_branch}'"
145
+ ) || run_and_success?(
146
+ "git reset --hard #{quiet} '#{requested_branch}'"
147
+ )
148
+ } ?
149
+ Success(input) :
150
+ Failure(
151
+ input.merge(:error => "Could not check out #{requested_branch}")
152
+ )
153
+ end
154
+
155
+ def sync_submodules(input = {})
156
+ return Failure(
157
+ input.merge(:error => "Could not sync submodules")
158
+ ) unless Dir.chdir(source_cache) {
159
+ run_and_success?("#{wrapped_git} submodule sync")
160
+ }
161
+
162
+ Success(input)
163
+ end
164
+
165
+ def update_submodules(input = {})
166
+ return Failure(
167
+ input.merge(:error => "Could not update submodules")
168
+ ) unless Dir.chdir(source_cache) {
169
+ run_and_success?("#{wrapped_git} submodule update --init --recursive")
170
+ }
171
+
172
+ Success(input)
173
+ end
174
+
175
+ def clean_source_cache(input = {})
176
+ return Failure(
177
+ input.merge(:error => "Could not clean source")
178
+ ) unless Dir.chdir(source_cache) {
179
+ run_and_success?('git clean -dfq')
180
+ }
181
+
182
+ Success(input)
183
+ end
184
+
185
+ def paths
186
+ config.paths
187
+ end
188
+
189
+ end
190
+
191
+ end
192
+ end
193
+ end
194
+ end
@@ -1,5 +1,5 @@
1
1
  module EY
2
2
  module Serverside
3
- VERSION = '2.7.8pre2'
3
+ VERSION = '2.8.0.pre'
4
4
  end
5
5
  end
@@ -0,0 +1,43 @@
1
+ require 'result'
2
+
3
+ module Railway
4
+ include Result::DSL
5
+
6
+ module DSL
7
+ def step(name, options = {})
8
+ with = options.delete(:with)
9
+ steps.push(:name => name, :with => with)
10
+ end
11
+
12
+ def steps
13
+ @steps ||= []
14
+ end
15
+ end
16
+
17
+ def self.included(base)
18
+ base.send :extend, DSL
19
+ end
20
+
21
+ def call(input = {})
22
+ steps = self.class.steps
23
+
24
+ return Failure('No steps') if steps.empty?
25
+
26
+ steps.
27
+ inject(Success(input)) {|result, step|
28
+ result.and_then {|data|
29
+ dispatch_step(step, data)
30
+ }
31
+ }
32
+ end
33
+
34
+ private
35
+ def dispatch_step(step, data)
36
+ begin
37
+ result = (step[:with] || self).send(step[:name], data)
38
+ result.is_a?(Result::Base) ? result : Success(result)
39
+ rescue => error
40
+ Failure(error)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,7 @@
1
+ require 'result/dsl'
2
+ require 'result/success'
3
+ require 'result/failure'
4
+
5
+ module Result
6
+ extend DSL
7
+ end
@@ -0,0 +1,41 @@
1
+ module Result
2
+
3
+ class Base
4
+ def initialize(to_wrap)
5
+ @wrapped = to_wrap
6
+ end
7
+
8
+ def success?
9
+ false
10
+ end
11
+
12
+ def failure?
13
+ false
14
+ end
15
+
16
+ def value
17
+ raise "not present"
18
+ end
19
+
20
+ def error
21
+ raise "not present"
22
+ end
23
+
24
+ def and_then
25
+ self
26
+ end
27
+
28
+ def or_else
29
+ self
30
+ end
31
+
32
+ def on_success
33
+ self
34
+ end
35
+
36
+ def on_failure
37
+ self
38
+ end
39
+ end
40
+
41
+ end
@@ -0,0 +1,16 @@
1
+ require 'result/success'
2
+ require 'result/failure'
3
+
4
+ module Result
5
+
6
+ module DSL
7
+ def Success(value)
8
+ Success.new(value)
9
+ end
10
+
11
+ def Failure(error)
12
+ Failure.new(error)
13
+ end
14
+ end
15
+
16
+ end
@@ -0,0 +1,29 @@
1
+ require 'result/base'
2
+
3
+ module Result
4
+
5
+ class Failure < Base
6
+ def initialize(to_wrap)
7
+ super
8
+ freeze
9
+ end
10
+
11
+ def error
12
+ @wrapped
13
+ end
14
+
15
+ def failure?
16
+ true
17
+ end
18
+
19
+ def or_else
20
+ yield error
21
+ end
22
+
23
+ def on_failure
24
+ yield error
25
+ super
26
+ end
27
+ end
28
+
29
+ end
@@ -0,0 +1,24 @@
1
+ require 'result/base'
2
+
3
+ module Result
4
+
5
+ class Success < Base
6
+ def value
7
+ @wrapped
8
+ end
9
+
10
+ def success?
11
+ true
12
+ end
13
+
14
+ def and_then
15
+ yield value
16
+ end
17
+
18
+ def on_success
19
+ yield value
20
+ super
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,34 @@
1
+ require 'engineyard-serverside/spawner'
2
+
3
+ module Runner
4
+ def runner
5
+ EY::Serverside::Spawner
6
+ end
7
+
8
+ # Internal: Run a command.
9
+ #
10
+ # cmd - A string command.
11
+ #
12
+ # Returns an instance of Spawner.
13
+ def run(cmd)
14
+ runner.run(cmd, shell, nil)
15
+ end
16
+
17
+ # Internal: Run a command and return the output.
18
+ #
19
+ # cmd - A string command.
20
+ #
21
+ # Returns the output of the command.
22
+ def run_and_output(cmd)
23
+ run(cmd).output
24
+ end
25
+
26
+ # Internal: Run a command and check if it was successful.
27
+ #
28
+ # cmd - A string command.
29
+ #
30
+ # Returns success.
31
+ def run_and_success?(cmd)
32
+ run(cmd).success?
33
+ end
34
+ end
@@ -27,7 +27,7 @@ describe "Deploying a simple application" do
27
27
  argv = adapter.deploy.commands.last.to_argv[2..-1]
28
28
  with_mocked_commands do
29
29
  capture do
30
- EY::Serverside::CLI.start(argv)
30
+ EY::Serverside::CLI::App.start(argv)
31
31
  end
32
32
  end
33
33
  end
@@ -2,6 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe "Deploying an application that uses Bundler" do
4
4
  VERSION_PATTERN = Regexp.quote(::EY::Serverside::DependencyManager::Bundler.default_version)
5
+ PARALLEL_JOBS = ::EY::Serverside::DependencyManager::Bundler.jobs_number
5
6
 
6
7
  context "with a Gemfile.lock" do
7
8
  before(:all) do
@@ -20,6 +21,11 @@ describe "Deploying an application that uses Bundler" do
20
21
  expect(@bundle_install_command).to include('--deployment')
21
22
  end
22
23
 
24
+ it "runs 'bundle install' with --jobs #{PARALLEL_JOBS}" do
25
+ expect(@bundle_install_command).not_to be_nil
26
+ expect(@bundle_install_command).to include("--jobs #{PARALLEL_JOBS}")
27
+ end
28
+
23
29
  it "removes bundled_gems directory if the ruby or system version changed" do
24
30
  should_run_clear_bundle_cmd = @deployer.commands.grep(/diff/).first
25
31
  expect(should_run_clear_bundle_cmd).not_to be_nil
@@ -92,6 +98,11 @@ describe "Deploying an application that uses Bundler" do
92
98
  expect(@bundle_install_command).not_to match(/--deployment/)
93
99
  end
94
100
 
101
+ it "runs 'bundle install' with --jobs #{PARALLEL_JOBS}" do
102
+ expect(@bundle_install_command).not_to be_nil
103
+ expect(@bundle_install_command).to include("--jobs #{PARALLEL_JOBS}")
104
+ end
105
+
95
106
  it "exports GIT_SSH for the bundle install" do
96
107
  expect(@bundle_install_command).to match(/export GIT_SSH/)
97
108
  end
@@ -135,5 +146,15 @@ describe "Deploying an application that uses Bundler" do
135
146
  expect(deploy_dir.join('current', 'after_bundle.ran' )).not_to exist
136
147
  end
137
148
  end
138
- end
139
149
 
150
+ context "with outdated bundler" do
151
+ before :all do
152
+ deploy_test_application( "bundler_old" )
153
+ @bundle_install_command = @deployer.commands.grep( /bundle _1.3.6_ install/ ).first
154
+ end
155
+
156
+ it "doesn't run 'bundle install' with --jobs" do
157
+ expect( @bundle_install_command ).to_not include "--jobs"
158
+ end
159
+ end
160
+ end