fastlane-plugin-firebase_app_distribution 0.9.1 → 0.10.1
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 +4 -4
- data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_action.rb +100 -70
- data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_add_testers_action.rb +3 -1
- data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_create_group_action.rb +3 -1
- data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_delete_group_action.rb +3 -1
- data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_get_latest_release.rb +18 -7
- data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_get_udids.rb +2 -1
- data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_remove_testers_action.rb +3 -1
- data/lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_apis.rb +48 -0
- data/lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_auth_client.rb +1 -0
- data/lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_error_message.rb +2 -0
- data/lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_helper.rb +45 -4
- data/lib/fastlane/plugin/firebase_app_distribution/version.rb +1 -1
- metadata +4 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 789a32fce54326215942dfb99d0bb843887a36d84ca3ecfc474d4408b02c103d
|
4
|
+
data.tar.gz: f2d3b26d638efddc8920e9df5b01bbb4efa176e26d91a33cb8ab781b2996ac11
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 72c6db99756504fc29a2e5ef24baf600a5bb13ddb3758385b240876fc5d3cf891c5c9bdc7037400aa3272d5aefe1fd2cdb2f2ea677b0dfa12f9fab78636012d3
|
7
|
+
data.tar.gz: d8a9c0d7ffc1d44813d8f97944d3db5dc3d3bf0eedfb4af3f89d4353d4bb3483a7ce4e7ae39bd502f1a302cc2ac94572ddee07842974644bbff0e9d02cf25cec
|
data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_action.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
require 'fastlane/action'
|
2
|
+
require 'fastlane_core'
|
2
3
|
require 'open3'
|
3
4
|
require 'shellwords'
|
4
5
|
require 'googleauth'
|
5
|
-
|
6
|
+
require_relative '../helper/firebase_app_distribution_apis'
|
6
7
|
require_relative '../helper/firebase_app_distribution_helper'
|
7
8
|
require_relative '../helper/firebase_app_distribution_error_message'
|
8
9
|
require_relative '../helper/firebase_app_distribution_auth_client'
|
@@ -34,8 +35,8 @@ module Fastlane
|
|
34
35
|
timeout = get_upload_timeout(params)
|
35
36
|
|
36
37
|
binary_path = get_binary_path(platform, params)
|
37
|
-
UI.user_error!("Couldn't
|
38
|
-
UI.user_error!("Couldn't find binary at path #{binary_path}.") unless File.exist?(binary_path)
|
38
|
+
UI.user_error!("Couldn't determine path for #{platform} binary.") if binary_path.nil?
|
39
|
+
UI.user_error!("Couldn't find #{platform} binary at path #{binary_path}.") unless File.exist?(binary_path)
|
39
40
|
binary_type = binary_type_from_path(binary_path)
|
40
41
|
|
41
42
|
# TODO(lkellogg): This sets the send timeout for all POST requests made by the client, but
|
@@ -56,7 +57,7 @@ module Fastlane
|
|
56
57
|
|
57
58
|
binary_type = binary_type_from_path(binary_path)
|
58
59
|
UI.message("📡 Uploading the #{binary_type}.")
|
59
|
-
operation = upload_binary(app_name, binary_path,
|
60
|
+
operation = upload_binary(client, app_name, binary_path, binary_type, timeout)
|
60
61
|
UI.message("🕵️ Validating upload…")
|
61
62
|
release = poll_upload_release_operation(client, operation, binary_type)
|
62
63
|
|
@@ -87,11 +88,12 @@ module Fastlane
|
|
87
88
|
test_devices =
|
88
89
|
get_value_from_value_or_file(params[:test_devices], params[:test_devices_file])
|
89
90
|
if present?(test_devices)
|
90
|
-
|
91
|
+
test_cases =
|
92
|
+
string_to_array(get_value_from_value_or_file(params[:test_case_ids], params[:test_case_ids_file]))&.map { |id| "#{app_name}/testCases/#{id}" }
|
91
93
|
test_password = test_password_from_params(params)
|
92
|
-
|
94
|
+
release_tests = test_release(alpha_client, release, test_devices, test_cases, params[:test_username], test_password, params[:test_username_resource], params[:test_password_resource])
|
93
95
|
unless params[:test_non_blocking]
|
94
|
-
poll_test_finished(alpha_client,
|
96
|
+
poll_test_finished(alpha_client, release_tests)
|
95
97
|
end
|
96
98
|
end
|
97
99
|
|
@@ -140,31 +142,6 @@ module Fastlane
|
|
140
142
|
test_password && test_password.sub(/\r?\n$/, "")
|
141
143
|
end
|
142
144
|
|
143
|
-
def self.app_id_from_params(params)
|
144
|
-
if params[:app]
|
145
|
-
app_id = params[:app]
|
146
|
-
elsif xcode_archive_path
|
147
|
-
plist_path = params[:googleservice_info_plist_path]
|
148
|
-
app_id = get_ios_app_id_from_archive_plist(xcode_archive_path, plist_path)
|
149
|
-
end
|
150
|
-
if app_id.nil?
|
151
|
-
UI.crash!(ErrorMessage::MISSING_APP_ID)
|
152
|
-
end
|
153
|
-
app_id
|
154
|
-
end
|
155
|
-
|
156
|
-
def self.xcode_archive_path
|
157
|
-
# prevents issues on cross-platform build environments where an XCode build happens within
|
158
|
-
# the same lane
|
159
|
-
return nil if lane_platform == :android
|
160
|
-
|
161
|
-
Actions.lane_context[SharedValues::XCODEBUILD_ARCHIVE]
|
162
|
-
end
|
163
|
-
|
164
|
-
def self.lane_platform
|
165
|
-
Actions.lane_context[Actions::SharedValues::PLATFORM_NAME]
|
166
|
-
end
|
167
|
-
|
168
145
|
def self.platform_from_app_id(app_id)
|
169
146
|
if app_id.include?(':ios:')
|
170
147
|
:ios
|
@@ -173,6 +150,7 @@ module Fastlane
|
|
173
150
|
end
|
174
151
|
end
|
175
152
|
|
153
|
+
# rubocop:disable Require/MissingRequireStatement
|
176
154
|
def self.get_binary_path(platform, params)
|
177
155
|
if platform == :ios
|
178
156
|
return params[:ipa_path] ||
|
@@ -193,7 +171,11 @@ module Fastlane
|
|
193
171
|
Dir["*.apk"].last ||
|
194
172
|
Dir[File.join("app", "build", "outputs", "apk", "release", "app-release.apk")].last
|
195
173
|
end
|
174
|
+
|
175
|
+
UI.error("Unable to determine binary path for unsupported platform #{platform}.")
|
176
|
+
nil
|
196
177
|
end
|
178
|
+
# rubocop:enable Require/MissingRequireStatement
|
197
179
|
|
198
180
|
def self.get_upload_timeout(params)
|
199
181
|
if params[:upload_timeout]
|
@@ -232,7 +214,9 @@ module Fastlane
|
|
232
214
|
def self.release_notes(params)
|
233
215
|
release_notes_param =
|
234
216
|
get_value_from_value_or_file(params[:release_notes], params[:release_notes_file])
|
217
|
+
# rubocop:disable Require/MissingRequireStatement
|
235
218
|
release_notes_param || Actions.lane_context[SharedValues::FL_CHANGELOG]
|
219
|
+
# rubocop:enable Require/MissingRequireStatement
|
236
220
|
end
|
237
221
|
|
238
222
|
def self.poll_upload_release_operation(client, operation, binary_type)
|
@@ -268,7 +252,7 @@ module Fastlane
|
|
268
252
|
extract_release(operation)
|
269
253
|
end
|
270
254
|
|
271
|
-
def self.upload_binary(app_name, binary_path,
|
255
|
+
def self.upload_binary(client, app_name, binary_path, binary_type, timeout)
|
272
256
|
options = Google::Apis::RequestOptions.new
|
273
257
|
options.max_elapsed_time = timeout # includes retries (default = no retries)
|
274
258
|
options.header = {
|
@@ -282,12 +266,21 @@ module Fastlane
|
|
282
266
|
# standard http call instead and convert it to a long running object
|
283
267
|
# https://github.com/googleapis/google-api-ruby-client/blob/main/generated/google-apis-firebaseappdistribution_v1/lib/google/apis/firebaseappdistribution_v1/service.rb#L79
|
284
268
|
# TODO(kbolay): Prefer client.upload_medium
|
285
|
-
response =
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
269
|
+
response = begin
|
270
|
+
client.http(
|
271
|
+
:post,
|
272
|
+
"https://firebaseappdistribution.googleapis.com/upload/v1/#{app_name}/releases:upload",
|
273
|
+
body: File.open(binary_path, 'rb'),
|
274
|
+
options: options
|
275
|
+
)
|
276
|
+
rescue Google::Apis::Error => err
|
277
|
+
case err.status_code.to_i
|
278
|
+
when 403
|
279
|
+
UI.crash!(ErrorMessage::PERMISSION_DENIED_ERROR)
|
280
|
+
else
|
281
|
+
UI.crash!("#{ErrorMessage.upload_binary_error(binary_type)} (#{err}, status_code: #{err.status_code})")
|
282
|
+
end
|
283
|
+
end
|
291
284
|
|
292
285
|
Google::Apis::FirebaseappdistributionV1::GoogleLongrunningOperation.from_json(response)
|
293
286
|
end
|
@@ -339,7 +332,10 @@ module Fastlane
|
|
339
332
|
end
|
340
333
|
end
|
341
334
|
|
342
|
-
def self.test_release(alpha_client, release, test_devices, username = nil, password = nil, username_resource = nil, password_resource = nil)
|
335
|
+
def self.test_release(alpha_client, release, test_devices, test_cases, username = nil, password = nil, username_resource = nil, password_resource = nil)
|
336
|
+
if present?(test_cases) && (!username_resource.nil? || !password_resource.nil?)
|
337
|
+
UI.user_error!("Password and username resource names are not supported for the testing agent.")
|
338
|
+
end
|
343
339
|
if username_resource.nil? ^ password_resource.nil?
|
344
340
|
UI.user_error!("Username and password resource names for automated tests need to be specified together.")
|
345
341
|
end
|
@@ -369,7 +365,7 @@ module Fastlane
|
|
369
365
|
end
|
370
366
|
end
|
371
367
|
|
372
|
-
device_executions = string_to_array(test_devices,
|
368
|
+
device_executions = string_to_array(test_devices, /[;\n]/).map do |td_string|
|
373
369
|
td_hash = parse_test_device_string(td_string)
|
374
370
|
Google::Apis::FirebaseappdistributionV1alpha::GoogleFirebaseAppdistroV1alphaDeviceExecution.new(
|
375
371
|
device: Google::Apis::FirebaseappdistributionV1alpha::GoogleFirebaseAppdistroV1alphaTestDevice.new(
|
@@ -381,37 +377,64 @@ module Fastlane
|
|
381
377
|
)
|
382
378
|
end
|
383
379
|
|
380
|
+
UI.message("🤖 Starting automated tests. Note: This feature is in beta.")
|
381
|
+
release_tests = []
|
382
|
+
if present?(test_cases)
|
383
|
+
test_cases.each do |tc|
|
384
|
+
release_tests.push(create_release_test(alpha_client, release.name, device_executions, login_credential, tc))
|
385
|
+
end
|
386
|
+
else
|
387
|
+
release_tests.push(create_release_test(alpha_client, release.name, device_executions, login_credential))
|
388
|
+
end
|
389
|
+
release_tests
|
390
|
+
end
|
391
|
+
|
392
|
+
def self.create_release_test(alpha_client, release_name, device_executions, login_credential, test_case_name = nil)
|
384
393
|
release_test =
|
385
394
|
Google::Apis::FirebaseappdistributionV1alpha::GoogleFirebaseAppdistroV1alphaReleaseTest.new(
|
395
|
+
device_executions: device_executions,
|
386
396
|
login_credential: login_credential,
|
387
|
-
|
397
|
+
test_case: test_case_name
|
388
398
|
)
|
389
|
-
alpha_client.create_project_app_release_test(
|
399
|
+
alpha_client.create_project_app_release_test(release_name, release_test)
|
390
400
|
rescue Google::Apis::Error => err
|
391
|
-
|
401
|
+
case err.status_code.to_i
|
402
|
+
when 404
|
403
|
+
UI.user_error!("Test Case #{test_case_name} not found")
|
404
|
+
else
|
405
|
+
UI.crash!(err)
|
406
|
+
end
|
392
407
|
end
|
393
408
|
|
394
|
-
def self.poll_test_finished(alpha_client,
|
409
|
+
def self.poll_test_finished(alpha_client, release_tests)
|
410
|
+
release_test_names = release_tests.map(&:name)
|
395
411
|
TEST_MAX_POLLING_RETRIES.times do
|
396
|
-
UI.message("⏳
|
412
|
+
UI.message("⏳ #{release_test_names.size} automated test results are pending.")
|
397
413
|
sleep(TEST_POLLING_INTERVAL_SECONDS)
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
end
|
403
|
-
release_test.device_executions.each do |de|
|
404
|
-
case de.state
|
405
|
-
when 'PASSED', 'IN_PROGRESS'
|
406
|
-
next
|
407
|
-
when 'FAILED'
|
408
|
-
UI.test_failure!("Automated test failed for #{device_to_s(de.device)}: #{de.failed_reason}.")
|
409
|
-
when 'INCONCLUSIVE'
|
410
|
-
UI.test_failure!("Automated test inconclusive for #{device_to_s(de.device)}: #{de.inconclusive_reason}.")
|
414
|
+
release_test_names.delete_if do |release_test_name|
|
415
|
+
release_test = alpha_client.get_project_app_release_test(release_test_name)
|
416
|
+
if release_test.device_executions.all? { |e| e.state == 'PASSED' }
|
417
|
+
true
|
411
418
|
else
|
412
|
-
|
419
|
+
release_test.device_executions.each do |de|
|
420
|
+
case de.state
|
421
|
+
when 'PASSED', 'IN_PROGRESS'
|
422
|
+
next
|
423
|
+
when 'FAILED'
|
424
|
+
UI.test_failure!("Automated test failed for #{device_to_s(de.device)}: #{de.failed_reason}.")
|
425
|
+
when 'INCONCLUSIVE'
|
426
|
+
UI.test_failure!("Automated test inconclusive for #{device_to_s(de.device)}: #{de.inconclusive_reason}.")
|
427
|
+
else
|
428
|
+
UI.test_failure!("Unsupported automated test state for #{device_to_s(de.device)}: #{de.state}.")
|
429
|
+
end
|
430
|
+
end
|
431
|
+
false
|
413
432
|
end
|
414
433
|
end
|
434
|
+
if release_test_names.empty?
|
435
|
+
UI.success("✅ Passed automated test(s).")
|
436
|
+
return
|
437
|
+
end
|
415
438
|
end
|
416
439
|
UI.test_failure!("It took longer than expected to process your test, please try again.")
|
417
440
|
end
|
@@ -441,7 +464,7 @@ module Fastlane
|
|
441
464
|
optional: true),
|
442
465
|
FastlaneCore::ConfigItem.new(key: :googleservice_info_plist_path,
|
443
466
|
env_name: "GOOGLESERVICE_INFO_PLIST_PATH",
|
444
|
-
description: "Path to your GoogleService-Info.plist file, relative to the archived product path",
|
467
|
+
description: "Path to your GoogleService-Info.plist file, relative to the archived product path (or directly, if no archived product path is found)",
|
445
468
|
default_value: "GoogleService-Info.plist",
|
446
469
|
optional: true,
|
447
470
|
type: String),
|
@@ -493,7 +516,7 @@ module Fastlane
|
|
493
516
|
type: String),
|
494
517
|
FastlaneCore::ConfigItem.new(key: :groups_file,
|
495
518
|
env_name: "FIREBASEAPPDISTRO_GROUPS_FILE",
|
496
|
-
description: "Path to file containing group aliases used for distribution, separated by commas",
|
519
|
+
description: "Path to file containing group aliases used for distribution, separated by commas or newlines",
|
497
520
|
optional: true,
|
498
521
|
type: String),
|
499
522
|
FastlaneCore::ConfigItem.new(key: :testers,
|
@@ -503,7 +526,7 @@ module Fastlane
|
|
503
526
|
type: String),
|
504
527
|
FastlaneCore::ConfigItem.new(key: :testers_file,
|
505
528
|
env_name: "FIREBASEAPPDISTRO_TESTERS_FILE",
|
506
|
-
description: "Path to file containing email addresses of testers, separated by commas",
|
529
|
+
description: "Path to file containing email addresses of testers, separated by commas or newlines",
|
507
530
|
optional: true,
|
508
531
|
type: String),
|
509
532
|
FastlaneCore::ConfigItem.new(key: :release_notes,
|
@@ -520,12 +543,13 @@ module Fastlane
|
|
520
543
|
# Release Testing
|
521
544
|
FastlaneCore::ConfigItem.new(key: :test_devices,
|
522
545
|
env_name: "FIREBASEAPPDISTRO_TEST_DEVICES",
|
523
|
-
description: "List of devices to run automated tests on, in the format 'model=<model-id>,version=<os-version-id>,locale=<locale>,orientation=<orientation>;model=<model-id>,...'. Run 'gcloud firebase test android|ios models list' to see available devices. Note: This feature is in beta",
|
546
|
+
description: "List of devices (separated by semicolons) to run automated tests on, in the format 'model=<model-id>,version=<os-version-id>,locale=<locale>,orientation=<orientation>;model=<model-id>,...'. Run 'gcloud firebase test android|ios models list' to see available devices. Note: This feature is in beta",
|
524
547
|
optional: true,
|
525
548
|
type: String),
|
526
549
|
FastlaneCore::ConfigItem.new(key: :test_devices_file,
|
527
550
|
env_name: "FIREBASEAPPDISTRO_TEST_DEVICES_FILE",
|
528
|
-
description: "Path to file containing a list of devices to run automated tests on, in the format 'model=<model-id>,version=<os-version-id>,locale=<locale>,orientation=<orientation>;model=<model-id>,...'.
|
551
|
+
description: "Path to file containing a list of devices (sepatated by semicolons or newlines) to run automated tests on, in the format 'model=<model-id>,version=<os-version-id>,locale=<locale>,orientation=<orientation>;model=<model-id>,...'. " \
|
552
|
+
"Run 'gcloud firebase test android|ios models list' to see available devices. Note: This feature is in beta",
|
529
553
|
optional: true,
|
530
554
|
type: String),
|
531
555
|
FastlaneCore::ConfigItem.new(key: :test_username,
|
@@ -559,6 +583,16 @@ module Fastlane
|
|
559
583
|
optional: false,
|
560
584
|
default_value: false,
|
561
585
|
type: Boolean),
|
586
|
+
FastlaneCore::ConfigItem.new(key: :test_case_ids,
|
587
|
+
env_name: "FIREBASEAPPDISTRO_TEST_CASE_IDS",
|
588
|
+
description: "Test Case IDs, separated by commas. Note: This feature is in beta",
|
589
|
+
optional: true,
|
590
|
+
type: String),
|
591
|
+
FastlaneCore::ConfigItem.new(key: :test_case_ids_file,
|
592
|
+
env_name: "FIREBASEAPPDISTRO_TEST_CASE_IDS_FILE",
|
593
|
+
description: "Path to file with containing Test Case IDs, separated by commas or newlines. Note: This feature is in beta",
|
594
|
+
optional: true,
|
595
|
+
type: String),
|
562
596
|
|
563
597
|
# Auth
|
564
598
|
FastlaneCore::ConfigItem.new(key: :firebase_cli_token,
|
@@ -577,11 +611,7 @@ module Fastlane
|
|
577
611
|
end
|
578
612
|
|
579
613
|
def self.is_supported?(platform)
|
580
|
-
|
581
|
-
# See: https://docs.fastlane.tools/advanced/#control-configuration-by-lane-and-by-platform
|
582
|
-
#
|
583
|
-
# [:ios, :mac, :android].include?(platform)
|
584
|
-
true
|
614
|
+
[:ios, :android].include?(platform)
|
585
615
|
end
|
586
616
|
|
587
617
|
def self.example_code
|
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'fastlane/action'
|
2
|
+
require 'fastlane_core'
|
2
3
|
require 'fastlane_core/ui/ui'
|
3
|
-
|
4
|
+
require_relative '../helper/firebase_app_distribution_apis'
|
4
5
|
require_relative '../helper/firebase_app_distribution_helper'
|
6
|
+
require_relative '../helper/firebase_app_distribution_error_message'
|
5
7
|
require_relative '../helper/firebase_app_distribution_auth_client'
|
6
8
|
|
7
9
|
module Fastlane
|
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'fastlane/action'
|
2
|
+
require 'fastlane_core'
|
2
3
|
require 'fastlane_core/ui/ui'
|
3
|
-
|
4
|
+
require_relative '../helper/firebase_app_distribution_apis'
|
4
5
|
require_relative '../helper/firebase_app_distribution_helper'
|
6
|
+
require_relative '../helper/firebase_app_distribution_error_message'
|
5
7
|
require_relative '../helper/firebase_app_distribution_auth_client'
|
6
8
|
|
7
9
|
module Fastlane
|
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'fastlane/action'
|
2
|
+
require 'fastlane_core'
|
2
3
|
require 'fastlane_core/ui/ui'
|
3
|
-
|
4
|
+
require_relative '../helper/firebase_app_distribution_apis'
|
4
5
|
require_relative '../helper/firebase_app_distribution_helper'
|
6
|
+
require_relative '../helper/firebase_app_distribution_error_message'
|
5
7
|
require_relative '../helper/firebase_app_distribution_auth_client'
|
6
8
|
|
7
9
|
module Fastlane
|
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'fastlane/action'
|
2
|
-
require '
|
2
|
+
require 'fastlane_core'
|
3
|
+
require_relative '../helper/firebase_app_distribution_apis'
|
3
4
|
require_relative '../helper/firebase_app_distribution_auth_client'
|
5
|
+
require_relative '../helper/firebase_app_distribution_error_message'
|
4
6
|
require_relative '../helper/firebase_app_distribution_helper'
|
5
7
|
|
6
8
|
module Fastlane
|
@@ -17,15 +19,15 @@ module Fastlane
|
|
17
19
|
client = Google::Apis::FirebaseappdistributionV1::FirebaseAppDistributionService.new
|
18
20
|
client.authorization = get_authorization(params[:service_credentials_file], params[:firebase_cli_token], params[:service_credentials_json_data], params[:debug])
|
19
21
|
|
20
|
-
|
21
|
-
|
22
|
-
parent = app_name_from_app_id(
|
22
|
+
app_id = app_id_from_params(params)
|
23
|
+
UI.message("⏳ Fetching latest release for app #{app_id}...")
|
24
|
+
parent = app_name_from_app_id(app_id)
|
23
25
|
|
24
26
|
begin
|
25
27
|
releases = client.list_project_app_releases(parent, page_size: 1).releases
|
26
28
|
rescue Google::Apis::Error => err
|
27
29
|
if err.status_code.to_i == 404
|
28
|
-
UI.user_error!("#{ErrorMessage::INVALID_APP_ID}: #{
|
30
|
+
UI.user_error!("#{ErrorMessage::INVALID_APP_ID}: #{app_id}")
|
29
31
|
else
|
30
32
|
UI.crash!(err)
|
31
33
|
end
|
@@ -33,7 +35,7 @@ module Fastlane
|
|
33
35
|
|
34
36
|
if releases.nil? || releases.empty?
|
35
37
|
latest_release = nil
|
36
|
-
UI.important("No releases for app #{
|
38
|
+
UI.important("No releases for app #{app_id} found in App Distribution. Returning nil and setting Actions.lane_context[SharedValues::FIREBASE_APP_DISTRO_LATEST_RELEASE].")
|
37
39
|
else
|
38
40
|
# latest_release = append_json_style_fields(response.releases[0].to_h)
|
39
41
|
latest_release = map_release_hash(releases[0])
|
@@ -78,10 +80,19 @@ module Fastlane
|
|
78
80
|
|
79
81
|
def self.available_options
|
80
82
|
[
|
83
|
+
# iOS Specific
|
84
|
+
FastlaneCore::ConfigItem.new(key: :googleservice_info_plist_path,
|
85
|
+
env_name: "GOOGLESERVICE_INFO_PLIST_PATH",
|
86
|
+
description: "Path to your GoogleService-Info.plist file, relative to the archived product path (or directly, if no archived product path is found)",
|
87
|
+
default_value: "GoogleService-Info.plist",
|
88
|
+
optional: true,
|
89
|
+
type: String),
|
90
|
+
|
91
|
+
# General
|
81
92
|
FastlaneCore::ConfigItem.new(key: :app,
|
82
93
|
env_name: "FIREBASEAPPDISTRO_APP",
|
83
94
|
description: "Your app's Firebase App ID. You can find the App ID in the Firebase console, on the General Settings page",
|
84
|
-
optional:
|
95
|
+
optional: true,
|
85
96
|
type: String),
|
86
97
|
FastlaneCore::ConfigItem.new(key: :firebase_cli_token,
|
87
98
|
description: "Auth token generated using Firebase CLI's login:ci command",
|
data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_get_udids.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
require 'fastlane/action'
|
2
|
+
require 'fastlane_core'
|
2
3
|
require 'open3'
|
3
4
|
require 'shellwords'
|
4
5
|
require 'googleauth'
|
5
|
-
|
6
|
+
require_relative '../helper/firebase_app_distribution_apis'
|
6
7
|
require_relative '../helper/firebase_app_distribution_helper'
|
7
8
|
require_relative '../helper/firebase_app_distribution_error_message'
|
8
9
|
require_relative '../helper/firebase_app_distribution_auth_client'
|
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'fastlane/action'
|
2
|
+
require 'fastlane_core'
|
2
3
|
require 'fastlane_core/ui/ui'
|
3
|
-
|
4
|
+
require_relative '../helper/firebase_app_distribution_apis'
|
4
5
|
require_relative '../helper/firebase_app_distribution_helper'
|
6
|
+
require_relative '../helper/firebase_app_distribution_error_message'
|
5
7
|
require_relative '../helper/firebase_app_distribution_auth_client'
|
6
8
|
|
7
9
|
module Fastlane
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'google/apis/firebaseappdistribution_v1'
|
2
|
+
require 'google/apis/firebaseappdistribution_v1alpha'
|
3
|
+
|
4
|
+
# This is partially copied from google/apis/firebaseappdistribution_v1alpha v0.9.0 (2024-12-08) based discovery document revision 20241204.
|
5
|
+
# We can't depend on that version directly as long as fastlane locks google-cloud-env < 2.0.0 (to support Ruby 2.6).
|
6
|
+
# Newer versions of the API clients depend on google-apis-core >= 0.15.0 which depends on googleauth ~> 1.9 which depends on google-cloud-env ~> 2.1.
|
7
|
+
# See also https://github.com/fastlane/fastlane/pull/21685#pullrequestreview-2490037163
|
8
|
+
module Google
|
9
|
+
module Apis
|
10
|
+
module FirebaseappdistributionV1alpha
|
11
|
+
class GoogleFirebaseAppdistroV1alphaReleaseTest
|
12
|
+
include Google::Apis::Core::Hashable
|
13
|
+
|
14
|
+
attr_accessor :create_time
|
15
|
+
attr_accessor :device_executions
|
16
|
+
attr_accessor :display_name
|
17
|
+
attr_accessor :login_credential
|
18
|
+
attr_accessor :name
|
19
|
+
attr_accessor :test_case
|
20
|
+
attr_accessor :test_state
|
21
|
+
|
22
|
+
def initialize(**args)
|
23
|
+
update!(**args)
|
24
|
+
end
|
25
|
+
|
26
|
+
def update!(**args)
|
27
|
+
@create_time = args[:create_time] if args.key?(:create_time)
|
28
|
+
@device_executions = args[:device_executions] if args.key?(:device_executions)
|
29
|
+
@display_name = args[:display_name] if args.key?(:display_name)
|
30
|
+
@login_credential = args[:login_credential] if args.key?(:login_credential)
|
31
|
+
@name = args[:name] if args.key?(:name)
|
32
|
+
@test_case = args[:test_case] if args.key?(:test_case)
|
33
|
+
@test_state = args[:test_state] if args.key?(:test_state)
|
34
|
+
end
|
35
|
+
|
36
|
+
class Representation < Google::Apis::Core::JsonRepresentation
|
37
|
+
property :create_time, as: 'createTime'
|
38
|
+
collection :device_executions, as: 'deviceExecutions', class: Google::Apis::FirebaseappdistributionV1alpha::GoogleFirebaseAppdistroV1alphaDeviceExecution, decorator: Google::Apis::FirebaseappdistributionV1alpha::GoogleFirebaseAppdistroV1alphaDeviceExecution::Representation
|
39
|
+
property :display_name, as: 'displayName'
|
40
|
+
property :login_credential, as: 'loginCredential', class: Google::Apis::FirebaseappdistributionV1alpha::GoogleFirebaseAppdistroV1alphaLoginCredential, decorator: Google::Apis::FirebaseappdistributionV1alpha::GoogleFirebaseAppdistroV1alphaLoginCredential::Representation
|
41
|
+
property :name, as: 'name'
|
42
|
+
property :test_case, as: 'testCase'
|
43
|
+
property :test_state, as: 'testState'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_error_message.rb
CHANGED
@@ -4,6 +4,8 @@ module ErrorMessage
|
|
4
4
|
SERVICE_CREDENTIALS_NOT_FOUND = "Service credentials file does not exist. Please check the service credentials path and try again."
|
5
5
|
PARSE_SERVICE_CREDENTIALS_ERROR = "Failed to extract service account information from the service credentials file."
|
6
6
|
PARSE_FIREBASE_TOOLS_JSON_ERROR = "Encountered error parsing json file. Ensure the firebase-tools.json file is formatted correctly."
|
7
|
+
PERMISSION_DENIED_ERROR = "The authenticated user does not have the required permissions on the Firebase project"
|
8
|
+
UPLOAD_BINARY_ERROR = "App Distribution halted because it had a problem uploading the app binary."
|
7
9
|
UPLOAD_RELEASE_NOTES_ERROR = "App Distribution halted because it had a problem uploading release notes."
|
8
10
|
UPLOAD_TESTERS_ERROR = "App Distribution halted because it had a problem adding testers/groups."
|
9
11
|
GET_RELEASE_TIMEOUT = "App Distribution failed to fetch release information."
|
data/lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_helper.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
|
+
require 'fastlane/action'
|
1
2
|
require 'fastlane_core/ui/ui'
|
2
3
|
require 'cfpropertylist'
|
4
|
+
require 'google/apis/core'
|
5
|
+
require 'google/apis/options'
|
6
|
+
require_relative './firebase_app_distribution_error_message'
|
3
7
|
|
4
8
|
module Fastlane
|
5
9
|
UI = FastlaneCore::UI unless Fastlane.const_defined?("UI")
|
@@ -27,21 +31,58 @@ module Fastlane
|
|
27
31
|
|
28
32
|
# Returns the array representation of a string with trimmed comma
|
29
33
|
# seperated values.
|
30
|
-
def string_to_array(string, delimiter =
|
34
|
+
def string_to_array(string, delimiter = /[,\n]/)
|
31
35
|
return [] if string.nil?
|
32
36
|
# Strip string and then strip individual values
|
33
37
|
string.strip.split(delimiter).map(&:strip)
|
34
38
|
end
|
35
39
|
|
40
|
+
def app_id_from_params(params)
|
41
|
+
plist_path = params[:googleservice_info_plist_path]
|
42
|
+
if params[:app]
|
43
|
+
UI.message("Using app ID from 'app' parameter")
|
44
|
+
app_id = params[:app]
|
45
|
+
elsif xcode_archive_path
|
46
|
+
UI.message("Using app ID from the GoogleService-Info.plist file located using the 'googleservice_info_plist_path' parameter, relative to the archive path: #{xcode_archive_path}")
|
47
|
+
app_id = get_ios_app_id_from_archive_plist(xcode_archive_path, plist_path)
|
48
|
+
elsif plist_path
|
49
|
+
UI.message("Using app ID from the GoogleService-Info.plist file located using the 'googleservice_info_plist_path' parameter directly since no archive path was found")
|
50
|
+
app_id = get_ios_app_id_from_plist(plist_path)
|
51
|
+
end
|
52
|
+
if app_id.nil?
|
53
|
+
UI.crash!(ErrorMessage::MISSING_APP_ID)
|
54
|
+
end
|
55
|
+
app_id
|
56
|
+
end
|
57
|
+
|
58
|
+
def lane_platform
|
59
|
+
# to_sym shouldn't be necessary, but possibly fixes #376
|
60
|
+
Actions.lane_context[Actions::SharedValues::PLATFORM_NAME]&.to_sym
|
61
|
+
end
|
62
|
+
|
63
|
+
def xcode_archive_path
|
64
|
+
# prevents issues on cross-platform build environments where an XCode build happens within
|
65
|
+
# the same lane
|
66
|
+
return nil if lane_platform == :android
|
67
|
+
|
68
|
+
# rubocop:disable Require/MissingRequireStatement
|
69
|
+
Actions.lane_context[Actions::SharedValues::XCODEBUILD_ARCHIVE]
|
70
|
+
# rubocop:enable Require/MissingRequireStatement
|
71
|
+
end
|
72
|
+
|
36
73
|
def parse_plist(path)
|
37
74
|
CFPropertyList.native_types(CFPropertyList::List.new(file: path).value)
|
38
75
|
end
|
39
76
|
|
40
|
-
def get_ios_app_id_from_archive_plist(archive_path,
|
77
|
+
def get_ios_app_id_from_archive_plist(archive_path, relative_plist_path)
|
41
78
|
app_path = parse_plist("#{archive_path}/Info.plist")["ApplicationProperties"]["ApplicationPath"]
|
42
79
|
UI.shell_error!("can't extract application path from Info.plist at #{archive_path}") if app_path.empty?
|
43
|
-
|
44
|
-
|
80
|
+
return get_ios_app_id_from_plist("#{archive_path}/Products/#{app_path}/#{relative_plist_path}")
|
81
|
+
end
|
82
|
+
|
83
|
+
def get_ios_app_id_from_plist(plist_path)
|
84
|
+
identifier = parse_plist(plist_path)["GOOGLE_APP_ID"]
|
85
|
+
UI.shell_error!("can't extract GOOGLE_APP_ID from #{plist_path}") if identifier.empty?
|
45
86
|
return identifier
|
46
87
|
end
|
47
88
|
|
metadata
CHANGED
@@ -1,16 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fastlane-plugin-firebase_app_distribution
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stefan Natchev
|
8
8
|
- Manny Jimenez
|
9
9
|
- Alonso Salas Infante
|
10
|
-
autorequire:
|
11
10
|
bindir: bin
|
12
11
|
cert_chain: []
|
13
|
-
date:
|
12
|
+
date: 2025-04-14 00:00:00.000000000 Z
|
14
13
|
dependencies:
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: google-apis-firebaseappdistribution_v1
|
@@ -166,7 +165,6 @@ dependencies:
|
|
166
165
|
- - ">="
|
167
166
|
- !ruby/object:Gem::Version
|
168
167
|
version: 2.127.1
|
169
|
-
description:
|
170
168
|
email:
|
171
169
|
- snatchev@google.com
|
172
170
|
- mannyjimenez@google.com
|
@@ -186,6 +184,7 @@ files:
|
|
186
184
|
- lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_get_latest_release.rb
|
187
185
|
- lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_get_udids.rb
|
188
186
|
- lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_remove_testers_action.rb
|
187
|
+
- lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_apis.rb
|
189
188
|
- lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_auth_client.rb
|
190
189
|
- lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_error_message.rb
|
191
190
|
- lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_helper.rb
|
@@ -194,7 +193,6 @@ homepage: https://github.com/fastlane/fastlane-plugin-firebase_app_distribution
|
|
194
193
|
licenses:
|
195
194
|
- MIT
|
196
195
|
metadata: {}
|
197
|
-
post_install_message:
|
198
196
|
rdoc_options: []
|
199
197
|
require_paths:
|
200
198
|
- lib
|
@@ -209,8 +207,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
209
207
|
- !ruby/object:Gem::Version
|
210
208
|
version: '0'
|
211
209
|
requirements: []
|
212
|
-
rubygems_version: 3.
|
213
|
-
signing_key:
|
210
|
+
rubygems_version: 3.6.2
|
214
211
|
specification_version: 4
|
215
212
|
summary: Release your beta builds to Firebase App Distribution. https://firebase.google.com/docs/app-distribution
|
216
213
|
test_files: []
|