fastlane-plugin-appcenter 1.8.1 → 1.9.0
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.
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
|