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.
Files changed (105) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +8 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +36 -0
  6. data/Gemfile +100 -0
  7. data/LICENSE +22 -0
  8. data/README.md +934 -0
  9. data/Rakefile +1 -0
  10. data/TESTING.md +29 -0
  11. data/bin/dpl +5 -0
  12. data/dpl.gemspec +32 -0
  13. data/lib/dpl/cli.rb +66 -0
  14. data/lib/dpl/error.rb +3 -0
  15. data/lib/dpl/provider.rb +264 -0
  16. data/lib/dpl/provider/anynines.rb +13 -0
  17. data/lib/dpl/provider/appfog.rb +21 -0
  18. data/lib/dpl/provider/atlas.rb +108 -0
  19. data/lib/dpl/provider/azure_webapps.rb +48 -0
  20. data/lib/dpl/provider/bintray.rb +509 -0
  21. data/lib/dpl/provider/bitballoon.rb +22 -0
  22. data/lib/dpl/provider/bluemix_cloud_foundry.rb +23 -0
  23. data/lib/dpl/provider/boxfuse.rb +57 -0
  24. data/lib/dpl/provider/catalyze.rb +49 -0
  25. data/lib/dpl/provider/chef_supermarket.rb +85 -0
  26. data/lib/dpl/provider/cloud66.rb +38 -0
  27. data/lib/dpl/provider/cloud_files.rb +38 -0
  28. data/lib/dpl/provider/cloud_foundry.rb +43 -0
  29. data/lib/dpl/provider/code_deploy.rb +123 -0
  30. data/lib/dpl/provider/deis.rb +119 -0
  31. data/lib/dpl/provider/divshot.rb +23 -0
  32. data/lib/dpl/provider/elastic_beanstalk.rb +195 -0
  33. data/lib/dpl/provider/engine_yard.rb +90 -0
  34. data/lib/dpl/provider/firebase.rb +27 -0
  35. data/lib/dpl/provider/gae.rb +97 -0
  36. data/lib/dpl/provider/gcs.rb +59 -0
  37. data/lib/dpl/provider/hackage.rb +29 -0
  38. data/lib/dpl/provider/heroku.rb +18 -0
  39. data/lib/dpl/provider/heroku/api.rb +98 -0
  40. data/lib/dpl/provider/heroku/generic.rb +94 -0
  41. data/lib/dpl/provider/heroku/git.rb +28 -0
  42. data/lib/dpl/provider/lambda.rb +236 -0
  43. data/lib/dpl/provider/launchpad.rb +48 -0
  44. data/lib/dpl/provider/modulus.rb +23 -0
  45. data/lib/dpl/provider/npm.rb +64 -0
  46. data/lib/dpl/provider/openshift.rb +59 -0
  47. data/lib/dpl/provider/ops_works.rb +132 -0
  48. data/lib/dpl/provider/packagecloud.rb +144 -0
  49. data/lib/dpl/provider/pages.rb +79 -0
  50. data/lib/dpl/provider/puppet_forge.rb +43 -0
  51. data/lib/dpl/provider/pypi.rb +111 -0
  52. data/lib/dpl/provider/releases.rb +139 -0
  53. data/lib/dpl/provider/rubygems.rb +51 -0
  54. data/lib/dpl/provider/s3.rb +123 -0
  55. data/lib/dpl/provider/scalingo.rb +97 -0
  56. data/lib/dpl/provider/script.rb +29 -0
  57. data/lib/dpl/provider/surge.rb +33 -0
  58. data/lib/dpl/provider/testfairy.rb +190 -0
  59. data/lib/dpl/provider/transifex.rb +45 -0
  60. data/lib/dpl/version.rb +3 -0
  61. data/notes/engine_yard.md +1 -0
  62. data/notes/heroku.md +3 -0
  63. data/spec/cli_spec.rb +36 -0
  64. data/spec/provider/anynines_spec.rb +20 -0
  65. data/spec/provider/appfog_spec.rb +35 -0
  66. data/spec/provider/atlas_spec.rb +99 -0
  67. data/spec/provider/azure_webapps_spec.rb +95 -0
  68. data/spec/provider/bintray_spec.rb +259 -0
  69. data/spec/provider/bitballoon_spec.rb +32 -0
  70. data/spec/provider/bluemixcloudfoundry_spec.rb +23 -0
  71. data/spec/provider/boxfuse_spec.rb +16 -0
  72. data/spec/provider/catalyze_spec.rb +39 -0
  73. data/spec/provider/chef_supermarket_spec.rb +51 -0
  74. data/spec/provider/cloud66_spec.rb +44 -0
  75. data/spec/provider/cloud_files_spec.rb +88 -0
  76. data/spec/provider/cloudfoundry_spec.rb +71 -0
  77. data/spec/provider/code_deploy_spec.rb +360 -0
  78. data/spec/provider/deis_spec.rb +116 -0
  79. data/spec/provider/divshot_spec.rb +28 -0
  80. data/spec/provider/elastic_beanstalk_spec.rb +209 -0
  81. data/spec/provider/firebase_spec.rb +40 -0
  82. data/spec/provider/gae_spec.rb +26 -0
  83. data/spec/provider/gcs_spec.rb +115 -0
  84. data/spec/provider/hackage_spec.rb +47 -0
  85. data/spec/provider/heroku_spec.rb +357 -0
  86. data/spec/provider/lambda_spec.rb +432 -0
  87. data/spec/provider/launchpad_spec.rb +33 -0
  88. data/spec/provider/modulus_spec.rb +29 -0
  89. data/spec/provider/npm_spec.rb +95 -0
  90. data/spec/provider/openshift_spec.rb +91 -0
  91. data/spec/provider/ops_works_spec.rb +127 -0
  92. data/spec/provider/packagecloud_spec.rb +56 -0
  93. data/spec/provider/puppet_forge_spec.rb +60 -0
  94. data/spec/provider/pypi_spec.rb +103 -0
  95. data/spec/provider/releases_spec.rb +303 -0
  96. data/spec/provider/rubygems_spec.rb +106 -0
  97. data/spec/provider/s3_spec.rb +174 -0
  98. data/spec/provider/scalingo_spec.rb +64 -0
  99. data/spec/provider/script_spec.rb +26 -0
  100. data/spec/provider/surge_spec.rb +15 -0
  101. data/spec/provider/testfairy_spec.rb +86 -0
  102. data/spec/provider/transifex_spec.rb +110 -0
  103. data/spec/provider_spec.rb +210 -0
  104. data/spec/spec_helper.rb +20 -0
  105. metadata +279 -0
@@ -0,0 +1,97 @@
1
+ module DPL
2
+ class Provider
3
+ class GAE < Provider
4
+ experimental 'Google App Engine'
5
+
6
+ BASE='https://dl.google.com/dl/cloudsdk/channels/rapid/'
7
+ NAME='google-cloud-sdk'
8
+ EXT='.tar.gz'
9
+ INSTALL='~'
10
+ BOOTSTRAP="#{INSTALL}/#{NAME}/bin/bootstrapping/install.py"
11
+ GCLOUD="#{INSTALL}/#{NAME}/bin/gcloud"
12
+
13
+ def with_python_2_7(cmd)
14
+ cmd.gsub!(/'/, "'\\\\''")
15
+ context.shell("bash -c 'source #{context.env['HOME']}/virtualenv/python2.7/bin/activate; #{cmd}'")
16
+ end
17
+
18
+ def install_deploy_dependencies
19
+ if File.exists? GCLOUD
20
+ return
21
+ end
22
+
23
+ $stderr.puts 'Python 2.7 Version'
24
+
25
+ unless with_python_2_7("python -c 'import sys; print(sys.version)'")
26
+ error 'Could not use python2.7'
27
+ end
28
+
29
+ $stderr.puts 'Downloading Google Cloud SDK ...'
30
+
31
+ unless context.shell("curl -L #{BASE + NAME + EXT} | gzip -d | tar -x -C #{INSTALL}")
32
+ error 'Could not download Google Cloud SDK.'
33
+ end
34
+
35
+ $stderr.puts 'Bootstrapping Google Cloud SDK ...'
36
+
37
+ unless with_python_2_7("#{BOOTSTRAP} --usage-reporting=false --command-completion=false --path-update=false")
38
+ error 'Could not bootstrap Google Cloud SDK.'
39
+ end
40
+ end
41
+
42
+ def needs_key?
43
+ false
44
+ end
45
+
46
+ def check_auth
47
+ unless with_python_2_7("#{GCLOUD} -q auth activate-service-account --key-file #{keyfile}")
48
+ error 'Authentication failed.'
49
+ end
50
+ end
51
+
52
+ def keyfile
53
+ options[:keyfile] || context.env['GOOGLECLOUDKEYFILE'] || 'service-account.json'
54
+ end
55
+
56
+ def project
57
+ options[:project] || context.env['GOOGLECLOUDPROJECT'] || context.env['CLOUDSDK_CORE_PROJECT'] || File.dirname(context.env['TRAVIS_REPO_SLUG'] || '')
58
+ end
59
+
60
+ def version
61
+ options[:version]
62
+ end
63
+
64
+ def config
65
+ options[:config] || 'app.yaml'
66
+ end
67
+
68
+ def no_promote
69
+ options[:no_promote]
70
+ end
71
+
72
+ def verbosity
73
+ options[:verbosity] || 'warning'
74
+ end
75
+
76
+ def no_stop_previous_version
77
+ options[:no_stop_previous_version]
78
+ end
79
+
80
+ def push_app
81
+ command = GCLOUD
82
+ command << ' --quiet'
83
+ command << " --verbosity \"#{verbosity}\""
84
+ command << " --project \"#{project}\""
85
+ command << " app deploy \"#{config}\""
86
+ command << " --version \"#{version}\"" unless version.to_s.empty?
87
+ command << " --#{no_promote ? 'no-' : ''}promote"
88
+ command << ' --no-stop-previous-version' unless no_stop_previous_version.to_s.empty?
89
+ unless with_python_2_7(command)
90
+ log 'Deployment failed.'
91
+ context.shell('find $HOME/.config/gcloud/logs -type f -print -exec cat {} \;')
92
+ error ''
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,59 @@
1
+ require 'kconv'
2
+
3
+ module DPL
4
+ class Provider
5
+ class GCS < Provider
6
+ requires 'gstore'
7
+ requires 'mime-types', version: '~> 2.0'
8
+
9
+ def needs_key?
10
+ false
11
+ end
12
+
13
+ def client
14
+ @client ||= GStore::Client.new(
15
+ :access_key => option(:access_key_id),
16
+ :secret_key => option(:secret_access_key)
17
+ )
18
+ end
19
+
20
+ def check_auth
21
+ log "Logging in with Access Key: #{option(:access_key_id)[-4..-1].rjust(20, '*')}"
22
+ end
23
+
24
+ def upload_path(filename)
25
+ [options[:upload_dir], filename].compact.join("/")
26
+ end
27
+
28
+ def push_app
29
+ glob_args = ["**/*"]
30
+ glob_args << File::FNM_DOTMATCH if options[:dot_match]
31
+ Dir.chdir(options.fetch(:local_dir, Dir.pwd)) do
32
+ Dir.glob(*glob_args) do |filename|
33
+ next if File.directory?(filename)
34
+ content_type = MIME::Types.type_for(filename).first.to_s
35
+ opts = { :"Content-Type" => content_type }.merge(encoding_option_for(filename))
36
+ opts["Cache-Control"] = options[:cache_control] if options[:cache_control]
37
+ opts["x-goog-acl"] = options[:acl] if options[:acl]
38
+
39
+ client.put_object(
40
+ option(:bucket),
41
+ upload_path(filename),
42
+ { :data => File.read(filename), :headers => opts }
43
+ )
44
+ end
45
+ end
46
+ end
47
+
48
+ private
49
+ def encoding_option_for(path)
50
+ if detect_encoding? && encoding_for(path)
51
+ {"Content-Encoding" => encoding_for(path)}
52
+ else
53
+ {}
54
+ end
55
+ end
56
+
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,29 @@
1
+ module DPL
2
+ class Provider
3
+ class Hackage < Provider
4
+ apt_get 'cabal', 'cabal-install'
5
+
6
+ def check_auth
7
+ unless option(:username) and option(:password)
8
+ raise Error, "must supply username and password"
9
+ end
10
+ end
11
+
12
+ def check_app
13
+ context.shell "cabal check" or raise Error, "cabal check failed"
14
+ end
15
+
16
+ def needs_key?
17
+ false
18
+ end
19
+
20
+ def push_app
21
+ context.shell "cabal sdist" or raise Error, "cabal sdist failed"
22
+ Dir.glob("dist/*.tar.gz") do |tar|
23
+ context.shell "cabal upload --username=#{option(:username)} --password=#{option(:password)} #{tar}"
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+
@@ -0,0 +1,18 @@
1
+ module DPL
2
+ class Provider
3
+ module Heroku
4
+ autoload :API, 'dpl/provider/heroku/api'
5
+ autoload :Generic, 'dpl/provider/heroku/generic'
6
+ autoload :Git, 'dpl/provider/heroku/git'
7
+
8
+ extend self
9
+
10
+ def new(context, options)
11
+ strategy = options[:strategy] || 'api'
12
+ constant = constants.detect { |c| c.to_s.downcase == strategy.downcase.gsub(/\W/, '') }
13
+ raise Error, 'unknown strategy %p' % strategy unless constant and constant != Generic
14
+ const_get(constant).new(context, options)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,98 @@
1
+ require 'json'
2
+ require 'shellwords'
3
+ require 'logger'
4
+
5
+ module DPL
6
+ class Provider
7
+ module Heroku
8
+ class API < Generic
9
+ attr_reader :build_id
10
+ requires 'faraday'
11
+ requires 'rendezvous'
12
+
13
+ def push_app
14
+ pack_archive
15
+ upload_archive
16
+ trigger_build
17
+ verify_build
18
+ end
19
+
20
+ def archive_file
21
+ Shellwords.escape("#{context.env['HOME']}/.dpl.#{option(:app)}.tgz")
22
+ end
23
+
24
+ def pack_archive
25
+ log "creating application archive"
26
+ context.shell "tar -zcf #{archive_file} --exclude .git ."
27
+ end
28
+
29
+ def upload_archive
30
+ log "uploading application archive"
31
+ context.shell "curl #{Shellwords.escape(put_url)} -X PUT -H 'Content-Type:' -H 'Accept: application/vnd.heroku+json; version=3' --data-binary @#{archive_file}"
32
+ end
33
+
34
+ def trigger_build
35
+ log "triggering new deployment"
36
+ response = faraday.post("/apps/#{option(:app)}/builds") do |req|
37
+ req.headers['Content-Type'] = 'application/json'
38
+ req.body = {
39
+ "source_blob" => {
40
+ "url" => get_url,
41
+ "version" => version
42
+ }
43
+ }.to_json
44
+ end
45
+
46
+ if response.success?
47
+ @build_id = JSON.parse(response.body)['id']
48
+ output_stream_url = JSON.parse(response.body)['output_stream_url']
49
+ context.shell "curl #{Shellwords.escape(output_stream_url)} -H 'Accept: application/vnd.heroku+json; version=3'"
50
+ else
51
+ handle_error_response(response)
52
+ end
53
+ end
54
+
55
+ def verify_build
56
+ loop do
57
+ response = faraday.get("/apps/#{option(:app)}/builds/#{build_id}/result")
58
+ exit_code = JSON.parse(response.body)['exit_code']
59
+ if exit_code.nil?
60
+ log "heroku build still pending"
61
+ sleep 5
62
+ next
63
+ elsif exit_code == 0
64
+ break
65
+ else
66
+ error "deploy failed, build exited with code #{exit_code}"
67
+ end
68
+ end
69
+ end
70
+
71
+ def get_url
72
+ source_blob.fetch("get_url")
73
+ end
74
+
75
+ def put_url
76
+ source_blob.fetch("put_url")
77
+ end
78
+
79
+ def source_blob
80
+ return @source_blob if @source_blob
81
+
82
+ response = faraday.post('/sources')
83
+
84
+ if response.success?
85
+ @source_blob = JSON.parse(response.body)["source_blob"]
86
+ else
87
+ handle_error_response(response)
88
+ end
89
+ end
90
+
91
+ def version
92
+ @version ||= options[:version] || context.env['TRAVIS_COMMIT'] || `git rev-parse HEAD`.strip
93
+ end
94
+
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,94 @@
1
+ require 'json'
2
+
3
+ module DPL
4
+ class Provider
5
+ module Heroku
6
+ class Generic < Provider
7
+ requires 'rendezvous'
8
+ requires 'faraday'
9
+
10
+ attr_reader :app, :user
11
+
12
+ def needs_key?
13
+ false
14
+ end
15
+
16
+ def faraday
17
+ return @conn if @conn
18
+ headers = { "Accept" => "application/vnd.heroku+json; version=3" }
19
+
20
+ if options[:user] and options[:password]
21
+ # no-op
22
+ else
23
+ headers.merge!({ "Authorization" => "Bearer #{option(:api_key)}" })
24
+ end
25
+
26
+ @conn = Faraday.new( url: 'https://api.heroku.com', headers: headers ) do |faraday|
27
+ if options[:user] and options[:password]
28
+ faraday.basic_auth(options[:user], options[:password])
29
+ end
30
+ if log_level = options[:log_level]
31
+ logger = Logger.new($stderr)
32
+ logger.level = Logger.const_get(log_level.upcase)
33
+
34
+ faraday.response :logger, logger do | logger |
35
+ logger.filter(/(.*Authorization: ).*/,'\1[REDACTED]')
36
+ end
37
+ end
38
+ faraday.adapter Faraday.default_adapter
39
+ end
40
+ end
41
+
42
+ def check_auth
43
+ response = faraday.get('/account')
44
+
45
+ if response.success?
46
+ email = JSON.parse(response.body)["email"]
47
+ @user = email
48
+ log "authentication succeeded"
49
+ else
50
+ handle_error_response(response)
51
+ end
52
+ end
53
+
54
+ def handle_error_response(response)
55
+ error_response = JSON.parse(response.body)
56
+ error "API request failed.\nMessage: #{error_response["message"]}\nReference: #{error_response["url"]}"
57
+ end
58
+
59
+ def check_app
60
+ log "checking for app #{option(:app)}"
61
+ response = faraday.get("/apps/#{option(:app)}")
62
+ if response.success?
63
+ @app = JSON.parse(response.body)
64
+ log "found app #{@app["name"]}"
65
+ else
66
+ handle_error_response(response)
67
+ end
68
+ end
69
+
70
+ def restart
71
+ response = faraday.delete "/apps/#{option(:app)}/dynos" do |req|
72
+ req.headers['Content-Type'] = 'application/json'
73
+ end
74
+ unless response.success?
75
+ handle_error_response(response)
76
+ end
77
+ end
78
+
79
+ def run(command)
80
+ response = faraday.post "/apps/#{option(:app)}/dynos" do |req|
81
+ req.headers['Content-Type'] = 'application/json'
82
+ req.body = {"command" => command, "attach" => true}.to_json
83
+ end
84
+ if response.success?
85
+ rendezvous_url = JSON.parse(response.body)["attach_url"]
86
+ Rendezvous.start(url: rendezvous_url)
87
+ else
88
+ handle_error_response(response)
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,28 @@
1
+ module DPL
2
+ class Provider
3
+ module Heroku
4
+ class Git < Generic
5
+ requires 'netrc'
6
+
7
+ def git_url
8
+ "https://git.heroku.com/#{option(:app)}.git"
9
+ end
10
+
11
+ def push_app
12
+ git_remote = options[:git] || git_url
13
+ write_netrc if git_remote.start_with?("https://")
14
+ log "$ git fetch origin $TRAVIS_BRANCH --unshallow"
15
+ context.shell "git fetch origin $TRAVIS_BRANCH --unshallow"
16
+ log "$ git push #{git_remote} HEAD:refs/heads/master -f"
17
+ context.shell "git push #{git_remote} HEAD:refs/heads/master -f"
18
+ end
19
+
20
+ def write_netrc
21
+ n = Netrc.read
22
+ n['git.heroku.com'] = [user, option(:api_key)]
23
+ n.save
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,236 @@
1
+ require 'json'
2
+ require 'tempfile'
3
+ require 'fileutils'
4
+
5
+ module DPL
6
+ class Provider
7
+ class Lambda < Provider
8
+ requires 'aws-sdk', version: '~> 2.0'
9
+ requires 'rubyzip', load: 'zip'
10
+
11
+ def lambda
12
+ @lambda ||= ::Aws::Lambda::Client.new(lambda_options)
13
+ end
14
+
15
+ def lambda_options
16
+ {
17
+ region: options[:region] || 'us-east-1',
18
+ credentials: ::Aws::Credentials.new(option(:access_key_id), option(:secret_access_key))
19
+ }
20
+ end
21
+
22
+ def push_app
23
+
24
+ # The original LambdaPreview client supported create/update in one call
25
+ # To keep compatibility we try to fetch the function and then decide
26
+ # whether to update the code or create a new function
27
+
28
+ function_name = options[:name] || option(:function_name)
29
+
30
+ begin
31
+ response = lambda.get_function({function_name: function_name})
32
+
33
+ log "Function #{function_name} already exists, updating."
34
+
35
+ # Options defined at
36
+ # https://docs.aws.amazon.com/sdkforruby/api/Aws/Lambda/Client.html#update_function_configuration-instance_method
37
+ response = lambda.update_function_configuration({
38
+ function_name: function_name,
39
+ description: options[:description] || default_description,
40
+ timeout: options[:timeout] || default_timeout,
41
+ memory_size: options[:memory_size] || default_memory_size,
42
+ role: option(:role),
43
+ handler: handler,
44
+ runtime: options[:runtime] || default_runtime,
45
+ vpc_config: vpc_config,
46
+ environment: environment_variables,
47
+ dead_letter_config: dead_letter_arn,
48
+ kms_key_arn: options[:kms_key_arn] || default_kms_key_arn,
49
+ tracing_config: tracing_mode
50
+ })
51
+
52
+ log "Updated configuration of function: #{response.function_name}."
53
+
54
+ if function_tags
55
+ log "Add tags to function #{response.function_name}."
56
+ response = lambda.tag_resource({
57
+ resource: response.function_arn,
58
+ tags: function_tags
59
+ })
60
+ end
61
+
62
+ # Options defined at
63
+ # https://docs.aws.amazon.com/sdkforruby/api/Aws/Lambda/Client.html#update_function_code-instance_method
64
+ response = lambda.update_function_code({
65
+ function_name: options[:name] || option(:function_name),
66
+ zip_file: function_zip,
67
+ publish: publish
68
+ })
69
+
70
+ log "Updated code of function: #{response.function_name}."
71
+ rescue ::Aws::Lambda::Errors::ResourceNotFoundException
72
+ log "Function #{function_name} does not exist, creating."
73
+ # Options defined at
74
+ # https://docs.aws.amazon.com/lambda/latest/dg/API_CreateFunction.html
75
+ response = lambda.create_function({
76
+ function_name: options[:name] || option(:function_name),
77
+ description: options[:description] || default_description,
78
+ timeout: options[:timeout] || default_timeout,
79
+ memory_size: options[:memory_size] || default_memory_size,
80
+ role: option(:role),
81
+ handler: handler,
82
+ code: {
83
+ zip_file: function_zip,
84
+ },
85
+ runtime: options[:runtime] || default_runtime,
86
+ publish: publish,
87
+ vpc_config: vpc_config,
88
+ environment: environment_variables,
89
+ dead_letter_config: dead_letter_arn,
90
+ kms_key_arn: options[:kms_key_arn] || default_kms_key_arn,
91
+ tracing_config: tracing_mode,
92
+ tags: function_tags
93
+ })
94
+
95
+ log "Created lambda: #{response.function_name}."
96
+ end
97
+ rescue ::Aws::Lambda::Errors::ServiceException => exception
98
+ error(exception.message)
99
+ rescue ::Aws::Lambda::Errors::InvalidParameterValueException => exception
100
+ error(exception.message)
101
+ rescue ::Aws::Lambda::Errors::ResourceNotFoundException => exception
102
+ error(exception.message)
103
+ end
104
+
105
+ def handler
106
+ module_name = options[:module_name] || default_module_name
107
+ handler_name = option(:handler_name)
108
+
109
+ "#{module_name}.#{handler_name}"
110
+ end
111
+
112
+ def function_zip
113
+ target_zip_path = File.absolute_path(options[:zip] || Dir.pwd)
114
+ dest_file_path = output_file_path
115
+
116
+ if File.directory?(target_zip_path)
117
+ zip_directory(dest_file_path, target_zip_path)
118
+ elsif File.file?(target_zip_path)
119
+ zip_file(dest_file_path, target_zip_path)
120
+ else
121
+ error('Invalid zip option. If set, must be path to directory, js file, or a zip file.')
122
+ end
123
+
124
+ File.new(dest_file_path)
125
+ end
126
+
127
+ def zip_file(dest_file_path, target_file_path)
128
+ if File.extname(target_file_path) == '.zip'
129
+ # Just copy it to the destination right away, since it is already a zip.
130
+ FileUtils.cp(target_file_path, dest_file_path)
131
+ dest_file_path
132
+ else
133
+ # Zip up the file.
134
+ src_directory_path = File.dirname(target_file_path)
135
+ files = [ target_file_path ]
136
+
137
+ create_zip(dest_file_path, src_directory_path, files)
138
+ end
139
+ end
140
+
141
+ def zip_directory(dest_file_path, target_directory_path)
142
+ files = Dir[File.join(target_directory_path, '**', '**')]
143
+ create_zip(dest_file_path, target_directory_path, files)
144
+ end
145
+
146
+ def create_zip(dest_file_path, src_directory_path, files)
147
+ Zip::File.open(dest_file_path, Zip::File::CREATE) do |zipfile|
148
+ files.each do |file|
149
+ zipfile.add(file.sub(src_directory_path + File::SEPARATOR, ''), file)
150
+ end
151
+ end
152
+
153
+ dest_file_path
154
+ end
155
+
156
+ def needs_key?
157
+ false
158
+ end
159
+
160
+ def check_auth
161
+ log "Using Access Key: #{option(:access_key_id)[-4..-1].rjust(20, '*')}"
162
+ end
163
+
164
+ def output_file_path
165
+ @output_file_path ||= '/tmp/' + random_chars(8) + '-lambda.zip'
166
+ end
167
+
168
+ def vpc_config
169
+ options[:subnet_ids] && options[:security_group_ids] ? { :subnet_ids => Array(options[:subnet_ids]), :security_group_ids => Array(options[:security_group_ids]) } : nil
170
+ end
171
+
172
+ def environment_variables
173
+ options[:environment_variables] ? { :variables => split_string_array_to_hash(options[:environment_variables]) } : nil
174
+ end
175
+
176
+ def dead_letter_arn
177
+ options[:dead_letter_arn] ? { :target_arn => options[:dead_letter_arn]} : nil
178
+ end
179
+
180
+ def tracing_mode
181
+ options[:tracing_mode] ? { :mode => options[:tracing_mode]} : nil
182
+ end
183
+
184
+ def default_kms_key_arn
185
+ nil
186
+ end
187
+
188
+ def function_tags
189
+ options[:function_tags] ? split_string_array_to_hash(options[:function_tags]) : nil
190
+ end
191
+
192
+ def default_runtime
193
+ 'nodejs'
194
+ end
195
+
196
+ def default_timeout
197
+ 3 # seconds
198
+ end
199
+
200
+ def default_description
201
+ "Deploy build #{context.env['TRAVIS_BUILD_NUMBER']} to AWS Lambda via Travis CI"
202
+ end
203
+
204
+ def default_memory_size
205
+ 128
206
+ end
207
+
208
+ def default_module_name
209
+ 'index'
210
+ end
211
+
212
+ def publish
213
+ !!options[:publish]
214
+ end
215
+
216
+ def split_string_array_to_hash(arr, delimiter="=")
217
+ variables = {}
218
+ Array(arr).map do |val|
219
+ keyval = val.split(delimiter)
220
+ variables[keyval[0]] = keyval[1]
221
+ end
222
+ variables
223
+ end
224
+
225
+ def random_chars(count=8)
226
+ (36**(count-1) + rand(36**count - 36**(count-1))).to_s(36)
227
+ end
228
+
229
+ def cleanup
230
+ end
231
+
232
+ def uncleanup
233
+ end
234
+ end
235
+ end
236
+ end