engineyard-serverside 2.2.1 → 2.3.0
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.
- 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
|