dpl-connect 1.8.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|