dpl-connect 1.8.43

Sign up to get free protection for your applications and to get access to all the features.
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,119 @@
1
+ module DPL
2
+ class Provider
3
+ class Deis < Provider
4
+
5
+ def install_deploy_dependencies
6
+ install_url = determine_install_url
7
+ context.shell "curl -sSL #{install_url} | bash -x -s #{option(:cli_version)}"
8
+ end
9
+
10
+ #Default to installing the default v1 client. Otherwise determine if this is a v2 client
11
+ def determine_install_url
12
+ return "https://raw.githubusercontent.com/teamhephy/workflow-cli/master/install-v2.sh"
13
+ end
14
+
15
+ def needs_key?
16
+ true
17
+ end
18
+
19
+ def check_auth
20
+ unless context.shell "./deis login #{option(:controller)}" \
21
+ " --username=#{option(:username)}" \
22
+ " --password=#{option(:password)}"
23
+ error 'Login failed.'
24
+ end
25
+ end
26
+
27
+ def check_app
28
+ unless context.shell "./deis apps:info --app=#{option(:app)}"
29
+ error 'Application could not be verified.'
30
+ end
31
+ end
32
+
33
+ def setup_key(file)
34
+ unless context.shell "./deis keys:add #{file}"
35
+ error 'Adding keys failed.'
36
+ end
37
+ end
38
+
39
+ def setup_git_ssh(path, key_path)
40
+ key_path = File.expand_path(key_path)
41
+ path = File.expand_path(path)
42
+
43
+ File.open(path, 'w') do |file|
44
+ file.write "#!/bin/sh\n"
45
+ file.write "exec ssh #{verbose_flag} -o StrictHostKeychecking=no -o CheckHostIP=no -o UserKnownHostsFile=/dev/null -i #{key_path} \"$@\"\n"
46
+ end
47
+
48
+ chmod(0740, path)
49
+ context.env['GIT_SSH'] = path
50
+
51
+ wait_for_git_access
52
+ end
53
+
54
+ def wait_for_git_access()
55
+ retry_count=0
56
+ max_retries=30
57
+
58
+ #Get the deis git remote host and port
59
+ remote_uri=repository_url.split("ssh://")[1].split("/")[0]
60
+ remote_host, remote_port = remote_uri.split(":")
61
+ puts "Git remote is #{remote_host} at port #{remote_port}"
62
+
63
+ #Try and connect to the github remote via ssh.
64
+ while retry_count < max_retries
65
+ puts "Waiting for ssh key to propagate..."
66
+ if context.shell "#{context.env['GIT_SSH']} #{remote_host} -p #{remote_port} 2>&1 | grep -c 'PTY allocation request failed' > /dev/null"
67
+ puts "SSH connection established."
68
+ break
69
+ end
70
+ retry_count += 1
71
+ sleep(1)
72
+ end
73
+ end
74
+
75
+ def remove_key
76
+ unless context.shell "./deis keys:remove #{option(:key_name)}"
77
+ error 'Removing keys failed.'
78
+ end
79
+ end
80
+
81
+ def repository_url
82
+ "ssh://git@#{builder_hostname}:2222/#{option(:app)}.git"
83
+ end
84
+
85
+ def builder_hostname
86
+ host_tokens = controller_host.split(".")
87
+ host_tokens[0] = [host_tokens[0], "builder"].join("-")
88
+ host_tokens.join(".")
89
+ end
90
+
91
+ def controller_host
92
+ option(:controller).gsub(/https?:\/\//, "").split(":")[0]
93
+ end
94
+
95
+ def push_app
96
+ unless context.shell "bash -c 'git push #{verbose_flag} #{repository_url} HEAD:refs/heads/master -f 2>&1 | tr -dc \"[:alnum:][:space:][:punct:]\" | sed -E \"s/remote: (\\[1G)+//\" | sed \"s/\\[K$//\"; exit ${PIPESTATUS[0]}'"
97
+ error 'Deploying application failed.'
98
+ end
99
+ end
100
+
101
+ def run(command)
102
+ unless context.shell "./deis run -a #{option(:app)} -- #{command}"
103
+ error 'Running command failed.'
104
+ end
105
+ end
106
+
107
+ def cleanup
108
+ return if options[:skip_cleanup]
109
+ context.shell "mv deis ~/deis"
110
+ super
111
+ context.shell "mv ~/deis deis"
112
+ end
113
+
114
+ def verbose_flag
115
+ '-v' if options[:verbose]
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,23 @@
1
+ module DPL
2
+ class Provider
3
+ class Divshot < Provider
4
+ npm_g 'divshot-cli', 'divshot'
5
+
6
+ def check_auth
7
+ raise Error, "must supply an api key" unless option(:api_key)
8
+ end
9
+
10
+ def check_app
11
+ error "missing divshot.json" unless File.exist? "divshot.json"
12
+ end
13
+
14
+ def needs_key?
15
+ false
16
+ end
17
+
18
+ def push_app
19
+ context.shell "divshot push #{options[:environment] || "production"} --token=#{option(:api_key)}"
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,195 @@
1
+ require 'time'
2
+
3
+ module DPL
4
+ class Provider
5
+ class ElasticBeanstalk < Provider
6
+ experimental 'AWS Elastic Beanstalk'
7
+
8
+ requires 'aws-sdk', version: '~> 2.0'
9
+ requires 'rubyzip', :load => 'zip'
10
+
11
+ DEFAULT_REGION = 'us-east-1'
12
+
13
+ def needs_key?
14
+ false
15
+ end
16
+
17
+ def access_key_id
18
+ options[:access_key_id] || context.env['AWS_ACCESS_KEY_ID'] || raise(Error, "missing access_key_id")
19
+ end
20
+
21
+ def secret_access_key
22
+ options[:secret_access_key] || context.env['AWS_SECRET_ACCESS_KEY'] || raise(Error, "missing secret_access_key")
23
+ end
24
+
25
+ def check_auth
26
+ options = {
27
+ :region => region,
28
+ :credentials => Aws::Credentials.new(access_key_id, secret_access_key)
29
+ }
30
+ Aws.config.update(options)
31
+ end
32
+
33
+ def check_app
34
+ end
35
+
36
+ def only_create_app_version
37
+ options[:only_create_app_version]
38
+ end
39
+
40
+ def push_app
41
+ @start_time = Time.now
42
+ create_bucket unless bucket_exists?
43
+
44
+ if options[:zip_file]
45
+ zip_file = File.expand_path(options[:zip_file])
46
+ else
47
+ zip_file = create_zip
48
+ end
49
+
50
+ s3_object = upload(archive_name, zip_file)
51
+ sleep 5 #s3 eventual consistency
52
+ version = create_app_version(s3_object)
53
+ if !only_create_app_version
54
+ update_app(version)
55
+ wait_until_deployed if options[:wait_until_deployed]
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ def app_name
62
+ option(:app)
63
+ end
64
+
65
+ def env_name
66
+ options[:env] || context.env['ELASTIC_BEANSTALK_ENV'] || raise(Error, "missing env")
67
+ end
68
+
69
+ def version_label
70
+ context.env['ELASTIC_BEANSTALK_LABEL'] || "travis-#{sha}-#{Time.now.to_i}"
71
+ end
72
+
73
+ def version_description
74
+ context.env['ELASTIC_BEANSTALK_DESCRIPTION'] || commit_msg
75
+ end
76
+
77
+ def archive_name
78
+ "#{version_label}.zip"
79
+ end
80
+
81
+ def region
82
+ options[:region] || DEFAULT_REGION
83
+ end
84
+
85
+ def bucket_name
86
+ option(:bucket_name)
87
+ end
88
+
89
+ def bucket_path
90
+ @bucket_path ||= options[:bucket_path] ? option(:bucket_path).gsub(/\/*$/,'/') : nil
91
+ end
92
+
93
+ def s3
94
+ @s3 ||= Aws::S3::Resource.new
95
+ end
96
+
97
+ def eb
98
+ @eb ||= Aws::ElasticBeanstalk::Client.new
99
+ end
100
+
101
+ def bucket_exists?
102
+ s3.bucket(bucket_name).exists?
103
+ end
104
+
105
+ def create_bucket
106
+ s3.bucket(bucket_name).create
107
+ end
108
+
109
+ def files_to_pack
110
+ `git ls-files -z`.split("\x0")
111
+ end
112
+
113
+ def create_zip
114
+ directory = Dir.pwd
115
+ zipfile_name = File.join(directory, archive_name)
116
+
117
+ Zip::File.open(zipfile_name, Zip::File::CREATE) do |zipfile|
118
+ files_to_pack.each do |file|
119
+ relative_archive_path = File.join(directory, '/')
120
+ zipfile.add(file.sub(relative_archive_path, ''), file)
121
+ end
122
+ end
123
+ zipfile_name
124
+ end
125
+
126
+ def upload(key, file)
127
+ options = {
128
+ :body => Pathname.new(file).open
129
+ }
130
+ bucket = s3.bucket(bucket_name)
131
+ obj = bucket_path ? bucket.object("#{bucket_path}#{key}") : bucket.object(key)
132
+ obj.put(options)
133
+ obj
134
+ end
135
+
136
+ def create_app_version(s3_object)
137
+ # Elastic Beanstalk doesn't support descriptions longer than 200 characters
138
+ description = version_description[0, 200]
139
+ options = {
140
+ :application_name => app_name,
141
+ :version_label => version_label,
142
+ :description => description,
143
+ :source_bundle => {
144
+ :s3_bucket => bucket_name,
145
+ :s3_key => s3_object.key
146
+ },
147
+ :auto_create_application => false
148
+ }
149
+ eb.create_application_version(options)
150
+ end
151
+
152
+ # Wait until EB environment update finishes
153
+ def wait_until_deployed
154
+ errorEvents = 0 # errors counter, should remain 0 for successful deployment
155
+ events = []
156
+
157
+ loop do
158
+ environment = eb.describe_environments({
159
+ :application_name => app_name,
160
+ :environment_names => [env_name]
161
+ })[:environments].first
162
+
163
+ eb.describe_events({
164
+ :environment_name => env_name,
165
+ :start_time => @start_time.utc.iso8601,
166
+ })[:events].reverse.each do |event|
167
+ message = "#{event[:event_date]} [#{event[:severity]}] #{event[:message]}"
168
+ unless events.include?(message)
169
+ events.push(message)
170
+ if event[:severity] == "ERROR"
171
+ errorEvents += 1
172
+ warn(message)
173
+ else
174
+ log(message)
175
+ end
176
+ end
177
+ end
178
+
179
+ break if environment[:status] == "Ready"
180
+ sleep 5
181
+ end
182
+
183
+ if errorEvents > 0 then error("Deployment failed.") end
184
+ end
185
+
186
+ def update_app(version)
187
+ options = {
188
+ :environment_name => env_name,
189
+ :version_label => version[:application_version][:version_label]
190
+ }
191
+ eb.update_environment(options)
192
+ end
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,90 @@
1
+ require 'time'
2
+
3
+ module DPL
4
+ class Provider
5
+ class EngineYard < Provider
6
+ requires 'engineyard-cloud-client'
7
+
8
+ def token
9
+ options[:api_key] ||= if options[:email] and options[:password]
10
+ EY::CloudClient.authenticate(options[:email], options[:password])
11
+ else
12
+ option(:api_key) # will raise
13
+ end
14
+ end
15
+
16
+ def api
17
+ @api ||= EY::CloudClient.new(:token => token)
18
+ end
19
+
20
+ def check_auth
21
+ log "authenticated as %s" % api.current_user.email
22
+ end
23
+
24
+ def check_app
25
+ remotes = `git remote -v`.scan(/\t[^\s]+\s/).map { |c| c.strip }.uniq
26
+ @current_sha = `git rev-parse HEAD`.chomp
27
+ resolver = api.resolve_app_environments(
28
+ :app_name => options[:app],
29
+ :account_name => options[:account],
30
+ :environment_name => options[:environment],
31
+ :remotes => remotes)
32
+ resolver.one_match { @app_env = resolver.matches.first }
33
+ resolver.no_matches { error resolver.errors.join("\n").inspect }
34
+ resolver.many_matches do |matches|
35
+ message = "Multiple matches possible, please be more specific:\n\n"
36
+ matches.each do |appenv|
37
+ message << "environment: '#{appenv.environment.name}' account: '#{appenv.environment.account.name}'\n"
38
+ end
39
+ error message
40
+ end
41
+ @app_env
42
+ end
43
+
44
+ def needs_key?
45
+ false
46
+ end
47
+
48
+ def cleanup
49
+ end
50
+
51
+ def uncleanup
52
+ end
53
+
54
+ def push_app
55
+ deploy_opts = {:ref => @current_sha}
56
+ if command = options[:migrate]
57
+ if command === true || command === "true"
58
+ error("\"true\" doesn't look like a migration command, try --migrate=\"rake db:migrate\"")
59
+ end
60
+ deploy_opts[:migrate] = true
61
+ deploy_opts[:migration_command] = command
62
+ end
63
+ print "deploying "
64
+ deployment = EY::CloudClient::Deployment.deploy(api, @app_env, deploy_opts)
65
+ result = poll_for_result(deployment)
66
+ unless result.successful
67
+ error "Deployment failed (see logs on Engine Yard)"
68
+ end
69
+ end
70
+
71
+ def poll_for_result(deployment)
72
+ until deployment.finished?
73
+ sleep 5
74
+ #TODO: configurable timeout?
75
+ print "."
76
+ deployment = EY::CloudClient::Deployment.get(api, deployment.app_environment, deployment.id)
77
+ end
78
+ puts "DONE: https://cloud.engineyard.com/apps/#{deployment.app.id}/environments/#{deployment.environment.id}/deployments/#{deployment.id}/pretty"
79
+ deployment
80
+ end
81
+
82
+ def deploy
83
+ super
84
+ rescue EY::CloudClient::Error => e
85
+ error(e.message)
86
+ end
87
+
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,27 @@
1
+ module DPL
2
+ class Provider
3
+ class Firebase < Provider
4
+ npm_g 'firebase-tools@^3.0', 'firebase'
5
+
6
+ def check_auth
7
+ raise Error, "must supply token option or FIREBASE_TOKEN environment variable" if !options[:token] && !context.env['FIREBASE_TOKEN']
8
+ end
9
+
10
+ def check_app
11
+ error "missing firebase.json" unless File.exist? "firebase.json"
12
+ end
13
+
14
+ def needs_key?
15
+ false
16
+ end
17
+
18
+ def push_app
19
+ command = "firebase deploy --non-interactive"
20
+ command << " --project #{options[:project]}" if options[:project]
21
+ command << " --message '#{options[:message]}'" if options[:message]
22
+ command << " --token '#{options[:token]}'" if options[:token]
23
+ context.shell command
24
+ end
25
+ end
26
+ end
27
+ end