dpl-connect 1.8.43
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +8 -0
- data/.rspec +2 -0
- data/.travis.yml +36 -0
- data/Gemfile +100 -0
- data/LICENSE +22 -0
- data/README.md +934 -0
- data/Rakefile +1 -0
- data/TESTING.md +29 -0
- data/bin/dpl +5 -0
- data/dpl.gemspec +32 -0
- data/lib/dpl/cli.rb +66 -0
- data/lib/dpl/error.rb +3 -0
- data/lib/dpl/provider.rb +264 -0
- data/lib/dpl/provider/anynines.rb +13 -0
- data/lib/dpl/provider/appfog.rb +21 -0
- data/lib/dpl/provider/atlas.rb +108 -0
- data/lib/dpl/provider/azure_webapps.rb +48 -0
- data/lib/dpl/provider/bintray.rb +509 -0
- data/lib/dpl/provider/bitballoon.rb +22 -0
- data/lib/dpl/provider/bluemix_cloud_foundry.rb +23 -0
- data/lib/dpl/provider/boxfuse.rb +57 -0
- data/lib/dpl/provider/catalyze.rb +49 -0
- data/lib/dpl/provider/chef_supermarket.rb +85 -0
- data/lib/dpl/provider/cloud66.rb +38 -0
- data/lib/dpl/provider/cloud_files.rb +38 -0
- data/lib/dpl/provider/cloud_foundry.rb +43 -0
- data/lib/dpl/provider/code_deploy.rb +123 -0
- data/lib/dpl/provider/deis.rb +119 -0
- data/lib/dpl/provider/divshot.rb +23 -0
- data/lib/dpl/provider/elastic_beanstalk.rb +195 -0
- data/lib/dpl/provider/engine_yard.rb +90 -0
- data/lib/dpl/provider/firebase.rb +27 -0
- data/lib/dpl/provider/gae.rb +97 -0
- data/lib/dpl/provider/gcs.rb +59 -0
- data/lib/dpl/provider/hackage.rb +29 -0
- data/lib/dpl/provider/heroku.rb +18 -0
- data/lib/dpl/provider/heroku/api.rb +98 -0
- data/lib/dpl/provider/heroku/generic.rb +94 -0
- data/lib/dpl/provider/heroku/git.rb +28 -0
- data/lib/dpl/provider/lambda.rb +236 -0
- data/lib/dpl/provider/launchpad.rb +48 -0
- data/lib/dpl/provider/modulus.rb +23 -0
- data/lib/dpl/provider/npm.rb +64 -0
- data/lib/dpl/provider/openshift.rb +59 -0
- data/lib/dpl/provider/ops_works.rb +132 -0
- data/lib/dpl/provider/packagecloud.rb +144 -0
- data/lib/dpl/provider/pages.rb +79 -0
- data/lib/dpl/provider/puppet_forge.rb +43 -0
- data/lib/dpl/provider/pypi.rb +111 -0
- data/lib/dpl/provider/releases.rb +139 -0
- data/lib/dpl/provider/rubygems.rb +51 -0
- data/lib/dpl/provider/s3.rb +123 -0
- data/lib/dpl/provider/scalingo.rb +97 -0
- data/lib/dpl/provider/script.rb +29 -0
- data/lib/dpl/provider/surge.rb +33 -0
- data/lib/dpl/provider/testfairy.rb +190 -0
- data/lib/dpl/provider/transifex.rb +45 -0
- data/lib/dpl/version.rb +3 -0
- data/notes/engine_yard.md +1 -0
- data/notes/heroku.md +3 -0
- data/spec/cli_spec.rb +36 -0
- data/spec/provider/anynines_spec.rb +20 -0
- data/spec/provider/appfog_spec.rb +35 -0
- data/spec/provider/atlas_spec.rb +99 -0
- data/spec/provider/azure_webapps_spec.rb +95 -0
- data/spec/provider/bintray_spec.rb +259 -0
- data/spec/provider/bitballoon_spec.rb +32 -0
- data/spec/provider/bluemixcloudfoundry_spec.rb +23 -0
- data/spec/provider/boxfuse_spec.rb +16 -0
- data/spec/provider/catalyze_spec.rb +39 -0
- data/spec/provider/chef_supermarket_spec.rb +51 -0
- data/spec/provider/cloud66_spec.rb +44 -0
- data/spec/provider/cloud_files_spec.rb +88 -0
- data/spec/provider/cloudfoundry_spec.rb +71 -0
- data/spec/provider/code_deploy_spec.rb +360 -0
- data/spec/provider/deis_spec.rb +116 -0
- data/spec/provider/divshot_spec.rb +28 -0
- data/spec/provider/elastic_beanstalk_spec.rb +209 -0
- data/spec/provider/firebase_spec.rb +40 -0
- data/spec/provider/gae_spec.rb +26 -0
- data/spec/provider/gcs_spec.rb +115 -0
- data/spec/provider/hackage_spec.rb +47 -0
- data/spec/provider/heroku_spec.rb +357 -0
- data/spec/provider/lambda_spec.rb +432 -0
- data/spec/provider/launchpad_spec.rb +33 -0
- data/spec/provider/modulus_spec.rb +29 -0
- data/spec/provider/npm_spec.rb +95 -0
- data/spec/provider/openshift_spec.rb +91 -0
- data/spec/provider/ops_works_spec.rb +127 -0
- data/spec/provider/packagecloud_spec.rb +56 -0
- data/spec/provider/puppet_forge_spec.rb +60 -0
- data/spec/provider/pypi_spec.rb +103 -0
- data/spec/provider/releases_spec.rb +303 -0
- data/spec/provider/rubygems_spec.rb +106 -0
- data/spec/provider/s3_spec.rb +174 -0
- data/spec/provider/scalingo_spec.rb +64 -0
- data/spec/provider/script_spec.rb +26 -0
- data/spec/provider/surge_spec.rb +15 -0
- data/spec/provider/testfairy_spec.rb +86 -0
- data/spec/provider/transifex_spec.rb +110 -0
- data/spec/provider_spec.rb +210 -0
- data/spec/spec_helper.rb +20 -0
- metadata +279 -0
@@ -0,0 +1,79 @@
|
|
1
|
+
module DPL
|
2
|
+
class Provider
|
3
|
+
class Pages < Provider
|
4
|
+
"""Implements Github Pages deployment
|
5
|
+
|
6
|
+
Options:
|
7
|
+
- repo [optional, for pushed to other repos]
|
8
|
+
- github-token [required]
|
9
|
+
- github-url [optional, defaults to github.com]
|
10
|
+
- target-branch [optional, defaults to gh-pages]
|
11
|
+
- local-dir [optional, defaults to `pwd`]
|
12
|
+
- fqdn [optional]
|
13
|
+
- project-name [optional, defaults to fqdn or repo slug]
|
14
|
+
- email [optional, defaults to deploy@travis-ci.org]
|
15
|
+
- name [optional, defaults to Deployment Bot]
|
16
|
+
"""
|
17
|
+
|
18
|
+
require 'tmpdir'
|
19
|
+
|
20
|
+
experimental 'GitHub Pages'
|
21
|
+
|
22
|
+
def initialize(context, options)
|
23
|
+
super
|
24
|
+
|
25
|
+
@build_dir = options[:local_dir] || '.'
|
26
|
+
@project_name = options[:project_name] || fqdn || slug
|
27
|
+
@target_branch = options[:target_branch] || 'gh-pages'
|
28
|
+
|
29
|
+
@gh_fqdn = fqdn
|
30
|
+
@gh_url = options[:github_url] || 'github.com'
|
31
|
+
@gh_token = option(:github_token)
|
32
|
+
|
33
|
+
@gh_email = options[:email] || 'deploy@travis-ci.org'
|
34
|
+
@gh_name = "#{options[:name] || 'Deployment Bot'} (from Travis CI)"
|
35
|
+
|
36
|
+
@gh_ref = "#{@gh_url}/#{slug}.git"
|
37
|
+
end
|
38
|
+
|
39
|
+
def fqdn
|
40
|
+
options.fetch(:fqdn) { nil }
|
41
|
+
end
|
42
|
+
|
43
|
+
def slug
|
44
|
+
options.fetch(:repo) { context.env['TRAVIS_REPO_SLUG'] }
|
45
|
+
end
|
46
|
+
|
47
|
+
def check_auth
|
48
|
+
end
|
49
|
+
|
50
|
+
def needs_key?
|
51
|
+
false
|
52
|
+
end
|
53
|
+
|
54
|
+
def github_deploy
|
55
|
+
context.shell 'rm -rf .git > /dev/null 2>&1'
|
56
|
+
context.shell "touch \"deployed at `date` by #{@gh_name}\""
|
57
|
+
context.shell 'git init' or raise 'Could not create new git repo'
|
58
|
+
context.shell "git config user.email '#{@gh_email}'"
|
59
|
+
context.shell "git config user.name '#{@gh_name}'"
|
60
|
+
context.shell "echo '#{@gh_fqdn}' > CNAME" if @gh_fqdn
|
61
|
+
context.shell 'git add .'
|
62
|
+
context.shell "FILES=\"`git commit -m 'Deploy #{@project_name} to #{@gh_ref}:#{@target_branch}' | tail`\"; echo \"$FILES\"; echo \"$FILES\" | [ `wc -l` -lt 10 ] || echo '...'"
|
63
|
+
context.shell "git push --force --quiet 'https://#{@gh_token}@#{@gh_ref}' master:#{@target_branch} > /dev/null 2>&1"
|
64
|
+
end
|
65
|
+
|
66
|
+
def push_app
|
67
|
+
Dir.mktmpdir {|tmpdir|
|
68
|
+
FileUtils.cp_r("#{@build_dir}/.", tmpdir)
|
69
|
+
FileUtils.cd(tmpdir, :verbose => true) do
|
70
|
+
unless github_deploy
|
71
|
+
error "Couldn't push the build to #{@gh_ref}:#{@target_branch}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
}
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module DPL
|
2
|
+
class Provider
|
3
|
+
class PuppetForge < Provider
|
4
|
+
require 'pathname'
|
5
|
+
|
6
|
+
requires 'json_pure', :version => '< 2.0', :load => 'json/pure'
|
7
|
+
requires 'puppet', :load => 'puppet/face'
|
8
|
+
requires 'puppet-blacksmith', :load => 'puppet_blacksmith'
|
9
|
+
|
10
|
+
def modulefile
|
11
|
+
@modulefile ||= Blacksmith::Modulefile.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def forge
|
15
|
+
@forge ||= Blacksmith::Forge.new(options[:user], options[:password], options[:url])
|
16
|
+
end
|
17
|
+
|
18
|
+
def build
|
19
|
+
pmod = Puppet::Face['module', :current]
|
20
|
+
pmod.build('./')
|
21
|
+
end
|
22
|
+
|
23
|
+
def needs_key?
|
24
|
+
false
|
25
|
+
end
|
26
|
+
|
27
|
+
def check_app
|
28
|
+
modulefile.metadata
|
29
|
+
end
|
30
|
+
|
31
|
+
def check_auth
|
32
|
+
raise Error, "must supply a user" unless option(:user)
|
33
|
+
raise Error, "must supply a password" unless option(:password)
|
34
|
+
end
|
35
|
+
|
36
|
+
def push_app
|
37
|
+
build
|
38
|
+
log "Uploading to Puppet Forge #{forge.username}/#{modulefile.name}"
|
39
|
+
forge.push!(modulefile.name)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module DPL
|
2
|
+
class Provider
|
3
|
+
class PyPI < Provider
|
4
|
+
DEFAULT_SERVER = 'https://upload.pypi.org/legacy/'
|
5
|
+
PYPIRC_FILE = '~/.pypirc'
|
6
|
+
|
7
|
+
def pypi_user
|
8
|
+
option(:username, :user) || context.env['PYPI_USER'] || context.env['PYPI_USERNAME']
|
9
|
+
end
|
10
|
+
|
11
|
+
def pypi_password
|
12
|
+
options[:password] || context.env['PYPI_PASSWORD']
|
13
|
+
end
|
14
|
+
|
15
|
+
def pypi_server
|
16
|
+
options[:server] || context.env['PYPI_SERVER'] || DEFAULT_SERVER
|
17
|
+
end
|
18
|
+
|
19
|
+
def pypi_distributions
|
20
|
+
options[:distributions] || context.env['PYPI_DISTRIBUTIONS'] || 'sdist'
|
21
|
+
end
|
22
|
+
|
23
|
+
def pypi_docs_dir_option
|
24
|
+
docs_dir = options[:docs_dir] || context.env['PYPI_DOCS_DIR'] || ''
|
25
|
+
if !docs_dir.empty?
|
26
|
+
'--upload-dir ' + docs_dir
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def skip_upload_docs?
|
31
|
+
! options.has_key?(:skip_upload_docs) ||
|
32
|
+
(options.has_key?(:skip_upload_docs) && options[:skip_upload_docs])
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.install_setuptools
|
36
|
+
shell 'wget https://bootstrap.pypa.io/ez_setup.py -O - | sudo python'
|
37
|
+
shell 'rm -f setuptools-*.zip'
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.install_twine
|
41
|
+
shell("pip install twine", retry: true) if `which twine`.chop.empty?
|
42
|
+
end
|
43
|
+
|
44
|
+
def initialize(*args)
|
45
|
+
super(*args)
|
46
|
+
self.class.pip 'wheel' if pypi_distributions.to_s.include? 'bdist_wheel'
|
47
|
+
end
|
48
|
+
|
49
|
+
install_setuptools
|
50
|
+
install_twine
|
51
|
+
|
52
|
+
def config
|
53
|
+
{
|
54
|
+
:header => '[distutils]',
|
55
|
+
:servers_line => 'index-servers = pypi',
|
56
|
+
:servers => {
|
57
|
+
'pypi' => [
|
58
|
+
"repository: #{pypi_server}",
|
59
|
+
"username: #{pypi_user}",
|
60
|
+
"password: #{pypi_password}",
|
61
|
+
]
|
62
|
+
}
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
def write_servers(f)
|
67
|
+
config[:servers].each do |key, val|
|
68
|
+
f.puts " " * 4 + key
|
69
|
+
end
|
70
|
+
|
71
|
+
config[:servers].each do |key, val|
|
72
|
+
f.puts "[#{key}]"
|
73
|
+
f.puts val
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def write_config
|
78
|
+
File.open(File.expand_path(PYPIRC_FILE), 'w') do |f|
|
79
|
+
config.each do |key, val|
|
80
|
+
f.puts(val) if val.is_a? String or val.is_a? Array
|
81
|
+
end
|
82
|
+
write_servers(f)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def check_auth
|
87
|
+
error "missing PyPI username" unless pypi_user
|
88
|
+
error "missing PyPI password" unless pypi_password
|
89
|
+
write_config
|
90
|
+
log "Authenticated as #{pypi_user}"
|
91
|
+
end
|
92
|
+
|
93
|
+
def check_app
|
94
|
+
end
|
95
|
+
|
96
|
+
def needs_key?
|
97
|
+
false
|
98
|
+
end
|
99
|
+
|
100
|
+
def push_app
|
101
|
+
context.shell "python setup.py #{pypi_distributions}"
|
102
|
+
context.shell "twine upload -r pypi dist/*"
|
103
|
+
context.shell "rm -rf dist/*"
|
104
|
+
unless skip_upload_docs?
|
105
|
+
log "Uploading documentation (skip with \"skip_upload_docs: true\")"
|
106
|
+
context.shell "python setup.py upload_docs #{pypi_docs_dir_option} -r #{pypi_server}"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
module DPL
|
2
|
+
class Provider
|
3
|
+
class Releases < Provider
|
4
|
+
require 'pathname'
|
5
|
+
|
6
|
+
if RUBY_VERSION >= "2.0.0"
|
7
|
+
requires 'octokit', version: '~> 4.6.2'
|
8
|
+
else
|
9
|
+
requires 'octokit', version: '~> 4.3.0'
|
10
|
+
end
|
11
|
+
|
12
|
+
requires 'mime-types', version: '~> 2.0'
|
13
|
+
|
14
|
+
def travis_tag
|
15
|
+
# Check if $TRAVIS_TAG is unset or set but empty
|
16
|
+
if context.env.fetch('TRAVIS_TAG','') == ''
|
17
|
+
nil
|
18
|
+
else
|
19
|
+
context.env['TRAVIS_TAG']
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_tag
|
24
|
+
if travis_tag.nil?
|
25
|
+
@tag ||= `git describe --tags --exact-match 2>/dev/null`.chomp
|
26
|
+
else
|
27
|
+
@tag ||= travis_tag
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def api
|
32
|
+
if options[:user] and options[:password]
|
33
|
+
@api ||= Octokit::Client.new(:login => options[:user], :password => options[:password])
|
34
|
+
else
|
35
|
+
@api ||= Octokit::Client.new(:access_token => option(:api_key))
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def slug
|
40
|
+
options.fetch(:repo) { context.env['TRAVIS_REPO_SLUG'] }
|
41
|
+
end
|
42
|
+
|
43
|
+
def releases
|
44
|
+
@releases ||= api.releases(slug)
|
45
|
+
end
|
46
|
+
|
47
|
+
def user
|
48
|
+
@user ||= api.user
|
49
|
+
end
|
50
|
+
|
51
|
+
def files
|
52
|
+
if options[:file_glob]
|
53
|
+
Array(options[:file]).map do |glob|
|
54
|
+
Dir.glob(glob)
|
55
|
+
end.flatten
|
56
|
+
else
|
57
|
+
Array(options[:file])
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def needs_key?
|
62
|
+
false
|
63
|
+
end
|
64
|
+
|
65
|
+
def check_app
|
66
|
+
log "Deploying to repo: #{slug}"
|
67
|
+
|
68
|
+
context.shell 'git fetch --tags' if travis_tag.nil?
|
69
|
+
log "Current tag is: #{get_tag}"
|
70
|
+
end
|
71
|
+
|
72
|
+
def setup_auth
|
73
|
+
user.login
|
74
|
+
end
|
75
|
+
|
76
|
+
def check_auth
|
77
|
+
setup_auth
|
78
|
+
|
79
|
+
unless api.scopes.include? 'public_repo' or api.scopes.include? 'repo'
|
80
|
+
raise Error, "Dpl does not have permission to upload assets. Make sure your token contains the repo or public_repo scope."
|
81
|
+
end
|
82
|
+
|
83
|
+
log "Logged in as #{user.name}"
|
84
|
+
end
|
85
|
+
|
86
|
+
def push_app
|
87
|
+
tag_matched = false
|
88
|
+
release_url = nil
|
89
|
+
|
90
|
+
if options[:release_number]
|
91
|
+
tag_matched = true
|
92
|
+
release_url = "https://api.github.com/repos/" + slug + "/releases/" + options[:release_number]
|
93
|
+
else
|
94
|
+
releases.each do |release|
|
95
|
+
if release.tag_name == get_tag
|
96
|
+
release_url = release.rels[:self].href
|
97
|
+
tag_matched = true
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
#If for some reason GitHub hasn't already created a release for the tag, create one
|
103
|
+
if tag_matched == false
|
104
|
+
release_url = api.create_release(slug, get_tag, options.merge({:draft => true})).rels[:self].href
|
105
|
+
end
|
106
|
+
|
107
|
+
files.each do |file|
|
108
|
+
existing_url = nil
|
109
|
+
filename = Pathname.new(file).basename.to_s
|
110
|
+
api.release(release_url).rels[:assets].get.data.each do |existing_file|
|
111
|
+
if existing_file.name == filename
|
112
|
+
existing_url = existing_file.url
|
113
|
+
end
|
114
|
+
end
|
115
|
+
if !existing_url
|
116
|
+
upload_file(file, filename, release_url)
|
117
|
+
elsif existing_url && options[:overwrite]
|
118
|
+
log "#{filename} already exists, overwriting."
|
119
|
+
api.delete_release_asset(existing_url)
|
120
|
+
upload_file(file, filename, release_url)
|
121
|
+
else
|
122
|
+
log "#{filename} already exists, skipping."
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
api.update_release(release_url, {:draft => false}.merge(options))
|
127
|
+
end
|
128
|
+
|
129
|
+
def upload_file(file, filename, release_url)
|
130
|
+
content_type = MIME::Types.type_for(file).first.to_s
|
131
|
+
if content_type.empty?
|
132
|
+
# Specify the default content type, as it is required by GitHub
|
133
|
+
content_type = "application/octet-stream"
|
134
|
+
end
|
135
|
+
api.upload_asset(release_url, file, {:name => filename, :content_type => content_type})
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module DPL
|
2
|
+
class Provider
|
3
|
+
class RubyGems < Provider
|
4
|
+
requires 'gems', version: '>= 0.8.3'
|
5
|
+
|
6
|
+
def setup_auth
|
7
|
+
::Gems.key = option(:api_key) if options[:api_key]
|
8
|
+
::Gems.username = option(:user) unless options[:api_key]
|
9
|
+
::Gems.password = option(:password) unless options[:api_key]
|
10
|
+
end
|
11
|
+
|
12
|
+
def needs_key?
|
13
|
+
false
|
14
|
+
end
|
15
|
+
|
16
|
+
def setup_gem
|
17
|
+
options[:gem] ||= options[:app]
|
18
|
+
end
|
19
|
+
|
20
|
+
def gemspec
|
21
|
+
options[:gemspec].gsub('.gemspec', '') if options[:gemspec]
|
22
|
+
end
|
23
|
+
|
24
|
+
def check_app
|
25
|
+
setup_auth
|
26
|
+
setup_gem
|
27
|
+
log "Looking up gem #{options[:gem]}"
|
28
|
+
info = ::Gems.info(options[:gem])
|
29
|
+
log "Found gem #{info['name']}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def check_auth
|
33
|
+
setup_auth
|
34
|
+
log "Authenticated with username #{::Gems.username}" if ::Gems.username
|
35
|
+
end
|
36
|
+
|
37
|
+
def push_app
|
38
|
+
setup_auth
|
39
|
+
setup_gem
|
40
|
+
context.shell "gem build #{gemspec || option(:gem)}.gemspec"
|
41
|
+
Dir.glob("#{gemspec || option(:gem)}-*.gem") do |f|
|
42
|
+
if options[:host]
|
43
|
+
log ::Gems.push(File.new(f), options[:host])
|
44
|
+
else
|
45
|
+
log ::Gems.push(File.new f)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module DPL
|
4
|
+
class Provider
|
5
|
+
class S3 < Provider
|
6
|
+
requires 'aws-sdk', version: '~> 2.0'
|
7
|
+
requires 'mime-types', version: '~> 2.0'
|
8
|
+
|
9
|
+
def api
|
10
|
+
@api ||= ::Aws::S3::Resource.new(s3_options)
|
11
|
+
end
|
12
|
+
|
13
|
+
def needs_key?
|
14
|
+
false
|
15
|
+
end
|
16
|
+
|
17
|
+
def check_app
|
18
|
+
log 'Warning: The endpoint option is no longer used and can be removed.' if options[:endpoint]
|
19
|
+
end
|
20
|
+
|
21
|
+
def access_key_id
|
22
|
+
options[:access_key_id] || context.env['AWS_ACCESS_KEY_ID'] || raise(Error, "missing access_key_id")
|
23
|
+
end
|
24
|
+
|
25
|
+
def secret_access_key
|
26
|
+
options[:secret_access_key] || context.env['AWS_SECRET_ACCESS_KEY'] || raise(Error, "missing secret_access_key")
|
27
|
+
end
|
28
|
+
|
29
|
+
def s3_options
|
30
|
+
{
|
31
|
+
region: options[:region] || 'us-east-1',
|
32
|
+
credentials: ::Aws::Credentials.new(access_key_id, secret_access_key)
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
def check_auth
|
37
|
+
log "Logging in with Access Key: #{access_key_id[-4..-1].rjust(20, '*')}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def upload_path(filename)
|
41
|
+
[options[:upload_dir], filename].compact.join("/")
|
42
|
+
end
|
43
|
+
|
44
|
+
def push_app
|
45
|
+
glob_args = ["**/*"]
|
46
|
+
glob_args << File::FNM_DOTMATCH if options[:dot_match]
|
47
|
+
Dir.chdir(options.fetch(:local_dir, Dir.pwd)) do
|
48
|
+
Dir.glob(*glob_args) do |filename|
|
49
|
+
opts = content_data_for(filename)
|
50
|
+
opts[:cache_control] = get_option_value_by_filename(options[:cache_control], filename) if options[:cache_control]
|
51
|
+
opts[:acl] = options[:acl].gsub(/_/, '-') if options[:acl]
|
52
|
+
opts[:expires] = get_option_value_by_filename(options[:expires], filename) if options[:expires]
|
53
|
+
opts[:storage_class] = options[:storage_class] if options[:storage_class]
|
54
|
+
opts[:server_side_encryption] = "AES256" if options[:server_side_encryption]
|
55
|
+
unless File.directory?(filename)
|
56
|
+
log "uploading #{filename.inspect} with #{opts.inspect}"
|
57
|
+
result = api.bucket(option(:bucket)).object(upload_path(filename)).upload_file(filename, opts)
|
58
|
+
warn "error while uploading #{filename.inspect}" unless result
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
if suffix = options[:index_document_suffix]
|
64
|
+
api.bucket(option(:bucket)).website.put(
|
65
|
+
website_configuration: {
|
66
|
+
index_document: {
|
67
|
+
suffix: suffix
|
68
|
+
}
|
69
|
+
}
|
70
|
+
)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def deploy
|
75
|
+
super
|
76
|
+
rescue ::Aws::S3::Errors::InvalidAccessKeyId
|
77
|
+
raise Error, "Invalid S3 Access Key Id, Stopping Deploy"
|
78
|
+
rescue ::Aws::S3::Errors::ChecksumError
|
79
|
+
raise Error, "Aws Secret Key does not match Access Key Id, Stopping Deploy"
|
80
|
+
rescue ::Aws::S3::Errors::AccessDenied
|
81
|
+
raise Error, "Oops, It looks like you tried to write to a bucket that isn't yours or doesn't exist yet. Please create the bucket before trying to write to it."
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
def content_data_for(path)
|
86
|
+
content_data = {}
|
87
|
+
content_type = MIME::Types.type_for(path).first
|
88
|
+
content_data[:content_type] = content_type.to_s
|
89
|
+
|
90
|
+
encoding = encoding_for(path)
|
91
|
+
if detect_encoding?
|
92
|
+
content_data[:content_encoding] = encoding if encoding
|
93
|
+
end
|
94
|
+
|
95
|
+
if encoding == 'text' && default_text_charset?
|
96
|
+
content_data[:content_type] = "#{content_data[:content_type]}; charset=#{default_text_charset}"
|
97
|
+
end
|
98
|
+
|
99
|
+
return content_data
|
100
|
+
end
|
101
|
+
|
102
|
+
def get_option_value_by_filename(option_values, filename)
|
103
|
+
return option_values if !option_values.kind_of?(Array)
|
104
|
+
preferred_value = nil
|
105
|
+
hashes = option_values.select {|value| value.kind_of?(Hash) }
|
106
|
+
hashes.each do |hash|
|
107
|
+
hash.each do |value, patterns|
|
108
|
+
unless patterns.kind_of?(Array)
|
109
|
+
patterns = [patterns]
|
110
|
+
end
|
111
|
+
patterns.each do |pattern|
|
112
|
+
if File.fnmatch?(pattern, filename)
|
113
|
+
preferred_value = value
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
preferred_value = option_values.select {|value| value.kind_of?(String) }.last if preferred_value.nil?
|
119
|
+
return preferred_value
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|