dpl 1.7.12.travis.742.4 → 1.7.12.travis.748.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/README.md +31 -2
- data/lib/dpl/provider.rb +1 -0
- data/lib/dpl/provider/testfairy.rb +184 -0
- data/spec/provider/testfairy_spec.rb +80 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
NGI1NmM1NTEzMjg0MjBjZWI3MWM0ZmZkYThlNjlkYmJkYmU3MDZiNA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
YzM0YmEyNTcyOTJhOWU4ZmIxYTIyNzMwM2U0NWEwMTI0YjBmNGFkNw==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MGI2MjBmZWU2YzNhZjVlZWExY2YyNDdjZjI1OGNmYjAzODQ0NTVhYjE5NDE2
|
10
|
+
MWJhMTI1YTMxMGM4N2MwY2UyY2Q2NmQxZDg5YTBkMDcyZmNmNjg5YmU3YjZk
|
11
|
+
MWUxMWQ3NDg3YTZmMWQxYTk3MjFiYzI3OGE4MTVhM2VkMGU5MDA=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ZDYwNTdlNzk4ZTg2NjhjNzYxZjllZDVlODU0ZTg1NDQ1N2E4MjVmYmNiYmVl
|
14
|
+
NGRmNWIxYzkxZGViODcwODM0N2RiZDEwNGQ5NDgzNTZjYWJiMjMxMzUzM2Y5
|
15
|
+
MjYxOGYyZWI0ZTQzYjJlODExNTI1YWIyMGMyM2NlZjdlYjc2OWE=
|
data/README.md
CHANGED
@@ -33,6 +33,7 @@ Dpl supports the following providers:
|
|
33
33
|
* [packagecloud](#packagecloud)
|
34
34
|
* [Chef Supermarket](#chef-supermarket)
|
35
35
|
* [Lambda](#lambda)
|
36
|
+
* [TestFairy](#testfairy)
|
36
37
|
|
37
38
|
## Installation:
|
38
39
|
|
@@ -50,8 +51,6 @@ Running dpl in a terminal that saves history is insecure as your password/api ke
|
|
50
51
|
###Global Flags
|
51
52
|
* `--provider=<provider>` sets the provider you want to deploy to. Every provider has slightly different flags, which are documented in the section about your provider following.
|
52
53
|
* Dpl will deploy by default from the latest commit. Use the `--skip_cleanup` flag to deploy from the current file state. Note that many providers deploy by git and could ignore this option.
|
53
|
-
|
54
|
-
|
55
54
|
### Heroku:
|
56
55
|
|
57
56
|
#### Options:
|
@@ -492,3 +491,33 @@ Deploy contents of a specific directory using specific module name:
|
|
492
491
|
--module_name="copy" \
|
493
492
|
--handler_name="handler";
|
494
493
|
```
|
494
|
+
|
495
|
+
### TestFairy:
|
496
|
+
|
497
|
+
Your Android(apk)/iOS(ipa) file will be uploaded to TestFairy,
|
498
|
+
and your testers can start testing your app.
|
499
|
+
|
500
|
+
#### Options:
|
501
|
+
* **api-key**: TestFairy API Key (https://app.testfairy.com/settings/) run "travis encrypt --add deploy.api-key" on your repo.
|
502
|
+
* **app-file**: Path to the app file that will be generated after the build (APK/IPA).
|
503
|
+
* **symbols-file**: Path to the symbols file.
|
504
|
+
* **keystore-file**: Path to your keystore-file (must, only for android). http://docs.travis-ci.com/user/encrypting-files/
|
505
|
+
* **storepass**: storepass (must, only for android).
|
506
|
+
* **alias**: alias (must, only for android).
|
507
|
+
* **testers-groups**: You can set a tester group to be notified about this build (group1,group1).
|
508
|
+
* **notify**: If true, an email you a changelog will be sent to your users.
|
509
|
+
* **auto-update**: If true, all the previous installations of this app will be automatically all upgraded to this version.
|
510
|
+
* **video-quality**: Video quality settings, "high", "medium" or "low". Default is "high".
|
511
|
+
* **screenshot-interval**: You can choose "1"\"2"\"10" sec.
|
512
|
+
* **max-duration**: Maximum session recording length, eg "20m" or "1h". Default is "10m". Maximum "24h".
|
513
|
+
* **advanced-options**: For example (option1,option2)
|
514
|
+
* **data-only-wifi**: If true, video and recorded metrics will be sent only when connected to a wifi network.
|
515
|
+
* **record-on-background**: If true, data will be collected while the app on background.
|
516
|
+
* **video**: If true, Video recording settings "true", "false". Default is "true".
|
517
|
+
* **icon-watermark**: Add a small watermark to app icon. Default is "false".
|
518
|
+
* **metrics**: Comma-separated list of metrics to record. View list on http://docs.testfairy.com/Upload_API.html.
|
519
|
+
|
520
|
+
#### Examples:
|
521
|
+
|
522
|
+
dpl --provider=testfairy --api-key=<api-key> --app-file="out/Sample.apk" --keystore-file="out/keystore" --storepass=<storepass> --alias=<alias>
|
523
|
+
|
data/lib/dpl/provider.rb
CHANGED
@@ -37,6 +37,7 @@ module DPL
|
|
37
37
|
autoload :PuppetForge, 'dpl/provider/puppet_forge'
|
38
38
|
autoload :Packagecloud, 'dpl/provider/packagecloud'
|
39
39
|
autoload :ChefSupermarket, 'dpl/provider/chef_supermarket'
|
40
|
+
autoload :TestFairy, 'dpl/provider/testfairy'
|
40
41
|
|
41
42
|
|
42
43
|
def self.new(context, options)
|
@@ -0,0 +1,184 @@
|
|
1
|
+
module DPL
|
2
|
+
class Provider
|
3
|
+
class TestFairy < Provider
|
4
|
+
|
5
|
+
require "net/http"
|
6
|
+
require 'net/http/post/multipart'
|
7
|
+
require 'json'
|
8
|
+
require 'tempfile'
|
9
|
+
|
10
|
+
|
11
|
+
VERSION = "0.1"
|
12
|
+
TAG = "-TestFairy-"
|
13
|
+
SERVER = "http://api.testfairy.com"
|
14
|
+
UPLOAD_URL_PATH = "/api/upload";
|
15
|
+
UPLOAD_SIGNED_URL_PATH = "/api/upload-signed";
|
16
|
+
|
17
|
+
def check_auth
|
18
|
+
if android?
|
19
|
+
storepassToPrint = option(:storepass).clone
|
20
|
+
aliasToPrint = option(:alias).clone
|
21
|
+
puts "keystore-file = #{option(:keystore_file)} storepass = #{storepassToPrint.sub! storepassToPrint[1..-2], '****'} alias = #{aliasToPrint.sub! aliasToPrint[1..-2], '****'}"
|
22
|
+
end
|
23
|
+
puts "api-key = #{option(:api_key).gsub(/[123456789]/, '*')} symbols-file = #{options[:symbols_file]}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def needs_key?
|
27
|
+
false
|
28
|
+
end
|
29
|
+
|
30
|
+
def push_app
|
31
|
+
puts "push_app #{TAG}"
|
32
|
+
response = upload_app
|
33
|
+
if android?
|
34
|
+
puts response['instrumented_url']
|
35
|
+
instrumentedFile = download_from_url response['instrumented_url']
|
36
|
+
signedApk = signing_apk instrumentedFile
|
37
|
+
response = upload_signed_apk signedApk
|
38
|
+
end
|
39
|
+
puts "Upload success!, check your build on #{response['build_url']}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def android?
|
43
|
+
option(:app_file).include? "apk"
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def signing_apk(instrumentedFile)
|
50
|
+
signed = Tempfile.new(['instrumented-signed', '.apk'])
|
51
|
+
zipOutput = %x[#{zip_path} -qd #{instrumentedFile} META-INF/*]
|
52
|
+
if zipOutput.include? 'error'
|
53
|
+
raise Error, zipOutput
|
54
|
+
end
|
55
|
+
|
56
|
+
jarSignerOutput = %x[#{jarsigner_path} -keystore #{option(:keystore_file)} -storepass #{option(:storepass)} -digestalg SHA1 -sigalg MD5withRSA #{instrumentedFile} #{option(:alias)}]
|
57
|
+
if jarSignerOutput.include? 'error'
|
58
|
+
raise Error, jarSignerOutput
|
59
|
+
end
|
60
|
+
|
61
|
+
verifyOutput = %x[#{jarsigner_path} -verify #{instrumentedFile}]
|
62
|
+
if !verifyOutput.include? 'jar verified'
|
63
|
+
raise Error, verifyOutput
|
64
|
+
end
|
65
|
+
|
66
|
+
zipAlignOutput = %x[#{zipalign_path} -f 4 #{instrumentedFile} #{signed.path}]
|
67
|
+
|
68
|
+
puts "signing Apk finished: #{signed.path()} (file size:#{File.size(signed.path())} )"
|
69
|
+
signed.path()
|
70
|
+
end
|
71
|
+
|
72
|
+
def download_from_url(url)
|
73
|
+
puts "downloading from #{url} "
|
74
|
+
uri = URI.parse(url)
|
75
|
+
instrumentedFile = Net::HTTP.start(uri.host, uri.port) do |http|
|
76
|
+
resp = http.get(uri.path)
|
77
|
+
file = Tempfile.new(['instrumented', '.apk'])
|
78
|
+
file.write(resp.body)
|
79
|
+
file.flush
|
80
|
+
file
|
81
|
+
end
|
82
|
+
puts "Done #{instrumentedFile.path()} (file size:#{File.size(instrumentedFile.path())} )"
|
83
|
+
instrumentedFile.path()
|
84
|
+
end
|
85
|
+
|
86
|
+
def upload_app
|
87
|
+
uploadUrl = SERVER + UPLOAD_URL_PATH
|
88
|
+
params = get_params
|
89
|
+
post uploadUrl, params
|
90
|
+
end
|
91
|
+
|
92
|
+
def upload_signed_apk apkPath
|
93
|
+
uploadSignedUrl = SERVER + UPLOAD_SIGNED_URL_PATH
|
94
|
+
|
95
|
+
params = {"api_key" => "#{option(:api_key)}"}
|
96
|
+
add_file_param params , 'apk_file', apkPath
|
97
|
+
add_file_param params, 'symbols_file', options[:symbols_file]
|
98
|
+
add_param params, 'testers-groups', options[:testers_groups]
|
99
|
+
add_boolean_param params, 'notify', options[:notify]
|
100
|
+
add_boolean_param params, 'auto-update', options[:auto_update]
|
101
|
+
|
102
|
+
post uploadSignedUrl, params
|
103
|
+
end
|
104
|
+
|
105
|
+
def post url, params
|
106
|
+
puts "Upload parameters = #{get_printable_params params} \nto #{url}"
|
107
|
+
uri = URI.parse(url)
|
108
|
+
request = Net::HTTP::Post::Multipart.new(uri.path, params, 'User-Agent' => "Travis plugin version=#{VERSION}")
|
109
|
+
res = Net::HTTP.start(uri.host, uri.port) do |http|
|
110
|
+
http.request(request)
|
111
|
+
end
|
112
|
+
puts res.body
|
113
|
+
resBody = JSON.parse(res.body)
|
114
|
+
if (resBody['status'] == 'fail')
|
115
|
+
raise Error, resBody['message']
|
116
|
+
end
|
117
|
+
return resBody
|
118
|
+
end
|
119
|
+
|
120
|
+
def get_printable_params params
|
121
|
+
paramsToPrint = params.clone
|
122
|
+
paramsToPrint['api_key'] = paramsToPrint['api_key'].gsub(/[123456789]/, '*')
|
123
|
+
paramsToPrint['apk_file'] = paramsToPrint['apk_file'].path()
|
124
|
+
JSON.pretty_generate(paramsToPrint)
|
125
|
+
end
|
126
|
+
|
127
|
+
def get_params
|
128
|
+
params = {'api_key' => "#{option(:api_key)}"}
|
129
|
+
add_file_param params, 'apk_file', option(:app_file)
|
130
|
+
add_file_param params, 'symbols_file', options[:symbols_file]
|
131
|
+
add_param params, 'video-quality', options[:video_quality]
|
132
|
+
add_param params, 'screenshot-interval', options[:screenshot_interval]
|
133
|
+
add_param params, 'max-duration', options[:max_duration]
|
134
|
+
add_param params, 'testers-groups', options[:testers_groups]
|
135
|
+
add_param params, 'advanced-options', options[:advanced_options]
|
136
|
+
add_param params, 'metrics', options[:metrics]
|
137
|
+
add_boolean_param params, 'data-only-wifi', options[:data_only_wifi]
|
138
|
+
add_boolean_param params, 'record-on-background', options[:record_on_background]
|
139
|
+
add_boolean_param params, 'video', options[:video]
|
140
|
+
add_boolean_param params, 'notify', options[:notify]
|
141
|
+
add_boolean_param params, 'icon-watermark', options[:icon_watermark]
|
142
|
+
|
143
|
+
travisCommitRange = context.env.fetch('TRAVIS_COMMIT_RANGE',nil)
|
144
|
+
if !travisCommitRange.nil?
|
145
|
+
changelog = %x[git log --pretty=oneline --abbrev-commit #{travisCommitRange}]
|
146
|
+
add_param params, 'changelog', changelog
|
147
|
+
end
|
148
|
+
params
|
149
|
+
end
|
150
|
+
|
151
|
+
def add_file_param params, fileName, filePath
|
152
|
+
if (!filePath.nil? && !filePath.empty?)
|
153
|
+
params[fileName] = UploadIO.new(File.new(filePath), "", filePath.split("/").last)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def add_param params, paramName, param
|
158
|
+
if (!param.nil? && !param.empty?)
|
159
|
+
params[paramName] = param
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def add_boolean_param params, paramName, param
|
164
|
+
if (!param.nil? && !param.empty?)
|
165
|
+
params[paramName] = (param == true) ? "on" : "off"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def zip_path
|
170
|
+
@zip_path ||= %x[which zip].split("\n").first
|
171
|
+
end
|
172
|
+
|
173
|
+
def zipalign_path
|
174
|
+
android_home_path = context.env.fetch('ANDROID_HOME', '/usr')
|
175
|
+
@zipalign_path ||= %x[find -L #{android_home_path} -name zipalign 2>/dev/null].split("\n").first
|
176
|
+
end
|
177
|
+
|
178
|
+
def jarsigner_path
|
179
|
+
java_home_path = context.env.fetch('JAVA_HOME', '/usr')
|
180
|
+
@jarsigner_path ||= %x[find -L #{java_home_path} -name jarsigner 2>/dev/null].split("\n").first
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'dpl/provider/testfairy'
|
3
|
+
|
4
|
+
describe DPL::Provider::TestFairy do
|
5
|
+
|
6
|
+
before (:all) do
|
7
|
+
|
8
|
+
%x[mkdir /tmp/android/]
|
9
|
+
%x[echo 'cp $3 $4' > /tmp/android/zipalign]
|
10
|
+
%x[chmod +x /tmp/android/zipalign]
|
11
|
+
|
12
|
+
@kyestore = '/tmp/debug.keystore'
|
13
|
+
%x[curl -Lso #{@kyestore} http://www.testfairy.com/support-files/travis/dpl/debug.keystore]
|
14
|
+
|
15
|
+
@local_android_app = '/tmp/android.apk'
|
16
|
+
%x[curl -Lso #{@local_android_app} http://www.testfairy.com/support-files/travis/dpl/android.apk]
|
17
|
+
|
18
|
+
@local_ios_app = '/tmp/ios.ipa'
|
19
|
+
%x[curl -Lso #{@local_ios_app} http://www.testfairy.com/support-files/travis/dpl/Empty.ipa]
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
let :context do
|
24
|
+
DummyContext.new
|
25
|
+
end
|
26
|
+
|
27
|
+
subject :provider do
|
28
|
+
# the account is travis-test@testfairy.com
|
29
|
+
described_class.new(context, :api_key => '4b85a2c03ba6026f4e22640a0432638180e1d1ea', :storepass => "android", :alias => "androiddebugkey", :keystore_file => @kyestore, :video => "true", :video_quality => 'low')
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#check_auth" do
|
33
|
+
example "check_auth without app_file" do
|
34
|
+
lambda {provider.check_auth}.should raise_error
|
35
|
+
end
|
36
|
+
|
37
|
+
example "check_auth with app_file" do
|
38
|
+
provider.options.update(:app_file => @local_android_app)
|
39
|
+
provider.check_auth
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "#needs_key?" do
|
44
|
+
example do
|
45
|
+
expect(provider.needs_key?).to eq(false)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "#push_app" do
|
50
|
+
before do
|
51
|
+
context.stub(:env) { {'ANDROID_HOME' => '/tmp/android', 'JAVA_HOME' => '/usr/bin'} }
|
52
|
+
end
|
53
|
+
|
54
|
+
example "push_app without app_file" do
|
55
|
+
lambda {provider.push_app}.should raise_error
|
56
|
+
end
|
57
|
+
|
58
|
+
example "push_app with app_file" do
|
59
|
+
provider.options.update(:app_file => @local_android_app)
|
60
|
+
provider.push_app
|
61
|
+
end
|
62
|
+
|
63
|
+
example "push_app with wrong alias" do
|
64
|
+
provider.options.update(:app_file => @local_android_app)
|
65
|
+
provider.options.update(:alias => 'test')
|
66
|
+
lambda {provider.push_app}.should raise_error
|
67
|
+
end
|
68
|
+
|
69
|
+
example "push_app with wrong storepass" do
|
70
|
+
provider.options.update(:app_file => @local_android_app)
|
71
|
+
provider.options.update(:storepass => 'test')
|
72
|
+
lambda {provider.push_app}.should raise_error
|
73
|
+
end
|
74
|
+
|
75
|
+
example "push_app with iOS app_file" do
|
76
|
+
provider.options.update(:app_file => @local_ios_app)
|
77
|
+
provider.push_app
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dpl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.7.12.travis.
|
4
|
+
version: 1.7.12.travis.748.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Konstantin Haase
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-04-
|
11
|
+
date: 2015-04-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -136,6 +136,7 @@ files:
|
|
136
136
|
- lib/dpl/provider/releases.rb
|
137
137
|
- lib/dpl/provider/rubygems.rb
|
138
138
|
- lib/dpl/provider/s3.rb
|
139
|
+
- lib/dpl/provider/testfairy.rb
|
139
140
|
- lib/dpl/version.rb
|
140
141
|
- notes/dotcloud.md
|
141
142
|
- notes/engine_yard.md
|
@@ -172,6 +173,7 @@ files:
|
|
172
173
|
- spec/provider/releases_spec.rb
|
173
174
|
- spec/provider/rubygems_spec.rb
|
174
175
|
- spec/provider/s3_spec.rb
|
176
|
+
- spec/provider/testfairy_spec.rb
|
175
177
|
- spec/provider_spec.rb
|
176
178
|
- spec/spec_helper.rb
|
177
179
|
homepage: https://github.com/travis-ci/dpl
|