engineyard-serverside 2.2.1 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/lib/engineyard-serverside.rb +2 -1
- data/lib/engineyard-serverside/cli.rb +11 -0
- data/lib/engineyard-serverside/configuration.rb +47 -4
- data/lib/engineyard-serverside/deploy.rb +28 -17
- data/lib/engineyard-serverside/deprecation.rb +10 -7
- data/lib/engineyard-serverside/rails_assets.rb +1 -1
- data/lib/engineyard-serverside/source.rb +73 -0
- data/lib/engineyard-serverside/source/archive.rb +58 -0
- data/lib/engineyard-serverside/source/git.rb +104 -0
- data/lib/engineyard-serverside/source_strategy.rb +77 -0
- data/lib/engineyard-serverside/version.rb +1 -1
- data/spec/archive_deploy_spec.rb +59 -0
- data/spec/configuration_spec.rb +37 -1
- data/spec/fixtures/retwisj.war +0 -0
- data/spec/git_strategy_spec.rb +24 -19
- data/spec/rollback_spec.rb +32 -0
- data/spec/source/archive_spec.rb +34 -0
- data/spec/source/git_spec.rb +44 -0
- data/spec/spec_helper.rb +6 -10
- data/spec/support/integration.rb +8 -14
- data/spec/support/source_doubles.rb +28 -0
- metadata +18 -5
- data/lib/engineyard-serverside/strategies/git.rb +0 -104
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ZTMyNDZmY2M5YmMyN2RjN2I3OWM1MGRlNjlhN2NjY2FkODExYjVmMg==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
M2ZmMWQ0Y2E5MDE5NTkzNjQ0ODFmYTJkZGJlYjlhMDc0NDMyMWQxYg==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MzA1YWVmMDUxMjhjNjdkNzhhN2FhOWU3NTJmZjYzNTJmNjk0MDUxYmJiYTY4
|
10
|
+
ZWQ0YTg0OGEyYTg5M2Y5MmRkMmM1YzIwNzhhZmY5NjhiYTMwY2RkMWFhMWFk
|
11
|
+
MmIzNmY3ZjU1YjQxNzU4NTE4MDg4YzUzMGQxYjY5MDk2MDAyYTM=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
YzQyZTQzZGEyNGQ0MmU2MWZkOTJmNTdjNzM0MmJhOWYxZjllMGE1NWE3OWRi
|
14
|
+
ZTFiNDMxZDJlNTJhZjU2OTdiNjU4MzIxOTIyNDYwZjNjMzVjODc4NzQzNDBh
|
15
|
+
YmExMzE0NzA0N2QxMDNjMDE3Yjk1NDc1NzI3ZWI0MTNjZjJhNTU=
|
@@ -19,10 +19,11 @@ $LOAD_PATH.unshift File.expand_path('vendor/multi_json/lib', File.dirname(__FILE
|
|
19
19
|
|
20
20
|
require 'escape'
|
21
21
|
require 'multi_json'
|
22
|
+
require 'uri'
|
22
23
|
|
23
24
|
require 'engineyard-serverside/version'
|
24
25
|
require 'engineyard-serverside/about'
|
25
|
-
|
26
|
+
|
26
27
|
require 'engineyard-serverside/task'
|
27
28
|
require 'engineyard-serverside/server'
|
28
29
|
require 'engineyard-serverside/deploy'
|
@@ -23,6 +23,17 @@ module EY
|
|
23
23
|
method_option :repo, :type => :string,
|
24
24
|
:desc => "Remote repo to deploy",
|
25
25
|
:aliases => ["-r"]
|
26
|
+
|
27
|
+
|
28
|
+
# Archive source strategy
|
29
|
+
method_option :archive, :type => :string,
|
30
|
+
:desc => "Remote URI for archive to download and unzip"
|
31
|
+
|
32
|
+
# Git source strategy
|
33
|
+
method_option :git, :type => :string,
|
34
|
+
:desc => "Remote git repo to deploy"
|
35
|
+
|
36
|
+
|
26
37
|
account_app_env_options
|
27
38
|
config_option
|
28
39
|
framework_env_option
|
@@ -3,6 +3,9 @@ require 'thor'
|
|
3
3
|
require 'pp'
|
4
4
|
require 'yaml'
|
5
5
|
require 'engineyard-serverside/paths'
|
6
|
+
require 'engineyard-serverside/source'
|
7
|
+
require 'engineyard-serverside/source/git'
|
8
|
+
require 'engineyard-serverside/source/archive'
|
6
9
|
|
7
10
|
module EY
|
8
11
|
module Serverside
|
@@ -47,6 +50,19 @@ module EY
|
|
47
50
|
end
|
48
51
|
end
|
49
52
|
|
53
|
+
def fetch_deprecated(attr, replacement, default)
|
54
|
+
called = false
|
55
|
+
result = fetch(attr) { called = true; default }
|
56
|
+
if !called # deprecated attr was found
|
57
|
+
@deprecation_warning ||= {}
|
58
|
+
@deprecation_warning[attr] ||= begin
|
59
|
+
EY::Serverside.deprecation_warning "The configuration key '#{attr}' is deprecated in favor of '#{replacement}'."
|
60
|
+
true
|
61
|
+
end
|
62
|
+
end
|
63
|
+
result
|
64
|
+
end
|
65
|
+
|
50
66
|
def_required_option :app
|
51
67
|
def_required_option :environment_name
|
52
68
|
def_required_option :account_name
|
@@ -55,14 +71,15 @@ module EY
|
|
55
71
|
def_required_option :instance_roles
|
56
72
|
def_required_option :instance_names
|
57
73
|
|
58
|
-
def_option :repo,
|
74
|
+
def_option(:git) { fetch(:repo, nil) } # repo is deprecated
|
75
|
+
def_option :archive, nil
|
59
76
|
def_option :migrate, nil
|
60
77
|
def_option :precompile_assets, 'detect'
|
61
78
|
def_option :precompile_assets_task, 'assets:precompile'
|
62
79
|
def_option :asset_strategy, 'shifting'
|
63
80
|
def_option :asset_dependencies, %w[app/assets lib/assets vendor/assets Gemfile.lock config/routes.rb config/application.rb]
|
64
81
|
def_option :stack, nil
|
65
|
-
def_option :strategy,
|
82
|
+
def_option(:source_class) { fetch_deprecated(:strategy, :source_class, nil) } # strategy is deprecated
|
66
83
|
def_option :branch, 'master'
|
67
84
|
def_option :current_roles, []
|
68
85
|
def_option :current_name, nil
|
@@ -85,6 +102,7 @@ module EY
|
|
85
102
|
alias app_name app
|
86
103
|
alias environment framework_env # legacy because it would be nice to have less confusion around "environment"
|
87
104
|
alias migration_command migrate
|
105
|
+
alias repo git
|
88
106
|
|
89
107
|
def initialize(options)
|
90
108
|
opts = string_keys(options)
|
@@ -180,8 +198,33 @@ module EY
|
|
180
198
|
EY::Serverside.node
|
181
199
|
end
|
182
200
|
|
183
|
-
|
184
|
-
|
201
|
+
# Infer the deploy source strategy to use based on flag or
|
202
|
+
# default to specified strategy.
|
203
|
+
#
|
204
|
+
# Returns a Source object.
|
205
|
+
def source(shell)
|
206
|
+
if archive && git
|
207
|
+
shell.fatal "Both --git and --archive specified. Precedence is not defined. Aborting"
|
208
|
+
raise "Both --git and --archive specified. Precedence is not defined. Aborting"
|
209
|
+
end
|
210
|
+
if archive
|
211
|
+
load_source(EY::Serverside::Source::Archive, shell, archive)
|
212
|
+
elsif source_class
|
213
|
+
load_source(EY::Serverside::Source.const_get(source_class), shell, git)
|
214
|
+
else # git can be nil for integrate or rollback
|
215
|
+
load_source(EY::Serverside::Source::Git, shell, git)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def load_source(klass, shell, uri)
|
220
|
+
klass.new(
|
221
|
+
shell,
|
222
|
+
:verbose => verbose,
|
223
|
+
:repository_cache => paths.repository_cache,
|
224
|
+
:app => app,
|
225
|
+
:uri => uri,
|
226
|
+
:ref => branch
|
227
|
+
)
|
185
228
|
end
|
186
229
|
|
187
230
|
def paths
|
@@ -58,19 +58,23 @@ module EY
|
|
58
58
|
end
|
59
59
|
|
60
60
|
def update_repository_cache
|
61
|
-
|
61
|
+
source.update_repository_cache
|
62
62
|
end
|
63
63
|
|
64
64
|
def gc_repository_cache
|
65
|
-
|
65
|
+
source.gc_repository_cache
|
66
66
|
end
|
67
67
|
|
68
68
|
def create_revision_file_command
|
69
|
-
|
69
|
+
source.create_revision_file_command(paths.active_revision)
|
70
70
|
end
|
71
71
|
|
72
72
|
def short_log_message(revision)
|
73
|
-
|
73
|
+
source.short_log_message(revision)
|
74
|
+
end
|
75
|
+
|
76
|
+
def unchanged_diff_between_revisions?(previous_revision, active_revision, asset_dependencies)
|
77
|
+
source.same?(previous_revision, active_revision, asset_dependencies)
|
74
78
|
end
|
75
79
|
|
76
80
|
def check_repository
|
@@ -186,12 +190,27 @@ chmod 0700 #{path}
|
|
186
190
|
@cleanup_failed = false
|
187
191
|
end
|
188
192
|
|
193
|
+
def abort_on_bad_paths_in_release_directory
|
194
|
+
shell.substatus "Checking for disruptive files in #{paths.releases}"
|
195
|
+
|
196
|
+
bad_paths = paths.all_releases.reject do |path|
|
197
|
+
path.basename.to_s =~ /^[\d]+$/
|
198
|
+
end
|
199
|
+
|
200
|
+
if bad_paths.any?
|
201
|
+
shell.fatal "Bad paths found in #{paths.releases}:\n\t#{bad_paths.join("\n\t")}\nStoring files in this directory will disrupt latest_release, diff detection, rollback, and possibly other features."
|
202
|
+
raise
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
|
189
207
|
# task
|
190
208
|
def rollback
|
191
209
|
if config.rollback_paths!
|
192
210
|
begin
|
193
211
|
rolled_back_release = paths.latest_release
|
194
212
|
shell.status "Rolling back to previous release: #{short_log_message(config.active_revision)}"
|
213
|
+
abort_on_bad_paths_in_release_directory
|
195
214
|
run_with_callbacks(:symlink)
|
196
215
|
sudo "rm -rf #{rolled_back_release}"
|
197
216
|
bundle
|
@@ -362,25 +381,17 @@ YML
|
|
362
381
|
end
|
363
382
|
end
|
364
383
|
|
365
|
-
protected
|
366
|
-
|
367
384
|
# Use [] to access attributes instead of calling methods so
|
368
385
|
# that we get nils instead of NoMethodError.
|
369
386
|
#
|
370
387
|
# Rollback doesn't know about the repository location (nor
|
371
388
|
# should it need to), but it would like to use #short_log_message.
|
372
|
-
def
|
389
|
+
def source
|
373
390
|
ensure_git_ssh_wrapper
|
374
|
-
@
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
:app => config.app,
|
379
|
-
:repo => config[:repo],
|
380
|
-
:ref => config[:branch]
|
381
|
-
)
|
382
|
-
end
|
383
|
-
public :strategy
|
391
|
+
@source ||= config.source(shell)
|
392
|
+
end
|
393
|
+
|
394
|
+
protected
|
384
395
|
|
385
396
|
def base_callback_command_for(what)
|
386
397
|
cmd = [About.binary, 'hook', what.to_s]
|
@@ -1,4 +1,6 @@
|
|
1
1
|
require 'engineyard-serverside/shell/helpers'
|
2
|
+
require 'engineyard-serverside/dependency_manager/bundler'
|
3
|
+
require 'engineyard-serverside/source/git'
|
2
4
|
|
3
5
|
module EY
|
4
6
|
module Serverside
|
@@ -12,14 +14,15 @@ module EY
|
|
12
14
|
end
|
13
15
|
end
|
14
16
|
|
17
|
+
DEPRECATED_CLASSES = {
|
18
|
+
:LoggedOutput => EY::Serverside::Shell::Helpers,
|
19
|
+
:LockfileParser => EY::Serverside::DependencyManager::Bundler::Lockfile,
|
20
|
+
:Strategies => EY::Serverside::Source::Git
|
21
|
+
}
|
15
22
|
def self.const_missing(const)
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
EY::Serverside::Shell::Helpers
|
20
|
-
when :LockfileParser
|
21
|
-
EY::Serverside.deprecation_warning("EY::Serverside::LockfileParser has been deprecated. Use EY::Serverside::DependencyManager::Bundler::Lockfile instead.")
|
22
|
-
EY::Serverside::DependencyManager::Bundler::Lockfile
|
23
|
+
if klass = DEPRECATED_CLASSES[const]
|
24
|
+
deprecation_warning("EY::Serverside::#{const} has been deprecated. Please use: #{klass}")
|
25
|
+
klass
|
23
26
|
else
|
24
27
|
super
|
25
28
|
end
|
@@ -75,7 +75,7 @@ module EY
|
|
75
75
|
asset_strategy.reusable? &&
|
76
76
|
previous_revision &&
|
77
77
|
active_revision &&
|
78
|
-
runner.
|
78
|
+
runner.unchanged_diff_between_revisions?(previous_revision, active_revision, asset_dependencies)
|
79
79
|
end
|
80
80
|
|
81
81
|
def precompile_detected_assets
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'engineyard-serverside/spawner'
|
3
|
+
|
4
|
+
class EY::Serverside::Source
|
5
|
+
attr_reader :uri, :opts, :source_cache, :ref, :shell
|
6
|
+
alias repository_cache source_cache
|
7
|
+
|
8
|
+
class << self
|
9
|
+
attr_reader :required_opts
|
10
|
+
def require_opts(*names)
|
11
|
+
@required_opts ||= []
|
12
|
+
@required_opts += names
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(shell, opts={})
|
17
|
+
@shell = shell
|
18
|
+
@opts = opts
|
19
|
+
|
20
|
+
missing = self.class.required_opts && self.class.required_opts.reject {|name| @opts[name] }
|
21
|
+
if missing and missing.any?
|
22
|
+
raise ArgumentError,
|
23
|
+
"Internal error: Missing keys #{missing.join(',')}. Required: #{self.class.required_opts.join(', ')}"
|
24
|
+
end
|
25
|
+
|
26
|
+
@ref = @opts[:ref]
|
27
|
+
@uri = @opts[:uri].to_s if @opts[:uri]
|
28
|
+
@source_cache = Pathname.new(@opts[:repository_cache]) if @opts[:repository_cache]
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
|
33
|
+
def in_source_cache(&block)
|
34
|
+
raise ArgumentError, "Block required" unless block
|
35
|
+
source_cache.mkpath
|
36
|
+
Dir.chdir(source_cache, &block)
|
37
|
+
end
|
38
|
+
|
39
|
+
def escape(*shell_commands)
|
40
|
+
Escape.shell_command(shell_commands)
|
41
|
+
end
|
42
|
+
|
43
|
+
def runner
|
44
|
+
EY::Serverside::Spawner
|
45
|
+
end
|
46
|
+
|
47
|
+
# Internal: Run a command.
|
48
|
+
#
|
49
|
+
# cmd - A string command.
|
50
|
+
#
|
51
|
+
# Returns an instance of Spawner.
|
52
|
+
def run(cmd)
|
53
|
+
runner.run(cmd, shell, nil)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Internal: Run a command and return the output.
|
57
|
+
#
|
58
|
+
# cmd - A string command.
|
59
|
+
#
|
60
|
+
# Returns the output of the command.
|
61
|
+
def run_and_output(cmd)
|
62
|
+
run(cmd).output
|
63
|
+
end
|
64
|
+
|
65
|
+
# Internal: Run a command and check if it was successful.
|
66
|
+
#
|
67
|
+
# cmd - A string command.
|
68
|
+
#
|
69
|
+
# Returns success.
|
70
|
+
def run_and_success?(cmd)
|
71
|
+
run(cmd).success?
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'engineyard-serverside/source'
|
2
|
+
|
3
|
+
# Deploy source for archive sourced deploy.
|
4
|
+
class EY::Serverside::Source::Archive < EY::Serverside::Source
|
5
|
+
require_opts :uri, :repository_cache
|
6
|
+
|
7
|
+
def create_revision_file_command(revision_file_path)
|
8
|
+
"echo #{escape(@checksum || filename)} > #{escape(revision_file_path.to_s)}"
|
9
|
+
end
|
10
|
+
|
11
|
+
def gc_repository_cache
|
12
|
+
# If files are uploaded to the server, we should clean them up here probably.
|
13
|
+
end
|
14
|
+
|
15
|
+
def same?(previous_rev, current_rev, paths=nil)
|
16
|
+
previous_rev == current_rev
|
17
|
+
end
|
18
|
+
|
19
|
+
def short_log_message(rev)
|
20
|
+
rev
|
21
|
+
end
|
22
|
+
|
23
|
+
def update_repository_cache
|
24
|
+
clean_cache
|
25
|
+
in_source_cache do
|
26
|
+
fetch && checksum && unarchive
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
protected
|
31
|
+
|
32
|
+
def checksum
|
33
|
+
@checksum = run_and_output("shasum #{escape(File.join(source_cache, filename))}").strip
|
34
|
+
end
|
35
|
+
|
36
|
+
def clean_cache
|
37
|
+
run "rm -rf #{source_cache} && mkdir -p #{source_cache}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def fetch_command
|
41
|
+
"curl --location --silent --show-error -O --user-agent #{escape("EngineYardDeploy/#{EY::Serverside::VERSION}")} #{escape(uri)}"
|
42
|
+
end
|
43
|
+
|
44
|
+
def fetch
|
45
|
+
run_and_success?(fetch_command)
|
46
|
+
end
|
47
|
+
|
48
|
+
def filename
|
49
|
+
@filename ||= File.basename(URI.parse(uri).path)
|
50
|
+
end
|
51
|
+
|
52
|
+
def unarchive
|
53
|
+
case File.extname(filename)
|
54
|
+
when '.zip', '.war'
|
55
|
+
run "unzip #{filename} && rm #{filename}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'engineyard-serverside/source'
|
2
|
+
|
3
|
+
# Deploy source for git repository sourced deploy.
|
4
|
+
class EY::Serverside::Source::Git < EY::Serverside::Source
|
5
|
+
require_opts :uri, :ref, :repository_cache
|
6
|
+
|
7
|
+
def create_revision_file_command(revision_file_path)
|
8
|
+
%Q{#{git} show --pretty=format:"%H" | head -1 > "#{revision_file_path}"}
|
9
|
+
end
|
10
|
+
|
11
|
+
def gc_repository_cache
|
12
|
+
shell.status "Garbage collecting cached git repository to reduce disk usage."
|
13
|
+
run("#{git} gc")
|
14
|
+
end
|
15
|
+
|
16
|
+
# Check if there have been changes.
|
17
|
+
# git diff --exit-code returns
|
18
|
+
# - 0 when nothing has changed
|
19
|
+
# - 1 when there are changes
|
20
|
+
#
|
21
|
+
# previous_revision - The previous ref string.
|
22
|
+
# active_revision - The current ref string.
|
23
|
+
#
|
24
|
+
#
|
25
|
+
# Returns a boolean whether there has been a change.
|
26
|
+
def same?(previous_revision, active_revision, paths=nil)
|
27
|
+
run_and_success?("#{git} diff '#{previous_revision}'..'#{active_revision}' --exit-code --name-only -- #{Array(paths).join(' ')} >/dev/null 2>&1")
|
28
|
+
end
|
29
|
+
|
30
|
+
# Get most recent commit message for revision.
|
31
|
+
def short_log_message(revision)
|
32
|
+
run_and_output("#{git} log --pretty=oneline --abbrev-commit -n 1 '#{revision}'").strip
|
33
|
+
end
|
34
|
+
|
35
|
+
def update_repository_cache
|
36
|
+
unless fetch && checkout
|
37
|
+
shell.fatal "git checkout #{to_checkout} failed."
|
38
|
+
raise "git checkout #{to_checkout} failed."
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
protected
|
43
|
+
|
44
|
+
# Internal:
|
45
|
+
# Returns .
|
46
|
+
def checkout
|
47
|
+
shell.status "Deploying revision #{short_log_message(to_checkout)}"
|
48
|
+
q = opts[:verbose] ? '' : '-q'
|
49
|
+
in_source_cache do
|
50
|
+
(run_and_success?("git checkout -f #{q} '#{to_checkout}'") ||
|
51
|
+
run_and_success?("git reset --hard #{q} '#{to_checkout}'")) &&
|
52
|
+
run_and_success?("git submodule sync") &&
|
53
|
+
run_and_success?("git submodule update --init") &&
|
54
|
+
run_and_success?("git clean -dfq")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Internal:
|
59
|
+
#
|
60
|
+
# Returns .
|
61
|
+
def clean_local_branch
|
62
|
+
run_and_success?("#{git} show-branch #{ref} > /dev/null 2>&1 && #{git} branch -D #{ref} > /dev/null 2>&1")
|
63
|
+
end
|
64
|
+
|
65
|
+
# Internal:
|
66
|
+
def fetch
|
67
|
+
run_and_success?(fetch_command)
|
68
|
+
end
|
69
|
+
|
70
|
+
def fetch_command
|
71
|
+
if usable_repository?
|
72
|
+
"#{git} fetch -q origin 2>&1"
|
73
|
+
else
|
74
|
+
"rm -rf #{repository_cache} && git clone -q #{uri} #{repository_cache} 2>&1"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def git
|
79
|
+
@git ||= "git --git-dir #{repository_cache}/.git --work-tree #{repository_cache}"
|
80
|
+
end
|
81
|
+
|
82
|
+
# Internal: Check for valid git repository.
|
83
|
+
#
|
84
|
+
# Returns a boolean.
|
85
|
+
def usable_repository?
|
86
|
+
repository_cache.directory? &&
|
87
|
+
run_and_output("#{git} remote -v | grep origin").include?(uri)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Internal: .
|
91
|
+
#
|
92
|
+
# Returns .
|
93
|
+
def to_checkout
|
94
|
+
@to_checkout ||= begin
|
95
|
+
clean_local_branch
|
96
|
+
remote_branch? ? "origin/#{ref}" : ref
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def remote_branch?
|
101
|
+
run_and_success?("#{git} show-branch origin/#{ref} > /dev/null 2>&1")
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'engineyard-serverside/spawner'
|
3
|
+
require 'escape'
|
4
|
+
|
5
|
+
class EY::Serverside::Source
|
6
|
+
attr_reader :uri, :opts, :source_cache, :ref, :shell
|
7
|
+
alias repository_cache source_cache
|
8
|
+
|
9
|
+
class << self
|
10
|
+
attr_reader :required_opts
|
11
|
+
def require_opts(*names)
|
12
|
+
@required_opts ||= []
|
13
|
+
@required_opts += names
|
14
|
+
end
|
15
|
+
|
16
|
+
def for(type)
|
17
|
+
const_get(type)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(shell, opts={})
|
22
|
+
@shell = shell
|
23
|
+
@opts = opts
|
24
|
+
|
25
|
+
if self.class.required_opts && !self.class.required_opts.all? {|name| @opts[name] }
|
26
|
+
raise ArgumentError,
|
27
|
+
"Missing required key(s) (#{self.class.required_opts.join(', ')} required)"
|
28
|
+
end
|
29
|
+
|
30
|
+
@ref = @opts[:ref]
|
31
|
+
@uri = @opts[:uri].to_s if @opts[:uri]
|
32
|
+
@source_cache = Pathname.new(@opts[:repository_cache]) if @opts[:repository_cache]
|
33
|
+
end
|
34
|
+
|
35
|
+
protected
|
36
|
+
|
37
|
+
def in_source_cache(&block)
|
38
|
+
raise ArgumentError, "Block required" unless block
|
39
|
+
source_cache.mkpath
|
40
|
+
Dir.chdir(source_cache, &block)
|
41
|
+
end
|
42
|
+
|
43
|
+
def escape(*shell_commands)
|
44
|
+
Escape.shell_command(shell_commands)
|
45
|
+
end
|
46
|
+
|
47
|
+
def runner
|
48
|
+
EY::Serverside::Spawner
|
49
|
+
end
|
50
|
+
|
51
|
+
# Internal: Run a command.
|
52
|
+
#
|
53
|
+
# cmd - A string command.
|
54
|
+
#
|
55
|
+
# Returns an instance of Spawner.
|
56
|
+
def run(cmd)
|
57
|
+
runner.run(cmd, shell, nil)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Internal: Run a command and return the output.
|
61
|
+
#
|
62
|
+
# cmd - A string command.
|
63
|
+
#
|
64
|
+
# Returns the output of the command.
|
65
|
+
def run_and_output(cmd)
|
66
|
+
run(cmd).output
|
67
|
+
end
|
68
|
+
|
69
|
+
# Internal: Run a command and check if it was successful.
|
70
|
+
#
|
71
|
+
# cmd - A string command.
|
72
|
+
#
|
73
|
+
# Returns success.
|
74
|
+
def run_and_success?(cmd)
|
75
|
+
run(cmd).success?
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class EY::Serverside::Source::Archive
|
4
|
+
def fetch_command
|
5
|
+
"cp #{uri} #{source_cache}"
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "Deploying a simple application" do
|
10
|
+
let(:adapter) {
|
11
|
+
EY::Serverside::Adapter.new do |args|
|
12
|
+
args.account_name = "account"
|
13
|
+
args.app = "application_name"
|
14
|
+
args.stack = "nginx_unicorn"
|
15
|
+
args.environment_name = "environment_name"
|
16
|
+
args.framework_env = "production"
|
17
|
+
args.archive = FIXTURES_DIR.join('retwisj.war')
|
18
|
+
args.verbose = true
|
19
|
+
args.instances = [{ :hostname => "localhost", :roles => ["solo"], :name => "single" }]
|
20
|
+
args.config = {
|
21
|
+
"deploy_to" => deploy_dir,
|
22
|
+
"release_path" => release_path.to_s,
|
23
|
+
"group" => GROUP
|
24
|
+
}
|
25
|
+
end
|
26
|
+
}
|
27
|
+
|
28
|
+
let(:binpath) {
|
29
|
+
File.expand_path(File.join(File.dirname(__FILE__), '..', 'bin', 'engineyard-serverside'))
|
30
|
+
}
|
31
|
+
|
32
|
+
before(:all) do
|
33
|
+
argv = adapter.deploy.commands.last.to_argv[2..-1]
|
34
|
+
with_mocked_commands do
|
35
|
+
capture do
|
36
|
+
EY::Serverside::CLI.start(argv)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
it "exploded the war" do
|
42
|
+
%w(META-INF WEB-INF).each {|dir|
|
43
|
+
File.exists?(deploy_dir.join('current', dir))
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
it "creates a REVISION file" do
|
48
|
+
path = deploy_dir.join('current', 'REVISION')
|
49
|
+
expect(path).to exist
|
50
|
+
checksum = File.read(path).strip
|
51
|
+
expect(checksum).to match(/7400dc058376745c11a98f768b799c6651428857\s+.*retwisj.war$/)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "restarts the app servers" do
|
55
|
+
restart = deploy_dir.join('current', 'restart')
|
56
|
+
restart.should exist
|
57
|
+
expect(restart.read.chomp).to eq(%|LANG="en_US.UTF-8" /engineyard/bin/app_application_name deploy|)
|
58
|
+
end
|
59
|
+
end
|
data/spec/configuration_spec.rb
CHANGED
@@ -15,7 +15,6 @@ describe EY::Serverside::Deploy::Configuration do
|
|
15
15
|
@config.migrate.should == nil
|
16
16
|
@config.migrate?.should == false
|
17
17
|
@config.branch.should == "master"
|
18
|
-
@config.strategy_class.should == EY::Serverside::Strategies::Git
|
19
18
|
@config.maintenance_on_migrate.should == true
|
20
19
|
@config.maintenance_on_restart.should == true
|
21
20
|
@config.required_downtime_stack?.should == true
|
@@ -43,6 +42,43 @@ describe EY::Serverside::Deploy::Configuration do
|
|
43
42
|
end
|
44
43
|
end
|
45
44
|
|
45
|
+
context "strategies" do
|
46
|
+
let(:options) {
|
47
|
+
{ "app" => "serverside" }
|
48
|
+
}
|
49
|
+
it "uses strategy if set" do
|
50
|
+
@config = EY::Serverside::Deploy::Configuration.new(
|
51
|
+
options.merge({'strategy' => 'IntegrationSpec', 'git' => 'git@github.com:engineyard/todo.git'})
|
52
|
+
)
|
53
|
+
capture do # deprecation warning
|
54
|
+
expect(@config.source(test_shell)).to be_a_kind_of(EY::Serverside::Source::IntegrationSpec)
|
55
|
+
end
|
56
|
+
read_output.should include("DEPRECATION WARNING: The configuration key 'strategy' is deprecated in favor of 'source_class'.")
|
57
|
+
end
|
58
|
+
|
59
|
+
it "uses source_class if set" do
|
60
|
+
@config = EY::Serverside::Deploy::Configuration.new(
|
61
|
+
options.merge({'source_class' => 'IntegrationSpec', 'git' => 'git@github.com:engineyard/todo.git'})
|
62
|
+
)
|
63
|
+
expect(@config.source(test_shell)).to be_a_kind_of(EY::Serverside::Source::IntegrationSpec)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "infers a git source" do
|
67
|
+
@config = EY::Serverside::Deploy::Configuration.new(
|
68
|
+
options.merge({ 'git' => 'git@github.com:engineyard/todo.git' })
|
69
|
+
)
|
70
|
+
expect(@config.source(test_shell)).to be_a_kind_of(EY::Serverside::Source::Git)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "infers a archive source" do
|
74
|
+
@config = EY::Serverside::Deploy::Configuration.new(
|
75
|
+
options.merge({'archive' => 'https://github.com/engineyard/todo/archive/master.zip'})
|
76
|
+
)
|
77
|
+
|
78
|
+
expect(@config.source(test_shell)).to be_a_kind_of(EY::Serverside::Source::Archive)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
46
82
|
context "command line options" do
|
47
83
|
before do
|
48
84
|
@config = EY::Serverside::Deploy::Configuration.new({
|
Binary file
|
data/spec/git_strategy_spec.rb
CHANGED
@@ -1,29 +1,34 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
system "tar xzf #{fixtures_dir.join('gitrepo.tar.gz')} --strip-components 1 -C #{gitrepo_dir}"
|
3
|
+
class EY::Serverside::Source::Git
|
4
|
+
def fetch_command
|
5
|
+
"mkdir -p #{source_cache} && tar xzf #{FIXTURES_DIR.join('gitrepo.tar.gz')} --strip-components 1 -C #{source_cache}"
|
6
|
+
end
|
7
|
+
end
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
:repository_cache => gitrepo_dir,
|
14
|
-
:ref => "master"
|
15
|
-
)
|
9
|
+
describe EY::Serverside::Source::Git do
|
10
|
+
before do
|
11
|
+
@source_cache = tmpdir.join("gitrepo-#{Time.now.utc.strftime("%Y%m%d%H%M%S")}#{Time.now.tv_usec}-#{$$}")
|
16
12
|
end
|
17
13
|
|
18
|
-
before { subject.checkout }
|
19
14
|
|
20
|
-
it "#
|
21
|
-
|
22
|
-
|
15
|
+
it "#update_repository_cache returns true for branches that exist" do
|
16
|
+
git = EY::Serverside::Source::Git.new(
|
17
|
+
test_shell,
|
18
|
+
:uri => FIXTURES_DIR.join('repos','default'),
|
19
|
+
:repository_cache => @source_cache,
|
20
|
+
:ref => "somebranch"
|
21
|
+
)
|
22
|
+
git.update_repository_cache
|
23
23
|
end
|
24
24
|
|
25
|
-
it "#
|
26
|
-
|
27
|
-
|
25
|
+
it "#update_repository_cache returns false for branches that do not exist" do
|
26
|
+
git = EY::Serverside::Source::Git.new(
|
27
|
+
test_shell,
|
28
|
+
:uri => FIXTURES_DIR.join('repos','default'),
|
29
|
+
:repository_cache => @source_cache,
|
30
|
+
:ref => "notabranch"
|
31
|
+
)
|
32
|
+
expect { git.update_repository_cache }.to raise_error
|
28
33
|
end
|
29
34
|
end
|
data/spec/rollback_spec.rb
CHANGED
@@ -30,6 +30,38 @@ describe "Rolling back" do
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
+
context "with a problematic file in the releases dir" do
|
34
|
+
before(:all) do
|
35
|
+
deploy_test_application('not_bundled', 'migrate' => nil)
|
36
|
+
@good_revision = deploy_dir.join('current', 'REVISION').read.strip
|
37
|
+
deploy_dir.join('current', 'REVISION').should exist
|
38
|
+
deploy_dir.join('current', 'restart').delete
|
39
|
+
deploy_test_application('not_bundled', 'migrate' => nil)
|
40
|
+
deploy_dir.join('current', 'REVISION').should exist
|
41
|
+
deploy_dir.join('current', 'restart').delete
|
42
|
+
end
|
43
|
+
|
44
|
+
it "rolls back to the older deploy" do
|
45
|
+
releases = @deployer.config.paths.all_releases
|
46
|
+
releases.size.should == 2
|
47
|
+
good_release = releases.first
|
48
|
+
bad_release = releases.last
|
49
|
+
|
50
|
+
@deployer.config.paths.releases.join('tmp').mkpath
|
51
|
+
|
52
|
+
expect { @deployer.rollback }.to raise_error
|
53
|
+
out = read_output
|
54
|
+
expect(out).to include("Bad paths found in #{@deployer.config.paths.releases}:")
|
55
|
+
expect(out).to include(@deployer.config.paths.releases.join('tmp').to_s)
|
56
|
+
expect(out).to include("Storing files in this directory will disrupt latest_release, diff detection, rollback, and possibly other features.")
|
57
|
+
expect(out).to_not include("Restarting with previous release.")
|
58
|
+
|
59
|
+
deploy_dir.join('current', 'restart').should_not exist
|
60
|
+
bad_release.should exist
|
61
|
+
good_release.should exist
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
33
65
|
context "with complex config" do
|
34
66
|
before(:all) do
|
35
67
|
deploy_test_application('ey_yml', 'migrate' => nil)
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe EY::Serverside::Source::Archive do
|
4
|
+
before do
|
5
|
+
described_class.any_instance.stub(:runner) { RunnerDouble }
|
6
|
+
end
|
7
|
+
|
8
|
+
context "source" do
|
9
|
+
let(:shell) { ShellDouble.new }
|
10
|
+
subject {
|
11
|
+
described_class.new(shell,
|
12
|
+
:uri => "http://server.com/app.war",
|
13
|
+
:repository_cache => TMPDIR)
|
14
|
+
}
|
15
|
+
|
16
|
+
it "cleans cache" do
|
17
|
+
expect(subject).to respond_to(:gc_repository_cache)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "compares revisions" do
|
21
|
+
expect(subject.same?("1", "1")).to be
|
22
|
+
end
|
23
|
+
|
24
|
+
it "understands short log message" do
|
25
|
+
expect(subject).to respond_to(:short_log_message)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "updates the cache" do
|
29
|
+
last_output = subject.update_repository_cache.output
|
30
|
+
expect(last_output).to eq("unzip app.war && rm app.war")
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe EY::Serverside::Source::Git do
|
4
|
+
before do
|
5
|
+
described_class.any_instance.stub(:runner) { RunnerDouble }
|
6
|
+
end
|
7
|
+
|
8
|
+
it "errors when required options are not used" do
|
9
|
+
expect { described_class.new(nil, {}) }.to raise_error(ArgumentError)
|
10
|
+
end
|
11
|
+
|
12
|
+
context "source" do
|
13
|
+
let(:shell) { ShellDouble.new }
|
14
|
+
subject {
|
15
|
+
described_class.new(shell,
|
16
|
+
:uri => "engineyard/engineyard-serverside.git",
|
17
|
+
:ref => "",
|
18
|
+
:repository_cache => "cache_dir")
|
19
|
+
}
|
20
|
+
|
21
|
+
it "creates the correct reivison file command" do
|
22
|
+
expect(subject.create_revision_file_command("directory/REVISION")).to eq(
|
23
|
+
"git --git-dir cache_dir/.git --work-tree cache_dir show --pretty=format:\"%H\" | head -1 > \"directory/REVISION\""
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "runs gc" do
|
28
|
+
expect(subject.gc_repository_cache.output).to eq("git --git-dir cache_dir/.git --work-tree cache_dir gc")
|
29
|
+
expect(shell.messages.last).to eq("Garbage collecting cached git repository to reduce disk usage.")
|
30
|
+
end
|
31
|
+
|
32
|
+
it "checks if it is the same revision" do
|
33
|
+
expect(subject.same?("", "")).to be
|
34
|
+
end
|
35
|
+
|
36
|
+
it "runs a short log message" do
|
37
|
+
expect(subject.short_log_message("rev")).to eq(
|
38
|
+
"git --git-dir cache_dir/.git --work-tree cache_dir log --pretty=oneline --abbrev-commit -n 1 'rev'"
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -15,7 +15,8 @@ end
|
|
15
15
|
require 'pp'
|
16
16
|
require 'engineyard-serverside'
|
17
17
|
require 'engineyard-serverside-adapter'
|
18
|
-
require
|
18
|
+
require 'support/integration'
|
19
|
+
require 'support/source_doubles'
|
19
20
|
|
20
21
|
FIXTURES_DIR = Pathname.new(__FILE__).dirname.join("fixtures")
|
21
22
|
TMPDIR = Pathname.new(__FILE__).dirname.parent.join('tmp')
|
@@ -28,11 +29,6 @@ module EY
|
|
28
29
|
@dna_json = j
|
29
30
|
@node = nil
|
30
31
|
end
|
31
|
-
|
32
|
-
class Strategies::Git
|
33
|
-
def short_log_message(_) "" end
|
34
|
-
end
|
35
|
-
|
36
32
|
end
|
37
33
|
end
|
38
34
|
|
@@ -232,7 +228,7 @@ exec "$@"
|
|
232
228
|
# spec/fixtures/repos dir are copied into the test github repository.
|
233
229
|
def deploy_test_application(repo_fixture_name = 'default', extra_config = {}, &block)
|
234
230
|
options = {
|
235
|
-
"
|
231
|
+
"source_class" => "IntegrationSpec",
|
236
232
|
"deploy_to" => deploy_dir.to_s,
|
237
233
|
"release_path" => release_path.to_s,
|
238
234
|
"group" => GROUP,
|
@@ -244,7 +240,7 @@ exec "$@"
|
|
244
240
|
"framework_env" => 'staging',
|
245
241
|
"branch" => 'somebranch',
|
246
242
|
"verbose" => true,
|
247
|
-
"
|
243
|
+
"git" => FIXTURES_DIR.join('repos', repo_fixture_name),
|
248
244
|
}.merge(extra_config)
|
249
245
|
|
250
246
|
# pretend there is a shared bundled_gems directory
|
@@ -260,11 +256,11 @@ exec "$@"
|
|
260
256
|
args.account_name = options['account_name']
|
261
257
|
args.migrate = options['migrate']
|
262
258
|
args.ref = options['branch']
|
263
|
-
args.
|
259
|
+
args.git = options['git']
|
264
260
|
args.config = {
|
265
261
|
"services_check_command" => "which echo",
|
266
262
|
"services_setup_command" => "echo 'services setup command'",
|
267
|
-
"
|
263
|
+
"source_class" => options["source_class"],
|
268
264
|
"deploy_to" => options["deploy_to"],
|
269
265
|
"release_path" => options["release_path"],
|
270
266
|
"group" => options["group"]
|
data/spec/support/integration.rb
CHANGED
@@ -51,18 +51,12 @@ class EY::Serverside::Deploy
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
-
class EY::Serverside::
|
55
|
-
attr_reader :
|
54
|
+
class EY::Serverside::Source::IntegrationSpec < EY::Serverside::Source
|
55
|
+
attr_reader :source_repo
|
56
56
|
|
57
|
-
def initialize(
|
58
|
-
|
59
|
-
|
60
|
-
end
|
61
|
-
|
62
|
-
@shell = shell
|
63
|
-
@ref = opts[:ref]
|
64
|
-
@source_repo = Pathname.new(opts[:repo])
|
65
|
-
@repository_cache = Pathname.new(opts[:repository_cache])
|
57
|
+
def initialize(*a)
|
58
|
+
super
|
59
|
+
@source_repo = Pathname.new(uri)
|
66
60
|
end
|
67
61
|
|
68
62
|
def update_repository_cache
|
@@ -71,8 +65,8 @@ class EY::Serverside::Strategies::IntegrationSpec
|
|
71
65
|
copy_fixture_repo_files
|
72
66
|
end
|
73
67
|
|
74
|
-
def create_revision_file_command(
|
75
|
-
"echo '#{@ref}' > #{
|
68
|
+
def create_revision_file_command(revision_path)
|
69
|
+
"echo '#{@ref}' > #{revision_path}"
|
76
70
|
end
|
77
71
|
|
78
72
|
def short_log_message(revision)
|
@@ -101,7 +95,7 @@ class EY::Serverside::Strategies::IntegrationSpec
|
|
101
95
|
shell.substatus "Test helpers copying repo fixture from #{source_repo}/ to #{repository_cache}"
|
102
96
|
# This uses a ruby method instead of shelling out because I was having
|
103
97
|
# trouble getting cp -R to behave consistently between distros.
|
104
|
-
|
98
|
+
system "rsync -aq #{source_repo}/ #{repository_cache}"
|
105
99
|
else
|
106
100
|
raise "Mock repo #{source_repo.inspect} does not exist. Path should be absolute. e.g. FIXTURES_DIR.join('repos','example')"
|
107
101
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class ShellDouble
|
2
|
+
attr_reader :messages
|
3
|
+
def initialize
|
4
|
+
@messages = []
|
5
|
+
end
|
6
|
+
|
7
|
+
def status(message)
|
8
|
+
@messages << message
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class RunnerDouble
|
13
|
+
def self.run(cmd, shell, server=nil)
|
14
|
+
new(cmd)
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(cmd)
|
18
|
+
@cmd = cmd
|
19
|
+
end
|
20
|
+
|
21
|
+
def output
|
22
|
+
@cmd
|
23
|
+
end
|
24
|
+
|
25
|
+
def success?
|
26
|
+
true
|
27
|
+
end
|
28
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: engineyard-serverside
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- EY Cloud Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-07
|
11
|
+
date: 2013-08-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -100,14 +100,14 @@ dependencies:
|
|
100
100
|
requirements:
|
101
101
|
- - ~>
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: 2.0
|
103
|
+
version: 2.1.0
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - ~>
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: 2.0
|
110
|
+
version: 2.1.0
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: sqlite3
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -154,8 +154,11 @@ files:
|
|
154
154
|
- lib/engineyard-serverside/shell/helpers.rb
|
155
155
|
- lib/engineyard-serverside/shell/yieldio.rb
|
156
156
|
- lib/engineyard-serverside/shell.rb
|
157
|
+
- lib/engineyard-serverside/source/archive.rb
|
158
|
+
- lib/engineyard-serverside/source/git.rb
|
159
|
+
- lib/engineyard-serverside/source.rb
|
160
|
+
- lib/engineyard-serverside/source_strategy.rb
|
157
161
|
- lib/engineyard-serverside/spawner.rb
|
158
|
-
- lib/engineyard-serverside/strategies/git.rb
|
159
162
|
- lib/engineyard-serverside/task.rb
|
160
163
|
- lib/engineyard-serverside/version.rb
|
161
164
|
- lib/engineyard-serverside.rb
|
@@ -220,6 +223,7 @@ files:
|
|
220
223
|
- lib/vendor/thor/README.md
|
221
224
|
- lib/vendor/thor/thor.gemspec
|
222
225
|
- LICENSE
|
226
|
+
- spec/archive_deploy_spec.rb
|
223
227
|
- spec/basic_deploy_spec.rb
|
224
228
|
- spec/bundler_deploy_spec.rb
|
225
229
|
- spec/configuration_spec.rb
|
@@ -355,6 +359,7 @@ files:
|
|
355
359
|
- spec/fixtures/repos/sqlite3/Gemfile
|
356
360
|
- spec/fixtures/repos/sqlite3/Gemfile.lock
|
357
361
|
- spec/fixtures/repos/sqlite3/README
|
362
|
+
- spec/fixtures/retwisj.war
|
358
363
|
- spec/fixtures/valid_hook.rb
|
359
364
|
- spec/git_strategy_spec.rb
|
360
365
|
- spec/lockfile_parser_spec.rb
|
@@ -367,9 +372,12 @@ files:
|
|
367
372
|
- spec/server_spec.rb
|
368
373
|
- spec/services_deploy_spec.rb
|
369
374
|
- spec/shell_spec.rb
|
375
|
+
- spec/source/archive_spec.rb
|
376
|
+
- spec/source/git_spec.rb
|
370
377
|
- spec/spec_helper.rb
|
371
378
|
- spec/sqlite3_deploy_spec.rb
|
372
379
|
- spec/support/integration.rb
|
380
|
+
- spec/support/source_doubles.rb
|
373
381
|
homepage: http://github.com/engineyard/engineyard-serverside
|
374
382
|
licenses:
|
375
383
|
- MIT
|
@@ -395,6 +403,7 @@ signing_key:
|
|
395
403
|
specification_version: 4
|
396
404
|
summary: A gem that deploys ruby applications on EY Cloud instances
|
397
405
|
test_files:
|
406
|
+
- spec/archive_deploy_spec.rb
|
398
407
|
- spec/basic_deploy_spec.rb
|
399
408
|
- spec/bundler_deploy_spec.rb
|
400
409
|
- spec/configuration_spec.rb
|
@@ -530,6 +539,7 @@ test_files:
|
|
530
539
|
- spec/fixtures/repos/sqlite3/Gemfile
|
531
540
|
- spec/fixtures/repos/sqlite3/Gemfile.lock
|
532
541
|
- spec/fixtures/repos/sqlite3/README
|
542
|
+
- spec/fixtures/retwisj.war
|
533
543
|
- spec/fixtures/valid_hook.rb
|
534
544
|
- spec/git_strategy_spec.rb
|
535
545
|
- spec/lockfile_parser_spec.rb
|
@@ -542,6 +552,9 @@ test_files:
|
|
542
552
|
- spec/server_spec.rb
|
543
553
|
- spec/services_deploy_spec.rb
|
544
554
|
- spec/shell_spec.rb
|
555
|
+
- spec/source/archive_spec.rb
|
556
|
+
- spec/source/git_spec.rb
|
545
557
|
- spec/spec_helper.rb
|
546
558
|
- spec/sqlite3_deploy_spec.rb
|
547
559
|
- spec/support/integration.rb
|
560
|
+
- spec/support/source_doubles.rb
|
@@ -1,104 +0,0 @@
|
|
1
|
-
require 'pathname'
|
2
|
-
|
3
|
-
module EY
|
4
|
-
module Serverside
|
5
|
-
module Strategies
|
6
|
-
class Git
|
7
|
-
attr_reader :shell, :opts
|
8
|
-
|
9
|
-
def initialize(shell, opts)
|
10
|
-
@shell = shell
|
11
|
-
@opts = opts
|
12
|
-
end
|
13
|
-
|
14
|
-
def update_repository_cache
|
15
|
-
unless fetch && checkout
|
16
|
-
abort "*** [Error] Git could not checkout (#{to_checkout}) ***"
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def usable_repository?
|
21
|
-
repository_cache.directory? && `#{git} remote -v | grep origin`[remote_uri]
|
22
|
-
end
|
23
|
-
|
24
|
-
def fetch
|
25
|
-
if usable_repository?
|
26
|
-
run("#{git} fetch -q origin 2>&1")
|
27
|
-
else
|
28
|
-
run("rm -rf #{repository_cache} && git clone -q #{remote_uri} #{repository_cache} 2>&1")
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def checkout
|
33
|
-
shell.status "Deploying revision #{short_log_message(to_checkout)}"
|
34
|
-
q = opts[:verbose] ? '' : '-q'
|
35
|
-
in_repository_cache do
|
36
|
-
(run("git checkout -f #{q} '#{to_checkout}'") ||
|
37
|
-
run("git reset --hard #{q} '#{to_checkout}'")) &&
|
38
|
-
run("git submodule sync") &&
|
39
|
-
run("git submodule update --init") &&
|
40
|
-
run("git clean -dfq")
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def to_checkout
|
45
|
-
return @to_checkout if @opts_ref == opts[:ref]
|
46
|
-
@opts_ref = opts[:ref]
|
47
|
-
clean_local_branch(@opts_ref)
|
48
|
-
@to_checkout = remote_branch?(@opts_ref) ? "origin/#{@opts_ref}" : @opts_ref
|
49
|
-
end
|
50
|
-
|
51
|
-
def clean_local_branch(ref)
|
52
|
-
system("#{git} show-branch #{ref} > /dev/null 2>&1 && #{git} branch -D #{ref} > /dev/null 2>&1")
|
53
|
-
end
|
54
|
-
|
55
|
-
def gc_repository_cache
|
56
|
-
shell.status "Garbage collecting cached git repository to reduce disk usage."
|
57
|
-
run("#{git} gc")
|
58
|
-
end
|
59
|
-
|
60
|
-
def create_revision_file_command(dir)
|
61
|
-
%Q{#{git} show --pretty=format:"%H" | head -1 > "#{dir}/REVISION"}
|
62
|
-
end
|
63
|
-
|
64
|
-
def short_log_message(rev)
|
65
|
-
`#{git} log --pretty=oneline --abbrev-commit -n 1 '#{rev}'`.strip
|
66
|
-
end
|
67
|
-
|
68
|
-
# git diff --exit-code returns
|
69
|
-
# 0 when nothing has changed
|
70
|
-
# 1 when there are changes
|
71
|
-
#
|
72
|
-
# Thes method returns true when nothing has changed, fales otherwise
|
73
|
-
def same?(previous_revision, active_revision, paths = nil)
|
74
|
-
run("#{git} diff '#{previous_revision}'..'#{active_revision}' --exit-code --name-only -- #{Array(paths).join(' ')} >/dev/null 2>&1")
|
75
|
-
end
|
76
|
-
|
77
|
-
private
|
78
|
-
def run(cmd)
|
79
|
-
EY::Serverside::Spawner.run(cmd, shell, nil).success?
|
80
|
-
end
|
81
|
-
|
82
|
-
def in_repository_cache
|
83
|
-
Dir.chdir(repository_cache) { yield }
|
84
|
-
end
|
85
|
-
|
86
|
-
def remote_uri
|
87
|
-
opts[:repo]
|
88
|
-
end
|
89
|
-
|
90
|
-
def repository_cache
|
91
|
-
Pathname.new(opts[:repository_cache])
|
92
|
-
end
|
93
|
-
|
94
|
-
def git
|
95
|
-
"git --git-dir #{repository_cache}/.git --work-tree #{repository_cache}"
|
96
|
-
end
|
97
|
-
|
98
|
-
def remote_branch?(ref)
|
99
|
-
system("#{git} show-branch origin/#{ref} > /dev/null 2>&1")
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|