fastlane-plugin-saucectl 0.1.3.pre → 0.1.4.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +21 -0
- data/README.md +80 -0
- data/lib/fastlane/plugin/saucectl/actions/delete_from_storage_action.rb +96 -0
- data/lib/fastlane/plugin/saucectl/actions/disabled_tests_action.rb +90 -0
- data/lib/fastlane/plugin/saucectl/actions/install_saucectl_action.rb +34 -0
- data/lib/fastlane/plugin/saucectl/actions/sauce_apps_action.rb +96 -0
- data/lib/fastlane/plugin/saucectl/actions/sauce_config_action.rb +312 -0
- data/lib/fastlane/plugin/saucectl/actions/sauce_devices_action.rb +95 -0
- data/lib/fastlane/plugin/saucectl/actions/sauce_runner_action.rb +56 -0
- data/lib/fastlane/plugin/saucectl/actions/sauce_upload_action.rb +133 -0
- data/lib/fastlane/plugin/saucectl/helper/api.rb +115 -0
- data/lib/fastlane/plugin/saucectl/helper/config.rb +97 -0
- data/lib/fastlane/plugin/saucectl/helper/espresso.rb +93 -0
- data/lib/fastlane/plugin/saucectl/helper/file_utils.rb +27 -0
- data/lib/fastlane/plugin/saucectl/helper/installer.rb +51 -0
- data/lib/fastlane/plugin/saucectl/helper/runner.rb +36 -0
- data/lib/fastlane/plugin/saucectl/helper/storage.rb +46 -0
- data/lib/fastlane/plugin/saucectl/helper/suites.rb +201 -0
- data/lib/fastlane/plugin/saucectl/helper/xctest.rb +168 -0
- data/lib/fastlane/plugin/saucectl/strings/messages.yml +12 -0
- data/lib/fastlane/plugin/saucectl/version.rb +5 -0
- data/lib/fastlane/plugin/saucectl.rb +17 -0
- metadata +24 -2
@@ -0,0 +1,312 @@
|
|
1
|
+
require 'fastlane/action'
|
2
|
+
require 'json'
|
3
|
+
require 'yaml'
|
4
|
+
require_relative '../helper/config'
|
5
|
+
require_relative '../helper/runner'
|
6
|
+
|
7
|
+
module Fastlane
|
8
|
+
module Actions
|
9
|
+
class SauceConfigAction < Action
|
10
|
+
@messages = YAML.load_file("#{__dir__}/../strings/messages.yml")
|
11
|
+
|
12
|
+
def self.run(params)
|
13
|
+
if params[:platform].eql?('android')
|
14
|
+
UI.user_error!("❌ For android platform you must specify devices or emulators under test in order to execute tests") if params[:emulators].nil? && params[:devices].nil?
|
15
|
+
else
|
16
|
+
if params[:emulators]
|
17
|
+
UI.user_error!("❌ Sauce Labs platform does not currently support virtual device execution for ios apps")
|
18
|
+
end
|
19
|
+
UI.user_error!("❌ For ios platform you must specify devices under test in order to execute tests") if params[:devices].nil?
|
20
|
+
end
|
21
|
+
|
22
|
+
Fastlane::Saucectl::ConfigGenerator.new(params).create
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.description
|
26
|
+
"Create SauceLabs configuration file for test execution based on given parameters"
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.details
|
30
|
+
"Create SauceLabs configuration file for test execution based on given parameters"
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.available_options
|
34
|
+
[
|
35
|
+
FastlaneCore::ConfigItem.new(key: :platform,
|
36
|
+
description: "application under test platform (ios or android)",
|
37
|
+
optional: false,
|
38
|
+
type: String,
|
39
|
+
verify_block: proc do |value|
|
40
|
+
UI.user_error!(@messages['platform_error']) if value.to_s.empty?
|
41
|
+
end),
|
42
|
+
FastlaneCore::ConfigItem.new(key: :kind,
|
43
|
+
description: "Specifies which framework is associated with the automation tests configured in this specification (xcuitest & espresso)",
|
44
|
+
optional: false,
|
45
|
+
type: String,
|
46
|
+
verify_block: proc do |value|
|
47
|
+
UI.user_error!(@messages['platform_error']) if value.to_s.empty?
|
48
|
+
end),
|
49
|
+
FastlaneCore::ConfigItem.new(key: :app,
|
50
|
+
description: "The path to the app",
|
51
|
+
optional: false,
|
52
|
+
type: String,
|
53
|
+
verify_block: proc do |value|
|
54
|
+
UI.user_error!(@messages['app_name_error']) unless value && !value.empty?
|
55
|
+
end),
|
56
|
+
FastlaneCore::ConfigItem.new(key: :test_app,
|
57
|
+
description: "The path to the testing app",
|
58
|
+
optional: false,
|
59
|
+
is_string: true,
|
60
|
+
verify_block: proc do |value|
|
61
|
+
UI.user_error!(@messages['test_runner_app_error']) unless value && !value.empty?
|
62
|
+
end),
|
63
|
+
FastlaneCore::ConfigItem.new(key: :region,
|
64
|
+
description: "Data Center region (us or eu), set using: region: 'eu'",
|
65
|
+
optional: false,
|
66
|
+
type: String,
|
67
|
+
verify_block: proc do |value|
|
68
|
+
UI.user_error!(@messages['region_error'].gsub!('$region', value)) unless @messages['supported_regions'].include?(value)
|
69
|
+
end),
|
70
|
+
FastlaneCore::ConfigItem.new(key: :retries,
|
71
|
+
description: "Sets the number of times to retry a failed suite",
|
72
|
+
optional: true,
|
73
|
+
type: Integer,
|
74
|
+
default_value: 0),
|
75
|
+
FastlaneCore::ConfigItem.new(key: :test_distribution,
|
76
|
+
description: "Test distribution method",
|
77
|
+
optional: true,
|
78
|
+
type: String,
|
79
|
+
default_value: 'class'),
|
80
|
+
FastlaneCore::ConfigItem.new(key: :test_class,
|
81
|
+
description: "Array of tests to execute",
|
82
|
+
optional: true,
|
83
|
+
type: Array),
|
84
|
+
FastlaneCore::ConfigItem.new(key: :emulators,
|
85
|
+
description: "The parent property that defines details for running this suite on virtual devices using an emulator",
|
86
|
+
optional: true,
|
87
|
+
type: Array,
|
88
|
+
verify_block: proc do |emulators|
|
89
|
+
emulators.each do |emulator|
|
90
|
+
if emulator.class != Hash
|
91
|
+
UI.user_error!("Each emulator must be represented by a Hash object, #{emulator.class} found")
|
92
|
+
end
|
93
|
+
verify_device_property(emulator, :name)
|
94
|
+
set_default_property(emulator, :orientation, 'portrait')
|
95
|
+
verify_device_property(emulator, :platform_versions)
|
96
|
+
end
|
97
|
+
end),
|
98
|
+
FastlaneCore::ConfigItem.new(key: :devices,
|
99
|
+
description: "The parent property that defines details for running this suite on real devices",
|
100
|
+
optional: true,
|
101
|
+
type: Array,
|
102
|
+
verify_block: proc do |devices|
|
103
|
+
devices.each do |device|
|
104
|
+
if device.class != Hash
|
105
|
+
UI.user_error!("Each device must be represented by a Hash object, #{device.class} found")
|
106
|
+
end
|
107
|
+
verify_optional_device_props(device)
|
108
|
+
set_default_property(device, :orientation, 'portrait')
|
109
|
+
set_default_property(device, :device_type, 'phone')
|
110
|
+
set_default_property(device, :private, true)
|
111
|
+
set_default_property(device, :carrier_connectivity, false)
|
112
|
+
end
|
113
|
+
end),
|
114
|
+
FastlaneCore::ConfigItem.new(key: :name,
|
115
|
+
description: "The name of the device or emulator",
|
116
|
+
optional: true,
|
117
|
+
type: String),
|
118
|
+
FastlaneCore::ConfigItem.new(key: :id,
|
119
|
+
description: "The id of the device",
|
120
|
+
optional: true,
|
121
|
+
type: String),
|
122
|
+
FastlaneCore::ConfigItem.new(key: :platform_versions,
|
123
|
+
description: "Platform versions of the virtual device you wish to test your application on: Virtual Device only",
|
124
|
+
optional: true,
|
125
|
+
type: Array),
|
126
|
+
FastlaneCore::ConfigItem.new(key: :platform_version,
|
127
|
+
description: "Platform version of the real device you wish to test your application on: Real device only",
|
128
|
+
optional: true,
|
129
|
+
type: String),
|
130
|
+
FastlaneCore::ConfigItem.new(key: :orientation,
|
131
|
+
description: "The orientation of the device. Default: portrait",
|
132
|
+
optional: true,
|
133
|
+
type: String,
|
134
|
+
default_value: 'portrait'),
|
135
|
+
FastlaneCore::ConfigItem.new(key: :device_type,
|
136
|
+
description: "Request that the matching device is a specific type of device. Valid values are: ANY TABLET PHONE any tablet phone",
|
137
|
+
optional: true,
|
138
|
+
type: String,
|
139
|
+
default_value: 'phone'),
|
140
|
+
FastlaneCore::ConfigItem.new(key: :private,
|
141
|
+
description: "Request that the matching device is from your organization's private pool",
|
142
|
+
optional: true,
|
143
|
+
is_string: false),
|
144
|
+
FastlaneCore::ConfigItem.new(key: :carrier_connectivity,
|
145
|
+
description: "Request that the matching device is also connected to a cellular network",
|
146
|
+
optional: true,
|
147
|
+
is_string: false),
|
148
|
+
FastlaneCore::ConfigItem.new(key: :test_target,
|
149
|
+
description: "Name of the Xcode test target name",
|
150
|
+
optional: true,
|
151
|
+
type: String),
|
152
|
+
FastlaneCore::ConfigItem.new(key: :test_plan,
|
153
|
+
description: "Name of the Xcode test plan",
|
154
|
+
optional: true,
|
155
|
+
type: String),
|
156
|
+
FastlaneCore::ConfigItem.new(key: :path_to_tests,
|
157
|
+
description: "Path to your espresso tests",
|
158
|
+
optional: true,
|
159
|
+
type: String,
|
160
|
+
default_value: "#{Dir.pwd}/app/src/androidTest"),
|
161
|
+
FastlaneCore::ConfigItem.new(key: :clear_data,
|
162
|
+
description: "Clear package data from device (android only)",
|
163
|
+
optional: true,
|
164
|
+
is_string: false,
|
165
|
+
default_value: true),
|
166
|
+
FastlaneCore::ConfigItem.new(key: :use_test_orchestrator,
|
167
|
+
description: "User Android test orchestrator (android only)",
|
168
|
+
optional: true,
|
169
|
+
is_string: false,
|
170
|
+
default_value: true),
|
171
|
+
FastlaneCore::ConfigItem.new(key: :max_concurrency_size,
|
172
|
+
description: "Sets the maximum number of suites to execute at the same time. If the test defines more suites than the max, excess suites are queued and run in order as each suite completes",
|
173
|
+
optional: true,
|
174
|
+
type: Integer,
|
175
|
+
default_value: 1)
|
176
|
+
]
|
177
|
+
end
|
178
|
+
|
179
|
+
def self.verify_device_property(device, property)
|
180
|
+
UI.user_error!("Each device must have #{property} property") unless device.key?(property)
|
181
|
+
end
|
182
|
+
|
183
|
+
def self.verify_optional_device_props(device)
|
184
|
+
unless device.key?(:name) || device.key?(:id)
|
185
|
+
UI.user_error!("Real devices must have a device name or device id")
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
private_class_method :verify_device_property
|
190
|
+
|
191
|
+
def self.set_default_property(device, property, default)
|
192
|
+
unless device.key?(property)
|
193
|
+
device[property] = default
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
private_class_method :set_default_property
|
198
|
+
|
199
|
+
def self.authors
|
200
|
+
["Ian Hamilton"]
|
201
|
+
end
|
202
|
+
|
203
|
+
def self.category
|
204
|
+
:testing
|
205
|
+
end
|
206
|
+
|
207
|
+
def self.is_supported?(platform)
|
208
|
+
[:ios, :android].include?(platform)
|
209
|
+
end
|
210
|
+
|
211
|
+
def self.example_code
|
212
|
+
[
|
213
|
+
"sauce_config({platform: 'android',
|
214
|
+
kind: 'espresso',
|
215
|
+
app: 'path/to/myTestApp.apk',
|
216
|
+
test_app: 'path/to/myTestRunner.apk',
|
217
|
+
path_to_tests: 'path/to/app/src/androidTest',
|
218
|
+
region: 'eu',
|
219
|
+
emulators: [ {name: 'Android GoogleApi Emulator', platform_versions: %w[10.0 11.0], orientation: 'portrait'}]
|
220
|
+
})",
|
221
|
+
"sauce_config({platform: 'android',
|
222
|
+
kind: 'espresso',
|
223
|
+
app: 'path/to/myTestApp.apk',
|
224
|
+
test_app: 'path/to/myTestRunner.apk',
|
225
|
+
path_to_tests: 'path/to/app/src/androidTest',
|
226
|
+
region: 'eu',
|
227
|
+
test_distribution: 'testCase',
|
228
|
+
devices: [ {name: 'RDC One', orientation: 'portrait', platform_version: '11.0'}]
|
229
|
+
})",
|
230
|
+
"sauce_config({platform: 'android',
|
231
|
+
kind: 'espresso',
|
232
|
+
app: 'path/to/myTestApp.apk',
|
233
|
+
test_app: 'path/to/myTestRunner.apk',
|
234
|
+
path_to_tests: 'path/to/app/src/androidTest',
|
235
|
+
region: 'eu',
|
236
|
+
test_distribution: 'shard',
|
237
|
+
devices: [ {name: 'RDC One', orientation: 'portrait', platform_version: '11.0'}]
|
238
|
+
})",
|
239
|
+
"sauce_config({platform: 'ios',
|
240
|
+
kind: 'xcuitest',
|
241
|
+
app: 'path/to/MyTestApp.ipa',
|
242
|
+
test_app: 'path/to/MyTestAppRunner.ipa',
|
243
|
+
region: 'eu',
|
244
|
+
devices: [ {name: 'iPhone RDC One'}, {id: 'iphone_rdc_two'} ],
|
245
|
+
test_target: 'MyDemoAppUITests'
|
246
|
+
})",
|
247
|
+
"sauce_config({platform: 'ios',
|
248
|
+
kind: 'xcuitest',
|
249
|
+
app: 'path/to/MyTestApp.ipa',
|
250
|
+
test_app: 'path/to/MyTestAppRunner.ipa',
|
251
|
+
region: 'eu',
|
252
|
+
devices: [ {name: 'iPhone RDC One'}, {id: 'iphone_rdc_two'} ],
|
253
|
+
test_target: 'MyDemoAppUITests',
|
254
|
+
test_distribution: 'shard',
|
255
|
+
})",
|
256
|
+
" sauce_config({platform: 'ios',
|
257
|
+
kind: 'xcuitest',
|
258
|
+
app: 'path/to/MyTestApp.ipa',
|
259
|
+
test_app: 'path/to/MyTestAppRunner.ipa',
|
260
|
+
region: 'eu',
|
261
|
+
devices: [ {name: 'iPhone RDC One'}, {id: 'iphone_rdc_two'} ],
|
262
|
+
test_target: 'MyDemoAppUITests',
|
263
|
+
test_distribution: 'testCase'
|
264
|
+
})",
|
265
|
+
"sauce_config({platform: 'ios',
|
266
|
+
kind: 'xcuitest',
|
267
|
+
app: 'path/to/MyTestApp.ipa',
|
268
|
+
test_app: 'path/to/MyTestAppRunner.ipa',
|
269
|
+
region: 'eu',
|
270
|
+
devices: [ {name: 'iPhone RDC One'}, {id: 'iphone_rdc_two'} ],
|
271
|
+
test_plan: 'EnabledUITests',
|
272
|
+
test_distribution: 'shard'
|
273
|
+
})",
|
274
|
+
"sauce_config({platform: 'ios',
|
275
|
+
kind: 'xcuitest',
|
276
|
+
app: 'path/to/MyTestApp.ipa',
|
277
|
+
test_app: 'path/to/MyTestAppRunner.ipa',
|
278
|
+
region: 'eu',
|
279
|
+
devices: [ {name: 'iPhone RDC One'}, {id: 'iphone_rdc_two'} ],
|
280
|
+
test_plan: 'UITests'
|
281
|
+
})",
|
282
|
+
"sauce_config({platform: 'android',
|
283
|
+
kind: 'espresso',
|
284
|
+
app: 'path/to/myTestApp.apk',
|
285
|
+
test_app: 'path/to/myTestRunner.apk',
|
286
|
+
path_to_tests: 'path/to/app/src/androidTest',
|
287
|
+
region: 'eu',
|
288
|
+
devices: [ {name: 'iPhone RDC One'}],
|
289
|
+
test_class: ['com.some.package.testing.SomeClassOne', 'com.some.package.testing.SomeClassTwo', 'com.some.package.testing.SomeClassThree', 'com.some.package.testing.SomeClassFour']
|
290
|
+
})",
|
291
|
+
"sauce_config({platform: 'android',
|
292
|
+
kind: 'espresso',
|
293
|
+
app: 'path/to/myTestApp.apk',
|
294
|
+
test_app: 'path/to/myTestRunner.apk',
|
295
|
+
path_to_tests: 'path/to/app/src/androidTest',
|
296
|
+
region: 'eu',
|
297
|
+
emulators: [ {name: 'iPhone RDC One', platform_versions: ['11.0']}, {name: 'iPhone RDC Two', platform_versions: ['11.0']}],
|
298
|
+
test_class: ['com.some.package.testing.SomeClassOne', 'com.some.package.testing.SomeClassTwo', 'com.some.package.testing.SomeClassThree', 'com.some.package.testing.SomeClassFour']
|
299
|
+
})",
|
300
|
+
"sauce_config({platform: 'ios',
|
301
|
+
kind: 'xcuitest',
|
302
|
+
app: 'path/to/myTestApp.app',
|
303
|
+
test_app: 'path/to/myTestRunner.app',
|
304
|
+
region: 'eu',
|
305
|
+
devices: [ {name: 'iPhone RDC One'}],
|
306
|
+
test_class: ['MyDemoAppUITests.SomeClassOne', 'MyDemoAppUITests.SomeClassTwo', 'MyDemoAppUITests.SomeClassThree', 'MyDemoAppUITests.SomeClassFour']
|
307
|
+
})"
|
308
|
+
]
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'fastlane/action'
|
2
|
+
require_relative '../helper/api'
|
3
|
+
|
4
|
+
module Fastlane
|
5
|
+
module Actions
|
6
|
+
class SauceDevicesAction < Action
|
7
|
+
@messages = YAML.load_file("#{__dir__}/../strings/messages.yml")
|
8
|
+
|
9
|
+
def self.run(params)
|
10
|
+
platform = params[:platform]
|
11
|
+
case platform
|
12
|
+
when 'android'
|
13
|
+
Fastlane::Saucectl::Api.new(params).fetch_android_devices
|
14
|
+
when 'ios'
|
15
|
+
Fastlane::Saucectl::Api.new(params).fetch_ios_devices
|
16
|
+
else
|
17
|
+
Fastlane::Saucectl::Api.new(params).available_devices
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.description
|
22
|
+
"Returns a list of Device IDs for all devices in the data center that are currently free for testing."
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.details
|
26
|
+
"Returns a list of Device IDs for all devices in the data center that are currently free for testing."
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.available_options
|
30
|
+
[
|
31
|
+
FastlaneCore::ConfigItem.new(key: :platform,
|
32
|
+
description: "Device platform that you wish to query",
|
33
|
+
optional: true,
|
34
|
+
is_string: true,
|
35
|
+
default_value: ''),
|
36
|
+
FastlaneCore::ConfigItem.new(key: :region,
|
37
|
+
description: "Data Center region (us or eu), set using: region: 'eu'",
|
38
|
+
optional: false,
|
39
|
+
type: String,
|
40
|
+
verify_block: proc do |value|
|
41
|
+
UI.user_error!(@messages['region_error'].gsub!('$region', value)) unless @messages['supported_regions'].include?(value)
|
42
|
+
end),
|
43
|
+
FastlaneCore::ConfigItem.new(key: :sauce_username,
|
44
|
+
env_name: "SAUCE_USERNAME",
|
45
|
+
description: "Your sauce labs username in order to authenticate upload requests",
|
46
|
+
default_value: Actions.lane_context[SharedValues::SAUCE_USERNAME],
|
47
|
+
optional: false,
|
48
|
+
type: String,
|
49
|
+
verify_block: proc do |value|
|
50
|
+
UI.user_error!(@messages['sauce_username_error']) unless value && !value.empty?
|
51
|
+
end),
|
52
|
+
FastlaneCore::ConfigItem.new(key: :sauce_access_key,
|
53
|
+
env_name: "SAUCE_ACCESS_KEY",
|
54
|
+
description: "Your sauce labs access key in order to authenticate upload requests",
|
55
|
+
default_value: Actions.lane_context[SharedValues::SAUCE_ACCESS_KEY],
|
56
|
+
optional: false,
|
57
|
+
type: String,
|
58
|
+
verify_block: proc do |value|
|
59
|
+
UI.user_error!(@messages['sauce_api_key_error']) unless value && !value.empty?
|
60
|
+
end)
|
61
|
+
]
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.authors
|
65
|
+
["Ian Hamilton"]
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.category
|
69
|
+
:testing
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.is_supported?(platform)
|
73
|
+
[:ios, :android].include?(platform)
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.example_code
|
77
|
+
[
|
78
|
+
"sauce_devices({platform: 'android',
|
79
|
+
region: 'eu',
|
80
|
+
sauce_username: 'foo',
|
81
|
+
sauce_access_key: 'bar123',
|
82
|
+
})",
|
83
|
+
"sauce_devices({region: 'eu',
|
84
|
+
sauce_username: 'foo',
|
85
|
+
sauce_access_key: 'bar123',
|
86
|
+
})",
|
87
|
+
"sauce_devices({region: 'us',
|
88
|
+
sauce_username: 'foo',
|
89
|
+
sauce_access_key: 'bar123',
|
90
|
+
})"
|
91
|
+
]
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require_relative '../helper/runner'
|
2
|
+
|
3
|
+
module Fastlane
|
4
|
+
module Actions
|
5
|
+
class SauceRunnerAction < Action
|
6
|
+
@messages = YAML.load_file("#{__dir__}/../strings/messages.yml")
|
7
|
+
|
8
|
+
def self.run(run = '')
|
9
|
+
Saucectl::Runner.new.execute
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.description
|
13
|
+
"Execute automated tests on sauce labs platform via saucectl binary for specified configuration"
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.details
|
17
|
+
"Execute automated tests on sauce labs platform via saucectl binary for specified configuration"
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.available_options
|
21
|
+
[
|
22
|
+
FastlaneCore::ConfigItem.new(key: :sauce_username,
|
23
|
+
env_name: "SAUCE_USERNAME",
|
24
|
+
default_value: Actions.lane_context[SharedValues::SAUCE_USERNAME],
|
25
|
+
description: "Your sauce labs username",
|
26
|
+
optional: false,
|
27
|
+
is_string: true,
|
28
|
+
verify_block: proc do |value|
|
29
|
+
UI.user_error!(@messages['sauce_username_error']) if value.empty?
|
30
|
+
end),
|
31
|
+
FastlaneCore::ConfigItem.new(key: :sauce_access_key,
|
32
|
+
env_name: "SAUCE_ACCESS_KEY",
|
33
|
+
default_value: Actions.lane_context[SharedValues::SAUCE_ACCESS_KEY],
|
34
|
+
description: "Your sauce labs access key",
|
35
|
+
optional: false,
|
36
|
+
is_string: true,
|
37
|
+
verify_block: proc do |value|
|
38
|
+
UI.user_error!(@messages['sauce_api_key_error']) if value.empty?
|
39
|
+
end)
|
40
|
+
]
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.authors
|
44
|
+
["Ian Hamilton"]
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.category
|
48
|
+
:testing
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.is_supported?(platform)
|
52
|
+
[:ios, :android].include?(platform)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'fastlane/action'
|
2
|
+
require 'json'
|
3
|
+
require 'yaml'
|
4
|
+
require_relative '../helper/api'
|
5
|
+
|
6
|
+
module Fastlane
|
7
|
+
module Actions
|
8
|
+
module SharedValues
|
9
|
+
SAUCE_USERNAME = :SAUCE_USERNAME
|
10
|
+
SAUCE_ACCESS_KEY = :SAUCE_ACCESS_KEY
|
11
|
+
end
|
12
|
+
|
13
|
+
class SauceUploadAction < Action
|
14
|
+
@messages = YAML.load_file("#{__dir__}/../strings/messages.yml")
|
15
|
+
|
16
|
+
def self.run(params)
|
17
|
+
response = Fastlane::Saucectl::Api.new(params).upload
|
18
|
+
body = JSON.parse(response.body)
|
19
|
+
body['item']['id']
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.description
|
23
|
+
"Upload test artifacts to sauce labs storage"
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.details
|
27
|
+
"Upload test artifacts to sauce labs storage"
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.available_options
|
31
|
+
[
|
32
|
+
FastlaneCore::ConfigItem.new(key: :platform,
|
33
|
+
description: "application under test platform (ios or android)",
|
34
|
+
optional: false,
|
35
|
+
is_string: true,
|
36
|
+
verify_block: proc do |value|
|
37
|
+
UI.user_error!(@messages['platform_error']) if value.to_s.empty?
|
38
|
+
end),
|
39
|
+
FastlaneCore::ConfigItem.new(key: :file,
|
40
|
+
description: "File to upload to sauce storage",
|
41
|
+
optional: false,
|
42
|
+
is_string: true,
|
43
|
+
verify_block: proc do |value|
|
44
|
+
UI.user_error!(@messages['file_error']) unless value && !value.empty?
|
45
|
+
if value
|
46
|
+
UI.user_error!("Could not find file to upload \"#{value}\" ") unless File.exist?(value)
|
47
|
+
extname = File.extname(value)
|
48
|
+
UI.user_error!("Extension not supported for \"#{value}\" ") unless @messages['accepted_file_types'].include?(extname)
|
49
|
+
end
|
50
|
+
end),
|
51
|
+
FastlaneCore::ConfigItem.new(key: :app,
|
52
|
+
description: "Name of the application to be uploaded",
|
53
|
+
optional: false,
|
54
|
+
is_string: true,
|
55
|
+
verify_block: proc do |value|
|
56
|
+
UI.user_error!(@messages['app_name_error']) unless value && !value.empty?
|
57
|
+
end),
|
58
|
+
FastlaneCore::ConfigItem.new(key: :region,
|
59
|
+
description: "Data Center region (us or eu), set using: region: 'eu'",
|
60
|
+
optional: false,
|
61
|
+
is_string: true,
|
62
|
+
verify_block: proc do |value|
|
63
|
+
UI.user_error!(@messages['region_error'].gsub!('$region', value)) unless @messages['supported_regions'].include?(value)
|
64
|
+
end),
|
65
|
+
FastlaneCore::ConfigItem.new(key: :sauce_username,
|
66
|
+
env_name: "SAUCE_USERNAME",
|
67
|
+
description: "Your sauce labs username in order to authenticate upload requests",
|
68
|
+
default_value: Actions.lane_context[SharedValues::SAUCE_USERNAME],
|
69
|
+
optional: false,
|
70
|
+
type: String,
|
71
|
+
verify_block: proc do |value|
|
72
|
+
UI.user_error!(@messages['sauce_username_error']) unless value && !value.empty?
|
73
|
+
end),
|
74
|
+
FastlaneCore::ConfigItem.new(key: :sauce_access_key,
|
75
|
+
env_name: "SAUCE_ACCESS_KEY",
|
76
|
+
description: "Your sauce labs access key in order to authenticate upload requests",
|
77
|
+
default_value: Actions.lane_context[SharedValues::SAUCE_ACCESS_KEY],
|
78
|
+
optional: false,
|
79
|
+
type: String,
|
80
|
+
verify_block: proc do |value|
|
81
|
+
UI.user_error!(@messages['sauce_api_key_error']) unless value && !value.empty?
|
82
|
+
end)
|
83
|
+
]
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.authors
|
87
|
+
["Ian Hamilton"]
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.category
|
91
|
+
:testing
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.is_supported?(platform)
|
95
|
+
[:ios, :android].include?(platform)
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.example_code
|
99
|
+
[
|
100
|
+
"sauce_upload({
|
101
|
+
platform: 'android',
|
102
|
+
sauce_username: 'username',
|
103
|
+
sauce_access_key: 'accessKey',
|
104
|
+
app: 'Android.MyCustomApp.apk',
|
105
|
+
file: 'app/build/outputs/apk/debug/app-debug.apk',
|
106
|
+
region: 'eu'
|
107
|
+
})",
|
108
|
+
"sauce_upload({
|
109
|
+
platform: 'android',
|
110
|
+
sauce_username: 'username',
|
111
|
+
sauce_access_key: 'accessKey',
|
112
|
+
app: 'Android.MyCustomApp.apk',
|
113
|
+
file: 'app/build/outputs/apk/debug/app-debug.apk',
|
114
|
+
region: 'eu',
|
115
|
+
app_description: 'this is a test description'
|
116
|
+
})",
|
117
|
+
"sauce_upload({
|
118
|
+
platform: 'ios',
|
119
|
+
sauce_username: 'username',
|
120
|
+
sauce_access_key: 'accessKey',
|
121
|
+
app: 'MyTestApp.ipa',
|
122
|
+
file: 'path/to/my/app/MyTestApp.ipa',
|
123
|
+
region: 'eu'
|
124
|
+
})"
|
125
|
+
]
|
126
|
+
end
|
127
|
+
|
128
|
+
def self.return_value
|
129
|
+
"Returns the application id of the app uploaded"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|