avodeploy 0.4.2 → 0.5
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 +4 -4
- data/CHANGELOG +20 -0
- data/README.md +1 -1
- data/avodeploy.gemspec +16 -14
- data/bin/avo +101 -104
- data/lib/avodeploy.rb +1 -0
- data/lib/avodeploy/bootstrap.rb +65 -73
- data/lib/avodeploy/command_execution_result.rb +6 -6
- data/lib/avodeploy/config.rb +120 -99
- data/lib/avodeploy/core_ext/string_colors.rb +9 -9
- data/lib/avodeploy/deployment.rb +43 -46
- data/lib/avodeploy/multi_io.rb +11 -11
- data/lib/avodeploy/scm_provider/bzr_scm_provider.rb +111 -0
- data/lib/avodeploy/scm_provider/git_scm_provider.rb +66 -45
- data/lib/avodeploy/scm_provider/scm_provider.rb +57 -43
- data/lib/avodeploy/skel/manifest_template.rb.erb +127 -116
- data/lib/avodeploy/strategy/base.rb +7 -7
- data/lib/avodeploy/strategy/local_copy.rb +99 -79
- data/lib/avodeploy/strategy/local_copy_partial.rb +86 -0
- data/lib/avodeploy/target.rb +32 -31
- data/lib/avodeploy/task/local_task_execution_environment.rb +112 -107
- data/lib/avodeploy/task/remote_task_execution_environment.rb +90 -94
- data/lib/avodeploy/task/task.rb +53 -42
- data/lib/avodeploy/task/task_dependency.rb +5 -5
- data/lib/avodeploy/task/task_execution_environment.rb +70 -59
- data/lib/avodeploy/task/task_manager.rb +187 -165
- data/lib/avodeploy/version.rb +1 -1
- metadata +7 -5
@@ -17,13 +17,13 @@
|
|
17
17
|
=end
|
18
18
|
|
19
19
|
AvoDeploy::Deployment.configure do
|
20
|
-
|
21
|
-
task :deploy, visibility: :public do
|
22
|
-
# stub for cli calls
|
23
|
-
end
|
24
20
|
|
25
|
-
|
26
|
-
|
27
|
-
|
21
|
+
task :deploy, visibility: :public do
|
22
|
+
# stub for cli calls
|
23
|
+
end
|
24
|
+
|
25
|
+
task :check_ssh_connection, before: :deploy, scope: :remote, visibility: :private do
|
26
|
+
log.info 'checking ssh connection'
|
27
|
+
end
|
28
28
|
|
29
29
|
end
|
@@ -18,84 +18,104 @@
|
|
18
18
|
|
19
19
|
AvoDeploy::Deployment.configure do
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
21
|
+
inherit_strategy :base
|
22
|
+
|
23
|
+
task :check_targets, before: :deploy do
|
24
|
+
raise RuntimeError, 'No target systems are configured' if targets.empty?
|
25
|
+
end
|
26
|
+
|
27
|
+
task :check_local_tools, before: :deploy do
|
28
|
+
check_util_availability ['tar'].concat(@scm.cli_utils)
|
29
|
+
end
|
30
|
+
|
31
|
+
task :check_remote_system, before: :deploy, scope: :remote do
|
32
|
+
res = command 'uname -a'
|
33
|
+
|
34
|
+
if res.stdout.include?('Linux') == false
|
35
|
+
raise RuntimeError, 'Only linux target systems are supported right now.'
|
36
|
+
end
|
37
|
+
|
38
|
+
check_util_availability ['tar']
|
39
|
+
end
|
40
|
+
|
41
|
+
task :check_temp_existance, after: :deploy do
|
42
|
+
if File.exist?('.avocado-tmp')
|
43
|
+
raise RuntimeError, 'The avocado tmp directory (.avocado-tmp) does already exist. That may indicate that another deployment is already running.'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
task :switch_to_temp_dir, after: :check_temp_existance do
|
48
|
+
command 'mkdir .avocado-tmp/'
|
49
|
+
chdir '.avocado-tmp/'
|
50
|
+
end
|
51
|
+
|
52
|
+
task :checkout_from_scm, after: :switch_to_temp_dir do
|
53
|
+
tag = nil
|
54
|
+
|
55
|
+
if @options.nil? == false && @options[:tag].nil? == false
|
56
|
+
tag = @options[:tag]
|
57
|
+
end
|
58
|
+
|
59
|
+
if get(:force_tag) && tag.nil?
|
60
|
+
raise RuntimeError, 'Deployment requires a tag but none was submitted'
|
61
|
+
end
|
62
|
+
|
63
|
+
@scm.checkout_from_remote(get(:repo_url), 'working-copy', get(:branch), tag)
|
64
|
+
end
|
65
|
+
|
66
|
+
task :chdir_to_working_copy, after: :checkout_from_scm do
|
67
|
+
chdir 'working-copy/'
|
68
|
+
end
|
69
|
+
|
70
|
+
task :get_scm_info, after: :chdir_to_working_copy do
|
71
|
+
set :revision, @scm.revision
|
72
|
+
end
|
73
|
+
|
74
|
+
task :create_revision_file, after: :get_scm_info do
|
75
|
+
command "echo '#{get(:revision)}' > REVISION"
|
76
|
+
end
|
77
|
+
|
78
|
+
task :create_deployment_tarball, after: :create_revision_file do
|
79
|
+
files_to_delete = ['Avofile'].concat(get(:ignore_files)).concat(@scm.scm_files)
|
80
|
+
|
81
|
+
exclude_param = ''
|
82
|
+
|
83
|
+
files_to_delete.each do |file|
|
84
|
+
exclude_param += " --exclude='^#{file}$'"
|
85
|
+
end
|
86
|
+
|
87
|
+
command "tar cfz ../deploy.tar.gz #{exclude_param} ."
|
88
|
+
end
|
89
|
+
|
90
|
+
task :switch_to_parent_dir, after: :create_deployment_tarball do
|
91
|
+
chdir '../'
|
92
|
+
end
|
93
|
+
|
94
|
+
task :upload, after: :switch_to_parent_dir do
|
95
|
+
targets.each_pair do |key, target|
|
96
|
+
copy_to_target(target, 'deploy.tar.gz', '/tmp/deploy.tar.gz')
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
task :create_deploy_dir, after: :upload, scope: :remote do
|
101
|
+
command "if [ ! -d '#{get(:deploy_dir)}' ]; then mkdir -p #{get(:deploy_dir)}; fi"
|
102
|
+
end
|
103
|
+
|
104
|
+
task :unpack, after: :create_deploy_dir, scope: :remote do
|
105
|
+
command "tar xvfz /tmp/deploy.tar.gz -C #{get(:deploy_dir)}/"
|
106
|
+
end
|
107
|
+
|
108
|
+
task :cleanup_remote, after: :unpack, scope: :remote do
|
109
|
+
command 'rm /tmp/deploy.tar.gz'
|
110
|
+
end
|
111
|
+
|
112
|
+
task :log_deployment, after: :cleanup_remote, scope: :remote do
|
113
|
+
command "echo '[#{Time.now.strftime('%Y-%m-%d %H-%M-%S')}] revision #{get(:revision)} deployed by #{ENV['USER']}' >> #{get(:log_file)}"
|
114
|
+
end
|
115
|
+
|
116
|
+
task :cleanup_local, after: :cleanup_remote do
|
117
|
+
chdir '../'
|
118
|
+
command 'rm -rf .avocado-tmp'
|
119
|
+
end
|
100
120
|
|
101
121
|
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
=begin
|
2
|
+
AVOCADO
|
3
|
+
The flexible and easy to use deployment framework for web applications
|
4
|
+
|
5
|
+
This program is free software; you can redistribute it and/or
|
6
|
+
modify it under the terms of the GNU General Public License Version 2
|
7
|
+
as published by the Free Software Foundation.
|
8
|
+
|
9
|
+
This program is distributed in the hope that it will be useful,
|
10
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
GNU General Public License for more details.
|
13
|
+
|
14
|
+
You should have received a copy of the GNU General Public License
|
15
|
+
along with this program; if not, write to the Free Software
|
16
|
+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
17
|
+
=end
|
18
|
+
|
19
|
+
AvoDeploy::Deployment.configure do
|
20
|
+
|
21
|
+
inherit_strategy :local_copy
|
22
|
+
|
23
|
+
task :get_deployed_revision, after: :chdir_to_working_copy, scope: :remote do
|
24
|
+
res = command "cat #{get(:deploy_dir)}/REVISION"
|
25
|
+
|
26
|
+
if get(:deployed_revisions).nil?
|
27
|
+
deployed_revisions = {}
|
28
|
+
else
|
29
|
+
deployed_revisions = get(:deployed_revisions)
|
30
|
+
end
|
31
|
+
|
32
|
+
revision = nil
|
33
|
+
|
34
|
+
if res.retval == 0
|
35
|
+
# file exists
|
36
|
+
revision = res.stdout.lines.first.strip
|
37
|
+
end
|
38
|
+
|
39
|
+
deployed_revisions[get(:name)] = revision
|
40
|
+
set(:deployed_revisions, deployed_revisions)
|
41
|
+
end
|
42
|
+
|
43
|
+
task :create_deployment_tarball, after: :create_revision_file do
|
44
|
+
new_revision = get(:revision)
|
45
|
+
|
46
|
+
get(:deployed_revisions).each_pair do |target_name, deployed_revision|
|
47
|
+
# determine, which files to exclude
|
48
|
+
files_to_delete = ['Avofile'].concat(get(:ignore_files)).concat(@scm.scm_files)
|
49
|
+
|
50
|
+
exclude_param = ''
|
51
|
+
|
52
|
+
files_to_delete.each do |file|
|
53
|
+
exclude_param += " --exclude='^#{file}$'"
|
54
|
+
end
|
55
|
+
|
56
|
+
# create deployment archive
|
57
|
+
if deployed_revision.nil?
|
58
|
+
# create full deployment archive
|
59
|
+
command "tar -czvf ../deploy_#{target_name.to_s}.tar.gz #{exclude_param} ."
|
60
|
+
else
|
61
|
+
# create partial deployment archive
|
62
|
+
diff_files = @scm.diff_files_between_revisions(deployed_revision, new_revision)
|
63
|
+
|
64
|
+
# always include the revision file
|
65
|
+
# UPDATE: not longer needed because REVISION is in the unknown_files array anyway
|
66
|
+
#diff_files << 'REVISION'
|
67
|
+
|
68
|
+
# include unknown files
|
69
|
+
unknown_files = @scm.unknown_files_in_workdir
|
70
|
+
|
71
|
+
File.open("../files_#{target_name.to_s}.txt", 'w') do |f|
|
72
|
+
f << diff_files.concat(unknown_files).join("\n")
|
73
|
+
end
|
74
|
+
|
75
|
+
command "tar cvfz ../deploy_#{target_name.to_s}.tar.gz -T ../files_#{target_name.to_s}.txt #{exclude_param}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
task :upload, after: :switch_to_parent_dir do
|
81
|
+
targets.each_pair do |key, target|
|
82
|
+
copy_to_target(target, "deploy_#{target.name.to_s}.tar.gz", '/tmp/deploy.tar.gz')
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
data/lib/avodeploy/target.rb
CHANGED
@@ -17,35 +17,36 @@
|
|
17
17
|
=end
|
18
18
|
|
19
19
|
module AvoDeploy
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
20
|
+
class Target
|
21
|
+
|
22
|
+
attr_reader :name
|
23
|
+
attr_reader :config
|
24
|
+
|
25
|
+
# Initializes the deployment target
|
26
|
+
#
|
27
|
+
# @param name [Symbol] target name
|
28
|
+
# @param config [Hash] target config
|
29
|
+
def initialize(name, config)
|
30
|
+
@name = name
|
31
|
+
@config = default_config.merge(config)
|
32
|
+
@config[:name] = name
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
# Sets up the config defaults
|
37
|
+
#
|
38
|
+
# @return [Hash] config defaults
|
39
|
+
def default_config
|
40
|
+
{
|
41
|
+
:name => '',
|
42
|
+
:host => nil,
|
43
|
+
:port => 22,
|
44
|
+
:user => 'root',
|
45
|
+
:auth => :pubkey,
|
46
|
+
:deploy_dir => '/var/www/',
|
47
|
+
:log_file => '/var/www/deploy.log',
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
51
52
|
end
|
@@ -17,111 +17,116 @@
|
|
17
17
|
=end
|
18
18
|
|
19
19
|
module AvoDeploy
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
20
|
+
module Task
|
21
|
+
class LocalTaskExecutionEnvironment < TaskExecutionEnvironment
|
22
|
+
|
23
|
+
# Initialized the environment
|
24
|
+
#
|
25
|
+
# @param config [Hash] deployment configuration
|
26
|
+
def initialize(config)
|
27
|
+
super
|
28
|
+
|
29
|
+
@dir = Dir.pwd
|
30
|
+
end
|
31
|
+
|
32
|
+
# Checks, if all utilities are available for the deployment process
|
33
|
+
# to be executed
|
34
|
+
#
|
35
|
+
# @param utils [Array] array with utilities to check
|
36
|
+
def check_util_availability(utils)
|
37
|
+
super(utils, 'locally')
|
38
|
+
end
|
39
|
+
|
40
|
+
# Changes the directory for commands to be executed in
|
41
|
+
#
|
42
|
+
# @param dir [String] the directory to change to
|
43
|
+
def chdir(dir)
|
44
|
+
log.debug "changing directory [#{dir.yellow}] " + "locally".cyan
|
45
|
+
|
46
|
+
Dir.chdir(dir)
|
47
|
+
@dir = Dir.pwd
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns the current working directory
|
51
|
+
#
|
52
|
+
# @return [String] current working directory
|
53
|
+
def cwd
|
54
|
+
@dir
|
55
|
+
end
|
56
|
+
|
57
|
+
# Returns all target systems to deploy to
|
58
|
+
#
|
59
|
+
# @return [Hash] hash of target systems
|
60
|
+
def targets
|
61
|
+
AvoDeploy::Deployment.instance.config.targets
|
62
|
+
end
|
63
|
+
|
64
|
+
# Copies a file to a remote system (= target)
|
65
|
+
#
|
66
|
+
# @param target [Target] the target system to deploy to
|
67
|
+
# @param file [String] the local file to upload
|
68
|
+
# @param remote [String] path on the remote system
|
69
|
+
def copy_to_target(target, file, remote)
|
70
|
+
log = AvoDeploy::Deployment.instance.log
|
71
|
+
|
72
|
+
log.info "started upload of file #{file} to #{target.name}"
|
73
|
+
|
74
|
+
Net::SSH.start(
|
75
|
+
target.config[:host],
|
76
|
+
target.config[:user],
|
77
|
+
{
|
78
|
+
:port => target.config[:port]
|
79
|
+
}
|
80
|
+
) do |session|
|
81
|
+
session.scp.upload!(file, remote, :recursive => true) do |ch, name, sent, total|
|
82
|
+
percentage = 0
|
83
|
+
|
84
|
+
begin
|
85
|
+
percentage = (sent.to_f * 100 / total.to_f).to_i
|
86
|
+
rescue Exception => e
|
87
|
+
AvoDeploy::Deployment.instance.handle_abort(e)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
log.info "upload completed"
|
93
|
+
end
|
94
|
+
|
95
|
+
# Executes a command locally in the current directory
|
96
|
+
#
|
97
|
+
# @param cmd [String] the command to execute
|
98
|
+
# @return [CommandExecutionResult] result of the command exection
|
99
|
+
def command(cmd)
|
100
|
+
log = AvoDeploy::Deployment.instance.log
|
101
|
+
|
102
|
+
log.info "Executing [" + cmd.yellow + "] " + "locally".cyan
|
103
|
+
|
104
|
+
result = AvoDeploy::CommandExecutionResult.new
|
105
|
+
|
106
|
+
begin
|
107
|
+
stdout, stderr, status = ::Open3.capture3(cmd, :chdir => cwd())
|
108
|
+
|
109
|
+
result.stdin = cmd
|
110
|
+
result.stdout = stdout
|
111
|
+
result.stderr = stderr
|
112
|
+
result.retval = status.exitstatus
|
113
|
+
|
114
|
+
if result.stdout.nil? == false && result.stdout.empty? == false
|
115
|
+
log.debug 'Stdout: ' + result.stdout.green
|
116
|
+
end
|
117
|
+
|
118
|
+
if result.stderr.nil? == false && result.stderr.empty? == false
|
119
|
+
log.debug 'Stderr: ' + result.stderr.red
|
120
|
+
end
|
121
|
+
|
122
|
+
log.debug 'Retval: ' + result.retval.to_s
|
123
|
+
rescue Exception => e
|
124
|
+
handle_abort e
|
125
|
+
end
|
126
|
+
|
127
|
+
result
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
end
|
127
132
|
end
|