fastlane 2.224.0 → 2.232.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +98 -92
  3. data/bin/fastlane +2 -2
  4. data/cert/lib/cert/options.rb +7 -2
  5. data/cert/lib/cert/runner.rb +23 -11
  6. data/deliver/lib/assets/summary.html.erb +3 -3
  7. data/deliver/lib/deliver/app_screenshot.rb +215 -347
  8. data/deliver/lib/deliver/app_screenshot_iterator.rb +4 -1
  9. data/deliver/lib/deliver/app_screenshot_validator.rb +5 -21
  10. data/deliver/lib/deliver/loader.rb +2 -9
  11. data/deliver/lib/deliver/options.rb +1 -1
  12. data/deliver/lib/deliver/runner.rb +1 -1
  13. data/deliver/lib/deliver/upload_metadata.rb +5 -0
  14. data/deliver/lib/deliver/upload_screenshots.rb +4 -2
  15. data/fastlane/lib/assets/completions/completion.bash +1 -1
  16. data/fastlane/lib/assets/completions/completion.sh +2 -2
  17. data/fastlane/lib/fastlane/actions/app_store_build_number.rb +16 -15
  18. data/fastlane/lib/fastlane/actions/appium.rb +1 -1
  19. data/fastlane/lib/fastlane/actions/docs/create_app_online.md +6 -3
  20. data/fastlane/lib/fastlane/actions/docs/sync_code_signing.md +12 -8
  21. data/fastlane/lib/fastlane/actions/docs/upload_to_app_store.md.erb +56 -17
  22. data/fastlane/lib/fastlane/actions/docs/upload_to_testflight.md +13 -1
  23. data/fastlane/lib/fastlane/actions/get_version_number.rb +1 -1
  24. data/fastlane/lib/fastlane/actions/import_certificate.rb +9 -1
  25. data/fastlane/lib/fastlane/actions/import_from_git.rb +11 -4
  26. data/fastlane/lib/fastlane/actions/increment_build_number.rb +1 -1
  27. data/fastlane/lib/fastlane/actions/install_xcode_plugin.rb +3 -2
  28. data/fastlane/lib/fastlane/actions/latest_testflight_build_number.rb +2 -2
  29. data/fastlane/lib/fastlane/actions/modify_services.rb +1 -0
  30. data/fastlane/lib/fastlane/actions/notarize.rb +4 -0
  31. data/fastlane/lib/fastlane/actions/onesignal.rb +1 -1
  32. data/fastlane/lib/fastlane/actions/register_device.rb +1 -1
  33. data/fastlane/lib/fastlane/actions/register_devices.rb +1 -1
  34. data/fastlane/lib/fastlane/actions/setup_ci.rb +14 -4
  35. data/fastlane/lib/fastlane/actions/testfairy.rb +41 -4
  36. data/fastlane/lib/fastlane/actions/unlock_keychain.rb +6 -1
  37. data/fastlane/lib/fastlane/actions/upload_to_app_store.rb +1 -1
  38. data/fastlane/lib/fastlane/actions/xcov.rb +1 -7
  39. data/fastlane/lib/fastlane/cli_tools_distributor.rb +9 -0
  40. data/fastlane/lib/fastlane/documentation/markdown_docs_generator.rb +4 -4
  41. data/fastlane/lib/fastlane/erb_template_helper.rb +1 -7
  42. data/fastlane/lib/fastlane/fast_file.rb +9 -6
  43. data/fastlane/lib/fastlane/helper/s3_client_helper.rb +4 -0
  44. data/fastlane/lib/fastlane/plugins/template/%gem_name%.gemspec.erb +1 -1
  45. data/fastlane/lib/fastlane/plugins/template/.github/workflows/test.yml +20 -20
  46. data/fastlane/lib/fastlane/plugins/template/.rubocop.yml +1 -1
  47. data/fastlane/lib/fastlane/version.rb +2 -1
  48. data/fastlane/swift/Actions.swift +1 -1
  49. data/fastlane/swift/Appfile.swift +13 -5
  50. data/fastlane/swift/ArgumentProcessor.swift +1 -1
  51. data/fastlane/swift/Atomic.swift +1 -1
  52. data/fastlane/swift/ControlCommand.swift +5 -4
  53. data/fastlane/swift/Deliverfile.swift +2 -2
  54. data/fastlane/swift/DeliverfileProtocol.swift +265 -68
  55. data/fastlane/swift/Fastlane.swift +187 -168
  56. data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/project.pbxproj +3 -1
  57. data/fastlane/swift/Gymfile.swift +2 -2
  58. data/fastlane/swift/GymfileProtocol.swift +227 -54
  59. data/fastlane/swift/LaneFileProtocol.swift +7 -5
  60. data/fastlane/swift/MainProcess.swift +1 -1
  61. data/fastlane/swift/Matchfile.swift +2 -2
  62. data/fastlane/swift/MatchfileProtocol.swift +226 -59
  63. data/fastlane/swift/OptionalConfigValue.swift +1 -1
  64. data/fastlane/swift/Plugins.swift +1 -1
  65. data/fastlane/swift/Precheckfile.swift +2 -2
  66. data/fastlane/swift/PrecheckfileProtocol.swift +45 -13
  67. data/fastlane/swift/RubyCommand.swift +6 -7
  68. data/fastlane/swift/RubyCommandable.swift +1 -1
  69. data/fastlane/swift/Runner.swift +3 -3
  70. data/fastlane/swift/RunnerArgument.swift +1 -1
  71. data/fastlane/swift/Scanfile.swift +2 -2
  72. data/fastlane/swift/ScanfileProtocol.swift +334 -84
  73. data/fastlane/swift/Screengrabfile.swift +2 -2
  74. data/fastlane/swift/ScreengrabfileProtocol.swift +89 -24
  75. data/fastlane/swift/Snapshotfile.swift +2 -2
  76. data/fastlane/swift/SnapshotfileProtocol.swift +216 -53
  77. data/fastlane/swift/SocketClient.swift +7 -7
  78. data/fastlane/swift/SocketClientDelegateProtocol.swift +1 -1
  79. data/fastlane/swift/SocketResponse.swift +1 -1
  80. data/fastlane/swift/formatting/Brewfile.lock.json +15 -25
  81. data/fastlane/swift/formatting/Rakefile +1 -2
  82. data/fastlane/swift/main.swift +1 -1
  83. data/fastlane_core/lib/assets/XMLTemplate.xml.erb +5 -1
  84. data/fastlane_core/lib/fastlane_core/cert_checker.rb +10 -0
  85. data/fastlane_core/lib/fastlane_core/command_executor.rb +3 -1
  86. data/fastlane_core/lib/fastlane_core/fastlane_pty.rb +5 -1
  87. data/fastlane_core/lib/fastlane_core/helper.rb +6 -1
  88. data/fastlane_core/lib/fastlane_core/ipa_file_analyser.rb +4 -14
  89. data/fastlane_core/lib/fastlane_core/ipa_upload_package_builder.rb +19 -2
  90. data/fastlane_core/lib/fastlane_core/itunes_transporter.rb +143 -106
  91. data/fastlane_core/lib/fastlane_core/keychain_importer.rb +3 -1
  92. data/fastlane_core/lib/fastlane_core/project.rb +8 -0
  93. data/fastlane_core/lib/fastlane_core/provisioning_profile.rb +7 -1
  94. data/frameit/lib/frameit/device.rb +2 -2
  95. data/frameit/lib/frameit/device_types.rb +108 -70
  96. data/frameit/lib/frameit/template_finder.rb +1 -1
  97. data/gym/lib/assets/wrap_xcodebuild/xcbuild-safe.sh +1 -0
  98. data/gym/lib/gym/module.rb +9 -4
  99. data/gym/lib/gym/options.rb +20 -2
  100. data/gym/lib/gym/runner.rb +38 -3
  101. data/match/lib/assets/READMETemplate.md +2 -2
  102. data/match/lib/match/generator.rb +2 -2
  103. data/match/lib/match/options.rb +1 -0
  104. data/match/lib/match/runner.rb +1 -1
  105. data/match/lib/match/storage/s3_storage.rb +4 -7
  106. data/pilot/lib/pilot/build_manager.rb +7 -1
  107. data/precheck/lib/precheck/options.rb +1 -1
  108. data/produce/lib/produce/commands_generator.rb +2 -0
  109. data/produce/lib/produce/developer_center.rb +1 -0
  110. data/produce/lib/produce/options.rb +1 -1
  111. data/produce/lib/produce/service.rb +6 -1
  112. data/scan/lib/scan/error_handler.rb +5 -0
  113. data/scan/lib/scan/options.rb +13 -3
  114. data/scan/lib/scan/test_command_generator.rb +10 -2
  115. data/sigh/lib/assets/resign.sh +7 -5
  116. data/sigh/lib/sigh/local_manage.rb +6 -4
  117. data/sigh/lib/sigh/options.rb +1 -0
  118. data/sigh/lib/sigh/runner.rb +23 -3
  119. data/snapshot/lib/snapshot/detect_values.rb +1 -1
  120. data/snapshot/lib/snapshot/options.rb +13 -1
  121. data/snapshot/lib/snapshot/simulator_launchers/simulator_launcher_base.rb +4 -2
  122. data/spaceship/lib/spaceship/client.rb +153 -22
  123. data/spaceship/lib/spaceship/connect_api/models/age_rating_declaration.rb +65 -9
  124. data/spaceship/lib/spaceship/connect_api/models/app_info_localization.rb +4 -4
  125. data/spaceship/lib/spaceship/connect_api/models/app_screenshot_set.rb +7 -1
  126. data/spaceship/lib/spaceship/connect_api/models/app_store_version_localization.rb +16 -16
  127. data/spaceship/lib/spaceship/connect_api/models/build_upload.rb +42 -0
  128. data/spaceship/lib/spaceship/connect_api/models/bundle_id_capability.rb +2 -0
  129. data/spaceship/lib/spaceship/connect_api/models/certificate.rb +33 -2
  130. data/spaceship/lib/spaceship/connect_api/models/device.rb +1 -2
  131. data/spaceship/lib/spaceship/connect_api/models/profile.rb +2 -3
  132. data/spaceship/lib/spaceship/connect_api/models/webhook.rb +62 -0
  133. data/spaceship/lib/spaceship/connect_api/provisioning/provisioning.rb +0 -6
  134. data/spaceship/lib/spaceship/connect_api/testflight/testflight.rb +9 -0
  135. data/spaceship/lib/spaceship/connect_api/tunes/tunes.rb +38 -0
  136. data/spaceship/lib/spaceship/connect_api.rb +2 -0
  137. data/spaceship/lib/spaceship/errors.rb +23 -6
  138. data/spaceship/lib/spaceship/portal/key.rb +22 -3
  139. data/spaceship/lib/spaceship/portal/portal_client.rb +29 -2
  140. data/spaceship/lib/spaceship/spaceauth_runner.rb +5 -15
  141. data/supply/lib/supply/client.rb +18 -1
  142. data/supply/lib/supply/uploader.rb +22 -11
  143. data/trainer/lib/trainer/legacy_xcresult.rb +586 -0
  144. data/trainer/lib/trainer/options.rb +5 -0
  145. data/trainer/lib/trainer/plist_test_summary_parser.rb +84 -0
  146. data/trainer/lib/trainer/test_parser.rb +12 -293
  147. data/trainer/lib/trainer/xcresult/helper.rb +63 -0
  148. data/trainer/lib/trainer/xcresult/repetition.rb +39 -0
  149. data/trainer/lib/trainer/xcresult/test_case.rb +221 -0
  150. data/trainer/lib/trainer/xcresult/test_case_attributes.rb +49 -0
  151. data/trainer/lib/trainer/xcresult/test_plan.rb +91 -0
  152. data/trainer/lib/trainer/xcresult/test_suite.rb +134 -0
  153. data/trainer/lib/trainer/xcresult.rb +31 -388
  154. data/trainer/lib/trainer.rb +3 -1
  155. metadata +172 -33
  156. data/fastlane/lib/fastlane/actions/hipchat.rb +0 -200
  157. data/fastlane/lib/fastlane/core_ext/bundler_monkey_patch.rb +0 -14
  158. data/fastlane/lib/fastlane/plugins/template/.circleci/config.yml +0 -43
  159. data/fastlane/lib/fastlane/plugins/template/.travis.yml +0 -4
@@ -54,10 +54,10 @@ module Scan
54
54
  options << "-scmProvider system"
55
55
  end
56
56
  if config[:result_bundle_path]
57
- options << "-resultBundlePath '#{config[:result_bundle_path].shellescape}'"
57
+ options << "-resultBundlePath #{config[:result_bundle_path].shellescape}"
58
58
  Scan.cache[:result_bundle_path] = config[:result_bundle_path]
59
59
  elsif config[:result_bundle]
60
- options << "-resultBundlePath '#{result_bundle_path(true)}'"
60
+ options << "-resultBundlePath #{result_bundle_path(true).shellescape}"
61
61
  end
62
62
  if FastlaneCore::Helper.xcode_at_least?(10)
63
63
  options << "-parallel-testing-enabled #{config[:parallel_testing] ? 'YES' : 'NO'}" unless config[:parallel_testing].nil?
@@ -69,6 +69,14 @@ module Scan
69
69
  options << "-enableAddressSanitizer #{config[:address_sanitizer] ? 'YES' : 'NO'}" unless config[:address_sanitizer].nil?
70
70
  options << "-enableThreadSanitizer #{config[:thread_sanitizer] ? 'YES' : 'NO'}" unless config[:thread_sanitizer].nil?
71
71
  if FastlaneCore::Helper.xcode_at_least?(11)
72
+ if config[:cloned_source_packages_path] && !options.include?("-clonedSourcePackagesDirPath #{config[:cloned_source_packages_path].shellescape}")
73
+ options << "-clonedSourcePackagesDirPath #{config[:cloned_source_packages_path].shellescape}"
74
+ end
75
+
76
+ if config[:package_cache_path] && !options.include?("-packageCachePath #{config[:package_cache_path].shellescape}")
77
+ options << "-packageCachePath #{config[:package_cache_path].shellescape}"
78
+ end
79
+
72
80
  options << "-testPlan '#{config[:testplan]}'" if config[:testplan]
73
81
 
74
82
  # detect_values will ensure that these values are present as Arrays if
@@ -548,8 +548,8 @@ function resign {
548
548
  for assetpack in "$ODR_DIR"/*
549
549
  do
550
550
  if [[ "$assetpack" == *.assetpack ]]; then
551
- rm -rf $assetpack/_CodeSignature
552
- /usr/bin/codesign ${VERBOSE} --generate-entitlement-der ${KEYCHAIN_FLAG} -f -s "$CERTIFICATE" "$assetpack"
551
+ rm -rf "$assetpack"/_CodeSignature
552
+ /usr/bin/codesign "${VERBOSE}" --generate-entitlement-der "${KEYCHAIN_FLAG}" -f -s "$CERTIFICATE" "$assetpack"
553
553
  checkStatus
554
554
  else
555
555
  log "Ignoring non-assetpack: $assetpack"
@@ -625,7 +625,7 @@ function resign {
625
625
  log "Creating an archived-expanded-entitlements.xcent file for Xcode 9 builds or earlier"
626
626
  cp -f "$ENTITLEMENTS" "$APP_PATH/archived-expanded-entitlements.xcent"
627
627
  fi
628
- /usr/bin/codesign ${VERBOSE} --generate-entitlement-der -f -s "$CERTIFICATE" --entitlements "$ENTITLEMENTS" "$APP_PATH"
628
+ /usr/bin/codesign "${VERBOSE}" --generate-entitlement-der -f -s "$CERTIFICATE" --entitlements "$ENTITLEMENTS" "$APP_PATH"
629
629
  checkStatus
630
630
  elif [[ -n "${USE_APP_ENTITLEMENTS}" ]]; then
631
631
  # Extract entitlements from provisioning profile and from the app binary
@@ -823,7 +823,7 @@ function resign {
823
823
  log "Certificate $CERTIFICATE matches a SHA1 pattern"
824
824
  local certificate_matches="$( security find-identity -v -p codesigning | grep -m 1 "$CERTIFICATE" )"
825
825
  if [ -n "$certificate_matches" ]; then
826
- certificate_name="$(/usr/bin/sed -E s/[^\"]+\"\([^\"]+\)\".*/\\1/ <<< $certificate_matches )"
826
+ certificate_name="$(/usr/bin/sed -E s/[^\"]+\"\([^\"]+\)\".*/\\1/ <<< "$certificate_matches" )"
827
827
  log "Certificate name: $certificate_name"
828
828
  fi
829
829
  fi
@@ -870,7 +870,7 @@ function resign {
870
870
  log "Creating an archived-expanded-entitlements.xcent file for Xcode 9 builds or earlier"
871
871
  cp -f "$PATCHED_ENTITLEMENTS" "$APP_PATH/archived-expanded-entitlements.xcent"
872
872
  fi
873
- /usr/bin/codesign ${VERBOSE} --generate-entitlement-der -f -s "$CERTIFICATE" --entitlements "$PATCHED_ENTITLEMENTS" "$APP_PATH"
873
+ /usr/bin/codesign "${VERBOSE}" --generate-entitlement-der -f -s "$CERTIFICATE" --entitlements "$PATCHED_ENTITLEMENTS" "$APP_PATH"
874
874
  checkStatus
875
875
  else
876
876
  log "Extracting entitlements from provisioning profile"
@@ -917,10 +917,12 @@ log "Repackaging as $NEW_FILE"
917
917
  # Navigate to the temporary directory (sending the output to null)
918
918
  # Zip all the contents, saving the zip file in the above directory
919
919
  # Navigate back to the originating directory (sending the output to null)
920
+ # shellcheck disable=SC2164
920
921
  pushd "$TEMP_DIR" > /dev/null
921
922
  # TODO: Fix shellcheck warning and remove directive
922
923
  # shellcheck disable=SC2035
923
924
  zip -qry "../$TEMP_DIR.ipa" *
925
+ # shellcheck disable=SC2164
924
926
  popd > /dev/null
925
927
 
926
928
  # Move the resulting ipa to the target destination
@@ -1,5 +1,6 @@
1
1
  require 'plist'
2
2
  require 'fastlane_core/globals'
3
+ require 'fastlane_core/provisioning_profile'
3
4
 
4
5
  require_relative 'module'
5
6
 
@@ -19,10 +20,10 @@ module Sigh
19
20
 
20
21
  def self.install_profile(profile)
21
22
  UI.message("Installing provisioning profile...")
22
- profile_path = File.expand_path("~") + "/Library/MobileDevice/Provisioning Profiles/"
23
+ profile_path = FastlaneCore::ProvisioningProfile.profiles_path
23
24
  uuid = ENV["SIGH_UUID"] || ENV["SIGH_UDID"]
24
25
  profile_filename = uuid + ".mobileprovision"
25
- destination = profile_path + profile_filename
26
+ destination = File.join(profile_path, profile_filename)
26
27
 
27
28
  # If the directory doesn't exist, make it first
28
29
  unless File.directory?(profile_path)
@@ -126,8 +127,9 @@ module Sigh
126
127
  end
127
128
 
128
129
  def self.load_profiles
129
- UI.message("Loading Provisioning profiles from ~/Library/MobileDevice/Provisioning Profiles/")
130
- profiles_path = File.expand_path("~") + "/Library/MobileDevice/Provisioning Profiles/*.mobileprovision"
130
+ profiles_path = FastlaneCore::ProvisioningProfile.profiles_path
131
+ UI.message("Loading Provisioning profiles from #{profiles_path}")
132
+ profiles_path = File.join(profiles_path, "*.mobileprovision")
131
133
  profile_paths = Dir[profiles_path]
132
134
 
133
135
  profiles = []
@@ -190,6 +190,7 @@ module Sigh
190
190
  env_name: "SIGH_PROVISIONING_PROFILE_TEMPLATE_NAME",
191
191
  description: "The name of provisioning profile template. If the developer account has provisioning profile templates (aka: custom entitlements), the template name can be found by inspecting the Entitlements drop-down while creating/editing a provisioning profile (e.g. \"Apple Pay Pass Suppression Development\")",
192
192
  optional: true,
193
+ deprecated: "Removed since May 2025 on App Store Connect API OpenAPI v3.8.0 - Learn more: https://docs.fastlane.tools/actions/match/#managed-capabilities",
193
194
  default_value: nil),
194
195
  FastlaneCore::ConfigItem.new(key: :fail_on_name_taken,
195
196
  env_name: "SIGH_FAIL_ON_NAME_TAKEN",
@@ -84,7 +84,7 @@ module Sigh
84
84
 
85
85
  includes = 'bundleId'
86
86
 
87
- unless Sigh.config[:skip_certificate_verification] || Sigh.config[:include_all_certificates]
87
+ unless (Sigh.config[:skip_certificate_verification] || Sigh.config[:include_all_certificates]) && Sigh.config[:cert_id].to_s.length == 0
88
88
  includes += ',certificates'
89
89
  end
90
90
 
@@ -105,6 +105,8 @@ module Sigh
105
105
 
106
106
  # Take the provisioning profile name into account
107
107
  results = filter_profiles_by_name(results) if Sigh.config[:provisioning_name].to_s.length > 0
108
+ # Take the cert_id into account
109
+ results = filter_profiles_by_cert_id(results) if Sigh.config[:cert_id].to_s.length > 0
108
110
  return results if Sigh.config[:skip_certificate_verification] || Sigh.config[:include_all_certificates]
109
111
 
110
112
  UI.message("Verifying certificates...")
@@ -174,13 +176,16 @@ module Sigh
174
176
 
175
177
  UI.important("Creating new provisioning profile for '#{Sigh.config[:app_identifier]}' with name '#{name}' for '#{Sigh.config[:platform]}' platform")
176
178
 
179
+ unless Sigh.config[:template_name].nil?
180
+ UI.important("Template name is set to '#{Sigh.config[:template_name]}', however, this is not supported by the App Store Connect API anymore, since May 2025. The template name will be ignored. For more information: https://docs.fastlane.tools/actions/match/#managed-capabilities")
181
+ end
182
+
177
183
  profile = Spaceship::ConnectAPI::Profile.create(
178
184
  name: name,
179
185
  profile_type: profile_type,
180
186
  bundle_id_id: bundle_id.id,
181
187
  certificate_ids: certificates_to_use.map(&:id),
182
- device_ids: devices_to_use.map(&:id),
183
- template_name: Sigh.config[:template_name]
188
+ device_ids: devices_to_use.map(&:id)
184
189
  )
185
190
 
186
191
  profile
@@ -196,6 +201,21 @@ module Sigh
196
201
  profiles
197
202
  end
198
203
 
204
+ def filter_profiles_by_cert_id(profiles)
205
+ filtered = profiles.find_all do |current_profile|
206
+ valid_cert_id = false
207
+ current_profile.certificates.each do |cert|
208
+ if cert.id == Sigh.config[:cert_id].to_s
209
+ valid_cert_id = true
210
+ else
211
+ UI.message("Provisioning Profile cert_id : '#{cert.id}' does not match given cert_id : '#{Sigh.config[:cert_id]}', skipping this one...")
212
+ end
213
+ end
214
+ valid_cert_id
215
+ end
216
+ filtered
217
+ end
218
+
199
219
  def fetch_certificates(certificate_types)
200
220
  filter = {
201
221
  certificateType: certificate_types.join(',')
@@ -66,7 +66,7 @@ module Snapshot
66
66
 
67
67
  config[:devices] << sim.name
68
68
  end
69
- elsif Snapshot.project.mac?
69
+ elsif config[:devices].nil? && Snapshot.project.mac?
70
70
  config[:devices] = ["Mac"]
71
71
  end
72
72
  end
@@ -5,6 +5,7 @@ require 'credentials_manager/appfile_config'
5
5
  require_relative 'module'
6
6
 
7
7
  module Snapshot
8
+ # rubocop:disable Metrics/ClassLength
8
9
  class Options
9
10
  def self.verify_type(item_name, acceptable_types, value)
10
11
  type_ok = [Array, String].any? { |type| value.kind_of?(type) }
@@ -257,6 +258,11 @@ module Snapshot
257
258
  description: "Sets a custom path for Swift Package Manager dependencies",
258
259
  type: String,
259
260
  optional: true),
261
+ FastlaneCore::ConfigItem.new(key: :package_cache_path,
262
+ env_name: "SNAPSHOT_PACKAGE_CACHE_PATH",
263
+ description: "Sets a custom package cache path for Swift Package Manager dependencies",
264
+ type: String,
265
+ optional: true),
260
266
  FastlaneCore::ConfigItem.new(key: :skip_package_dependencies_resolution,
261
267
  env_name: "SNAPSHOT_SKIP_PACKAGE_DEPENDENCIES_RESOLUTION",
262
268
  description: "Skips resolution of Swift Package Manager dependencies",
@@ -264,7 +270,12 @@ module Snapshot
264
270
  default_value: false),
265
271
  FastlaneCore::ConfigItem.new(key: :disable_package_automatic_updates,
266
272
  env_name: "SNAPSHOT_DISABLE_PACKAGE_AUTOMATIC_UPDATES",
267
- description: "Prevents packages from automatically being resolved to versions other than those recorded in the `Package.resolved` file",
273
+ description: "Prevents packages from automatically being resolved to versions other than those recorded in the `Package.resolved` file. This translates in the option `-disableAutomaticPackageResolution` being passed to xcodebuild",
274
+ type: Boolean,
275
+ default_value: false),
276
+ FastlaneCore::ConfigItem.new(key: :skip_package_repository_fetches,
277
+ env_name: "SNAPSHOT_SKIP_PACKAGE_REPOSITORY_FETCHES",
278
+ description: "Skips updating package dependencies from their remote. This translates in the option `-skipPackageUpdates` being passed to xcodebuild",
268
279
  type: Boolean,
269
280
  default_value: false),
270
281
  FastlaneCore::ConfigItem.new(key: :package_authorization_provider,
@@ -332,4 +343,5 @@ module Snapshot
332
343
  ]
333
344
  end
334
345
  end
346
+ # rubocop:enable Metrics/ClassLength
335
347
  end
@@ -133,12 +133,14 @@ module Snapshot
133
133
  UI.message("Overriding Status Bar")
134
134
 
135
135
  if arguments.nil? || arguments.empty?
136
- # The time needs to be passed as ISO8601 so the simulator formats it correctly
136
+ # The time must be passed as HH:MM format (e.g., "09:41")
137
+ # Note: Despite the simctl manual stating ISO date strings are supported, only HH:MM format actually works
137
138
  time = Time.new(2007, 1, 9, 9, 41, 0)
139
+ time_str = time.strftime("%H:%M")
138
140
 
139
141
  # If you don't override the operator name, you'll get "Carrier" in the status bar on no-notch devices such as iPhone 8. Pass an empty string to blank it out.
140
142
 
141
- arguments = "--time #{time.iso8601} --dataNetwork wifi --wifiMode active --wifiBars 3 --cellularMode active --operatorName '' --cellularBars 4 --batteryState charged --batteryLevel 100"
143
+ arguments = "--time #{time_str} --dataNetwork wifi --wifiMode active --wifiBars 3 --cellularMode active --operatorName '' --cellularBars 4 --batteryState charged --batteryLevel 100"
142
144
  end
143
145
 
144
146
  Helper.backticks("xcrun simctl status_bar #{device_udid} override #{arguments} &> /dev/null")
@@ -450,6 +450,114 @@ module Spaceship
450
450
  return false
451
451
  end
452
452
 
453
+ def do_sirp(user, password, modified_cookie)
454
+ require 'fastlane-sirp'
455
+ require 'base64'
456
+
457
+ client = SIRP::Client.new(2048)
458
+ a = client.start_authentication
459
+
460
+ data = {
461
+ a: Base64.strict_encode64(to_byte(a)),
462
+ accountName: user,
463
+ protocols: ['s2k', 's2k_fo']
464
+ }
465
+
466
+ response = request(:post) do |req|
467
+ req.url("https://idmsa.apple.com/appleauth/auth/signin/init")
468
+ req.body = data.to_json
469
+ req.headers['Content-Type'] = 'application/json'
470
+ req.headers['X-Requested-With'] = 'XMLHttpRequest'
471
+ req.headers['X-Apple-Widget-Key'] = self.itc_service_key
472
+ req.headers['Accept'] = 'application/json, text/javascript'
473
+ req.headers["Cookie"] = modified_cookie if modified_cookie
474
+ end
475
+
476
+ puts("Received SIRP signin init response: #{response.body}") if Spaceship::Globals.verbose?
477
+
478
+ body = response.body
479
+ unless body.kind_of?(Hash)
480
+ raise UnexpectedResponse, "Expected JSON response, but got #{body.class}: #{body.to_s[0..1000]}"
481
+ end
482
+
483
+ if body["serviceErrors"]
484
+ raise UnexpectedResponse, body
485
+ end
486
+
487
+ iterations = body["iteration"]
488
+ salt = Base64.strict_decode64(body["salt"])
489
+ b = Base64.strict_decode64(body["b"])
490
+ c = body["c"]
491
+ protocol = body["protocol"]
492
+
493
+ key_length = 32
494
+ encrypted_password = pbkdf2(password, salt, iterations, key_length, protocol)
495
+
496
+ m1 = client.process_challenge(
497
+ user,
498
+ to_hex(encrypted_password),
499
+ to_hex(salt),
500
+ to_hex(b),
501
+ is_password_encrypted: true
502
+ )
503
+ m2 = client.H_AMK
504
+
505
+ if m1 == false
506
+ puts("Error processing SIRP challenge") if Spaceship::Globals.verbose?
507
+ raise SIRPAuthenticationError
508
+ end
509
+
510
+ data = {
511
+ accountName: user,
512
+ c: c,
513
+ m1: Base64.encode64(to_byte(m1)).strip,
514
+ m2: Base64.encode64(to_byte(m2)).strip,
515
+ rememberMe: false
516
+ }
517
+
518
+ hashcash = self.fetch_hashcash
519
+
520
+ response = request(:post) do |req|
521
+ req.url("https://idmsa.apple.com/appleauth/auth/signin/complete?isRememberMeEnabled=false")
522
+ req.body = data.to_json
523
+ req.headers['Content-Type'] = 'application/json'
524
+ req.headers['X-Requested-With'] = 'XMLHttpRequest'
525
+ req.headers['X-Apple-Widget-Key'] = self.itc_service_key
526
+ req.headers['Accept'] = 'application/json, text/javascript'
527
+ req.headers["Cookie"] = modified_cookie if modified_cookie
528
+ req.headers["X-Apple-HC"] = hashcash if hashcash
529
+ end
530
+
531
+ puts("Completed SIRP authentication with status of #{response.status}") if Spaceship::Globals.verbose?
532
+
533
+ return response
534
+ end
535
+
536
+ def pbkdf2(password, salt, iterations, key_length, protocol, digest = OpenSSL::Digest::SHA256.new)
537
+ require 'openssl'
538
+
539
+ unless %w[s2k s2k_fo].include?(protocol)
540
+ raise SIRPAuthenticationError, "Unsupported protocol '#{protocol}' for pbkdf2"
541
+ end
542
+
543
+ password = OpenSSL::Digest::SHA256.digest(password)
544
+
545
+ if protocol == 's2k_fo'
546
+ puts("Using legacy s2k_fo protocol for password digest") if Spaceship::Globals.verbose?
547
+ password = to_hex(password)
548
+ end
549
+
550
+ OpenSSL::PKCS5.pbkdf2_hmac(password, salt, iterations, key_length, digest)
551
+ end
552
+
553
+ def to_hex(str)
554
+ str.unpack1('H*')
555
+ end
556
+
557
+ def to_byte(str)
558
+ [str].pack('H*')
559
+ end
560
+
453
561
  # This method is used for both the Apple Dev Portal and App Store Connect
454
562
  # This will also handle 2 step verification and 2 factor authentication
455
563
  #
@@ -465,12 +573,6 @@ module Spaceship
465
573
  # If the session is valid no need to attempt to generate a new one.
466
574
  return true if has_valid_session
467
575
 
468
- data = {
469
- accountName: user,
470
- password: password,
471
- rememberMe: true
472
- }
473
-
474
576
  begin
475
577
  # The below workaround is only needed for 2 step verified machines
476
578
  # Due to escaping of cookie values we have a little workaround here
@@ -491,22 +593,7 @@ module Spaceship
491
593
  modified_cookie.gsub!(unescaped_important_cookie, escaped_important_cookie)
492
594
  end
493
595
 
494
- # Fixes issue https://github.com/fastlane/fastlane/issues/21071
495
- # On 2023-02-23, Apple added a custom implementation
496
- # of hashcash to their auth flow
497
- # hashcash = nil
498
- hashcash = self.fetch_hashcash
499
-
500
- response = request(:post) do |req|
501
- req.url("https://idmsa.apple.com/appleauth/auth/signin")
502
- req.body = data.to_json
503
- req.headers['Content-Type'] = 'application/json'
504
- req.headers['X-Requested-With'] = 'XMLHttpRequest'
505
- req.headers['X-Apple-Widget-Key'] = self.itc_service_key
506
- req.headers['Accept'] = 'application/json, text/javascript'
507
- req.headers["Cookie"] = modified_cookie if modified_cookie
508
- req.headers["X-Apple-HC"] = hashcash if hashcash
509
- end
596
+ response = perform_login_method(user, password, modified_cookie)
510
597
  rescue UnauthorizedAccessError
511
598
  raise InvalidUserCredentialsError.new, "Invalid username and password combination. Used '#{user}' as the username."
512
599
  end
@@ -552,6 +639,40 @@ module Spaceship
552
639
  end
553
640
  # rubocop:enable Metrics/PerceivedComplexity
554
641
 
642
+ def perform_login_method(user, password, modified_cookie)
643
+ do_legacy_signin = ENV['FASTLANE_USE_LEGACY_PRE_SIRP_AUTH']
644
+ if do_legacy_signin
645
+ puts("Starting legacy Apple ID login") if Spaceship::Globals.verbose?
646
+
647
+ # Fixes issue https://github.com/fastlane/fastlane/issues/21071
648
+ # On 2023-02-23, Apple added a custom implementation
649
+ # of hashcash to their auth flow
650
+ # hashcash = nil
651
+ hashcash = self.fetch_hashcash
652
+
653
+ data = {
654
+ accountName: user,
655
+ password: password,
656
+ rememberMe: true
657
+ }
658
+
659
+ return request(:post) do |req|
660
+ req.url("https://idmsa.apple.com/appleauth/auth/signin")
661
+ req.body = data.to_json
662
+ req.headers['Content-Type'] = 'application/json'
663
+ req.headers['X-Requested-With'] = 'XMLHttpRequest'
664
+ req.headers['X-Apple-Widget-Key'] = self.itc_service_key
665
+ req.headers['Accept'] = 'application/json, text/javascript'
666
+ req.headers["Cookie"] = modified_cookie if modified_cookie
667
+ req.headers["X-Apple-HC"] = hashcash if hashcash
668
+ end
669
+ else
670
+ # Fixes issue https://github.com/fastlane/fastlane/issues/26368#issuecomment-2424190032
671
+ puts("Starting SIRP Apple ID login") if Spaceship::Globals.verbose?
672
+ return do_sirp(user, password, modified_cookie)
673
+ end
674
+ end
675
+
555
676
  def fetch_hashcash
556
677
  response = request(:get, "https://idmsa.apple.com/appleauth/auth/signin?widgetKey=#{self.itc_service_key}")
557
678
  headers = response.headers
@@ -939,6 +1060,10 @@ module Spaceship
939
1060
  raise BadGatewayError.new, "Apple 502 detected - this might be temporary server error, try again later"
940
1061
  end
941
1062
 
1063
+ if response.body.to_s.include?("<title>503 Service Temporarily Unavailable</title>") || response.body.to_s.include?("<h1>503 Service Temporarily Unavailable</h1>")
1064
+ raise AppleTimeoutError.new, "Apple 503 detected - this might be temporary server error, check https://developer.apple.com/system-status/ to see if there is a known downtime"
1065
+ end
1066
+
942
1067
  return response
943
1068
  end
944
1069
  end
@@ -955,6 +1080,12 @@ module Spaceship
955
1080
  raise AccessForbiddenError.new, msg
956
1081
  when 429
957
1082
  raise TooManyRequestsError, response.to_hash
1083
+ when 502
1084
+ raise BadGatewayError.new, "Apple 502 detected - this might be temporary server error, try again later"
1085
+ when 503
1086
+ raise AppleTimeoutError.new, "Apple 503 detected - this might be temporary server error, check https://developer.apple.com/system-status/ to see if there is a known downtime"
1087
+ when 504
1088
+ raise GatewayTimeoutError.new, "Apple 504 detected - this might be temporary server error, try again later"
958
1089
  end
959
1090
  end
960
1091
 
@@ -8,33 +8,66 @@ module Spaceship
8
8
  attr_accessor :alcohol_tobacco_or_drug_use_or_references
9
9
  attr_accessor :contests
10
10
  attr_accessor :gambling_simulated
11
+ attr_accessor :guns_or_other_weapons
12
+ attr_accessor :horror_or_fear_themes
13
+ attr_accessor :mature_or_suggestive_themes
11
14
  attr_accessor :medical_or_treatment_information
12
15
  attr_accessor :profanity_or_crude_humor
13
16
  attr_accessor :sexual_content_graphic_and_nudity
14
17
  attr_accessor :sexual_content_or_nudity
15
- attr_accessor :horror_or_fear_themes
16
- attr_accessor :mature_or_suggestive_themes
17
18
  attr_accessor :violence_cartoon_or_fantasy
18
19
  attr_accessor :violence_realistic_prolonged_graphic_or_sadistic
19
20
  attr_accessor :violence_realistic
20
21
 
21
22
  # Boolean
23
+ attr_accessor :advertising
24
+ attr_accessor :age_assurance
22
25
  attr_accessor :gambling
23
- attr_accessor :seventeen_plus
26
+ attr_accessor :health_or_wellness_topics
27
+ attr_accessor :loot_box
28
+ attr_accessor :messaging_and_chat
29
+ attr_accessor :parental_controls
24
30
  attr_accessor :unrestricted_web_access
31
+ attr_accessor :user_generated_content
32
+
33
+ # AgeRating
34
+ attr_accessor :age_rating_override_v2
35
+
36
+ # KoreaAgeRating
37
+ attr_accessor :korea_age_rating_override
25
38
 
26
39
  # KidsAge
27
40
  attr_accessor :kids_age_band
28
41
 
42
+ # URL
43
+ attr_accessor :developer_age_rating_info_url
44
+
29
45
  # Deprecated as of App Store Connect API 1.3
30
46
  attr_accessor :gambling_and_contests
31
47
 
32
48
  module Rating
33
49
  NONE = "NONE"
50
+ INFREQUENT = "INFREQUENT"
34
51
  INFREQUENT_OR_MILD = "INFREQUENT_OR_MILD"
52
+ FREQUENT = "FREQUENT"
35
53
  FREQUENT_OR_INTENSE = "FREQUENT_OR_INTENSE"
36
54
  end
37
55
 
56
+ module AgeRating
57
+ NONE = "NONE"
58
+ NINE_PLUS = "NINE_PLUS"
59
+ THIRTEEN_PLUS = "THIRTEEN_PLUS"
60
+ SIXTEEN_PLUS = "SIXTEEN_PLUS"
61
+ EIGHTEEN_PLUS = "EIGHTEEN_PLUS"
62
+ UNRATED = "UNRATED"
63
+ end
64
+
65
+ module KoreaAgeRating
66
+ NONE = "NONE"
67
+ FIFTEEN_PLUS = "FIFTEEN_PLUS"
68
+ NINETEEN_PLUS = "NINETEEN_PLUS"
69
+ end
70
+
38
71
  module KidsAge
39
72
  FIVE_AND_UNDER = "FIVE_AND_UNDER"
40
73
  SIX_TO_EIGHT = "SIX_TO_EIGHT"
@@ -42,24 +75,34 @@ module Spaceship
42
75
  end
43
76
 
44
77
  attr_mapping({
78
+ "advertising" => "advertising",
79
+ "ageAssurance" => "age_assurance",
80
+ "ageRatingOverrideV2" => "age_rating_override_v2",
45
81
  "alcoholTobaccoOrDrugUseOrReferences" => "alcohol_tobacco_or_drug_use_or_references",
46
82
  "contests" => "contests",
83
+ "developerAgeRatingInfoUrl" => "developer_age_rating_info_url",
47
84
  "gambling" => "gambling",
48
85
  "gamblingSimulated" => "gambling_simulated",
86
+ "gunsOrOtherWeapons" => "guns_or_other_weapons",
87
+ "healthOrWellnessTopics" => "health_or_wellness_topics",
88
+ "horrorOrFearThemes" => "horror_or_fear_themes",
89
+ "kidsAgeBand" => "kids_age_band",
90
+ "koreaAgeRatingOverride" => "korea_age_rating_override",
91
+ "lootBox" => "loot_box",
92
+ "matureOrSuggestiveThemes" => "mature_or_suggestive_themes",
49
93
  "medicalOrTreatmentInformation" => "medical_or_treatment_information",
94
+ "messagingAndChat" => "messaging_and_chat",
95
+ "parentalControls" => "parental_controls",
50
96
  "profanityOrCrudeHumor" => "profanity_or_crude_humor",
51
- "seventeenPlus" => "seventeen_plus",
52
97
  "sexualContentGraphicAndNudity" => "sexual_content_graphic_and_nudity",
53
98
  "sexualContentOrNudity" => "sexual_content_or_nudity",
54
- "horrorOrFearThemes" => "horror_or_fear_themes",
55
- "matureOrSuggestiveThemes" => "mature_or_suggestive_themes",
56
99
  "unrestrictedWebAccess" => "unrestricted_web_access",
100
+ "userGeneratedContent" => "user_generated_content",
57
101
  "violenceCartoonOrFantasy" => "violence_cartoon_or_fantasy",
58
102
  "violenceRealisticProlongedGraphicOrSadistic" => "violence_realistic_prolonged_graphic_or_sadistic",
59
103
  "violenceRealistic" => "violence_realistic",
60
- "kidsAgeBand" => "kids_age_band",
61
104
 
62
- # Deprecated as of App Store Connect API 1.3
105
+ # Deprecated as of App Store Connect API 1.3 - No longer accepted by API
63
106
  "gamblingAndContests" => "gambling_and_contests",
64
107
  })
65
108
 
@@ -122,7 +165,20 @@ module Spaceship
122
165
  end
123
166
 
124
167
  def self.map_value_from_itc(key, value)
125
- if ["gamblingAndContests", "unrestrictedWebAccess"].include?(key)
168
+ boolean_keys = [
169
+ "advertising",
170
+ "ageAssurance",
171
+ "gambling",
172
+ "gamblingAndContests",
173
+ "healthOrWellnessTopics",
174
+ "lootBox",
175
+ "messagingAndChat",
176
+ "parentalControls",
177
+ "unrestrictedWebAccess",
178
+ "userGeneratedContent"
179
+ ]
180
+
181
+ if boolean_keys.include?(key)
126
182
  new_value = LEGACY_BOOLEAN_VALUE_ITC_MAP[value]
127
183
  return value if new_value.nil?
128
184
  return new_value
@@ -33,15 +33,15 @@ module Spaceship
33
33
  client ||= Spaceship::ConnectAPI
34
34
  attributes = reverse_attr_mapping(attributes)
35
35
  client.patch_app_info_localization(app_info_localization_id: id, attributes: attributes)
36
- rescue
37
- raise Spaceship::AppStoreLocalizationError, @locale
36
+ rescue => error
37
+ raise Spaceship::AppStoreLocalizationError.new(@locale, error)
38
38
  end
39
39
 
40
40
  def delete!(client: nil, filter: {}, includes: nil, limit: nil, sort: nil)
41
41
  client ||= Spaceship::ConnectAPI
42
42
  client.delete_app_info_localization(app_info_localization_id: id)
43
- rescue
44
- raise Spaceship::AppStoreLocalizationError, @locale
43
+ rescue => error
44
+ raise Spaceship::AppStoreLocalizationError.new(@locale, error)
45
45
  end
46
46
  end
47
47
  end
@@ -43,12 +43,15 @@ module Spaceship
43
43
  APP_WATCH_SERIES_3 = "APP_WATCH_SERIES_3"
44
44
  APP_WATCH_SERIES_4 = "APP_WATCH_SERIES_4"
45
45
  APP_WATCH_SERIES_7 = "APP_WATCH_SERIES_7"
46
+ APP_WATCH_SERIES_10 = "APP_WATCH_SERIES_10"
46
47
  APP_WATCH_ULTRA = "APP_WATCH_ULTRA"
47
48
 
48
49
  APP_APPLE_TV = "APP_APPLE_TV"
49
50
 
50
51
  APP_DESKTOP = "APP_DESKTOP"
51
52
 
53
+ APP_APPLE_VISION_PRO = "APP_APPLE_VISION_PRO"
54
+
52
55
  ALL_IMESSAGE = [
53
56
  IMESSAGE_APP_IPHONE_40,
54
57
  IMESSAGE_APP_IPHONE_47,
@@ -98,9 +101,12 @@ module Spaceship
98
101
  APP_WATCH_SERIES_3,
99
102
  APP_WATCH_SERIES_4,
100
103
  APP_WATCH_SERIES_7,
104
+ APP_WATCH_SERIES_10,
101
105
  APP_WATCH_ULTRA,
102
106
 
103
- APP_DESKTOP
107
+ APP_DESKTOP,
108
+
109
+ APP_APPLE_VISION_PRO
104
110
  ]
105
111
  end
106
112