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.
Files changed (100) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +172 -0
  3. data/CODE_OF_CONDUCT.md +74 -0
  4. data/CONTRIBUTING.md +392 -0
  5. data/Gemfile +32 -0
  6. data/Gemfile.lock +611 -0
  7. data/LICENSE +19 -0
  8. data/README.md +2744 -0
  9. data/Rakefile +210 -0
  10. data/bin/dpl +11 -0
  11. data/config/transliterate.yml +733 -0
  12. data/dpl.gemspec +23 -0
  13. data/lib/dpl/assets/atlas/install +19 -0
  14. data/lib/dpl/assets/convox/install +11 -0
  15. data/lib/dpl/assets/dpl/README.erb.md +138 -0
  16. data/lib/dpl/assets/dpl/git_ssh +8 -0
  17. data/lib/dpl/assets/git/detect_private_key +8 -0
  18. data/lib/dpl/assets/hephy/filter_log +3 -0
  19. data/lib/dpl/assets/pypi/install +4 -0
  20. data/lib/dpl/assets/scalingo/install +6 -0
  21. data/lib/dpl/cli.rb +100 -0
  22. data/lib/dpl/ctx/bash.rb +549 -0
  23. data/lib/dpl/ctx/test.rb +255 -0
  24. data/lib/dpl/ctx.rb +4 -0
  25. data/lib/dpl/helper/assets.rb +38 -0
  26. data/lib/dpl/helper/cmd.rb +169 -0
  27. data/lib/dpl/helper/config_file.rb +49 -0
  28. data/lib/dpl/helper/cookbook_site_streaming_uploader.rb +249 -0
  29. data/lib/dpl/helper/env.rb +92 -0
  30. data/lib/dpl/helper/github.rb +22 -0
  31. data/lib/dpl/helper/interpolate.rb +160 -0
  32. data/lib/dpl/helper/memoize.rb +23 -0
  33. data/lib/dpl/helper/squiggle.rb +24 -0
  34. data/lib/dpl/helper/transliterate.rb +13 -0
  35. data/lib/dpl/helper/wrap.rb +11 -0
  36. data/lib/dpl/helper/zip.rb +71 -0
  37. data/lib/dpl/provider/dsl.rb +410 -0
  38. data/lib/dpl/provider/examples.rb +132 -0
  39. data/lib/dpl/provider/status.rb +61 -0
  40. data/lib/dpl/provider.rb +651 -0
  41. data/lib/dpl/providers/anynines.rb +71 -0
  42. data/lib/dpl/providers/azure_web_apps.rb +63 -0
  43. data/lib/dpl/providers/bintray.rb +324 -0
  44. data/lib/dpl/providers/bluemixcloudfoundry.rb +98 -0
  45. data/lib/dpl/providers/boxfuse.rb +52 -0
  46. data/lib/dpl/providers/cargo.rb +32 -0
  47. data/lib/dpl/providers/chef_supermarket.rb +132 -0
  48. data/lib/dpl/providers/cloud66.rb +46 -0
  49. data/lib/dpl/providers/cloudfiles.rb +62 -0
  50. data/lib/dpl/providers/cloudformation.rb +281 -0
  51. data/lib/dpl/providers/cloudfoundry.rb +89 -0
  52. data/lib/dpl/providers/codedeploy.rb +190 -0
  53. data/lib/dpl/providers/convox.rb +130 -0
  54. data/lib/dpl/providers/datica.rb +64 -0
  55. data/lib/dpl/providers/ecr.rb +129 -0
  56. data/lib/dpl/providers/elasticbeanstalk.rb +207 -0
  57. data/lib/dpl/providers/engineyard.rb +113 -0
  58. data/lib/dpl/providers/firebase.rb +45 -0
  59. data/lib/dpl/providers/flynn.rb +35 -0
  60. data/lib/dpl/providers/gae.rb +78 -0
  61. data/lib/dpl/providers/gcs.rb +132 -0
  62. data/lib/dpl/providers/git_push.rb +273 -0
  63. data/lib/dpl/providers/gleis.rb +74 -0
  64. data/lib/dpl/providers/hackage.rb +53 -0
  65. data/lib/dpl/providers/hephy.rb +107 -0
  66. data/lib/dpl/providers/heroku/api.rb +123 -0
  67. data/lib/dpl/providers/heroku/git.rb +54 -0
  68. data/lib/dpl/providers/heroku.rb +111 -0
  69. data/lib/dpl/providers/lambda.rb +211 -0
  70. data/lib/dpl/providers/launchpad.rb +80 -0
  71. data/lib/dpl/providers/netlify.rb +38 -0
  72. data/lib/dpl/providers/npm.rb +130 -0
  73. data/lib/dpl/providers/nuget.rb +41 -0
  74. data/lib/dpl/providers/openshift.rb +52 -0
  75. data/lib/dpl/providers/opsworks.rb +146 -0
  76. data/lib/dpl/providers/packagecloud.rb_ +194 -0
  77. data/lib/dpl/providers/pages/api.rb +106 -0
  78. data/lib/dpl/providers/pages/git.rb +262 -0
  79. data/lib/dpl/providers/pages.rb +18 -0
  80. data/lib/dpl/providers/puppetforge.rb +50 -0
  81. data/lib/dpl/providers/pypi.rb +125 -0
  82. data/lib/dpl/providers/releases.rb +234 -0
  83. data/lib/dpl/providers/rubygems.rb +97 -0
  84. data/lib/dpl/providers/s3.rb +251 -0
  85. data/lib/dpl/providers/scalingo.rb +69 -0
  86. data/lib/dpl/providers/script.rb +32 -0
  87. data/lib/dpl/providers/snap.rb +68 -0
  88. data/lib/dpl/providers/surge.rb +59 -0
  89. data/lib/dpl/providers/testfairy.rb +101 -0
  90. data/lib/dpl/providers/transifex.rb +72 -0
  91. data/lib/dpl/providers.rb +48 -0
  92. data/lib/dpl/string_ext.rb +23 -0
  93. data/lib/dpl/support/aws_sdk_patch.rb +26 -0
  94. data/lib/dpl/support/gems.rb +73 -0
  95. data/lib/dpl/support/gstore_patch.rb +8 -0
  96. data/lib/dpl/support/version.rb +84 -0
  97. data/lib/dpl/version.rb +5 -0
  98. data/lib/dpl.rb +23 -0
  99. data/status.json +237 -0
  100. metadata +161 -0
@@ -0,0 +1,410 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dpl/helper/squiggle'
4
+ require 'dpl/helper/wrap'
5
+ require 'dpl/provider/status'
6
+
7
+ # TODO: figure out how to allow adding domain specific behavior like this to Cl
8
+ class Cl::Opt
9
+ OPTS << :interpolate
10
+
11
+ def interpolate?
12
+ opts[:interpolate]
13
+ end
14
+ end
15
+
16
+ module Dpl
17
+ class Provider < Cl::Cmd
18
+ # DSL available on the provider's class body.
19
+ #
20
+ # Use this to declare various features, requirements, and attributes that
21
+ # apply to your provider.
22
+ module Dsl
23
+ include Squiggle
24
+
25
+ # Declare the full name of the provider. Required if the proper provider
26
+ # name does not match the provider's class name.
27
+ #
28
+ # @param name [String] The provider's full name
29
+ # @return The previously declared full name if no argument is given
30
+ def full_name(name = nil)
31
+ name ? @full_name = name : @full_name || self.name.split('::').last
32
+ end
33
+
34
+ # Summary of the provider's functionality.
35
+ def summary(summary = nil)
36
+ summary ? super : @summary || "#{full_name} deployment provider"
37
+ end
38
+
39
+ # Summary of the provider's functionality.
40
+ def description(str = nil)
41
+ str = str.strip if str
42
+ super
43
+ end
44
+
45
+ # Set or read the provider's maturity status with an optional message
46
+ def status(status = nil, msg = nil)
47
+ status ? @status = Status.new(self, status, msg) : @status
48
+ end
49
+
50
+ # Declare additional variables available for interpolation.
51
+ #
52
+ # Interpolating strings, when these exposed to the user, should safelist
53
+ # which variables are available. Options declared on a provider are
54
+ # always available, except if they are flags, arrays, internal, or
55
+ # secrets. This method can be used to allow additional variables, e.g.
56
+ # from the git context.
57
+ def vars(*vars)
58
+ return self.vars.concat(vars) if vars.any?
59
+ return @vars if instance_variable_defined?(:@vars)
60
+
61
+ vars = superclass.respond_to?(:vars) ? superclass.vars : []
62
+ reject = %i[flag array internal interpolate secret]
63
+ opts = reject.inject(self.opts) { |options, attr| options.reject(&:"#{attr}?") }
64
+ @vars = vars.dup.concat(opts.map(&:name)).uniq.sort - [:strategy]
65
+ end
66
+
67
+ # @!method env
68
+ # Declare an environment variable prefix to accept env vars as options
69
+ #
70
+ # This method is defined in `Env::ClassMethods`.
71
+ #
72
+ # Declares an environment variable prefix that imports environment
73
+ # variables into `opts` if they match declared options.
74
+ #
75
+ # For example, with the following declaration on the class body:
76
+ #
77
+ # ```ruby
78
+ # env :aws
79
+ # opt '--access_key_id ID'
80
+ # ```
81
+ #
82
+ # if the environment variable `AWS_ACCESS_KEY_ID` is set then the option
83
+ # `opts[:access_key_id]` will default to the value given on that
84
+ # variable (i.e. it could still be overwritten by the user by passing
85
+ # the `--access_key_id` option).
86
+
87
+ # @!method opt
88
+ # Declare command line options that the provider supports.
89
+ #
90
+ # This method is inherited from the base class `Cl::Cmd` which is defined
91
+ # in the Rubygem `Cl`. See the gem's documentation for details on how
92
+ # to declare command line options.
93
+ #
94
+ # @see https://github.com/svenfuchs/cl
95
+
96
+ def path(path)
97
+ ENV['PATH'] = "#{File.expand_path(path)}:#{ENV['PATH']}"
98
+ end
99
+
100
+ def move(*paths)
101
+ paths.any? ? @move = paths : @move ||= []
102
+ end
103
+
104
+ def node_js(*requirements)
105
+ runtimes(:node_js, requirements)
106
+ end
107
+
108
+ def python(*requirements)
109
+ runtimes(:python, requirements)
110
+ end
111
+
112
+ def runtimes(name = nil, requirements = nil)
113
+ return @runtimes ||= [] unless name
114
+
115
+ runtimes << [name, requirements]
116
+ end
117
+
118
+ # Declare APT packages the provider depends on. These will be installed
119
+ # during the `before_install` stage using `apt-get install`, unless the
120
+ # given cmd is already available according to `which [cmd]`.
121
+ #
122
+ # @param package [String] Package name (required).
123
+ # @param cmd [String] Executable command installed by that package (optional, defaults to the package name).
124
+ #
125
+ # @return Previously declared apt packages if no arguments were given.
126
+ def apt(package = nil, cmd = nil)
127
+ return apt << [package, cmd].compact if package
128
+
129
+ @apt ||= self == Provider ? [] : superclass.apt.dup
130
+ end
131
+
132
+ # Whether or not the provider depends on any apt packages.
133
+ def apt?
134
+ apt.any?
135
+ end
136
+
137
+ # Declare additional paths to Ruby gem source code that this provider
138
+ # requires.
139
+ #
140
+ # These gems will be installed, and files required at runtime, during the
141
+ # `before_init` stage (not at install time, and/or load time), unless they
142
+ # are already installed.
143
+ #
144
+ # @param name [String] Ruby gem name (required)
145
+ # @param version [String] Ruby gem version (required)
146
+ # @param opts [Hash] options
147
+ # @option opts [Array<String>, String] :require A single path or a list of paths to source files to require from this Ruby gem. If not given the name of the gem will be assumed to be the path to be required.
148
+ #
149
+ # @return Previously declared gems if no arguments were given
150
+ def gem(name = nil, version = nil, opts = {})
151
+ return gem << [name, version, opts] if name
152
+
153
+ @gem ||= self == Provider ? [] : superclass.gem.dup
154
+ end
155
+
156
+ def gem?
157
+ gem.any?
158
+ end
159
+
160
+ # Declare NPM packages the provider depends on. These will be installed
161
+ # during the `before_install` stage using `npm install -g`, unless the
162
+ # given cmd is already available according to `which [cmd]`.
163
+ #
164
+ # @param package [String] Package name (required).
165
+ # @param cmd [String] Executable command installed by that package (optional, defaults to the package name).
166
+ #
167
+ # @return Previously declared NPM packages if no arguments are given.
168
+ def npm(package = nil, cmd = nil)
169
+ return npm << [package, cmd].compact if package
170
+
171
+ @npm ||= self == Provider ? [] : superclass.npm.dup
172
+ end
173
+
174
+ # Whether or not the provider depends on any NPM packages.
175
+ def npm?
176
+ npm.any?
177
+ end
178
+
179
+ # Declare Python packages the provider depends on. These will be installed
180
+ # during the `before_install` stage using `pip install --user`. A previously
181
+ # installed package is uninstalled before that, but only if `version` was
182
+ # given.
183
+ #
184
+ # @param package [String] Package name (required).
185
+ # @param cmd [String] Executable command installed by that package (optional, defaults to the package name).
186
+ # @param version [String] Package version (optional).
187
+ #
188
+ # @return Previously declared Python packages if no arguments are given.
189
+ def pip(package = nil, cmd = nil, version = nil)
190
+ return pip << [package, cmd, version].compact if package
191
+
192
+ @pip ||= self == Provider ? [] : superclass.pip.dup
193
+ end
194
+
195
+ # Whether or not the provider depends on any Python packages.
196
+ def pip?
197
+ pip.any?
198
+ end
199
+
200
+ # Declare shell commands used by the provider.
201
+ #
202
+ # This exists so shell commands used can be separated from the
203
+ # implementation that runs them. This is useful in order to easily get an
204
+ # overview of all shell commands used by a provider on one hand, and in
205
+ # order to keep the implementation code focussed on the logic and
206
+ # functionality it provides, rather than the details of (potentially long
207
+ # winded) shell commands.
208
+ #
209
+ # For example, a shell command declared on the class body like so:
210
+ #
211
+ # ```ruby
212
+ # cmds git_push: 'git push -f %{target}'
213
+ # ```
214
+ #
215
+ # can be used in the deploy stage like so:
216
+ #
217
+ # ```ruby
218
+ # def deploy
219
+ # shell :git_push
220
+ # end
221
+ # ```
222
+ #
223
+ # The variable `%{target}` will be interpolated by calling the method
224
+ # `target` on the provider instance, so it will expect that method to
225
+ # exist.
226
+ #
227
+ # @param cmds [Hash] Commands to declare.
228
+ # @return Previously declared cmds if no argument is given.
229
+ #
230
+ # @see Dpl::Ctx::Bash#shell Ctx::Bash#shell for more details on how to call shell
231
+ # commands.
232
+ def cmds(cmds = nil)
233
+ return self.cmds.update(cmds) if cmds
234
+
235
+ @cmds ||= self == Provider ? {} : superclass.cmds.dup
236
+ end
237
+
238
+ # Declare error messages that are raised if a shell command fails.
239
+ #
240
+ # This exists so error messages can be separated from the implementation
241
+ # that uses them. This is useful in order to easily get an overview of
242
+ # all error messages used by a provider on one hand, and in order to keep
243
+ # the implementation code focussed on the logic and functionality it
244
+ # provides, rather than the details of (potentially long winded) error
245
+ # message strings.
246
+ #
247
+ # The method `shell` will raise an error if the given shell command fails
248
+ # (returns a non-zero exit code) unless it is called with the option
249
+ # `assert: false`. The error message declared using `errs` will be used
250
+ # to raise with the eror.
251
+ #
252
+ # For example, an error message declared on the class body like so:
253
+ #
254
+ # ```ruby
255
+ # errs git_push: 'Failed to push to %{target}'
256
+ # ```
257
+ #
258
+ # will be included to the raised error if the given command has failed:
259
+ #
260
+ # ```ruby
261
+ # def deploy
262
+ # shell :git_push
263
+ # end
264
+ # ```
265
+ #
266
+ # The variable `%{target}` will be interpolated by calling the method
267
+ # `target` on the provider instance, so it will expect that method to
268
+ # exist.
269
+ #
270
+ # @param errs [Hash] Error messages to declare.
271
+ # @return Previously declared errs if no argument is given.
272
+ #
273
+ # See Dpl::Ctx::Bash#shell for more details on how to call shell
274
+ # commands.
275
+ def errs(errs = nil)
276
+ return self.errs.update(errs) if errs
277
+
278
+ @errs ||= self == Provider ? {} : superclass.errs.dup
279
+ end
280
+
281
+ # Declare other messages, such as info level log output, warnings, or
282
+ # custom strings, such as commit messages or descriptions.
283
+ #
284
+ # This exists so various messages can be separated from the
285
+ # implementation that uses them. This is useful in order to easily get an
286
+ # overview of all error messages used by a provider on one hand, and in
287
+ # order to keep the implementation code focussed on the logic and
288
+ # functionality it provides, rather than the details of (potentially long
289
+ # winded) message strings.
290
+ #
291
+ # For example, a message declared on the class body like so:
292
+ #
293
+ # ```ruby
294
+ # msgs login: 'Logging in to the service %{full_name}'
295
+ # ```
296
+ #
297
+ # could be used by the implementation like so:
298
+ #
299
+ # ```ruby
300
+ # def login
301
+ # info :login
302
+ # end
303
+ # ```
304
+ #
305
+ # The variable `%{full_name}` will be interpolated by calling the method
306
+ # `full_name` on the provider instance, so it will expect that method to
307
+ # exist.
308
+ #
309
+ # It is possible to use msgs in order to declare and use custom messages,
310
+ # e.g. for the commit message on a commit a provider needs to create, or
311
+ # a description that needs to be included to an API call.
312
+ #
313
+ # For example, a message declared on the class body like so:
314
+ #
315
+ # ```ruby
316
+ # cmds git_commit: 'git commit -am "%{commit_msg}"'
317
+ # msgs commit_msg: 'Commit build artifacts on build %{build_number}'
318
+ # ```
319
+ #
320
+ # could be used by the implementation like so:
321
+ #
322
+ # ```ruby
323
+ # def create_commit
324
+ # shell :git_commit
325
+ # end
326
+ #
327
+ # def commit_msg
328
+ # interpolate(msg(:commit_msg))
329
+ # end
330
+ # ```
331
+ #
332
+ # Note that in cases where builtin methods such as `shell`, `info`,
333
+ # `warn` etc. are not used the method `interpolate` needs to be used in
334
+ # order to interpolate variables used in a message (if any).
335
+ #
336
+ # @param msgs [Hash] Messages to declare.
337
+ # @return Previously declared msgs if no argument is given.
338
+ def msgs(msgs = nil)
339
+ return self.msgs.update(msgs) if msgs
340
+
341
+ @msgs ||= self == Provider ? {} : superclass.msgs.dup
342
+ end
343
+
344
+ def strs(strs = nil)
345
+ return self.strs.update(strs) if strs
346
+
347
+ @strs ||= self == Provider ? {} : superclass.strs.dup
348
+ end
349
+
350
+ # Declare artifacts, such as executables during the `install` stage that
351
+ # need to be kept during `cleanup`.
352
+ #
353
+ # @param paths [String] Paths to artifacts to keep during `cleanup`
354
+ # @return Previously declared artifacts to keep if no argument is given.
355
+ def keep(*paths)
356
+ return keep.concat(paths) if paths.any?
357
+
358
+ @keep ||= self == Provider ? [] : superclass.keep.dup
359
+ end
360
+
361
+ # Declare features that the provider needs.
362
+ #
363
+ # Known features currently are:
364
+ #
365
+ # * `ssh_key`: Generates a temporary, per-build SSH key, and calls the
366
+ # methods `add_key` and `remove_key` if the provider defines them.
367
+ # This gives providers the opportunity to install this key on their
368
+ # service, and remove it after the deployment has finished.
369
+ # * `git`: Populates the git config.user and config.email attributes,
370
+ # unless present.
371
+ # * `git_http_user_agent`: Changes the environment variable
372
+ # `GIT_HTTP_USER_AGENT` to the one generated by `user_agent`. This
373
+ # gives providers the opportunity to identify and track coming from
374
+ # Travis CI and/or dpl.
375
+ #
376
+ # @param features [Symbol] Features to activate for this provider
377
+ # @return Previously declared features needed if no argument is given.
378
+ def needs(*features)
379
+ return needs.concat(features) if features.any?
380
+
381
+ @needs ||= self == Provider ? [] : superclass.needs.dup
382
+ end
383
+
384
+ # Whether or not the provider has declared any features it needs.
385
+ def needs?(feature)
386
+ needs.include?(feature)
387
+ end
388
+
389
+ # Generates a useragent string that identifies the current dpl version,
390
+ # and whether it runs int he context of Travis CI. Can include arbitrary
391
+ # extra strings or key value pairs (passed as String or Hash arguments).
392
+ # @param strs [String(s) or Hash(es)] Additional strings or key value pairs to include to the useragent string.
393
+ # @return [String] The useragent string
394
+ def user_agent(*strs)
395
+ strs.unshift "dpl/#{Dpl::VERSION}"
396
+ strs.unshift 'travis/0.1.0' if ENV['TRAVIS']
397
+ strs = strs.flat_map { |e| e.is_a?(Hash) ? e.map { |k, v| "#{k}/#{v}" } : e }
398
+ strs.join(' ').gsub(/\s+/, ' ').strip
399
+ end
400
+
401
+ def ruby_version
402
+ Gem::Version.new(RUBY_VERSION)
403
+ end
404
+
405
+ def ruby_pre?(version)
406
+ ruby_version < Gem::Version.new(version)
407
+ end
408
+ end
409
+ end
410
+ end
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dpl
4
+ class Examples < Struct.new(:const)
5
+ def cmds
6
+ examples.map(&:cmd).join("\n")
7
+ end
8
+
9
+ def full_config
10
+ full.config
11
+ end
12
+
13
+ def configs
14
+ examples.map(&:config)
15
+ end
16
+
17
+ def examples
18
+ [requireds, required, many].flatten.compact.uniq
19
+ end
20
+
21
+ def requireds
22
+ requireds_opts.map { |opts| example(opts) }
23
+ end
24
+
25
+ def required
26
+ opts = required_opts
27
+ example(opts)
28
+ end
29
+
30
+ def many
31
+ opts = const.opts.opts
32
+ opts = order(opts)
33
+ opts = without_required(opts)
34
+ opts = with_required(opts)
35
+ opts = filter(opts)
36
+ opts = opts[0, 5]
37
+ example(opts)
38
+ end
39
+
40
+ def full
41
+ opts = const.opts.opts
42
+ opts = filter(opts)
43
+ example(opts)
44
+ end
45
+
46
+ def filter(opts)
47
+ opts = opts.reject(&:internal?)
48
+ opts.reject { |opt| opt.name == :help }
49
+ end
50
+
51
+ def order(opts)
52
+ cmmn = const.superclass.opts.opts
53
+ opts - cmmn + cmmn
54
+ end
55
+
56
+ def with_required(opts)
57
+ requireds = requireds_opts.first || []
58
+ opts = requireds + required_opts + opts
59
+ opts.uniq
60
+ end
61
+
62
+ def without_required(opts)
63
+ opts -= const.required.flatten.map { |key| const.opts[key] }
64
+ opts - required_opts.map(&:opts)
65
+ end
66
+
67
+ def example(opts)
68
+ return unless opts.any?
69
+
70
+ opts = required_opts.concat(opts).uniq.compact
71
+ Example.new(const, opts)
72
+ end
73
+
74
+ def requireds_opts
75
+ opts = const.required.flatten(1)
76
+ opts.map { |keys| Array(keys).map { |key| const.opts[key] } }
77
+ end
78
+
79
+ def required_opts
80
+ const.opts.select(&:required?)
81
+ end
82
+ end
83
+
84
+ class Example < Struct.new(:const, :opts)
85
+ def config
86
+ config = opts_for(opts)
87
+ config = config.merge(strategy: strategy) # hmm.
88
+ compact(config)
89
+ end
90
+
91
+ def strategy
92
+ const.registry_key.to_s.split(':').last if const.registry_key.to_s.include?(':')
93
+ end
94
+
95
+ def cmd
96
+ "dpl #{name} #{strs_for(opts)}"
97
+ end
98
+
99
+ def ==(other)
100
+ const == other.const && opts == other.opts
101
+ end
102
+
103
+ def name
104
+ const.registry_key.to_s.split(':').join(' ')
105
+ end
106
+
107
+ def opts_for(opts)
108
+ opts.map { |opt| [opt.name, value_for(opt)] }.to_h
109
+ end
110
+
111
+ def strs_for(opts)
112
+ opts.map { |opt| str_for(opt) }.join(' ')
113
+ end
114
+
115
+ def str_for(opt)
116
+ "--#{opt.name} #{value_for(opt)}".strip
117
+ end
118
+
119
+ def value_for(opt)
120
+ return if opt.type == :flag
121
+ return 1 if opt.type == :integer
122
+ return opt.enum.first if opt.enum?
123
+
124
+ str = opt.strs.detect { |str| str =~ /^--#{opt.name} (.*)$/ } && ::Regexp.last_match(1)
125
+ str ? str.downcase : 'str'
126
+ end
127
+
128
+ def compact(hash)
129
+ hash.reject { |_, value| value.nil? }
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dpl
4
+ class Provider < Cl::Cmd
5
+ class Status < Struct.new(:provider, :status, :info)
6
+ STATUS = %i[dev alpha beta stable deprecated].freeze
7
+
8
+ MSG = {
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**',
12
+ deprecated: 'Support for deployments to %s is *deprecated**',
13
+ pre_stable: 'Please see [Maturity Levels](%s) for details.'
14
+ }.freeze
15
+
16
+ URL = 'https://github.com/travis-ci/dpl/#maturity-levels'
17
+
18
+ def initialize(provider, status, info)
19
+ unknown!(status) unless known?(status)
20
+ super
21
+ end
22
+
23
+ def announce?
24
+ !stable?
25
+ end
26
+
27
+ def msg
28
+ msg = (MSG[status] % name).to_s
29
+ msg << "(#{info})" if info
30
+ msg << ". #{MSG[:pre_stable] % URL}" if pre_stable?
31
+ msg
32
+ end
33
+
34
+ private
35
+
36
+ def name
37
+ provider.full_name
38
+ end
39
+
40
+ def pre_stable?
41
+ STATUS.index(status) < STATUS.index(:stable)
42
+ end
43
+
44
+ def stable?
45
+ status == :stable
46
+ end
47
+
48
+ def deprecated?
49
+ status == :deprecated
50
+ end
51
+
52
+ def known?(status)
53
+ STATUS.include?(status)
54
+ end
55
+
56
+ def unknown!(status)
57
+ raise "Unknown status: #{status.inspect}. Known statuses are: #{STATUS.map(&:inspect).join(', ')}"
58
+ end
59
+ end
60
+ end
61
+ end