dpl 1.10.17.travis.6637.6 → 2.0.0.alpha.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +74 -0
- data/CONTRIBUTING.md +392 -0
- data/Gemfile +17 -3
- data/Gemfile.lock +373 -0
- data/LICENSE +16 -19
- data/NOTES.md +275 -0
- data/README.md +1977 -707
- data/Rakefile +2 -2
- data/bin/dpl +7 -3
- data/lib/dpl.rb +20 -0
- data/lib/dpl/assets/atlas/install +19 -0
- data/lib/dpl/assets/dpl/README.erb.md +133 -0
- data/lib/dpl/assets/dpl/git_ssh +2 -0
- data/lib/dpl/assets/git/detect_private_key +8 -0
- data/lib/dpl/assets/hephy/filter_log +3 -0
- data/lib/dpl/assets/pypi/install +4 -0
- data/lib/dpl/assets/scalingo/install +6 -0
- data/lib/dpl/cli.rb +36 -48
- data/lib/dpl/ctx.rb +2 -0
- data/lib/dpl/ctx/bash.rb +543 -0
- data/lib/dpl/ctx/test.rb +242 -0
- data/lib/dpl/helper/assets.rb +36 -0
- data/lib/dpl/helper/cmd.rb +167 -0
- data/lib/dpl/helper/config_file.rb +47 -0
- data/lib/dpl/helper/env.rb +39 -0
- data/lib/dpl/helper/interpolate.rb +126 -0
- data/lib/dpl/helper/memoize.rb +20 -0
- data/lib/dpl/helper/squiggle.rb +22 -0
- data/lib/dpl/helper/zip.rb +69 -0
- data/lib/dpl/provider.rb +562 -234
- data/lib/dpl/provider/dsl.rb +369 -0
- data/lib/dpl/provider/examples.rb +128 -0
- data/lib/dpl/provider/status.rb +59 -0
- data/lib/dpl/providers.rb +40 -0
- data/lib/dpl/providers/anynines.rb +65 -0
- data/lib/dpl/providers/atlas.rb +49 -0
- data/lib/dpl/providers/azure_web_apps.rb +59 -0
- data/lib/dpl/providers/bintray.rb +313 -0
- data/lib/dpl/providers/bluemixcloudfoundry.rb +92 -0
- data/lib/dpl/providers/boxfuse.rb +48 -0
- data/lib/dpl/providers/cargo.rb +19 -0
- data/lib/dpl/providers/chef_supermarket.rb +128 -0
- data/lib/dpl/providers/cloud66.rb +40 -0
- data/lib/dpl/providers/cloudfiles.rb +56 -0
- data/lib/dpl/providers/cloudfoundry.rb +81 -0
- data/lib/dpl/providers/codedeploy.rb +179 -0
- data/lib/dpl/providers/datica.rb +60 -0
- data/lib/dpl/providers/elasticbeanstalk.rb +195 -0
- data/lib/dpl/providers/engineyard.rb +107 -0
- data/lib/dpl/providers/firebase.rb +41 -0
- data/lib/dpl/providers/gae.rb +74 -0
- data/lib/dpl/providers/gcs.rb +105 -0
- data/lib/dpl/providers/hackage.rb +47 -0
- data/lib/dpl/providers/hephy.rb +101 -0
- data/lib/dpl/providers/heroku.rb +111 -0
- data/lib/dpl/providers/heroku/api.rb +119 -0
- data/lib/dpl/providers/heroku/git.rb +50 -0
- data/lib/dpl/providers/lambda.rb +202 -0
- data/lib/dpl/providers/launchpad.rb +74 -0
- data/lib/dpl/providers/netlify.rb +30 -0
- data/lib/dpl/providers/npm.rb +88 -0
- data/lib/dpl/providers/openshift.rb +46 -0
- data/lib/dpl/providers/opsworks.rb +142 -0
- data/lib/dpl/providers/packagecloud.rb +190 -0
- data/lib/dpl/providers/pages.rb +17 -0
- data/lib/dpl/providers/pages/api.rb +102 -0
- data/lib/dpl/providers/pages/git.rb +251 -0
- data/lib/dpl/providers/puppetforge.rb +44 -0
- data/lib/dpl/providers/pypi.rb +120 -0
- data/lib/dpl/providers/releases.rb +214 -0
- data/lib/dpl/providers/rubygems.rb +89 -0
- data/lib/dpl/providers/s3.rb +243 -0
- data/lib/dpl/providers/scalingo.rb +63 -0
- data/lib/dpl/providers/script.rb +28 -0
- data/lib/dpl/providers/snap.rb +59 -0
- data/lib/dpl/providers/surge.rb +55 -0
- data/lib/dpl/providers/testfairy.rb +93 -0
- data/lib/dpl/providers/transifex.rb +66 -0
- data/lib/dpl/support/aws_sdk_patch.rb +23 -0
- data/lib/dpl/support/gems.rb +69 -0
- data/lib/dpl/support/gstore_patch.rb +6 -0
- data/lib/dpl/support/version.rb +83 -0
- data/lib/dpl/version.rb +2 -2
- metadata +98 -169
- data/.coveralls.yml +0 -1
- data/.github/CONTRIBUTING.md +0 -173
- data/.github/stale.yml +0 -53
- data/.gitignore +0 -13
- data/.rspec +0 -2
- data/.travis.yml +0 -56
- data/dpl-anynines.gemspec +0 -3
- data/dpl-atlas.gemspec +0 -3
- data/dpl-azure_webapps.gemspec +0 -3
- data/dpl-bintray.gemspec +0 -3
- data/dpl-bitballoon.gemspec +0 -3
- data/dpl-bluemix_cloud_foundry.gemspec +0 -3
- data/dpl-boxfuse.gemspec +0 -3
- data/dpl-cargo.gemspec +0 -3
- data/dpl-catalyze.gemspec +0 -3
- data/dpl-chef_supermarket.gemspec +0 -20
- data/dpl-cloud66.gemspec +0 -3
- data/dpl-cloud_files.gemspec +0 -3
- data/dpl-cloud_foundry.gemspec +0 -3
- data/dpl-code_deploy.gemspec +0 -3
- data/dpl-deis.gemspec +0 -3
- data/dpl-elastic_beanstalk.gemspec +0 -3
- data/dpl-engine_yard.gemspec +0 -3
- data/dpl-firebase.gemspec +0 -3
- data/dpl-gae.gemspec +0 -3
- data/dpl-gcs.gemspec +0 -3
- data/dpl-hackage.gemspec +0 -3
- data/dpl-hephy.gemspec +0 -3
- data/dpl-heroku.gemspec +0 -3
- data/dpl-lambda.gemspec +0 -3
- data/dpl-launchpad.gemspec +0 -3
- data/dpl-npm.gemspec +0 -3
- data/dpl-openshift.gemspec +0 -3
- data/dpl-ops_works.gemspec +0 -3
- data/dpl-packagecloud.gemspec +0 -3
- data/dpl-pages.gemspec +0 -3
- data/dpl-puppet_forge.gemspec +0 -3
- data/dpl-pypi.gemspec +0 -3
- data/dpl-releases.gemspec +0 -8
- data/dpl-rubygems.gemspec +0 -3
- data/dpl-s3.gemspec +0 -3
- data/dpl-scalingo.gemspec +0 -3
- data/dpl-script.gemspec +0 -3
- data/dpl-snap.gemspec +0 -3
- data/dpl-surge.gemspec +0 -3
- data/dpl-testfairy.gemspec +0 -3
- data/dpl-transifex.gemspec +0 -3
- data/dpl.gemspec +0 -3
- data/gemspec_helper.rb +0 -51
- data/lib/dpl/error.rb +0 -3
- data/notes/engine_yard.md +0 -1
- data/notes/heroku.md +0 -3
- data/spec/cli_spec.rb +0 -36
- data/spec/provider_spec.rb +0 -191
- data/spec/spec_helper.rb +0 -20
@@ -0,0 +1,179 @@
|
|
1
|
+
module Dpl
|
2
|
+
module Providers
|
3
|
+
# split this up to CodeDeploy::Github and CodeDeploy::S3 using the
|
4
|
+
# revision_type, in order to make opts more strict
|
5
|
+
class Codedeploy < Provider
|
6
|
+
status :alpha
|
7
|
+
|
8
|
+
full_name 'AWS Code Deploy'
|
9
|
+
|
10
|
+
description sq(<<-str)
|
11
|
+
tbd
|
12
|
+
str
|
13
|
+
|
14
|
+
gem 'aws-sdk-codedeploy', '~> 1.0'
|
15
|
+
gem 'aws-sdk-s3', '~> 1.0'
|
16
|
+
|
17
|
+
env :aws
|
18
|
+
config '~/.aws/credentials', '~/.aws/config', prefix: 'aws'
|
19
|
+
|
20
|
+
opt '--access_key_id ID', 'AWS access key', required: true, secret: true
|
21
|
+
opt '--secret_access_key KEY', 'AWS secret access key', required: true, secret: true
|
22
|
+
opt '--application NAME', 'CodeDeploy application name', required: true
|
23
|
+
opt '--deployment_group GROUP', 'CodeDeploy deployment group name'
|
24
|
+
opt '--revision_type TYPE', 'CodeDeploy revision type', enum: %w(s3 github), downcase: true
|
25
|
+
opt '--commit_id SHA', 'Commit ID in case of GitHub'
|
26
|
+
opt '--repository NAME', 'Repository name in case of GitHub'
|
27
|
+
opt '--bucket NAME', 'S3 bucket in case of S3'
|
28
|
+
opt '--region REGION', 'AWS availability zone', default: 'us-east-1'
|
29
|
+
opt '--file_exists_behavior STR', 'How to handle files that already exist in a deployment target location', enum: %w(disallow overwrite retain), default: 'disallow'
|
30
|
+
opt '--wait_until_deployed', 'Wait until the deployment has finished'
|
31
|
+
opt '--bundle_type TYPE'
|
32
|
+
opt '--endpoint ENDPOINT'
|
33
|
+
opt '--key KEY'
|
34
|
+
opt '--description DESCR'
|
35
|
+
|
36
|
+
msgs login: 'Using Access Key: %{access_key_id}',
|
37
|
+
deploy_triggered: 'Deployment triggered: %s',
|
38
|
+
register_revision: 'Registering app revision with version=%s, etag=%s',
|
39
|
+
waiting_for_deploy: 'Waiting for the deployment to finish ',
|
40
|
+
finished_deploy: 'done: %s.',
|
41
|
+
description: 'Deploy build %{build_number} via Travis CI',
|
42
|
+
missing_bucket: 'Missing required bucket for S3 deployment',
|
43
|
+
missing_key: 'Missing required key for S3 deployment',
|
44
|
+
unknown_revision_type: 'Unknown revision type %p',
|
45
|
+
unknown_bundle_type: 'Unknown bundle type'
|
46
|
+
|
47
|
+
def login
|
48
|
+
info :login
|
49
|
+
end
|
50
|
+
|
51
|
+
def deploy
|
52
|
+
register_revision if revision_info[:version]
|
53
|
+
id = create_deployment
|
54
|
+
info :deploy_triggered, id
|
55
|
+
wait_until_deployed(id) if wait_until_deployed?
|
56
|
+
rescue Aws::CodeDeploy::Errors::DeploymentLimitExceededException => e
|
57
|
+
error e.message
|
58
|
+
end
|
59
|
+
|
60
|
+
def register_revision
|
61
|
+
info :register_revision, revision_info[:version], revision_info[:e_tag]
|
62
|
+
code_deploy.register_application_revision(
|
63
|
+
revision: revision,
|
64
|
+
application_name: application,
|
65
|
+
description: description
|
66
|
+
)
|
67
|
+
end
|
68
|
+
|
69
|
+
def create_deployment
|
70
|
+
deployment = code_deploy.create_deployment(
|
71
|
+
revision: revision,
|
72
|
+
application_name: application,
|
73
|
+
deployment_group_name: deployment_group,
|
74
|
+
description: description,
|
75
|
+
file_exists_behavior: file_exists_behavior.upcase
|
76
|
+
)
|
77
|
+
deployment.deployment_id
|
78
|
+
end
|
79
|
+
|
80
|
+
def wait_until_deployed(id)
|
81
|
+
print :waiting_for_deploy
|
82
|
+
status = poll(id) until %w(Succeeded Failed Stopped).include?(status)
|
83
|
+
info :finished_deploy, status
|
84
|
+
end
|
85
|
+
|
86
|
+
def poll(id)
|
87
|
+
sleep 5
|
88
|
+
print '.'
|
89
|
+
code_deploy.get_deployment(deployment_id: id)[:deployment_info][:status]
|
90
|
+
end
|
91
|
+
|
92
|
+
def revision_info
|
93
|
+
revision[:s3_location] || {}
|
94
|
+
end
|
95
|
+
|
96
|
+
def revision
|
97
|
+
@revision ||= case revision_type
|
98
|
+
when 's3' then s3_revision
|
99
|
+
when 'github' then github_revision
|
100
|
+
when nil then bucket? ? s3_revision : github_revision
|
101
|
+
else error :unknown_revision_type, revision_type
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def s3_revision
|
106
|
+
{
|
107
|
+
revision_type: 'S3',
|
108
|
+
s3_location: compact(
|
109
|
+
bucket: bucket,
|
110
|
+
bundle_type: bundle_type,
|
111
|
+
version: revision_version_info[:version_id],
|
112
|
+
e_tag: revision_version_info[:etag],
|
113
|
+
key: key,
|
114
|
+
)
|
115
|
+
}
|
116
|
+
end
|
117
|
+
|
118
|
+
def revision_version_info
|
119
|
+
s3.head_object(bucket: bucket, key: key)
|
120
|
+
rescue Aws::Errors::ServiceError => e
|
121
|
+
error e.message
|
122
|
+
end
|
123
|
+
|
124
|
+
def github_revision
|
125
|
+
{
|
126
|
+
revision_type: 'GitHub',
|
127
|
+
git_hub_location: {
|
128
|
+
commit_id: commit_id,
|
129
|
+
repository: repository
|
130
|
+
}
|
131
|
+
}
|
132
|
+
end
|
133
|
+
|
134
|
+
def commit_id
|
135
|
+
super || git_sha
|
136
|
+
end
|
137
|
+
|
138
|
+
def repository
|
139
|
+
super || ENV['TRAVIS_REPO_SLUG'] || File.basename(Dir.pwd)
|
140
|
+
end
|
141
|
+
|
142
|
+
def bucket
|
143
|
+
super || error(:missing_bucket)
|
144
|
+
end
|
145
|
+
|
146
|
+
def key
|
147
|
+
super || error(:missing_key)
|
148
|
+
end
|
149
|
+
|
150
|
+
def bundle_type
|
151
|
+
super || key =~ /\.(tar|tgz|zip)$/ && $1 || error(:unknown_bundle_type)
|
152
|
+
end
|
153
|
+
|
154
|
+
def description
|
155
|
+
super || interpolate(msg(:description))
|
156
|
+
end
|
157
|
+
|
158
|
+
def build_number
|
159
|
+
ENV['TRAVIS_BUILD_NUMBER']
|
160
|
+
end
|
161
|
+
|
162
|
+
def code_deploy
|
163
|
+
@code_deploy ||= Aws::CodeDeploy::Client.new(client_options)
|
164
|
+
end
|
165
|
+
|
166
|
+
def s3
|
167
|
+
@s3 ||= Aws::S3::Client.new(client_options)
|
168
|
+
end
|
169
|
+
|
170
|
+
def client_options
|
171
|
+
compact(region: region, credentials: credentials, endpoint: endpoint)
|
172
|
+
end
|
173
|
+
|
174
|
+
def credentials
|
175
|
+
Aws::Credentials.new(access_key_id, secret_access_key)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Dpl
|
2
|
+
module Providers
|
3
|
+
class Datica < Provider
|
4
|
+
status :dev
|
5
|
+
|
6
|
+
register :datica, :catalyze
|
7
|
+
|
8
|
+
description sq(<<-str)
|
9
|
+
tbd
|
10
|
+
str
|
11
|
+
|
12
|
+
env :datica, :catalyze
|
13
|
+
|
14
|
+
opt '--target TARGET', 'The git remote repository to deploy to', required: true
|
15
|
+
opt '--path PATH', 'Path to files to deploy', default: '.'
|
16
|
+
|
17
|
+
needs :git
|
18
|
+
|
19
|
+
cmds checkout: 'git checkout HEAD',
|
20
|
+
add: 'git add %{path} --all --force',
|
21
|
+
commit: 'git commit -m "%{message}" --quiet',
|
22
|
+
push: 'git push --force %{target} HEAD:master'
|
23
|
+
|
24
|
+
msgs commit: 'Committing build files for deployment',
|
25
|
+
push: 'Deploying to Datica: %{target}'
|
26
|
+
|
27
|
+
def setup
|
28
|
+
commit unless cleanup?
|
29
|
+
end
|
30
|
+
|
31
|
+
def deploy
|
32
|
+
shell :push
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def commit
|
38
|
+
info :commit
|
39
|
+
shell :checkout
|
40
|
+
shell :add
|
41
|
+
shell :commit
|
42
|
+
end
|
43
|
+
|
44
|
+
def message
|
45
|
+
vars.empty? ? 'Local build' : 'Build #%s (%s) of %s@%s' % vars
|
46
|
+
end
|
47
|
+
|
48
|
+
VARS = %w(
|
49
|
+
TRAVIS_BUILD_NUMBER
|
50
|
+
TRAVIS_COMMIT
|
51
|
+
TRAVIS_REPO_SLUG
|
52
|
+
TRAVIS_BRANCH
|
53
|
+
)
|
54
|
+
|
55
|
+
def vars
|
56
|
+
@vars ||= ENV.values_at(*VARS).compact
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,195 @@
|
|
1
|
+
module Dpl
|
2
|
+
module Providers
|
3
|
+
class Elasticbeanstalk < Provider
|
4
|
+
status :alpha
|
5
|
+
|
6
|
+
full_name 'AWS Elastic Beanstalk'
|
7
|
+
|
8
|
+
description sq(<<-str)
|
9
|
+
tbd
|
10
|
+
str
|
11
|
+
|
12
|
+
gem 'aws-sdk-elasticbeanstalk', '~> 1.0'
|
13
|
+
gem 'aws-sdk-s3', '~> 1.0'
|
14
|
+
gem 'rubyzip', '~> 1.2.2', require: 'zip'
|
15
|
+
gem 'pathspec', '~> 0.2.1', require: 'pathspec'
|
16
|
+
|
17
|
+
env :aws, :elastic_beanstalk
|
18
|
+
config '~/.aws/credentials', '~/.aws/config', prefix: 'aws'
|
19
|
+
|
20
|
+
opt '--access_key_id ID', 'AWS Access Key ID', required: true, secret: true
|
21
|
+
opt '--secret_access_key KEY', 'AWS Secret Key', required: true, secret: true
|
22
|
+
opt '--region REGION', 'AWS Region the Elastic Beanstalk app is running in', default: 'us-east-1'
|
23
|
+
opt '--app NAME', 'Elastic Beanstalk application name', default: :repo_name
|
24
|
+
opt '--env NAME', 'Elastic Beanstalk environment name which will be updated', required: true
|
25
|
+
opt '--bucket NAME', 'Bucket name to upload app to', required: true, alias: :bucket_name
|
26
|
+
opt '--bucket_path PATH', 'Location within Bucket to upload app to'
|
27
|
+
opt '--description DESC', 'Description for the application version'
|
28
|
+
opt '--label LABEL', 'Label for the application version'
|
29
|
+
opt '--zip_file PATH', 'The zip file that you want to deploy'
|
30
|
+
opt '--only_create_app_version', 'Only create the app version, do not actually deploy it'
|
31
|
+
opt '--wait_until_deployed', 'Wait until the deployment has finished'
|
32
|
+
opt '--debug', internal: true
|
33
|
+
|
34
|
+
msgs login: 'Using Access Key: %{access_key_id}',
|
35
|
+
zip_add: 'Adding %s'
|
36
|
+
|
37
|
+
msgs clean_description: 'Removed non-printable characters from the version description'
|
38
|
+
|
39
|
+
attr_reader :started, :object, :version
|
40
|
+
|
41
|
+
def login
|
42
|
+
info :login
|
43
|
+
end
|
44
|
+
|
45
|
+
def setup
|
46
|
+
info :login
|
47
|
+
Aws.config.update(credentials: credentials, region: region)
|
48
|
+
end
|
49
|
+
|
50
|
+
def deploy
|
51
|
+
@started = Time.now
|
52
|
+
bucket.create unless bucket.exists?
|
53
|
+
create_zip unless zip_exists?
|
54
|
+
upload
|
55
|
+
create_version
|
56
|
+
update_app unless only_create_app_version?
|
57
|
+
end
|
58
|
+
|
59
|
+
def zip_file
|
60
|
+
zip_file? ? expand(super) : archive_name
|
61
|
+
end
|
62
|
+
|
63
|
+
def archive_name
|
64
|
+
"#{label}.zip"
|
65
|
+
end
|
66
|
+
|
67
|
+
def label
|
68
|
+
@label ||= super || "travis-#{git_sha}-#{Time.now.to_i}"
|
69
|
+
end
|
70
|
+
|
71
|
+
def description
|
72
|
+
super || git_commit_msg
|
73
|
+
end
|
74
|
+
|
75
|
+
def bucket_path
|
76
|
+
bucket_path? ? "#{super.gsub(/\/*$/, '')}/#{archive_name}" : archive_name
|
77
|
+
end
|
78
|
+
|
79
|
+
def cwd
|
80
|
+
@cwd ||= "#{Dir.pwd}/"
|
81
|
+
end
|
82
|
+
|
83
|
+
def zip_exists?
|
84
|
+
File.exists?(zip_file)
|
85
|
+
end
|
86
|
+
|
87
|
+
def create_zip
|
88
|
+
::Zip::File.open(zip_file, ::Zip::File::CREATE) do |zip|
|
89
|
+
files.each do |path|
|
90
|
+
debug :zip_add, path
|
91
|
+
zip.add(path.sub(cwd, ''), path)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def upload
|
97
|
+
@object = bucket.object(bucket_path)
|
98
|
+
object.put(body: File.open(zip_file))
|
99
|
+
sleep 5 # s3 eventual consistency
|
100
|
+
end
|
101
|
+
|
102
|
+
def create_version
|
103
|
+
@version = eb.create_application_version(
|
104
|
+
application_name: app,
|
105
|
+
version_label: label,
|
106
|
+
description: clean(description[0, 200]),
|
107
|
+
source_bundle: {
|
108
|
+
s3_bucket: bucket.name,
|
109
|
+
s3_key: object.key
|
110
|
+
},
|
111
|
+
auto_create_application: false
|
112
|
+
)
|
113
|
+
end
|
114
|
+
|
115
|
+
def update_app
|
116
|
+
eb.update_environment(
|
117
|
+
environment_name: env,
|
118
|
+
version_label: version[:application_version][:version_label]
|
119
|
+
)
|
120
|
+
wait_until_deployed if wait_until_deployed?
|
121
|
+
end
|
122
|
+
|
123
|
+
def wait_until_deployed
|
124
|
+
msgs = []
|
125
|
+
1.upto(20) { return if check_deployment(msgs) }
|
126
|
+
error 'Too many failures'
|
127
|
+
end
|
128
|
+
|
129
|
+
def check_deployment(msgs)
|
130
|
+
sleep 5
|
131
|
+
events.each do |event|
|
132
|
+
msg = "#{event.event_date} [#{event.severity}] #{event.message}"
|
133
|
+
error "Deployment failed: #{msg}" if event.severity == 'ERROR'
|
134
|
+
info msg unless msgs.include?(msg)
|
135
|
+
msgs << msg
|
136
|
+
end
|
137
|
+
environment[:status] == 'Ready'
|
138
|
+
rescue Aws::Errors::ServiceError => e
|
139
|
+
info "Caught #{e}: #{e.message}. Retrying ..."
|
140
|
+
end
|
141
|
+
|
142
|
+
def files
|
143
|
+
files = Dir.glob('**/*', File::FNM_DOTMATCH)
|
144
|
+
files = filter(files, '.ebignore') if file?('.ebignore')
|
145
|
+
files
|
146
|
+
end
|
147
|
+
|
148
|
+
def filter(files, spec)
|
149
|
+
spec = PathSpec.from_filename(spec)
|
150
|
+
files.reject { |file| spec.match(file) }
|
151
|
+
end
|
152
|
+
|
153
|
+
def events
|
154
|
+
args = { environment_name: env, start_time: started.utc.iso8601 }
|
155
|
+
eb.describe_events(args)[:events].reverse
|
156
|
+
end
|
157
|
+
|
158
|
+
def environment
|
159
|
+
args = { application_name: app, environment_names: [env] }
|
160
|
+
eb.describe_environments(args)[:environments].first
|
161
|
+
end
|
162
|
+
|
163
|
+
def credentials
|
164
|
+
Aws::Credentials.new(access_key_id, secret_access_key)
|
165
|
+
end
|
166
|
+
|
167
|
+
def s3
|
168
|
+
@s3 ||= Aws::S3::Resource.new
|
169
|
+
end
|
170
|
+
|
171
|
+
def bucket
|
172
|
+
@bucket ||= s3.bucket(super)
|
173
|
+
end
|
174
|
+
|
175
|
+
def eb
|
176
|
+
@eb ||= Aws::ElasticBeanstalk::Client.new(retry_limit: 10)
|
177
|
+
end
|
178
|
+
|
179
|
+
# We do not actually know what characters are valid on AWS EB's side,
|
180
|
+
# see: https://github.com/aws/aws-sdk-ruby/issues/1502
|
181
|
+
#
|
182
|
+
# Reference: https://www.w3.org/TR/xml/#charsets
|
183
|
+
NON_PRINTABLE_CHARS = "\u0009\u000A\u000D\u0020-\uD7FF\uE000-\uFFFD\u10000-\u10FFFF"
|
184
|
+
|
185
|
+
def clean(str)
|
186
|
+
str.gsub!(/[^#{NON_PRINTABLE_CHARS}]/, '') && info(:clean_description)
|
187
|
+
str
|
188
|
+
end
|
189
|
+
|
190
|
+
def debug(*args)
|
191
|
+
info *args if debug?
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module Dpl
|
2
|
+
module Providers
|
3
|
+
class Engineyard < Provider
|
4
|
+
status :alpha
|
5
|
+
|
6
|
+
description sq(<<-str)
|
7
|
+
tbd
|
8
|
+
str
|
9
|
+
|
10
|
+
gem 'ey-core', '~> 3.5'
|
11
|
+
|
12
|
+
required :api_key, [:email, :password]
|
13
|
+
|
14
|
+
opt '--api_key KEY', 'Engine Yard API key', secret: true
|
15
|
+
opt '--email EMAIL', 'Engine Yard account email'
|
16
|
+
opt '--password PASS', 'Engine Yard password', secret: true
|
17
|
+
opt '--app APP', 'Engine Yard application name', default: :repo_name
|
18
|
+
opt '--env ENV', 'Engine Yard application environment', alias: :environment
|
19
|
+
opt '--migrate CMD', 'Engine Yard migration commands'
|
20
|
+
opt '--account NAME', 'Engine Yard account name'
|
21
|
+
|
22
|
+
msgs deploy: 'Deploying ...',
|
23
|
+
login: 'Authenticating via email and password ...',
|
24
|
+
write_rc: 'Authenticating via api token ...',
|
25
|
+
authenticated: 'Authenticated as %{name}',
|
26
|
+
invalid_migrate: 'Invalid migration command, try --migrate="rake db:migrate"',
|
27
|
+
envs: 'Checking environment ...',
|
28
|
+
no_env: 'No matching environment found',
|
29
|
+
too_many_envs: 'Multiple environments match, please be more specific: %s',
|
30
|
+
env_entry: 'environment=%s account=%s'
|
31
|
+
|
32
|
+
cmds login: "ey-core login << str\n%{email}\n%{password}\nstr",
|
33
|
+
whoami: 'ey-core whoami',
|
34
|
+
envs: 'ey-core environments',
|
35
|
+
deploy: 'ey-core deploy %{deploy_opts}'
|
36
|
+
|
37
|
+
def login
|
38
|
+
api_key? ? write_rc : authenticate
|
39
|
+
info :authenticated, name: whoami
|
40
|
+
end
|
41
|
+
|
42
|
+
def validate
|
43
|
+
error :invalid_migrate if invalid_migrate?
|
44
|
+
env
|
45
|
+
end
|
46
|
+
|
47
|
+
def deploy
|
48
|
+
shell :deploy
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def authenticate
|
54
|
+
shell :login, echo: false, capture: true
|
55
|
+
end
|
56
|
+
|
57
|
+
def whoami
|
58
|
+
shell(:whoami, echo: false, capture: true) =~ /email\s*:\s*"(.+)"/ && $1
|
59
|
+
end
|
60
|
+
|
61
|
+
def write_rc
|
62
|
+
info :write_rc
|
63
|
+
write_file '~/.ey-core', "https://api.engineyard.com/: #{api_key}"
|
64
|
+
end
|
65
|
+
|
66
|
+
def invalid_migrate?
|
67
|
+
migrate.is_a?(TrueClass) || migrate == 'true'
|
68
|
+
end
|
69
|
+
|
70
|
+
def deploy_opts
|
71
|
+
opts = [%(--ref="#{git_sha}" --environment="#{env}")]
|
72
|
+
opts << opts_for(%i(app account))
|
73
|
+
opts << migrate_opt
|
74
|
+
opts.join(' ')
|
75
|
+
end
|
76
|
+
|
77
|
+
def migrate_opt
|
78
|
+
migrate? ? opts_for(%i(migrate)) : '--no-migrate'
|
79
|
+
end
|
80
|
+
|
81
|
+
def env
|
82
|
+
@env ||= super || detect_env(envs)
|
83
|
+
end
|
84
|
+
|
85
|
+
def detect_env(envs)
|
86
|
+
case envs.size
|
87
|
+
when 1 then envs.first[:name]
|
88
|
+
when 0 then error :no_env
|
89
|
+
else too_many_envs(envs)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def envs
|
94
|
+
lines = shell(:envs, echo: false, capture: true).split("\n")[2..-1] || []
|
95
|
+
envs = lines.map { |line| line.split('|')[1..-1].map(&:strip) }
|
96
|
+
envs = envs.map { |pair| %i(name account).zip(pair).to_h }
|
97
|
+
envs.select { |env| env[:name] == opts[:env] } if env?
|
98
|
+
envs
|
99
|
+
end
|
100
|
+
|
101
|
+
def too_many_envs(envs)
|
102
|
+
envs = envs.map { |env| msg(:env_entry) % env.values_at(:name, :account) }
|
103
|
+
error msg(:too_many_envs) % envs.join(', ')
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|