dpl 2.0.3.beta.4 → 2.0.3.beta.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.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +15 -3
  3. data/Gemfile.lock +444 -211
  4. data/Rakefile +36 -34
  5. data/bin/dpl +3 -1
  6. data/dpl.gemspec +25 -0
  7. data/lib/dpl/cli.rb +19 -14
  8. data/lib/dpl/ctx/bash.rb +18 -12
  9. data/lib/dpl/ctx/test.rb +21 -15
  10. data/lib/dpl/ctx.rb +2 -0
  11. data/lib/dpl/helper/assets.rb +4 -2
  12. data/lib/dpl/helper/cmd.rb +20 -18
  13. data/lib/dpl/helper/config_file.rb +5 -3
  14. data/lib/dpl/helper/cookbook_site_streaming_uploader.rb +249 -0
  15. data/lib/dpl/helper/env.rb +26 -22
  16. data/lib/dpl/helper/github.rb +2 -0
  17. data/lib/dpl/helper/interpolate.rb +8 -4
  18. data/lib/dpl/helper/memoize.rb +4 -1
  19. data/lib/dpl/helper/squiggle.rb +3 -1
  20. data/lib/dpl/helper/transliterate.rb +3 -1
  21. data/lib/dpl/helper/wrap.rb +3 -1
  22. data/lib/dpl/helper/zip.rb +3 -1
  23. data/lib/dpl/provider/dsl.rb +18 -4
  24. data/lib/dpl/provider/examples.rb +6 -2
  25. data/lib/dpl/provider/status.rb +26 -24
  26. data/lib/dpl/providers/anynines.rb +22 -20
  27. data/lib/dpl/providers/azure_web_apps.rb +21 -19
  28. data/lib/dpl/providers/bintray.rb +44 -37
  29. data/lib/dpl/providers/bluemixcloudfoundry.rb +38 -36
  30. data/lib/dpl/providers/boxfuse.rb +12 -10
  31. data/lib/dpl/providers/cargo.rb +7 -5
  32. data/lib/dpl/providers/chef_supermarket.rb +82 -80
  33. data/lib/dpl/providers/cloud66.rb +17 -15
  34. data/lib/dpl/providers/cloudfiles.rb +8 -6
  35. data/lib/dpl/providers/cloudformation.rb +191 -187
  36. data/lib/dpl/providers/cloudfoundry.rb +32 -30
  37. data/lib/dpl/providers/codedeploy.rb +35 -33
  38. data/lib/dpl/providers/convox.rb +32 -25
  39. data/lib/dpl/providers/datica.rb +30 -28
  40. data/lib/dpl/providers/ecr.rb +66 -64
  41. data/lib/dpl/providers/elasticbeanstalk.rb +14 -12
  42. data/lib/dpl/providers/engineyard.rb +60 -58
  43. data/lib/dpl/providers/firebase.rb +6 -4
  44. data/lib/dpl/providers/flynn.rb +8 -6
  45. data/lib/dpl/providers/gae.rb +28 -25
  46. data/lib/dpl/providers/gcs.rb +59 -57
  47. data/lib/dpl/providers/git_push.rb +199 -195
  48. data/lib/dpl/providers/gleis.rb +19 -17
  49. data/lib/dpl/providers/hackage.rb +15 -13
  50. data/lib/dpl/providers/hephy.rb +18 -16
  51. data/lib/dpl/providers/heroku/api.rb +72 -70
  52. data/lib/dpl/providers/heroku/git.rb +15 -13
  53. data/lib/dpl/providers/heroku.rb +40 -38
  54. data/lib/dpl/providers/lambda.rb +134 -134
  55. data/lib/dpl/providers/launchpad.rb +45 -43
  56. data/lib/dpl/providers/netlify.rb +7 -5
  57. data/lib/dpl/providers/npm.rb +61 -58
  58. data/lib/dpl/providers/nuget.rb +8 -6
  59. data/lib/dpl/providers/openshift.rb +8 -6
  60. data/lib/dpl/providers/opsworks.rb +23 -21
  61. data/lib/dpl/providers/pages/api.rb +14 -14
  62. data/lib/dpl/providers/pages/git.rb +53 -47
  63. data/lib/dpl/providers/pages.rb +3 -1
  64. data/lib/dpl/providers/puppetforge.rb +6 -4
  65. data/lib/dpl/providers/pypi.rb +55 -54
  66. data/lib/dpl/providers/releases.rb +30 -23
  67. data/lib/dpl/providers/rubygems.rb +35 -31
  68. data/lib/dpl/providers/s3.rb +148 -142
  69. data/lib/dpl/providers/scalingo.rb +18 -16
  70. data/lib/dpl/providers/script.rb +4 -2
  71. data/lib/dpl/providers/snap.rb +12 -9
  72. data/lib/dpl/providers/surge.rb +7 -5
  73. data/lib/dpl/providers/testfairy.rb +47 -43
  74. data/lib/dpl/providers/transifex.rb +20 -18
  75. data/lib/dpl/providers.rb +3 -1
  76. data/lib/dpl/string_ext.rb +3 -1
  77. data/lib/dpl/support/aws_sdk_patch.rb +4 -1
  78. data/lib/dpl/support/gems.rb +7 -3
  79. data/lib/dpl/support/gstore_patch.rb +3 -1
  80. data/lib/dpl/support/version.rb +13 -12
  81. data/lib/dpl/version.rb +3 -1
  82. data/lib/dpl.rb +2 -0
  83. data/status.json +237 -0
  84. metadata +32 -15
  85. /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
+
@@ -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.map { |key, value| [unprefix(key).downcase.to_sym, value] }.to_h
25
- env.map { |key, value| [dealias(key), value] }.to_h
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 { |opt| opt.secret? }
37
- env = self.strs.map { |str| "`#{str}_#{opt.name.upcase}=<#{opt.name}>`" }
38
- env += self.strs.map { |str| "`#{str}#{opt.name.upcase}=<#{opt.name}>`" } if opts[:allow_skip_underscore]
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
- def dealias(key)
50
- opt = cmd.opts.detect { |opt| opt.aliases.include?(key) }
51
- opt ? opt.name : key
52
- end
53
+ def dealias(key)
54
+ opt = cmd.opts.detect { |option| option.aliases.include?(key) }
55
+ opt ? opt.name : key
56
+ end
53
57
 
54
- def unprefix(key)
55
- strs.inject(key) { |key, str| key.sub(/^#{str}_?/, '') }
56
- end
58
+ def unprefix(key)
59
+ strs.inject(key) { |key, str| key.sub(/^#{str}_?/, '') }
60
+ end
57
61
 
58
- def keys
59
- keys = cmd.opts.map(&:name) + cmd.opts.map(&:aliases).flatten
60
- strs.map { |str| keys.map { |key| keys_for(str, key) } }.flatten
61
- end
62
- memoize :keys
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
- def keys_for(str, key)
65
- keys = [["#{str}_", key.upcase].join]
66
- keys << [str, key.upcase].join if opts[:allow_skip_underscore]
67
- keys
68
- end
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?
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dpl/helper/transliterate'
2
4
 
3
5
  # I18n.load_path << File.expand_path('config/transliterate.yml')
@@ -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 == 0
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(obfuscate escape quote)
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($1.to_sym))
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)
@@ -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.new('cannot pass arguments to memoized method %p' % name) unless args.empty?
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
  }
@@ -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/ && $1.size
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('../../../../config/transliterate.yml', __FILE__)))
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|
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Wrap
2
- extend self
4
+ module_function
3
5
 
4
6
  def wrap(str, width = 80)
5
7
  str.lines.map do |line|
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'tempfile'
2
4
 
3
5
  module Dpl
4
6
  class Zip < Struct.new(:src, :dest, :opts)
5
- ZIP_EXT = %w(.zip .jar)
7
+ ZIP_EXT = %w[.zip .jar].freeze
6
8
 
7
9
  def initialize(*)
8
10
  require 'zip'
@@ -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(flag array internal interpolate secret)
60
- opts = reject.inject(self.opts) { |opts, attr| opts.reject(&:"#{attr}?") }
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 === e ? e.map { |k, v| "#{k}/#{v}" } : e }
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 = opts - const.required.flatten.map { |key| const.opts[key] }
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
- str = opt.strs.detect { |str| str =~ /^--#{opt.name} (.*)$/ } && $1
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
 
@@ -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(dev alpha beta stable deprecated)
6
+ STATUS = %i[dev alpha beta stable deprecated].freeze
5
7
 
6
8
  MSG = {
7
- dev: 'Support for deployments to %s is in **development**',
8
- alpha: 'Support for deployments to %s is in **alpha**',
9
- beta: 'Support for deployments to %s is in **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 = "#{MSG[status] % name}"
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
- def name
35
- provider.full_name
36
- end
36
+ def name
37
+ provider.full_name
38
+ end
37
39
 
38
- def pre_stable?
39
- STATUS.index(status) < STATUS.index(:stable)
40
- end
40
+ def pre_stable?
41
+ STATUS.index(status) < STATUS.index(:stable)
42
+ end
41
43
 
42
- def stable?
43
- status == :stable
44
- end
44
+ def stable?
45
+ status == :stable
46
+ end
45
47
 
46
- def deprecated?
47
- status == :deprecated
48
- end
48
+ def deprecated?
49
+ status == :deprecated
50
+ end
49
51
 
50
- def known?(status)
51
- STATUS.include?(status)
52
- end
52
+ def known?(status)
53
+ STATUS.include?(status)
54
+ end
53
55
 
54
- def unknown!(status)
55
- raise "Unknown status: #{status.inspect}. Known statuses are: #{STATUS.map(&:inspect).join(', ')}"
56
- end
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