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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +172 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/CONTRIBUTING.md +392 -0
- data/Gemfile +32 -0
- data/Gemfile.lock +611 -0
- data/LICENSE +19 -0
- data/README.md +2744 -0
- data/Rakefile +210 -0
- data/bin/dpl +11 -0
- data/config/transliterate.yml +733 -0
- data/dpl.gemspec +23 -0
- data/lib/dpl/assets/atlas/install +19 -0
- data/lib/dpl/assets/convox/install +11 -0
- data/lib/dpl/assets/dpl/README.erb.md +138 -0
- data/lib/dpl/assets/dpl/git_ssh +8 -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 +100 -0
- data/lib/dpl/ctx/bash.rb +549 -0
- data/lib/dpl/ctx/test.rb +255 -0
- data/lib/dpl/ctx.rb +4 -0
- data/lib/dpl/helper/assets.rb +38 -0
- data/lib/dpl/helper/cmd.rb +169 -0
- data/lib/dpl/helper/config_file.rb +49 -0
- data/lib/dpl/helper/cookbook_site_streaming_uploader.rb +249 -0
- data/lib/dpl/helper/env.rb +92 -0
- data/lib/dpl/helper/github.rb +22 -0
- data/lib/dpl/helper/interpolate.rb +160 -0
- data/lib/dpl/helper/memoize.rb +23 -0
- data/lib/dpl/helper/squiggle.rb +24 -0
- data/lib/dpl/helper/transliterate.rb +13 -0
- data/lib/dpl/helper/wrap.rb +11 -0
- data/lib/dpl/helper/zip.rb +71 -0
- data/lib/dpl/provider/dsl.rb +410 -0
- data/lib/dpl/provider/examples.rb +132 -0
- data/lib/dpl/provider/status.rb +61 -0
- data/lib/dpl/provider.rb +651 -0
- data/lib/dpl/providers/anynines.rb +71 -0
- data/lib/dpl/providers/azure_web_apps.rb +63 -0
- data/lib/dpl/providers/bintray.rb +324 -0
- data/lib/dpl/providers/bluemixcloudfoundry.rb +98 -0
- data/lib/dpl/providers/boxfuse.rb +52 -0
- data/lib/dpl/providers/cargo.rb +32 -0
- data/lib/dpl/providers/chef_supermarket.rb +132 -0
- data/lib/dpl/providers/cloud66.rb +46 -0
- data/lib/dpl/providers/cloudfiles.rb +62 -0
- data/lib/dpl/providers/cloudformation.rb +281 -0
- data/lib/dpl/providers/cloudfoundry.rb +89 -0
- data/lib/dpl/providers/codedeploy.rb +190 -0
- data/lib/dpl/providers/convox.rb +130 -0
- data/lib/dpl/providers/datica.rb +64 -0
- data/lib/dpl/providers/ecr.rb +129 -0
- data/lib/dpl/providers/elasticbeanstalk.rb +207 -0
- data/lib/dpl/providers/engineyard.rb +113 -0
- data/lib/dpl/providers/firebase.rb +45 -0
- data/lib/dpl/providers/flynn.rb +35 -0
- data/lib/dpl/providers/gae.rb +78 -0
- data/lib/dpl/providers/gcs.rb +132 -0
- data/lib/dpl/providers/git_push.rb +273 -0
- data/lib/dpl/providers/gleis.rb +74 -0
- data/lib/dpl/providers/hackage.rb +53 -0
- data/lib/dpl/providers/hephy.rb +107 -0
- data/lib/dpl/providers/heroku/api.rb +123 -0
- data/lib/dpl/providers/heroku/git.rb +54 -0
- data/lib/dpl/providers/heroku.rb +111 -0
- data/lib/dpl/providers/lambda.rb +211 -0
- data/lib/dpl/providers/launchpad.rb +80 -0
- data/lib/dpl/providers/netlify.rb +38 -0
- data/lib/dpl/providers/npm.rb +130 -0
- data/lib/dpl/providers/nuget.rb +41 -0
- data/lib/dpl/providers/openshift.rb +52 -0
- data/lib/dpl/providers/opsworks.rb +146 -0
- data/lib/dpl/providers/packagecloud.rb_ +194 -0
- data/lib/dpl/providers/pages/api.rb +106 -0
- data/lib/dpl/providers/pages/git.rb +262 -0
- data/lib/dpl/providers/pages.rb +18 -0
- data/lib/dpl/providers/puppetforge.rb +50 -0
- data/lib/dpl/providers/pypi.rb +125 -0
- data/lib/dpl/providers/releases.rb +234 -0
- data/lib/dpl/providers/rubygems.rb +97 -0
- data/lib/dpl/providers/s3.rb +251 -0
- data/lib/dpl/providers/scalingo.rb +69 -0
- data/lib/dpl/providers/script.rb +32 -0
- data/lib/dpl/providers/snap.rb +68 -0
- data/lib/dpl/providers/surge.rb +59 -0
- data/lib/dpl/providers/testfairy.rb +101 -0
- data/lib/dpl/providers/transifex.rb +72 -0
- data/lib/dpl/providers.rb +48 -0
- data/lib/dpl/string_ext.rb +23 -0
- data/lib/dpl/support/aws_sdk_patch.rb +26 -0
- data/lib/dpl/support/gems.rb +73 -0
- data/lib/dpl/support/gstore_patch.rb +8 -0
- data/lib/dpl/support/version.rb +84 -0
- data/lib/dpl/version.rb +5 -0
- data/lib/dpl.rb +23 -0
- data/status.json +237 -0
- metadata +161 -0
@@ -0,0 +1,207 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dpl
|
4
|
+
module Providers
|
5
|
+
class Elasticbeanstalk < Provider
|
6
|
+
register :elasticbeanstalk
|
7
|
+
|
8
|
+
status :stable
|
9
|
+
|
10
|
+
full_name 'AWS Elastic Beanstalk'
|
11
|
+
|
12
|
+
description sq(<<-STR)
|
13
|
+
Deploy to AWS Elastic Beanstalk: https://aws.amazon.com/elasticbeanstalk/
|
14
|
+
|
15
|
+
This provider:
|
16
|
+
|
17
|
+
* Creates a zip file (or uses one you provide)
|
18
|
+
* Uploads it to your EB application
|
19
|
+
* Optionally deploys to a specific EB environment
|
20
|
+
* Optionally waits until the deployment finishes
|
21
|
+
STR
|
22
|
+
|
23
|
+
gem 'aws-sdk-elasticbeanstalk', '~> 1'
|
24
|
+
gem 'aws-sdk-s3', '~> 1'
|
25
|
+
gem 'rubyzip', '~> 2.3', require: 'zip'
|
26
|
+
gem 'pathspec', '~> 1.1', require: 'pathspec'
|
27
|
+
|
28
|
+
env :aws, :elastic_beanstalk
|
29
|
+
config '~/.aws/credentials', '~/.aws/config', prefix: 'aws'
|
30
|
+
|
31
|
+
opt '--access_key_id ID', 'AWS Access Key ID', required: true, secret: true
|
32
|
+
opt '--secret_access_key KEY', 'AWS Secret Key', required: true, secret: true
|
33
|
+
opt '--region REGION', 'AWS Region the Elastic Beanstalk app is running in', default: 'us-east-1'
|
34
|
+
opt '--app NAME', 'Elastic Beanstalk application name', default: :repo_name
|
35
|
+
opt '--env NAME', 'Elastic Beanstalk environment name to be updated.'
|
36
|
+
opt '--bucket NAME', 'Bucket name to upload app to', required: true, alias: :bucket_name
|
37
|
+
opt '--bucket_path PATH', 'Location within Bucket to upload app to'
|
38
|
+
opt '--description DESC', 'Description for the application version'
|
39
|
+
opt '--label LABEL', 'Label for the application version'
|
40
|
+
opt '--zip_file PATH', 'The zip file that you want to deploy. If not given, a zipfile will be created from the current directory, honoring .ebignore and .gitignore.'
|
41
|
+
opt '--wait_until_deployed', 'Wait until the deployment has finished', requires: :env
|
42
|
+
opt '--wait_until_deployed_timeout SEC', 'How many seconds to wait for Elastic Beanstalk deployment update.', type: :integer, default: 600
|
43
|
+
opt '--debug', internal: true
|
44
|
+
|
45
|
+
msgs login: 'Using Access Key: %{access_key_id}',
|
46
|
+
zip_add: 'Adding %s'
|
47
|
+
|
48
|
+
msgs clean_description: 'Removed non-printable characters from the version description'
|
49
|
+
|
50
|
+
attr_reader :started, :object, :version
|
51
|
+
|
52
|
+
def login
|
53
|
+
info :login
|
54
|
+
end
|
55
|
+
|
56
|
+
def setup
|
57
|
+
info :login
|
58
|
+
Aws.config.update(credentials:, region:)
|
59
|
+
end
|
60
|
+
|
61
|
+
def deploy
|
62
|
+
@started = Time.now
|
63
|
+
bucket.create unless bucket.exists?
|
64
|
+
create_zip unless zip_exists?
|
65
|
+
upload
|
66
|
+
create_version
|
67
|
+
update_app if env?
|
68
|
+
end
|
69
|
+
|
70
|
+
def zip_file
|
71
|
+
zip_file? ? expand(super) : archive_name
|
72
|
+
end
|
73
|
+
|
74
|
+
def archive_name
|
75
|
+
"#{label}.zip"
|
76
|
+
end
|
77
|
+
|
78
|
+
def label
|
79
|
+
@label ||= super || "travis-#{git_sha}-#{Time.now.to_i}"
|
80
|
+
end
|
81
|
+
|
82
|
+
def description
|
83
|
+
super || git_commit_msg
|
84
|
+
end
|
85
|
+
|
86
|
+
def bucket_path
|
87
|
+
bucket_path? ? "#{super.gsub(%r{/*$}, '')}/#{archive_name}" : archive_name
|
88
|
+
end
|
89
|
+
|
90
|
+
def cwd
|
91
|
+
@cwd ||= "#{Dir.pwd}/"
|
92
|
+
end
|
93
|
+
|
94
|
+
def zip_exists?
|
95
|
+
File.exist?(zip_file)
|
96
|
+
end
|
97
|
+
|
98
|
+
def create_zip
|
99
|
+
::Zip::File.open(zip_file, ::Zip::File::CREATE) do |zip|
|
100
|
+
files.each do |path|
|
101
|
+
debug :zip_add, path
|
102
|
+
zip.add(path.sub(cwd, ''), path)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def upload
|
108
|
+
@object = bucket.object(bucket_path)
|
109
|
+
object.put(body: File.open(zip_file))
|
110
|
+
sleep 5 # s3 eventual consistency
|
111
|
+
end
|
112
|
+
|
113
|
+
def create_version
|
114
|
+
@version = eb.create_application_version(
|
115
|
+
application_name: app,
|
116
|
+
version_label: label,
|
117
|
+
description: clean(description[0, 200]),
|
118
|
+
source_bundle: {
|
119
|
+
s3_bucket: bucket.name,
|
120
|
+
s3_key: object.key
|
121
|
+
},
|
122
|
+
auto_create_application: false
|
123
|
+
)
|
124
|
+
end
|
125
|
+
|
126
|
+
def update_app
|
127
|
+
eb.update_environment(
|
128
|
+
environment_name: env,
|
129
|
+
version_label: version[:application_version][:version_label]
|
130
|
+
)
|
131
|
+
wait_until_deployed if wait_until_deployed?
|
132
|
+
end
|
133
|
+
|
134
|
+
def wait_until_deployed
|
135
|
+
msgs = []
|
136
|
+
1.upto(wait_until_deployed_timeout / 5) { return if check_deployment(msgs) }
|
137
|
+
error 'Deploy status unknown due to timeout. Increase the wait_until_deployed_timeout option'
|
138
|
+
end
|
139
|
+
|
140
|
+
def check_deployment(msgs)
|
141
|
+
sleep 5
|
142
|
+
events.each do |event|
|
143
|
+
msg = "#{event.event_date} [#{event.severity}] #{event.message}"
|
144
|
+
error "Deployment failed: #{msg}" if event.severity == 'ERROR'
|
145
|
+
info msg unless msgs.include?(msg)
|
146
|
+
msgs << msg
|
147
|
+
end
|
148
|
+
environment[:status] == 'Ready'
|
149
|
+
rescue Aws::Errors::ServiceError => e
|
150
|
+
info "Caught #{e}: #{e.message}. Retrying ..."
|
151
|
+
end
|
152
|
+
|
153
|
+
def files
|
154
|
+
files = Dir.glob('**/*', File::FNM_DOTMATCH)
|
155
|
+
ignore = %w[.ebignore .gitignore].detect { |file| file?(file) }
|
156
|
+
files = filter(files, ignore) if ignore
|
157
|
+
files
|
158
|
+
end
|
159
|
+
|
160
|
+
def filter(files, spec)
|
161
|
+
spec = PathSpec.from_filename(spec)
|
162
|
+
files.reject { |file| spec.match(file) }
|
163
|
+
end
|
164
|
+
|
165
|
+
def events
|
166
|
+
args = { environment_name: env, start_time: started.utc.iso8601 }
|
167
|
+
eb.describe_events(args)[:events].reverse
|
168
|
+
end
|
169
|
+
|
170
|
+
def environment
|
171
|
+
args = { application_name: app, environment_names: [env] }
|
172
|
+
eb.describe_environments(args)[:environments].first
|
173
|
+
end
|
174
|
+
|
175
|
+
def credentials
|
176
|
+
Aws::Credentials.new(access_key_id, secret_access_key)
|
177
|
+
end
|
178
|
+
|
179
|
+
def s3
|
180
|
+
@s3 ||= Aws::S3::Resource.new
|
181
|
+
end
|
182
|
+
|
183
|
+
def bucket
|
184
|
+
@bucket ||= s3.bucket(super)
|
185
|
+
end
|
186
|
+
|
187
|
+
def eb
|
188
|
+
@eb ||= Aws::ElasticBeanstalk::Client.new(retry_limit: 10)
|
189
|
+
end
|
190
|
+
|
191
|
+
# We do not actually know what characters are valid on AWS EB's side,
|
192
|
+
# see: https://github.com/aws/aws-sdk-ruby/issues/1502
|
193
|
+
#
|
194
|
+
# Reference: https://www.w3.org/TR/xml/#charsets
|
195
|
+
NON_PRINTABLE_CHARS = "\u0009\u000A\u000D\u0020-\uD7FF\uE000-\uFFFD\u10000-\u10FFFF"
|
196
|
+
|
197
|
+
def clean(str)
|
198
|
+
str.gsub!(/[^#{NON_PRINTABLE_CHARS}]/, '') && info(:clean_description)
|
199
|
+
str
|
200
|
+
end
|
201
|
+
|
202
|
+
def debug(*args)
|
203
|
+
info(*args) if debug?
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dpl
|
4
|
+
module Providers
|
5
|
+
class Engineyard < Provider
|
6
|
+
register :engineyard
|
7
|
+
|
8
|
+
status :alpha
|
9
|
+
|
10
|
+
description sq(<<-STR)
|
11
|
+
tbd
|
12
|
+
STR
|
13
|
+
|
14
|
+
gem 'ey-core', '~> 3.6'
|
15
|
+
|
16
|
+
required :api_key, %i[email password]
|
17
|
+
|
18
|
+
env :engineyard, :ey
|
19
|
+
|
20
|
+
opt '--api_key KEY', 'Engine Yard API key', secret: true, note: 'can be obtained at https://cloud.engineyard.com/cli'
|
21
|
+
opt '--email EMAIL', 'Engine Yard account email'
|
22
|
+
opt '--password PASS', 'Engine Yard password', secret: true
|
23
|
+
opt '--app APP', 'Engine Yard application name', default: :repo_name
|
24
|
+
opt '--env ENV', 'Engine Yard application environment', alias: :environment
|
25
|
+
opt '--migrate CMD', 'Engine Yard migration commands'
|
26
|
+
opt '--account NAME', 'Engine Yard account name'
|
27
|
+
|
28
|
+
msgs deploy: 'Deploying ...',
|
29
|
+
login: 'Authenticating via email and password ...',
|
30
|
+
write_rc: 'Authenticating via api token ...',
|
31
|
+
authenticated: 'Authenticated as %{name}',
|
32
|
+
invalid_migrate: 'Invalid migration command, try --migrate="rake db:migrate"',
|
33
|
+
envs: 'Checking environment ...',
|
34
|
+
no_env: 'No matching environment found',
|
35
|
+
too_many_envs: 'Multiple environments match, please be more specific: %s',
|
36
|
+
env_entry: 'environment=%s account=%s'
|
37
|
+
|
38
|
+
cmds login: "ey-core login << str\n%{email}\n%{password}\nstr",
|
39
|
+
whoami: 'ey-core whoami',
|
40
|
+
envs: 'ey-core environments',
|
41
|
+
deploy: 'ey-core deploy %{deploy_opts}'
|
42
|
+
|
43
|
+
def login
|
44
|
+
api_key? ? write_rc : authenticate
|
45
|
+
info :authenticated, name: whoami
|
46
|
+
end
|
47
|
+
|
48
|
+
def validate
|
49
|
+
error :invalid_migrate if invalid_migrate?
|
50
|
+
env
|
51
|
+
end
|
52
|
+
|
53
|
+
def deploy
|
54
|
+
shell :deploy
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def authenticate
|
60
|
+
shell :login, echo: false, capture: true
|
61
|
+
end
|
62
|
+
|
63
|
+
def whoami
|
64
|
+
shell(:whoami, echo: false, capture: true) =~ /email\s*:\s*"(.+)"/ && ::Regexp.last_match(1)
|
65
|
+
end
|
66
|
+
|
67
|
+
def write_rc
|
68
|
+
info :write_rc
|
69
|
+
write_file '~/.ey-core', "https://api.engineyard.com/: #{api_key}"
|
70
|
+
end
|
71
|
+
|
72
|
+
def invalid_migrate?
|
73
|
+
migrate.is_a?(TrueClass) || migrate == 'true'
|
74
|
+
end
|
75
|
+
|
76
|
+
def deploy_opts
|
77
|
+
opts = [%(--ref="#{git_sha}" --environment="#{env}")]
|
78
|
+
opts << opts_for(%i[app account])
|
79
|
+
opts << migrate_opt
|
80
|
+
opts.join(' ')
|
81
|
+
end
|
82
|
+
|
83
|
+
def migrate_opt
|
84
|
+
migrate? ? opts_for(%i[migrate]) : '--no-migrate'
|
85
|
+
end
|
86
|
+
|
87
|
+
def env
|
88
|
+
@env ||= super || detect_env(envs)
|
89
|
+
end
|
90
|
+
|
91
|
+
def detect_env(envs)
|
92
|
+
case envs.size
|
93
|
+
when 1 then envs.first[:name]
|
94
|
+
when 0 then error :no_env
|
95
|
+
else too_many_envs(envs)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def envs
|
100
|
+
lines = shell(:envs, echo: false, capture: true).split("\n")[2..] || []
|
101
|
+
envs = lines.map { |line| line.split('|')[1..].map(&:strip) }
|
102
|
+
envs = envs.map { |pair| %i[name account].zip(pair).to_h }
|
103
|
+
envs.select { |env| env[:name] == opts[:env] } if env?
|
104
|
+
envs
|
105
|
+
end
|
106
|
+
|
107
|
+
def too_many_envs(envs)
|
108
|
+
envs = envs.map { |env| msg(:env_entry) % env.values_at(:name, :account) }
|
109
|
+
error msg(:too_many_envs) % envs.join(', ')
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dpl
|
4
|
+
module Providers
|
5
|
+
class Firebase < Provider
|
6
|
+
register :firebase
|
7
|
+
|
8
|
+
status :stable
|
9
|
+
|
10
|
+
description sq(<<-STR)
|
11
|
+
tbd
|
12
|
+
STR
|
13
|
+
|
14
|
+
node_js '>= 8.0.0'
|
15
|
+
|
16
|
+
npm 'firebase-tools@^6.3', 'firebase'
|
17
|
+
|
18
|
+
path 'node_modules/.bin'
|
19
|
+
|
20
|
+
env :firebase
|
21
|
+
|
22
|
+
opt '--token TOKEN', 'Firebase CI access token (generate with firebase login:ci)', required: true, secret: true
|
23
|
+
opt '--project NAME', 'Firebase project to deploy to (defaults to the one specified in your firebase.json)'
|
24
|
+
opt '--message MSG', 'Message describing this deployment.'
|
25
|
+
opt '--only SERVICES', 'Firebase services to deploy', note: 'can be a comma-separated list'
|
26
|
+
opt '--force', 'Whether or not to delete Cloud Functions missing from the current working directory'
|
27
|
+
|
28
|
+
cmds deploy: 'firebase deploy --non-interactive %{deploy_opts}'
|
29
|
+
errs deploy: 'Firebase deployment failed'
|
30
|
+
msgs missing_config: 'Missing firebase.json'
|
31
|
+
|
32
|
+
def validate
|
33
|
+
error :missing_config unless File.exist?('firebase.json')
|
34
|
+
end
|
35
|
+
|
36
|
+
def deploy
|
37
|
+
shell :deploy
|
38
|
+
end
|
39
|
+
|
40
|
+
def deploy_opts
|
41
|
+
opts_for(%i[project message token only force])
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dpl
|
4
|
+
module Providers
|
5
|
+
class Flynn < Provider
|
6
|
+
register :flynn
|
7
|
+
|
8
|
+
status :dev
|
9
|
+
|
10
|
+
full_name 'Flynn'
|
11
|
+
|
12
|
+
description sq(<<-STR)
|
13
|
+
Flynn provider for Dpl
|
14
|
+
STR
|
15
|
+
|
16
|
+
opt '--git URL', 'Flynn Git remote URL', required: true
|
17
|
+
|
18
|
+
needs :git, :git_http_user_agent
|
19
|
+
|
20
|
+
cmds fetch: 'git fetch origin $TRAVIS_BRANCH --unshallow',
|
21
|
+
push: 'git push %{remote} HEAD:refs/heads/master -f'
|
22
|
+
|
23
|
+
def deploy
|
24
|
+
shell :fetch, assert: false
|
25
|
+
shell :push
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def remote
|
31
|
+
git
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dpl
|
4
|
+
module Providers
|
5
|
+
class Gae < Provider
|
6
|
+
register :gae
|
7
|
+
|
8
|
+
status :stable
|
9
|
+
|
10
|
+
full_name 'Google App Engine'
|
11
|
+
|
12
|
+
description sq(<<-STR)
|
13
|
+
tbd
|
14
|
+
STR
|
15
|
+
|
16
|
+
python '>= 2.7.9'
|
17
|
+
|
18
|
+
env :gae, :googlecloud, :cloudsdk_core, allow_skip_underscore: true
|
19
|
+
|
20
|
+
opt '--project ID', 'Project ID used to identify the project on Google Cloud', required: true
|
21
|
+
opt '--keyfile FILE', 'Path to the JSON file containing your Service Account credentials in JSON Web Token format. To be obtained via the Google Developers Console. Should be handled with care as it contains authorization keys.', default: 'service-account.json'
|
22
|
+
opt '--config FILE', 'Path to your service configuration file', type: :array, default: 'app.yaml'
|
23
|
+
opt '--version VER', 'The version of the app that will be created or replaced by this deployment. If you do not specify a version, one will be generated for you'
|
24
|
+
opt '--verbosity LEVEL', 'Adjust the log verbosity', default: 'warning'
|
25
|
+
opt '--promote', 'Whether to promote the deployed version', default: true
|
26
|
+
opt '--stop_previous_version', 'Prevent the deployment from stopping a previously promoted version', default: true
|
27
|
+
opt '--install_sdk', 'Whether to install the Google Cloud SDK', default: true
|
28
|
+
|
29
|
+
URL = 'https://dl.google.com/dl/cloudsdk/channels/rapid/google-cloud-sdk.tar.gz'
|
30
|
+
|
31
|
+
cmds install: 'curl -L %{URL} | tar xz -C ~ && ~/google-cloud-sdk/install.sh --path-update false --usage-reporting false --command-completion false',
|
32
|
+
login: 'gcloud -q auth activate-service-account --key-file %{keyfile}',
|
33
|
+
deploy: 'gcloud -q app deploy %{config} %{deploy_opts}',
|
34
|
+
cat_logs: 'find $HOME/.config/gcloud/logs -type f -print -exec cat {} \;'
|
35
|
+
|
36
|
+
errs install: 'Failed to download Google Cloud SDK.',
|
37
|
+
login: 'Failed to authenticate.'
|
38
|
+
|
39
|
+
msgs failed: 'Deployment failed.'
|
40
|
+
|
41
|
+
path '~/google-cloud-sdk/bin'
|
42
|
+
|
43
|
+
def install
|
44
|
+
return unless install_sdk?
|
45
|
+
|
46
|
+
shell :install
|
47
|
+
end
|
48
|
+
|
49
|
+
def login
|
50
|
+
shell :login
|
51
|
+
end
|
52
|
+
|
53
|
+
def deploy
|
54
|
+
shell :deploy
|
55
|
+
failed unless success?
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def deploy_opts
|
61
|
+
opts = [*opts_for(%i[project verbosity version])]
|
62
|
+
opts << '--no-promote' unless promote?
|
63
|
+
opts << '--no-stop-previous-version' unless stop_previous_version?
|
64
|
+
opts.join(' ')
|
65
|
+
end
|
66
|
+
|
67
|
+
def failed
|
68
|
+
warn :failed
|
69
|
+
shell :cat_logs
|
70
|
+
error ''
|
71
|
+
end
|
72
|
+
|
73
|
+
def project
|
74
|
+
super || File.dirname(build_dir)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'kconv'
|
4
|
+
|
5
|
+
module Dpl
|
6
|
+
module Providers
|
7
|
+
class Gcs < Provider
|
8
|
+
register :gcs
|
9
|
+
|
10
|
+
status :stable
|
11
|
+
|
12
|
+
full_name 'Google Cloud Store'
|
13
|
+
|
14
|
+
description sq(<<-STR)
|
15
|
+
tbd
|
16
|
+
STR
|
17
|
+
|
18
|
+
gem 'mime-types', '~> 3.4.1'
|
19
|
+
|
20
|
+
python '>= 2.7.9'
|
21
|
+
|
22
|
+
env :gcs
|
23
|
+
|
24
|
+
required :key_file, %i[access_key_id secret_access_key]
|
25
|
+
|
26
|
+
opt '--key_file FILE', 'Path to a GCS service account key JSON file'
|
27
|
+
opt '--access_key_id ID', 'GCS Interoperable Access Key ID', secret: true
|
28
|
+
opt '--secret_access_key KEY', 'GCS Interoperable Access Secret', secret: true
|
29
|
+
opt '--bucket BUCKET', 'GCS Bucket', required: true
|
30
|
+
opt '--local_dir DIR', 'Local directory to upload from', default: '.'
|
31
|
+
opt '--upload_dir DIR', 'GCS directory to upload to'
|
32
|
+
opt '--dot_match', 'Upload hidden files starting with a dot'
|
33
|
+
opt '--acl ACL', 'Access control to set for uploaded objects', default: 'private', enum: %w[private public-read public-read-write authenticated-read bucket-owner-read bucket-owner-full-control], see: 'https://cloud.google.com/storage/docs/reference-headers#xgoogacl'
|
34
|
+
opt '--detect_encoding', 'HTTP header Content-Encoding to set for files compressed with gzip and compress utilities.'
|
35
|
+
opt '--cache_control HEADER', 'HTTP header Cache-Control to suggest that the browser cache the file.', see: 'https://cloud.google.com/storage/docs/xml-api/reference-headers#cachecontrol'
|
36
|
+
opt '--glob GLOB', default: '**/*'
|
37
|
+
|
38
|
+
cmds install: 'curl -L %{URL} | tar xz -C ~ && ~/google-cloud-sdk/install.sh --quiet --path-update false --usage-reporting false --command-completion false',
|
39
|
+
login_key: 'gcloud auth activate-service-account --key-file=%{key_file}',
|
40
|
+
rsync: 'gsutil %{gs_opts} rsync %{rsync_opts} %{glob} %{target}',
|
41
|
+
copy: 'gsutil %{gs_opts} cp %{copy_opts} -r %{source} %{target}'
|
42
|
+
|
43
|
+
msgs login_key: 'Authenticating with service account key file %{key_file}',
|
44
|
+
login_creds: 'Authenticating with access key: %{access_key_id}'
|
45
|
+
|
46
|
+
errs copy: 'Failed uploading files.'
|
47
|
+
|
48
|
+
URL = 'https://dl.google.com/dl/cloudsdk/channels/rapid/google-cloud-sdk.tar.gz'
|
49
|
+
|
50
|
+
BOTO = sq(<<-STR)
|
51
|
+
[Credentials]
|
52
|
+
gs_access_key_id = %{access_key_id}
|
53
|
+
gs_secret_access_key = %{secret_access_key}
|
54
|
+
STR
|
55
|
+
|
56
|
+
path '~/google-cloud-sdk'
|
57
|
+
move '/etc/boto.cfg'
|
58
|
+
|
59
|
+
def install
|
60
|
+
shell :install
|
61
|
+
end
|
62
|
+
|
63
|
+
def login
|
64
|
+
key_file? ? login_key : login_creds
|
65
|
+
end
|
66
|
+
|
67
|
+
def deploy
|
68
|
+
Dir.chdir(local_dir) do
|
69
|
+
files.each { |file| copy(file) }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def login_key
|
76
|
+
shell :login_key
|
77
|
+
end
|
78
|
+
|
79
|
+
def login_creds
|
80
|
+
info :login_creds
|
81
|
+
write_boto
|
82
|
+
end
|
83
|
+
|
84
|
+
def write_boto
|
85
|
+
write_file '~/.boto', interpolate(BOTO, opts, secure: true), 0600
|
86
|
+
end
|
87
|
+
|
88
|
+
def files
|
89
|
+
Dir.glob(*glob_args).select { |path| File.file?(path) }
|
90
|
+
end
|
91
|
+
|
92
|
+
def copy(source)
|
93
|
+
to = [target.sub(%r{/$}, ''), source].join('/')
|
94
|
+
shell :copy, gs_opts: gs_opts(source), source:, target: to
|
95
|
+
end
|
96
|
+
|
97
|
+
def dirname(path)
|
98
|
+
dir = File.dirname(path)
|
99
|
+
dir unless dir.empty? || dir == '.'
|
100
|
+
end
|
101
|
+
|
102
|
+
def gs_opts(path)
|
103
|
+
opts = []
|
104
|
+
opts << %(-h "Cache-Control:#{cache_control}") if cache_control?
|
105
|
+
opts << %(-h "Content-Encoding:#{encoding(path)}") if detect_encoding?
|
106
|
+
opts << %(-h "Content-type:#{mime_type(path)}") if mime_type(path)
|
107
|
+
"#{opts.join(' ')} " if opts.any?
|
108
|
+
end
|
109
|
+
|
110
|
+
def copy_opts
|
111
|
+
opts = []
|
112
|
+
opts << %(-a "#{acl}") if acl?
|
113
|
+
"#{opts.join(' ')} " if opts.any?
|
114
|
+
end
|
115
|
+
|
116
|
+
def target
|
117
|
+
"gs://#{bucket}/#{upload_dir}"
|
118
|
+
end
|
119
|
+
|
120
|
+
def mime_type(path)
|
121
|
+
type = MIME::Types.type_for(path).first
|
122
|
+
type&.to_s
|
123
|
+
end
|
124
|
+
|
125
|
+
def glob_args
|
126
|
+
args = [glob]
|
127
|
+
args << File::FNM_DOTMATCH if dot_match?
|
128
|
+
args
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|