dpl 2.0.0.alpha.2 → 2.0.0.alpha.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +34 -1
  3. data/Gemfile.lock +13 -8
  4. data/NOTES.md +1 -74
  5. data/README.md +464 -193
  6. data/lib/dpl/assets/convox/install +11 -0
  7. data/lib/dpl/assets/dpl/README.erb.md +4 -0
  8. data/lib/dpl/cli.rb +54 -18
  9. data/lib/dpl/ctx/test.rb +7 -3
  10. data/lib/dpl/helper/env.rb +67 -18
  11. data/lib/dpl/helper/wrap.rb +9 -0
  12. data/lib/dpl/provider.rb +11 -9
  13. data/lib/dpl/provider/dsl.rb +3 -1
  14. data/lib/dpl/provider/status.rb +6 -6
  15. data/lib/dpl/providers.rb +3 -1
  16. data/lib/dpl/providers/anynines.rb +5 -3
  17. data/lib/dpl/providers/azure_web_apps.rb +1 -1
  18. data/lib/dpl/providers/bintray.rb +2 -0
  19. data/lib/dpl/providers/bluemixcloudfoundry.rb +5 -3
  20. data/lib/dpl/providers/boxfuse.rb +1 -1
  21. data/lib/dpl/providers/cargo.rb +10 -1
  22. data/lib/dpl/providers/chef_supermarket.rb +3 -1
  23. data/lib/dpl/providers/cloud66.rb +2 -0
  24. data/lib/dpl/providers/cloudfiles.rb +2 -0
  25. data/lib/dpl/providers/cloudformation.rb +278 -0
  26. data/lib/dpl/providers/cloudfoundry.rb +6 -4
  27. data/lib/dpl/providers/codedeploy.rb +5 -5
  28. data/lib/dpl/providers/convox.rb +121 -0
  29. data/lib/dpl/providers/datica.rb +1 -1
  30. data/lib/dpl/providers/engineyard.rb +2 -0
  31. data/lib/dpl/providers/gae.rb +6 -7
  32. data/lib/dpl/providers/gcs.rb +5 -3
  33. data/lib/dpl/providers/gleis.rb +70 -0
  34. data/lib/dpl/providers/hackage.rb +2 -0
  35. data/lib/dpl/providers/hephy.rb +3 -1
  36. data/lib/dpl/providers/heroku.rb +4 -8
  37. data/lib/dpl/providers/heroku/api.rb +4 -2
  38. data/lib/dpl/providers/heroku/git.rb +3 -1
  39. data/lib/dpl/providers/lambda.rb +4 -4
  40. data/lib/dpl/providers/launchpad.rb +3 -1
  41. data/lib/dpl/providers/netlify.rb +2 -0
  42. data/lib/dpl/providers/npm.rb +2 -0
  43. data/lib/dpl/providers/openshift.rb +2 -0
  44. data/lib/dpl/providers/opsworks.rb +1 -1
  45. data/lib/dpl/providers/packagecloud.rb +2 -0
  46. data/lib/dpl/providers/pages.rb +4 -7
  47. data/lib/dpl/providers/pages/api.rb +16 -12
  48. data/lib/dpl/providers/pages/git.rb +16 -12
  49. data/lib/dpl/providers/puppetforge.rb +2 -0
  50. data/lib/dpl/providers/pypi.rb +2 -0
  51. data/lib/dpl/providers/releases.rb +8 -6
  52. data/lib/dpl/providers/rubygems.rb +3 -1
  53. data/lib/dpl/providers/s3.rb +7 -7
  54. data/lib/dpl/providers/scalingo.rb +2 -0
  55. data/lib/dpl/providers/testfairy.rb +2 -0
  56. data/lib/dpl/providers/transifex.rb +2 -0
  57. data/lib/dpl/version.rb +1 -1
  58. metadata +7 -3
  59. data/lib/dpl/providers/atlas.rb +0 -49
@@ -0,0 +1,11 @@
1
+ #!/bin/bash
2
+
3
+ if ! command -v convox &> /dev/null; then
4
+ echo "Downloading convox CLI"
5
+ mkdir -p $HOME/bin
6
+ export PATH="$HOME/bin:$PATH"
7
+ curl -sL -o $HOME/bin/convox %{install_url}
8
+ chmod +x $HOME/bin/convox
9
+ else
10
+ echo "Convox CLI exists. Skipping installation"
11
+ fi
@@ -101,9 +101,13 @@ Dpl supports the following providers:
101
101
  <% providers.each do |key, name|%>
102
102
  ### <%= name %>
103
103
 
104
+ <%= header(key) %>
105
+
104
106
  ```
105
107
  <%= help(key) %>
106
108
  ```
109
+
110
+ <%= footer(key) %>
107
111
  <% end -%>
108
112
 
109
113
  <%= File.read('./CONTRIBUTING.md').gsub(/^#/, '##') %>
@@ -8,37 +8,77 @@ module Dpl
8
8
  end
9
9
 
10
10
  def run(args)
11
- args = untaint(args)
12
- args = with_provider_opt(args)
13
11
  super
14
- rescue UnknownCmd
15
- unknown_provider(args.first)
16
- rescue Error => e
12
+ rescue UnknownCmd => e
13
+ unknown_provider(e)
14
+ rescue UnknownOption => e
15
+ unknown_option(e)
16
+ rescue Cl::Error, Error => e
17
17
  error(e)
18
18
  end
19
19
 
20
+ def runner(args)
21
+ super(normalize(args))
22
+ end
23
+
24
+ def normalize(args)
25
+ args = untaint(args)
26
+ args = with_cmd_opts(args, provider: 0, strategy: 1)
27
+ args = with_strategy_default(args, :strategy) # should be a generic dispatch feature in Cl
28
+ args
29
+ end
30
+
20
31
  # Tainting is being used for automatically obfuscating values for secure
21
32
  # options, so we want to untaint all incoming args here.
22
33
  def untaint(args)
23
34
  args.map(&:dup).each(&:untaint)
24
35
  end
25
36
 
26
- # backwards compatibility for travis-build dpl v1 integration
27
- def with_provider_opt(args)
28
- return args unless arg = args.detect { |arg| arg.include?('--provider') }
29
- args.delete(arg)
30
- [arg.split('=').last, *args]
37
+ def with_cmd_opts(args, cmds)
38
+ cmds.inject(args) do |args, (cmd, pos)|
39
+ with_cmd_opt(args, cmd, pos)
40
+ end
41
+ end
42
+
43
+ def with_cmd_opt(args, cmd, pos)
44
+ return args unless opt = args.detect { |arg| arg.start_with?("--#{cmd}") }
45
+ ix = args.index(opt)
46
+ args.delete(opt)
47
+ value = opt.include?('=') ? opt.split('=').last : args.delete_at(ix)
48
+ args.insert(pos, value)
49
+ args
50
+ end
51
+
52
+ STRATEGIES = {
53
+ 'heroku' => 'api',
54
+ 'pages' => 'git'
55
+ }
56
+
57
+ def with_strategy_default(args, cmd)
58
+ return args unless default = STRATEGIES[args.first]
59
+ args.insert(1, default) if args[1].nil? || args[1].to_s.start_with?('--')
60
+ args
31
61
  end
32
62
 
33
63
  def error(e)
34
64
  msg = "\e[31m#{e.message}\e[0m"
35
- msg = [msg, *e.backtrace].join("\n") if e.backtrace?
65
+ msg = [msg, *e.backtrace].join("\n") if backtrace?(e)
66
+ abort msg
67
+ end
68
+
69
+ def backtrace?(e)
70
+ e.respond_to?(:backtrace?) && e.backtrace?
71
+ end
72
+
73
+ def unknown_provider(e)
74
+ msg = "\e[31m#{e.message}\e[0m"
75
+ msg << "\nDid you mean: #{e.suggestions.join(', ')}?" if e.suggestions.any?
36
76
  abort msg
37
77
  end
38
78
 
39
- def unknown_provider(name)
40
- msg = "\e[31mUnknown provider: #{name}\e[0m"
41
- msg << "\nDid you mean: #{suggestions(name).join(', ')}?" if suggestions(name).any?
79
+ def unknown_option(e)
80
+ msg = "\e[31m#{e.message}\e[0m"
81
+ msg << "\nDid you mean: #{e.suggestions.join(', ')}?" if e.suggestions.any?
42
82
  abort msg
43
83
  end
44
84
 
@@ -46,9 +86,5 @@ module Dpl
46
86
  return [] unless defined?(DidYouMean)
47
87
  DidYouMean::SpellChecker.new(dictionary: providers).correct(name)
48
88
  end
49
-
50
- def providers
51
- Cl::Cmd.registry.keys.map(&:to_s)
52
- end
53
89
  end
54
90
  end
@@ -60,8 +60,8 @@ module Dpl
60
60
  info cmd.msg if cmd.msg?
61
61
  info cmd.echo if cmd.echo?
62
62
  cmds << cmd.cmd
63
- return true unless cmd.capture?
64
- stdout[cmd.key] || 'captured_stdout'
63
+ return stdout[cmd.key] if stdout.key?(cmd.key)
64
+ cmd.capture? ? 'captured_stdout' : true
65
65
  end
66
66
 
67
67
  def success?
@@ -86,7 +86,7 @@ module Dpl
86
86
 
87
87
  def deprecate_opt(key, msg)
88
88
  msg = "please use #{msg}" if msg.is_a?(Symbol)
89
- warn("deprecated option #{key} (#{msg})")
89
+ warn "Deprecated option #{key} used (#{msg})."
90
90
  end
91
91
 
92
92
  def repo_name
@@ -105,6 +105,10 @@ module Dpl
105
105
  1
106
106
  end
107
107
 
108
+ def git_branch
109
+ 'git branch'
110
+ end
111
+
108
112
  def git_commit_msg
109
113
  'commit msg'
110
114
  end
@@ -1,35 +1,84 @@
1
+ require 'dpl/helper/memoize'
2
+
1
3
  module Dpl
2
4
  module Env
3
5
  def self.included(base)
4
6
  base.extend(ClassMethods)
5
7
  end
6
8
 
9
+ class Env
10
+ include Memoize
11
+ # opts[:allow_skip_underscore] allows unconventional ENV vars such as GOOGLECLOUDKEYFILE
12
+
13
+ attr_reader :cmd, :env, :strs, :keys, :opts
14
+
15
+ def initialize(env, args)
16
+ @env = env
17
+ @opts = args.last.is_a?(Hash) ? args.pop : {}
18
+ @strs = args.map(&:to_s).map(&:upcase)
19
+ end
20
+
21
+ def env(cmd)
22
+ @cmd = cmd
23
+ 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
+ end
27
+
28
+ def description(cmd)
29
+ strs = self.strs.map { |str| "#{str}_" }
30
+ strs += self.strs if opts[:allow_skip_underscore]
31
+ strs = strs.size > 1 ? "[#{strs.sort.join('|')}]" : strs.join
32
+ "Options can be given via env vars if prefixed with `#{strs}`. #{example(cmd)}"
33
+ end
34
+
35
+ 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]
39
+ "E.g. the option `--#{opt.name}` can be given as #{sentence(env)}."
40
+ end
41
+
42
+ def sentence(strs)
43
+ return strs.join if strs.size == 1
44
+ [strs[0..-2].join(', '), strs[-1]].join(' or ')
45
+ end
46
+
47
+ private
48
+
49
+ def dealias(key)
50
+ opt = cmd.opts.detect { |opt| opt.aliases.include?(key) }
51
+ opt ? opt.name : key
52
+ end
53
+
54
+ def unprefix(key)
55
+ strs.inject(key) { |key, str| key.sub(/^#{str}_?/, '') }
56
+ end
57
+
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
63
+
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
69
+ end
70
+
7
71
  # should this sit in Cl?
8
72
  module ClassMethods
9
- attr_reader :env_prefixes
10
-
11
73
  def env(*strs)
12
- opts = strs.last.is_a?(Hash) ? strs.pop : {}
13
74
  if strs.any?
14
- strs = strs.map(&:to_s).map(&:upcase)
15
- @env_prefixes = strs.map { |str| "#{str.to_s.upcase}_" }
16
- # allow unconventional ENV vars such as GOOGLECLOUDKEYFILE
17
- @env_prefixes += strs if opts[:allow_skip_underscore]
18
- elsif env_prefixes
19
- opts = ENV.select { |key, _| prefixed?(key) }
20
- opts.map { |key, value| [unprefix(key).downcase.to_sym, value] }.to_h
75
+ @env = Env.new(ENV, strs)
76
+ elsif env = @env || superclass.instance_variable_get(:@env)
77
+ env.env(self)
21
78
  else
22
79
  {}
23
80
  end
24
81
  end
25
-
26
- def prefixed?(key)
27
- env_prefixes.any? { |prefix| key.to_s.start_with?(prefix) }
28
- end
29
-
30
- def unprefix(key)
31
- env_prefixes.inject(key) { |key, prefix| key.sub(prefix, '') }
32
- end
33
82
  end
34
83
 
35
84
  def opts
@@ -0,0 +1,9 @@
1
+ module Wrap
2
+ extend self
3
+
4
+ def wrap(str, width = 80)
5
+ str.lines.map do |line|
6
+ line.size > width ? line.gsub(/(.{1,#{width}})(\s+|$)/, "\\1\n").strip : line
7
+ end.join("\n")
8
+ end
9
+ end
@@ -147,8 +147,8 @@ module Dpl
147
147
 
148
148
  arg :provider, 'The provider name', required: true
149
149
 
150
- opt '--run CMD', 'Command to execute after the deployment finished successfully', type: :array
151
- opt '--cleanup', 'Skip cleaning up build artifacts before the deployment', negate: %w(skip)
150
+ opt '--cleanup', 'Clean up build artifacts from the Git working directory before the deployment', negate: %w(skip)
151
+ opt '--run CMD', 'Commands to execute after the deployment finished successfully', type: :array
152
152
  opt '--stage NAME', 'Execute the given stage(s) only', type: :array, internal: true, default: STAGES
153
153
  opt '--backtrace', 'Print the backtrace for exceptions', internal: true
154
154
  opt '--fold', 'Wrap log output in folds', internal: true
@@ -170,13 +170,15 @@ module Dpl
170
170
  :validate_runtimes, :user_agent
171
171
 
172
172
  def_delegators :ctx, :apt_get, :gem_require, :npm_install, :pip_install,
173
- :build_dir, :build_number, :repo_slug, :encoding, :git_author_email,
174
- :git_author_name, :git_branch, :git_commit_msg, :git_dirty?, :git_log,
175
- :git_ls_files, :git_ls_remote?, :git_remote_urls, :git_rev_parse,
176
- :git_sha, :git_tag, :machine_name, :node_version, :npm_version, :sleep,
177
- :ssh_keygen, :success?, :tmp_dir, :which, :logger, :rendezvous,
178
- :file_size, :write_file, :write_netrc, :last_out, :last_err, :test?,
179
- :tty?
173
+ :build_dir, :build_number, :encoding, :file_size, :git_author_email,
174
+ :git_author_name, :git_branch, :git_branch, :git_commit_author,
175
+ :git_commit_msg, :git_commit_msg, :git_dirty?, :git_log, :git_log,
176
+ :git_ls_files, :git_ls_remote?, :git_remote_urls, :git_remote_urls,
177
+ :git_rev_parse, :git_rev_parse, :git_sha, :git_tag, :last_err, :last_out,
178
+ :last_out, :logger, :machine_name, :mv, :node_version, :node_version,
179
+ :npm_version, :rendezvous, :rendezvous, :repo_slug, :sleep, :sleep,
180
+ :ssh_keygen, :success?, :test?, :test?, :tmp_dir, :tty?, :which, :which,
181
+ :write_file, :write_netrc
180
182
 
181
183
  attr_reader :repo_name, :key_name
182
184
 
@@ -1,3 +1,5 @@
1
+ require 'dpl/helper/squiggle'
2
+ require 'dpl/helper/wrap'
1
3
  require 'dpl/provider/status'
2
4
 
3
5
  module Dpl
@@ -25,7 +27,7 @@ module Dpl
25
27
 
26
28
  # Summary of the provider's functionality.
27
29
  def description(str = nil)
28
- str << status.msg if str && status && status.announce?
30
+ str = str.strip if str
29
31
  super
30
32
  end
31
33
 
@@ -4,11 +4,11 @@ module Dpl
4
4
  STATUS = %i(dev alpha beta stable deprecated)
5
5
 
6
6
  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',
10
- deprecated: 'Support for deployments to %s is deprecated',
11
- pre_stable: 'Please see here: %s'
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**',
10
+ deprecated: 'Support for deployments to %s is *deprecated**',
11
+ pre_stable: 'Please see [Maturity Levels](%s) for details.'
12
12
  }
13
13
 
14
14
  URL = 'https://github.com/travis-ci/dpl/#maturity-levels'
@@ -26,7 +26,7 @@ module Dpl
26
26
  msg = "#{MSG[status] % name}"
27
27
  msg << "(#{info})" if info
28
28
  msg << ". #{MSG[:pre_stable] % URL}" if pre_stable?
29
- "\n#{msg}\n"
29
+ msg
30
30
  end
31
31
 
32
32
  private
@@ -1,5 +1,4 @@
1
1
  require 'dpl/providers/anynines'
2
- require 'dpl/providers/atlas'
3
2
  require 'dpl/providers/azure_web_apps'
4
3
  require 'dpl/providers/bintray'
5
4
  require 'dpl/providers/boxfuse'
@@ -9,13 +8,16 @@ require 'dpl/providers/datica'
9
8
  require 'dpl/providers/chef_supermarket'
10
9
  require 'dpl/providers/cloud66'
11
10
  require 'dpl/providers/cloudfiles'
11
+ require 'dpl/providers/cloudformation'
12
12
  require 'dpl/providers/cloudfoundry'
13
13
  require 'dpl/providers/codedeploy'
14
+ require 'dpl/providers/convox'
14
15
  require 'dpl/providers/elasticbeanstalk'
15
16
  require 'dpl/providers/engineyard'
16
17
  require 'dpl/providers/firebase'
17
18
  require 'dpl/providers/gae'
18
19
  require 'dpl/providers/gcs'
20
+ require 'dpl/providers/gleis'
19
21
  require 'dpl/providers/hackage'
20
22
  require 'dpl/providers/hephy'
21
23
  require 'dpl/providers/heroku'
@@ -7,12 +7,14 @@ module Dpl
7
7
  tbd
8
8
  str
9
9
 
10
+ env :anynines
11
+
10
12
  opt '--username USER', 'anynines username', required: true
11
13
  opt '--password PASS', 'anynines password', required: true, secret: true
12
- opt '--organization ORG', 'anynines target organization', required: true
13
- opt '--space SPACE', 'anynines target space', required: true
14
+ opt '--organization ORG', 'anynines organization', required: true
15
+ opt '--space SPACE', 'anynines space', required: true
14
16
  opt '--app_name APP', 'Application name'
15
- opt '--buildpack PACK', 'Custom buildpack name or Git URL'
17
+ opt '--buildpack PACK', 'Buildpack name or Git URL'
16
18
  opt '--manifest FILE', 'Path to the manifest'
17
19
  opt '--logout', default: true, internal: true
18
20
 
@@ -11,9 +11,9 @@ module Dpl
11
11
 
12
12
  env :AZURE_WA
13
13
 
14
- opt '--site SITE', 'Web App name (e.g. myapp in myapp.azurewebsites.net)', required: true
15
14
  opt '--username NAME', 'Web App Deployment Username', required: true
16
15
  opt '--password PASS', 'Web App Deployment Password', required: true, secret: true
16
+ opt '--site SITE', 'Web App name (e.g. myapp in myapp.azurewebsites.net)', required: true
17
17
  opt '--slot SLOT', 'Slot name (if your app uses staging deployment)'
18
18
  opt '--verbose', 'Print deployment output from Azure. Warning: If authentication fails, Git prints credentials in clear text. Correct credentials remain hidden.'
19
19
 
@@ -13,6 +13,8 @@ module Dpl
13
13
 
14
14
  gem 'json'
15
15
 
16
+ env :bintray
17
+
16
18
  opt '--user USER', 'Bintray user', required: true
17
19
  opt '--key KEY', 'Bintray API key', required: true, secret: true
18
20
  opt '--file FILE', 'Path to a descriptor file for the Bintray upload', required: true
@@ -9,14 +9,16 @@ module Dpl
9
9
  tbd
10
10
  str
11
11
 
12
+ env :cloudfoundry
13
+
12
14
  opt '--username USER', 'Bluemix username', required: true
13
15
  opt '--password PASS', 'Bluemix password', required: true, secret: true
14
- opt '--organization ORG', 'Bluemix target organization', required: true
15
- opt '--space SPACE', 'Bluemix target space', required: true
16
+ opt '--organization ORG', 'Bluemix organization', required: true
17
+ opt '--space SPACE', 'Bluemix space', required: true
16
18
  opt '--region REGION', 'Bluemix region', default: 'ng', enum: %w(ng eu-gb eu-de au-syd)
17
19
  opt '--api URL', 'Bluemix api URL'
18
20
  opt '--app_name APP', 'Application name'
19
- opt '--buildpack PACK', 'Custom buildpack name or Git URL'
21
+ opt '--buildpack PACK', 'Buildpack name or Git URL'
20
22
  opt '--manifest FILE', 'Path to the manifest'
21
23
  opt '--skip_ssl_validation', 'Skip SSL validation'
22
24
  opt '--logout', default: true, internal: true
@@ -11,11 +11,11 @@ module Dpl
11
11
 
12
12
  opt '--user USER', required: true
13
13
  opt '--secret SECRET', required: true, secret: true
14
- opt '--config_file FILE', alias: :configfile, deprecated: :configfile
15
14
  opt '--payload PAYLOAD'
16
15
  opt '--app APP'
17
16
  opt '--version VERSION'
18
17
  opt '--env ENV'
18
+ opt '--config_file FILE', alias: :configfile, deprecated: :configfile
19
19
  opt '--extra_args ARGS'
20
20
 
21
21
  URL = 'https://files.boxfuse.com/com/boxfuse/client/boxfuse-commandline/latest/boxfuse-commandline-latest-linux-x64.tar.gz'
@@ -7,13 +7,22 @@ module Dpl
7
7
  tbd
8
8
  str
9
9
 
10
+ env :cargo
11
+
10
12
  opt '--token TOKEN', 'Cargo registry API token', required: true, secret: true
13
+ opt '--allow_dirty', 'Allow publishing from a dirty git working directory'
11
14
 
12
- cmds publish: 'cargo publish --token %{token}'
15
+ cmds publish: 'cargo publish %{publish_opts}'
13
16
 
14
17
  def deploy
15
18
  shell :publish
16
19
  end
20
+
21
+ private
22
+
23
+ def publish_opts
24
+ opts_for(%i(token allow_dirty), dashed: true)
25
+ end
17
26
  end
18
27
  end
19
28
  end