fastlane-plugin-saucectl 0.1.3.pre → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,318 @@
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
+ FastlaneCore::ConfigItem.new(key: :test_class,
80
+ description: "Array of tests to execute",
81
+ optional: true,
82
+ type: Array),
83
+ FastlaneCore::ConfigItem.new(key: :size,
84
+ description: "Instructs saucectl to run only tests that are annotated with the matching size value i.e @SmallTest, @MediumTest or @LargeTest. Valid values are small, medium, or large. You may only specify one value for this property",
85
+ optional: true,
86
+ type: String),
87
+ FastlaneCore::ConfigItem.new(key: :annotation,
88
+ description: "Instructs saucectl to run only tests that match a custom annotation that you have set",
89
+ optional: true,
90
+ type: String),
91
+ FastlaneCore::ConfigItem.new(key: :emulators,
92
+ description: "The parent property that defines details for running this suite on virtual devices using an emulator",
93
+ optional: true,
94
+ type: Array,
95
+ verify_block: proc do |emulators|
96
+ emulators.each do |emulator|
97
+ if emulator.class != Hash
98
+ UI.user_error!("Each emulator must be represented by a Hash object, #{emulator.class} found")
99
+ end
100
+ verify_device_property(emulator, :name)
101
+ set_default_property(emulator, :orientation, 'portrait')
102
+ verify_device_property(emulator, :platform_versions)
103
+ end
104
+ end),
105
+ FastlaneCore::ConfigItem.new(key: :devices,
106
+ description: "The parent property that defines details for running this suite on real devices",
107
+ optional: true,
108
+ type: Array,
109
+ verify_block: proc do |devices|
110
+ devices.each do |device|
111
+ if device.class != Hash
112
+ UI.user_error!("Each device must be represented by a Hash object, #{device.class} found")
113
+ end
114
+ verify_optional_device_props(device)
115
+ set_default_property(device, :orientation, 'portrait')
116
+ set_default_property(device, :device_type, 'phone')
117
+ set_default_property(device, :private, true)
118
+ set_default_property(device, :carrier_connectivity, false)
119
+ end
120
+ end),
121
+ FastlaneCore::ConfigItem.new(key: :name,
122
+ description: "The name of the device or emulator",
123
+ optional: true,
124
+ type: String),
125
+ FastlaneCore::ConfigItem.new(key: :id,
126
+ description: "The id of the device",
127
+ optional: true,
128
+ type: String),
129
+ FastlaneCore::ConfigItem.new(key: :platform_versions,
130
+ description: "Platform versions of the virtual device you wish to test your application on: Virtual Device only",
131
+ optional: true,
132
+ type: Array),
133
+ FastlaneCore::ConfigItem.new(key: :platform_version,
134
+ description: "Platform version of the real device you wish to test your application on: Real device only",
135
+ optional: true,
136
+ type: String),
137
+ FastlaneCore::ConfigItem.new(key: :orientation,
138
+ description: "The orientation of the device. Default: portrait",
139
+ optional: true,
140
+ type: String,
141
+ default_value: 'portrait'),
142
+ FastlaneCore::ConfigItem.new(key: :device_type,
143
+ description: "Request that the matching device is a specific type of device. Valid values are: ANY TABLET PHONE any tablet phone",
144
+ optional: true,
145
+ type: String,
146
+ default_value: 'phone'),
147
+ FastlaneCore::ConfigItem.new(key: :private,
148
+ description: "Request that the matching device is from your organization's private pool",
149
+ optional: true,
150
+ is_string: false),
151
+ FastlaneCore::ConfigItem.new(key: :carrier_connectivity,
152
+ description: "Request that the matching device is also connected to a cellular network",
153
+ optional: true,
154
+ is_string: false),
155
+ FastlaneCore::ConfigItem.new(key: :test_target,
156
+ description: "Name of the Xcode test target name",
157
+ optional: true,
158
+ type: String),
159
+ FastlaneCore::ConfigItem.new(key: :test_plan,
160
+ description: "Name of the Xcode test plan",
161
+ optional: true,
162
+ type: String),
163
+ FastlaneCore::ConfigItem.new(key: :path_to_tests,
164
+ description: "Path to your espresso tests",
165
+ optional: true,
166
+ type: String),
167
+ FastlaneCore::ConfigItem.new(key: :clear_data,
168
+ description: "Clear package data from device (android only)",
169
+ optional: true,
170
+ is_string: false,
171
+ default_value: true),
172
+ FastlaneCore::ConfigItem.new(key: :use_test_orchestrator,
173
+ description: "User Android test orchestrator (android only)",
174
+ optional: true,
175
+ is_string: false,
176
+ default_value: true),
177
+ FastlaneCore::ConfigItem.new(key: :max_concurrency_size,
178
+ 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",
179
+ optional: true,
180
+ type: Integer,
181
+ default_value: 1)
182
+ ]
183
+ end
184
+
185
+ def self.verify_device_property(device, property)
186
+ UI.user_error!("Each device must have #{property} property") unless device.key?(property)
187
+ end
188
+
189
+ def self.verify_optional_device_props(device)
190
+ unless device.key?(:name) || device.key?(:id)
191
+ UI.user_error!("Real devices must have a device name or device id")
192
+ end
193
+ end
194
+
195
+ private_class_method :verify_device_property
196
+
197
+ def self.set_default_property(device, property, default)
198
+ unless device.key?(property)
199
+ device[property] = default
200
+ end
201
+ end
202
+
203
+ private_class_method :set_default_property
204
+
205
+ def self.authors
206
+ ["Ian Hamilton"]
207
+ end
208
+
209
+ def self.category
210
+ :testing
211
+ end
212
+
213
+ def self.is_supported?(platform)
214
+ [:ios, :android].include?(platform)
215
+ end
216
+
217
+ def self.example_code
218
+ [
219
+ "sauce_config({platform: 'android',
220
+ kind: 'espresso',
221
+ app: 'path/to/myTestApp.apk',
222
+ test_app: 'path/to/myTestRunner.apk',
223
+ path_to_tests: 'path/to/app/src/androidTest',
224
+ region: 'eu',
225
+ emulators: [ {name: 'Android GoogleApi Emulator', platform_versions: %w[10.0 11.0], orientation: 'portrait'}]
226
+ })",
227
+ "sauce_config({platform: 'android',
228
+ kind: 'espresso',
229
+ app: 'path/to/myTestApp.apk',
230
+ test_app: 'path/to/myTestRunner.apk',
231
+ path_to_tests: 'path/to/app/src/androidTest',
232
+ region: 'eu',
233
+ test_distribution: 'testCase',
234
+ devices: [ {name: 'RDC One', orientation: 'portrait', platform_version: '11.0'}]
235
+ })",
236
+ "sauce_config({platform: 'android',
237
+ kind: 'espresso',
238
+ app: 'path/to/myTestApp.apk',
239
+ test_app: 'path/to/myTestRunner.apk',
240
+ path_to_tests: 'path/to/app/src/androidTest',
241
+ region: 'eu',
242
+ test_distribution: 'shard',
243
+ devices: [ {name: 'RDC One', orientation: 'portrait', platform_version: '11.0'}]
244
+ })",
245
+ "sauce_config({platform: 'ios',
246
+ kind: 'xcuitest',
247
+ app: 'path/to/MyTestApp.ipa',
248
+ test_app: 'path/to/MyTestAppRunner.ipa',
249
+ region: 'eu',
250
+ devices: [ {name: 'iPhone RDC One'}, {id: 'iphone_rdc_two'} ],
251
+ test_target: 'MyDemoAppUITests'
252
+ })",
253
+ "sauce_config({platform: 'ios',
254
+ kind: 'xcuitest',
255
+ app: 'path/to/MyTestApp.ipa',
256
+ test_app: 'path/to/MyTestAppRunner.ipa',
257
+ region: 'eu',
258
+ devices: [ {name: 'iPhone RDC One'}, {id: 'iphone_rdc_two'} ],
259
+ test_target: 'MyDemoAppUITests',
260
+ test_distribution: 'shard',
261
+ })",
262
+ " sauce_config({platform: 'ios',
263
+ kind: 'xcuitest',
264
+ app: 'path/to/MyTestApp.ipa',
265
+ test_app: 'path/to/MyTestAppRunner.ipa',
266
+ region: 'eu',
267
+ devices: [ {name: 'iPhone RDC One'}, {id: 'iphone_rdc_two'} ],
268
+ test_target: 'MyDemoAppUITests',
269
+ test_distribution: 'testCase'
270
+ })",
271
+ "sauce_config({platform: 'ios',
272
+ kind: 'xcuitest',
273
+ app: 'path/to/MyTestApp.ipa',
274
+ test_app: 'path/to/MyTestAppRunner.ipa',
275
+ region: 'eu',
276
+ devices: [ {name: 'iPhone RDC One'}, {id: 'iphone_rdc_two'} ],
277
+ test_plan: 'EnabledUITests',
278
+ test_distribution: 'shard'
279
+ })",
280
+ "sauce_config({platform: 'ios',
281
+ kind: 'xcuitest',
282
+ app: 'path/to/MyTestApp.ipa',
283
+ test_app: 'path/to/MyTestAppRunner.ipa',
284
+ region: 'eu',
285
+ devices: [ {name: 'iPhone RDC One'}, {id: 'iphone_rdc_two'} ],
286
+ test_plan: 'UITests'
287
+ })",
288
+ "sauce_config({platform: 'android',
289
+ kind: 'espresso',
290
+ app: 'path/to/myTestApp.apk',
291
+ test_app: 'path/to/myTestRunner.apk',
292
+ path_to_tests: 'path/to/app/src/androidTest',
293
+ region: 'eu',
294
+ devices: [ {name: 'iPhone RDC One'}],
295
+ test_class: ['com.some.package.testing.SomeClassOne', 'com.some.package.testing.SomeClassTwo', 'com.some.package.testing.SomeClassThree', 'com.some.package.testing.SomeClassFour']
296
+ })",
297
+ "sauce_config({platform: 'android',
298
+ kind: 'espresso',
299
+ app: 'path/to/myTestApp.apk',
300
+ test_app: 'path/to/myTestRunner.apk',
301
+ path_to_tests: 'path/to/app/src/androidTest',
302
+ region: 'eu',
303
+ emulators: [ {name: 'iPhone RDC One', platform_versions: ['11.0']}, {name: 'iPhone RDC Two', platform_versions: ['11.0']}],
304
+ test_class: ['com.some.package.testing.SomeClassOne', 'com.some.package.testing.SomeClassTwo', 'com.some.package.testing.SomeClassThree', 'com.some.package.testing.SomeClassFour']
305
+ })",
306
+ "sauce_config({platform: 'ios',
307
+ kind: 'xcuitest',
308
+ app: 'path/to/myTestApp.app',
309
+ test_app: 'path/to/myTestRunner.app',
310
+ region: 'eu',
311
+ devices: [ {name: 'iPhone RDC One'}],
312
+ test_class: ['MyDemoAppUITests.SomeClassOne', 'MyDemoAppUITests.SomeClassTwo', 'MyDemoAppUITests.SomeClassThree', 'MyDemoAppUITests.SomeClassFour']
313
+ })"
314
+ ]
315
+ end
316
+ end
317
+ end
318
+ 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