dpl 2.0.3.beta.4 → 2.0.3.beta.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +15 -3
- data/Gemfile.lock +444 -211
- data/Rakefile +36 -34
- data/bin/dpl +3 -1
- data/dpl.gemspec +25 -0
- data/lib/dpl/cli.rb +19 -14
- data/lib/dpl/ctx/bash.rb +18 -12
- data/lib/dpl/ctx/test.rb +21 -15
- data/lib/dpl/ctx.rb +2 -0
- data/lib/dpl/helper/assets.rb +4 -2
- data/lib/dpl/helper/cmd.rb +20 -18
- data/lib/dpl/helper/config_file.rb +5 -3
- data/lib/dpl/helper/cookbook_site_streaming_uploader.rb +249 -0
- data/lib/dpl/helper/env.rb +26 -22
- data/lib/dpl/helper/github.rb +2 -0
- data/lib/dpl/helper/interpolate.rb +8 -4
- data/lib/dpl/helper/memoize.rb +4 -1
- data/lib/dpl/helper/squiggle.rb +3 -1
- data/lib/dpl/helper/transliterate.rb +3 -1
- data/lib/dpl/helper/wrap.rb +3 -1
- data/lib/dpl/helper/zip.rb +3 -1
- data/lib/dpl/provider/dsl.rb +18 -4
- data/lib/dpl/provider/examples.rb +6 -2
- data/lib/dpl/provider/status.rb +26 -24
- data/lib/dpl/providers/anynines.rb +22 -20
- data/lib/dpl/providers/azure_web_apps.rb +21 -19
- data/lib/dpl/providers/bintray.rb +44 -37
- data/lib/dpl/providers/bluemixcloudfoundry.rb +38 -36
- data/lib/dpl/providers/boxfuse.rb +12 -10
- data/lib/dpl/providers/cargo.rb +7 -5
- data/lib/dpl/providers/chef_supermarket.rb +82 -80
- data/lib/dpl/providers/cloud66.rb +17 -15
- data/lib/dpl/providers/cloudfiles.rb +8 -6
- data/lib/dpl/providers/cloudformation.rb +191 -187
- data/lib/dpl/providers/cloudfoundry.rb +32 -30
- data/lib/dpl/providers/codedeploy.rb +35 -33
- data/lib/dpl/providers/convox.rb +32 -25
- data/lib/dpl/providers/datica.rb +30 -28
- data/lib/dpl/providers/ecr.rb +66 -64
- data/lib/dpl/providers/elasticbeanstalk.rb +14 -12
- data/lib/dpl/providers/engineyard.rb +60 -58
- data/lib/dpl/providers/firebase.rb +6 -4
- data/lib/dpl/providers/flynn.rb +8 -6
- data/lib/dpl/providers/gae.rb +28 -25
- data/lib/dpl/providers/gcs.rb +59 -57
- data/lib/dpl/providers/git_push.rb +199 -195
- data/lib/dpl/providers/gleis.rb +19 -17
- data/lib/dpl/providers/hackage.rb +15 -13
- data/lib/dpl/providers/hephy.rb +18 -16
- data/lib/dpl/providers/heroku/api.rb +72 -70
- data/lib/dpl/providers/heroku/git.rb +15 -13
- data/lib/dpl/providers/heroku.rb +40 -38
- data/lib/dpl/providers/lambda.rb +134 -134
- data/lib/dpl/providers/launchpad.rb +45 -43
- data/lib/dpl/providers/netlify.rb +7 -5
- data/lib/dpl/providers/npm.rb +61 -58
- data/lib/dpl/providers/nuget.rb +8 -6
- data/lib/dpl/providers/openshift.rb +8 -6
- data/lib/dpl/providers/opsworks.rb +23 -21
- data/lib/dpl/providers/pages/api.rb +14 -14
- data/lib/dpl/providers/pages/git.rb +53 -47
- data/lib/dpl/providers/pages.rb +3 -1
- data/lib/dpl/providers/puppetforge.rb +6 -4
- data/lib/dpl/providers/pypi.rb +55 -54
- data/lib/dpl/providers/releases.rb +30 -23
- data/lib/dpl/providers/rubygems.rb +35 -31
- data/lib/dpl/providers/s3.rb +148 -142
- data/lib/dpl/providers/scalingo.rb +18 -16
- data/lib/dpl/providers/script.rb +4 -2
- data/lib/dpl/providers/snap.rb +12 -9
- data/lib/dpl/providers/surge.rb +7 -5
- data/lib/dpl/providers/testfairy.rb +47 -43
- data/lib/dpl/providers/transifex.rb +20 -18
- data/lib/dpl/providers.rb +3 -1
- data/lib/dpl/string_ext.rb +3 -1
- data/lib/dpl/support/aws_sdk_patch.rb +4 -1
- data/lib/dpl/support/gems.rb +7 -3
- data/lib/dpl/support/gstore_patch.rb +3 -1
- data/lib/dpl/support/version.rb +13 -12
- data/lib/dpl/version.rb +3 -1
- data/lib/dpl.rb +2 -0
- data/status.json +237 -0
- metadata +32 -15
- /data/lib/dpl/providers/{packagecloud.rb → packagecloud.rb_} +0 -0
@@ -0,0 +1,249 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Stanislav Vitvitskiy
|
3
|
+
# Author:: Nuo Yan (nuo@chef.io)
|
4
|
+
# Author:: Christopher Walters (<cw@chef.io>)
|
5
|
+
# Copyright:: Copyright (c) Chef Software Inc.
|
6
|
+
# License:: Apache License, Version 2.0
|
7
|
+
#
|
8
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
9
|
+
# you may not use this file except in compliance with the License.
|
10
|
+
# You may obtain a copy of the License at
|
11
|
+
#
|
12
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
#
|
14
|
+
# Unless required by applicable law or agreed to in writing, software
|
15
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
16
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
17
|
+
# See the License for the specific language governing permissions and
|
18
|
+
# limitations under the License.
|
19
|
+
#
|
20
|
+
|
21
|
+
autoload :URI, "uri"
|
22
|
+
module Net
|
23
|
+
autoload :HTTP, "net/http"
|
24
|
+
end
|
25
|
+
autoload :OpenSSL, "openssl"
|
26
|
+
module Mixlib
|
27
|
+
module Authentication
|
28
|
+
autoload :SignedHeaderAuth, "mixlib/authentication/signedheaderauth"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
require 'chef'
|
32
|
+
require "chef-utils/dist" unless defined?(ChefUtils::Dist)
|
33
|
+
class Chef
|
34
|
+
class Knife
|
35
|
+
module Core
|
36
|
+
# == Chef::Knife::Core::CookbookSiteStreamingUploader
|
37
|
+
# A streaming multipart HTTP upload implementation. Used to upload cookbooks
|
38
|
+
# (in tarball form) to https://supermarket.chef.io
|
39
|
+
#
|
40
|
+
# inspired by http://stanislavvitvitskiy.blogspot.com/2008/12/multipart-post-in-ruby.html
|
41
|
+
class CookbookSiteStreamingUploader
|
42
|
+
|
43
|
+
DefaultHeaders = { "accept" => "application/json", "x-chef-version" => ::Chef::VERSION }.freeze # rubocop:disable Naming/ConstantName
|
44
|
+
|
45
|
+
class << self
|
46
|
+
|
47
|
+
def create_build_dir(cookbook)
|
48
|
+
tmp_cookbook_path = Tempfile.new("#{ChefUtils::Dist::Infra::SHORT}-#{cookbook.name}-build")
|
49
|
+
tmp_cookbook_path.close
|
50
|
+
tmp_cookbook_dir = tmp_cookbook_path.path
|
51
|
+
File.unlink(tmp_cookbook_dir)
|
52
|
+
FileUtils.mkdir_p(tmp_cookbook_dir)
|
53
|
+
Chef::Log.trace("Staging at #{tmp_cookbook_dir}")
|
54
|
+
checksums_to_on_disk_paths = cookbook.checksums
|
55
|
+
cookbook.each_file do |manifest_record|
|
56
|
+
path_in_cookbook = manifest_record[:path]
|
57
|
+
on_disk_path = checksums_to_on_disk_paths[manifest_record[:checksum]]
|
58
|
+
dest = File.join(tmp_cookbook_dir, cookbook.name.to_s, path_in_cookbook)
|
59
|
+
FileUtils.mkdir_p(File.dirname(dest))
|
60
|
+
Chef::Log.trace("Staging #{on_disk_path} to #{dest}")
|
61
|
+
FileUtils.cp(on_disk_path, dest)
|
62
|
+
end
|
63
|
+
|
64
|
+
# First, generate metadata
|
65
|
+
Chef::Log.trace("Generating metadata")
|
66
|
+
kcm = Chef::Knife::CookbookMetadata.new
|
67
|
+
kcm.config[:cookbook_path] = [ tmp_cookbook_dir ]
|
68
|
+
kcm.name_args = [ cookbook.name.to_s ]
|
69
|
+
kcm.run
|
70
|
+
|
71
|
+
tmp_cookbook_dir
|
72
|
+
end
|
73
|
+
|
74
|
+
def post(to_url, user_id, secret_key_filename, params = {}, headers = {})
|
75
|
+
make_request(:post, to_url, user_id, secret_key_filename, params, headers)
|
76
|
+
end
|
77
|
+
|
78
|
+
def put(to_url, user_id, secret_key_filename, params = {}, headers = {})
|
79
|
+
make_request(:put, to_url, user_id, secret_key_filename, params, headers)
|
80
|
+
end
|
81
|
+
|
82
|
+
def make_request(http_verb, to_url, user_id, secret_key_filename, params = {}, headers = {})
|
83
|
+
boundary = "----RubyMultipartClient" + rand(1000000).to_s + "ZZZZZ"
|
84
|
+
parts = []
|
85
|
+
content_file = nil
|
86
|
+
|
87
|
+
secret_key = OpenSSL::PKey::RSA.new(File.read(secret_key_filename))
|
88
|
+
|
89
|
+
unless params.nil? || params.empty?
|
90
|
+
params.each do |key, value|
|
91
|
+
if value.is_a?(File)
|
92
|
+
content_file = value
|
93
|
+
filepath = value.path
|
94
|
+
filename = File.basename(filepath)
|
95
|
+
parts << StringPart.new( "--" + boundary + "\r\n" +
|
96
|
+
"Content-Disposition: form-data; name=\"" + key.to_s + "\"; filename=\"" + filename + "\"\r\n" +
|
97
|
+
"Content-Type: application/octet-stream\r\n\r\n")
|
98
|
+
parts << StreamPart.new(value, File.size(filepath))
|
99
|
+
parts << StringPart.new("\r\n")
|
100
|
+
else
|
101
|
+
parts << StringPart.new( "--" + boundary + "\r\n" +
|
102
|
+
"Content-Disposition: form-data; name=\"" + key.to_s + "\"\r\n\r\n")
|
103
|
+
parts << StringPart.new(value.to_s + "\r\n")
|
104
|
+
end
|
105
|
+
end
|
106
|
+
parts << StringPart.new("--" + boundary + "--\r\n")
|
107
|
+
end
|
108
|
+
|
109
|
+
body_stream = MultipartStream.new(parts)
|
110
|
+
|
111
|
+
timestamp = Time.now.utc.iso8601
|
112
|
+
|
113
|
+
url = URI.parse(to_url)
|
114
|
+
|
115
|
+
Chef::Log.logger.debug("Signing: method: #{http_verb}, url: #{url}, file: #{content_file}, User-id: #{user_id}, Timestamp: #{timestamp}")
|
116
|
+
|
117
|
+
# We use the body for signing the request if the file parameter
|
118
|
+
# wasn't a valid file or wasn't included. Extract the body (with
|
119
|
+
# multi-part delimiters intact) to sign the request.
|
120
|
+
# TODO: tim: 2009-12-28: It'd be nice to remove this special case, and
|
121
|
+
# always hash the entire request body. In the file case it would just be
|
122
|
+
# expanded multipart text - the entire body of the POST.
|
123
|
+
content_body = parts.inject("") { |result, part| result + part.read(0, part.size) }
|
124
|
+
content_file.rewind if content_file # we consumed the file for the above operation, so rewind it.
|
125
|
+
|
126
|
+
signing_options = {
|
127
|
+
http_method: http_verb,
|
128
|
+
path: url.path,
|
129
|
+
user_id: user_id,
|
130
|
+
timestamp: timestamp }
|
131
|
+
(content_file && signing_options[:file] = content_file) || (signing_options[:body] = (content_body || ""))
|
132
|
+
|
133
|
+
headers.merge!(Mixlib::Authentication::SignedHeaderAuth.signing_object(signing_options).sign(secret_key))
|
134
|
+
|
135
|
+
content_file.rewind if content_file
|
136
|
+
|
137
|
+
# net/http doesn't like symbols for header keys, so we'll to_s each one just in case
|
138
|
+
headers = DefaultHeaders.merge(Hash[*headers.map { |k, v| [k.to_s, v] }.flatten])
|
139
|
+
|
140
|
+
req = case http_verb
|
141
|
+
when :put
|
142
|
+
Net::HTTP::Put.new(url.path, headers)
|
143
|
+
when :post
|
144
|
+
Net::HTTP::Post.new(url.path, headers)
|
145
|
+
end
|
146
|
+
req.content_length = body_stream.size
|
147
|
+
req.content_type = "multipart/form-data; boundary=" + boundary unless parts.empty?
|
148
|
+
req.body_stream = body_stream
|
149
|
+
|
150
|
+
http = Chef::HTTP::BasicClient.new(url).http_client
|
151
|
+
res = http.request(req)
|
152
|
+
|
153
|
+
# alias status to code and to_s to body for test purposes
|
154
|
+
# TODO: stop the following madness!
|
155
|
+
class << res
|
156
|
+
alias :to_s :body
|
157
|
+
|
158
|
+
# BUG this makes the response compatible with what response_steps expects to test headers (response.headers[] -> response[])
|
159
|
+
def headers # rubocop:disable Lint/NestedMethodDefinition
|
160
|
+
self
|
161
|
+
end
|
162
|
+
|
163
|
+
def status # rubocop:disable Lint/NestedMethodDefinition
|
164
|
+
code.to_i
|
165
|
+
end
|
166
|
+
end
|
167
|
+
res
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
class StreamPart
|
173
|
+
def initialize(stream, size)
|
174
|
+
@stream, @size = stream, size
|
175
|
+
end
|
176
|
+
|
177
|
+
def size
|
178
|
+
@size
|
179
|
+
end
|
180
|
+
|
181
|
+
# read the specified amount from the stream
|
182
|
+
def read(offset, how_much)
|
183
|
+
@stream.read(how_much)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
class StringPart
|
188
|
+
def initialize(str)
|
189
|
+
@str = str
|
190
|
+
end
|
191
|
+
|
192
|
+
def size
|
193
|
+
@str.length
|
194
|
+
end
|
195
|
+
|
196
|
+
# read the specified amount from the string starting at the offset
|
197
|
+
def read(offset, how_much)
|
198
|
+
@str[offset, how_much]
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
class MultipartStream
|
203
|
+
def initialize(parts)
|
204
|
+
@parts = parts
|
205
|
+
@part_no = 0
|
206
|
+
@part_offset = 0
|
207
|
+
end
|
208
|
+
|
209
|
+
def size
|
210
|
+
@parts.inject(0) { |size, part| size + part.size }
|
211
|
+
end
|
212
|
+
|
213
|
+
def read(how_much, dst_buf = nil)
|
214
|
+
if @part_no >= @parts.size
|
215
|
+
dst_buf.replace("") if dst_buf
|
216
|
+
return dst_buf
|
217
|
+
end
|
218
|
+
|
219
|
+
how_much_current_part = @parts[@part_no].size - @part_offset
|
220
|
+
|
221
|
+
how_much_current_part = if how_much_current_part > how_much
|
222
|
+
how_much
|
223
|
+
else
|
224
|
+
how_much_current_part
|
225
|
+
end
|
226
|
+
|
227
|
+
how_much_next_part = how_much - how_much_current_part
|
228
|
+
|
229
|
+
current_part = @parts[@part_no].read(@part_offset, how_much_current_part)
|
230
|
+
|
231
|
+
# recurse into the next part if the current one was not large enough
|
232
|
+
if how_much_next_part > 0
|
233
|
+
@part_no += 1
|
234
|
+
@part_offset = 0
|
235
|
+
next_part = read(how_much_next_part)
|
236
|
+
result = current_part + (next_part || "")
|
237
|
+
else
|
238
|
+
@part_offset += how_much_current_part
|
239
|
+
result = current_part
|
240
|
+
end
|
241
|
+
dst_buf ? dst_buf.replace(result || "") : result
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
data/lib/dpl/helper/env.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'dpl/helper/memoize'
|
2
4
|
|
3
5
|
module Dpl
|
@@ -21,8 +23,8 @@ module Dpl
|
|
21
23
|
def env(cmd)
|
22
24
|
@cmd = cmd
|
23
25
|
env = @env.select { |key, _| keys.include?(key) }
|
24
|
-
env = env.
|
25
|
-
env.
|
26
|
+
env = env.transform_keys { |key| unprefix(key).downcase.to_sym }
|
27
|
+
env.transform_keys { |key| dealias(key) }
|
26
28
|
end
|
27
29
|
|
28
30
|
def description(cmd)
|
@@ -33,39 +35,41 @@ module Dpl
|
|
33
35
|
end
|
34
36
|
|
35
37
|
def example(cmd)
|
36
|
-
return unless opt = cmd.opts.detect { |
|
37
|
-
|
38
|
-
env
|
38
|
+
return unless opt = cmd.opts.detect { |option| option.secret? }
|
39
|
+
|
40
|
+
env = strs.map { |str| "`#{str}_#{opt.name.upcase}=<#{opt.name}>`" }
|
41
|
+
env += strs.map { |str| "`#{str}#{opt.name.upcase}=<#{opt.name}>`" } if opts[:allow_skip_underscore]
|
39
42
|
"E.g. the option `--#{opt.name}` can be given as #{sentence(env)}."
|
40
43
|
end
|
41
44
|
|
42
45
|
def sentence(strs)
|
43
46
|
return strs.join if strs.size == 1
|
47
|
+
|
44
48
|
[strs[0..-2].join(', '), strs[-1]].join(' or ')
|
45
49
|
end
|
46
50
|
|
47
51
|
private
|
48
52
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
+
def dealias(key)
|
54
|
+
opt = cmd.opts.detect { |option| option.aliases.include?(key) }
|
55
|
+
opt ? opt.name : key
|
56
|
+
end
|
53
57
|
|
54
|
-
|
55
|
-
|
56
|
-
|
58
|
+
def unprefix(key)
|
59
|
+
strs.inject(key) { |key, str| key.sub(/^#{str}_?/, '') }
|
60
|
+
end
|
57
61
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
62
|
+
def keys
|
63
|
+
keys = cmd.opts.map(&:name) + cmd.opts.map(&:aliases).flatten
|
64
|
+
strs.map { |str| keys.map { |key| keys_for(str, key) } }.flatten
|
65
|
+
end
|
66
|
+
memoize :keys
|
63
67
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
68
|
+
def keys_for(str, key)
|
69
|
+
keys = [["#{str}_", key.upcase].join]
|
70
|
+
keys << [str, key.upcase].join if opts[:allow_skip_underscore]
|
71
|
+
keys
|
72
|
+
end
|
69
73
|
end
|
70
74
|
|
71
75
|
# should this sit in Cl?
|
data/lib/dpl/helper/github.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'uri'
|
2
4
|
|
3
5
|
module Dpl
|
@@ -67,15 +69,16 @@ module Dpl
|
|
67
69
|
# length of the original string.
|
68
70
|
def obfuscate(str, opts = {})
|
69
71
|
return str if opts[:secure] || !str.blacklisted?
|
72
|
+
|
70
73
|
keep = (str.length / (4.0 + str.length / 5).round).round
|
71
|
-
keep = 1 if keep
|
74
|
+
keep = 1 if keep.zero?
|
72
75
|
str[0, keep] + '*' * (20 - keep)
|
73
76
|
end
|
74
77
|
|
75
78
|
class Interpolator < Struct.new(:str, :obj, :args, :opts)
|
76
79
|
include Interpolate
|
77
80
|
|
78
|
-
MODIFIER = %i
|
81
|
+
MODIFIER = %i[obfuscate escape quote].freeze
|
79
82
|
PATTERN = /%\{(\$?[\w]+)\}/
|
80
83
|
ENV_VAR = /^\$[A-Z_]+$/
|
81
84
|
UPCASE = /^[A-Z_]+$/
|
@@ -93,7 +96,7 @@ module Dpl
|
|
93
96
|
@blacklist_result = false
|
94
97
|
str = str.to_s.gsub(PATTERN) do
|
95
98
|
@blacklist_result = true
|
96
|
-
normalize(lookup(
|
99
|
+
normalize(lookup(::Regexp.last_match(1).to_sym))
|
97
100
|
end
|
98
101
|
@blacklist_result || (args.is_a?(Array) && args.any? { |arg| arg.is_a?(String) && arg.blacklisted? }) ? str.blacklist : str
|
99
102
|
end
|
@@ -108,6 +111,7 @@ module Dpl
|
|
108
111
|
|
109
112
|
def secrets(str)
|
110
113
|
return [] unless str.is_a?(String) && str.blacklisted?
|
114
|
+
|
111
115
|
opts = obj.class.opts.select(&:secret?)
|
112
116
|
secrets = opts.map { |opt| obj.opts[opt.name] }.compact
|
113
117
|
secrets.select { |secret| str.include?(secret) }
|
@@ -117,7 +121,7 @@ module Dpl
|
|
117
121
|
obj.is_a?(Array) ? obj.join(' ') : obj.to_s
|
118
122
|
end
|
119
123
|
|
120
|
-
def lookup(key)
|
124
|
+
def lookup(key)
|
121
125
|
if vars? && !var?(key)
|
122
126
|
UNKNOWN % key
|
123
127
|
elsif mod = modifier(key)
|
data/lib/dpl/helper/memoize.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Memoize
|
2
4
|
class ArgsError < StandardError; end
|
3
5
|
|
@@ -6,8 +8,9 @@ module Memoize
|
|
6
8
|
ivar = :"@#{name.to_s.sub('?', '_predicate')}"
|
7
9
|
prepend Module.new {
|
8
10
|
define_method(name) do |*args|
|
9
|
-
raise ArgsError
|
11
|
+
raise ArgsError, 'cannot pass arguments to memoized method %p' % name unless args.empty?
|
10
12
|
return instance_variable_get(ivar) if instance_variable_defined?(ivar)
|
13
|
+
|
11
14
|
instance_variable_set(ivar, super())
|
12
15
|
end
|
13
16
|
}
|
data/lib/dpl/helper/squiggle.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Beloved squiggly heredocs did not exist in Ruby 2.1, which we still want to
|
2
4
|
# support, so let's give kudos with a method `sq`.
|
3
5
|
module Squiggle
|
@@ -16,7 +18,7 @@ module Squiggle
|
|
16
18
|
# while this line sits on the same level as the first line.
|
17
19
|
# str
|
18
20
|
def sq(str)
|
19
|
-
width = str =~ /( *)\S/ &&
|
21
|
+
width = str =~ /( *)\S/ && ::Regexp.last_match(1).size
|
20
22
|
str.lines.map { |line| line.gsub(/^ {#{width}}/, '') }.join
|
21
23
|
end
|
22
24
|
end
|
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Dpl
|
2
4
|
module Transliterate
|
3
|
-
APPROXIMATIONS = YAML.load(File.read(File.expand_path('
|
5
|
+
APPROXIMATIONS = YAML.load(File.read(File.expand_path('../../../config/transliterate.yml', __dir__)))
|
4
6
|
|
5
7
|
def transliterate(string, replacement = '.')
|
6
8
|
string.gsub(/[^\x00-\x7f]/u) do |char|
|
data/lib/dpl/helper/wrap.rb
CHANGED
data/lib/dpl/helper/zip.rb
CHANGED
data/lib/dpl/provider/dsl.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'dpl/helper/squiggle'
|
2
4
|
require 'dpl/helper/wrap'
|
3
5
|
require 'dpl/provider/status'
|
4
6
|
|
5
|
-
# TODO figure out how to allow adding domain specific behavior like this to Cl
|
7
|
+
# TODO: figure out how to allow adding domain specific behavior like this to Cl
|
6
8
|
class Cl::Opt
|
7
9
|
OPTS << :interpolate
|
8
10
|
|
@@ -55,9 +57,10 @@ module Dpl
|
|
55
57
|
def vars(*vars)
|
56
58
|
return self.vars.concat(vars) if vars.any?
|
57
59
|
return @vars if instance_variable_defined?(:@vars)
|
60
|
+
|
58
61
|
vars = superclass.respond_to?(:vars) ? superclass.vars : []
|
59
|
-
reject = %i
|
60
|
-
opts = reject.inject(self.opts) { |
|
62
|
+
reject = %i[flag array internal interpolate secret]
|
63
|
+
opts = reject.inject(self.opts) { |options, attr| options.reject(&:"#{attr}?") }
|
61
64
|
@vars = vars.dup.concat(opts.map(&:name)).uniq.sort - [:strategy]
|
62
65
|
end
|
63
66
|
|
@@ -108,6 +111,7 @@ module Dpl
|
|
108
111
|
|
109
112
|
def runtimes(name = nil, requirements = nil)
|
110
113
|
return @runtimes ||= [] unless name
|
114
|
+
|
111
115
|
runtimes << [name, requirements]
|
112
116
|
end
|
113
117
|
|
@@ -121,6 +125,7 @@ module Dpl
|
|
121
125
|
# @return Previously declared apt packages if no arguments were given.
|
122
126
|
def apt(package = nil, cmd = nil)
|
123
127
|
return apt << [package, cmd].compact if package
|
128
|
+
|
124
129
|
@apt ||= self == Provider ? [] : superclass.apt.dup
|
125
130
|
end
|
126
131
|
|
@@ -144,6 +149,7 @@ module Dpl
|
|
144
149
|
# @return Previously declared gems if no arguments were given
|
145
150
|
def gem(name = nil, version = nil, opts = {})
|
146
151
|
return gem << [name, version, opts] if name
|
152
|
+
|
147
153
|
@gem ||= self == Provider ? [] : superclass.gem.dup
|
148
154
|
end
|
149
155
|
|
@@ -161,6 +167,7 @@ module Dpl
|
|
161
167
|
# @return Previously declared NPM packages if no arguments are given.
|
162
168
|
def npm(package = nil, cmd = nil)
|
163
169
|
return npm << [package, cmd].compact if package
|
170
|
+
|
164
171
|
@npm ||= self == Provider ? [] : superclass.npm.dup
|
165
172
|
end
|
166
173
|
|
@@ -181,6 +188,7 @@ module Dpl
|
|
181
188
|
# @return Previously declared Python packages if no arguments are given.
|
182
189
|
def pip(package = nil, cmd = nil, version = nil)
|
183
190
|
return pip << [package, cmd, version].compact if package
|
191
|
+
|
184
192
|
@pip ||= self == Provider ? [] : superclass.pip.dup
|
185
193
|
end
|
186
194
|
|
@@ -223,6 +231,7 @@ module Dpl
|
|
223
231
|
# commands.
|
224
232
|
def cmds(cmds = nil)
|
225
233
|
return self.cmds.update(cmds) if cmds
|
234
|
+
|
226
235
|
@cmds ||= self == Provider ? {} : superclass.cmds.dup
|
227
236
|
end
|
228
237
|
|
@@ -265,6 +274,7 @@ module Dpl
|
|
265
274
|
# commands.
|
266
275
|
def errs(errs = nil)
|
267
276
|
return self.errs.update(errs) if errs
|
277
|
+
|
268
278
|
@errs ||= self == Provider ? {} : superclass.errs.dup
|
269
279
|
end
|
270
280
|
|
@@ -327,11 +337,13 @@ module Dpl
|
|
327
337
|
# @return Previously declared msgs if no argument is given.
|
328
338
|
def msgs(msgs = nil)
|
329
339
|
return self.msgs.update(msgs) if msgs
|
340
|
+
|
330
341
|
@msgs ||= self == Provider ? {} : superclass.msgs.dup
|
331
342
|
end
|
332
343
|
|
333
344
|
def strs(strs = nil)
|
334
345
|
return self.strs.update(strs) if strs
|
346
|
+
|
335
347
|
@strs ||= self == Provider ? {} : superclass.strs.dup
|
336
348
|
end
|
337
349
|
|
@@ -342,6 +354,7 @@ module Dpl
|
|
342
354
|
# @return Previously declared artifacts to keep if no argument is given.
|
343
355
|
def keep(*paths)
|
344
356
|
return keep.concat(paths) if paths.any?
|
357
|
+
|
345
358
|
@keep ||= self == Provider ? [] : superclass.keep.dup
|
346
359
|
end
|
347
360
|
|
@@ -364,6 +377,7 @@ module Dpl
|
|
364
377
|
# @return Previously declared features needed if no argument is given.
|
365
378
|
def needs(*features)
|
366
379
|
return needs.concat(features) if features.any?
|
380
|
+
|
367
381
|
@needs ||= self == Provider ? [] : superclass.needs.dup
|
368
382
|
end
|
369
383
|
|
@@ -380,7 +394,7 @@ module Dpl
|
|
380
394
|
def user_agent(*strs)
|
381
395
|
strs.unshift "dpl/#{Dpl::VERSION}"
|
382
396
|
strs.unshift 'travis/0.1.0' if ENV['TRAVIS']
|
383
|
-
strs = strs.flat_map { |e| Hash
|
397
|
+
strs = strs.flat_map { |e| e.is_a?(Hash) ? e.map { |k, v| "#{k}/#{v}" } : e }
|
384
398
|
strs.join(' ').gsub(/\s+/, ' ').strip
|
385
399
|
end
|
386
400
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Dpl
|
2
4
|
class Examples < Struct.new(:const)
|
3
5
|
def cmds
|
@@ -58,12 +60,13 @@ module Dpl
|
|
58
60
|
end
|
59
61
|
|
60
62
|
def without_required(opts)
|
61
|
-
opts
|
63
|
+
opts -= const.required.flatten.map { |key| const.opts[key] }
|
62
64
|
opts - required_opts.map(&:opts)
|
63
65
|
end
|
64
66
|
|
65
67
|
def example(opts)
|
66
68
|
return unless opts.any?
|
69
|
+
|
67
70
|
opts = required_opts.concat(opts).uniq.compact
|
68
71
|
Example.new(const, opts)
|
69
72
|
end
|
@@ -117,7 +120,8 @@ module Dpl
|
|
117
120
|
return if opt.type == :flag
|
118
121
|
return 1 if opt.type == :integer
|
119
122
|
return opt.enum.first if opt.enum?
|
120
|
-
|
123
|
+
|
124
|
+
str = opt.strs.detect { |str| str =~ /^--#{opt.name} (.*)$/ } && ::Regexp.last_match(1)
|
121
125
|
str ? str.downcase : 'str'
|
122
126
|
end
|
123
127
|
|
data/lib/dpl/provider/status.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Dpl
|
2
4
|
class Provider < Cl::Cmd
|
3
5
|
class Status < Struct.new(:provider, :status, :info)
|
4
|
-
STATUS = %i
|
6
|
+
STATUS = %i[dev alpha beta stable deprecated].freeze
|
5
7
|
|
6
8
|
MSG = {
|
7
|
-
dev:
|
8
|
-
alpha:
|
9
|
-
beta:
|
9
|
+
dev: 'Support for deployments to %s is in **development**',
|
10
|
+
alpha: 'Support for deployments to %s is in **alpha**',
|
11
|
+
beta: 'Support for deployments to %s is in **beta**',
|
10
12
|
deprecated: 'Support for deployments to %s is *deprecated**',
|
11
13
|
pre_stable: 'Please see [Maturity Levels](%s) for details.'
|
12
|
-
}
|
14
|
+
}.freeze
|
13
15
|
|
14
16
|
URL = 'https://github.com/travis-ci/dpl/#maturity-levels'
|
15
17
|
|
@@ -23,7 +25,7 @@ module Dpl
|
|
23
25
|
end
|
24
26
|
|
25
27
|
def msg
|
26
|
-
msg =
|
28
|
+
msg = (MSG[status] % name).to_s
|
27
29
|
msg << "(#{info})" if info
|
28
30
|
msg << ". #{MSG[:pre_stable] % URL}" if pre_stable?
|
29
31
|
msg
|
@@ -31,29 +33,29 @@ module Dpl
|
|
31
33
|
|
32
34
|
private
|
33
35
|
|
34
|
-
|
35
|
-
|
36
|
-
|
36
|
+
def name
|
37
|
+
provider.full_name
|
38
|
+
end
|
37
39
|
|
38
|
-
|
39
|
-
|
40
|
-
|
40
|
+
def pre_stable?
|
41
|
+
STATUS.index(status) < STATUS.index(:stable)
|
42
|
+
end
|
41
43
|
|
42
|
-
|
43
|
-
|
44
|
-
|
44
|
+
def stable?
|
45
|
+
status == :stable
|
46
|
+
end
|
45
47
|
|
46
|
-
|
47
|
-
|
48
|
-
|
48
|
+
def deprecated?
|
49
|
+
status == :deprecated
|
50
|
+
end
|
49
51
|
|
50
|
-
|
51
|
-
|
52
|
-
|
52
|
+
def known?(status)
|
53
|
+
STATUS.include?(status)
|
54
|
+
end
|
53
55
|
|
54
|
-
|
55
|
-
|
56
|
-
|
56
|
+
def unknown!(status)
|
57
|
+
raise "Unknown status: #{status.inspect}. Known statuses are: #{STATUS.map(&:inspect).join(', ')}"
|
58
|
+
end
|
57
59
|
end
|
58
60
|
end
|
59
61
|
end
|