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
+ 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