fastlane-plugin-appcenter 1.8.1 → 1.9.0
Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 89d582118585c4f375abd0b893ad9648180e33d19308d20c881aea0262356a82
|
4
|
+
data.tar.gz: 57a447973defb5be52cee9ed03a9d635e442cc30b523152b23d0754b63638c14
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3c9c355551542046daffa8383aee7521d9185b76cc4351e494e6645de638a982af60812bb14982ef171707716dce5761d87e98dd9455a2548bde66d3157237db
|
7
|
+
data.tar.gz: c9a7690e05d9251cae36125ab72669bf11733b2fbf25c8d0f15544fe741b9f09e525d924524eb4daccc7056bdd290c06bc68df5f6a72d64558fc225fb4597544
|
data/README.md
CHANGED
@@ -119,7 +119,7 @@ Here is the list of all existing parameters:
|
|
119
119
|
| `release_notes_link` <br/> `APPCENTER_DISTRIBUTE_RELEASE_NOTES_LINK` | Additional release notes link |
|
120
120
|
| `build_number` <br/> `APPCENTER_DISTRIBUTE_BUILD_NUMBER` | The build number, required for macOS .pkg and .dmg builds, as well as Android ProGuard `mapping.txt` when using `upload_mapping_only` |
|
121
121
|
| `version` <br/> `APPCENTER_DISTRIBUTE_VERSION` | The build version, required for .pkg, .dmg, .zip and .msi builds, as well as Android ProGuard `mapping.txt` when using `upload_mapping_only` |
|
122
|
-
| `timeout` <br/> `APPCENTER_DISTRIBUTE_TIMEOUT` | Request timeout in seconds |
|
122
|
+
| `timeout` <br/> `APPCENTER_DISTRIBUTE_TIMEOUT` | Request timeout in seconds applied to individual HTTP requests. Some commands use multiple HTTP requests, large file uploads are also split in multiple HTTP requests |
|
123
123
|
| `dsa_signature` <br/> `APPCENTER_DISTRIBUTE_DSA_SIGNATURE` | DSA signature of the macOS or Windows release for Sparkle update feed |
|
124
124
|
| `strict` <br/> `APPCENTER_STRICT_MODE` | Strict mode, set to 'true' to fail early in case a potential error was detected |
|
125
125
|
|
@@ -9,6 +9,23 @@ module Fastlane
|
|
9
9
|
windows: %w(.appx .appxbundle .appxupload .msix .msixbundle .msixupload .zip .msi),
|
10
10
|
custom: %w(.zip)
|
11
11
|
}
|
12
|
+
CONTENT_TYPES = {
|
13
|
+
apk: "application/vnd.android.package-archive",
|
14
|
+
aab: "application/vnd.android.package-archive",
|
15
|
+
msi: "application/x-msi",
|
16
|
+
plist: "application/xml",
|
17
|
+
aetx: "application/c-x509-ca-cert",
|
18
|
+
cer: "application/pkix-cert",
|
19
|
+
xap: "application/x-silverlight-app",
|
20
|
+
appx: "application/x-appx",
|
21
|
+
appxbundle: "application/x-appxbundle",
|
22
|
+
appxupload: "application/x-appxupload",
|
23
|
+
appxsym: "application/x-appxupload",
|
24
|
+
msix: "application/x-msix",
|
25
|
+
msixbundle: "application/x-msixbundle",
|
26
|
+
msixupload: "application/x-msixupload",
|
27
|
+
msixsym: "application/x-msixupload",
|
28
|
+
}
|
12
29
|
ALL_SUPPORTED_EXTENSIONS = SUPPORTED_EXTENSIONS.values.flatten.sort!.uniq!
|
13
30
|
STORE_ONLY_EXTENSIONS = %w(.aab)
|
14
31
|
STORE_SUPPORTED_EXTENSIONS = %w(.aab .apk .ipa)
|
@@ -186,14 +203,29 @@ module Fastlane
|
|
186
203
|
UI.message("Starting release upload...")
|
187
204
|
upload_details = Helper::AppcenterHelper.create_release_upload(api_token, owner_name, app_name, release_upload_body)
|
188
205
|
if upload_details
|
189
|
-
upload_id = upload_details['
|
190
|
-
|
206
|
+
upload_id = upload_details['id']
|
207
|
+
|
208
|
+
UI.message("Setting Metadata...")
|
209
|
+
content_type = Constants::CONTENT_TYPES[File.extname(file)&.delete('.').downcase.to_sym] || "application/octet-stream"
|
210
|
+
set_metadata_url = "#{upload_details['upload_domain']}/upload/set_metadata/#{upload_details['package_asset_id']}?file_name=#{File.basename(file)}&file_size=#{File.size(file)}&token=#{upload_details['url_encoded_token']}&content_type=#{content_type}"
|
211
|
+
chunk_size = Helper::AppcenterHelper.set_release_upload_metadata(set_metadata_url, api_token, owner_name, app_name, upload_id, timeout)
|
212
|
+
UI.abort_with_message!("Upload aborted") unless chunk_size
|
191
213
|
|
192
214
|
UI.message("Uploading release binary...")
|
193
|
-
|
215
|
+
upload_url = "#{upload_details['upload_domain']}/upload/upload_chunk/#{upload_details['package_asset_id']}?token=#{upload_details['url_encoded_token']}"
|
216
|
+
uploaded = Helper::AppcenterHelper.upload_build(api_token, owner_name, app_name, file, upload_id, upload_url, content_type, chunk_size, timeout)
|
217
|
+
UI.abort_with_message!("Upload aborted") unless uploaded
|
218
|
+
|
219
|
+
UI.message("Finishing release...")
|
220
|
+
finish_url = "#{upload_details['upload_domain']}/upload/finished/#{upload_details['package_asset_id']}?token=#{upload_details['url_encoded_token']}"
|
221
|
+
finished = Helper::AppcenterHelper.finish_release_upload(finish_url, api_token, owner_name, app_name, upload_id, timeout)
|
222
|
+
UI.abort_with_message!("Upload aborted") unless finished
|
194
223
|
|
195
|
-
|
196
|
-
|
224
|
+
UI.message("Waiting for release to be ready...")
|
225
|
+
release_status_url = "v0.1/apps/#{owner_name}/#{app_name}/uploads/releases/#{upload_id}"
|
226
|
+
release_id = Helper::AppcenterHelper.poll_for_release_id(api_token, release_status_url)
|
227
|
+
|
228
|
+
if release_id.is_a? Integer
|
197
229
|
release_url = Helper::AppcenterHelper.get_release_url(owner_type, owner_name, app_name, release_id)
|
198
230
|
UI.message("Release '#{release_id}' committed: #{release_url}")
|
199
231
|
|
@@ -323,7 +355,6 @@ module Fastlane
|
|
323
355
|
release = self.run_release_upload(params) unless upload_dsym_only || upload_mapping_only
|
324
356
|
params[:version] = release['short_version'] if release
|
325
357
|
params[:build_number] = release['version'] if release
|
326
|
-
|
327
358
|
self.run_dsym_upload(params) unless upload_mapping_only || upload_build_only
|
328
359
|
self.run_mapping_upload(params) unless upload_dsym_only || upload_build_only
|
329
360
|
end
|
@@ -603,7 +634,7 @@ module Fastlane
|
|
603
634
|
|
604
635
|
FastlaneCore::ConfigItem.new(key: :timeout,
|
605
636
|
env_name: "APPCENTER_DISTRIBUTE_TIMEOUT",
|
606
|
-
description: "Request timeout in seconds",
|
637
|
+
description: "Request timeout in seconds applied to individual HTTP requests. Some commands use multiple HTTP requests, large file uploads are also split in multiple HTTP requests",
|
607
638
|
optional: true,
|
608
639
|
type: Integer),
|
609
640
|
|
@@ -1,7 +1,22 @@
|
|
1
|
+
class File
|
2
|
+
def each_chunk(chunk_size)
|
3
|
+
yield read(chunk_size) until eof?
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
1
7
|
module Fastlane
|
2
8
|
module Helper
|
3
9
|
class AppcenterHelper
|
4
10
|
|
11
|
+
# Time to wait between 2 status polls in seconds
|
12
|
+
RELEASE_UPLOAD_STATUS_POLL_INTERVAL = 1
|
13
|
+
|
14
|
+
# Maximum number of retries for a request
|
15
|
+
MAX_REQUEST_RETRIES = 2
|
16
|
+
|
17
|
+
# Delay between retries in seconds
|
18
|
+
REQUEST_RETRY_INTERVAL = 5
|
19
|
+
|
5
20
|
# basic utility method to check file types that App Center will accept,
|
6
21
|
# accounting for file types that can and should be zip-compressed
|
7
22
|
# before they are uploaded
|
@@ -22,7 +37,6 @@ module Fastlane
|
|
22
37
|
if ENV['APPCENTER_ENV']&.upcase == 'INT'
|
23
38
|
default_api_url = "https://api-gateway-core-integration.dev.avalanch.es"
|
24
39
|
end
|
25
|
-
|
26
40
|
options = {
|
27
41
|
url: upload_url || default_api_url
|
28
42
|
}
|
@@ -48,13 +62,11 @@ module Fastlane
|
|
48
62
|
# upload_url
|
49
63
|
def self.create_release_upload(api_token, owner_name, app_name, body)
|
50
64
|
connection = self.connection
|
51
|
-
|
52
|
-
url = "v0.1/apps/#{owner_name}/#{app_name}/release_uploads"
|
65
|
+
url = "v0.1/apps/#{owner_name}/#{app_name}/uploads/releases"
|
53
66
|
body ||= {}
|
54
67
|
|
55
68
|
UI.message("DEBUG: POST #{url}") if ENV['DEBUG']
|
56
69
|
UI.message("DEBUG: POST body: #{JSON.pretty_generate(body)}\n") if ENV['DEBUG']
|
57
|
-
|
58
70
|
response = connection.post(url) do |req|
|
59
71
|
req.headers['X-API-Token'] = api_token
|
60
72
|
req.headers['internal-request-source'] = "fastlane"
|
@@ -62,7 +74,6 @@ module Fastlane
|
|
62
74
|
end
|
63
75
|
|
64
76
|
UI.message("DEBUG: #{response.status} #{JSON.pretty_generate(response.body)}\n") if ENV['DEBUG']
|
65
|
-
|
66
77
|
case response.status
|
67
78
|
when 200...300
|
68
79
|
response.body
|
@@ -229,50 +240,141 @@ module Fastlane
|
|
229
240
|
end
|
230
241
|
end
|
231
242
|
|
232
|
-
#
|
233
|
-
#
|
234
|
-
#
|
235
|
-
def self.
|
236
|
-
connection = self.connection(
|
237
|
-
|
238
|
-
options = {}
|
239
|
-
options[:upload_id] = upload_id
|
240
|
-
# ipa field is used for .apk, .aab and .ipa files
|
241
|
-
options[:ipa] = Faraday::UploadIO.new(file, 'application/octet-stream') if file && File.exist?(file)
|
243
|
+
# sets metadata for new upload in App Center
|
244
|
+
# returns:
|
245
|
+
# chunk size
|
246
|
+
def self.set_release_upload_metadata(set_metadata_url, api_token, owner_name, app_name, upload_id, timeout)
|
247
|
+
connection = self.connection(set_metadata_url)
|
242
248
|
|
243
|
-
UI.message("DEBUG: POST #{
|
249
|
+
UI.message("DEBUG: POST #{set_metadata_url}") if ENV['DEBUG']
|
244
250
|
UI.message("DEBUG: POST body <data>\n") if ENV['DEBUG']
|
245
|
-
|
246
251
|
response = connection.post do |req|
|
247
252
|
req.options.timeout = timeout
|
248
253
|
req.headers['internal-request-source'] = "fastlane"
|
249
|
-
req.body = options
|
250
254
|
end
|
255
|
+
UI.message("DEBUG: #{response.status} #{JSON.pretty_generate(response.body)}\n") if ENV['DEBUG']
|
251
256
|
|
257
|
+
case response.status
|
258
|
+
when 200...300
|
259
|
+
chunk_size = response.body['chunk_size']
|
260
|
+
unless chunk_size.is_a? Integer
|
261
|
+
UI.error("Set metadata didn't return chunk size: #{response.status}: #{response.body}")
|
262
|
+
false
|
263
|
+
else
|
264
|
+
UI.message("Metadata set")
|
265
|
+
chunk_size
|
266
|
+
end
|
267
|
+
when 401
|
268
|
+
UI.user_error!("Auth Error, provided invalid token")
|
269
|
+
false
|
270
|
+
else
|
271
|
+
UI.error("Error setting metadata: #{response.status}: #{response.body}")
|
272
|
+
false
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
# Verifies a successful upload to App Center
|
277
|
+
# returns:
|
278
|
+
# successful upload response body.
|
279
|
+
def self.finish_release_upload(finish_url, api_token, owner_name, app_name, upload_id, timeout)
|
280
|
+
connection = self.connection(finish_url)
|
281
|
+
|
282
|
+
UI.message("DEBUG: POST #{finish_url}") if ENV['DEBUG']
|
283
|
+
response = connection.post do |req|
|
284
|
+
req.options.timeout = timeout
|
285
|
+
req.headers['internal-request-source'] = "fastlane"
|
286
|
+
end
|
252
287
|
UI.message("DEBUG: #{response.status} #{JSON.pretty_generate(response.body)}\n") if ENV['DEBUG']
|
253
288
|
|
254
289
|
case response.status
|
255
290
|
when 200...300
|
256
|
-
|
257
|
-
|
291
|
+
if response.body['error'] == false
|
292
|
+
UI.message("Upload finished")
|
293
|
+
self.update_release_upload(api_token, owner_name, app_name, upload_id, 'uploadFinished')
|
294
|
+
else
|
295
|
+
UI.error("Error finishing upload: #{response.body['message']}")
|
296
|
+
false
|
297
|
+
end
|
258
298
|
when 401
|
259
299
|
UI.user_error!("Auth Error, provided invalid token")
|
260
300
|
false
|
261
301
|
else
|
262
|
-
UI.error("Error
|
263
|
-
self.update_release_upload(api_token, owner_name, app_name, upload_id, 'aborted')
|
264
|
-
UI.error("Release aborted")
|
302
|
+
UI.error("Error finishing upload: #{response.status}: #{response.body}")
|
265
303
|
false
|
266
304
|
end
|
267
305
|
end
|
268
306
|
|
307
|
+
# upload binary for specified upload_url
|
308
|
+
# if succeed, then commits the release
|
309
|
+
# otherwise aborts
|
310
|
+
def self.upload_build(api_token, owner_name, app_name, file, upload_id, upload_url, content_type, chunk_size, timeout)
|
311
|
+
block_number = 1
|
312
|
+
|
313
|
+
File.open(file).each_chunk(chunk_size) do |chunk|
|
314
|
+
upload_chunk_url = "#{upload_url}&block_number=#{block_number}"
|
315
|
+
retries = 0
|
316
|
+
|
317
|
+
while retries <= MAX_REQUEST_RETRIES
|
318
|
+
begin
|
319
|
+
connection = self.connection(upload_chunk_url, true)
|
320
|
+
|
321
|
+
UI.message("DEBUG: POST #{upload_chunk_url}") if ENV['DEBUG']
|
322
|
+
UI.message("DEBUG: POST body <data>\n") if ENV['DEBUG']
|
323
|
+
response = connection.post do |req|
|
324
|
+
req.options.timeout = timeout
|
325
|
+
req.headers['internal-request-source'] = "fastlane"
|
326
|
+
req.headers['Content-Length'] = chunk.length.to_s
|
327
|
+
req.body = chunk
|
328
|
+
end
|
329
|
+
UI.message("DEBUG: #{response.status} #{JSON.pretty_generate(response.body)}\n") if ENV['DEBUG']
|
330
|
+
status = response.status
|
331
|
+
message = response.body
|
332
|
+
rescue Faraday::Error => e
|
333
|
+
|
334
|
+
# Low level HTTP errors, we will retry them
|
335
|
+
status = 0
|
336
|
+
message = e.message
|
337
|
+
end
|
338
|
+
|
339
|
+
case status
|
340
|
+
when 200...300
|
341
|
+
if response.body['error'] == false
|
342
|
+
UI.message("Chunk uploaded")
|
343
|
+
block_number += 1
|
344
|
+
break
|
345
|
+
else
|
346
|
+
UI.error("Error uploading binary #{response.body['message']}")
|
347
|
+
return false
|
348
|
+
end
|
349
|
+
when 401
|
350
|
+
UI.user_error!("Auth Error, provided invalid token")
|
351
|
+
return false
|
352
|
+
when 400...407, 409...428, 430...499
|
353
|
+
UI.user_error!("Client error: #{response.status}: #{response.body}")
|
354
|
+
return false
|
355
|
+
else
|
356
|
+
if retries < MAX_REQUEST_RETRIES
|
357
|
+
UI.message("DEBUG: Retryable error uploading binary #{status}: #{message}")
|
358
|
+
retries += 1
|
359
|
+
sleep(REQUEST_RETRY_INTERVAL)
|
360
|
+
else
|
361
|
+
UI.error("Error uploading binary #{status}: #{message}")
|
362
|
+
return false
|
363
|
+
end
|
364
|
+
end
|
365
|
+
end
|
366
|
+
end
|
367
|
+
UI.message("Binary uploaded")
|
368
|
+
end
|
369
|
+
|
269
370
|
# Commits or aborts the upload process for a release
|
270
371
|
def self.update_release_upload(api_token, owner_name, app_name, upload_id, status)
|
271
372
|
connection = self.connection
|
272
373
|
|
273
|
-
url = "v0.1/apps/#{owner_name}/#{app_name}/
|
374
|
+
url = "v0.1/apps/#{owner_name}/#{app_name}/uploads/releases/#{upload_id}"
|
274
375
|
body = {
|
275
|
-
|
376
|
+
upload_status: status,
|
377
|
+
id: upload_id
|
276
378
|
}
|
277
379
|
|
278
380
|
UI.message("DEBUG: PATCH #{url}") if ENV['DEBUG']
|
@@ -331,6 +433,40 @@ module Fastlane
|
|
331
433
|
end
|
332
434
|
end
|
333
435
|
|
436
|
+
# Polls the upload for a release id. When a release is uploaded, we have to check
|
437
|
+
# for a successful extraction before we can continue.
|
438
|
+
# returns:
|
439
|
+
# release_distinct_id
|
440
|
+
def self.poll_for_release_id(api_token, url)
|
441
|
+
connection = self.connection
|
442
|
+
|
443
|
+
while true
|
444
|
+
UI.message("DEBUG: GET #{url}") if ENV['DEBUG']
|
445
|
+
response = connection.get(url) do |req|
|
446
|
+
req.headers['X-API-Token'] = api_token
|
447
|
+
req.headers['internal-request-source'] = "fastlane"
|
448
|
+
end
|
449
|
+
|
450
|
+
UI.message("DEBUG: #{response.status} #{JSON.pretty_generate(response.body)}\n") if ENV['DEBUG']
|
451
|
+
|
452
|
+
case response.status
|
453
|
+
when 200...300
|
454
|
+
case response.body['upload_status']
|
455
|
+
when "readyToBePublished"
|
456
|
+
return response.body['release_distinct_id']
|
457
|
+
when "error"
|
458
|
+
UI.error("Error fetching release: #{response.body['error_details']}")
|
459
|
+
return false
|
460
|
+
else
|
461
|
+
sleep(RELEASE_UPLOAD_STATUS_POLL_INTERVAL)
|
462
|
+
end
|
463
|
+
else
|
464
|
+
UI.error("Error fetching information about release #{response.status}: #{response.body}")
|
465
|
+
return false
|
466
|
+
end
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|
334
470
|
# get distribution group or store
|
335
471
|
def self.get_destination(api_token, owner_name, app_name, destination_type, destination_name)
|
336
472
|
connection = self.connection
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fastlane-plugin-appcenter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Microsoft Corporation
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-07-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -155,7 +155,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
155
155
|
- !ruby/object:Gem::Version
|
156
156
|
version: '0'
|
157
157
|
requirements: []
|
158
|
-
rubygems_version: 3.0.
|
158
|
+
rubygems_version: 3.0.3
|
159
159
|
signing_key:
|
160
160
|
specification_version: 4
|
161
161
|
summary: Fastlane plugin for App Center
|