travis_dpl_test 2.0.3.beta.4.ror
Sign up to get free protection for your applications and to get access to all the features.
- 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/ctx/bash.rb
ADDED
@@ -0,0 +1,549 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'English'
|
4
|
+
require 'cl'
|
5
|
+
require 'fileutils'
|
6
|
+
require 'logger'
|
7
|
+
require 'open3'
|
8
|
+
require 'tmpdir'
|
9
|
+
require 'securerandom'
|
10
|
+
require 'dpl/support/version'
|
11
|
+
|
12
|
+
module Dpl
|
13
|
+
module Ctx
|
14
|
+
class Bash < Cl::Ctx
|
15
|
+
include FileUtils
|
16
|
+
|
17
|
+
attr_accessor :folds, :stdout, :stderr, :last_out, :last_err
|
18
|
+
|
19
|
+
def initialize(stdout = $stdout, stderr = $stderr)
|
20
|
+
@stdout = stdout
|
21
|
+
@stderr = stderr
|
22
|
+
@folds = 0
|
23
|
+
super('dpl', abort: false)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Folds any log output from the given block
|
27
|
+
#
|
28
|
+
# Starts a log fold with the given fold message, calls the block, and
|
29
|
+
# closes the fold.
|
30
|
+
#
|
31
|
+
# @param msg [String] the message that will appear on the log fold
|
32
|
+
def fold(msg)
|
33
|
+
self.folds += 1
|
34
|
+
print "travis_fold:start:dpl.#{folds}\r\e[K"
|
35
|
+
time do
|
36
|
+
info "\e[33m#{msg}\e[0m"
|
37
|
+
yield
|
38
|
+
end
|
39
|
+
ensure
|
40
|
+
print "\ntravis_fold:end:dpl.#{folds}\r\e[K"
|
41
|
+
end
|
42
|
+
|
43
|
+
# Times the given block
|
44
|
+
#
|
45
|
+
# Starts a travis time log tag, calls the block, and closes the tag,
|
46
|
+
# including timing information. This makes a timing badge appear on
|
47
|
+
# the surrounding log fold.
|
48
|
+
def time
|
49
|
+
id = SecureRandom.hex[0, 8]
|
50
|
+
start = Time.now.to_i * (10**9)
|
51
|
+
print "travis_time:start:#{id}\r\e[K"
|
52
|
+
yield
|
53
|
+
ensure
|
54
|
+
finish = Time.now.to_i * (10**9)
|
55
|
+
duration = finish - start
|
56
|
+
print "\ntravis_time:end:#{id}:start=#{start},finish=#{finish},duration=#{duration}\r\e[K"
|
57
|
+
end
|
58
|
+
|
59
|
+
# Outputs a deprecation warning for a given deprecated option key to stderr.
|
60
|
+
#
|
61
|
+
# @param key [Symbol] the deprecated option key
|
62
|
+
# @param msg [String or Symbol] the deprecation message. if given a Symbol this will be wrapped into the string "Please use #{symbol}".
|
63
|
+
def deprecate_opt(key, msg)
|
64
|
+
msg = "please use #{msg}" if msg.is_a?(Symbol)
|
65
|
+
warn "Deprecated option #{key} used (#{msg})."
|
66
|
+
end
|
67
|
+
|
68
|
+
# Outputs an info level message to stdout.
|
69
|
+
def info(*msgs)
|
70
|
+
stdout.puts(*msgs)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Prints an info level message to stdout.
|
74
|
+
#
|
75
|
+
# This method does not append a newline character to the given message,
|
76
|
+
# which usually is not the desired behaviour. The method is intended to
|
77
|
+
# be used if an initial, partial message is supposed to be printed, which
|
78
|
+
# will be completed later (using the method `info`).
|
79
|
+
#
|
80
|
+
# For example:
|
81
|
+
#
|
82
|
+
# print 'Starting a long running task ...'
|
83
|
+
# run_long_running_task
|
84
|
+
# info 'done.'
|
85
|
+
def print(chars)
|
86
|
+
stdout.print(chars)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Outputs an warning message to stderr
|
90
|
+
#
|
91
|
+
# This method is intended to be used for warning messages that are
|
92
|
+
# supposed to show up in the build log, but do not qualify as errors that
|
93
|
+
# would abort the deployment process. The warning will be highlighted as
|
94
|
+
# yellow text. Use sparingly.
|
95
|
+
def warn(*msgs)
|
96
|
+
msgs = msgs.join("\n").lines
|
97
|
+
msgs.each { |msg| stderr.puts("\e[33;1m#{msg}\e[0m") }
|
98
|
+
end
|
99
|
+
|
100
|
+
# Raises an exception, halting the deployment process.
|
101
|
+
#
|
102
|
+
# The calling executable `bin/dpl` will catch the exception, and abort
|
103
|
+
# the ruby process with the given error message.
|
104
|
+
#
|
105
|
+
# This method is intended to be used for all error conditions that
|
106
|
+
# require the deployment process to be aborted.
|
107
|
+
def error(message)
|
108
|
+
raise Error, message
|
109
|
+
end
|
110
|
+
|
111
|
+
# Returns a logger
|
112
|
+
#
|
113
|
+
# Returns a logger instance, with the given log level set. This can be
|
114
|
+
# used to pass to clients that accept a Ruby logger, such as Faraday,
|
115
|
+
# for debugging purposes.
|
116
|
+
#
|
117
|
+
# Use with care.
|
118
|
+
#
|
119
|
+
# @param level [Symbol] the Ruby logger log level
|
120
|
+
def logger(level = :info)
|
121
|
+
logger = Logger.new(stderr)
|
122
|
+
logger.level = Logger.const_get(level.to_s.upcase)
|
123
|
+
logger
|
124
|
+
end
|
125
|
+
|
126
|
+
def validate_runtimes(runtimes)
|
127
|
+
failed = runtimes.reject(&method(:validate_runtime))
|
128
|
+
failed = failed.map { |name, versions| "#{name} (#{versions.join(', ')})" }
|
129
|
+
error "Failed validating runtimes: #{failed.join(', ')}" if failed.any?
|
130
|
+
end
|
131
|
+
|
132
|
+
def validate_runtime(args)
|
133
|
+
name, required = *args
|
134
|
+
info "Validating required runtime version: #{name} (#{required.join(', ')})"
|
135
|
+
version = name == :node_js ? node_version : python_version
|
136
|
+
required.all? { |required| Version.new(version).satisfies?(required) }
|
137
|
+
end
|
138
|
+
|
139
|
+
def apts_get(packages)
|
140
|
+
packages = packages.reject { |name, cmd = name| which(cmd || name) }
|
141
|
+
return unless packages.any?
|
142
|
+
|
143
|
+
apt_update
|
144
|
+
packages.each { |package, cmd| apt_get(package, cmd || package, update: false) }
|
145
|
+
end
|
146
|
+
|
147
|
+
# Installs an APT package
|
148
|
+
#
|
149
|
+
# Installs the APT package with the given name, unless the command is already
|
150
|
+
# available (as determined by `which [cmd]`.
|
151
|
+
#
|
152
|
+
# @param package [String] the package name
|
153
|
+
# @param cmd [String] an executable installed by the package, defaults to the package name
|
154
|
+
def apt_get(package, cmd = package, opts = {})
|
155
|
+
return if which(cmd)
|
156
|
+
|
157
|
+
apt_update unless opts[:update].is_a?(FalseClass)
|
158
|
+
shell "sudo apt-get -qq install #{package}", retry: true
|
159
|
+
end
|
160
|
+
|
161
|
+
def apt_update
|
162
|
+
shell 'sudo apt-get update', retry: true
|
163
|
+
end
|
164
|
+
|
165
|
+
# Requires source files from Ruby gems, installing them on demand if required
|
166
|
+
#
|
167
|
+
# Installs the Ruby gems with the given version, if not already installed, and
|
168
|
+
# requires the specified source files from that gem.
|
169
|
+
#
|
170
|
+
# This happens using the bundler/inline API.
|
171
|
+
#
|
172
|
+
# @param gems [Array<String, String, Hash>] Array of gem requirements: gem name, version, and options (`require`: A single path or a list of paths to source files to require from this Ruby gem)
|
173
|
+
#
|
174
|
+
# @see https://bundler.io/v2.0/guides/bundler_in_a_single_file_ruby_script.html
|
175
|
+
def gems_require(gems)
|
176
|
+
# A local Gemfile.lock might interfer with bundler/inline, even though
|
177
|
+
# it should not. Switching to a temporary dir fixes this.
|
178
|
+
Dir.chdir(tmp_dir) do
|
179
|
+
require 'bundler/inline'
|
180
|
+
info "Installing gem dependencies: #{gems.map { |name, version, _| "#{name} #{"(#{version})" if version}".strip }.join(', ')}"
|
181
|
+
env = ENV.to_h
|
182
|
+
# Bundler.reset!
|
183
|
+
# Gem.loaded_specs.clear
|
184
|
+
gemfile do
|
185
|
+
source 'https://rubygems.org'
|
186
|
+
gems.each { |g| gem(*g) }
|
187
|
+
end
|
188
|
+
# https://github.com/bundler/bundler/issues/7181
|
189
|
+
ENV.replace(env)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# Installs an NPM package
|
194
|
+
#
|
195
|
+
# Installs the NPM package with the given name, unless the command is already
|
196
|
+
# available (as determined by `which [cmd]`.
|
197
|
+
#
|
198
|
+
# @param package [String] the package name
|
199
|
+
# @param cmd [String] an executable installed by the package, defaults to the package name
|
200
|
+
def npm_install(package, cmd = package)
|
201
|
+
shell "npm install -g #{package}", retry: true unless which(cmd)
|
202
|
+
end
|
203
|
+
|
204
|
+
# Installs a Python package
|
205
|
+
#
|
206
|
+
# Installs the Python package with the given name. A previously installed
|
207
|
+
# package is uninstalled before that, but only if `version` was given.
|
208
|
+
#
|
209
|
+
# @param package [String] Package name (required).
|
210
|
+
# @param cmd [String] Executable command installed by that package (optional, defaults to the package name).
|
211
|
+
# @param version [String] Package version (optional).
|
212
|
+
def pip_install(package, cmd = package, version = nil)
|
213
|
+
ENV['VIRTUAL_ENV'] = File.expand_path('~/dpl_venv')
|
214
|
+
ENV['PATH'] = File.expand_path("~/dpl_venv/bin:#{ENV['PATH']}")
|
215
|
+
shell 'virtualenv --no-site-packages ~/dpl_venv', echo: true
|
216
|
+
shell 'pip install urllib3[secure]'
|
217
|
+
cmd = "pip install #{package}"
|
218
|
+
cmd << pip_version(version) if version
|
219
|
+
shell cmd, retry: true
|
220
|
+
end
|
221
|
+
|
222
|
+
def pip_version(version)
|
223
|
+
version =~ /^\d+/ ? "==#{version}" : version
|
224
|
+
end
|
225
|
+
|
226
|
+
# Generates an SSH key
|
227
|
+
#
|
228
|
+
# @param name [String] the key name
|
229
|
+
# @param file [String] path to the key file
|
230
|
+
def ssh_keygen(name, file)
|
231
|
+
shell %(ssh-keygen -t rsa -N "" -C #{name} -f #{file})
|
232
|
+
end
|
233
|
+
|
234
|
+
# Runs a single shell command
|
235
|
+
#
|
236
|
+
# This the is the central point of executing any shell commands. It allows two
|
237
|
+
# strategies for running commands in subprocesses:
|
238
|
+
#
|
239
|
+
# * Using [Kernel#system](https://ruby-doc.org/core-2.6.3/Kernel.html#method-i-system)
|
240
|
+
# which is the default strategy, and should be used when possible. The stdout
|
241
|
+
# and stderr streams will not be captured, but streamed directly to the parent
|
242
|
+
# process (so any output on these streams appears in the build log as soon as
|
243
|
+
# possible).
|
244
|
+
#
|
245
|
+
# * Using [Open3.capture3](https://ruby-doc.org/stdlib-2.6.3/libdoc/open3/rdoc/Open3.html#method-c-capture3)
|
246
|
+
# which captures both stdout and stderr, and does not automatically output it
|
247
|
+
# to the build log. Implementors can choose to display it after the shell command
|
248
|
+
# has completed, using the `%{out}` and `%{err}` interpolation variables. Use
|
249
|
+
# sparingly.
|
250
|
+
#
|
251
|
+
# The method accepts the following options:
|
252
|
+
#
|
253
|
+
# @param cmd [String] the shell command to execute
|
254
|
+
# @param opts [Hash] options
|
255
|
+
#
|
256
|
+
# @option opts [Boolean] :echo output the command to stdout before running it
|
257
|
+
# @option opts [Boolean] :silence silence all log output by redirecting stdout and stderr to `/dev/null`
|
258
|
+
# @option opts [Boolean] :capture use `Open3.capture3` to capture stdout and stderr
|
259
|
+
# @option opts [String] :python wrap the command into Bash code that enforces the given Python version to be used
|
260
|
+
# @option opts [String] :retry retries the command 2 more times if it fails
|
261
|
+
# @option opts [String] :info message to output to stdout if the command has exited with the exit code 0 (supports the interpolation variable `${out}` for stdout in case it was captured.
|
262
|
+
# @option opts [String] :assert error message to be raised if the command has exited with a non-zero exit code (supports the interpolation variable `${out}` for stdout in case it was captured.
|
263
|
+
#
|
264
|
+
# @return [Boolean] whether or not the command was successful (has exited with the exit code 0)
|
265
|
+
def shell(cmd, opts = {})
|
266
|
+
cmd = Cmd.new(nil, cmd, opts) if cmd.is_a?(String)
|
267
|
+
info cmd.msg if cmd.msg?
|
268
|
+
info cmd.echo if cmd.echo?
|
269
|
+
|
270
|
+
@last_out, @last_err, @last_status = retrying(cmd.retry ? 2 : 0) do
|
271
|
+
send(cmd.capture? ? :open3 : :system, cmd.cmd, cmd.opts)
|
272
|
+
end
|
273
|
+
|
274
|
+
info format(cmd.success, out: last_out) if success? && cmd.success?
|
275
|
+
error format(cmd.error, err: last_err) if failed? && cmd.assert?
|
276
|
+
|
277
|
+
success? && cmd.capture? ? last_out.chomp : @last_status
|
278
|
+
end
|
279
|
+
|
280
|
+
def retrying(max, tries = 0, status = false)
|
281
|
+
loop do
|
282
|
+
tries += 1
|
283
|
+
out, err, status = yield
|
284
|
+
return [out, err, status] if status || tries > max
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
# Runs a shell command and captures stdout, stderr, and the exit status
|
289
|
+
#
|
290
|
+
# Runs the given command using `Open3.capture3`, which will capture the
|
291
|
+
# stdout and stderr streams, as well as the exit status. I.e. this will
|
292
|
+
# *not* stream log output in real time, but capture the output, and allow
|
293
|
+
# implementors to display it later (using the `%{out}` and `%{err}`
|
294
|
+
# interpolation variables.
|
295
|
+
#
|
296
|
+
# Use sparingly.
|
297
|
+
#
|
298
|
+
# @option chdir [String] directory temporarily to change to before running the command
|
299
|
+
def open3(cmd, opts)
|
300
|
+
opts = [opts[:chdir] ? only(opts, :chdir) : nil].compact
|
301
|
+
out, err, status = Open3.capture3(cmd, *opts)
|
302
|
+
[out, err, status.success?]
|
303
|
+
end
|
304
|
+
|
305
|
+
# Runs a shell command, streaming any stdout or stderr output, and
|
306
|
+
# returning the exit status
|
307
|
+
#
|
308
|
+
# This is the default method for executing shell commands. The stdout and
|
309
|
+
# stderr will not be captured, but streamed directly to the parent process.
|
310
|
+
#
|
311
|
+
# @option chdir [String] directory temporarily to change to before running the command
|
312
|
+
def system(cmd, opts = {})
|
313
|
+
opts = [opts[:chdir] ? only(opts, :chdir) : nil].compact
|
314
|
+
Kernel.system(cmd, *opts)
|
315
|
+
['', '', last_process_status]
|
316
|
+
end
|
317
|
+
|
318
|
+
# Whether or not the last executed shell command was successful.
|
319
|
+
def success?
|
320
|
+
!!@last_status
|
321
|
+
end
|
322
|
+
|
323
|
+
# Whether or not the last executed shell command has failed.
|
324
|
+
def failed?
|
325
|
+
!success?
|
326
|
+
end
|
327
|
+
|
328
|
+
# Returns the last child process' exit status
|
329
|
+
#
|
330
|
+
# Internal, and not to be used by implementors. $? is a read-only
|
331
|
+
# variable, so we use a method that we can stub during tests.
|
332
|
+
def last_process_status
|
333
|
+
$CHILD_STATUS.success?
|
334
|
+
end
|
335
|
+
|
336
|
+
# Whether or not the current Ruby process runs with superuser priviledges.
|
337
|
+
def sudo?
|
338
|
+
Process::UID.eid.zero?
|
339
|
+
end
|
340
|
+
|
341
|
+
# Returns current repository name
|
342
|
+
#
|
343
|
+
# Uses the environment variable `TRAVIS_REPO_SLUG` if present, or the
|
344
|
+
# current directory's base name.
|
345
|
+
#
|
346
|
+
# Note that this might return an unexpected string outside of the context
|
347
|
+
# of Travis CI build environments if the method is called at a time when
|
348
|
+
# the current working directory has changed.
|
349
|
+
def repo_name
|
350
|
+
ENV['TRAVIS_REPO_SLUG'] ? ENV['TRAVIS_REPO_SLUG'].split('/').last : File.basename(Dir.pwd)
|
351
|
+
end
|
352
|
+
|
353
|
+
# Returns current repository slug
|
354
|
+
#
|
355
|
+
# Uses the environment variable `TRAVIS_REPO_SLUG` if present, or the
|
356
|
+
# last two segmens of the current working directory's path.
|
357
|
+
#
|
358
|
+
# Note that this might return an unexpected string outside of the context
|
359
|
+
# of Travis CI build environments if the method is called at a time when
|
360
|
+
# the current working directory has changed.
|
361
|
+
def repo_slug
|
362
|
+
ENV['TRAVIS_REPO_SLUG'] || Dir.pwd.split('/')[-2, 2].join('/')
|
363
|
+
end
|
364
|
+
|
365
|
+
# Returns the current build directory
|
366
|
+
#
|
367
|
+
# Uses the environment variable `TRAVIS_REPO_SLUG` if present, and
|
368
|
+
# defaults to `.` otherwise.
|
369
|
+
#
|
370
|
+
# Note that this might return an unexpected string outside of the context
|
371
|
+
# of Travis CI build environments if the method is called at a time when
|
372
|
+
# the current working directory has changed.
|
373
|
+
def build_dir
|
374
|
+
ENV['TRAVIS_BUILD_DIR'] || '.'
|
375
|
+
end
|
376
|
+
|
377
|
+
# Returns the current build number
|
378
|
+
#
|
379
|
+
# Returns the value of the environment variable `TRAVIS_BUILD_NUMBER` if
|
380
|
+
# present.
|
381
|
+
def build_number
|
382
|
+
ENV['TRAVIS_BUILD_NUMBER'] || raise('TRAVIS_BUILD_NUMBER not set')
|
383
|
+
end
|
384
|
+
|
385
|
+
# Returns the encoding of the given file, as determined by `file`.
|
386
|
+
def encoding(path)
|
387
|
+
case `file '#{path}'`
|
388
|
+
when /gzip compressed/
|
389
|
+
'gzip'
|
390
|
+
when /compress'd/
|
391
|
+
'compress'
|
392
|
+
when /text/
|
393
|
+
'text'
|
394
|
+
when /data/
|
395
|
+
# shrugs?
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
# Returns the current branch name
|
400
|
+
def git_branch
|
401
|
+
ENV['TRAVIS_BRANCH'] || git_rev_parse('HEAD')
|
402
|
+
end
|
403
|
+
|
404
|
+
# Returns the message of the commit `git_sha`.
|
405
|
+
def git_commit_msg
|
406
|
+
`git log #{git_sha} -n 1 --pretty=%B`.chomp
|
407
|
+
end
|
408
|
+
|
409
|
+
# Returns the committer name of the commit `git_sha`.
|
410
|
+
def git_author_name
|
411
|
+
`git log #{git_sha} -n 1 --pretty=%an`.chomp
|
412
|
+
end
|
413
|
+
|
414
|
+
# Returns the comitter email of the commit `git_sha`.
|
415
|
+
def git_author_email
|
416
|
+
`git log #{git_sha} -n 1 --pretty=%ae`.chomp
|
417
|
+
end
|
418
|
+
|
419
|
+
# Whether or not the git working directory is dirty or has new or deleted files
|
420
|
+
def git_dirty?
|
421
|
+
!`git status --short`.chomp.empty?
|
422
|
+
end
|
423
|
+
|
424
|
+
# Returns the output of `git log`, using the given args.
|
425
|
+
def git_log(args)
|
426
|
+
`git log #{args}`.chomp
|
427
|
+
end
|
428
|
+
|
429
|
+
# Returns the Git log, separated by NULs
|
430
|
+
#
|
431
|
+
# Returns the output of `git ls-files -z`, which separates log entries by
|
432
|
+
# NULs, rather than newline characters.
|
433
|
+
def git_ls_files
|
434
|
+
`git ls-files -z`.split("\x0")
|
435
|
+
end
|
436
|
+
|
437
|
+
# Returns true if the given ref exists remotely
|
438
|
+
def git_ls_remote?(url, ref)
|
439
|
+
Kernel.system("git ls-remote --exit-code #{url} #{ref} > /dev/null 2>&1")
|
440
|
+
end
|
441
|
+
|
442
|
+
# Returns known Git remote URLs
|
443
|
+
def git_remote_urls
|
444
|
+
`git remote -v`.scan(/\t[^\s]+\s/).map(&:strip).uniq
|
445
|
+
end
|
446
|
+
|
447
|
+
# Returns the sha for the given Git ref
|
448
|
+
def git_rev_parse(ref)
|
449
|
+
`git rev-parse #{ref}`.strip
|
450
|
+
end
|
451
|
+
|
452
|
+
# Returns the latest tag name, if any
|
453
|
+
def git_tag
|
454
|
+
`git describe --tags --exact-match 2>/dev/null`.chomp
|
455
|
+
end
|
456
|
+
|
457
|
+
# Returns the current commit sha
|
458
|
+
def git_sha
|
459
|
+
ENV['TRAVIS_COMMIT'] || `git rev-parse HEAD`.chomp
|
460
|
+
end
|
461
|
+
|
462
|
+
# Returns the local machine's hostname
|
463
|
+
def machine_name
|
464
|
+
`hostname`.strip
|
465
|
+
end
|
466
|
+
|
467
|
+
# Returns the current Node.js version
|
468
|
+
def node_version
|
469
|
+
`node -v`.sub(/^v/, '').chomp
|
470
|
+
end
|
471
|
+
|
472
|
+
# Returns the current NPM version
|
473
|
+
def npm_version
|
474
|
+
`npm --version`
|
475
|
+
end
|
476
|
+
|
477
|
+
# Returns the current Node.js version
|
478
|
+
def python_version
|
479
|
+
`python --version 2>&1`.sub(/^Python /, '').chomp
|
480
|
+
end
|
481
|
+
|
482
|
+
# Returns true or false depending if the given command can be found
|
483
|
+
def which(cmd)
|
484
|
+
!`which #{cmd}`.chomp.empty? if cmd
|
485
|
+
end
|
486
|
+
|
487
|
+
# Returns a unique temporary directory name
|
488
|
+
def tmp_dir
|
489
|
+
@tmp_dir ||= Dir.mktmpdir
|
490
|
+
end
|
491
|
+
|
492
|
+
# Returns the size of the given file path
|
493
|
+
def file_size(path)
|
494
|
+
File.size(path)
|
495
|
+
end
|
496
|
+
|
497
|
+
def move_files(paths)
|
498
|
+
paths.each do |path|
|
499
|
+
target = "#{tmp_dir}/#{File.basename(path)}"
|
500
|
+
mv(path, target) if File.exist?(path)
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
504
|
+
def unmove_files(paths)
|
505
|
+
paths.each do |path|
|
506
|
+
source = "#{tmp_dir}/#{File.basename(path)}"
|
507
|
+
mv(source, path) if File.exist?(source)
|
508
|
+
end
|
509
|
+
end
|
510
|
+
|
511
|
+
def mv(src, dest)
|
512
|
+
Kernel.system("sudo mv #{src} #{dest} 2> /dev/null")
|
513
|
+
end
|
514
|
+
|
515
|
+
# Writes the given content to the given file path
|
516
|
+
def write_file(path, content, chmod = nil)
|
517
|
+
path = File.expand_path(path)
|
518
|
+
FileUtils.mkdir_p(File.dirname(path))
|
519
|
+
File.open(path, 'w+') { |f| f.write(content) }
|
520
|
+
FileUtils.chmod(chmod, path) if chmod
|
521
|
+
end
|
522
|
+
|
523
|
+
# Writes the given machine, login, and password to ~/.netrc
|
524
|
+
def write_netrc(machine, login, password)
|
525
|
+
require 'netrc'
|
526
|
+
netrc = Netrc.read
|
527
|
+
netrc[machine] = [login, password]
|
528
|
+
netrc.save
|
529
|
+
end
|
530
|
+
|
531
|
+
def sleep(sec)
|
532
|
+
Kernel.sleep(sec)
|
533
|
+
end
|
534
|
+
|
535
|
+
def tty?
|
536
|
+
$stdout.isatty
|
537
|
+
end
|
538
|
+
|
539
|
+
# Returns a copy of the given hash, reduced to the given keys
|
540
|
+
def only(hash, *keys)
|
541
|
+
hash.select { |key, _| keys.include?(key) }.to_h
|
542
|
+
end
|
543
|
+
|
544
|
+
def test?
|
545
|
+
false
|
546
|
+
end
|
547
|
+
end
|
548
|
+
end
|
549
|
+
end
|