fastlane 2.227.0 → 2.232.2

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.
Files changed (132) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +102 -96
  3. data/bin/fastlane +2 -2
  4. data/deliver/lib/assets/summary.html.erb +3 -3
  5. data/deliver/lib/deliver/app_screenshot.rb +215 -347
  6. data/deliver/lib/deliver/app_screenshot_iterator.rb +4 -1
  7. data/deliver/lib/deliver/app_screenshot_validator.rb +5 -21
  8. data/deliver/lib/deliver/loader.rb +2 -9
  9. data/deliver/lib/deliver/runner.rb +1 -1
  10. data/deliver/lib/deliver/upload_metadata.rb +5 -0
  11. data/deliver/lib/deliver/upload_screenshots.rb +4 -2
  12. data/fastlane/lib/assets/completions/completion.bash +1 -1
  13. data/fastlane/lib/assets/completions/completion.sh +2 -2
  14. data/fastlane/lib/fastlane/actions/app_store_build_number.rb +19 -14
  15. data/fastlane/lib/fastlane/actions/appium.rb +1 -1
  16. data/fastlane/lib/fastlane/actions/docs/create_app_online.md +6 -3
  17. data/fastlane/lib/fastlane/actions/docs/sync_code_signing.md +11 -7
  18. data/fastlane/lib/fastlane/actions/docs/upload_to_app_store.md.erb +56 -17
  19. data/fastlane/lib/fastlane/actions/docs/upload_to_testflight.md +13 -1
  20. data/fastlane/lib/fastlane/actions/get_version_number.rb +1 -1
  21. data/fastlane/lib/fastlane/actions/import_certificate.rb +9 -1
  22. data/fastlane/lib/fastlane/actions/increment_build_number.rb +1 -1
  23. data/fastlane/lib/fastlane/actions/install_xcode_plugin.rb +3 -2
  24. data/fastlane/lib/fastlane/actions/latest_testflight_build_number.rb +1 -1
  25. data/fastlane/lib/fastlane/actions/modify_services.rb +1 -0
  26. data/fastlane/lib/fastlane/actions/notarize.rb +1 -1
  27. data/fastlane/lib/fastlane/actions/upload_to_app_store.rb +1 -1
  28. data/fastlane/lib/fastlane/actions/xcov.rb +1 -7
  29. data/fastlane/lib/fastlane/cli_tools_distributor.rb +19 -1
  30. data/fastlane/lib/fastlane/console.rb +2 -2
  31. data/fastlane/lib/fastlane/documentation/markdown_docs_generator.rb +4 -4
  32. data/fastlane/lib/fastlane/erb_template_helper.rb +1 -7
  33. data/fastlane/lib/fastlane/helper/s3_client_helper.rb +4 -0
  34. data/fastlane/lib/fastlane/plugins/template/%gem_name%.gemspec.erb +1 -1
  35. data/fastlane/lib/fastlane/plugins/template/.github/workflows/test.yml +20 -20
  36. data/fastlane/lib/fastlane/plugins/template/.rubocop.yml +1 -1
  37. data/fastlane/lib/fastlane/version.rb +2 -1
  38. data/fastlane/swift/Actions.swift +1 -1
  39. data/fastlane/swift/Appfile.swift +13 -5
  40. data/fastlane/swift/ArgumentProcessor.swift +1 -1
  41. data/fastlane/swift/Atomic.swift +1 -1
  42. data/fastlane/swift/ControlCommand.swift +5 -4
  43. data/fastlane/swift/Deliverfile.swift +2 -2
  44. data/fastlane/swift/DeliverfileProtocol.swift +265 -68
  45. data/fastlane/swift/Fastlane.swift +150 -157
  46. data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/project.pbxproj +3 -1
  47. data/fastlane/swift/Gymfile.swift +2 -2
  48. data/fastlane/swift/GymfileProtocol.swift +227 -54
  49. data/fastlane/swift/LaneFileProtocol.swift +4 -2
  50. data/fastlane/swift/MainProcess.swift +1 -1
  51. data/fastlane/swift/Matchfile.swift +2 -2
  52. data/fastlane/swift/MatchfileProtocol.swift +226 -59
  53. data/fastlane/swift/OptionalConfigValue.swift +1 -1
  54. data/fastlane/swift/Plugins.swift +1 -1
  55. data/fastlane/swift/Precheckfile.swift +2 -2
  56. data/fastlane/swift/PrecheckfileProtocol.swift +45 -13
  57. data/fastlane/swift/RubyCommand.swift +6 -7
  58. data/fastlane/swift/RubyCommandable.swift +1 -1
  59. data/fastlane/swift/Runner.swift +3 -3
  60. data/fastlane/swift/RunnerArgument.swift +1 -1
  61. data/fastlane/swift/Scanfile.swift +2 -2
  62. data/fastlane/swift/ScanfileProtocol.swift +334 -84
  63. data/fastlane/swift/Screengrabfile.swift +2 -2
  64. data/fastlane/swift/ScreengrabfileProtocol.swift +89 -24
  65. data/fastlane/swift/Snapshotfile.swift +2 -2
  66. data/fastlane/swift/SnapshotfileProtocol.swift +216 -53
  67. data/fastlane/swift/SocketClient.swift +7 -7
  68. data/fastlane/swift/SocketClientDelegateProtocol.swift +1 -1
  69. data/fastlane/swift/SocketResponse.swift +1 -1
  70. data/fastlane/swift/formatting/Rakefile +1 -2
  71. data/fastlane/swift/main.swift +1 -1
  72. data/fastlane_core/lib/assets/XMLTemplate.xml.erb +5 -1
  73. data/fastlane_core/lib/fastlane_core/cert_checker.rb +10 -0
  74. data/fastlane_core/lib/fastlane_core/command_executor.rb +3 -1
  75. data/fastlane_core/lib/fastlane_core/fastlane_pty.rb +5 -1
  76. data/fastlane_core/lib/fastlane_core/ipa_file_analyser.rb +4 -14
  77. data/fastlane_core/lib/fastlane_core/ipa_upload_package_builder.rb +19 -2
  78. data/fastlane_core/lib/fastlane_core/itunes_transporter.rb +143 -106
  79. data/fastlane_core/lib/fastlane_core/keychain_importer.rb +3 -1
  80. data/fastlane_core/lib/fastlane_core/project.rb +8 -0
  81. data/fastlane_core/lib/fastlane_core/provisioning_profile.rb +7 -1
  82. data/frameit/lib/frameit/device.rb +2 -2
  83. data/frameit/lib/frameit/device_types.rb +108 -70
  84. data/frameit/lib/frameit/template_finder.rb +1 -1
  85. data/gym/lib/assets/wrap_xcodebuild/xcbuild-safe.sh +1 -0
  86. data/gym/lib/gym/module.rb +9 -4
  87. data/gym/lib/gym/options.rb +20 -2
  88. data/gym/lib/gym/runner.rb +38 -3
  89. data/match/lib/match/options.rb +1 -0
  90. data/match/lib/match/storage/s3_storage.rb +4 -7
  91. data/pilot/lib/pilot/build_manager.rb +7 -1
  92. data/produce/lib/produce/commands_generator.rb +2 -0
  93. data/produce/lib/produce/developer_center.rb +1 -0
  94. data/produce/lib/produce/service.rb +6 -1
  95. data/scan/lib/scan/error_handler.rb +5 -0
  96. data/scan/lib/scan/options.rb +13 -3
  97. data/scan/lib/scan/test_command_generator.rb +10 -2
  98. data/sigh/lib/assets/resign.sh +6 -3
  99. data/sigh/lib/sigh/local_manage.rb +6 -4
  100. data/sigh/lib/sigh/options.rb +1 -0
  101. data/sigh/lib/sigh/runner.rb +23 -3
  102. data/snapshot/lib/snapshot/detect_values.rb +1 -1
  103. data/snapshot/lib/snapshot/options.rb +13 -1
  104. data/snapshot/lib/snapshot/simulator_launchers/simulator_launcher_base.rb +4 -2
  105. data/spaceship/lib/spaceship/client.rb +32 -2
  106. data/spaceship/lib/spaceship/connect_api/models/age_rating_declaration.rb +65 -9
  107. data/spaceship/lib/spaceship/connect_api/models/app_info_localization.rb +4 -4
  108. data/spaceship/lib/spaceship/connect_api/models/app_screenshot_set.rb +7 -1
  109. data/spaceship/lib/spaceship/connect_api/models/app_store_version_localization.rb +16 -16
  110. data/spaceship/lib/spaceship/connect_api/models/build_upload.rb +42 -0
  111. data/spaceship/lib/spaceship/connect_api/models/bundle_id_capability.rb +2 -0
  112. data/spaceship/lib/spaceship/connect_api/models/certificate.rb +32 -2
  113. data/spaceship/lib/spaceship/connect_api/models/device.rb +1 -2
  114. data/spaceship/lib/spaceship/connect_api/models/profile.rb +2 -3
  115. data/spaceship/lib/spaceship/connect_api/models/webhook.rb +62 -0
  116. data/spaceship/lib/spaceship/connect_api/provisioning/provisioning.rb +0 -6
  117. data/spaceship/lib/spaceship/connect_api/testflight/testflight.rb +9 -0
  118. data/spaceship/lib/spaceship/connect_api/tunes/tunes.rb +38 -0
  119. data/spaceship/lib/spaceship/connect_api.rb +2 -0
  120. data/spaceship/lib/spaceship/errors.rb +8 -6
  121. data/spaceship/lib/spaceship/portal/key.rb +22 -3
  122. data/spaceship/lib/spaceship/portal/portal_client.rb +29 -2
  123. data/spaceship/lib/spaceship/spaceauth_runner.rb +5 -15
  124. data/supply/lib/supply/client.rb +18 -1
  125. data/trainer/lib/trainer/legacy_xcresult.rb +1 -1
  126. data/trainer/lib/trainer/test_parser.rb +1 -1
  127. data/trainer/lib/trainer/xcresult/helper.rb +11 -1
  128. metadata +153 -37
  129. data/fastlane/lib/fastlane/actions/hipchat.rb +0 -200
  130. data/fastlane/lib/fastlane/core_ext/bundler_monkey_patch.rb +0 -14
  131. data/fastlane/lib/fastlane/plugins/template/.circleci/config.yml +0 -43
  132. data/fastlane/lib/fastlane/plugins/template/.travis.yml +0 -4
@@ -51,6 +51,45 @@ module FastlaneCore
51
51
  not_implemented(__method__)
52
52
  end
53
53
 
54
+ # Builds a string array of credentials parameters based on the provided authentication details.
55
+ #
56
+ # @param username [String, nil] The username for authentication (optional).
57
+ # @param password [String, nil] The password for authentication (optional).
58
+ # @param jwt [String, nil] A JSON Web Token for token-based authentication (optional).
59
+ # @param api_key [Hash, nil] An API key for authentication (optional).
60
+ #
61
+ # @return [String] A string containing the appropriate credentials for authentication.
62
+ def build_credential_params(username = nil, password = nil, jwt = nil, api_key = nil)
63
+ not_implemented(__method__)
64
+ end
65
+
66
+ # Runs preparations before executing any command from the executor.
67
+ #
68
+ # @param original_api_key [Hash] api key containing the issuer id and private key
69
+ # @return [Hash] copy of `api_key` which includes an extra `key_dir` with the location of the .p8 file on disk
70
+ def prepare(original_api_key:)
71
+ return if original_api_key.nil?
72
+ # Create .p8 file from api_key and provide api key info which contains .p8 file path
73
+ api_key = original_api_key.dup
74
+ if self.kind_of?(ShellScriptTransporterExecutor)
75
+ # as of Transporter v3.3.0, the app is unable to detect the private keys under the 'private_keys' folder in current directory
76
+ # so we must rely on the other search paths in the Home dir:
77
+ # https://help.apple.com/itc/transporteruserguide/en.lproj/static.html#itc803b7be80
78
+ private_keys_dir = File.join(Dir.home, ".appstoreconnect/private_keys")
79
+ unless Dir.exist?(private_keys_dir)
80
+ FileUtils.mkdir_p(private_keys_dir)
81
+ end
82
+ api_key[:key_dir] = private_keys_dir
83
+ else
84
+ api_key[:key_dir] = Dir.mktmpdir("deliver-")
85
+ end
86
+ # Specified p8 needs to be generated to call altool or iTMSTransporter
87
+ File.open(File.join(api_key[:key_dir], "AuthKey_#{api_key[:key_id]}.p8"), "wb") do |p8|
88
+ p8.write(api_key[:key])
89
+ end
90
+ api_key
91
+ end
92
+
54
93
  def execute(command, hide_output)
55
94
  if Helper.test?
56
95
  yield(nil) if block_given?
@@ -180,8 +219,8 @@ module FastlaneCore
180
219
  end
181
220
 
182
221
  def file_upload_option(source)
183
- ext = File.extname(source).downcase
184
- is_asset_file_type = !File.directory?(source) && [".ipa", ".pkg", ".dmg", ".zip"].include?(ext)
222
+ file_ext = File.extname(source).downcase
223
+ is_asset_file_type = !File.directory?(source) && allowed_package_extensions.map { |ext| ".#{ext}" }.include?(file_ext)
185
224
 
186
225
  if is_asset_file_type
187
226
  return "-assetFile #{source.shellescape}"
@@ -207,11 +246,16 @@ module FastlaneCore
207
246
  end
208
247
  return deliver_additional_params
209
248
  end
249
+
250
+ def allowed_package_extensions
251
+ ["ipa", "pkg", "dmg", "zip"]
252
+ end
210
253
  end
211
254
 
212
255
  # Generates commands and executes the altool.
213
256
  class AltoolTransporterExecutor < TransporterExecutor
214
- ERROR_REGEX = /\*\*\* Error:\s+(.+)/
257
+ # Xcode 26 uses ERROR, while previous versions used *** Error
258
+ ERROR_REGEX = /(?:\*\*\*\s*)?ERROR:\s+(.+)/i
215
259
 
216
260
  private_constant :ERROR_REGEX
217
261
 
@@ -249,21 +293,7 @@ module FastlaneCore
249
293
  @errors << "-1 indicates altool exited abnormally; try retrying (see https://github.com/fastlane/fastlane/issues/21535)" if exit_status == -1
250
294
 
251
295
  unless @errors.empty? || @all_lines.empty?
252
- # Print the last lines that appear after the last error from the logs
253
- # If error text is not detected, it will be 20 lines
254
- # This is key for non-verbose mode
255
-
256
- # The format of altool's result with error is like below
257
- # > *** Error: Error uploading '...'.
258
- # > *** Error: ...
259
- # > {
260
- # > NSLocalizedDescription = "...",
261
- # > ...
262
- # > }
263
- # So this line tries to find the line which has "*** Error:" prefix from bottom of log
264
- error_line_index = @all_lines.rindex { |line| ERROR_REGEX.match?(line) }
265
-
266
- @all_lines[(error_line_index || -20)..-1].each do |line|
296
+ @all_lines.each do |line|
267
297
  UI.important("[altool] #{line}")
268
298
  end
269
299
  UI.message("Application Loader output above ^")
@@ -271,7 +301,15 @@ module FastlaneCore
271
301
  end
272
302
 
273
303
  yield(@all_lines) if block_given?
274
- exit_status.zero?
304
+ @errors.empty?
305
+ end
306
+
307
+ def build_credential_params(username = nil, password = nil, jwt = nil, api_key = nil)
308
+ if !username.nil? && !password.nil? && api_key.nil?
309
+ "-u #{username.shellescape} -p #{password.shellescape}"
310
+ elsif !api_key.nil?
311
+ "--apiKey #{api_key[:key_id]} --apiIssuer #{api_key[:issuer_id]}"
312
+ end
275
313
  end
276
314
 
277
315
  def build_upload_command(username, password, source = "/tmp", provider_short_name = "", jwt = nil, platform = nil, api_key = nil)
@@ -280,10 +318,7 @@ module FastlaneCore
280
318
  ("API_PRIVATE_KEYS_DIR=#{api_key[:key_dir]}" if use_api_key),
281
319
  "xcrun altool",
282
320
  "--upload-app",
283
- ("-u #{username.shellescape}" unless use_api_key),
284
- ("-p #{password.shellescape}" unless use_api_key),
285
- ("--apiKey #{api_key[:key_id]}" if use_api_key),
286
- ("--apiIssuer #{api_key[:issuer_id]}" if use_api_key),
321
+ build_credential_params(username, password, jwt, api_key),
287
322
  ("--asc-provider #{provider_short_name}" unless use_api_key || provider_short_name.to_s.empty?),
288
323
  platform_option(platform),
289
324
  file_upload_option(source),
@@ -298,10 +333,7 @@ module FastlaneCore
298
333
  ("API_PRIVATE_KEYS_DIR=#{api_key[:key_dir]}" if use_api_key),
299
334
  "xcrun altool",
300
335
  "--list-providers",
301
- ("-u #{username.shellescape}" unless use_api_key),
302
- ("-p #{password.shellescape}" unless use_api_key),
303
- ("--apiKey #{api_key[:key_id]}" if use_api_key),
304
- ("--apiIssuer #{api_key[:issuer_id]}" if use_api_key),
336
+ build_credential_params(username, password, jwt, api_key),
305
337
  "--output-format json"
306
338
  ].compact.join(' ')
307
339
  end
@@ -318,10 +350,7 @@ module FastlaneCore
318
350
  ("API_PRIVATE_KEYS_DIR=#{api_key[:key_dir]}" if use_api_key),
319
351
  "xcrun altool",
320
352
  "--validate-app",
321
- ("-u #{username.shellescape}" unless use_api_key),
322
- ("-p #{password.shellescape}" unless use_api_key),
323
- ("--apiKey #{api_key[:key_id]}" if use_api_key),
324
- ("--apiIssuer #{api_key[:issuer_id]}" if use_api_key),
353
+ build_credential_params(username, password, nil, api_key),
325
354
  ("--asc-provider #{provider_short_name}" unless use_api_key || provider_short_name.to_s.empty?),
326
355
  platform_option(platform),
327
356
  file_upload_option(source)
@@ -385,14 +414,21 @@ module FastlaneCore
385
414
 
386
415
  # Generates commands and executes the iTMSTransporter through the shell script it provides by the same name
387
416
  class ShellScriptTransporterExecutor < TransporterExecutor
417
+ def build_credential_params(username = nil, password = nil, jwt = nil, api_key = nil)
418
+ if !(username.nil? || password.nil?) && (jwt.nil? && api_key.nil?)
419
+ "-u #{username.shellescape} -p #{shell_escaped_password(password)}"
420
+ elsif !jwt.nil? && api_key.nil?
421
+ "-jwt #{jwt}"
422
+ elsif !api_key.nil?
423
+ "-apiIssuer #{api_key[:issuer_id]} -apiKey #{api_key[:key_id]}"
424
+ end
425
+ end
426
+
388
427
  def build_upload_command(username, password, source = "/tmp", provider_short_name = "", jwt = nil, platform = nil, api_key = nil)
389
- use_jwt = !jwt.to_s.empty?
390
428
  [
391
429
  '"' + Helper.transporter_path + '"',
392
430
  "-m upload",
393
- ("-u #{username.shellescape}" unless use_jwt),
394
- ("-p #{shell_escaped_password(password)}" unless use_jwt),
395
- ("-jwt #{jwt}" if use_jwt),
431
+ build_credential_params(username, password, jwt, api_key),
396
432
  file_upload_option(source),
397
433
  additional_upload_parameters, # that's here, because the user might overwrite the -t option
398
434
  "-k 100000",
@@ -402,13 +438,10 @@ module FastlaneCore
402
438
  end
403
439
 
404
440
  def build_download_command(username, password, apple_id, destination = "/tmp", provider_short_name = "", jwt = nil)
405
- use_jwt = !jwt.to_s.empty?
406
441
  [
407
442
  '"' + Helper.transporter_path + '"',
408
443
  "-m lookupMetadata",
409
- ("-u #{username.shellescape}" unless use_jwt),
410
- ("-p #{shell_escaped_password(password)}" unless use_jwt),
411
- ("-jwt #{jwt}" if use_jwt),
444
+ build_credential_params(username, password, jwt),
412
445
  "-apple_id #{apple_id}",
413
446
  "-destination '#{destination}'",
414
447
  ("-itc_provider #{provider_short_name}" if jwt.nil? && !provider_short_name.to_s.empty?)
@@ -416,25 +449,19 @@ module FastlaneCore
416
449
  end
417
450
 
418
451
  def build_provider_ids_command(username, password, jwt = nil, api_key = nil)
419
- use_jwt = !jwt.to_s.empty?
420
452
  [
421
453
  '"' + Helper.transporter_path + '"',
422
454
  '-m provider',
423
- ("-u \"#{username.shellescape}\"" unless use_jwt),
424
- ("-p #{shell_escaped_password(password)}" unless use_jwt),
425
- ("-jwt #{jwt}" if use_jwt)
455
+ build_credential_params(username, password, jwt, api_key)
426
456
  ].compact.join(' ')
427
457
  end
428
458
 
429
459
  def build_verify_command(username, password, source = "/tmp", provider_short_name = "", **kwargs)
430
460
  jwt = kwargs[:jwt]
431
- use_jwt = !jwt.to_s.empty?
432
461
  [
433
462
  '"' + Helper.transporter_path + '"',
434
463
  '-m verify',
435
- ("-u #{username.shellescape}" unless use_jwt),
436
- ("-p #{shell_escaped_password(password)}" unless use_jwt),
437
- ("-jwt #{jwt}" if use_jwt),
464
+ build_credential_params(username, password, jwt),
438
465
  "-f #{source.shellescape}",
439
466
  ("-WONoPause true" if Helper.windows?), # Windows only: process instantly returns instead of waiting for key press
440
467
  ("-itc_provider #{provider_short_name}" if jwt.nil? && !provider_short_name.to_s.empty?)
@@ -456,6 +483,31 @@ module FastlaneCore
456
483
  UI.error("Could not download/upload from App Store Connect! It's probably related to your password or your internet connection.")
457
484
  end
458
485
 
486
+ def file_upload_option(source)
487
+ # uploading packages on non-macOS platforms requires AppStoreInfo.plist starting with Transporter >= 4.1
488
+ if !Helper.is_mac? && File.directory?(source)
489
+ asset_file = Dir.glob(File.join(source, "*.{#{allowed_package_extensions.join(',')}}")).first
490
+ unless asset_file
491
+ UI.user_error!("No package file (#{allowed_package_extensions.join(',')}) found in #{source}")
492
+ end
493
+
494
+ appstore_info_path = File.join(source, "AppStoreInfo.plist")
495
+ unless File.file?(appstore_info_path)
496
+ UI.error("AppStoreInfo.plist is required for uploading #{File.extname(asset_file)} files on non-macOS platforms.")
497
+ UI.error("Expected AppStoreInfo.plist in the same directory as the #{File.extname(asset_file)} file.")
498
+ UI.error("Generate it by running either 'fastlane gym [...] --generate_appstore_info'")
499
+ UI.error("Or add '<key>generateAppStoreInformation</key><true/>' in an options.plist then run 'fastlane gym [...] --export_options options.plist'.")
500
+ UI.user_error!("Missing required AppStoreInfo.plist file for iTMSTransporter upload")
501
+ end
502
+
503
+ UI.verbose("Using AppStoreInfo.plist for iTMSTransporter upload: #{appstore_info_path}")
504
+ return "-assetFile #{asset_file.shellescape} -assetDescription #{appstore_info_path.shellescape}"
505
+ end
506
+
507
+ # use standard behavior for other file types or macOS platform
508
+ super(source)
509
+ end
510
+
459
511
  private
460
512
 
461
513
  def shell_escaped_password(password)
@@ -482,16 +534,26 @@ module FastlaneCore
482
534
  # Generates commands and executes the iTMSTransporter by invoking its Java app directly, to avoid the crazy parameter
483
535
  # escaping problems in its accompanying shell script.
484
536
  class JavaTransporterExecutor < TransporterExecutor
537
+ def build_credential_params(username = nil, password = nil, jwt = nil, api_key = nil, is_password_from_env = false)
538
+ if !username.nil? && jwt.to_s.empty?
539
+ if is_password_from_env
540
+ "-u #{username.shellescape} -p @env:ITMS_TRANSPORTER_PASSWORD"
541
+ elsif !password.nil?
542
+ "-u #{username.shellescape} -p #{password.shellescape}"
543
+ end
544
+ elsif !jwt.to_s.empty?
545
+ "-jwt #{jwt}"
546
+ end
547
+ end
548
+
485
549
  def build_upload_command(username, password, source = "/tmp", provider_short_name = "", jwt = nil, platform = nil, api_key = nil)
486
- use_jwt = !jwt.to_s.empty?
487
- if !Helper.user_defined_itms_path? && Helper.mac? && Helper.xcode_at_least?(11)
550
+ credential_params = build_credential_params(username, password, jwt, api_key, is_default_itms_on_xcode_11?)
551
+ if is_default_itms_on_xcode_11?
488
552
  [
489
- ("ITMS_TRANSPORTER_PASSWORD=#{password.shellescape}" unless use_jwt),
553
+ ("ITMS_TRANSPORTER_PASSWORD=#{password.shellescape}" if jwt.to_s.empty?),
490
554
  'xcrun iTMSTransporter',
491
555
  '-m upload',
492
- ("-u #{username.shellescape}" unless use_jwt),
493
- ("-p @env:ITMS_TRANSPORTER_PASSWORD" unless use_jwt),
494
- ("-jwt #{jwt}" if use_jwt),
556
+ credential_params,
495
557
  file_upload_option(source),
496
558
  additional_upload_parameters, # that's here, because the user might overwrite the -t option
497
559
  '-k 100000',
@@ -510,9 +572,7 @@ module FastlaneCore
510
572
  '-Dsun.net.http.retryPost=false',
511
573
  java_code_option,
512
574
  '-m upload',
513
- ("-u #{username.shellescape}" unless use_jwt),
514
- ("-p #{password.shellescape}" unless use_jwt),
515
- ("-jwt #{jwt}" if use_jwt),
575
+ credential_params,
516
576
  file_upload_option(source),
517
577
  additional_upload_parameters, # that's here, because the user might overwrite the -t option
518
578
  '-k 100000',
@@ -524,15 +584,13 @@ module FastlaneCore
524
584
 
525
585
  def build_verify_command(username, password, source = "/tmp", provider_short_name = "", **kwargs)
526
586
  jwt = kwargs[:jwt]
527
- use_jwt = !jwt.to_s.empty?
528
- if !Helper.user_defined_itms_path? && Helper.mac? && Helper.xcode_at_least?(11)
587
+ credential_params = build_credential_params(username, password, jwt, nil, is_default_itms_on_xcode_11?)
588
+ if is_default_itms_on_xcode_11?
529
589
  [
530
- ("ITMS_TRANSPORTER_PASSWORD=#{password.shellescape}" unless use_jwt),
590
+ ("ITMS_TRANSPORTER_PASSWORD=#{password.shellescape}" if jwt.to_s.empty?),
531
591
  'xcrun iTMSTransporter',
532
592
  '-m verify',
533
- ("-u #{username.shellescape}" unless use_jwt),
534
- ("-p @env:ITMS_TRANSPORTER_PASSWORD" unless use_jwt),
535
- ("-jwt #{jwt}" if use_jwt),
593
+ credential_params,
536
594
  "-f #{source.shellescape}",
537
595
  ("-itc_provider #{provider_short_name}" if jwt.nil? && !provider_short_name.to_s.empty?),
538
596
  '2>&1' # cause stderr to be written to stdout
@@ -549,9 +607,7 @@ module FastlaneCore
549
607
  '-Dsun.net.http.retryPost=false',
550
608
  java_code_option,
551
609
  '-m verify',
552
- ("-u #{username.shellescape}" unless use_jwt),
553
- ("-p #{password.shellescape}" unless use_jwt),
554
- ("-jwt #{jwt}" if use_jwt),
610
+ credential_params,
555
611
  "-f #{source.shellescape}",
556
612
  ("-itc_provider #{provider_short_name}" if jwt.nil? && !provider_short_name.to_s.empty?),
557
613
  '2>&1' # cause stderr to be written to stdout
@@ -560,15 +616,13 @@ module FastlaneCore
560
616
  end
561
617
 
562
618
  def build_download_command(username, password, apple_id, destination = "/tmp", provider_short_name = "", jwt = nil)
563
- use_jwt = !jwt.to_s.empty?
564
- if !Helper.user_defined_itms_path? && Helper.mac? && Helper.xcode_at_least?(11)
619
+ credential_params = build_credential_params(username, password, jwt, nil, is_default_itms_on_xcode_11?)
620
+ if is_default_itms_on_xcode_11?
565
621
  [
566
- ("ITMS_TRANSPORTER_PASSWORD=#{password.shellescape}" unless use_jwt),
622
+ ("ITMS_TRANSPORTER_PASSWORD=#{password.shellescape}" if jwt.to_s.empty?),
567
623
  'xcrun iTMSTransporter',
568
624
  '-m lookupMetadata',
569
- ("-u #{username.shellescape}" unless use_jwt),
570
- ("-p @env:ITMS_TRANSPORTER_PASSWORD" unless use_jwt),
571
- ("-jwt #{jwt}" if use_jwt),
625
+ credential_params,
572
626
  "-apple_id #{apple_id.shellescape}",
573
627
  "-destination #{destination.shellescape}",
574
628
  ("-itc_provider #{provider_short_name}" if jwt.nil? && !provider_short_name.to_s.empty?),
@@ -586,9 +640,7 @@ module FastlaneCore
586
640
  '-Dsun.net.http.retryPost=false',
587
641
  java_code_option,
588
642
  '-m lookupMetadata',
589
- ("-u #{username.shellescape}" unless use_jwt),
590
- ("-p #{password.shellescape}" unless use_jwt),
591
- ("-jwt #{jwt}" if use_jwt),
643
+ credential_params,
592
644
  "-apple_id #{apple_id.shellescape}",
593
645
  "-destination #{destination.shellescape}",
594
646
  ("-itc_provider #{provider_short_name}" if jwt.nil? && !provider_short_name.to_s.empty?),
@@ -598,15 +650,13 @@ module FastlaneCore
598
650
  end
599
651
 
600
652
  def build_provider_ids_command(username, password, jwt = nil, api_key = nil)
601
- use_jwt = !jwt.to_s.empty?
602
- if !Helper.user_defined_itms_path? && Helper.mac? && Helper.xcode_at_least?(11)
653
+ credential_params = build_credential_params(username, password, jwt, api_key, is_default_itms_on_xcode_11?)
654
+ if is_default_itms_on_xcode_11?
603
655
  [
604
- ("ITMS_TRANSPORTER_PASSWORD=#{password.shellescape}" unless use_jwt),
656
+ ("ITMS_TRANSPORTER_PASSWORD=#{password.shellescape}" if jwt.to_s.empty?),
605
657
  'xcrun iTMSTransporter',
606
658
  '-m provider',
607
- ("-u #{username.shellescape}" unless use_jwt),
608
- ("-p @env:ITMS_TRANSPORTER_PASSWORD" unless use_jwt),
609
- ("-jwt #{jwt}" if use_jwt),
659
+ credential_params,
610
660
  '2>&1' # cause stderr to be written to stdout
611
661
  ].compact.join(' ')
612
662
  else
@@ -621,14 +671,16 @@ module FastlaneCore
621
671
  '-Dsun.net.http.retryPost=false',
622
672
  java_code_option,
623
673
  '-m provider',
624
- ("-u #{username.shellescape}" unless use_jwt),
625
- ("-p #{password.shellescape}" unless use_jwt),
626
- ("-jwt #{jwt}" if use_jwt),
674
+ credential_params,
627
675
  '2>&1' # cause stderr to be written to stdout
628
676
  ].compact.join(' ')
629
677
  end
630
678
  end
631
679
 
680
+ def is_default_itms_on_xcode_11?
681
+ !Helper.user_defined_itms_path? && Helper.mac? && Helper.xcode_at_least?(11)
682
+ end
683
+
632
684
  def java_code_option
633
685
  if Helper.mac? && Helper.xcode_at_least?(9)
634
686
  return "-jar #{Helper.transporter_java_jar_path.shellescape}"
@@ -686,7 +738,7 @@ module FastlaneCore
686
738
  use_shell_script ||= Helper.windows?
687
739
  use_shell_script ||= Feature.enabled?('FASTLANE_ITUNES_TRANSPORTER_USE_SHELL_SCRIPT')
688
740
 
689
- if jwt.to_s.empty?
741
+ if jwt.to_s.empty? && api_key.nil?
690
742
  @user = user
691
743
  @password = password || load_password_for_transporter
692
744
  end
@@ -754,16 +806,16 @@ module FastlaneCore
754
806
  raise "app_id and dir are required or package_path or asset_path is required" if (app_id.nil? || dir.nil?) && package_path.nil? && asset_path.nil?
755
807
 
756
808
  # Transport can upload .ipa, .dmg, and .pkg files directly with -assetFile
757
- # However, -assetFile requires -assetDescription if Linux or Windows
758
- # This will give the asset directly if macOS and asset_path exists
759
- # otherwise it will use the .itmsp package
809
+ # However, -assetFile requires -assetDescription arguments if Linux or Windows.
810
+ # This will return the asset directly if asset_path exists,
811
+ # otherwise it will use the .itmsp package for the -f argument
760
812
 
761
813
  force_itmsp = FastlaneCore::Env.truthy?("ITMSTRANSPORTER_FORCE_ITMS_PACKAGE_UPLOAD")
762
814
  can_use_asset_path = Helper.is_mac? && asset_path
763
815
 
764
816
  actual_dir = if can_use_asset_path && !force_itmsp
765
817
  # The asset gets deleted upon completion so copying to a temp directory
766
- # (with randomized filename, for multibyte-mixed filename upload fails)
818
+ # (with randomized filename. for multibyte-mixed filename it fails to upload)
767
819
  new_file_name = "#{SecureRandom.uuid}#{File.extname(asset_path)}"
768
820
  tmp_asset_path = File.join(Dir.tmpdir, new_file_name)
769
821
  FileUtils.cp(asset_path, tmp_asset_path)
@@ -783,9 +835,7 @@ module FastlaneCore
783
835
  # Handle AppStore Connect API
784
836
  use_api_key = !@api_key.nil?
785
837
  api_key_placeholder = use_api_key ? { key_id: "YourKeyID", issuer_id: "YourIssuerID", key_dir: "YourTmpP8KeyDir" } : nil
786
-
787
- api_key = nil
788
- api_key = api_key_with_p8_file_path(@api_key) if use_api_key
838
+ api_key = @transporter_executor.prepare(original_api_key: @api_key)
789
839
 
790
840
  command = @transporter_executor.build_upload_command(@user, @password, actual_dir, @provider_short_name, @jwt, platform, api_key)
791
841
  UI.verbose(@transporter_executor.build_upload_command(@user, password_placeholder, actual_dir, @provider_short_name, jwt_placeholder, platform, api_key_placeholder))
@@ -846,8 +896,7 @@ module FastlaneCore
846
896
 
847
897
  # Masking credentials for verbose outputs
848
898
  api_key_placeholder = use_api_key ? { key_id: "YourKeyID", issuer_id: "YourIssuerID", key_dir: "YourTmpP8KeyDir" } : nil
849
-
850
- api_key = api_key_with_p8_file_path(@api_key) if use_api_key
899
+ api_key = @transporter_executor.prepare(original_api_key: @api_key)
851
900
 
852
901
  command = @transporter_executor.build_verify_command(@user, @password, actual_dir, @provider_short_name, jwt: @jwt, platform: platform, api_key: api_key)
853
902
  UI.verbose(@transporter_executor.build_verify_command(@user, password_placeholder, actual_dir, @provider_short_name, jwt: jwt_placeholder, platform: platform, api_key: api_key_placeholder))
@@ -882,8 +931,7 @@ module FastlaneCore
882
931
  use_api_key = !@api_key.nil?
883
932
  api_key_placeholder = use_api_key ? { key_id: "YourKeyID", issuer_id: "YourIssuerID", key_dir: "YourTmpP8KeyDir" } : nil
884
933
 
885
- api_key = nil
886
- api_key = api_key_with_p8_file_path(@api_key) if use_api_key
934
+ api_key = @transporter_executor.prepare(original_api_key: @api_key)
887
935
 
888
936
  command = @transporter_executor.build_provider_ids_command(@user, @password, @jwt, api_key)
889
937
  UI.verbose(@transporter_executor.build_provider_ids_command(@user, password_placeholder, jwt_placeholder, api_key_placeholder))
@@ -908,17 +956,6 @@ module FastlaneCore
908
956
 
909
957
  TWO_FACTOR_ENV_VARIABLE = "FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD"
910
958
 
911
- # Create .p8 file from api_key and provide api key info which contains .p8 file path
912
- def api_key_with_p8_file_path(original_api_key)
913
- api_key = original_api_key.dup
914
- api_key[:key_dir] = Dir.mktmpdir("deliver-")
915
- # Specified p8 needs to be generated to call altool
916
- File.open(File.join(api_key[:key_dir], "AuthKey_#{api_key[:key_id]}.p8"), "wb") do |p8|
917
- p8.write(api_key[:key])
918
- end
919
- api_key
920
- end
921
-
922
959
  # Returns whether altool should be used or ItunesTransporter should be used
923
960
  def should_use_altool?(altool_compatible_command, use_shell_script)
924
961
  # Xcode 14 no longer supports iTMSTransporter. Use altool instead
@@ -4,13 +4,15 @@ require 'security'
4
4
 
5
5
  module FastlaneCore
6
6
  class KeychainImporter
7
- def self.import_file(path, keychain_path, keychain_password: nil, certificate_password: "", skip_set_partition_list: false, output: FastlaneCore::Globals.verbose?)
7
+ def self.import_file(path, keychain_path, keychain_password: nil, certificate_password: "", certificate_format: nil, skip_set_partition_list: false, output: FastlaneCore::Globals.verbose?)
8
8
  UI.user_error!("Could not find file '#{path}'") unless File.exist?(path)
9
9
 
10
10
  password_part = " -P #{certificate_password.shellescape}"
11
+ certificate_format_part = certificate_format.to_s.strip.empty? ? "" : " -f #{certificate_format.shellescape}"
11
12
 
12
13
  command = "security import #{path.shellescape} -k '#{keychain_path.shellescape}'"
13
14
  command << password_part
15
+ command << certificate_format_part
14
16
  command << " -T /usr/bin/codesign" # to not be asked for permission when running a tool like `gym` (before Sierra)
15
17
  command << " -T /usr/bin/security"
16
18
  command << " -T /usr/bin/productbuild" # to not be asked for permission when using an installer cert for macOS
@@ -348,10 +348,18 @@ module FastlaneCore
348
348
  proj << "-clonedSourcePackagesDirPath #{options[:cloned_source_packages_path].shellescape}"
349
349
  end
350
350
 
351
+ if xcode_at_least_11 && options[:package_cache_path]
352
+ proj << "-packageCachePath #{options[:package_cache_path].shellescape}"
353
+ end
354
+
351
355
  if xcode_at_least_11 && options[:disable_package_automatic_updates]
352
356
  proj << "-disableAutomaticPackageResolution"
353
357
  end
354
358
 
359
+ if xcode_at_least_11 && options[:skip_package_repository_fetches]
360
+ proj << "-skipPackageUpdates"
361
+ end
362
+
355
363
  return proj
356
364
  end
357
365
 
@@ -73,7 +73,13 @@ module FastlaneCore
73
73
  end
74
74
 
75
75
  def profiles_path
76
- path = File.expand_path("~") + "/Library/MobileDevice/Provisioning Profiles/"
76
+ path = File.expand_path("~")
77
+ # Xcode 16 has a new location for provisioning profiles.
78
+ if FastlaneCore::Helper.xcode_at_least?(16)
79
+ path = File.join(path, "Library", "Developer", "Xcode", "UserData", "Provisioning Profiles")
80
+ else
81
+ path = File.join(path, "Library", "MobileDevice", "Provisioning Profiles")
82
+ end
77
83
  # If the directory doesn't exist, create it first
78
84
  unless File.directory?(path)
79
85
  FileUtils.mkdir_p(path)
@@ -71,9 +71,9 @@ module Frameit
71
71
  return nil
72
72
  end
73
73
 
74
- # Previously ENV[FRAMEIT_FORCE_DEVICE_TYPE] was matched to Deliver::AppScreenshot::ScreenSize constants. However,
74
+ # Previously ENV[FRAMEIT_FORCE_DEVICE_TYPE] was matched to Deliver::AppScreenshot display type strings.
75
75
  # options.rb defined a few Apple devices with unspecified IDs, this option was never read from Frameit.config.
76
- # Therefore this function matches both ScreenSize constants and formatted names to maintain backward compatibility.
76
+ # Therefore this function matches both DisplayType constants and formatted names to maintain backward compatibility.
77
77
  def self.find_device_by_id_or_name(id)
78
78
  return nil if id.nil?
79
79
  found_device = nil