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,97 @@
1
+ require 'net/http'
2
+ require 'uri'
3
+ require 'json'
4
+ require 'date'
5
+
6
+ module DPL
7
+ class Provider
8
+ class Scalingo < Provider
9
+
10
+ def install_deploy_dependencies
11
+ unless context.shell "curl -OL https://cli-dl.scalingo.io/release/scalingo_latest_linux_amd64.tar.gz && tar -zxvf scalingo_latest_linux_amd64.tar.gz && mv scalingo_*_linux_amd64/scalingo . && rm scalingo_latest_linux_amd64.tar.gz && rm -r scalingo_*_linux_amd64"
12
+ error "Couldn't install Scalingo CLI."
13
+ end
14
+ end
15
+
16
+ def initialize(context, options)
17
+ super
18
+ @options = options
19
+ @remote = options[:remote] || "scalingo"
20
+ @branch = options[:branch] || "master"
21
+ end
22
+
23
+ def logged_in
24
+ context.shell "DISABLE_INTERACTIVE=true ./scalingo login 2> /dev/null > /dev/null"
25
+ end
26
+
27
+ def check_auth
28
+ if @options[:api_key]
29
+ unless context.shell "mkdir -p ~/.config/scalingo"
30
+ error "Couldn't create authentication file."
31
+ end
32
+ url = URI.parse('http://api.scalingo.com/v1/users/self')
33
+ http = Net::HTTP.new(url.host, url.port)
34
+ request = Net::HTTP::Get.new(url.request_uri)
35
+ request.basic_auth("", @options[:api_key])
36
+ request["Accept"] = "application/json"
37
+ request["Content-type"] = "application/json"
38
+ response = http.request(request)
39
+ data = {}
40
+ if File.exist?("#{Dir.home}/.config/scalingo/auth")
41
+ data = JSON.parse(File.read("#{Dir.home}/.config/scalingo/auth"))
42
+ end
43
+ begin
44
+ user = JSON.parse(response.body)
45
+ rescue
46
+ error "Invalid API token."
47
+ end
48
+ data["auth_config_data"] = {}
49
+ data["auth_config_data"]["api.scalingo.com"] = {}
50
+ data["auth_config_data"]["api.scalingo.com"]["id"] = user["user"]["id"]
51
+ data["auth_config_data"]["api.scalingo.com"]["last_name"] = user["user"]["last_name"]
52
+ data["auth_config_data"]["api.scalingo.com"]["username"] = user["user"]["username"]
53
+ data["auth_config_data"]["api.scalingo.com"]["email"] = user["user"]["email"]
54
+ data["auth_config_data"]["api.scalingo.com"]["first_name"] = user["user"]["first_name"]
55
+ data["auth_config_data"]["api.scalingo.com"]["auth_token"] = @options[:api_key]
56
+ data["last_update"] = DateTime.now
57
+ f = File.open("#{Dir.home}/.config/scalingo/auth", "w+") {
58
+ |f| f.write(data.to_json)
59
+ }
60
+ elsif @options[:username] && @options[:password]
61
+ context.shell "echo -e \"#{@options[:username]}\n#{@options[:password]}\" | timeout 2 ./scalingo login 2> /dev/null > /dev/null"
62
+ end
63
+ if !logged_in
64
+ error "Couldn't connect to Scalingo API."
65
+ end
66
+ end
67
+
68
+ def setup_key(file, type = nil)
69
+ if !logged_in
70
+ error "Couldn't connect to Scalingo API."
71
+ end
72
+ unless context.shell "./scalingo keys-add dpl_tmp_key #{file}"
73
+ error "Couldn't add ssh key."
74
+ end
75
+ end
76
+
77
+ def remove_key
78
+ if !logged_in
79
+ error "Couldn't connect to Scalingo API."
80
+ end
81
+ unless context.shell "./scalingo keys-remove dpl_tmp_key"
82
+ error "Couldn't remove ssh key."
83
+ end
84
+ end
85
+
86
+ def push_app
87
+ if @options[:app]
88
+ context.shell "git remote add #{@remote} git@scalingo.com:#{@options[:app]}.git 2> /dev/null > /dev/null"
89
+ end
90
+ unless context.shell "git push #{@remote} #{@branch} -f"
91
+ error "Couldn't push your app."
92
+ end
93
+ end
94
+
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,29 @@
1
+ module DPL
2
+ class Provider
3
+ class Script < Provider
4
+
5
+ experimental 'Script'
6
+
7
+ def check_auth
8
+ end
9
+
10
+ def check_app
11
+ end
12
+
13
+ def needs_key?
14
+ false
15
+ end
16
+
17
+ def push_app
18
+ context.shell script
19
+ if $?.exitstatus != 0
20
+ raise Error, "Script failed with status #{$?.exitstatus}"
21
+ end
22
+ end
23
+
24
+ def script
25
+ options[:script]
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,33 @@
1
+ module DPL
2
+ class Provider
3
+ class Surge < Provider
4
+ npm_g 'surge'
5
+
6
+ def project
7
+ File.expand_path( (context.env['TRAVIS_BUILD_DIR'] || '.' ) + "/" + (options[:project] || '') )
8
+ end
9
+
10
+ def domain
11
+ options[:domain] || ''
12
+ end
13
+
14
+ def check_auth
15
+ if ! context.env['SURGE_TOKEN'] then raise Error, "Please add SURGE_TOKEN in Travis settings (get your token with 'surge token')" end
16
+ if ! context.env['SURGE_LOGIN'] then raise Error, "Please add SURGE_LOGIN in Travis settings (its your email)" end
17
+ end
18
+
19
+ def check_app
20
+ if ! File.directory?(project) then raise Error, "Please set a valid project folder path in .travis.yml under deploy: project: myPath" end
21
+ if domain.empty? && ! File.exist?("#{project}/CNAME") then raise Error, "Please set domain in .travis.yml under deploy: project: myDomain (or in a CNAME file in the repo project folder)" end
22
+ end
23
+
24
+ def needs_key?
25
+ false
26
+ end
27
+
28
+ def push_app
29
+ context.shell "surge #{project} #{domain}"
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,190 @@
1
+ module DPL
2
+ class Provider
3
+ class TestFairy < Provider
4
+
5
+ requires "multipart-post", load: 'net/http/post/multipart', version: '2.0.0'
6
+
7
+ require "net/http"
8
+ require 'net/http/post/multipart'
9
+ require 'json'
10
+ require 'tempfile'
11
+
12
+
13
+ VERSION = "0.1"
14
+ TAG = "-TestFairy-"
15
+ SERVER = "http://api.testfairy.com"
16
+ UPLOAD_URL_PATH = "/api/upload";
17
+ UPLOAD_SIGNED_URL_PATH = "/api/upload-signed";
18
+
19
+ def check_auth
20
+ if android?
21
+ storepassToPrint = option(:storepass).clone
22
+ aliasToPrint = option(:alias).clone
23
+ puts "keystore-file = #{option(:keystore_file)} storepass = #{storepassToPrint.sub! storepassToPrint[1..-2], '****'} alias = #{aliasToPrint.sub! aliasToPrint[1..-2], '****'}"
24
+ end
25
+ puts "api-key = #{option(:api_key).gsub(/[123456789]/, '*')} symbols-file = #{options[:symbols_file]}"
26
+ end
27
+
28
+ def needs_key?
29
+ false
30
+ end
31
+
32
+ def push_app
33
+ puts "push_app #{TAG}"
34
+ response = upload_app
35
+ if android?
36
+ puts response['instrumented_url']
37
+ instrumentedFile = download_from_url response['instrumented_url']
38
+ signedApk = signing_apk instrumentedFile
39
+ response = upload_signed_apk signedApk
40
+ end
41
+ puts "Upload success!, check your build on #{response['build_url']}"
42
+ end
43
+
44
+ def android?
45
+ option(:app_file).include? "apk"
46
+ end
47
+
48
+
49
+ private
50
+
51
+ def signing_apk(instrumentedFile)
52
+ signed = Tempfile.new(['instrumented-signed', '.apk'])
53
+ zipOutput = %x[#{zip_path} -qd #{instrumentedFile} META-INF/*]
54
+ if zipOutput.include? 'error'
55
+ raise Error, zipOutput
56
+ end
57
+
58
+ jarSignerOutput = %x[#{jarsigner_path} -keystore #{option(:keystore_file)} -storepass #{option(:storepass)} -digestalg SHA1 -sigalg MD5withRSA #{instrumentedFile} #{option(:alias)}]
59
+ if jarSignerOutput.include? 'error'
60
+ raise Error, jarSignerOutput
61
+ end
62
+
63
+ verifyOutput = %x[#{jarsigner_path} -verify #{instrumentedFile}]
64
+ if !verifyOutput.include? 'jar verified'
65
+ raise Error, verifyOutput
66
+ end
67
+
68
+ zipAlignOutput = %x[#{zipalign_path} -f 4 #{instrumentedFile} #{signed.path}]
69
+
70
+ puts "signing Apk finished: #{signed.path()} (file size:#{File.size(signed.path())} )"
71
+ signed.path()
72
+ end
73
+
74
+ def download_from_url(url)
75
+ puts "downloading from #{url} "
76
+ url = "#{url}?api_key=#{option(:api_key)}"
77
+ uri = URI.parse(url)
78
+ instrumentedFile = Net::HTTP.start(uri.host, uri.port) do |http|
79
+ resp = http.get "#{uri.path}?#{uri.query}"
80
+ if resp.code == "302"
81
+ resp = Net::HTTP.get_response(URI.parse(resp.header['location']))
82
+ end
83
+ file = Tempfile.new(['instrumented', '.apk'])
84
+ file.write(resp.body)
85
+ file.flush
86
+ file
87
+ end
88
+ puts "Done #{instrumentedFile.path()} (file size:#{File.size(instrumentedFile.path())} )"
89
+ instrumentedFile.path()
90
+ end
91
+
92
+ def upload_app
93
+ uploadUrl = SERVER + UPLOAD_URL_PATH
94
+ params = get_params
95
+ post uploadUrl, params
96
+ end
97
+
98
+ def upload_signed_apk apkPath
99
+ uploadSignedUrl = SERVER + UPLOAD_SIGNED_URL_PATH
100
+
101
+ params = {"api_key" => "#{option(:api_key)}"}
102
+ add_file_param params , 'apk_file', apkPath
103
+ add_file_param params, 'symbols_file', options[:symbols_file]
104
+ add_param params, 'testers-groups', options[:testers_groups]
105
+ add_boolean_param params, 'notify', options[:notify]
106
+ add_boolean_param params, 'auto-update', options[:auto_update]
107
+
108
+ post uploadSignedUrl, params
109
+ end
110
+
111
+ def post url, params
112
+ puts "Upload parameters = #{get_printable_params params} \nto #{url}"
113
+ uri = URI.parse(url)
114
+ request = Net::HTTP::Post::Multipart.new(uri.path, params, 'User-Agent' => "Travis plugin version=#{VERSION}")
115
+ res = Net::HTTP.start(uri.host, uri.port) do |http|
116
+ http.request(request)
117
+ end
118
+ puts res.body
119
+ resBody = JSON.parse(res.body)
120
+ if (resBody['status'] == 'fail')
121
+ raise Error, resBody['message']
122
+ end
123
+ return resBody
124
+ end
125
+
126
+ def get_printable_params params
127
+ paramsToPrint = params.clone
128
+ paramsToPrint['api_key'] = paramsToPrint['api_key'].gsub(/[123456789]/, '*')
129
+ paramsToPrint['apk_file'] = paramsToPrint['apk_file'].path()
130
+ JSON.pretty_generate(paramsToPrint)
131
+ end
132
+
133
+ def get_params
134
+ params = {'api_key' => "#{option(:api_key)}"}
135
+ add_file_param params, 'apk_file', option(:app_file)
136
+ add_file_param params, 'symbols_file', options[:symbols_file]
137
+ add_param params, 'video-quality', options[:video_quality]
138
+ add_param params, 'screenshot-interval', options[:screenshot_interval]
139
+ add_param params, 'max-duration', options[:max_duration]
140
+ add_param params, 'testers-groups', options[:testers_groups]
141
+ add_param params, 'advanced-options', options[:advanced_options]
142
+ add_param params, 'metrics', options[:metrics]
143
+ add_boolean_param params, 'data-only-wifi', options[:data_only_wifi]
144
+ add_boolean_param params, 'record-on-background', options[:record_on_background]
145
+ add_boolean_param params, 'video', options[:video]
146
+ add_boolean_param params, 'notify', options[:notify]
147
+ add_boolean_param params, 'icon-watermark', options[:icon_watermark]
148
+
149
+ travisCommitRange = context.env.fetch('TRAVIS_COMMIT_RANGE',nil)
150
+ if !travisCommitRange.nil?
151
+ changelog = %x[git log --pretty=oneline --abbrev-commit #{travisCommitRange}]
152
+ add_param params, 'changelog', changelog
153
+ end
154
+ params
155
+ end
156
+
157
+ def add_file_param params, fileName, filePath
158
+ if (!filePath.nil? && !filePath.empty?)
159
+ params[fileName] = UploadIO.new(File.new(filePath), "", filePath.split("/").last)
160
+ end
161
+ end
162
+
163
+ def add_param params, paramName, param
164
+ if (!param.nil? && !param.empty?)
165
+ params[paramName] = param
166
+ end
167
+ end
168
+
169
+ def add_boolean_param params, paramName, param
170
+ if (!param.nil?)
171
+ params[paramName] = (param == true) ? "on" : "off"
172
+ end
173
+ end
174
+
175
+ def zip_path
176
+ @zip_path ||= %x[which zip].split("\n").first
177
+ end
178
+
179
+ def zipalign_path
180
+ android_home_path = context.env.fetch('ANDROID_HOME', '/usr')
181
+ @zipalign_path ||= %x[find -L #{android_home_path} -name zipalign 2>/dev/null].split("\n").first
182
+ end
183
+
184
+ def jarsigner_path
185
+ java_home_path = context.env.fetch('JAVA_HOME', '/usr')
186
+ @jarsigner_path ||= %x[find -L #{java_home_path} -name jarsigner 2>/dev/null].split("\n").first
187
+ end
188
+ end
189
+ end
190
+ end
@@ -0,0 +1,45 @@
1
+ module DPL
2
+ class Provider
3
+ class Transifex < Provider
4
+ experimental 'Transifex'
5
+
6
+ DEFAULT_CLIENT_VERSION = '>=0.11'
7
+ DEFAULT_HOSTNAME = 'https://www.transifex.com'
8
+
9
+ def install_deploy_dependencies
10
+ cli_version = options[:cli_version] || DEFAULT_CLIENT_VERSION
11
+ self.class.pip 'transifex', 'transifex', cli_version
12
+ end
13
+
14
+ def needs_key?
15
+ false
16
+ end
17
+
18
+ def check_auth
19
+ install_deploy_dependencies
20
+ write_transifexrc
21
+ context.shell 'tx status'
22
+ end
23
+
24
+ def push_app
25
+ source_push
26
+ end
27
+
28
+ def write_transifexrc
29
+ File.open(File.expand_path('~/.transifexrc'), 'w') do |f|
30
+ f.puts [
31
+ "[#{options[:hostname] || DEFAULT_HOSTNAME}]",
32
+ "hostname = #{options[:hostname] || DEFAULT_HOSTNAME}",
33
+ "username = #{options[:username]}",
34
+ "password = #{options[:password]}",
35
+ "token = #{options[:token]}",
36
+ ].join("\n")
37
+ end
38
+ end
39
+
40
+ def source_push
41
+ context.shell 'tx push --source --no-interactive', retry: true
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,3 @@
1
+ module DPL
2
+ VERSION = '1.8.43'
3
+ end
@@ -0,0 +1 @@
1
+ EY has a a special deploy app. Get in touch with Kevin Holler if we don't hear back from them.
@@ -0,0 +1,3 @@
1
+ Heroku might send out emails for new deploy keys (doesn't do it for me, but for some others).
2
+
3
+ Alternative is Anvil, but it's not perfect, as it duplicates a lot of Heroku logic internally (and failed for me in one case).
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+ require 'dpl/cli'
3
+
4
+ describe DPL::CLI do
5
+ describe "#options" do
6
+ example { expect(described_class.new.options[:app]) .to eq(File.basename(Dir.pwd)) }
7
+ example { expect(described_class.new(:app => 'foo') .options[:app]).to eq('foo') }
8
+ example { expect(described_class.new("--app=foo") .options[:app]).to eq('foo') }
9
+ example { expect(described_class.new("--app") .options[:app]).to eq(true) }
10
+ example { expect(described_class.new("--app=foo", "--app=bar") .options[:app]).to eq(['foo', 'bar']) }
11
+
12
+ example "error handling" do
13
+ expect($stderr).to receive(:puts).with('invalid option "app"')
14
+ expect { described_class.new("app") }.to raise_error(SystemExit)
15
+ end
16
+ end
17
+
18
+ describe "#run" do
19
+ example "triggers deploy" do
20
+ provider = double('provider')
21
+ expect(DPL::Provider).to receive(:new).and_return(provider)
22
+ expect(provider).to receive(:deploy)
23
+
24
+ described_class.run("--provider=foo")
25
+ end
26
+
27
+ example "error handling" do
28
+ expect($stderr).to receive(:puts).with('missing provider')
29
+ expect { described_class.run }.to raise_error(SystemExit)
30
+ end
31
+
32
+ example "error handling in debug mode" do
33
+ expect { described_class.run("--debug") }.to raise_error(DPL::Error, 'missing provider')
34
+ end
35
+ end
36
+ end