engineyard-serverside 2.7.8pre2 → 2.8.0.pre

Sign up to get free protection for your applications and to get access to all the features.
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