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.
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