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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b432a12336537ce51caa06e26321f2047cc7d7c8ebe1c4abfe94a105b201e4ba
4
- data.tar.gz: 1c50c9c30886b1d8f5435a7d85d081a0f2e6e0ecd837ca877ed2d51511eabecf
3
+ metadata.gz: 789a32fce54326215942dfb99d0bb843887a36d84ca3ecfc474d4408b02c103d
4
+ data.tar.gz: f2d3b26d638efddc8920e9df5b01bbb4efa176e26d91a33cb8ab781b2996ac11
5
5
  SHA512:
6
- metadata.gz: d296fa3989b9d3788b8322d21fed387e908c02c27157f3affe1dab72c0a19035ed871ea63be642c312cb7f0f636130406f161d629e2abd23da99aa98eab11f4a
7
- data.tar.gz: 07b723bf3cf631e1dfc8402c890be0a78753d6d57e178c68f8c66b950727e0157d9573151ee08badf851f6a55c7f9a7b1965846bed4f5589969247614dc75cbd
6
+ metadata.gz: 72c6db99756504fc29a2e5ef24baf600a5bb13ddb3758385b240876fc5d3cf891c5c9bdc7037400aa3272d5aefe1fd2cdb2f2ea677b0dfa12f9fab78636012d3
7
+ data.tar.gz: d8a9c0d7ffc1d44813d8f97944d3db5dc3d3bf0eedfb4af3f89d4353d4bb3483a7ce4e7ae39bd502f1a302cc2ac94572ddee07842974644bbff0e9d02cf25cec
@@ -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
- require 'google/apis/firebaseappdistribution_v1'
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 find binary.") if binary_path.nil?
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, client, timeout)
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
- UI.message("🤖 Starting automated tests. Note: This feature is in beta.")
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
- release_test = test_release(alpha_client, release, test_devices, params[:test_username], test_password, params[:test_username_resource], params[:test_password_resource])
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, release_test.name)
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, client, timeout)
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 = client.http(
286
- :post,
287
- "https://firebaseappdistribution.googleapis.com/upload/v1/#{app_name}/releases:upload",
288
- body: File.open(binary_path, 'rb'),
289
- options: options
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, ';').map do |td_string|
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
- device_executions: device_executions
397
+ test_case: test_case_name
388
398
  )
389
- alpha_client.create_project_app_release_test(release.name, release_test)
399
+ alpha_client.create_project_app_release_test(release_name, release_test)
390
400
  rescue Google::Apis::Error => err
391
- UI.crash!(err)
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, release_test_name)
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("⏳ The automated test results are pending.")
412
+ UI.message("⏳ #{release_test_names.size} automated test results are pending.")
397
413
  sleep(TEST_POLLING_INTERVAL_SECONDS)
398
- release_test = alpha_client.get_project_app_release_test(release_test_name)
399
- if release_test.device_executions.all? { |e| e.state == 'PASSED' }
400
- UI.success("✅ Passed automated test(s).")
401
- return
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
- UI.test_failure!("Unsupported automated test state for #{device_to_s(de.device)}: #{de.state}.")
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>,...'. Run 'gcloud firebase test android|ios models list' to see available devices. Note: This feature is in beta",
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
- # Adjust this if your plugin only works for a particular platform (iOS vs. Android, for example)
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
- require 'google/apis/firebaseappdistribution_v1'
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
- require 'google/apis/firebaseappdistribution_v1'
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
- require 'google/apis/firebaseappdistribution_v1'
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 'google/apis/firebaseappdistribution_v1'
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
- UI.message("⏳ Fetching latest release for app #{params[:app]}...")
21
-
22
- parent = app_name_from_app_id(params[:app])
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}: #{params[:app]}")
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 #{params[:app]} found in App Distribution. Returning nil and setting Actions.lane_context[SharedValues::FIREBASE_APP_DISTRO_LATEST_RELEASE].")
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: false,
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",
@@ -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
- require 'google/apis/firebaseappdistribution_v1alpha'
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
- require 'google/apis/firebaseappdistribution_v1'
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
@@ -1,5 +1,6 @@
1
1
  require 'googleauth'
2
2
  require 'fastlane_core/ui/ui'
3
+ require_relative './firebase_app_distribution_error_message'
3
4
 
4
5
  module Fastlane
5
6
  UI = FastlaneCore::UI unless Fastlane.const_defined?("UI")
@@ -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."
@@ -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, plist_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
- identifier = parse_plist("#{archive_path}/Products/#{app_path}/#{plist_path}")["GOOGLE_APP_ID"]
44
- UI.shell_error!("can't extract GOOGLE_APP_ID") if identifier.empty?
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
 
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
2
  module FirebaseAppDistribution
3
- VERSION = "0.9.1"
3
+ VERSION = "0.10.1"
4
4
  end
5
5
  end
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.9.1
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: 2024-04-30 00:00:00.000000000 Z
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.5.9
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: []