travis_dpl_test 2.0.3.beta.4.ror
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 +7 -0
- data/CHANGELOG.md +172 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/CONTRIBUTING.md +392 -0
- data/Gemfile +32 -0
- data/Gemfile.lock +611 -0
- data/LICENSE +19 -0
- data/README.md +2744 -0
- data/Rakefile +210 -0
- data/bin/dpl +11 -0
- data/config/transliterate.yml +733 -0
- data/dpl.gemspec +23 -0
- data/lib/dpl/assets/atlas/install +19 -0
- data/lib/dpl/assets/convox/install +11 -0
- data/lib/dpl/assets/dpl/README.erb.md +138 -0
- data/lib/dpl/assets/dpl/git_ssh +8 -0
- data/lib/dpl/assets/git/detect_private_key +8 -0
- data/lib/dpl/assets/hephy/filter_log +3 -0
- data/lib/dpl/assets/pypi/install +4 -0
- data/lib/dpl/assets/scalingo/install +6 -0
- data/lib/dpl/cli.rb +100 -0
- data/lib/dpl/ctx/bash.rb +549 -0
- data/lib/dpl/ctx/test.rb +255 -0
- data/lib/dpl/ctx.rb +4 -0
- data/lib/dpl/helper/assets.rb +38 -0
- data/lib/dpl/helper/cmd.rb +169 -0
- data/lib/dpl/helper/config_file.rb +49 -0
- data/lib/dpl/helper/cookbook_site_streaming_uploader.rb +249 -0
- data/lib/dpl/helper/env.rb +92 -0
- data/lib/dpl/helper/github.rb +22 -0
- data/lib/dpl/helper/interpolate.rb +160 -0
- data/lib/dpl/helper/memoize.rb +23 -0
- data/lib/dpl/helper/squiggle.rb +24 -0
- data/lib/dpl/helper/transliterate.rb +13 -0
- data/lib/dpl/helper/wrap.rb +11 -0
- data/lib/dpl/helper/zip.rb +71 -0
- data/lib/dpl/provider/dsl.rb +410 -0
- data/lib/dpl/provider/examples.rb +132 -0
- data/lib/dpl/provider/status.rb +61 -0
- data/lib/dpl/provider.rb +651 -0
- data/lib/dpl/providers/anynines.rb +71 -0
- data/lib/dpl/providers/azure_web_apps.rb +63 -0
- data/lib/dpl/providers/bintray.rb +324 -0
- data/lib/dpl/providers/bluemixcloudfoundry.rb +98 -0
- data/lib/dpl/providers/boxfuse.rb +52 -0
- data/lib/dpl/providers/cargo.rb +32 -0
- data/lib/dpl/providers/chef_supermarket.rb +132 -0
- data/lib/dpl/providers/cloud66.rb +46 -0
- data/lib/dpl/providers/cloudfiles.rb +62 -0
- data/lib/dpl/providers/cloudformation.rb +281 -0
- data/lib/dpl/providers/cloudfoundry.rb +89 -0
- data/lib/dpl/providers/codedeploy.rb +190 -0
- data/lib/dpl/providers/convox.rb +130 -0
- data/lib/dpl/providers/datica.rb +64 -0
- data/lib/dpl/providers/ecr.rb +129 -0
- data/lib/dpl/providers/elasticbeanstalk.rb +207 -0
- data/lib/dpl/providers/engineyard.rb +113 -0
- data/lib/dpl/providers/firebase.rb +45 -0
- data/lib/dpl/providers/flynn.rb +35 -0
- data/lib/dpl/providers/gae.rb +78 -0
- data/lib/dpl/providers/gcs.rb +132 -0
- data/lib/dpl/providers/git_push.rb +273 -0
- data/lib/dpl/providers/gleis.rb +74 -0
- data/lib/dpl/providers/hackage.rb +53 -0
- data/lib/dpl/providers/hephy.rb +107 -0
- data/lib/dpl/providers/heroku/api.rb +123 -0
- data/lib/dpl/providers/heroku/git.rb +54 -0
- data/lib/dpl/providers/heroku.rb +111 -0
- data/lib/dpl/providers/lambda.rb +211 -0
- data/lib/dpl/providers/launchpad.rb +80 -0
- data/lib/dpl/providers/netlify.rb +38 -0
- data/lib/dpl/providers/npm.rb +130 -0
- data/lib/dpl/providers/nuget.rb +41 -0
- data/lib/dpl/providers/openshift.rb +52 -0
- data/lib/dpl/providers/opsworks.rb +146 -0
- data/lib/dpl/providers/packagecloud.rb_ +194 -0
- data/lib/dpl/providers/pages/api.rb +106 -0
- data/lib/dpl/providers/pages/git.rb +262 -0
- data/lib/dpl/providers/pages.rb +18 -0
- data/lib/dpl/providers/puppetforge.rb +50 -0
- data/lib/dpl/providers/pypi.rb +125 -0
- data/lib/dpl/providers/releases.rb +234 -0
- data/lib/dpl/providers/rubygems.rb +97 -0
- data/lib/dpl/providers/s3.rb +251 -0
- data/lib/dpl/providers/scalingo.rb +69 -0
- data/lib/dpl/providers/script.rb +32 -0
- data/lib/dpl/providers/snap.rb +68 -0
- data/lib/dpl/providers/surge.rb +59 -0
- data/lib/dpl/providers/testfairy.rb +101 -0
- data/lib/dpl/providers/transifex.rb +72 -0
- data/lib/dpl/providers.rb +48 -0
- data/lib/dpl/string_ext.rb +23 -0
- data/lib/dpl/support/aws_sdk_patch.rb +26 -0
- data/lib/dpl/support/gems.rb +73 -0
- data/lib/dpl/support/gstore_patch.rb +8 -0
- data/lib/dpl/support/version.rb +84 -0
- data/lib/dpl/version.rb +5 -0
- data/lib/dpl.rb +23 -0
- data/status.json +237 -0
- metadata +161 -0
data/lib/dpl/provider.rb
ADDED
|
@@ -0,0 +1,651 @@
|
|
|
1
|
+
require 'cl'
|
|
2
|
+
require 'fileutils'
|
|
3
|
+
require 'forwardable'
|
|
4
|
+
require 'shellwords'
|
|
5
|
+
require 'dpl/helper/assets'
|
|
6
|
+
require 'dpl/helper/cmd'
|
|
7
|
+
require 'dpl/helper/config_file'
|
|
8
|
+
require 'dpl/helper/env'
|
|
9
|
+
require 'dpl/helper/interpolate'
|
|
10
|
+
require 'dpl/helper/memoize'
|
|
11
|
+
require 'dpl/helper/squiggle'
|
|
12
|
+
require 'dpl/provider/dsl'
|
|
13
|
+
require 'dpl/provider/examples'
|
|
14
|
+
require 'dpl/version'
|
|
15
|
+
|
|
16
|
+
module Dpl
|
|
17
|
+
# Base class for all concrete providers that `dpl` supports.
|
|
18
|
+
#
|
|
19
|
+
# These are subclasses of `Cl::Cmd` which means they are going to be detected
|
|
20
|
+
# by the first argument passed to `dpl [provider]`, instantiated, and run.
|
|
21
|
+
#
|
|
22
|
+
# Implementors are encouraged to use the provider DSL to declare various
|
|
23
|
+
# features, requirements, and attributes that apply to their provider, to
|
|
24
|
+
# implement any of the following stages (methods) according to their needs
|
|
25
|
+
# and semantics:
|
|
26
|
+
#
|
|
27
|
+
# * init
|
|
28
|
+
# * install
|
|
29
|
+
# * login
|
|
30
|
+
# * setup
|
|
31
|
+
# * validate
|
|
32
|
+
# * prepare
|
|
33
|
+
# * deploy
|
|
34
|
+
# * finish
|
|
35
|
+
#
|
|
36
|
+
# The main logic should sit in the `deploy` stage.
|
|
37
|
+
#
|
|
38
|
+
# If at any time the method `error` is called, or any exception raised the
|
|
39
|
+
# deploy process will be halted, and subsequent stages skipped. However, the
|
|
40
|
+
# stage `finish` will run even if previous stages have raised an error,
|
|
41
|
+
# giving the provider the opportunity to potentially clean up stage.
|
|
42
|
+
#
|
|
43
|
+
# In addition to this the following methods will be called if implemented
|
|
44
|
+
# by the provider:
|
|
45
|
+
#
|
|
46
|
+
# * run_cmd
|
|
47
|
+
# * add_key
|
|
48
|
+
# * remove_key
|
|
49
|
+
#
|
|
50
|
+
# Like the `finish` stage, the method `remove_key` will be called even if
|
|
51
|
+
# previous stages have raised an error.
|
|
52
|
+
#
|
|
53
|
+
# See the respective method's documentation for details on these.
|
|
54
|
+
#
|
|
55
|
+
# The following stages are not meant to be overwritten, but considered
|
|
56
|
+
# internal:
|
|
57
|
+
#
|
|
58
|
+
# * before_install
|
|
59
|
+
# * before_setup
|
|
60
|
+
# * before_prepare
|
|
61
|
+
# * before_finish
|
|
62
|
+
#
|
|
63
|
+
# Dependencies declared as required, such as APT, NPM, or Python are going to
|
|
64
|
+
# be installed as part of the `before_install` stage .
|
|
65
|
+
#
|
|
66
|
+
# Cleanup is run as part of the `before_prepare` stage if the option
|
|
67
|
+
# `--cleanup` was given. This will use `git stash --all` in order to reset
|
|
68
|
+
# the working directory to the committed state, and cleanup any left over
|
|
69
|
+
# artifacts from the build process. Providers can use the DSL method `keep`
|
|
70
|
+
# in order to declare known artifacts (such as CLI tooling installed to the
|
|
71
|
+
# working directory) that needs to be moved out of the way and restored after
|
|
72
|
+
# the cleanup process. (It is recommended to place such artifacts outside of
|
|
73
|
+
# the build working directory though, for example in `~/.dpl`).
|
|
74
|
+
#
|
|
75
|
+
# The method `run_cmd` is called for each command specified using the `--run`
|
|
76
|
+
# option. By default, these command are going to be run as local shell
|
|
77
|
+
# commands, but providers can choose to overwrite this method in order to run
|
|
78
|
+
# the command on a remote machine.
|
|
79
|
+
#
|
|
80
|
+
# @see https://github.com/svenfuchs/cl Cl's documentation for details on how
|
|
81
|
+
# providers (commands) are declared and run.
|
|
82
|
+
|
|
83
|
+
class Provider < Cl::Cmd
|
|
84
|
+
extend Dsl, Forwardable
|
|
85
|
+
include Assets, Env, ConfigFile, FileUtils, Interpolate, Memoize, Squiggle
|
|
86
|
+
|
|
87
|
+
class << self
|
|
88
|
+
def examples
|
|
89
|
+
@examples ||= super || Examples.new(self).cmds
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def move_files(ctx)
|
|
93
|
+
ctx.move_files(move) if move.any?
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def unmove_files(ctx)
|
|
97
|
+
ctx.unmove_files(move) if move.any?
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def install_deps?
|
|
101
|
+
apt? || gem? || npm? || pip?
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def install_deps(ctx)
|
|
105
|
+
ctx.apts_get(apt) if apt?
|
|
106
|
+
ctx.gems_require(gem) if gem?
|
|
107
|
+
npm.each { |npm| ctx.npm_install *npm } if npm?
|
|
108
|
+
pip.each { |pip| ctx.pip_install *pip } if pip?
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def validate_runtimes(ctx)
|
|
112
|
+
ctx.validate_runtimes(runtimes) if runtimes.any?
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Fold names to display in the build log.
|
|
117
|
+
FOLDS = {
|
|
118
|
+
init: 'Initialize deployment',
|
|
119
|
+
setup: 'Setup deployment',
|
|
120
|
+
validate: 'Validate deployment',
|
|
121
|
+
install: 'Install deployment dependencies',
|
|
122
|
+
login: 'Authenticate deployment',
|
|
123
|
+
prepare: 'Prepare deployment',
|
|
124
|
+
deploy: 'Run deployment',
|
|
125
|
+
finish: 'Finish deployment',
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
# Deployment process stages.
|
|
129
|
+
#
|
|
130
|
+
# In addition to the stages listed here the stage `finish` will be run at
|
|
131
|
+
# the end of the process.
|
|
132
|
+
#
|
|
133
|
+
# Also, the methods `add_key` (called before `setup`), `remove_key` (called
|
|
134
|
+
# before `finish`), and `run_cmd` (called after `deploy`) may be of
|
|
135
|
+
# interest to implementors.
|
|
136
|
+
STAGES = %i(
|
|
137
|
+
init
|
|
138
|
+
install
|
|
139
|
+
login
|
|
140
|
+
setup
|
|
141
|
+
validate
|
|
142
|
+
prepare
|
|
143
|
+
deploy
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
abstract
|
|
147
|
+
|
|
148
|
+
opt '--cleanup', 'Clean up build artifacts from the Git working directory before the deployment', negate: %w(skip)
|
|
149
|
+
opt '--run CMD', 'Commands to execute after the deployment finished successfully', type: :array
|
|
150
|
+
opt '--stage NAME', 'Execute the given stage(s) only', type: :array, internal: true, default: STAGES
|
|
151
|
+
opt '--backtrace', 'Print the backtrace for exceptions', internal: true
|
|
152
|
+
opt '--fold', 'Wrap log output in folds', internal: true
|
|
153
|
+
opt '--edge', internal: true
|
|
154
|
+
|
|
155
|
+
vars *%i(
|
|
156
|
+
git_author_email
|
|
157
|
+
git_author_name
|
|
158
|
+
git_branch
|
|
159
|
+
git_commit_author
|
|
160
|
+
git_commit_msg
|
|
161
|
+
git_sha
|
|
162
|
+
git_tag
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
msgs before_install: 'Installing deployment dependencies',
|
|
166
|
+
before_setup: 'Setting the build environment up for the deployment',
|
|
167
|
+
setup_git_ssh: 'Setting up git-ssh',
|
|
168
|
+
cleanup: 'Cleaning up git repository with `git stash --all`',
|
|
169
|
+
ssh_keygen: 'Generating SSH key',
|
|
170
|
+
setup_git_ua: 'Setting up git HTTP user agent',
|
|
171
|
+
ssh_remote_host: 'SSH remote is %s at port %s',
|
|
172
|
+
ssh_try_connect: 'Waiting for SSH connection ...',
|
|
173
|
+
ssh_connected: 'SSH connection established.',
|
|
174
|
+
ssh_failed: 'Failed to establish SSH connection.'
|
|
175
|
+
|
|
176
|
+
def_delegators :'self.class', :status, :full_name, :install_deps,
|
|
177
|
+
:install_deps?, :keep, :move_files, :unmove_files, :needs?, :runtimes,
|
|
178
|
+
:validate_runtimes, :user_agent
|
|
179
|
+
|
|
180
|
+
def_delegators :ctx, :apt_get, :gem_require, :npm_install, :pip_install,
|
|
181
|
+
:build_dir, :build_number, :encoding, :file_size, :git_author_email,
|
|
182
|
+
:git_author_name, :git_branch, :git_branch, :git_commit_author,
|
|
183
|
+
:git_commit_msg, :git_commit_msg, :git_dirty?, :git_log, :git_log,
|
|
184
|
+
:git_ls_files, :git_ls_remote?, :git_remote_urls, :git_remote_urls,
|
|
185
|
+
:git_rev_parse, :git_rev_parse, :git_sha, :git_tag, :last_err, :last_out,
|
|
186
|
+
:last_out, :logger, :machine_name, :mv, :node_version, :node_version,
|
|
187
|
+
:npm_version, :rendezvous, :rendezvous, :repo_slug, :sleep, :sleep,
|
|
188
|
+
:ssh_keygen, :success?, :test?, :test?, :tmp_dir, :tty?, :which, :which,
|
|
189
|
+
:write_file, :write_netrc
|
|
190
|
+
|
|
191
|
+
attr_reader :repo_name, :key_name
|
|
192
|
+
|
|
193
|
+
def initialize(ctx, *args)
|
|
194
|
+
@repo_name = ctx.repo_name
|
|
195
|
+
@key_name = ctx.machine_name
|
|
196
|
+
super
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# Runs all stages, all commands provided by the user, as well as the final
|
|
200
|
+
# stage `finish` (which will be run even if an error has been raised during
|
|
201
|
+
# previous stages).
|
|
202
|
+
def run
|
|
203
|
+
stages = stage.select { |stage| run_stage?(stage) }
|
|
204
|
+
stages.each { |stage| run_stage(stage) }
|
|
205
|
+
run_cmds
|
|
206
|
+
rescue Error
|
|
207
|
+
raise
|
|
208
|
+
rescue Exception => e
|
|
209
|
+
raise Error.new("#{e.message} (#{e.class})", backtrace: backtrace? ? e.backtrace : nil) unless test?
|
|
210
|
+
raise
|
|
211
|
+
ensure
|
|
212
|
+
run_stage(:finish, fold: false) if finish?
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# Whether or not a stage needs to be run
|
|
216
|
+
def run_stage?(stage)
|
|
217
|
+
respond_to?(:"before_#{stage}") || respond_to?(stage)
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def finish?
|
|
221
|
+
stage.size == STAGES.size
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# Runs a single stage.
|
|
225
|
+
#
|
|
226
|
+
# For each stage the base class has the opportunity to implement a `before`
|
|
227
|
+
# stage method, in order to apply default behaviour. Provider implementors
|
|
228
|
+
# are asked to not overwrite these methods.
|
|
229
|
+
#
|
|
230
|
+
# Any log output from both the before stage and stage method is going to be
|
|
231
|
+
# folded in the resulting build log.
|
|
232
|
+
def run_stage(stage, opts = {})
|
|
233
|
+
fold(stage, opts) do
|
|
234
|
+
send(:"before_#{stage}") if respond_to?(:"before_#{stage}")
|
|
235
|
+
send(stage) if respond_to?(stage)
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# Initialize the deployment process.
|
|
240
|
+
#
|
|
241
|
+
# This will:
|
|
242
|
+
#
|
|
243
|
+
# * Displays warning messages about the provider's maturity status, and deprecated
|
|
244
|
+
# options used.
|
|
245
|
+
# * Setup a ~/.dpl working directory
|
|
246
|
+
# * Move files out of the way that have been declared as such
|
|
247
|
+
def before_init
|
|
248
|
+
warn status.msg if status && status.announce?
|
|
249
|
+
deprecations.each { |(key, msg)| ctx.deprecate_opt(key, msg) }
|
|
250
|
+
setup_dpl_dir
|
|
251
|
+
move_files(ctx)
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
# Install APT, NPM, and Python dependencies as declared by the provider.
|
|
255
|
+
def before_install
|
|
256
|
+
validate_runtimes(ctx)
|
|
257
|
+
return unless install_deps?
|
|
258
|
+
info :before_install
|
|
259
|
+
install_deps(ctx)
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
# Sets the build environment up for the deployment.
|
|
263
|
+
#
|
|
264
|
+
# This will:
|
|
265
|
+
#
|
|
266
|
+
# * Setup a ~/.dpl working directory
|
|
267
|
+
# * Create a temporary, per build SSH key, and call `add_key` if the feature `ssh_key` has been declared as required.
|
|
268
|
+
# * Setup git config (email and user name) if the feature `git` has been declared as required.
|
|
269
|
+
# * Either set or unset the environment variable `GIT_HTTP_USER_AGENT` depending if the feature `git_http_user_agent` has been declared as required.
|
|
270
|
+
def before_setup
|
|
271
|
+
info :before_setup
|
|
272
|
+
setup_ssh_key if needs?(:ssh_key)
|
|
273
|
+
setup_git_config if needs?(:git)
|
|
274
|
+
setup_git_http_user_agent
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# Prepares the deployment by cleaning up the working directory.
|
|
278
|
+
#
|
|
279
|
+
# @see Provider#cleanup
|
|
280
|
+
def before_prepare
|
|
281
|
+
cleanup if cleanup?
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
# Runs each command as given by the user using the `--run` option.
|
|
285
|
+
#
|
|
286
|
+
# For a command that matches `restart` the method `restart` will be called
|
|
287
|
+
# (which can be overwritten by providers, e.g. in order to restart service
|
|
288
|
+
# instances).
|
|
289
|
+
#
|
|
290
|
+
# All other commands will be passed to the method `run_cmd`. By default this
|
|
291
|
+
# will be run as a shell command locally, but providers can choose to
|
|
292
|
+
# overwrite this method in order to run the command on a remote machine.
|
|
293
|
+
def run_cmds
|
|
294
|
+
Array(opts[:run]).each do |cmd|
|
|
295
|
+
cmd.downcase == 'restart' ? restart : run_cmd(cmd)
|
|
296
|
+
end
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
def run_cmd(cmd)
|
|
300
|
+
cmd.downcase == 'restart' ? restart : shell(cmd)
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
# Finalizes the deployment process.
|
|
304
|
+
#
|
|
305
|
+
# This will:
|
|
306
|
+
#
|
|
307
|
+
# * Call the method `remove_key` if implemented by the provider, and if the
|
|
308
|
+
# feature `ssh_key` has been declared as required.
|
|
309
|
+
# * Revert the cleanup process, i.e. restore files moved out of the way
|
|
310
|
+
# during `cleanup`.
|
|
311
|
+
# * Remove the temporary directory `~/.dpl`
|
|
312
|
+
def before_finish
|
|
313
|
+
remove_key if needs?(:ssh_key) && respond_to?(:remove_key)
|
|
314
|
+
uncleanup if cleanup?
|
|
315
|
+
unmove_files(ctx)
|
|
316
|
+
remove_dpl_dir
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
# Resets the current working directory to the commited state.
|
|
320
|
+
#
|
|
321
|
+
# Cleanup will use `git stash --all` in order to reset the working
|
|
322
|
+
# directory to the committed state, and cleanup any left over artifacts
|
|
323
|
+
# from the build process. Providers can use the DSL method `keep` in order
|
|
324
|
+
# to declare known artifacts (such as CLI tooling installed to the working
|
|
325
|
+
# directory) that needs to be moved out of the way and restored after the
|
|
326
|
+
# cleanup process.
|
|
327
|
+
def cleanup
|
|
328
|
+
info :cleanup
|
|
329
|
+
keep.each { |path| shell "mv ./#{path} ~/#{path}", echo: false, assert: false }
|
|
330
|
+
shell 'git stash --all'
|
|
331
|
+
keep.each { |path| shell "mv ~/#{path} ./#{path}", echo: false, assert: false }
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
# Restore files that have been cleaned up.
|
|
335
|
+
def uncleanup
|
|
336
|
+
shell 'git stash pop', assert: false
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
# Creates the directory `~/.dpl` as an internal working directory.
|
|
340
|
+
def setup_dpl_dir
|
|
341
|
+
rm_rf '~/.dpl'
|
|
342
|
+
mkdir_p '~/.dpl'
|
|
343
|
+
chmod 0700, '~/.dpl'
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
# Remove the internal working directory `~/.dpl`.
|
|
347
|
+
def remove_dpl_dir
|
|
348
|
+
rm_rf '~/.dpl'
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
# Creates an SSH key, and sets up git-ssh if needed.
|
|
352
|
+
#
|
|
353
|
+
# This will:
|
|
354
|
+
#
|
|
355
|
+
# * Create a temporary, per build SSH key.
|
|
356
|
+
# * Setup a `git-ssh` executable to use that key.
|
|
357
|
+
# * Call the method `add_key` if implemented by the provider.
|
|
358
|
+
def setup_ssh_key
|
|
359
|
+
ssh_keygen(key_name, '~/.dpl/id_rsa')
|
|
360
|
+
setup_git_ssh('~/.dpl/id_rsa')
|
|
361
|
+
add_key('~/.dpl/id_rsa.pub') if respond_to?(:add_key)
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
# Setup git config
|
|
365
|
+
#
|
|
366
|
+
# This adds the current user's name and email address (as user@localhost)
|
|
367
|
+
# to the git config.
|
|
368
|
+
def setup_git_config
|
|
369
|
+
shell "git config user.email >/dev/null 2>/dev/null || git config user.email `whoami`@localhost", echo: false, assert: false
|
|
370
|
+
shell "git config user.name >/dev/null 2>/dev/null || git config user.name `whoami`", echo: false, assert: false
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
# Sets up `git-ssh` and the GIT_SSH env var
|
|
374
|
+
def setup_git_ssh(key)
|
|
375
|
+
info :setup_git_ssh
|
|
376
|
+
path, conf = '~/.dpl/git-ssh', asset(:dpl, :git_ssh).read % expand(key)
|
|
377
|
+
open(path, 'w+') { |file| file.write(conf) }
|
|
378
|
+
chmod(0740, path)
|
|
379
|
+
ENV['GIT_SSH'] = expand(path)
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
# Generates an SSH key.
|
|
383
|
+
def ssh_keygen(key, path)
|
|
384
|
+
info :ssh_keygen
|
|
385
|
+
ctx.ssh_keygen(key, expand(path))
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
# Sets or unsets the environment variable `GIT_HTTP_USER_AGENT`.
|
|
389
|
+
def setup_git_http_user_agent
|
|
390
|
+
return ENV.delete('GIT_HTTP_USER_AGENT') unless needs?(:git_http_user_agent)
|
|
391
|
+
info :setup_git_ua
|
|
392
|
+
ENV['GIT_HTTP_USER_AGENT'] = user_agent(git: `git --version`[/[\d\.]+/])
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
# Waits for SSH access on the given host and port.
|
|
396
|
+
#
|
|
397
|
+
# This will try to connect to the given SSH host and port, and keep
|
|
398
|
+
# retrying 30 times, waiting a second inbetween retries.
|
|
399
|
+
def wait_for_ssh_access(host, port)
|
|
400
|
+
info :ssh_remote_host, host, port
|
|
401
|
+
1.upto(20) { try_ssh_access(host, port) && break || sleep(3) }
|
|
402
|
+
success? ? info(:ssh_connected) : error(:ssh_failed)
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
# Tries to connect to the given SSH host and port.
|
|
406
|
+
def try_ssh_access(host, port)
|
|
407
|
+
info :ssh_try_connect
|
|
408
|
+
shell "#{ENV['GIT_SSH']} #{host} -p #{port} 2>&1 | grep -c 'PTY allocation request failed' > /dev/null", echo: false, assert: false
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
# Creates a log fold.
|
|
412
|
+
#
|
|
413
|
+
# Folds any log output from the given block into a fold with the given
|
|
414
|
+
# name.
|
|
415
|
+
def fold(name, opts = {}, &block)
|
|
416
|
+
return yield unless fold?(name, opts)
|
|
417
|
+
title = FOLDS[name] || "deploy.#{name}"
|
|
418
|
+
ctx.fold(title, &block)
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
# Checks if the given stage needs to be folded.
|
|
422
|
+
#
|
|
423
|
+
# Depends on the option `--fold`, also omits folds for the init and finish
|
|
424
|
+
# stages. Can be overwritten by passing `fold: false`.
|
|
425
|
+
def fold?(name, opts = {})
|
|
426
|
+
!opts[:fold].is_a?(FalseClass) && super() && !%i(init).include?(name)
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
# Runs a script as a shell command.
|
|
430
|
+
#
|
|
431
|
+
# Scripts can be stored as separate files (assets) in the directory
|
|
432
|
+
# `lib/dpl/assets/[provider]`.
|
|
433
|
+
#
|
|
434
|
+
# This is meant for large shell commands that would be hard to read if
|
|
435
|
+
# embedded in Ruby code. Storing them as separate files helps with proper
|
|
436
|
+
# syntax highlighting etc in editors, and allows to execute them for
|
|
437
|
+
# testing purposes.
|
|
438
|
+
#
|
|
439
|
+
# Scripts can have interpolation variables. See Dpl::Interpolate for
|
|
440
|
+
# details on interpolating variables.
|
|
441
|
+
#
|
|
442
|
+
# See Ctx::Bash#shell for details on the options accepted.
|
|
443
|
+
def script(name, opts = {})
|
|
444
|
+
opts[:assert] = name if opts[:assert].is_a?(TrueClass)
|
|
445
|
+
shell(asset(name).read, opts.merge(echo: false))
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
# Runs a single shell command.
|
|
449
|
+
#
|
|
450
|
+
# Shell commands can have interpolation variables. See Dpl::Interpolate for
|
|
451
|
+
# details on interpolating variables.
|
|
452
|
+
#
|
|
453
|
+
# See Ctx::Bash#shell for details on the options accepted.
|
|
454
|
+
def shell(cmd, *args)
|
|
455
|
+
opts = args.last.is_a?(Hash) ? args.pop : {}
|
|
456
|
+
cmd = Cmd.new(self, cmd, opts)
|
|
457
|
+
ctx.shell(cmd)
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
# @!method print
|
|
461
|
+
# Prints a partial message to stdout
|
|
462
|
+
#
|
|
463
|
+
# This method does not append a newline character to the given message,
|
|
464
|
+
# which usually is not the desired behaviour. The method is intended to be
|
|
465
|
+
# used if an initial, partial message is supposed to be printed, which will
|
|
466
|
+
# be completed later (using the method `info`).
|
|
467
|
+
#
|
|
468
|
+
# For example:
|
|
469
|
+
#
|
|
470
|
+
# print 'Starting a long running task ...'
|
|
471
|
+
# run_long_running_task
|
|
472
|
+
# info 'done.'
|
|
473
|
+
#
|
|
474
|
+
# Messages support interpolation variables. See Dpl::Interpolate for
|
|
475
|
+
# details on interpolating variables.
|
|
476
|
+
|
|
477
|
+
# @!method info
|
|
478
|
+
# Outputs an info message to stdout
|
|
479
|
+
#
|
|
480
|
+
# This method is intended to be used for default, info level messages that
|
|
481
|
+
# are supposed to show up in the build log.
|
|
482
|
+
#
|
|
483
|
+
# @!method warn
|
|
484
|
+
# Outputs an warning message to stderr
|
|
485
|
+
#
|
|
486
|
+
# This method is intended to be used for warning messages that are supposed
|
|
487
|
+
# to show up in the build log, but do not qualify as errors that would
|
|
488
|
+
# abort the deployment process. The warning will be highlighted as red
|
|
489
|
+
# text. Use sparingly.
|
|
490
|
+
#
|
|
491
|
+
# Messages support interpolation variables. See Dpl::Interpolate for
|
|
492
|
+
# details on interpolating variables.
|
|
493
|
+
|
|
494
|
+
# @!method error
|
|
495
|
+
# Outputs an error message to stderr, and raises an error, halting the
|
|
496
|
+
# deployment process.
|
|
497
|
+
#
|
|
498
|
+
# This method is intended to be used for all error conditions that require
|
|
499
|
+
# the deployment process to be aborted.
|
|
500
|
+
#
|
|
501
|
+
# Messages support interpolation variables. See Dpl::Interpolate for
|
|
502
|
+
# details on interpolating variables.
|
|
503
|
+
%i(print info warn error).each do |level|
|
|
504
|
+
define_method(level) do |msg, *args|
|
|
505
|
+
msg = interpolate(self.msg(msg), args) if msg.is_a?(Symbol)
|
|
506
|
+
ctx.send(level, msg)
|
|
507
|
+
end
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
# @!method cmd
|
|
511
|
+
# Looks up a shell command from the commands declared by the provider
|
|
512
|
+
# (using the class level DSL).
|
|
513
|
+
#
|
|
514
|
+
# Not usually useful to be used by provider implementors directly. Use the
|
|
515
|
+
# method `shell` in order to execute shell commands.
|
|
516
|
+
|
|
517
|
+
# @!method err
|
|
518
|
+
# Looks up an error message from the error messages declared by the
|
|
519
|
+
# provider (using the class level DSL), as needed by the option `assert`
|
|
520
|
+
# when passed to the method `shell`.
|
|
521
|
+
|
|
522
|
+
# @!method msg
|
|
523
|
+
# Looks up a message from the messages declared by the provider (using the
|
|
524
|
+
# class level DSL).
|
|
525
|
+
#
|
|
526
|
+
# For example, a message declared on the class body like so:
|
|
527
|
+
#
|
|
528
|
+
# ```ruby
|
|
529
|
+
# msgs commit_msg: 'Commit build artifacts on build %{build_number}'
|
|
530
|
+
# ```
|
|
531
|
+
#
|
|
532
|
+
# could be used by the implementation like so:
|
|
533
|
+
#
|
|
534
|
+
# ```ruby
|
|
535
|
+
# def commit_msg
|
|
536
|
+
# interpolate(msg(:commit_msg))
|
|
537
|
+
# end
|
|
538
|
+
# ```
|
|
539
|
+
#
|
|
540
|
+
# Note that the the method `interpolate` needs to be used in order to
|
|
541
|
+
# interpolate variables used in a message (if any).
|
|
542
|
+
%i(cmd err msg str).each do |name|
|
|
543
|
+
define_method(name) do |*keys|
|
|
544
|
+
key = keys.detect { |key| key.is_a?(Symbol) }
|
|
545
|
+
self.class.send(:"#{name}s")[key] if key
|
|
546
|
+
end
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
# Escapes the given string so it can be safely used in Bash.
|
|
550
|
+
def escape(str)
|
|
551
|
+
Shellwords.escape(str)
|
|
552
|
+
end
|
|
553
|
+
|
|
554
|
+
# Double quotes the given string.
|
|
555
|
+
def quote(str)
|
|
556
|
+
%("#{str.to_s.gsub('"', '\"')}")
|
|
557
|
+
end
|
|
558
|
+
|
|
559
|
+
# Outdents the given string.
|
|
560
|
+
#
|
|
561
|
+
# @see Dpl::Squiggle
|
|
562
|
+
def sq(str)
|
|
563
|
+
self.class.sq(str)
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
# Generate shell option strings to be passed to a shell command.
|
|
567
|
+
#
|
|
568
|
+
# This generates strings like `--key="value"` for the option keys passed.
|
|
569
|
+
# These keys are supposed to correspond to methods on the provider
|
|
570
|
+
# instance, which will be called in order to determine the option value.
|
|
571
|
+
#
|
|
572
|
+
# If the returned value is an array then the option will be repeated
|
|
573
|
+
# multiple times. If it is a String then it will be double quoted.
|
|
574
|
+
# Otherwise it is assumed to be a flag that does not have a value.
|
|
575
|
+
#
|
|
576
|
+
# @option prefix [String] Use this to set a single dash as an option prefix (defaults to two dashes).
|
|
577
|
+
# @option dashed [Boolean] Use this to dasherize the option key (rather than underscore it, defaults to underscore).
|
|
578
|
+
def opts_for(keys, opts = {})
|
|
579
|
+
strs = Array(keys).map { |key| opt_for(key, opts) if send(:"#{key}?") }.compact
|
|
580
|
+
strs.join(' ') if strs.any?
|
|
581
|
+
end
|
|
582
|
+
|
|
583
|
+
def opt_for(key, opts = {})
|
|
584
|
+
case value = send(key)
|
|
585
|
+
when String then "#{opt_key(key, opts)}=#{value.inspect}"
|
|
586
|
+
when Array then value.map { |value| "#{opt_key(key, opts)}=#{value.inspect}" }
|
|
587
|
+
else opt_key(key, opts)
|
|
588
|
+
end
|
|
589
|
+
end
|
|
590
|
+
|
|
591
|
+
def opt_key(key, opts)
|
|
592
|
+
"#{opts[:prefix] || '--'}#{opts[:dashed] ? key.to_s.gsub('_', '-') : key}"
|
|
593
|
+
end
|
|
594
|
+
|
|
595
|
+
# Compacts the given hash by rejecting nil values.
|
|
596
|
+
def compact(hash)
|
|
597
|
+
hash.reject { |_, value| value.nil? }
|
|
598
|
+
end
|
|
599
|
+
|
|
600
|
+
# Returns a new hash with the given keys selected from the given hash.
|
|
601
|
+
def only(hash, *keys)
|
|
602
|
+
hash.select { |key, _| keys.include?(key) }
|
|
603
|
+
end
|
|
604
|
+
|
|
605
|
+
# Deep symbolizes the given hash's keys
|
|
606
|
+
def symbolize(obj)
|
|
607
|
+
case obj
|
|
608
|
+
when Hash
|
|
609
|
+
obj.map { |key, obj| [key.to_sym, symbolize(obj)] }.to_h
|
|
610
|
+
when Array
|
|
611
|
+
obj.map { |obj| symbolize(obj) }
|
|
612
|
+
else
|
|
613
|
+
obj
|
|
614
|
+
end
|
|
615
|
+
end
|
|
616
|
+
|
|
617
|
+
def file?(path)
|
|
618
|
+
File.file?(expand(path))
|
|
619
|
+
end
|
|
620
|
+
|
|
621
|
+
def mkdir_p(path)
|
|
622
|
+
FileUtils.mkdir_p(expand(path))
|
|
623
|
+
end
|
|
624
|
+
|
|
625
|
+
def chmod(perm, path)
|
|
626
|
+
super(perm, expand(path))
|
|
627
|
+
end
|
|
628
|
+
|
|
629
|
+
def mv(src, dest)
|
|
630
|
+
super(expand(src), expand(dest))
|
|
631
|
+
end
|
|
632
|
+
|
|
633
|
+
def rm_rf(path)
|
|
634
|
+
super(expand(path))
|
|
635
|
+
end
|
|
636
|
+
|
|
637
|
+
def open(path, *args, &block)
|
|
638
|
+
File.open(expand(path), *args, &block)
|
|
639
|
+
end
|
|
640
|
+
|
|
641
|
+
def read(path)
|
|
642
|
+
File.read(expand(path))
|
|
643
|
+
end
|
|
644
|
+
|
|
645
|
+
def expand(*args)
|
|
646
|
+
File.expand_path(*args)
|
|
647
|
+
end
|
|
648
|
+
end
|
|
649
|
+
end
|
|
650
|
+
|
|
651
|
+
require 'dpl/providers'
|