dpl 2.0.0.alpha.12 → 2.0.2.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +30 -2
- data/CONTRIBUTING.md +3 -3
- data/Gemfile +1 -0
- data/Gemfile.lock +385 -0
- data/README.md +352 -141
- data/lib/dpl/assets/dpl/README.erb.md +1 -1
- data/lib/dpl/ctx/test.rb +4 -1
- data/lib/dpl/helper/interpolate.rb +24 -1
- data/lib/dpl/provider.rb +11 -3
- data/lib/dpl/provider/dsl.rb +25 -0
- data/lib/dpl/providers.rb +4 -0
- data/lib/dpl/providers/anynines.rb +2 -0
- data/lib/dpl/providers/azure_web_apps.rb +2 -0
- data/lib/dpl/providers/bintray.rb +2 -0
- data/lib/dpl/providers/bluemixcloudfoundry.rb +3 -1
- data/lib/dpl/providers/boxfuse.rb +2 -0
- data/lib/dpl/providers/cargo.rb +3 -1
- data/lib/dpl/providers/cloud66.rb +2 -0
- data/lib/dpl/providers/cloudfiles.rb +2 -0
- data/lib/dpl/providers/cloudformation.rb +1 -0
- data/lib/dpl/providers/cloudfoundry.rb +5 -1
- data/lib/dpl/providers/codedeploy.rb +13 -4
- data/lib/dpl/providers/convox.rb +2 -0
- data/lib/dpl/providers/datica.rb +2 -0
- data/lib/dpl/providers/ecr.rb +127 -0
- data/lib/dpl/providers/elasticbeanstalk.rb +14 -6
- data/lib/dpl/providers/engineyard.rb +2 -0
- data/lib/dpl/providers/firebase.rb +2 -0
- data/lib/dpl/providers/flynn.rb +33 -0
- data/lib/dpl/providers/gae.rb +2 -0
- data/lib/dpl/providers/gcs.rb +2 -0
- data/lib/dpl/providers/git_push.rb +269 -0
- data/lib/dpl/providers/gleis.rb +3 -1
- data/lib/dpl/providers/hackage.rb +2 -0
- data/lib/dpl/providers/hephy.rb +2 -0
- data/lib/dpl/providers/heroku.rb +2 -0
- data/lib/dpl/providers/heroku/api.rb +1 -1
- data/lib/dpl/providers/heroku/git.rb +1 -1
- data/lib/dpl/providers/lambda.rb +5 -3
- data/lib/dpl/providers/launchpad.rb +2 -0
- data/lib/dpl/providers/netlify.rb +2 -0
- data/lib/dpl/providers/npm.rb +2 -0
- data/lib/dpl/providers/nuget.rb +39 -0
- data/lib/dpl/providers/openshift.rb +2 -0
- data/lib/dpl/providers/opsworks.rb +2 -0
- data/lib/dpl/providers/packagecloud.rb +2 -0
- data/lib/dpl/providers/pages.rb +2 -0
- data/lib/dpl/providers/pages/api.rb +1 -1
- data/lib/dpl/providers/pages/git.rb +5 -5
- data/lib/dpl/providers/puppetforge.rb +2 -0
- data/lib/dpl/providers/pypi.rb +2 -0
- data/lib/dpl/providers/releases.rb +3 -1
- data/lib/dpl/providers/rubygems.rb +2 -0
- data/lib/dpl/providers/s3.rb +4 -2
- data/lib/dpl/providers/scalingo.rb +2 -0
- data/lib/dpl/providers/script.rb +2 -0
- data/lib/dpl/providers/snap.rb +8 -2
- data/lib/dpl/providers/surge.rb +3 -1
- data/lib/dpl/providers/testfairy.rb +2 -0
- data/lib/dpl/providers/transifex.rb +2 -0
- data/lib/dpl/version.rb +1 -1
- metadata +8 -3
@@ -1,7 +1,7 @@
|
|
1
1
|
# Dpl [![Build Status](https://travis-ci.com/travis-ci/dpl.svg?branch=master)](https://travis-ci.com/travis-ci/dpl) [![Code Climate](https://codeclimate.com/github/travis-ci/dpl.svg)](https://codeclimate.com/github/travis-ci/dpl) [![Coverage Status](https://coveralls.io/repos/travis-ci/dpl/badge.svg?branch=master&service=github&cache=2019-08-09_17:00)](https://coveralls.io/github/travis-ci/dpl?branch=master) [![Gem Version](https://img.shields.io/gem/v/dpl)](http://rubygems.org/gems/dpl) [![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://rubydoc.info/github/travis-ci/dpl)
|
2
2
|
|
3
3
|
This version of the README documents dpl v2, the next major version of dpl.
|
4
|
-
The
|
4
|
+
The README for dpl v1, the version that is currently used in production on
|
5
5
|
Travis CI can be found [here](https://github.com/travis-ci/dpl/blob/v1/README.md).
|
6
6
|
|
7
7
|
Dpl is command line tool for deploying code, html, packages, or build artifacts
|
data/lib/dpl/ctx/test.rb
CHANGED
@@ -36,10 +36,13 @@ module Dpl
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def gems_require(gems)
|
39
|
-
gems.each { |gem| gem_require(gem) }
|
39
|
+
gems.each { |gem| gem_require(*gem) }
|
40
40
|
end
|
41
41
|
|
42
42
|
def gem_require(name, version = nil, opts = {})
|
43
|
+
# not sure why this is needed. bundler should take care of this, but
|
44
|
+
# it does not for octokit for whatever reason
|
45
|
+
require opts[:require] || name rescue nil
|
43
46
|
cmds << "[gem:require] #{name} (#{version}, #{opts})"
|
44
47
|
end
|
45
48
|
|
@@ -52,6 +52,14 @@ module Dpl
|
|
52
52
|
Interpolator.new(str, self, args || {}, opts).apply
|
53
53
|
end
|
54
54
|
|
55
|
+
# Interpolation variables as declared by the provider.
|
56
|
+
#
|
57
|
+
# By default this contains string option names, but additional
|
58
|
+
# methods can be added using Provider::Dsl#vars.
|
59
|
+
def vars
|
60
|
+
self.class.vars
|
61
|
+
end
|
62
|
+
|
55
63
|
# Obfuscates the given string.
|
56
64
|
#
|
57
65
|
# Replaces all but the first N characters with asterisks, and paddes
|
@@ -71,6 +79,7 @@ module Dpl
|
|
71
79
|
PATTERN = /%\{(\$?[\w]+)\}/
|
72
80
|
ENV_VAR = /^\$[A-Z_]+$/
|
73
81
|
UPCASE = /^[A-Z_]+$/
|
82
|
+
UNKNOWN = '[unknown variable: %s]'
|
74
83
|
|
75
84
|
def apply
|
76
85
|
str = interpolate(self.str.to_s)
|
@@ -102,7 +111,9 @@ module Dpl
|
|
102
111
|
end
|
103
112
|
|
104
113
|
def lookup(key)
|
105
|
-
if
|
114
|
+
if vars? && !var?(key)
|
115
|
+
UNKNOWN % key
|
116
|
+
elsif mod = modifier(key)
|
106
117
|
key = key.to_s.sub("#{mod}d_", '')
|
107
118
|
obj.send(mod, lookup(key))
|
108
119
|
elsif key.to_s =~ ENV_VAR
|
@@ -121,6 +132,18 @@ module Dpl
|
|
121
132
|
def modifier(key)
|
122
133
|
MODIFIER.detect { |mod| key.to_s.start_with?("#{mod}d_") }
|
123
134
|
end
|
135
|
+
|
136
|
+
def var?(key)
|
137
|
+
vars.include?(key)
|
138
|
+
end
|
139
|
+
|
140
|
+
def vars
|
141
|
+
opts[:vars]
|
142
|
+
end
|
143
|
+
|
144
|
+
def vars?
|
145
|
+
!!vars
|
146
|
+
end
|
124
147
|
end
|
125
148
|
end
|
126
149
|
end
|
data/lib/dpl/provider.rb
CHANGED
@@ -145,8 +145,6 @@ module Dpl
|
|
145
145
|
|
146
146
|
abstract
|
147
147
|
|
148
|
-
arg :provider, 'The provider name', required: true
|
149
|
-
|
150
148
|
opt '--cleanup', 'Clean up build artifacts from the Git working directory before the deployment', negate: %w(skip)
|
151
149
|
opt '--run CMD', 'Commands to execute after the deployment finished successfully', type: :array
|
152
150
|
opt '--stage NAME', 'Execute the given stage(s) only', type: :array, internal: true, default: STAGES
|
@@ -154,6 +152,16 @@ module Dpl
|
|
154
152
|
opt '--fold', 'Wrap log output in folds', internal: true
|
155
153
|
opt '--edge', internal: true
|
156
154
|
|
155
|
+
vars *%i(
|
156
|
+
git_author_email
|
157
|
+
git_author_name
|
158
|
+
git_branch
|
159
|
+
git_commit_author
|
160
|
+
git_commit_msg
|
161
|
+
git_sha
|
162
|
+
git_tag
|
163
|
+
)
|
164
|
+
|
157
165
|
msgs before_install: 'Installing deployment dependencies',
|
158
166
|
before_setup: 'Setting the build environment up for the deployment',
|
159
167
|
setup_git_ssh: 'Setting up git-ssh',
|
@@ -545,7 +553,7 @@ module Dpl
|
|
545
553
|
|
546
554
|
# Double quotes the given string.
|
547
555
|
def quote(str)
|
548
|
-
%("#{str.gsub('"', '\"')}")
|
556
|
+
%("#{str.to_s.gsub('"', '\"')}")
|
549
557
|
end
|
550
558
|
|
551
559
|
# Outdents the given string.
|
data/lib/dpl/provider/dsl.rb
CHANGED
@@ -2,6 +2,15 @@ require 'dpl/helper/squiggle'
|
|
2
2
|
require 'dpl/helper/wrap'
|
3
3
|
require 'dpl/provider/status'
|
4
4
|
|
5
|
+
# TODO figure out how to allow adding domain specific behavior like this to Cl
|
6
|
+
class Cl::Opt
|
7
|
+
OPTS << :interpolate
|
8
|
+
|
9
|
+
def interpolate?
|
10
|
+
opts[:interpolate]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
5
14
|
module Dpl
|
6
15
|
class Provider < Cl::Cmd
|
7
16
|
# DSL available on the provider's class body.
|
@@ -36,6 +45,22 @@ module Dpl
|
|
36
45
|
status ? @status = Status.new(self, status, msg) : @status
|
37
46
|
end
|
38
47
|
|
48
|
+
# Declare additional variables available for interpolation.
|
49
|
+
#
|
50
|
+
# Interpolating strings, when these exposed to the user, should safelist
|
51
|
+
# which variables are available. Options declared on a provider are
|
52
|
+
# always available, except if they are flags, arrays, internal, or
|
53
|
+
# secrets. This method can be used to allow additional variables, e.g.
|
54
|
+
# from the git context.
|
55
|
+
def vars(*vars)
|
56
|
+
return self.vars.concat(vars) if vars.any?
|
57
|
+
return @vars if instance_variable_defined?(:@vars)
|
58
|
+
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}?") }
|
61
|
+
@vars = vars.dup.concat(opts.map(&:name)).uniq.sort - [:strategy]
|
62
|
+
end
|
63
|
+
|
39
64
|
# @!method env
|
40
65
|
# Declare an environment variable prefix to accept env vars as options
|
41
66
|
#
|
data/lib/dpl/providers.rb
CHANGED
@@ -11,12 +11,15 @@ require 'dpl/providers/cloudfiles'
|
|
11
11
|
require 'dpl/providers/cloudformation'
|
12
12
|
require 'dpl/providers/cloudfoundry'
|
13
13
|
require 'dpl/providers/codedeploy'
|
14
|
+
require 'dpl/providers/ecr'
|
14
15
|
require 'dpl/providers/convox'
|
15
16
|
require 'dpl/providers/elasticbeanstalk'
|
16
17
|
require 'dpl/providers/engineyard'
|
17
18
|
require 'dpl/providers/firebase'
|
19
|
+
require 'dpl/providers/flynn'
|
18
20
|
require 'dpl/providers/gae'
|
19
21
|
require 'dpl/providers/gcs'
|
22
|
+
require 'dpl/providers/git_push'
|
20
23
|
require 'dpl/providers/gleis'
|
21
24
|
require 'dpl/providers/hackage'
|
22
25
|
require 'dpl/providers/hephy'
|
@@ -25,6 +28,7 @@ require 'dpl/providers/lambda'
|
|
25
28
|
require 'dpl/providers/launchpad'
|
26
29
|
require 'dpl/providers/netlify'
|
27
30
|
require 'dpl/providers/npm'
|
31
|
+
require 'dpl/providers/nuget'
|
28
32
|
require 'dpl/providers/openshift'
|
29
33
|
require 'dpl/providers/opsworks'
|
30
34
|
require 'dpl/providers/packagecloud'
|
data/lib/dpl/providers/cargo.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
module Dpl
|
2
2
|
module Providers
|
3
3
|
class Cloudfoundry < Provider
|
4
|
+
register :cloudfoundry
|
5
|
+
|
4
6
|
status :stable
|
5
7
|
|
6
8
|
full_name 'Cloud Foundry'
|
@@ -20,10 +22,11 @@ module Dpl
|
|
20
22
|
opt '--buildpack PACK', 'Buildpack name or Git URL'
|
21
23
|
opt '--manifest FILE', 'Path to the manifest'
|
22
24
|
opt '--skip_ssl_validation', 'Skip SSL validation'
|
25
|
+
opt '--deployment_strategy STRATEGY', 'Deployment strategy, either rolling or null'
|
23
26
|
opt '--v3', 'Use the v3 API version to push the application'
|
24
27
|
opt '--logout', default: true, internal: true
|
25
28
|
|
26
|
-
cmds install: 'test $(uname) = "Linux" && rel="linux64-binary" || rel="macosx64"; wget "https://cli.run.pivotal.io/stable?release=${rel}&source=github" -qO cf.tgz && tar -zxvf cf.tgz && rm cf.tgz',
|
29
|
+
cmds install: 'test $(uname) = "Linux" && rel="linux64-binary" || rel="macosx64"; wget "https://cli.run.pivotal.io/stable?release=${rel}&version=v7&source=github" -qO cf.tgz && tar -zxvf cf.tgz && rm cf.tgz',
|
27
30
|
api: './cf api %{api} %{skip_ssl_validation_opt}',
|
28
31
|
login: './cf login -u %{username} -p %{password} -o %{organization} -s %{space}',
|
29
32
|
push: './cf %{push_cmd} %{push_args}',
|
@@ -68,6 +71,7 @@ module Dpl
|
|
68
71
|
args = []
|
69
72
|
args << quote(app_name) if app_name?
|
70
73
|
args << "-f #{manifest}" if manifest?
|
74
|
+
args << "--strategy #{deployment_strategy}" if deployment_strategy?
|
71
75
|
args.join(' ')
|
72
76
|
end
|
73
77
|
|
@@ -3,7 +3,9 @@ module Dpl
|
|
3
3
|
# split this up to CodeDeploy::Github and CodeDeploy::S3 using the
|
4
4
|
# revision_type, in order to make opts more strict
|
5
5
|
class Codedeploy < Provider
|
6
|
-
|
6
|
+
register :codedeploy
|
7
|
+
|
8
|
+
status :stable
|
7
9
|
|
8
10
|
full_name 'AWS Code Deploy'
|
9
11
|
|
@@ -30,7 +32,7 @@ module Dpl
|
|
30
32
|
opt '--wait_until_deployed', 'Wait until the deployment has finished'
|
31
33
|
opt '--bundle_type TYPE', 'Bundle type of the revision'
|
32
34
|
opt '--key KEY', 'S3 bucket key of the revision'
|
33
|
-
opt '--description DESCR', 'Description of the revision'
|
35
|
+
opt '--description DESCR', 'Description of the revision', interpolate: true
|
34
36
|
opt '--endpoint ENDPOINT', 'S3 endpoint url'
|
35
37
|
|
36
38
|
msgs login: 'Using Access Key: %{access_key_id}',
|
@@ -44,6 +46,8 @@ module Dpl
|
|
44
46
|
unknown_revision_type: 'Unknown revision type %p',
|
45
47
|
unknown_bundle_type: 'Unknown bundle type'
|
46
48
|
|
49
|
+
vars :build_number
|
50
|
+
|
47
51
|
def login
|
48
52
|
info :login
|
49
53
|
end
|
@@ -80,7 +84,12 @@ module Dpl
|
|
80
84
|
def wait_until_deployed(id)
|
81
85
|
print :waiting_for_deploy
|
82
86
|
status = poll(id) until %w(Succeeded Failed Stopped).include?(status)
|
83
|
-
|
87
|
+
case status
|
88
|
+
when 'Succeeded'
|
89
|
+
info :finished_deploy, status
|
90
|
+
else
|
91
|
+
error :finished_deploy, status
|
92
|
+
end
|
84
93
|
end
|
85
94
|
|
86
95
|
def poll(id)
|
@@ -152,7 +161,7 @@ module Dpl
|
|
152
161
|
end
|
153
162
|
|
154
163
|
def description
|
155
|
-
super ||
|
164
|
+
interpolate(super || msg(:description), vars: vars)
|
156
165
|
end
|
157
166
|
|
158
167
|
def build_number
|
data/lib/dpl/providers/convox.rb
CHANGED
data/lib/dpl/providers/datica.rb
CHANGED
@@ -0,0 +1,127 @@
|
|
1
|
+
module Dpl
|
2
|
+
module Providers
|
3
|
+
class Ecr < Provider
|
4
|
+
status :alpha
|
5
|
+
|
6
|
+
full_name 'AWS ECR'
|
7
|
+
|
8
|
+
description sq(<<-str)
|
9
|
+
tbd
|
10
|
+
str
|
11
|
+
|
12
|
+
gem 'aws-sdk-ecr', '~> 1.0'
|
13
|
+
# gem 'docker-api', '~> 1.34'
|
14
|
+
gem 'json'
|
15
|
+
|
16
|
+
env :aws
|
17
|
+
|
18
|
+
opt '--access_key_id ID', 'AWS access key', required: true, secret: true
|
19
|
+
opt '--secret_access_key KEY', 'AWS secret access key', required: true, secret: true
|
20
|
+
opt '--account_id ID', 'AWS Account ID', note: 'Required if the repository is owned by a different account than the IAM user'
|
21
|
+
opt '--source SOURCE', 'Image to push', note: 'can be the id or the name and optional tag (e.g. mysql:5.6)', required: true
|
22
|
+
opt '--target TARGET', 'Comma separated list of partial repository names to push to', eg: 'image-one:tag,image-two', required: true
|
23
|
+
opt '--region REGION', 'Comma separated list of regions to push to', default: 'us-east-1'
|
24
|
+
|
25
|
+
msgs login: 'Using Access Key: %{access_key_id}',
|
26
|
+
auth_region: 'Authenticated with %{url}',
|
27
|
+
deploy: 'Pushing image %{source} to regions %{regions} as %{targets}',
|
28
|
+
image_pushed: 'Pushed image %{source} to region %{region} as %{target}'
|
29
|
+
|
30
|
+
cmds login: 'docker login -u %{user} -p %{pass} %{url}',
|
31
|
+
tag: 'docker tag %{source} %{url}/%{repo}:%{tag}',
|
32
|
+
push: 'docker push %{url}/%{repo}'
|
33
|
+
|
34
|
+
errs unknown_image: 'Image %{source} not found in the local Docker repository'
|
35
|
+
|
36
|
+
attr_reader :endpoints
|
37
|
+
|
38
|
+
def login
|
39
|
+
info :login
|
40
|
+
auth_regions
|
41
|
+
end
|
42
|
+
|
43
|
+
def validate
|
44
|
+
# TODO validate the image exists locally
|
45
|
+
end
|
46
|
+
|
47
|
+
def deploy
|
48
|
+
info :deploy, regions: regions.join(', '), targets: targets.join(', ')
|
49
|
+
regions.product(targets).each do |region, target|
|
50
|
+
push(region, target)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def push(region, target)
|
57
|
+
url, repo, tag = endpoints[region], *target.split(':')
|
58
|
+
shell :tag, url: url, repo: repo, tag: tag || 'latest'
|
59
|
+
shell :push, url: url, repo: repo
|
60
|
+
info :image_pushed, region: region, target: target
|
61
|
+
end
|
62
|
+
|
63
|
+
def auth_regions
|
64
|
+
@endpoints = regions.map { |region| [region, auth_region(region)] }.to_h
|
65
|
+
end
|
66
|
+
|
67
|
+
def auth_region(region)
|
68
|
+
token = auth_token(region)
|
69
|
+
user, pass = parse_auth(token.authorization_token)
|
70
|
+
url = token.proxy_endpoint
|
71
|
+
shell :login, user: user, pass: pass, url: url, echo: false, silent: true
|
72
|
+
info :auth_region, url: url
|
73
|
+
strip_protocol(url)
|
74
|
+
end
|
75
|
+
|
76
|
+
def auth_token(region)
|
77
|
+
ecr(region).get_authorization_token(registry_ids).authorization_data[0]
|
78
|
+
end
|
79
|
+
|
80
|
+
def registry_ids
|
81
|
+
account_id? ? { registry_ids: [account_id] } : {}
|
82
|
+
end
|
83
|
+
|
84
|
+
def regions
|
85
|
+
# not sure how this was meant to be normalized when being a YAML list
|
86
|
+
region.split(',')
|
87
|
+
end
|
88
|
+
|
89
|
+
def targets
|
90
|
+
# not sure how this was meant to be normalized when being a YAML list
|
91
|
+
target.split(',')
|
92
|
+
end
|
93
|
+
|
94
|
+
def creds
|
95
|
+
@creds ||= only(opts, :access_key_id, :secret_access_key)
|
96
|
+
end
|
97
|
+
|
98
|
+
def ecr(region)
|
99
|
+
Aws::ECR::Client.new(region: region, **creds)
|
100
|
+
end
|
101
|
+
|
102
|
+
def parse_auth(str)
|
103
|
+
user, pass = Base64.decode64(str).split(':')
|
104
|
+
[user, pass.chomp]
|
105
|
+
end
|
106
|
+
|
107
|
+
def strip_protocol(url)
|
108
|
+
url.sub(/^https?:\/\//, '')
|
109
|
+
end
|
110
|
+
|
111
|
+
def progress(events)
|
112
|
+
events.split("\r\n").each do |event|
|
113
|
+
event = JSON.parse(event)
|
114
|
+
if e = event['error']
|
115
|
+
error e
|
116
|
+
elsif %w(Preparing Pushing).include?(event['status'])
|
117
|
+
nil
|
118
|
+
elsif event['id']
|
119
|
+
info "#{event['status']} [#{event['id']}]"
|
120
|
+
elsif event['status']
|
121
|
+
info event['status']
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|